aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorHarald Welte <laforge@gnumonks.org>2009-06-10 05:40:52 +0800
committerHarald Welte <laforge@gnumonks.org>2009-06-10 05:40:52 +0800
commit13e10daa330ea2b699c9aa9d14b3adbd01111fd6 (patch)
treebf9144f9cf625baab472492b3047970cab14ef83 /src
parentf7c43524cfc6e30a0223d3aaff89fe955d6e5146 (diff)
move openbsc into its own subdirectory
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am27
-rw-r--r--src/abis_nm.c2332
-rw-r--r--src/abis_rsl.c1263
-rw-r--r--src/bs11_config.c805
-rw-r--r--src/bsc_hack.c1159
-rw-r--r--src/chan_alloc.c256
-rw-r--r--src/db.c464
-rw-r--r--src/debug.c161
-rw-r--r--src/e1_config.c108
-rw-r--r--src/e1_input.c498
-rw-r--r--src/gsm_04_08.c1723
-rw-r--r--src/gsm_04_11.c500
-rw-r--r--src/gsm_data.c209
-rw-r--r--src/gsm_subscriber.c143
-rw-r--r--src/gsm_utils.c73
-rw-r--r--src/input/ipaccess.c597
-rw-r--r--src/input/misdn.c542
-rw-r--r--src/ipaccess-config.c198
-rw-r--r--src/ipaccess-find.c180
-rw-r--r--src/isdnsync.c192
-rw-r--r--src/msgb.c70
-rw-r--r--src/paging.c262
-rw-r--r--src/rs232.c249
-rw-r--r--src/select.c107
-rw-r--r--src/signal.c80
-rw-r--r--src/subchan_demux.c319
-rw-r--r--src/telnet_interface.c236
-rw-r--r--src/timer.c174
-rw-r--r--src/tlv_parser.c105
-rw-r--r--src/trau_frame.c255
-rw-r--r--src/trau_mux.c212
-rw-r--r--src/vty/buffer.c460
-rw-r--r--src/vty/cardshell.h5
-rw-r--r--src/vty/command.c3416
-rw-r--r--src/vty/vector.c186
-rw-r--r--src/vty/vty.c1634
-rw-r--r--src/vty_interface.c905
37 files changed, 0 insertions, 20105 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
deleted file mode 100644
index fbbbfdc94..000000000
--- a/src/Makefile.am
+++ /dev/null
@@ -1,27 +0,0 @@
-INCLUDES = $(all_includes) -I$(top_srcdir)/include
-AM_CFLAGS=-Wall
-
-sbin_PROGRAMS = bsc_hack bs11_config ipaccess-find ipaccess-config isdnsync
-noinst_LIBRARIES = libbsc.a libvty.a
-noinst_HEADERS = vty/cardshell.h
-
-libbsc_a_SOURCES = abis_rsl.c abis_nm.c gsm_04_08.c gsm_data.c \
- gsm_subscriber.c msgb.c select.c chan_alloc.c timer.c debug.c db.c \
- gsm_04_11.c telnet_interface.c subchan_demux.c \
- trau_frame.c trau_mux.c paging.c e1_config.c e1_input.c tlv_parser.c \
- input/misdn.c input/ipaccess.c signal.c gsm_utils.c
-
-libvty_a_SOURCES = vty/buffer.c vty/command.c vty/vector.c vty/vty.c
-
-bsc_hack_SOURCES = bsc_hack.c vty_interface.c
-bsc_hack_LDADD = libbsc.a libvty.a -ldl -ldbi $(LIBCRYPT)
-
-bs11_config_SOURCES = bs11_config.c abis_nm.c gsm_data.c msgb.c debug.c \
- select.c timer.c rs232.c tlv_parser.c signal.c
-
-ipaccess_find_SOURCES = ipaccess-find.c select.c timer.c
-
-ipaccess_config_SOURCES = ipaccess-config.c
-ipaccess_config_LDADD = libbsc.a libvty.a -ldl -ldbi $(LIBCRYPT)
-
-isdnsync_SOURCES = isdnsync.c
diff --git a/src/abis_nm.c b/src/abis_nm.c
deleted file mode 100644
index 74dba2377..000000000
--- a/src/abis_nm.c
+++ /dev/null
@@ -1,2332 +0,0 @@
-/* GSM Network Management (OML) messages on the A-bis interface
- * 3GPP TS 12.21 version 8.0.0 Release 1999 / ETSI TS 100 623 V8.0.0 */
-
-/* (C) 2008-2009 by Harald Welte <laforge@gnumonks.org>
- *
- * All Rights Reserved
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- */
-
-
-#include <errno.h>
-#include <unistd.h>
-#include <stdio.h>
-#include <fcntl.h>
-#include <stdlib.h>
-#include <libgen.h>
-#include <time.h>
-#include <limits.h>
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-
-#include <openbsc/gsm_data.h>
-#include <openbsc/debug.h>
-#include <openbsc/msgb.h>
-#include <openbsc/tlv.h>
-#include <openbsc/abis_nm.h>
-#include <openbsc/misdn.h>
-#include <openbsc/signal.h>
-
-#define OM_ALLOC_SIZE 1024
-#define OM_HEADROOM_SIZE 128
-
-/* unidirectional messages from BTS to BSC */
-static const enum abis_nm_msgtype reports[] = {
- NM_MT_SW_ACTIVATED_REP,
- NM_MT_TEST_REP,
- NM_MT_STATECHG_EVENT_REP,
- NM_MT_FAILURE_EVENT_REP,
-};
-
-/* messages without ACK/NACK */
-static const enum abis_nm_msgtype no_ack_nack[] = {
- NM_MT_MEAS_RES_REQ,
- NM_MT_STOP_MEAS,
- NM_MT_START_MEAS,
-};
-
-/* Messages related to software load */
-static const enum abis_nm_msgtype sw_load_msgs[] = {
- NM_MT_LOAD_INIT_ACK,
- NM_MT_LOAD_INIT_NACK,
- NM_MT_LOAD_SEG_ACK,
- NM_MT_LOAD_ABORT,
- NM_MT_LOAD_END_ACK,
- NM_MT_LOAD_END_NACK,
- //NM_MT_SW_ACT_REQ,
- NM_MT_ACTIVATE_SW_ACK,
- NM_MT_ACTIVATE_SW_NACK,
- NM_MT_SW_ACTIVATED_REP,
-};
-
-static const enum abis_nm_msgtype nacks[] = {
- NM_MT_LOAD_INIT_NACK,
- NM_MT_LOAD_END_NACK,
- NM_MT_SW_ACT_REQ_NACK,
- NM_MT_ACTIVATE_SW_NACK,
- NM_MT_ESTABLISH_TEI_NACK,
- NM_MT_CONN_TERR_SIGN_NACK,
- NM_MT_DISC_TERR_SIGN_NACK,
- NM_MT_CONN_TERR_TRAF_NACK,
- NM_MT_DISC_TERR_TRAF_NACK,
- NM_MT_CONN_MDROP_LINK_NACK,
- NM_MT_DISC_MDROP_LINK_NACK,
- NM_MT_SET_BTS_ATTR_NACK,
- NM_MT_SET_RADIO_ATTR_NACK,
- NM_MT_SET_CHAN_ATTR_NACK,
- NM_MT_PERF_TEST_NACK,
- NM_MT_SEND_TEST_REP_NACK,
- NM_MT_STOP_TEST_NACK,
- NM_MT_STOP_EVENT_REP_NACK,
- NM_MT_REST_EVENT_REP_NACK,
- NM_MT_CHG_ADM_STATE_NACK,
- NM_MT_CHG_ADM_STATE_REQ_NACK,
- NM_MT_REP_OUTST_ALARMS_NACK,
- NM_MT_CHANGEOVER_NACK,
- NM_MT_OPSTART_NACK,
- NM_MT_REINIT_NACK,
- NM_MT_SET_SITE_OUT_NACK,
- NM_MT_CHG_HW_CONF_NACK,
- NM_MT_GET_ATTR_NACK,
- NM_MT_SET_ALARM_THRES_NACK,
- NM_MT_BS11_BEGIN_DB_TX_NACK,
- NM_MT_BS11_END_DB_TX_NACK,
- NM_MT_BS11_CREATE_OBJ_NACK,
- NM_MT_BS11_DELETE_OBJ_NACK,
-};
-
-static const char *nack_names[0xff] = {
- [NM_MT_LOAD_INIT_NACK] = "SOFTWARE LOAD INIT",
- [NM_MT_LOAD_END_NACK] = "SOFTWARE LOAD END",
- [NM_MT_SW_ACT_REQ_NACK] = "SOFTWARE ACTIVATE REQUEST",
- [NM_MT_ACTIVATE_SW_NACK] = "ACTIVATE SOFTWARE",
- [NM_MT_ESTABLISH_TEI_NACK] = "ESTABLISH TEI",
- [NM_MT_CONN_TERR_SIGN_NACK] = "CONNECT TERRESTRIAL SIGNALLING",
- [NM_MT_DISC_TERR_SIGN_NACK] = "DISCONNECT TERRESTRIAL SIGNALLING",
- [NM_MT_CONN_TERR_TRAF_NACK] = "CONNECT TERRESTRIAL TRAFFIC",
- [NM_MT_DISC_TERR_TRAF_NACK] = "DISCONNECT TERRESTRIAL TRAFFIC",
- [NM_MT_CONN_MDROP_LINK_NACK] = "CONNECT MULTI-DROP LINK",
- [NM_MT_DISC_MDROP_LINK_NACK] = "DISCONNECT MULTI-DROP LINK",
- [NM_MT_SET_BTS_ATTR_NACK] = "SET BTS ATTRIBUTE",
- [NM_MT_SET_RADIO_ATTR_NACK] = "SET RADIO ATTRIBUTE",
- [NM_MT_SET_CHAN_ATTR_NACK] = "SET CHANNEL ATTRIBUTE",
- [NM_MT_PERF_TEST_NACK] = "PERFORM TEST",
- [NM_MT_SEND_TEST_REP_NACK] = "SEND TEST REPORT",
- [NM_MT_STOP_TEST_NACK] = "STOP TEST",
- [NM_MT_STOP_EVENT_REP_NACK] = "STOP EVENT REPORT",
- [NM_MT_REST_EVENT_REP_NACK] = "RESET EVENT REPORT",
- [NM_MT_CHG_ADM_STATE_NACK] = "CHANGE ADMINISTRATIVE STATE",
- [NM_MT_CHG_ADM_STATE_REQ_NACK] = "CHANGE ADMINISTRATIVE STATE REQUEST",
- [NM_MT_REP_OUTST_ALARMS_NACK] = "REPORT OUTSTANDING ALARMS",
- [NM_MT_CHANGEOVER_NACK] = "CHANGEOVER",
- [NM_MT_OPSTART_NACK] = "OPSTART",
- [NM_MT_REINIT_NACK] = "REINIT",
- [NM_MT_SET_SITE_OUT_NACK] = "SET SITE OUTPUT",
- [NM_MT_CHG_HW_CONF_NACK] = "CHANGE HARDWARE CONFIGURATION",
- [NM_MT_GET_ATTR_NACK] = "GET ATTRIBUTE",
- [NM_MT_SET_ALARM_THRES_NACK] = "SET ALARM THRESHOLD",
- [NM_MT_BS11_BEGIN_DB_TX_NACK] = "BS11 BEGIN DATABASE TRANSMISSION",
- [NM_MT_BS11_END_DB_TX_NACK] = "BS11 END DATABASE TRANSMISSION",
- [NM_MT_BS11_CREATE_OBJ_NACK] = "BS11 CREATE OBJECT",
- [NM_MT_BS11_DELETE_OBJ_NACK] = "BS11 DELETE OBJECT",
-};
-
-/* Chapter 9.4.36 */
-static const char *nack_cause_names[] = {
- /* General Nack Causes */
- [NM_NACK_INCORR_STRUCT] = "Incorrect message structure",
- [NM_NACK_MSGTYPE_INVAL] = "Invalid message type value",
- [NM_NACK_OBJCLASS_INVAL] = "Invalid Object class value",
- [NM_NACK_OBJCLASS_NOTSUPP] = "Object class not supported",
- [NM_NACK_BTSNR_UNKN] = "BTS no. unknown",
- [NM_NACK_TRXNR_UNKN] = "Baseband Transceiver no. unknown",
- [NM_NACK_OBJINST_UNKN] = "Object Instance unknown",
- [NM_NACK_ATTRID_INVAL] = "Invalid attribute identifier value",
- [NM_NACK_ATTRID_NOTSUPP] = "Attribute identifier not supported",
- [NM_NACK_PARAM_RANGE] = "Parameter value outside permitted range",
- [NM_NACK_ATTRLIST_INCONSISTENT] = "Inconsistency in attribute list",
- [NM_NACK_SPEC_IMPL_NOTSUPP] = "Specified implementation not supported",
- [NM_NACK_CANT_PERFORM] = "Message cannot be performed",
- /* Specific Nack Causes */
- [NM_NACK_RES_NOTIMPL] = "Resource not implemented",
- [NM_NACK_RES_NOTAVAIL] = "Resource not available",
- [NM_NACK_FREQ_NOTAVAIL] = "Frequency not available",
- [NM_NACK_TEST_NOTSUPP] = "Test not supported",
- [NM_NACK_CAPACITY_RESTR] = "Capacity restrictions",
- [NM_NACK_PHYSCFG_NOTPERFORM] = "Physical configuration cannot be performed",
- [NM_NACK_TEST_NOTINIT] = "Test not initiated",
- [NM_NACK_PHYSCFG_NOTRESTORE] = "Physical configuration cannot be restored",
- [NM_NACK_TEST_NOSUCH] = "No such test",
- [NM_NACK_TEST_NOSTOP] = "Test cannot be stopped",
- [NM_NACK_MSGINCONSIST_PHYSCFG] = "Message inconsistent with physical configuration",
- [NM_NACK_FILE_INCOMPLETE] = "Complete file notreceived",
- [NM_NACK_FILE_NOTAVAIL] = "File not available at destination",
- [MN_NACK_FILE_NOTACTIVATE] = "File cannot be activate",
- [NM_NACK_REQ_NOT_GRANT] = "Request not granted",
- [NM_NACK_WAIT] = "Wait",
- [NM_NACK_NOTH_REPORT_EXIST] = "Nothing reportable existing",
- [NM_NACK_MEAS_NOTSUPP] = "Measurement not supported",
- [NM_NACK_MEAS_NOTSTART] = "Measurement not started",
-};
-
-static char namebuf[255];
-static const char *nack_cause_name(u_int8_t cause)
-{
- if (cause < ARRAY_SIZE(nack_cause_names) && nack_cause_names[cause])
- return nack_cause_names[cause];
-
- snprintf(namebuf, sizeof(namebuf), "0x%02x\n", cause);
- return namebuf;
-}
-
-/* Chapter 9.4.16: Event Type */
-static const char *event_type_names[] = {
- [NM_EVT_COMM_FAIL] = "communication failure",
- [NM_EVT_QOS_FAIL] = "quality of service failure",
- [NM_EVT_PROC_FAIL] = "processing failure",
- [NM_EVT_EQUIP_FAIL] = "equipment failure",
- [NM_EVT_ENV_FAIL] = "environment failure",
-};
-
-static const char *event_type_name(u_int8_t cause)
-{
- if (cause < ARRAY_SIZE(event_type_names) && event_type_names[cause])
- return event_type_names[cause];
-
- snprintf(namebuf, sizeof(namebuf), "0x%02x\n", cause);
- return namebuf;
-}
-
-/* Chapter 9.4.63: Perceived Severity */
-static const char *severity_names[] = {
- [NM_SEVER_CEASED] = "failure ceased",
- [NM_SEVER_CRITICAL] = "critical failure",
- [NM_SEVER_MAJOR] = "major failure",
- [NM_SEVER_MINOR] = "minor failure",
- [NM_SEVER_WARNING] = "warning level failure",
- [NM_SEVER_INDETERMINATE] = "indeterminate failure",
-};
-
-static const char *severity_name(u_int8_t cause)
-{
- if (cause < ARRAY_SIZE(severity_names) && severity_names[cause])
- return severity_names[cause];
-
- snprintf(namebuf, sizeof(namebuf), "0x%02x\n", cause);
- return namebuf;
-}
-
-/* Attributes that the BSC can set, not only get, according to Section 9.4 */
-static const enum abis_nm_attr nm_att_settable[] = {
- NM_ATT_ADD_INFO,
- NM_ATT_ADD_TEXT,
- NM_ATT_DEST,
- NM_ATT_EVENT_TYPE,
- NM_ATT_FILE_DATA,
- NM_ATT_GET_ARI,
- NM_ATT_HW_CONF_CHG,
- NM_ATT_LIST_REQ_ATTR,
- NM_ATT_MDROP_LINK,
- NM_ATT_MDROP_NEXT,
- NM_ATT_NACK_CAUSES,
- NM_ATT_OUTST_ALARM,
- NM_ATT_PHYS_CONF,
- NM_ATT_PROB_CAUSE,
- NM_ATT_RAD_SUBC,
- NM_ATT_SOURCE,
- NM_ATT_SPEC_PROB,
- NM_ATT_START_TIME,
- NM_ATT_TEST_DUR,
- NM_ATT_TEST_NO,
- NM_ATT_TEST_REPORT,
- NM_ATT_WINDOW_SIZE,
- NM_ATT_SEVERITY,
- NM_ATT_MEAS_RES,
- NM_ATT_MEAS_TYPE,
-};
-
-static const struct tlv_definition nm_att_tlvdef = {
- .def = {
- [NM_ATT_ABIS_CHANNEL] = { TLV_TYPE_FIXED, 3 },
- [NM_ATT_ADD_INFO] = { TLV_TYPE_TL16V },
- [NM_ATT_ADD_TEXT] = { TLV_TYPE_TL16V },
- [NM_ATT_ADM_STATE] = { TLV_TYPE_TV },
- [NM_ATT_ARFCN_LIST]= { TLV_TYPE_TL16V },
- [NM_ATT_AUTON_REPORT] = { TLV_TYPE_TV },
- [NM_ATT_AVAIL_STATUS] = { TLV_TYPE_TL16V },
- [NM_ATT_BCCH_ARFCN] = { TLV_TYPE_FIXED, 2 },
- [NM_ATT_BSIC] = { TLV_TYPE_TV },
- [NM_ATT_BTS_AIR_TIMER] = { TLV_TYPE_TV },
- [NM_ATT_CCCH_L_I_P] = { TLV_TYPE_TV },
- [NM_ATT_CCCH_L_T] = { TLV_TYPE_TV },
- [NM_ATT_CHAN_COMB] = { TLV_TYPE_TV },
- [NM_ATT_CONN_FAIL_CRIT] = { TLV_TYPE_TL16V },
- [NM_ATT_DEST] = { TLV_TYPE_TL16V },
- [NM_ATT_EVENT_TYPE] = { TLV_TYPE_TV },
- [NM_ATT_FILE_DATA] = { TLV_TYPE_TL16V },
- [NM_ATT_FILE_ID] = { TLV_TYPE_TL16V },
- [NM_ATT_FILE_VERSION] = { TLV_TYPE_TL16V },
- [NM_ATT_GSM_TIME] = { TLV_TYPE_FIXED, 2 },
- [NM_ATT_HSN] = { TLV_TYPE_TV },
- [NM_ATT_HW_CONFIG] = { TLV_TYPE_TL16V },
- [NM_ATT_HW_DESC] = { TLV_TYPE_TL16V },
- [NM_ATT_INTAVE_PARAM] = { TLV_TYPE_TV },
- [NM_ATT_INTERF_BOUND] = { TLV_TYPE_FIXED, 6 },
- [NM_ATT_LIST_REQ_ATTR] = { TLV_TYPE_TL16V },
- [NM_ATT_MAIO] = { TLV_TYPE_TV },
- [NM_ATT_MANUF_STATE] = { TLV_TYPE_TV },
- [NM_ATT_MANUF_THRESH] = { TLV_TYPE_TL16V },
- [NM_ATT_MANUF_ID] = { TLV_TYPE_TL16V },
- [NM_ATT_MAX_TA] = { TLV_TYPE_TV },
- [NM_ATT_MDROP_LINK] = { TLV_TYPE_FIXED, 2 },
- [NM_ATT_MDROP_NEXT] = { TLV_TYPE_FIXED, 2 },
- [NM_ATT_NACK_CAUSES] = { TLV_TYPE_TV },
- [NM_ATT_NY1] = { TLV_TYPE_TV },
- [NM_ATT_OPER_STATE] = { TLV_TYPE_TV },
- [NM_ATT_OVERL_PERIOD] = { TLV_TYPE_TL16V },
- [NM_ATT_PHYS_CONF] = { TLV_TYPE_TL16V },
- [NM_ATT_POWER_CLASS] = { TLV_TYPE_TV },
- [NM_ATT_POWER_THRESH] = { TLV_TYPE_FIXED, 3 },
- [NM_ATT_PROB_CAUSE] = { TLV_TYPE_FIXED, 3 },
- [NM_ATT_RACH_B_THRESH] = { TLV_TYPE_TV },
- [NM_ATT_LDAVG_SLOTS] = { TLV_TYPE_FIXED, 2 },
- [NM_ATT_RAD_SUBC] = { TLV_TYPE_TV },
- [NM_ATT_RF_MAXPOWR_R] = { TLV_TYPE_TV },
- [NM_ATT_SITE_INPUTS] = { TLV_TYPE_TL16V },
- [NM_ATT_SITE_OUTPUTS] = { TLV_TYPE_TL16V },
- [NM_ATT_SOURCE] = { TLV_TYPE_TL16V },
- [NM_ATT_SPEC_PROB] = { TLV_TYPE_TV },
- [NM_ATT_START_TIME] = { TLV_TYPE_FIXED, 2 },
- [NM_ATT_T200] = { TLV_TYPE_FIXED, 7 },
- [NM_ATT_TEI] = { TLV_TYPE_TV },
- [NM_ATT_TEST_DUR] = { TLV_TYPE_FIXED, 2 },
- [NM_ATT_TEST_NO] = { TLV_TYPE_TV },
- [NM_ATT_TEST_REPORT] = { TLV_TYPE_TL16V },
- [NM_ATT_VSWR_THRESH] = { TLV_TYPE_FIXED, 2 },
- [NM_ATT_WINDOW_SIZE] = { TLV_TYPE_TV },
- [NM_ATT_TSC] = { TLV_TYPE_TV },
- [NM_ATT_SW_CONFIG] = { TLV_TYPE_TL16V },
- [NM_ATT_SEVERITY] = { TLV_TYPE_TV },
- [NM_ATT_GET_ARI] = { TLV_TYPE_TL16V },
- [NM_ATT_HW_CONF_CHG] = { TLV_TYPE_TL16V },
- [NM_ATT_OUTST_ALARM] = { TLV_TYPE_TV },
- [NM_ATT_FILE_DATA] = { TLV_TYPE_TL16V },
- [NM_ATT_MEAS_RES] = { TLV_TYPE_TL16V },
- /* BS11 specifics */
- [NM_ATT_BS11_ESN_FW_CODE_NO] = { TLV_TYPE_TLV },
- [NM_ATT_BS11_ESN_HW_CODE_NO] = { TLV_TYPE_TLV },
- [NM_ATT_BS11_ESN_PCB_SERIAL] = { TLV_TYPE_TLV },
- [NM_ATT_BS11_BOOT_SW_VERS] = { TLV_TYPE_TLV },
- [0xd5] = { TLV_TYPE_TLV },
- [0xa8] = { TLV_TYPE_TLV },
- [NM_ATT_BS11_PASSWORD] = { TLV_TYPE_TLV },
- [NM_ATT_BS11_TXPWR] = { TLV_TYPE_TLV },
- [NM_ATT_BS11_RSSI_OFFS] = { TLV_TYPE_TLV },
- [NM_ATT_BS11_LINE_CFG] = { TLV_TYPE_TV },
- [NM_ATT_BS11_L1_PROT_TYPE] = { TLV_TYPE_TV },
- [NM_ATT_BS11_BIT_ERR_THESH] = { TLV_TYPE_FIXED, 2 },
- [NM_ATT_BS11_DIVERSITY] = { TLV_TYPE_TLV },
- [NM_ATT_BS11_LMT_LOGON_SESSION]={ TLV_TYPE_TLV },
- [NM_ATT_BS11_LMT_LOGIN_TIME] = { TLV_TYPE_TLV },
- [NM_ATT_BS11_LMT_USER_ACC_LEV] ={ TLV_TYPE_TLV },
- [NM_ATT_BS11_LMT_USER_NAME] = { TLV_TYPE_TLV },
- [NM_ATT_BS11_BTS_STATE] = { TLV_TYPE_TLV },
- [NM_ATT_BS11_E1_STATE] = { TLV_TYPE_TLV },
- [NM_ATT_BS11_PLL_MODE] = { TLV_TYPE_TLV },
- [NM_ATT_BS11_PLL] = { TLV_TYPE_TLV },
- [NM_ATT_BS11_CCLK_ACCURACY] = { TLV_TYPE_TV },
- [NM_ATT_BS11_CCLK_TYPE] = { TLV_TYPE_TV },
- /* ip.access specifics */
- [NM_ATT_IPACC_RSL_BSC_IP] = { TLV_TYPE_FIXED, 4 },
- [NM_ATT_IPACC_RSL_BSC_PORT] = { TLV_TYPE_FIXED, 2 },
- [NM_ATT_IPACC_PRIM_OML_IP] = { TLV_TYPE_FIXED, 6 },
- [0x95] = { TLV_TYPE_FIXED, 2 },
- [0x85] = { TLV_TYPE_TV },
-
- },
-};
-
-int abis_nm_tlv_parse(struct tlv_parsed *tp, const u_int8_t *buf, int len)
-{
- return tlv_parse(tp, &nm_att_tlvdef, buf, len, 0, 0);
-}
-
-static int is_in_arr(enum abis_nm_msgtype mt, const enum abis_nm_msgtype *arr, int size)
-{
- int i;
-
- for (i = 0; i < size; i++) {
- if (arr[i] == mt)
- return 1;
- }
-
- return 0;
-}
-
-#if 0
-/* is this msgtype the usual ACK/NACK type ? */
-static int is_ack_nack(enum abis_nm_msgtype mt)
-{
- return !is_in_arr(mt, no_ack_nack, ARRAY_SIZE(no_ack_nack));
-}
-#endif
-
-/* is this msgtype a report ? */
-static int is_report(enum abis_nm_msgtype mt)
-{
- return is_in_arr(mt, reports, ARRAY_SIZE(reports));
-}
-
-#define MT_ACK(x) (x+1)
-#define MT_NACK(x) (x+2)
-
-static void fill_om_hdr(struct abis_om_hdr *oh, u_int8_t len)
-{
- oh->mdisc = ABIS_OM_MDISC_FOM;
- oh->placement = ABIS_OM_PLACEMENT_ONLY;
- oh->sequence = 0;
- oh->length = len;
-}
-
-static void fill_om_fom_hdr(struct abis_om_hdr *oh, u_int8_t len,
- u_int8_t msg_type, u_int8_t obj_class,
- u_int8_t bts_nr, u_int8_t trx_nr, u_int8_t ts_nr)
-{
- struct abis_om_fom_hdr *foh =
- (struct abis_om_fom_hdr *) oh->data;
-
- fill_om_hdr(oh, len+sizeof(*foh));
- foh->msg_type = msg_type;
- foh->obj_class = obj_class;
- foh->obj_inst.bts_nr = bts_nr;
- foh->obj_inst.trx_nr = trx_nr;
- foh->obj_inst.ts_nr = ts_nr;
-}
-
-static struct msgb *nm_msgb_alloc(void)
-{
- return msgb_alloc_headroom(OM_ALLOC_SIZE, OM_HEADROOM_SIZE);
-}
-
-/* Send a OML NM Message from BSC to BTS */
-int abis_nm_sendmsg(struct gsm_bts *bts, struct msgb *msg)
-{
- msg->trx = bts->c0;
-
- return _abis_nm_sendmsg(msg);
-}
-
-static int abis_nm_rcvmsg_sw(struct msgb *mb);
-
-static const char *obj_class_name(u_int8_t oc)
-{
- switch (oc) {
- case NM_OC_SITE_MANAGER:
- return "SITE MANAGER";
- case NM_OC_BTS:
- return "BTS";
- case NM_OC_RADIO_CARRIER:
- return "RADIO CARRIER";
- case NM_OC_BASEB_TRANSC:
- return "BASEBAND TRANSCEIVER";
- case NM_OC_CHANNEL:
- return "CHANNEL";
- case NM_OC_BS11_ADJC:
- return "ADJC";
- case NM_OC_BS11_HANDOVER:
- return "HANDOVER";
- case NM_OC_BS11_PWR_CTRL:
- return "POWER CONTROL";
- case NM_OC_BS11_BTSE:
- return "BTSE";
- case NM_OC_BS11_RACK:
- return "RACK";
- case NM_OC_BS11_TEST:
- return "TEST";
- case NM_OC_BS11_ENVABTSE:
- return "ENVABTSE";
- case NM_OC_BS11_BPORT:
- return "BPORT";
- case NM_OC_GPRS_NSE:
- return "GPRS NSE";
- case NM_OC_GPRS_CELL:
- return "GPRS CELL";
- case NM_OC_GPRS_NSVC0:
- return "GPRS NSVC0";
- case NM_OC_GPRS_NSVC1:
- return "GPRS NSVC1";
- case NM_OC_BS11:
- return "SIEMENSHW";
- }
-
- return "UNKNOWN";
-}
-
-const char *nm_opstate_name(u_int8_t os)
-{
- switch (os) {
- case 1:
- return "Disabled";
- case 2:
- return "Enabled";
- case 0xff:
- return "NULL";
- default:
- return "RFU";
- }
-}
-
-/* Chapter 9.4.7 */
-static const char *avail_names[] = {
- "In test",
- "Failed",
- "Power off",
- "Off line",
- "<not used>",
- "Dependency",
- "Degraded",
- "Not installed",
-};
-
-const char *nm_avail_name(u_int8_t avail)
-{
- if (avail == 0xff)
- return "OK";
- if (avail >= ARRAY_SIZE(avail_names))
- return "UNKNOWN";
- return avail_names[avail];
-}
-
-const char *nm_adm_name(u_int8_t adm)
-{
- switch (adm) {
- case 1:
- return "Locked";
- case 2:
- return "Unlocked";
- case 3:
- return "Shutdown";
- default:
- return "<not used>";
- }
-}
-
-/* obtain the gsm_nm_state data structure for a given object instance */
-static struct gsm_nm_state *
-objclass2nmstate(struct gsm_bts *bts, u_int8_t obj_class,
- struct abis_om_obj_inst *obj_inst)
-{
- struct gsm_bts_trx *trx;
- struct gsm_nm_state *nm_state = NULL;
-
- switch (obj_class) {
- case NM_OC_BTS:
- nm_state = &bts->nm_state;
- break;
- case NM_OC_RADIO_CARRIER:
- if (obj_inst->trx_nr >= bts->num_trx)
- return NULL;
- trx = &bts->trx[obj_inst->trx_nr];
- nm_state = &trx->nm_state;
- break;
- case NM_OC_BASEB_TRANSC:
- if (obj_inst->trx_nr >= bts->num_trx)
- return NULL;
- trx = &bts->trx[obj_inst->trx_nr];
- nm_state = &trx->bb_transc.nm_state;
- break;
- case NM_OC_CHANNEL:
- if (obj_inst->trx_nr > bts->num_trx)
- return NULL;
- trx = &bts->trx[obj_inst->trx_nr];
- if (obj_inst->ts_nr >= TRX_NR_TS)
- return NULL;
- nm_state = &trx->ts[obj_inst->ts_nr].nm_state;
- break;
- case NM_OC_SITE_MANAGER:
- nm_state = &bts->site_mgr.nm_state;
- break;
- case NM_OC_BS11:
- switch (obj_inst->bts_nr) {
- case BS11_OBJ_CCLK:
- nm_state = &bts->bs11.cclk.nm_state;
- break;
- case BS11_OBJ_BBSIG:
- if (obj_inst->ts_nr > bts->num_trx)
- return NULL;
- trx = &bts->trx[obj_inst->ts_nr];
- nm_state = &trx->bs11.bbsig.nm_state;
- break;
- case BS11_OBJ_PA:
- if (obj_inst->ts_nr > bts->num_trx)
- return NULL;
- trx = &bts->trx[obj_inst->ts_nr];
- nm_state = &trx->bs11.pa.nm_state;
- break;
- default:
- return NULL;
- }
- case NM_OC_BS11_RACK:
- nm_state = &bts->bs11.rack.nm_state;
- break;
- case NM_OC_BS11_ENVABTSE:
- if (obj_inst->trx_nr > ARRAY_SIZE(bts->bs11.envabtse))
- return NULL;
- nm_state = &bts->bs11.envabtse[obj_inst->trx_nr].nm_state;
- break;
- }
- return nm_state;
-}
-
-/* obtain the in-memory data structure of a given object instance */
-static void *
-objclass2obj(struct gsm_bts *bts, u_int8_t obj_class,
- struct abis_om_obj_inst *obj_inst)
-{
- struct gsm_bts_trx *trx;
- void *obj = NULL;
-
- switch (obj_class) {
- case NM_OC_BTS:
- obj = bts;
- break;
- case NM_OC_RADIO_CARRIER:
- if (obj_inst->trx_nr >= bts->num_trx)
- return NULL;
- trx = &bts->trx[obj_inst->trx_nr];
- obj = trx;
- break;
- case NM_OC_BASEB_TRANSC:
- if (obj_inst->trx_nr >= bts->num_trx)
- return NULL;
- trx = &bts->trx[obj_inst->trx_nr];
- obj = &trx->bb_transc;
- break;
- case NM_OC_CHANNEL:
- if (obj_inst->trx_nr > bts->num_trx)
- return NULL;
- trx = &bts->trx[obj_inst->trx_nr];
- if (obj_inst->ts_nr >= TRX_NR_TS)
- return NULL;
- obj = &trx->ts[obj_inst->ts_nr];
- break;
- case NM_OC_SITE_MANAGER:
- obj = &bts->site_mgr;
- break;
- }
- return obj;
-}
-
-/* Update the administrative state of a given object in our in-memory data
- * structures and send an event to the higher layer */
-static int update_admstate(struct gsm_bts *bts, u_int8_t obj_class,
- struct abis_om_obj_inst *obj_inst, u_int8_t adm_state)
-{
- struct gsm_nm_state *nm_state, new_state;
- void *obj;
- int rc;
-
- obj = objclass2obj(bts, obj_class, obj_inst);
- nm_state = objclass2nmstate(bts, obj_class, obj_inst);
- if (!nm_state)
- return -1;
-
- new_state = *nm_state;
- new_state.administrative = adm_state;
-
- rc = nm_state_event(EVT_STATECHG_ADM, obj_class, obj, nm_state, &new_state);
-
- nm_state->administrative = adm_state;
-
- return rc;
-}
-
-static int abis_nm_rx_statechg_rep(struct msgb *mb)
-{
- struct abis_om_hdr *oh = msgb_l2(mb);
- struct abis_om_fom_hdr *foh = msgb_l3(mb);
- struct gsm_bts *bts = mb->trx->bts;
- struct tlv_parsed tp;
- struct gsm_nm_state *nm_state, new_state;
- int rc;
-
- DEBUGPC(DNM, "STATE CHG: ");
-
- memset(&new_state, 0, sizeof(new_state));
-
- nm_state = objclass2nmstate(bts, foh->obj_class, &foh->obj_inst);
- if (!nm_state) {
- DEBUGPC(DNM, "\n");
- return -EINVAL;
- }
-
- new_state = *nm_state;
-
- abis_nm_tlv_parse(&tp, foh->data, oh->length-sizeof(*foh));
- if (TLVP_PRESENT(&tp, NM_ATT_OPER_STATE)) {
- new_state.operational = *TLVP_VAL(&tp, NM_ATT_OPER_STATE);
- DEBUGPC(DNM, "OP_STATE=%s ", nm_opstate_name(new_state.operational));
- }
- if (TLVP_PRESENT(&tp, NM_ATT_AVAIL_STATUS)) {
- if (TLVP_LEN(&tp, NM_ATT_AVAIL_STATUS) == 0)
- new_state.availability = 0xff;
- else
- new_state.availability = *TLVP_VAL(&tp, NM_ATT_AVAIL_STATUS);
- DEBUGPC(DNM, "AVAIL=%s(%02x) ", nm_avail_name(new_state.availability),
- new_state.availability);
- }
- if (TLVP_PRESENT(&tp, NM_ATT_ADM_STATE)) {
- new_state.administrative = *TLVP_VAL(&tp, NM_ATT_ADM_STATE);
- DEBUGPC(DNM, "ADM=%02x ", nm_adm_name(new_state.administrative));
- }
- DEBUGPC(DNM, "\n");
-
- if (memcmp(&new_state, nm_state, sizeof(new_state))) {
- /* Update the operational state of a given object in our in-memory data
- * structures and send an event to the higher layer */
- void *obj = objclass2obj(bts, foh->obj_class, &foh->obj_inst);
- rc = nm_state_event(EVT_STATECHG_OPER, foh->obj_class, obj, nm_state, &new_state);
- *nm_state = new_state;
- }
-#if 0
- if (op_state == 1) {
- /* try to enable objects that are disabled */
- abis_nm_opstart(bts, foh->obj_class,
- foh->obj_inst.bts_nr,
- foh->obj_inst.trx_nr,
- foh->obj_inst.ts_nr);
- }
-#endif
- return 0;
-}
-
-static int rx_fail_evt_rep(struct msgb *mb)
-{
- struct abis_om_hdr *oh = msgb_l2(mb);
- struct abis_om_fom_hdr *foh = msgb_l3(mb);
- struct tlv_parsed tp;
-
- DEBUGPC(DNM, "Failure Event Report ");
-
- abis_nm_tlv_parse(&tp, foh->data, oh->length-sizeof(*foh));
-
- if (TLVP_PRESENT(&tp, NM_ATT_EVENT_TYPE))
- DEBUGPC(DNM, "Type=%s ", event_type_name(*TLVP_VAL(&tp, NM_ATT_EVENT_TYPE)));
- if (TLVP_PRESENT(&tp, NM_ATT_SEVERITY))
- DEBUGPC(DNM, "Severity=%s ", severity_name(*TLVP_VAL(&tp, NM_ATT_SEVERITY)));
-
- DEBUGPC(DNM, "\n");
-
- return 0;
-}
-
-static int abis_nm_rcvmsg_report(struct msgb *mb)
-{
- struct abis_om_fom_hdr *foh = msgb_l3(mb);
- u_int8_t mt = foh->msg_type;
-
- DEBUGP(DNM, "OC=%s(%02x) INST=(%02x,%02x,%02x) ",
- obj_class_name(foh->obj_class), foh->obj_class,
- foh->obj_inst.bts_nr, foh->obj_inst.trx_nr,
- foh->obj_inst.ts_nr);
-
- //nmh->cfg->report_cb(mb, foh);
-
- switch (mt) {
- case NM_MT_STATECHG_EVENT_REP:
- return abis_nm_rx_statechg_rep(mb);
- break;
- case NM_MT_SW_ACTIVATED_REP:
- DEBUGPC(DNM, "Software Activated Report\n");
- dispatch_signal(SS_NM, S_NM_SW_ACTIV_REP, mb);
- break;
- case NM_MT_FAILURE_EVENT_REP:
- rx_fail_evt_rep(mb);
- dispatch_signal(SS_NM, S_NM_FAIL_REP, mb);
- break;
- default:
- DEBUGPC(DNM, "reporting NM MT 0x%02x\n", mt);
- break;
-
- };
-
- return 0;
-}
-
-/* Activate the specified software into the BTS */
-static int ipacc_sw_activate(struct gsm_bts *bts, u_int8_t obj_class, u_int8_t i0, u_int8_t i1,
- u_int8_t i2, u_int8_t *sw_desc, u_int8_t swdesc_len)
-{
- struct abis_om_hdr *oh;
- struct msgb *msg = nm_msgb_alloc();
- u_int8_t len = swdesc_len;
- u_int8_t *trailer;
-
- oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
- fill_om_fom_hdr(oh, len, NM_MT_ACTIVATE_SW, obj_class, i0, i1, i2);
-
- trailer = msgb_put(msg, swdesc_len);
- memcpy(trailer, sw_desc, swdesc_len);
-
- return abis_nm_sendmsg(bts, msg);
-}
-
-static int abis_nm_rx_sw_act_req(struct msgb *mb)
-{
- struct abis_om_hdr *oh = msgb_l2(mb);
- struct abis_om_fom_hdr *foh = msgb_l3(mb);
- int nack = 0;
- int ret;
-
- DEBUGP(DNM, "Software Activate Request ");
-
- if (foh->obj_class >= 0xf0 && foh->obj_class <= 0xf3) {
- DEBUGPC(DNM, "NACKing for GPRS obj_class 0x%02x\n", foh->obj_class);
- nack = 1;
- } else
- DEBUGPC(DNM, "ACKing and Activating\n");
-
- ret = abis_nm_sw_act_req_ack(mb->trx->bts, foh->obj_class,
- foh->obj_inst.bts_nr,
- foh->obj_inst.trx_nr,
- foh->obj_inst.ts_nr, nack,
- foh->data, oh->length-sizeof(*foh));
-
- if (nack)
- return ret;
-
- /* FIXME: properly parse attributes */
- return ipacc_sw_activate(mb->trx->bts, foh->obj_class,
- foh->obj_inst.bts_nr,
- foh->obj_inst.trx_nr,
- foh->obj_inst.ts_nr,
- foh->data + oh->length-sizeof(*foh)-22, 22);
-}
-
-/* Receive a CHANGE_ADM_STATE_ACK, parse the TLV and update local state */
-static int abis_nm_rx_chg_adm_state_ack(struct msgb *mb)
-{
- struct abis_om_hdr *oh = msgb_l2(mb);
- struct abis_om_fom_hdr *foh = msgb_l3(mb);
- struct tlv_parsed tp;
- u_int8_t adm_state;
-
- abis_nm_tlv_parse(&tp, foh->data, oh->length-sizeof(*foh));
- if (!TLVP_PRESENT(&tp, NM_ATT_ADM_STATE))
- return -EINVAL;
-
- adm_state = *TLVP_VAL(&tp, NM_ATT_ADM_STATE);
-
- return update_admstate(mb->trx->bts, foh->obj_class, &foh->obj_inst, adm_state);
-}
-
-static int abis_nm_rx_lmt_event(struct msgb *mb)
-{
- struct abis_om_hdr *oh = msgb_l2(mb);
- struct abis_om_fom_hdr *foh = msgb_l3(mb);
- struct tlv_parsed tp;
-
- DEBUGP(DNM, "LMT Event ");
- abis_nm_tlv_parse(&tp, foh->data, oh->length-sizeof(*foh));
- if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) &&
- TLVP_LEN(&tp, NM_ATT_BS11_LMT_LOGON_SESSION) >= 1) {
- u_int8_t onoff = *TLVP_VAL(&tp, NM_ATT_BS11_LMT_LOGON_SESSION);
- DEBUGPC(DNM, "LOG%s ", onoff ? "ON" : "OFF");
- }
- if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV) &&
- TLVP_LEN(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV) >= 1) {
- u_int8_t level = *TLVP_VAL(&tp, NM_ATT_BS11_LMT_USER_ACC_LEV);
- DEBUGPC(DNM, "Level=%u ", level);
- }
- if (TLVP_PRESENT(&tp, NM_ATT_BS11_LMT_USER_NAME) &&
- TLVP_LEN(&tp, NM_ATT_BS11_LMT_USER_NAME) >= 1) {
- char *name = (char *) TLVP_VAL(&tp, NM_ATT_BS11_LMT_USER_NAME);
- DEBUGPC(DNM, "Username=%s ", name);
- }
- DEBUGPC(DNM, "\n");
- /* FIXME: parse LMT LOGON TIME */
- return 0;
-}
-
-/* Receive a OML NM Message from BTS */
-static int abis_nm_rcvmsg_fom(struct msgb *mb)
-{
- struct abis_om_hdr *oh = msgb_l2(mb);
- struct abis_om_fom_hdr *foh = msgb_l3(mb);
- u_int8_t mt = foh->msg_type;
-
- /* check for unsolicited message */
- if (is_report(mt))
- return abis_nm_rcvmsg_report(mb);
-
- if (is_in_arr(mt, sw_load_msgs, ARRAY_SIZE(sw_load_msgs)))
- return abis_nm_rcvmsg_sw(mb);
-
- if (is_in_arr(mt, nacks, ARRAY_SIZE(nacks))) {
- struct tlv_parsed tp;
- if (nack_names[mt])
- DEBUGP(DNM, "%s NACK ", nack_names[mt]);
- /* FIXME: NACK cause */
- else
- DEBUGP(DNM, "NACK 0x%02x ", mt);
-
- abis_nm_tlv_parse(&tp, foh->data, oh->length-sizeof(*foh));
- if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
- DEBUGPC(DNM, "CAUSE=%s\n",
- nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
- else
- DEBUGPC(DNM, "\n");
- }
-#if 0
- /* check if last message is to be acked */
- if (is_ack_nack(nmh->last_msgtype)) {
- if (mt == MT_ACK(nmh->last_msgtype)) {
- fprintf(stderr, "received ACK (0x%x)\n",
- foh->msg_type);
- /* we got our ACK, continue sending the next msg */
- } else if (mt == MT_NACK(nmh->last_msgtype)) {
- /* we got a NACK, signal this to the caller */
- fprintf(stderr, "received NACK (0x%x)\n",
- foh->msg_type);
- /* FIXME: somehow signal this to the caller */
- } else {
- /* really strange things happen */
- return -EINVAL;
- }
- }
-#endif
-
- switch (mt) {
- case NM_MT_CHG_ADM_STATE_ACK:
- return abis_nm_rx_chg_adm_state_ack(mb);
- break;
- case NM_MT_SW_ACT_REQ:
- return abis_nm_rx_sw_act_req(mb);
- break;
- case NM_MT_BS11_LMT_SESSION:
- return abis_nm_rx_lmt_event(mb);
- break;
- }
-
- return 0;
-}
-
-static int abis_nm_rx_ipacc(struct msgb *mb);
-
-static int abis_nm_rcvmsg_manuf(struct msgb *mb)
-{
- int rc;
- int bts_type = mb->trx->bts->type;
-
- switch (bts_type) {
- case GSM_BTS_TYPE_NANOBTS_900:
- case GSM_BTS_TYPE_NANOBTS_1800:
- rc = abis_nm_rx_ipacc(mb);
- break;
- default:
- fprintf(stderr, "don't know how to parse OML for this "
- "BTS type (%u)\n", bts_type);
- rc = 0;
- break;
- }
-
- return rc;
-}
-
-/* High-Level API */
-/* Entry-point where L2 OML from BTS enters the NM code */
-int abis_nm_rcvmsg(struct msgb *msg)
-{
- struct abis_om_hdr *oh = msgb_l2(msg);
- int rc = 0;
-
- /* Various consistency checks */
- if (oh->placement != ABIS_OM_PLACEMENT_ONLY) {
- fprintf(stderr, "ABIS OML placement 0x%x not supported\n",
- oh->placement);
- return -EINVAL;
- }
- if (oh->sequence != 0) {
- fprintf(stderr, "ABIS OML sequence 0x%x != 0x00\n",
- oh->sequence);
- return -EINVAL;
- }
-#if 0
- unsigned int l2_len = msg->tail - (u_int8_t *)msgb_l2(msg);
- unsigned int hlen = sizeof(*oh) + sizeof(struct abis_om_fom_hdr);
- if (oh->length + hlen > l2_len) {
- fprintf(stderr, "ABIS OML truncated message (%u > %u)\n",
- oh->length + sizeof(*oh), l2_len);
- return -EINVAL;
- }
- if (oh->length + hlen < l2_len)
- fprintf(stderr, "ABIS OML message with extra trailer?!? (oh->len=%d, sizeof_oh=%d l2_len=%d\n", oh->length, sizeof(*oh), l2_len);
-#endif
- msg->l3h = (unsigned char *)oh + sizeof(*oh);
-
- switch (oh->mdisc) {
- case ABIS_OM_MDISC_FOM:
- rc = abis_nm_rcvmsg_fom(msg);
- break;
- case ABIS_OM_MDISC_MANUF:
- rc = abis_nm_rcvmsg_manuf(msg);
- break;
- case ABIS_OM_MDISC_MMI:
- case ABIS_OM_MDISC_TRAU:
- fprintf(stderr, "unimplemented ABIS OML message discriminator 0x%x\n",
- oh->mdisc);
- break;
- default:
- fprintf(stderr, "unknown ABIS OML message discriminator 0x%x\n",
- oh->mdisc);
- return -EINVAL;
- }
-
- msgb_free(msg);
- return rc;
-}
-
-#if 0
-/* initialized all resources */
-struct abis_nm_h *abis_nm_init(struct abis_nm_cfg *cfg)
-{
- struct abis_nm_h *nmh;
-
- nmh = malloc(sizeof(*nmh));
- if (!nmh)
- return NULL;
-
- nmh->cfg = cfg;
-
- return nmh;
-}
-
-/* free all resources */
-void abis_nm_fini(struct abis_nm_h *nmh)
-{
- free(nmh);
-}
-#endif
-
-/* Here we are trying to define a high-level API that can be used by
- * the actual BSC implementation. However, the architecture is currently
- * still under design. Ideally the calls to this API would be synchronous,
- * while the underlying stack behind the APi runs in a traditional select
- * based state machine.
- */
-
-/* 6.2 Software Load: */
-enum sw_state {
- SW_STATE_NONE,
- SW_STATE_WAIT_INITACK,
- SW_STATE_WAIT_SEGACK,
- SW_STATE_WAIT_ENDACK,
- SW_STATE_WAIT_ACTACK,
- SW_STATE_ERROR,
-};
-
-struct abis_nm_sw {
- struct gsm_bts *bts;
- gsm_cbfn *cbfn;
- void *cb_data;
- int forced;
-
- /* this will become part of the SW LOAD INITIATE */
- u_int8_t obj_class;
- u_int8_t obj_instance[3];
-
- u_int8_t file_id[255];
- u_int8_t file_id_len;
-
- u_int8_t file_version[255];
- u_int8_t file_version_len;
-
- u_int8_t window_size;
- u_int8_t seg_in_window;
-
- int fd;
- FILE *stream;
- enum sw_state state;
- int last_seg;
-};
-
-static struct abis_nm_sw g_sw;
-
-/* 6.2.1 / 8.3.1: Load Data Initiate */
-static int sw_load_init(struct abis_nm_sw *sw)
-{
- struct abis_om_hdr *oh;
- struct msgb *msg = nm_msgb_alloc();
- u_int8_t len = 3*2 + sw->file_id_len + sw->file_version_len;
-
- oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
- fill_om_fom_hdr(oh, len, NM_MT_LOAD_INIT, sw->obj_class,
- sw->obj_instance[0], sw->obj_instance[1],
- sw->obj_instance[2]);
-
- /* FIXME: this is BS11 specific format */
- msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
- msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
- sw->file_version);
- msgb_tv_put(msg, NM_ATT_WINDOW_SIZE, sw->window_size);
-
- return abis_nm_sendmsg(sw->bts, msg);
-}
-
-static int is_last_line(FILE *stream)
-{
- char next_seg_buf[256];
- long pos;
-
- /* check if we're sending the last line */
- pos = ftell(stream);
- if (!fgets(next_seg_buf, sizeof(next_seg_buf)-2, stream)) {
- fseek(stream, pos, SEEK_SET);
- return 1;
- }
-
- fseek(stream, pos, SEEK_SET);
- return 0;
-}
-
-/* 6.2.2 / 8.3.2 Load Data Segment */
-static int sw_load_segment(struct abis_nm_sw *sw)
-{
- struct abis_om_hdr *oh;
- struct msgb *msg = nm_msgb_alloc();
- char seg_buf[256];
- char *line_buf = seg_buf+2;
- unsigned char *tlv;
- u_int8_t len;
-
- oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
-
- switch (sw->bts->type) {
- case GSM_BTS_TYPE_BS11:
- if (fgets(line_buf, sizeof(seg_buf)-2, sw->stream) == NULL) {
- perror("fgets reading segment");
- return -EINVAL;
- }
- seg_buf[0] = 0x00;
-
- /* check if we're sending the last line */
- sw->last_seg = is_last_line(sw->stream);
- if (sw->last_seg)
- seg_buf[1] = 0;
- else
- seg_buf[1] = 1 + sw->seg_in_window++;
-
- len = strlen(line_buf) + 2;
- tlv = msgb_put(msg, TLV_GROSS_LEN(len));
- tlv_put(tlv, NM_ATT_BS11_FILE_DATA, len, (u_int8_t *)seg_buf);
- /* BS11 wants CR + LF in excess of the TLV length !?! */
- tlv[1] -= 2;
-
- /* we only now know the exact length for the OM hdr */
- len = strlen(line_buf)+2;
- break;
- default:
- /* FIXME: Other BTS types */
- return -1;
- }
-
- fill_om_fom_hdr(oh, len, NM_MT_LOAD_SEG, sw->obj_class,
- sw->obj_instance[0], sw->obj_instance[1],
- sw->obj_instance[2]);
-
- return abis_nm_sendmsg(sw->bts, msg);
-}
-
-/* 6.2.4 / 8.3.4 Load Data End */
-static int sw_load_end(struct abis_nm_sw *sw)
-{
- struct abis_om_hdr *oh;
- struct msgb *msg = nm_msgb_alloc();
- u_int8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
-
- oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
- fill_om_fom_hdr(oh, len, NM_MT_LOAD_END, sw->obj_class,
- sw->obj_instance[0], sw->obj_instance[1],
- sw->obj_instance[2]);
-
- /* FIXME: this is BS11 specific format */
- msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
- msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
- sw->file_version);
-
- return abis_nm_sendmsg(sw->bts, msg);
-}
-
-/* Activate the specified software into the BTS */
-static int sw_activate(struct abis_nm_sw *sw)
-{
- struct abis_om_hdr *oh;
- struct msgb *msg = nm_msgb_alloc();
- u_int8_t len = 2*2 + sw->file_id_len + sw->file_version_len;
-
- oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
- fill_om_fom_hdr(oh, len, NM_MT_ACTIVATE_SW, sw->obj_class,
- sw->obj_instance[0], sw->obj_instance[1],
- sw->obj_instance[2]);
-
- /* FIXME: this is BS11 specific format */
- msgb_tlv_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
- msgb_tlv_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
- sw->file_version);
-
- return abis_nm_sendmsg(sw->bts, msg);
-}
-
-static int sw_open_file(struct abis_nm_sw *sw, const char *fname)
-{
- char file_id[12+1];
- char file_version[80+1];
- int rc;
-
- sw->fd = open(fname, O_RDONLY);
- if (sw->fd < 0)
- return sw->fd;
-
- switch (sw->bts->type) {
- case GSM_BTS_TYPE_BS11:
- sw->stream = fdopen(sw->fd, "r");
- if (!sw->stream) {
- perror("fdopen");
- return -1;
- }
- /* read first line and parse file ID and VERSION */
- rc = fscanf(sw->stream, "@(#)%12s:%80s\r\n",
- file_id, file_version);
- if (rc != 2) {
- perror("parsing header line of software file");
- return -1;
- }
- strcpy((char *)sw->file_id, file_id);
- sw->file_id_len = strlen(file_id);
- strcpy((char *)sw->file_version, file_version);
- sw->file_version_len = strlen(file_version);
- /* rewind to start of file */
- rewind(sw->stream);
- break;
- default:
- /* We don't know how to treat them yet */
- close(sw->fd);
- return -EINVAL;
- }
-
- return 0;
-}
-
-static void sw_close_file(struct abis_nm_sw *sw)
-{
- switch (sw->bts->type) {
- case GSM_BTS_TYPE_BS11:
- fclose(sw->stream);
- break;
- default:
- close(sw->fd);
- break;
- }
-}
-
-/* Fill the window */
-static int sw_fill_window(struct abis_nm_sw *sw)
-{
- int rc;
-
- while (sw->seg_in_window < sw->window_size) {
- rc = sw_load_segment(sw);
- if (rc < 0)
- return rc;
- if (sw->last_seg)
- break;
- }
- return 0;
-}
-
-/* callback function from abis_nm_rcvmsg() handler */
-static int abis_nm_rcvmsg_sw(struct msgb *mb)
-{
- struct abis_om_fom_hdr *foh = msgb_l3(mb);
- int rc = -1;
- struct abis_nm_sw *sw = &g_sw;
- enum sw_state old_state = sw->state;
-
- //DEBUGP(DNM, "state %u, NM MT 0x%02x\n", sw->state, foh->msg_type);
-
- switch (sw->state) {
- case SW_STATE_WAIT_INITACK:
- switch (foh->msg_type) {
- case NM_MT_LOAD_INIT_ACK:
- /* fill window with segments */
- if (sw->cbfn)
- sw->cbfn(GSM_HOOK_NM_SWLOAD,
- NM_MT_LOAD_INIT_ACK, mb,
- sw->cb_data, NULL);
- rc = sw_fill_window(sw);
- sw->state = SW_STATE_WAIT_SEGACK;
- break;
- case NM_MT_LOAD_INIT_NACK:
- if (sw->forced) {
- DEBUGP(DNM, "FORCED: Ignoring Software Load "
- "Init NACK\n");
- if (sw->cbfn)
- sw->cbfn(GSM_HOOK_NM_SWLOAD,
- NM_MT_LOAD_INIT_ACK, mb,
- sw->cb_data, NULL);
- rc = sw_fill_window(sw);
- sw->state = SW_STATE_WAIT_SEGACK;
- } else {
- DEBUGP(DNM, "Software Load Init NACK\n");
- /* FIXME: cause */
- if (sw->cbfn)
- sw->cbfn(GSM_HOOK_NM_SWLOAD,
- NM_MT_LOAD_INIT_NACK, mb,
- sw->cb_data, NULL);
- sw->state = SW_STATE_ERROR;
- }
- break;
- }
- break;
- case SW_STATE_WAIT_SEGACK:
- switch (foh->msg_type) {
- case NM_MT_LOAD_SEG_ACK:
- if (sw->cbfn)
- sw->cbfn(GSM_HOOK_NM_SWLOAD,
- NM_MT_LOAD_SEG_ACK, mb,
- sw->cb_data, NULL);
- sw->seg_in_window = 0;
- if (!sw->last_seg) {
- /* fill window with more segments */
- rc = sw_fill_window(sw);
- sw->state = SW_STATE_WAIT_SEGACK;
- } else {
- /* end the transfer */
- sw->state = SW_STATE_WAIT_ENDACK;
- rc = sw_load_end(sw);
- }
- break;
- }
- break;
- case SW_STATE_WAIT_ENDACK:
- switch (foh->msg_type) {
- case NM_MT_LOAD_END_ACK:
- sw_close_file(sw);
- DEBUGP(DNM, "Software Load End (BTS %u)\n",
- sw->bts->nr);
- sw->state = SW_STATE_NONE;
- if (sw->cbfn)
- sw->cbfn(GSM_HOOK_NM_SWLOAD,
- NM_MT_LOAD_END_ACK, mb,
- sw->cb_data, NULL);
- break;
- case NM_MT_LOAD_END_NACK:
- if (sw->forced) {
- DEBUGP(DNM, "FORCED: Ignoring Software Load"
- "End NACK\n");
- sw->state = SW_STATE_NONE;
- if (sw->cbfn)
- sw->cbfn(GSM_HOOK_NM_SWLOAD,
- NM_MT_LOAD_END_ACK, mb,
- sw->cb_data, NULL);
- } else {
- DEBUGP(DNM, "Software Load End NACK\n");
- /* FIXME: cause */
- sw->state = SW_STATE_ERROR;
- if (sw->cbfn)
- sw->cbfn(GSM_HOOK_NM_SWLOAD,
- NM_MT_LOAD_END_NACK, mb,
- sw->cb_data, NULL);
- }
- break;
- }
- case SW_STATE_WAIT_ACTACK:
- switch (foh->msg_type) {
- case NM_MT_ACTIVATE_SW_ACK:
- /* we're done */
- DEBUGP(DNM, "Activate Software DONE!\n");
- sw->state = SW_STATE_NONE;
- rc = 0;
- if (sw->cbfn)
- sw->cbfn(GSM_HOOK_NM_SWLOAD,
- NM_MT_ACTIVATE_SW_ACK, mb,
- sw->cb_data, NULL);
- break;
- case NM_MT_ACTIVATE_SW_NACK:
- DEBUGP(DNM, "Activate Software NACK\n");
- /* FIXME: cause */
- sw->state = SW_STATE_ERROR;
- if (sw->cbfn)
- sw->cbfn(GSM_HOOK_NM_SWLOAD,
- NM_MT_ACTIVATE_SW_NACK, mb,
- sw->cb_data, NULL);
- break;
- }
- case SW_STATE_NONE:
- switch (foh->msg_type) {
- case NM_MT_ACTIVATE_SW_ACK:
- rc = 0;
- break;
- }
- break;
- case SW_STATE_ERROR:
- break;
- }
-
- if (rc)
- DEBUGP(DNM, "unexpected NM MT 0x%02x in state %u -> %u\n",
- foh->msg_type, old_state, sw->state);
-
- return rc;
-}
-
-/* Load the specified software into the BTS */
-int abis_nm_software_load(struct gsm_bts *bts, const char *fname,
- u_int8_t win_size, int forced,
- gsm_cbfn *cbfn, void *cb_data)
-{
- struct abis_nm_sw *sw = &g_sw;
- int rc;
-
- DEBUGP(DNM, "Software Load (BTS %u, File \"%s\")\n",
- bts->nr, fname);
-
- if (sw->state != SW_STATE_NONE)
- return -EBUSY;
-
- sw->bts = bts;
- sw->obj_class = NM_OC_SITE_MANAGER;
- sw->obj_instance[0] = 0xff;
- sw->obj_instance[1] = 0xff;
- sw->obj_instance[2] = 0xff;
- sw->window_size = win_size;
- sw->state = SW_STATE_WAIT_INITACK;
- sw->cbfn = cbfn;
- sw->cb_data = cb_data;
- sw->forced = forced;
-
- rc = sw_open_file(sw, fname);
- if (rc < 0) {
- sw->state = SW_STATE_NONE;
- return rc;
- }
-
- return sw_load_init(sw);
-}
-
-int abis_nm_software_load_status(struct gsm_bts *bts)
-{
- struct abis_nm_sw *sw = &g_sw;
- struct stat st;
- int rc, percent;
-
- rc = fstat(sw->fd, &st);
- if (rc < 0) {
- perror("ERROR during stat");
- return rc;
- }
-
- percent = (ftell(sw->stream) * 100) / st.st_size;
- return percent;
-}
-
-/* Activate the specified software into the BTS */
-int abis_nm_software_activate(struct gsm_bts *bts, const char *fname,
- gsm_cbfn *cbfn, void *cb_data)
-{
- struct abis_nm_sw *sw = &g_sw;
- int rc;
-
- DEBUGP(DNM, "Activating Software (BTS %u, File \"%s\")\n",
- bts->nr, fname);
-
- if (sw->state != SW_STATE_NONE)
- return -EBUSY;
-
- sw->bts = bts;
- sw->obj_class = NM_OC_SITE_MANAGER;
- sw->obj_instance[0] = 0xff;
- sw->obj_instance[1] = 0xff;
- sw->obj_instance[2] = 0xff;
- sw->state = SW_STATE_WAIT_ACTACK;
- sw->cbfn = cbfn;
- sw->cb_data = cb_data;
-
- /* Open the file in order to fill some sw struct members */
- rc = sw_open_file(sw, fname);
- if (rc < 0) {
- sw->state = SW_STATE_NONE;
- return rc;
- }
- sw_close_file(sw);
-
- return sw_activate(sw);
-}
-
-static void fill_nm_channel(struct abis_nm_channel *ch, u_int8_t bts_port,
- u_int8_t ts_nr, u_int8_t subslot_nr)
-{
- ch->attrib = NM_ATT_ABIS_CHANNEL;
- ch->bts_port = bts_port;
- ch->timeslot = ts_nr;
- ch->subslot = subslot_nr;
-}
-
-int abis_nm_establish_tei(struct gsm_bts *bts, u_int8_t trx_nr,
- u_int8_t e1_port, u_int8_t e1_timeslot, u_int8_t e1_subslot,
- u_int8_t tei)
-{
- struct abis_om_hdr *oh;
- struct abis_nm_channel *ch;
- u_int8_t len = sizeof(*ch) + 2;
- struct msgb *msg = nm_msgb_alloc();
-
- oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
- fill_om_fom_hdr(oh, len, NM_MT_ESTABLISH_TEI, NM_OC_RADIO_CARRIER,
- bts->bts_nr, trx_nr, 0xff);
-
- msgb_tv_put(msg, NM_ATT_TEI, tei);
-
- ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
- fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
-
- return abis_nm_sendmsg(bts, msg);
-}
-
-/* connect signalling of one (BTS,TRX) to a particular timeslot on the E1 */
-int abis_nm_conn_terr_sign(struct gsm_bts_trx *trx,
- u_int8_t e1_port, u_int8_t e1_timeslot, u_int8_t e1_subslot)
-{
- struct gsm_bts *bts = trx->bts;
- struct abis_om_hdr *oh;
- struct abis_nm_channel *ch;
- struct msgb *msg = nm_msgb_alloc();
-
- oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
- fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_SIGN,
- NM_OC_RADIO_CARRIER, bts->bts_nr, trx->nr, 0xff);
-
- ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
- fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
-
- return abis_nm_sendmsg(bts, msg);
-}
-
-#if 0
-int abis_nm_disc_terr_sign(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
- struct abis_nm_abis_channel *chan)
-{
-}
-#endif
-
-int abis_nm_conn_terr_traf(struct gsm_bts_trx_ts *ts,
- u_int8_t e1_port, u_int8_t e1_timeslot,
- u_int8_t e1_subslot)
-{
- struct gsm_bts *bts = ts->trx->bts;
- struct abis_om_hdr *oh;
- struct abis_nm_channel *ch;
- struct msgb *msg = nm_msgb_alloc();
-
- oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
- fill_om_fom_hdr(oh, sizeof(*ch), NM_MT_CONN_TERR_TRAF,
- NM_OC_CHANNEL, bts->bts_nr, ts->trx->nr, ts->nr);
-
- ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
- fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
-
- DEBUGP(DNM, "CONNECT TERR TRAF Um=%s E1=(%u,%u,%u)\n",
- gsm_ts_name(ts),
- e1_port, e1_timeslot, e1_subslot);
-
- return abis_nm_sendmsg(bts, msg);
-}
-
-#if 0
-int abis_nm_disc_terr_traf(struct abis_nm_h *h, struct abis_om_obj_inst *inst,
- struct abis_nm_abis_channel *chan,
- u_int8_t subchan)
-{
-}
-#endif
-
-/* Chapter 8.6.1 */
-int abis_nm_set_bts_attr(struct gsm_bts *bts, u_int8_t *attr, int attr_len)
-{
- struct abis_om_hdr *oh;
- struct msgb *msg = nm_msgb_alloc();
- u_int8_t *cur;
-
- DEBUGP(DNM, "Set BTS Attr (bts=%d)\n", bts->nr);
-
- oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
- fill_om_fom_hdr(oh, attr_len, NM_MT_SET_BTS_ATTR, NM_OC_BTS, bts->bts_nr, 0xff, 0xff);
- cur = msgb_put(msg, attr_len);
- memcpy(cur, attr, attr_len);
-
- return abis_nm_sendmsg(bts, msg);
-}
-
-/* Chapter 8.6.2 */
-int abis_nm_set_radio_attr(struct gsm_bts_trx *trx, u_int8_t *attr, int attr_len)
-{
- struct abis_om_hdr *oh;
- struct msgb *msg = nm_msgb_alloc();
- u_int8_t *cur;
-
- DEBUGP(DNM, "Set TRX Attr (bts=%d,trx=%d)\n", trx->bts->nr, trx->nr);
-
- oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
- fill_om_fom_hdr(oh, attr_len, NM_MT_SET_RADIO_ATTR, NM_OC_RADIO_CARRIER,
- trx->bts->bts_nr, trx->nr, 0xff);
- cur = msgb_put(msg, attr_len);
- memcpy(cur, attr, attr_len);
-
- return abis_nm_sendmsg(trx->bts, msg);
-}
-
-/* Chapter 8.6.3 */
-int abis_nm_set_channel_attr(struct gsm_bts_trx_ts *ts, u_int8_t chan_comb)
-{
- struct gsm_bts *bts = ts->trx->bts;
- struct abis_om_hdr *oh;
- u_int16_t arfcn = htons(ts->trx->arfcn);
- u_int8_t zero = 0x00;
- struct msgb *msg = nm_msgb_alloc();
- u_int8_t len = 2 + 2;
-
- if (bts->type == GSM_BTS_TYPE_BS11)
- len += 4 + 2 + 2 + 3;
-
- DEBUGP(DNM, "Set Chan Attr %s\n", gsm_ts_name(ts));
-
- oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
- fill_om_fom_hdr(oh, len, NM_MT_SET_CHAN_ATTR,
- NM_OC_CHANNEL, bts->bts_nr,
- ts->trx->nr, ts->nr);
- /* FIXME: don't send ARFCN list, hopping sequence, mAIO, ...*/
- if (bts->type == GSM_BTS_TYPE_BS11)
- msgb_tlv16_put(msg, NM_ATT_ARFCN_LIST, 1, &arfcn);
- msgb_tv_put(msg, NM_ATT_CHAN_COMB, chan_comb);
- if (bts->type == GSM_BTS_TYPE_BS11) {
- msgb_tv_put(msg, NM_ATT_HSN, 0x00);
- msgb_tv_put(msg, NM_ATT_MAIO, 0x00);
- }
- msgb_tv_put(msg, NM_ATT_TSC, 0x07); /* training sequence */
- if (bts->type == GSM_BTS_TYPE_BS11)
- msgb_tlv_put(msg, 0x59, 1, &zero);
-
- return abis_nm_sendmsg(bts, msg);
-}
-
-int abis_nm_sw_act_req_ack(struct gsm_bts *bts, u_int8_t obj_class, u_int8_t i1,
- u_int8_t i2, u_int8_t i3, int nack, u_int8_t *attr, int att_len)
-{
- struct abis_om_hdr *oh;
- struct msgb *msg = nm_msgb_alloc();
- u_int8_t msgtype = NM_MT_SW_ACT_REQ_ACK;
- u_int8_t len = att_len;
-
- if (nack) {
- len += 2;
- msgtype = NM_MT_SW_ACT_REQ_NACK;
- }
-
- oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
- fill_om_fom_hdr(oh, att_len, msgtype, obj_class, i1, i2, i3);
-
- if (attr) {
- u_int8_t *ptr = msgb_put(msg, att_len);
- memcpy(ptr, attr, att_len);
- }
- if (nack)
- msgb_tv_put(msg, NM_ATT_NACK_CAUSES, NM_NACK_OBJCLASS_NOTSUPP);
-
- return abis_nm_sendmsg(bts, msg);
-}
-
-int abis_nm_raw_msg(struct gsm_bts *bts, int len, u_int8_t *rawmsg)
-{
- struct msgb *msg = nm_msgb_alloc();
- struct abis_om_hdr *oh;
- u_int8_t *data;
-
- oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
- fill_om_hdr(oh, len);
- data = msgb_put(msg, len);
- memcpy(data, rawmsg, len);
-
- return abis_nm_sendmsg(bts, msg);
-}
-
-/* Siemens specific commands */
-static int __simple_cmd(struct gsm_bts *bts, u_int8_t msg_type)
-{
- struct abis_om_hdr *oh;
- struct msgb *msg = nm_msgb_alloc();
-
- oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
- fill_om_fom_hdr(oh, 0, msg_type, NM_OC_SITE_MANAGER,
- 0xff, 0xff, 0xff);
-
- return abis_nm_sendmsg(bts, msg);
-}
-
-/* Chapter 8.9.2 */
-int abis_nm_opstart(struct gsm_bts *bts, u_int8_t obj_class, u_int8_t i0, u_int8_t i1, u_int8_t i2)
-{
- struct abis_om_hdr *oh;
- struct msgb *msg = nm_msgb_alloc();
-
- DEBUGP(DNM, "Sending OPSTART obj_class=0x%02x obj_inst=(0x%02x, 0x%02x, 0x%02x)\n",
- obj_class, i0, i1, i2);
- oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
- fill_om_fom_hdr(oh, 0, NM_MT_OPSTART, obj_class, i0, i1, i2);
-
- return abis_nm_sendmsg(bts, msg);
-}
-
-/* Chapter 8.8.5 */
-int abis_nm_chg_adm_state(struct gsm_bts *bts, u_int8_t obj_class, u_int8_t i0,
- u_int8_t i1, u_int8_t i2, u_int8_t adm_state)
-{
- struct abis_om_hdr *oh;
- struct msgb *msg = nm_msgb_alloc();
-
- oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
- fill_om_fom_hdr(oh, 2, NM_MT_CHG_ADM_STATE, obj_class, i0, i1, i2);
- msgb_tv_put(msg, NM_ATT_ADM_STATE, adm_state);
-
- return abis_nm_sendmsg(bts, msg);
-}
-
-
-int abis_nm_event_reports(struct gsm_bts *bts, int on)
-{
- if (on == 0)
- return __simple_cmd(bts, NM_MT_STOP_EVENT_REP);
- else
- return __simple_cmd(bts, NM_MT_REST_EVENT_REP);
-}
-
-/* Siemens (or BS-11) specific commands */
-
-int abis_nm_bs11_bsc_disconnect(struct gsm_bts *bts, int reconnect)
-{
- if (reconnect == 0)
- return __simple_cmd(bts, NM_MT_BS11_DISCONNECT);
- else
- return __simple_cmd(bts, NM_MT_BS11_RECONNECT);
-}
-
-int abis_nm_bs11_restart(struct gsm_bts *bts)
-{
- return __simple_cmd(bts, NM_MT_BS11_RESTART);
-}
-
-
-struct bs11_date_time {
- u_int16_t year;
- u_int8_t month;
- u_int8_t day;
- u_int8_t hour;
- u_int8_t min;
- u_int8_t sec;
-} __attribute__((packed));
-
-
-void get_bs11_date_time(struct bs11_date_time *aet)
-{
- time_t t;
- struct tm *tm;
-
- t = time(NULL);
- tm = localtime(&t);
- aet->sec = tm->tm_sec;
- aet->min = tm->tm_min;
- aet->hour = tm->tm_hour;
- aet->day = tm->tm_mday;
- aet->month = tm->tm_mon;
- aet->year = htons(1900 + tm->tm_year);
-}
-
-int abis_nm_bs11_reset_resource(struct gsm_bts *bts)
-{
- return __simple_cmd(bts, NM_MT_BS11_RESET_RESOURCE);
-}
-
-int abis_nm_bs11_db_transmission(struct gsm_bts *bts, int begin)
-{
- if (begin)
- return __simple_cmd(bts, NM_MT_BS11_BEGIN_DB_TX);
- else
- return __simple_cmd(bts, NM_MT_BS11_END_DB_TX);
-}
-
-int abis_nm_bs11_create_object(struct gsm_bts *bts,
- enum abis_bs11_objtype type, u_int8_t idx,
- u_int8_t attr_len, const u_int8_t *attr)
-{
- struct abis_om_hdr *oh;
- struct msgb *msg = nm_msgb_alloc();
- u_int8_t *cur;
-
- oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
- fill_om_fom_hdr(oh, attr_len, NM_MT_BS11_CREATE_OBJ,
- NM_OC_BS11, type, 0, idx);
- cur = msgb_put(msg, attr_len);
- memcpy(cur, attr, attr_len);
-
- return abis_nm_sendmsg(bts, msg);
-}
-
-int abis_nm_bs11_delete_object(struct gsm_bts *bts,
- enum abis_bs11_objtype type, u_int8_t idx)
-{
- struct abis_om_hdr *oh;
- struct msgb *msg = nm_msgb_alloc();
-
- oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
- fill_om_fom_hdr(oh, 0, NM_MT_BS11_DELETE_OBJ,
- NM_OC_BS11, type, 0, idx);
-
- return abis_nm_sendmsg(bts, msg);
-}
-
-int abis_nm_bs11_create_envaBTSE(struct gsm_bts *bts, u_int8_t idx)
-{
- struct abis_om_hdr *oh;
- struct msgb *msg = nm_msgb_alloc();
- u_int8_t zero = 0x00;
-
- oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
- fill_om_fom_hdr(oh, 3, NM_MT_BS11_CREATE_OBJ,
- NM_OC_BS11_ENVABTSE, 0, idx, 0xff);
- msgb_tlv_put(msg, 0x99, 1, &zero);
-
- return abis_nm_sendmsg(bts, msg);
-}
-
-int abis_nm_bs11_create_bport(struct gsm_bts *bts, u_int8_t idx)
-{
- struct abis_om_hdr *oh;
- struct msgb *msg = nm_msgb_alloc();
-
- oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
- fill_om_fom_hdr(oh, 0, NM_MT_BS11_CREATE_OBJ, NM_OC_BS11_BPORT,
- idx, 0, 0);
-
- return abis_nm_sendmsg(bts, msg);
-}
-
-static const u_int8_t sm_attr[] = { NM_ATT_TEI, NM_ATT_ABIS_CHANNEL };
-int abis_nm_bs11_get_oml_tei_ts(struct gsm_bts *bts)
-{
- struct abis_om_hdr *oh;
- struct msgb *msg = nm_msgb_alloc();
-
- oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
- fill_om_fom_hdr(oh, 2+sizeof(sm_attr), NM_MT_GET_ATTR, NM_OC_SITE_MANAGER,
- 0xff, 0xff, 0xff);
- msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(sm_attr), sm_attr);
-
- return abis_nm_sendmsg(bts, msg);
-}
-
-/* like abis_nm_conn_terr_traf + set_tei */
-int abis_nm_bs11_conn_oml_tei(struct gsm_bts *bts, u_int8_t e1_port,
- u_int8_t e1_timeslot, u_int8_t e1_subslot,
- u_int8_t tei)
-{
- struct abis_om_hdr *oh;
- struct abis_nm_channel *ch;
- struct msgb *msg = nm_msgb_alloc();
-
- oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
- fill_om_fom_hdr(oh, sizeof(*ch)+2, NM_MT_BS11_SET_ATTR,
- NM_OC_SITE_MANAGER, 0xff, 0xff, 0xff);
-
- ch = (struct abis_nm_channel *) msgb_put(msg, sizeof(*ch));
- fill_nm_channel(ch, e1_port, e1_timeslot, e1_subslot);
- msgb_tv_put(msg, NM_ATT_TEI, tei);
-
- return abis_nm_sendmsg(bts, msg);
-}
-
-int abis_nm_bs11_set_trx_power(struct gsm_bts_trx *trx, u_int8_t level)
-{
- struct abis_om_hdr *oh;
- struct msgb *msg = nm_msgb_alloc();
-
- oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
- fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR,
- NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
- msgb_tlv_put(msg, NM_ATT_BS11_TXPWR, 1, &level);
-
- return abis_nm_sendmsg(trx->bts, msg);
-}
-
-int abis_nm_bs11_get_trx_power(struct gsm_bts_trx *trx)
-{
- struct abis_om_hdr *oh;
- struct msgb *msg = nm_msgb_alloc();
- u_int8_t attr = NM_ATT_BS11_TXPWR;
-
- oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
- fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
- NM_OC_BS11, BS11_OBJ_PA, 0x00, trx->nr);
- msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr);
-
- return abis_nm_sendmsg(trx->bts, msg);
-}
-
-int abis_nm_bs11_get_pll_mode(struct gsm_bts *bts)
-{
- struct abis_om_hdr *oh;
- struct msgb *msg = nm_msgb_alloc();
- u_int8_t attr[] = { NM_ATT_BS11_PLL_MODE };
-
- oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
- fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
- NM_OC_BS11, BS11_OBJ_LI, 0x00, 0x00);
- msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
-
- return abis_nm_sendmsg(bts, msg);
-}
-
-int abis_nm_bs11_get_cclk(struct gsm_bts *bts)
-{
- struct abis_om_hdr *oh;
- struct msgb *msg = nm_msgb_alloc();
- u_int8_t attr[] = { NM_ATT_BS11_CCLK_ACCURACY,
- NM_ATT_BS11_CCLK_TYPE };
-
- oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
- fill_om_fom_hdr(oh, 2+sizeof(attr), NM_MT_GET_ATTR,
- NM_OC_BS11, BS11_OBJ_CCLK, 0x00, 0x00);
- msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), attr);
-
- return abis_nm_sendmsg(bts, msg);
-
-}
-
-//static const u_int8_t bs11_logon_c7[] = { 0x07, 0xd9, 0x01, 0x11, 0x0d, 0x10, 0x20 };
-static const u_int8_t bs11_logon_c8[] = { 0x02 };
-static const u_int8_t bs11_logon_c9[] = "FACTORY";
-
-int abis_nm_bs11_factory_logon(struct gsm_bts *bts, int on)
-{
- struct abis_om_hdr *oh;
- struct msgb *msg = nm_msgb_alloc();
- struct bs11_date_time bdt;
-
- get_bs11_date_time(&bdt);
-
- oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
- if (on) {
- u_int8_t len = 3*2 + sizeof(bdt)
- + sizeof(bs11_logon_c8) + sizeof(bs11_logon_c9);
- fill_om_fom_hdr(oh, len, NM_MT_BS11_LMT_LOGON,
- NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
- msgb_tlv_put(msg, NM_ATT_BS11_LMT_LOGIN_TIME,
- sizeof(bdt), (u_int8_t *) &bdt);
- msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_ACC_LEV,
- sizeof(bs11_logon_c8), bs11_logon_c8);
- msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_NAME,
- sizeof(bs11_logon_c9), bs11_logon_c9);
- } else {
- fill_om_fom_hdr(oh, 0, NM_MT_BS11_LMT_LOGOFF,
- NM_OC_BS11_BTSE, 0xff, 0xff, 0xff);
- }
-
- return abis_nm_sendmsg(bts, msg);
-}
-
-int abis_nm_bs11_set_trx1_pw(struct gsm_bts *bts, const char *password)
-{
- struct abis_om_hdr *oh;
- struct msgb *msg;
-
- if (strlen(password) != 10)
- return -EINVAL;
-
- msg = nm_msgb_alloc();
- oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
- fill_om_fom_hdr(oh, 2+strlen(password), NM_MT_BS11_SET_ATTR,
- NM_OC_BS11, BS11_OBJ_TRX1, 0x00, 0x00);
- msgb_tlv_put(msg, NM_ATT_BS11_PASSWORD, 10, (const u_int8_t *)password);
-
- return abis_nm_sendmsg(bts, msg);
-}
-
-/* change the BS-11 PLL Mode to either locked (E1 derived) or standalone */
-int abis_nm_bs11_set_pll_locked(struct gsm_bts *bts, int locked)
-{
- struct abis_om_hdr *oh;
- struct msgb *msg;
- u_int8_t tlv_value;
-
- msg = nm_msgb_alloc();
- oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
- fill_om_fom_hdr(oh, 3, NM_MT_BS11_SET_ATTR, NM_OC_BS11,
- BS11_OBJ_LI, 0x00, 0x00);
-
- if (locked)
- tlv_value = BS11_LI_PLL_LOCKED;
- else
- tlv_value = BS11_LI_PLL_STANDALONE;
-
- msgb_tlv_put(msg, NM_ATT_BS11_PLL_MODE, 1, &tlv_value);
-
- return abis_nm_sendmsg(bts, msg);
-}
-
-int abis_nm_bs11_get_state(struct gsm_bts *bts)
-{
- return __simple_cmd(bts, NM_MT_BS11_GET_STATE);
-}
-
-/* BS11 SWL */
-
-struct abis_nm_bs11_sw {
- struct gsm_bts *bts;
- char swl_fname[PATH_MAX];
- u_int8_t win_size;
- int forced;
- struct llist_head file_list;
- gsm_cbfn *user_cb; /* specified by the user */
-};
-static struct abis_nm_bs11_sw _g_bs11_sw, *g_bs11_sw = &_g_bs11_sw;
-
-struct file_list_entry {
- struct llist_head list;
- char fname[PATH_MAX];
-};
-
-struct file_list_entry *fl_dequeue(struct llist_head *queue)
-{
- struct llist_head *lh;
-
- if (llist_empty(queue))
- return NULL;
-
- lh = queue->next;
- llist_del(lh);
-
- return llist_entry(lh, struct file_list_entry, list);
-}
-
-static int bs11_read_swl_file(struct abis_nm_bs11_sw *bs11_sw)
-{
- char linebuf[255];
- struct llist_head *lh, *lh2;
- FILE *swl;
- int rc = 0;
-
- swl = fopen(bs11_sw->swl_fname, "r");
- if (!swl)
- return -ENODEV;
-
- /* zero the stale file list, if any */
- llist_for_each_safe(lh, lh2, &bs11_sw->file_list) {
- llist_del(lh);
- free(lh);
- }
-
- while (fgets(linebuf, sizeof(linebuf), swl)) {
- char file_id[12+1];
- char file_version[80+1];
- struct file_list_entry *fle;
- static char dir[PATH_MAX];
-
- if (strlen(linebuf) < 4)
- continue;
-
- rc = sscanf(linebuf+4, "%12s:%80s\r\n", file_id, file_version);
- if (rc < 0) {
- perror("ERR parsing SWL file");
- rc = -EINVAL;
- goto out;
- }
- if (rc < 2)
- continue;
-
- fle = malloc(sizeof(*fle));
- if (!fle) {
- rc = -ENOMEM;
- goto out;
- }
- memset(fle, 0, sizeof(*fle));
-
- /* construct new filename */
- strncpy(dir, bs11_sw->swl_fname, sizeof(dir));
- strncat(fle->fname, dirname(dir), sizeof(fle->fname) - 1);
- strcat(fle->fname, "/");
- strncat(fle->fname, file_id, sizeof(fle->fname) - 1 -strlen(fle->fname));
-
- llist_add_tail(&fle->list, &bs11_sw->file_list);
- }
-
-out:
- fclose(swl);
- return rc;
-}
-
-/* bs11 swload specific callback, passed to abis_nm core swload */
-static int bs11_swload_cbfn(unsigned int hook, unsigned int event,
- struct msgb *msg, void *data, void *param)
-{
- struct abis_nm_bs11_sw *bs11_sw = data;
- struct file_list_entry *fle;
- int rc = 0;
-
- switch (event) {
- case NM_MT_LOAD_END_ACK:
- fle = fl_dequeue(&bs11_sw->file_list);
- if (fle) {
- /* start download the next file of our file list */
- rc = abis_nm_software_load(bs11_sw->bts, fle->fname,
- bs11_sw->win_size,
- bs11_sw->forced,
- &bs11_swload_cbfn, bs11_sw);
- free(fle);
- } else {
- /* activate the SWL */
- rc = abis_nm_software_activate(bs11_sw->bts,
- bs11_sw->swl_fname,
- bs11_swload_cbfn,
- bs11_sw);
- }
- break;
- case NM_MT_LOAD_SEG_ACK:
- case NM_MT_LOAD_END_NACK:
- case NM_MT_LOAD_INIT_ACK:
- case NM_MT_LOAD_INIT_NACK:
- case NM_MT_ACTIVATE_SW_NACK:
- case NM_MT_ACTIVATE_SW_ACK:
- default:
- /* fallthrough to the user callback */
- if (bs11_sw->user_cb)
- rc = bs11_sw->user_cb(hook, event, msg, NULL, NULL);
- break;
- }
-
- return rc;
-}
-
-/* Siemens provides a SWL file that is a mere listing of all the other
- * files that are part of a software release. We need to upload first
- * the list file, and then each file that is listed in the list file */
-int abis_nm_bs11_load_swl(struct gsm_bts *bts, const char *fname,
- u_int8_t win_size, int forced, gsm_cbfn *cbfn)
-{
- struct abis_nm_bs11_sw *bs11_sw = g_bs11_sw;
- struct file_list_entry *fle;
- int rc = 0;
-
- INIT_LLIST_HEAD(&bs11_sw->file_list);
- bs11_sw->bts = bts;
- bs11_sw->win_size = win_size;
- bs11_sw->user_cb = cbfn;
- bs11_sw->forced = forced;
-
- strncpy(bs11_sw->swl_fname, fname, sizeof(bs11_sw->swl_fname));
- rc = bs11_read_swl_file(bs11_sw);
- if (rc < 0)
- return rc;
-
- /* dequeue next item in file list */
- fle = fl_dequeue(&bs11_sw->file_list);
- if (!fle)
- return -EINVAL;
-
- /* start download the next file of our file list */
- rc = abis_nm_software_load(bts, fle->fname, win_size, forced,
- bs11_swload_cbfn, bs11_sw);
- free(fle);
- return rc;
-}
-
-#if 0
-static u_int8_t req_attr_btse[] = {
- NM_ATT_ADM_STATE, NM_ATT_BS11_LMT_LOGON_SESSION,
- NM_ATT_BS11_LMT_LOGIN_TIME, NM_ATT_BS11_LMT_USER_ACC_LEV,
- NM_ATT_BS11_LMT_USER_NAME,
-
- 0xaf, NM_ATT_BS11_RX_OFFSET, NM_ATT_BS11_VENDOR_NAME,
-
- NM_ATT_BS11_SW_LOAD_INTENDED, NM_ATT_BS11_SW_LOAD_SAFETY,
-
- NM_ATT_BS11_SW_LOAD_STORED };
-
-static u_int8_t req_attr_btsm[] = {
- NM_ATT_ABIS_CHANNEL, NM_ATT_TEI, NM_ATT_BS11_ABIS_EXT_TIME,
- NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xce, NM_ATT_FILE_ID,
- NM_ATT_FILE_VERSION, NM_ATT_OPER_STATE, 0xe8, NM_ATT_BS11_ALL_TEST_CATG,
- NM_ATT_SW_DESCR, NM_ATT_GET_ARI };
-#endif
-
-static u_int8_t req_attr[] = {
- NM_ATT_ADM_STATE, NM_ATT_AVAIL_STATUS, 0xa8, NM_ATT_OPER_STATE,
- 0xd5, 0xa1, NM_ATT_BS11_ESN_FW_CODE_NO, NM_ATT_BS11_ESN_HW_CODE_NO,
- 0x42, NM_ATT_BS11_ESN_PCB_SERIAL, NM_ATT_BS11_PLL };
-
-int abis_nm_bs11_get_serno(struct gsm_bts *bts)
-{
- struct abis_om_hdr *oh;
- struct msgb *msg = nm_msgb_alloc();
-
- oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
- /* SiemensHW CCTRL object */
- fill_om_fom_hdr(oh, 2+sizeof(req_attr), NM_MT_GET_ATTR, NM_OC_BS11,
- 0x03, 0x00, 0x00);
- msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(req_attr), req_attr);
-
- return abis_nm_sendmsg(bts, msg);
-}
-
-int abis_nm_bs11_set_ext_time(struct gsm_bts *bts)
-{
- struct abis_om_hdr *oh;
- struct msgb *msg = nm_msgb_alloc();
- struct bs11_date_time aet;
-
- get_bs11_date_time(&aet);
- oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
- /* SiemensHW CCTRL object */
- fill_om_fom_hdr(oh, 2+sizeof(aet), NM_MT_BS11_SET_ATTR, NM_OC_SITE_MANAGER,
- 0xff, 0xff, 0xff);
- msgb_tlv_put(msg, NM_ATT_BS11_ABIS_EXT_TIME, sizeof(aet), (u_int8_t *) &aet);
-
- return abis_nm_sendmsg(bts, msg);
-}
-
-/* ip.access nanoBTS specific commands */
-static const char ipaccess_magic[] = "com.ipaccess";
-
-
-static int abis_nm_rx_ipacc(struct msgb *msg)
-{
- struct abis_om_hdr *oh = msgb_l2(msg);
- struct abis_om_fom_hdr *foh;
- u_int8_t idstrlen = oh->data[0];
- struct tlv_parsed tp;
-
- if (strncmp((char *)&oh->data[1], ipaccess_magic, idstrlen)) {
- DEBUGP(DNM, "id string is not com.ipaccess !?!\n");
- return -EINVAL;
- }
-
- foh = (struct abis_om_fom_hdr *) (oh->data + 1 + idstrlen);
- abis_nm_tlv_parse(&tp, foh->data, oh->length-sizeof(*foh));
-
- DEBUGP(DNM, "IPACCESS(0x%02x): ", foh->msg_type);
-
- switch (foh->msg_type) {
- case NM_MT_IPACC_RSL_CONNECT_ACK:
- DEBUGPC(DNM, "RSL CONNECT ACK ");
- if (TLVP_PRESENT(&tp, NM_ATT_IPACC_RSL_BSC_IP))
- DEBUGPC(DNM, "IP=%s ",
- inet_ntoa(*((struct in_addr *)
- TLVP_VAL(&tp, NM_ATT_IPACC_RSL_BSC_IP))));
- if (TLVP_PRESENT(&tp, NM_ATT_IPACC_RSL_BSC_PORT))
- DEBUGPC(DNM, "PORT=%u ",
- ntohs(*((u_int16_t *)
- TLVP_VAL(&tp, NM_ATT_IPACC_RSL_BSC_PORT))));
- DEBUGPC(DNM, "\n");
- break;
- case NM_MT_IPACC_RSL_CONNECT_NACK:
- DEBUGPC(DNM, "RSL CONNECT NACK ");
- if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
- DEBUGPC(DNM, " CAUSE=%s\n",
- nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
- else
- DEBUGPC(DNM, "\n");
- break;
- case NM_MT_IPACC_SET_NVATTR_ACK:
- DEBUGPC(DNM, "SET NVATTR ACK\n");
- /* FIXME: decode and show the actual attributes */
- break;
- case NM_MT_IPACC_SET_NVATTR_NACK:
- DEBUGPC(DNM, "SET NVATTR NACK ");
- if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
- DEBUGPC(DNM, " CAUSE=%s\n",
- nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
- else
- DEBUGPC(DNM, "\n");
- break;
- default:
- DEBUGPC(DNM, "unknown\n");
- break;
- }
- return 0;
-}
-
-/* send an ip-access manufacturer specific message */
-int abis_nm_ipaccess_msg(struct gsm_bts *bts, u_int8_t msg_type,
- u_int8_t obj_class, u_int8_t bts_nr,
- u_int8_t trx_nr, u_int8_t ts_nr,
- u_int8_t *attr, int attr_len)
-{
- struct msgb *msg = nm_msgb_alloc();
- struct abis_om_hdr *oh;
- struct abis_om_fom_hdr *foh;
- u_int8_t *data;
-
- /* construct the 12.21 OM header, observe the erroneous length */
- oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
- fill_om_hdr(oh, sizeof(*foh) + attr_len);
- oh->mdisc = ABIS_OM_MDISC_MANUF;
-
- /* add the ip.access magic */
- data = msgb_put(msg, sizeof(ipaccess_magic)+1);
- *data++ = sizeof(ipaccess_magic);
- memcpy(data, ipaccess_magic, sizeof(ipaccess_magic));
-
- /* fill the 12.21 FOM header */
- foh = (struct abis_om_fom_hdr *) msgb_put(msg, sizeof(*foh));
- foh->msg_type = msg_type;
- foh->obj_class = obj_class;
- foh->obj_inst.bts_nr = bts_nr;
- foh->obj_inst.trx_nr = trx_nr;
- foh->obj_inst.ts_nr = ts_nr;
-
- if (attr && attr_len) {
- data = msgb_put(msg, attr_len);
- memcpy(data, attr, attr_len);
- }
-
- return abis_nm_sendmsg(bts, msg);
-}
-
-/* set some attributes in NVRAM */
-int abis_nm_ipaccess_set_nvattr(struct gsm_bts *bts, u_int8_t *attr,
- int attr_len)
-{
- return abis_nm_ipaccess_msg(bts, NM_MT_IPACC_SET_NVATTR,
- NM_OC_BASEB_TRANSC, 0, 0, 0xff, attr,
- attr_len);
-}
-
-/* restart / reboot an ip.access nanoBTS */
-int abis_nm_ipaccess_restart(struct gsm_bts *bts)
-{
- return __simple_cmd(bts, NM_MT_IPACC_RESTART);
-}
diff --git a/src/abis_rsl.c b/src/abis_rsl.c
deleted file mode 100644
index 4b2a7fccf..000000000
--- a/src/abis_rsl.c
+++ /dev/null
@@ -1,1263 +0,0 @@
-/* GSM Radio Signalling Link messages on the A-bis interface
- * 3GPP TS 08.58 version 8.6.0 Release 1999 / ETSI TS 100 596 V8.6.0 */
-
-/* (C) 2008-2009 by Harald Welte <laforge@gnumonks.org>
- *
- * All Rights Reserved
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <sys/types.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-
-#include <openbsc/gsm_data.h>
-#include <openbsc/gsm_04_08.h>
-#include <openbsc/abis_rsl.h>
-#include <openbsc/chan_alloc.h>
-#include <openbsc/debug.h>
-#include <openbsc/tlv.h>
-#include <openbsc/paging.h>
-#include <openbsc/signal.h>
-
-#define RSL_ALLOC_SIZE 1024
-#define RSL_ALLOC_HEADROOM 128
-
-#define MAX(a, b) (a) >= (b) ? (a) : (b)
-
-static const struct tlv_definition rsl_att_tlvdef = {
- .def = {
- [RSL_IE_CHAN_NR] = { TLV_TYPE_TV },
- [RSL_IE_LINK_IDENT] = { TLV_TYPE_TV },
- [RSL_IE_ACT_TYPE] = { TLV_TYPE_TV },
- [RSL_IE_BS_POWER] = { TLV_TYPE_TV },
- [RSL_IE_CHAN_IDENT] = { TLV_TYPE_TLV },
- [RSL_IE_CHAN_MODE] = { TLV_TYPE_TLV },
- [RSL_IE_ENCR_INFO] = { TLV_TYPE_TLV },
- [RSL_IE_FRAME_NUMBER] = { TLV_TYPE_FIXED, 2 },
- [RSL_IE_HANDO_REF] = { TLV_TYPE_TV },
- [RSL_IE_L1_INFO] = { TLV_TYPE_FIXED, 2 },
- [RSL_IE_L3_INFO] = { TLV_TYPE_TL16V },
- [RSL_IE_MS_IDENTITY] = { TLV_TYPE_TLV },
- [RSL_IE_MS_POWER] = { TLV_TYPE_TV },
- [RSL_IE_PAGING_GROUP] = { TLV_TYPE_TV },
- [RSL_IE_PAGING_LOAD] = { TLV_TYPE_FIXED, 2 },
- [RSL_IE_PYHS_CONTEXT] = { TLV_TYPE_TLV },
- [RSL_IE_ACCESS_DELAY] = { TLV_TYPE_TV },
- [RSL_IE_RACH_LOAD] = { TLV_TYPE_TLV },
- [RSL_IE_REQ_REFERENCE] = { TLV_TYPE_FIXED, 3 },
- [RSL_IE_RELEASE_MODE] = { TLV_TYPE_TV },
- [RSL_IE_RESOURCE_INFO] = { TLV_TYPE_TLV },
- [RSL_IE_RLM_CAUSE] = { TLV_TYPE_TLV },
- [RSL_IE_STARTNG_TIME] = { TLV_TYPE_FIXED, 2 },
- [RSL_IE_TIMING_ADVANCE] = { TLV_TYPE_TV },
- [RSL_IE_UPLINK_MEAS] = { TLV_TYPE_TLV },
- [RSL_IE_CAUSE] = { TLV_TYPE_TLV },
- [RSL_IE_MEAS_RES_NR] = { TLV_TYPE_TV },
- [RSL_IE_MSG_ID] = { TLV_TYPE_TV },
- [RSL_IE_SYSINFO_TYPE] = { TLV_TYPE_TV },
- [RSL_IE_MS_POWER_PARAM] = { TLV_TYPE_TLV },
- [RSL_IE_BS_POWER_PARAM] = { TLV_TYPE_TLV },
- [RSL_IE_PREPROC_PARAM] = { TLV_TYPE_TLV },
- [RSL_IE_PREPROC_MEAS] = { TLV_TYPE_TLV },
- [RSL_IE_IMM_ASS_INFO] = { TLV_TYPE_TLV },
- [RSL_IE_SMSCB_INFO] = { TLV_TYPE_FIXED, 23 },
- [RSL_IE_MS_TIMING_OFFSET] = { TLV_TYPE_TV },
- [RSL_IE_ERR_MSG] = { TLV_TYPE_TLV },
- [RSL_IE_FULL_BCCH_INFO] = { TLV_TYPE_TLV },
- [RSL_IE_CHAN_NEEDED] = { TLV_TYPE_TV },
- [RSL_IE_CB_CMD_TYPE] = { TLV_TYPE_TV },
- [RSL_IE_SMSCB_MSG] = { TLV_TYPE_TLV },
- [RSL_IE_FULL_IMM_ASS_INFO] = { TLV_TYPE_TLV },
- [RSL_IE_SACCH_INFO] = { TLV_TYPE_TLV },
- [RSL_IE_CBCH_LOAD_INFO] = { TLV_TYPE_TV },
- [RSL_IE_SMSCB_CHAN_INDICATOR] = { TLV_TYPE_TV },
- [RSL_IE_GROUP_CALL_REF] = { TLV_TYPE_TLV },
- [RSL_IE_CHAN_DESC] = { TLV_TYPE_TLV },
- [RSL_IE_NCH_DRX_INFO] = { TLV_TYPE_TLV },
- [RSL_IE_CMD_INDICATOR] = { TLV_TYPE_TLV },
- [RSL_IE_EMLPP_PRIO] = { TLV_TYPE_TV },
- [RSL_IE_UIC] = { TLV_TYPE_TLV },
- [RSL_IE_MAIN_CHAN_REF] = { TLV_TYPE_TV },
- [RSL_IE_MR_CONFIG] = { TLV_TYPE_TLV },
- [RSL_IE_MR_CONTROL] = { TLV_TYPE_TV },
- [RSL_IE_SUP_CODEC_TYPES] = { TLV_TYPE_TLV },
- [RSL_IE_CODEC_CONFIG] = { TLV_TYPE_TLV },
- [RSL_IE_RTD] = { TLV_TYPE_TV },
- [RSL_IE_TFO_STATUS] = { TLV_TYPE_TV },
- [RSL_IE_LLP_APDU] = { TLV_TYPE_TLV },
- [RSL_IE_IPAC_REMOTE_IP] = { TLV_TYPE_FIXED, 4 },
- [RSL_IE_IPAC_REMOTE_PORT] = { TLV_TYPE_FIXED, 2 },
- [RSL_IE_IPAC_LOCAL_IP] = { TLV_TYPE_FIXED, 4 },
- [RSL_IE_IPAC_LOCAL_PORT] = { TLV_TYPE_FIXED, 2 },
- [0xf4] = { TLV_TYPE_TV },
- [0xf8] = { TLV_TYPE_FIXED, 2 },
- [0xfc] = { TLV_TYPE_TV },
- },
-};
-#define rsl_tlv_parse(dec, buf, len) \
- tlv_parse(dec, &rsl_att_tlvdef, buf, len, 0, 0)
-
-static u_int8_t mdisc_by_msgtype(u_int8_t msg_type)
-{
- /* mask off the transparent bit ? */
- msg_type &= 0xfe;
-
- if ((msg_type & 0xf0) == 0x00)
- return ABIS_RSL_MDISC_RLL;
- if ((msg_type & 0xf0) == 0x10) {
- if (msg_type >= 0x19 && msg_type <= 0x22)
- return ABIS_RSL_MDISC_TRX;
- else
- return ABIS_RSL_MDISC_COM_CHAN;
- }
- if ((msg_type & 0xe0) == 0x20)
- return ABIS_RSL_MDISC_DED_CHAN;
-
- return ABIS_RSL_MDISC_LOC;
-}
-
-static inline void init_dchan_hdr(struct abis_rsl_dchan_hdr *dh,
- u_int8_t msg_type)
-{
- dh->c.msg_discr = mdisc_by_msgtype(msg_type);
- dh->c.msg_type = msg_type;
- dh->ie_chan = RSL_IE_CHAN_NR;
-}
-
-static inline void init_llm_hdr(struct abis_rsl_rll_hdr *dh,
- u_int8_t msg_type)
-{
- /* dh->c.msg_discr = mdisc_by_msgtype(msg_type); */
- dh->c.msg_discr = ABIS_RSL_MDISC_RLL;
- dh->c.msg_type = msg_type;
- dh->ie_chan = RSL_IE_CHAN_NR;
- dh->ie_link_id = RSL_IE_LINK_IDENT;
-}
-
-
-/* encode channel number as per Section 9.3.1 */
-u_int8_t rsl_enc_chan_nr(u_int8_t type, u_int8_t subch, u_int8_t timeslot)
-{
- u_int8_t ret;
-
- ret = (timeslot & 0x07) | type;
-
- switch (type) {
- case RSL_CHAN_Lm_ACCHs:
- subch &= 0x01;
- break;
- case RSL_CHAN_SDCCH4_ACCH:
- subch &= 0x07;
- break;
- case RSL_CHAN_SDCCH8_ACCH:
- subch &= 0x07;
- break;
- default:
- /* no subchannels allowed */
- subch = 0x00;
- break;
- }
- ret |= (subch << 3);
-
- return ret;
-}
-
-/* determine logical channel based on TRX and channel number IE */
-struct gsm_lchan *lchan_lookup(struct gsm_bts_trx *trx, u_int8_t chan_nr)
-{
- struct gsm_lchan *lchan;
- u_int8_t ts_nr = chan_nr & 0x07;
- u_int8_t cbits = chan_nr >> 3;
- u_int8_t lch_idx;
- struct gsm_bts_trx_ts *ts = &trx->ts[ts_nr];
-
- if (cbits == 0x01) {
- lch_idx = 0; /* TCH/F */
- if (ts->pchan != GSM_PCHAN_TCH_F)
- fprintf(stderr, "chan_nr=0x%02x but pchan=%u\n",
- chan_nr, ts->pchan);
- } else if ((cbits & 0x1e) == 0x02) {
- lch_idx = cbits & 0x1; /* TCH/H */
- if (ts->pchan != GSM_PCHAN_TCH_H)
- fprintf(stderr, "chan_nr=0x%02x but pchan=%u\n",
- chan_nr, ts->pchan);
- } else if ((cbits & 0x1c) == 0x04) {
- lch_idx = cbits & 0x3; /* SDCCH/4 */
- if (ts->pchan != GSM_PCHAN_CCCH_SDCCH4)
- fprintf(stderr, "chan_nr=0x%02x but pchan=%u\n",
- chan_nr, ts->pchan);
- } else if ((cbits & 0x18) == 0x08) {
- lch_idx = cbits & 0x7; /* SDCCH/8 */
- if (ts->pchan != GSM_PCHAN_SDCCH8_SACCH8C)
- fprintf(stderr, "chan_nr=0x%02x but pchan=%u\n",
- chan_nr, ts->pchan);
- } else if (cbits == 0x10 || cbits == 0x11 || cbits == 0x12) {
- lch_idx = 0;
- if (ts->pchan != GSM_PCHAN_CCCH &&
- ts->pchan != GSM_PCHAN_CCCH_SDCCH4)
- fprintf(stderr, "chan_nr=0x%02x but pchan=%u\n",
- chan_nr, ts->pchan);
- /* FIXME: we should not return first sdcch4 !!! */
- } else {
- fprintf(stderr, "unknown chan_nr=0x%02x\n", chan_nr);
- return NULL;
- }
-
- lchan = &ts->lchan[lch_idx];
-
- return lchan;
-}
-
-u_int8_t lchan2chan_nr(struct gsm_lchan *lchan)
-{
- struct gsm_bts_trx_ts *ts = lchan->ts;
- u_int8_t cbits, chan_nr;
-
- switch (ts->pchan) {
- case GSM_PCHAN_TCH_F:
- cbits = 0x01;
- break;
- case GSM_PCHAN_TCH_H:
- cbits = 0x02;
- cbits += lchan->nr;
- break;
- case GSM_PCHAN_CCCH_SDCCH4:
- cbits = 0x04;
- cbits += lchan->nr;
- break;
- case GSM_PCHAN_SDCCH8_SACCH8C:
- cbits = 0x08;
- cbits += lchan->nr;
- break;
- default:
- case GSM_PCHAN_CCCH:
- cbits = 0x10;
- break;
- }
-
- chan_nr = (cbits << 3) | (ts->nr & 0x7);
-
- return chan_nr;
-}
-
-/* As per TS 03.03 Section 2.2, the IMSI has 'not more than 15 digits' */
-u_int64_t str_to_imsi(const char *imsi_str)
-{
- u_int64_t ret;
-
- ret = strtoull(imsi_str, NULL, 10);
-
- return ret;
-}
-
-/* Table 5 Clause 7 TS 05.02 */
-unsigned int n_pag_blocks(int bs_ccch_sdcch_comb, unsigned int bs_ag_blks_res)
-{
- if (!bs_ccch_sdcch_comb)
- return 9 - bs_ag_blks_res;
- else
- return 3 - bs_ag_blks_res;
-}
-
-/* Chapter 6.5.2 of TS 05.02 */
-unsigned int get_ccch_group(u_int64_t imsi, unsigned int bs_cc_chans,
- unsigned int n_pag_blocks)
-{
- return (imsi % 1000) % (bs_cc_chans * n_pag_blocks) / n_pag_blocks;
-}
-
-/* Chapter 6.5.2 of TS 05.02 */
-unsigned int get_paging_group(u_int64_t imsi, unsigned int bs_cc_chans,
- int n_pag_blocks)
-{
- return (imsi % 1000) % (bs_cc_chans * n_pag_blocks) % n_pag_blocks;
-}
-
-static struct msgb *rsl_msgb_alloc(void)
-{
- return msgb_alloc_headroom(RSL_ALLOC_SIZE, RSL_ALLOC_HEADROOM);
-}
-
-#define MACBLOCK_SIZE 23
-static void pad_macblock(u_int8_t *out, const u_int8_t *in, int len)
-{
- memcpy(out, in, len);
-
- if (len < MACBLOCK_SIZE)
- memset(out+len, 0x2b, MACBLOCK_SIZE-len);
-}
-
-static void print_rsl_cause(u_int8_t *cause_tlv)
-{
- u_int8_t cause_len;
- int i;
-
- if (cause_tlv[0] != RSL_IE_CAUSE)
- return;
-
- cause_len = cause_tlv[1];
- DEBUGPC(DRSL, "CAUSE: ");
- for (i = 0; i < cause_len; i++)
- DEBUGPC(DRSL, "%02x ", cause_tlv[2+i]);
-}
-
-/* Send a BCCH_INFO message as per Chapter 8.5.1 */
-int rsl_bcch_info(struct gsm_bts_trx *trx, u_int8_t type,
- const u_int8_t *data, int len)
-{
- struct abis_rsl_dchan_hdr *dh;
- struct msgb *msg = rsl_msgb_alloc();
-
- dh = (struct abis_rsl_dchan_hdr *) msgb_put(msg, sizeof*dh);
- init_dchan_hdr(dh, RSL_MT_BCCH_INFO);
- dh->chan_nr = RSL_CHAN_BCCH;
-
- msgb_tv_put(msg, RSL_IE_SYSINFO_TYPE, type);
- msgb_tlv_put(msg, RSL_IE_FULL_BCCH_INFO, len, data);
-
- msg->trx = trx;
-
- return abis_rsl_sendmsg(msg);
-}
-
-int rsl_sacch_filling(struct gsm_bts_trx *trx, u_int8_t type,
- const u_int8_t *data, int len)
-{
- struct abis_rsl_common_hdr *ch;
- struct msgb *msg = rsl_msgb_alloc();
-
- ch = (struct abis_rsl_common_hdr *) msgb_put(msg, sizeof(*ch));
- ch->msg_discr = ABIS_RSL_MDISC_TRX;
- ch->msg_type = RSL_MT_SACCH_FILL;
-
- msgb_tv_put(msg, RSL_IE_SYSINFO_TYPE, type);
- msgb_tl16v_put(msg, RSL_IE_L3_INFO, len, data);
-
- msg->trx = trx;
-
- return abis_rsl_sendmsg(msg);
-}
-
-/* Chapter 8.4.1 */
-#if 0
-int rsl_chan_activate(struct gsm_bts_trx *trx, u_int8_t chan_nr,
- u_int8_t act_type,
- struct rsl_ie_chan_mode *chan_mode,
- struct rsl_ie_chan_ident *chan_ident,
- u_int8_t bs_power, u_int8_t ms_power,
- u_int8_t ta)
-{
- struct abis_rsl_dchan_hdr *dh;
- struct msgb *msg = rsl_msgb_alloc();
-
- dh = (struct abis_rsl_dchan_hdr *) msgb_put(msg, sizeof(*dh));
- init_dchan_hdr(dh, RSL_MT_CHAN_ACTIV);
- dh->chan_nr = chan_nr;
-
- msgb_tv_put(msg, RSL_IE_ACT_TYPE, act_type);
- /* For compatibility with Phase 1 */
- msgb_tlv_put(msg, RSL_IE_CHAN_MODE, sizeof(*chan_mode),
- (u_int8_t *) chan_mode);
- msgb_tlv_put(msg, RSL_IE_CHAN_IDENT, 4,
- (u_int8_t *) chan_ident);
-#if 0
- msgb_tlv_put(msg, RSL_IE_ENCR_INFO, 1,
- (u_int8_t *) &encr_info);
-#endif
- msgb_tv_put(msg, RSL_IE_BS_POWER, bs_power);
- msgb_tv_put(msg, RSL_IE_MS_POWER, ms_power);
- msgb_tv_put(msg, RSL_IE_TIMING_ADVANCE, ta);
-
- msg->trx = trx;
-
- return abis_rsl_sendmsg(msg);
-}
-#endif
-
-int rsl_chan_activate_lchan(struct gsm_lchan *lchan, u_int8_t act_type,
- u_int8_t ta, u_int8_t mode)
-{
- struct abis_rsl_dchan_hdr *dh;
- struct msgb *msg = rsl_msgb_alloc();
-
- u_int8_t chan_nr = lchan2chan_nr(lchan);
- u_int16_t arfcn = lchan->ts->trx->arfcn;
- struct rsl_ie_chan_mode cm;
- struct rsl_ie_chan_ident ci;
-
- memset(&cm, 0, sizeof(cm));
- /* FIXME: what to do with data calls ? */
- cm.dtx_dtu = 0x00;
- switch (lchan->type) {
- case GSM_LCHAN_SDCCH:
- cm.spd_ind = RSL_CMOD_SPD_SIGN;
- cm.chan_rt = RSL_CMOD_CRT_SDCCH;
- cm.chan_rate = 0x00;
- break;
- case GSM_LCHAN_TCH_F:
- cm.chan_rt = RSL_CMOD_CRT_TCH_Bm;
- switch (mode) {
- case RSL_CMOD_SPD_SIGN:
- cm.spd_ind = RSL_CMOD_SPD_SIGN;
- cm.chan_rate = 0x00;
- break;
- case RSL_CMOD_SPD_SPEECH:
- cm.spd_ind = RSL_CMOD_SPD_SPEECH;
- cm.chan_rate = RSL_CMOD_SP_GSM2;
- break;
- }
- break;
- case GSM_LCHAN_TCH_H:
- DEBUGP(DRSL, "Unimplemented TCH_H activation\n");
- return -1;
- case GSM_LCHAN_UNKNOWN:
- case GSM_LCHAN_NONE:
- return -1;
- }
-
- memset(&ci, 0, sizeof(ci));
- ci.chan_desc.iei = 0x64;
- ci.chan_desc.chan_nr = chan_nr;
- ci.chan_desc.oct3 = (lchan->ts->trx->bts->tsc << 5) | ((arfcn & 0x3ff) >> 8);
- ci.chan_desc.oct4 = arfcn & 0xff;
-
- dh = (struct abis_rsl_dchan_hdr *) msgb_put(msg, sizeof(*dh));
- init_dchan_hdr(dh, RSL_MT_CHAN_ACTIV);
- dh->chan_nr = chan_nr;
-
- msgb_tv_put(msg, RSL_IE_ACT_TYPE, act_type);
- /* For compatibility with Phase 1 */
- msgb_tlv_put(msg, RSL_IE_CHAN_MODE, sizeof(cm),
- (u_int8_t *) &cm);
- msgb_tlv_put(msg, RSL_IE_CHAN_IDENT, 4,
- (u_int8_t *) &ci);
-#if 0
- msgb_tlv_put(msg, RSL_IE_ENCR_INFO, 1,
- (u_int8_t *) &encr_info);
-#endif
- msgb_tv_put(msg, RSL_IE_BS_POWER, lchan->bs_power);
- msgb_tv_put(msg, RSL_IE_MS_POWER, lchan->ms_power);
- msgb_tv_put(msg, RSL_IE_TIMING_ADVANCE, ta);
-
- msg->trx = lchan->ts->trx;
-
- return abis_rsl_sendmsg(msg);
-}
-
-/* Chapter 8.4.9 */
-int rsl_chan_mode_modify_req(struct gsm_lchan *lchan)
-{
- struct abis_rsl_dchan_hdr *dh;
- struct msgb *msg = rsl_msgb_alloc();
-
- u_int8_t chan_nr = lchan2chan_nr(lchan);
- struct rsl_ie_chan_mode cm;
-
- memset(&cm, 0, sizeof(cm));
-
- /* FIXME: what to do with data calls ? */
- cm.dtx_dtu = 0x00;
- switch (lchan->type) {
- /* todo more modes */
- case GSM_LCHAN_TCH_F:
- cm.spd_ind = RSL_CMOD_SPD_SPEECH;
- cm.chan_rt = RSL_CMOD_CRT_TCH_Bm;
- switch(lchan->tch_mode) {
- case GSM48_CMODE_SPEECH_V1:
- cm.chan_rate = RSL_CMOD_SP_GSM1;
- break;
- case GSM48_CMODE_SPEECH_EFR:
- cm.chan_rate = RSL_CMOD_SP_GSM2;
- break;
- default:
- DEBUGP(DRSL, "Unimplemented channel modification\n");
- return -1;
- }
- break;
- default:
- DEBUGP(DRSL, "Unimplemented channel modification\n");
- return -1;
- }
-
- dh = (struct abis_rsl_dchan_hdr *) msgb_put(msg, sizeof(*dh));
- init_dchan_hdr(dh, RSL_MT_MODE_MODIFY_REQ);
- dh->chan_nr = chan_nr;
-
- msgb_tlv_put(msg, RSL_IE_CHAN_MODE, sizeof(cm),
- (u_int8_t *) &cm);
-#if 0
- msgb_tlv_put(msg, RSL_IE_ENCR_INFO, 1,
- (u_int8_t *) &encr_info);
-#endif
-
- msg->trx = lchan->ts->trx;
-
- return abis_rsl_sendmsg(msg);
-}
-
-/* Chapter 9.1.7 of 04.08 */
-int rsl_chan_release(struct gsm_lchan *lchan)
-{
- struct abis_rsl_dchan_hdr *dh;
- struct msgb *msg = rsl_msgb_alloc();
-
- dh = (struct abis_rsl_dchan_hdr *) msgb_put(msg, sizeof(*dh));
- init_dchan_hdr(dh, RSL_MT_RF_CHAN_REL);
- dh->chan_nr = lchan2chan_nr(lchan);
-
- msg->lchan = lchan;
- msg->trx = lchan->ts->trx;
-
- DEBUGP(DRSL, "Channel Release CMD channel=%s chan_nr=0x%02x\n",
- gsm_ts_name(lchan->ts), dh->chan_nr);
-
- return abis_rsl_sendmsg(msg);
-}
-
-int rsl_paging_cmd(struct gsm_bts *bts, u_int8_t paging_group, u_int8_t len,
- u_int8_t *ms_ident, u_int8_t chan_needed)
-{
- struct abis_rsl_dchan_hdr *dh;
- struct msgb *msg = rsl_msgb_alloc();
-
- dh = (struct abis_rsl_dchan_hdr *) msgb_put(msg, sizeof(*dh));
- init_dchan_hdr(dh, RSL_MT_PAGING_CMD);
- dh->chan_nr = RSL_CHAN_PCH_AGCH;
-
- msgb_tv_put(msg, RSL_IE_PAGING_GROUP, paging_group);
- msgb_tlv_put(msg, RSL_IE_MS_IDENTITY, len-2, ms_ident+2);
- msgb_tv_put(msg, RSL_IE_CHAN_NEEDED, chan_needed);
-
- msg->trx = bts->c0;
-
- return abis_rsl_sendmsg(msg);
-}
-
-int rsl_paging_cmd_subscr(struct gsm_bts *bts, u_int8_t chan_need,
- struct gsm_subscriber *subscr)
-{
-#if 0
- u_int8_t mi[128];
- unsigned int mi_len;
- u_int8_t paging_group;
-#endif
-
- return -1;
-}
-
-int imsi_str2bcd(u_int8_t *bcd_out, const char *str_in)
-{
- int i, len = strlen(str_in);
-
- for (i = 0; i < len; i++) {
- int num = str_in[i] - 0x30;
- if (num < 0 || num > 9)
- return -1;
- if (i % 2 == 0)
- bcd_out[i/2] = num;
- else
- bcd_out[i/2] |= (num << 4);
- }
-
- return 0;
-}
-
-/* Chapter 8.5.6 */
-int rsl_imm_assign_cmd(struct gsm_bts *bts, u_int8_t len, u_int8_t *val)
-{
- struct msgb *msg = rsl_msgb_alloc();
- struct abis_rsl_dchan_hdr *dh;
- u_int8_t buf[MACBLOCK_SIZE];
-
- dh = (struct abis_rsl_dchan_hdr *) msgb_put(msg, sizeof(*dh));
- init_dchan_hdr(dh, RSL_MT_IMMEDIATE_ASSIGN_CMD);
- dh->chan_nr = RSL_CHAN_PCH_AGCH;
-
- switch (bts->type) {
- case GSM_BTS_TYPE_BS11:
- msgb_tlv_put(msg, RSL_IE_IMM_ASS_INFO, len, val);
- break;
- default:
- /* If phase 2, construct a FULL_IMM_ASS_INFO */
- pad_macblock(buf, val, len);
- msgb_tlv_put(msg, RSL_IE_FULL_IMM_ASS_INFO, MACBLOCK_SIZE, buf);
- break;
- }
-
- msg->trx = bts->c0;
-
- return abis_rsl_sendmsg(msg);
-}
-
-/* Send "DATA REQUEST" message with given L3 Info payload */
-/* Chapter 8.3.1 */
-int rsl_data_request(struct msgb *msg, u_int8_t link_id)
-{
- u_int8_t l3_len = msg->tail - (u_int8_t *)msgb_l3(msg);
- struct abis_rsl_rll_hdr *rh;
-
- if (msg->lchan == NULL) {
- fprintf(stderr, "cannot send DATA REQUEST to unknown lchan\n");
- return -EINVAL;
- }
-
- /* First push the L3 IE tag and length */
- msgb_tv16_push(msg, RSL_IE_L3_INFO, l3_len);
-
- /* Then push the RSL header */
- rh = (struct abis_rsl_rll_hdr *) msgb_push(msg, sizeof(*rh));
- init_llm_hdr(rh, RSL_MT_DATA_REQ);
- rh->c.msg_discr |= ABIS_RSL_MDISC_TRANSP;
- rh->chan_nr = lchan2chan_nr(msg->lchan);
- rh->link_id = link_id;
-
- msg->trx = msg->lchan->ts->trx;
-
- return abis_rsl_sendmsg(msg);
-}
-
-/* Chapter 8.4.2: Channel Activate Acknowledge */
-static int rsl_rx_chan_act_ack(struct msgb *msg)
-{
- struct abis_rsl_dchan_hdr *rslh = msgb_l2(msg);
-
- /* BTS has confirmed channel activation, we now need
- * to assign the activated channel to the MS */
- if (rslh->ie_chan != RSL_IE_CHAN_NR)
- return -EINVAL;
-
- return 0;
-}
-
-/* Chapter 8.4.3: Channel Activate NACK */
-static int rsl_rx_chan_act_nack(struct msgb *msg)
-{
- struct abis_rsl_dchan_hdr *dh = msgb_l2(msg);
- struct tlv_parsed tp;
-
- /* BTS has rejected channel activation ?!? */
- if (dh->ie_chan != RSL_IE_CHAN_NR)
- return -EINVAL;
-
- rsl_tlv_parse(&tp, dh->data, msgb_l2len(msg)-sizeof(*dh));
- if (TLVP_PRESENT(&tp, RSL_IE_CAUSE))
- DEBUGPC(DRSL, "CAUSE=0x%02x ", *TLVP_VAL(&tp, RSL_IE_CAUSE));
-
- return 0;
-}
-
-/* Chapter 8.4.4: Connection Failure Indication */
-static int rsl_rx_conn_fail(struct msgb *msg)
-{
- struct abis_rsl_dchan_hdr *dh = msgb_l2(msg);
- struct tlv_parsed tp;
-
- DEBUGPC(DRSL, "CONNECTION FAIL: ");
- print_rsl_cause(dh->data);
-
- rsl_tlv_parse(&tp, dh->data, msgb_l2len(msg)-sizeof(*dh));
-
- if (msg->trx->bts->type == GSM_BTS_TYPE_BS11) {
- /* FIXME: we have no idea what cause 0x18 is !!! */
- if (TLVP_PRESENT(&tp, RSL_IE_CAUSE) &&
- TLVP_LEN(&tp, RSL_IE_CAUSE) >= 1 &&
- *TLVP_VAL(&tp, RSL_IE_CAUSE) == 0x18) {
- if (msg->lchan->use_count > 0) {
- DEBUGPC(DRSL, "Cause 0x18 IGNORING, lchan in use! (%d times)\n", msg->lchan->use_count);
- return 0;
- }
- }
- }
-
- DEBUGPC(DRSL, "RELEASING.\n");
-
- /* FIXME: only free it after channel release ACK */
- return rsl_chan_release(msg->lchan);
-}
-
-static int rsl_rx_meas_res(struct msgb *msg)
-{
- struct abis_rsl_dchan_hdr *dh = msgb_l2(msg);
- struct tlv_parsed tp;
-
- DEBUGPC(DRSL, "MEASUREMENT RESULT ");
- rsl_tlv_parse(&tp, dh->data, msgb_l2len(msg)-sizeof(*dh));
-
- if (TLVP_PRESENT(&tp, RSL_IE_MEAS_RES_NR))
- DEBUGPC(DRSL, "NR=%d ", *TLVP_VAL(&tp, RSL_IE_MEAS_RES_NR));
- if (TLVP_PRESENT(&tp, RSL_IE_UPLINK_MEAS)) {
- u_int8_t len = TLVP_LEN(&tp, RSL_IE_UPLINK_MEAS);
- const u_int8_t *val = TLVP_VAL(&tp, RSL_IE_UPLINK_MEAS);
- if (len >= 3) {
- if (val[0] & 0x40)
- DEBUGPC(DRSL, "DTXd ");
- DEBUGPC(DRSL, "RXL-FULL-up=%d RXL-SUB-up=%d ",
- val[0] & 0x3f, val[1] & 0x3f);
- DEBUGPC(DRSL, "RXQ-FULL-up=%d RXQ-SUB-up=%d ",
- val[2]>>3 & 0x7, val[2] & 0x7);
- }
- }
- if (TLVP_PRESENT(&tp, RSL_IE_BS_POWER))
- DEBUGPC(DRSL, "BS_POWER=%d ", *TLVP_VAL(&tp, RSL_IE_BS_POWER));
- if (TLVP_PRESENT(&tp, RSL_IE_MS_TIMING_OFFSET))
- DEBUGPC(DRSL, "MS_TO=%d ",
- *TLVP_VAL(&tp, RSL_IE_MS_TIMING_OFFSET));
- if (TLVP_PRESENT(&tp, RSL_IE_L1_INFO))
- DEBUGPC(DRSL, "L1 ");
- if (TLVP_PRESENT(&tp, RSL_IE_L3_INFO)) {
- DEBUGPC(DRSL, "L3\n");
- msg->l3h = TLVP_VAL(&tp, RSL_IE_L3_INFO);
- return gsm0408_rcvmsg(msg);
- } else
- DEBUGPC(DRSL, "\n");
-
- return 0;
-}
-
-static int abis_rsl_rx_dchan(struct msgb *msg)
-{
- struct abis_rsl_dchan_hdr *rslh = msgb_l2(msg);
- int rc = 0;
- char *ts_name;
-
- msg->lchan = lchan_lookup(msg->trx, rslh->chan_nr);
- ts_name = gsm_ts_name(msg->lchan->ts);
-
- DEBUGP(DRSL, "channel=%s chan_nr=0x%02x ", ts_name, rslh->chan_nr);
-
- switch (rslh->c.msg_type) {
- case RSL_MT_CHAN_ACTIV_ACK:
- DEBUGPC(DRSL, "CHANNEL ACTIVATE ACK\n");
- rc = rsl_rx_chan_act_ack(msg);
- break;
- case RSL_MT_CHAN_ACTIV_NACK:
- DEBUGPC(DRSL, "CHANNEL ACTIVATE NACK\n");
- rc = rsl_rx_chan_act_nack(msg);
- break;
- case RSL_MT_CONN_FAIL:
- rc = rsl_rx_conn_fail(msg);
- break;
- case RSL_MT_MEAS_RES:
- rc = rsl_rx_meas_res(msg);
- break;
- case RSL_MT_RF_CHAN_REL_ACK:
- DEBUGPC(DRSL, "RF CHANNEL RELEASE ACK\n");
- lchan_free(msg->lchan);
- break;
- case RSL_MT_MODE_MODIFY_ACK:
- DEBUGPC(DRSL, "CHANNEL MODE MODIFY ACK\n");
- break;
- case RSL_MT_MODE_MODIFY_NACK:
- DEBUGPC(DRSL, "CHANNEL MODE MODIFY NACK\n");
- break;
- case RSL_MT_PHY_CONTEXT_CONF:
- case RSL_MT_PREPROC_MEAS_RES:
- case RSL_MT_TALKER_DET:
- case RSL_MT_LISTENER_DET:
- case RSL_MT_REMOTE_CODEC_CONF_REP:
- case RSL_MT_MR_CODEC_MOD_ACK:
- case RSL_MT_MR_CODEC_MOD_NACK:
- case RSL_MT_MR_CODEC_MOD_PER:
- DEBUGPC(DRSL, "Unimplemented Abis RSL DChan msg 0x%02x\n",
- rslh->c.msg_type);
- break;
- default:
- DEBUGPC(DRSL, "unknown Abis RSL DChan msg 0x%02x\n",
- rslh->c.msg_type);
- return -EINVAL;
- }
-
- return rc;
-}
-
-static int rsl_rx_error_rep(struct msgb *msg)
-{
- struct abis_rsl_common_hdr *rslh = msgb_l2(msg);
-
- DEBUGP(DRSL, "ERROR REPORT ");
- print_rsl_cause(rslh->data);
- DEBUGPC(DRSL, "\n");
-
- return 0;
-}
-
-static int abis_rsl_rx_trx(struct msgb *msg)
-{
- struct abis_rsl_common_hdr *rslh = msgb_l2(msg);
- int rc = 0;
-
- switch (rslh->msg_type) {
- case RSL_MT_ERROR_REPORT:
- rc = rsl_rx_error_rep(msg);
- break;
- case RSL_MT_RF_RES_IND:
- /* interference on idle channels of TRX */
- //DEBUGP(DRSL, "TRX: RF Interference Indication\n");
- break;
- case RSL_MT_OVERLOAD:
- /* indicate CCCH / ACCH / processor overload */
- DEBUGP(DRSL, "TRX: CCCH/ACCH/CPU Overload\n");
- break;
- default:
- DEBUGP(DRSL, "Unknown Abis RSL TRX message type 0x%02x\n",
- rslh->msg_type);
- return -EINVAL;
- }
- return rc;
-}
-
-/* MS has requested a channel on the RACH */
-static int rsl_rx_chan_rqd(struct msgb *msg)
-{
- struct gsm_bts *bts = msg->trx->bts;
- struct abis_rsl_dchan_hdr *rqd_hdr = msgb_l2(msg);
- struct gsm48_req_ref *rqd_ref;
- struct gsm48_imm_ass ia;
- enum gsm_chan_t lctype;
- enum gsm_chreq_reason_t chreq_reason;
- struct gsm_lchan *lchan;
- u_int8_t rqd_ta;
- int ret;
-
- u_int16_t arfcn;
- u_int8_t ts_number, subch;
-
- /* parse request reference to be used in immediate assign */
- if (rqd_hdr->data[0] != RSL_IE_REQ_REFERENCE)
- return -EINVAL;
-
- rqd_ref = (struct gsm48_req_ref *) &rqd_hdr->data[1];
-
- /* parse access delay and use as TA */
- if (rqd_hdr->data[sizeof(struct gsm48_req_ref)+1] != RSL_IE_ACCESS_DELAY)
- return -EINVAL;
- rqd_ta = rqd_hdr->data[sizeof(struct gsm48_req_ref)+2];
-
- /* determine channel type (SDCCH/TCH_F/TCH_H) based on
- * request reference RA */
- lctype = get_ctype_by_chreq(bts, rqd_ref->ra);
- chreq_reason = get_reason_by_chreq(bts, rqd_ref->ra);
-
- /* check availability / allocate channel */
- lchan = lchan_alloc(bts, lctype);
- if (!lchan) {
- fprintf(stderr, "CHAN RQD: no resources\n");
- /* FIXME: send some kind of reject ?!? */
- return -ENOMEM;
- }
-
- ts_number = lchan->ts->nr;
- arfcn = lchan->ts->trx->arfcn;
- subch = lchan->nr;
-
- lchan->ms_power = lchan->bs_power = 0x0f; /* 30dB reduction */
- rsl_chan_activate_lchan(lchan, 0x00, rqd_ta, RSL_CMOD_SPD_SIGN);
-
- /* create IMMEDIATE ASSIGN 04.08 messge */
- memset(&ia, 0, sizeof(ia));
- ia.l2_plen = 0x2d;
- ia.proto_discr = GSM48_PDISC_RR;
- ia.msg_type = GSM48_MT_RR_IMM_ASS;
- ia.page_mode = GSM48_PM_SAME;
- ia.chan_desc.chan_nr = lchan2chan_nr(lchan);
- ia.chan_desc.h0.h = 0;
- ia.chan_desc.h0.arfcn_high = arfcn >> 8;
- ia.chan_desc.h0.arfcn_low = arfcn & 0xff;
- ia.chan_desc.h0.tsc = 7;
- /* use request reference extracted from CHAN_RQD */
- memcpy(&ia.req_ref, rqd_ref, sizeof(ia.req_ref));
- ia.timing_advance = rqd_ta;
- ia.mob_alloc_len = 0;
-
- DEBUGP(DRSL, "Activating ARFCN(%u) TS(%u) SS(%u) lctype %s "
- "chan_nr=0x%02x r=%s ra=0x%02x\n",
- arfcn, ts_number, subch, gsm_lchan_name(lchan->type),
- ia.chan_desc.chan_nr, gsm_chreq_name(chreq_reason),
- rqd_ref->ra);
-
- /* FIXME: Start timer T3101 to wait for GSM48_MT_RR_PAG_RESP */
-
- /* send IMMEDIATE ASSIGN CMD on RSL to BTS (to send on CCCH to MS) */
- ret = rsl_imm_assign_cmd(bts, sizeof(ia), (u_int8_t *) &ia);
-
- return ret;
-}
-
-/* MS has requested a channel on the RACH */
-static int rsl_rx_ccch_load(struct msgb *msg)
-{
- struct abis_rsl_dchan_hdr *rslh = msgb_l2(msg);
- u_int16_t pg_buf_space;
- u_int16_t rach_slot_count = -1;
- u_int16_t rach_busy_count = -1;
- u_int16_t rach_access_count = -1;
-
- switch (rslh->data[0]) {
- case RSL_IE_PAGING_LOAD:
- pg_buf_space = rslh->data[1] << 8 | rslh->data[2];
- paging_update_buffer_space(msg->trx->bts, pg_buf_space);
- break;
- case RSL_IE_RACH_LOAD:
- if (msg->data_len >= 7) {
- rach_slot_count = rslh->data[2] << 8 | rslh->data[3];
- rach_busy_count = rslh->data[4] << 8 | rslh->data[5];
- rach_access_count = rslh->data[6] << 8 | rslh->data[7];
- }
- break;
- default:
- break;
- }
-
- return 0;
-}
-
-static int abis_rsl_rx_cchan(struct msgb *msg)
-{
- struct abis_rsl_dchan_hdr *rslh = msgb_l2(msg);
- int rc = 0;
-
- msg->lchan = lchan_lookup(msg->trx, rslh->chan_nr);
-
- switch (rslh->c.msg_type) {
- case RSL_MT_CHAN_RQD:
- /* MS has requested a channel on the RACH */
- rc = rsl_rx_chan_rqd(msg);
- break;
- case RSL_MT_CCCH_LOAD_IND:
- /* current load on the CCCH */
- rc = rsl_rx_ccch_load(msg);
- break;
- case RSL_MT_DELETE_IND:
- /* CCCH overloaded, IMM_ASSIGN was dropped */
- case RSL_MT_CBCH_LOAD_IND:
- /* current load on the CBCH */
- fprintf(stderr, "Unimplemented Abis RSL TRX message type "
- "0x%02x\n", rslh->c.msg_type);
- break;
- default:
- fprintf(stderr, "Unknown Abis RSL TRX message type 0x%02x\n",
- rslh->c.msg_type);
- return -EINVAL;
- }
-
- return rc;
-}
-
-static int rsl_rx_rll_err_ind(struct msgb *msg)
-{
- struct abis_rsl_rll_hdr *rllh = msgb_l2(msg);
- u_int8_t *rlm_cause = rllh->data;
-
- DEBUGPC(DRLL, "cause=0x%02x", rlm_cause[1]);
-
- return 0;
-}
-
-/* ESTABLISH INDICATION, LOCATION AREA UPDATE REQUEST
- 0x02, 0x06,
- 0x01, 0x20,
- 0x02, 0x00,
- 0x0b, 0x00, 0x0f, 0x05, 0x08, ... */
-
-static int abis_rsl_rx_rll(struct msgb *msg)
-{
- struct abis_rsl_rll_hdr *rllh = msgb_l2(msg);
- int rc = 0;
- char *ts_name;
-
- msg->lchan = lchan_lookup(msg->trx, rllh->chan_nr);
- ts_name = gsm_ts_name(msg->lchan->ts);
- DEBUGP(DRLL, "channel=%s chan_nr=0x%02x ", ts_name, rllh->chan_nr);
-
- switch (rllh->c.msg_type) {
- case RSL_MT_DATA_IND:
- DEBUGPC(DRLL, "DATA INDICATION\n");
- if (msgb_l2len(msg) >
- sizeof(struct abis_rsl_common_hdr) + sizeof(*rllh) &&
- rllh->data[0] == RSL_IE_L3_INFO) {
- msg->l3h = &rllh->data[3];
- return gsm0408_rcvmsg(msg);
- }
- break;
- case RSL_MT_EST_IND:
- DEBUGPC(DRLL, "ESTABLISH INDICATION\n");
- if (msgb_l2len(msg) >
- sizeof(struct abis_rsl_common_hdr) + sizeof(*rllh) &&
- rllh->data[0] == RSL_IE_L3_INFO) {
- msg->l3h = &rllh->data[3];
- return gsm0408_rcvmsg(msg);
- }
- break;
- case RSL_MT_REL_IND:
- DEBUGPC(DRLL, "RELEASE INDICATION ");
- break;
- case RSL_MT_REL_CONF:
- DEBUGPC(DRLL, "RELEASE CONFIRMATION ");
- break;
- case RSL_MT_ERROR_IND:
- DEBUGPC(DRLL, "ERROR INDICATION ");
- rc = rsl_rx_rll_err_ind(msg);
- break;
- case RSL_MT_UNIT_DATA_IND:
- DEBUGPC(DRLL, "unimplemented Abis RLL message type 0x%02x ",
- rllh->c.msg_type);
- break;
- default:
- DEBUGPC(DRLL, "unknown Abis RLL message type 0x%02x ",
- rllh->c.msg_type);
- }
- DEBUGPC(DRLL, "\n");
- return rc;
-}
-
-/* ip.access specific RSL extensions */
-int rsl_ipacc_bind(struct gsm_lchan *lchan)
-{
- struct msgb *msg = rsl_msgb_alloc();
- struct abis_rsl_dchan_hdr *dh;
-
- dh = (struct abis_rsl_dchan_hdr *) msgb_put(msg, sizeof(*dh));
- init_dchan_hdr(dh, RSL_MT_IPAC_BIND);
- dh->c.msg_discr = ABIS_RSL_MDISC_IPACCESS;
- dh->chan_nr = lchan2chan_nr(lchan);
-
- msg->trx = lchan->ts->trx;
-
- return abis_rsl_sendmsg(msg);
-}
-
-int rsl_ipacc_connect(struct gsm_lchan *lchan, u_int32_t ip, u_int16_t port, u_int16_t f8, u_int8_t fc)
-{
- struct msgb *msg = rsl_msgb_alloc();
- struct abis_rsl_dchan_hdr *dh;
- u_int8_t *att_f8, *att_ip, *att_port;
-
- dh = (struct abis_rsl_dchan_hdr *) msgb_put(msg, sizeof(*dh));
- init_dchan_hdr(dh, RSL_MT_IPAC_CONNECT);
- dh->c.msg_discr = ABIS_RSL_MDISC_IPACCESS;
- dh->chan_nr = lchan2chan_nr(lchan);
-
- att_f8 = msgb_put(msg, sizeof(f8)+1);
- att_f8[0] = 0xf8;
- att_f8[1] = f8 >> 8;
- att_f8[2] = f8 & 0xff;
-
- att_ip = msgb_put(msg, sizeof(ip)+1);
- att_ip[0] = RSL_IE_IPAC_REMOTE_IP;
- att_ip[1] = ip >> 24;
- att_ip[2] = ip >> 16;
- att_ip[3] = ip >> 8;
- att_ip[4] = ip & 0xff;
- //att_ip[4] = 11;
-
- att_port = msgb_put(msg, sizeof(port)+1);
- att_port[0] = RSL_IE_IPAC_REMOTE_PORT;
- att_port[1] = port >> 8;
- att_port[2] = port & 0xff;
-
- msgb_tv_put(msg, 0xf4, 1); /* F4 01 */
- msgb_tv_put(msg, 0xfc, fc); /* FC 7F */
- msg->trx = lchan->ts->trx;
-
- return abis_rsl_sendmsg(msg);
-}
-
-static int abis_rsl_rx_ipacc_bindack(struct msgb *msg)
-{
- struct abis_rsl_dchan_hdr *dh = msgb_l2(msg);
- struct tlv_parsed tv;
- struct gsm_bts_trx_ts *ts = msg->lchan->ts;
- struct in_addr ip;
- u_int16_t port, attr_f8;
-
- /* the BTS has acknowledged a local bind, it now tells us the IP
- * address and port number to which it has bound the given logical
- * channel */
-
- rsl_tlv_parse(&tv, dh->data, msgb_l2len(msg)-sizeof(*dh));
- if (!TLVP_PRESENT(&tv, RSL_IE_IPAC_LOCAL_PORT) ||
- !TLVP_PRESENT(&tv, RSL_IE_IPAC_LOCAL_IP) ||
- !TLVP_PRESENT(&tv, 0xfc) ||
- !TLVP_PRESENT(&tv, 0xf8)) {
- DEBUGPC(DRSL, "mandatory IE missing");
- return -EINVAL;
- }
- ip.s_addr = *((u_int32_t *) TLVP_VAL(&tv, RSL_IE_IPAC_LOCAL_IP));
- port = *((u_int16_t *) TLVP_VAL(&tv, RSL_IE_IPAC_LOCAL_PORT));
- attr_f8 = *((u_int16_t *) TLVP_VAL(&tv, 0xf8));
-
- DEBUGPC(DRSL, "IP=%s PORT=%d FC=%d F8=%d",
- inet_ntoa(ip), ntohs(port), *TLVP_VAL(&tv, 0xfc),
- ntohs(attr_f8));
-
- /* update our local information about this TS */
- ts->abis_ip.bound_ip = ntohl(ip.s_addr);
- ts->abis_ip.bound_port = ntohs(port);
- ts->abis_ip.attr_f8 = ntohs(attr_f8);
- ts->abis_ip.attr_fc = *TLVP_VAL(&tv, 0xfc);
-
- dispatch_signal(SS_ABISIP, S_ABISIP_BIND_ACK, msg->lchan);
-
- return 0;
-}
-
-static int abis_rsl_rx_ipacc_disc_ind(struct msgb *msg)
-{
- struct abis_rsl_dchan_hdr *dh = msgb_l2(msg);
- struct tlv_parsed tv;
-
- rsl_tlv_parse(&tv, dh->data, msgb_l2len(msg)-sizeof(*dh));
- if (!TLVP_PRESENT(&tv, RSL_IE_CAUSE)) {
- DEBUGPC(DRSL, "mandatory IE missing! ");
- return -EINVAL;
- }
-
- DEBUGPC(DRSL, "cause=0x%02x ", *TLVP_VAL(&tv, RSL_IE_CAUSE));
-
- return 0;
-}
-
-static int abis_rsl_rx_ipacc(struct msgb *msg)
-{
- struct abis_rsl_rll_hdr *rllh = msgb_l2(msg);
- int rc = 0;
-
- msg->lchan = lchan_lookup(msg->trx, rllh->chan_nr);
- DEBUGP(DRSL, "channel=%s chan_nr=0x%02x ",
- gsm_ts_name(msg->lchan->ts), rllh->chan_nr);
-
- switch (rllh->c.msg_type) {
- case RSL_MT_IPAC_BIND_ACK:
- DEBUGPC(DRSL, "IPAC_BIND_ACK ");
- rc = abis_rsl_rx_ipacc_bindack(msg);
- break;
- case RSL_MT_IPAC_BIND_NACK:
- /* somehow the BTS was unable to bind the lchan to its local
- * port?!? */
- DEBUGPC(DRSL, "IPAC_BIND_NACK ");
- break;
- case RSL_MT_IPAC_CONNECT_ACK:
- /* the BTS tells us that a connect operation was successful */
- DEBUGPC(DRSL, "IPAC_CONNECT_ACK ");
- break;
- case RSL_MT_IPAC_CONNECT_NACK:
- /* somehow the BTS was unable to connect the lchan to a remote
- * port */
- DEBUGPC(DRSL, "IPAC_CONNECT_NACK ");
- break;
- case RSL_MT_IPAC_DISCONNECT_IND:
- DEBUGPC(DRSL, "IPAC_DISCONNECT_IND ");
- rc = abis_rsl_rx_ipacc_disc_ind(msg);
- break;
- default:
- DEBUGPC(DRSL, "Unknown ip.access msg_type 0x%02x", rllh->c.msg_type);
- break;
- }
- DEBUGPC(DRSL, "\n");
-
- return rc;
-}
-
-
-/* Entry-point where L2 RSL from BTS enters */
-int abis_rsl_rcvmsg(struct msgb *msg)
-{
- struct abis_rsl_common_hdr *rslh = msgb_l2(msg) ;
- int rc = 0;
-
- switch (rslh->msg_discr & 0xfe) {
- case ABIS_RSL_MDISC_RLL:
- rc = abis_rsl_rx_rll(msg);
- break;
- case ABIS_RSL_MDISC_DED_CHAN:
- rc = abis_rsl_rx_dchan(msg);
- break;
- case ABIS_RSL_MDISC_COM_CHAN:
- rc = abis_rsl_rx_cchan(msg);
- break;
- case ABIS_RSL_MDISC_TRX:
- rc = abis_rsl_rx_trx(msg);
- break;
- case ABIS_RSL_MDISC_LOC:
- fprintf(stderr, "unimplemented RSL msg disc 0x%02x\n",
- rslh->msg_discr);
- break;
- case ABIS_RSL_MDISC_IPACCESS:
- rc = abis_rsl_rx_ipacc(msg);
- break;
- default:
- fprintf(stderr, "unknown RSL message discriminator 0x%02x\n",
- rslh->msg_discr);
- return -EINVAL;
- }
- msgb_free(msg);
- return rc;
-}
-
-
-/* Section 3.3.2.3 . I think this looks like a table */
-int rsl_ccch_conf_to_bs_cc_chans(int ccch_conf)
-{
- switch (ccch_conf) {
- case RSL_BCCH_CCCH_CONF_1_NC:
- return 1;
- case RSL_BCCH_CCCH_CONF_1_C:
- return 1;
- case RSL_BCCH_CCCH_CONF_2_NC:
- return 2;
- case RSL_BCCH_CCCH_CONF_3_NC:
- return 3;
- case RSL_BCCH_CCCH_CONF_4_NC:
- return 4;
- default:
- return -1;
- }
-}
-
-int rsl_ccch_conf_to_bs_ccch_sdcch_comb(int ccch_conf)
-{
- switch (ccch_conf) {
- case RSL_BCCH_CCCH_CONF_1_NC:
- return 0;
- case RSL_BCCH_CCCH_CONF_1_C:
- return 1;
- case RSL_BCCH_CCCH_CONF_2_NC:
- return 0;
- case RSL_BCCH_CCCH_CONF_3_NC:
- return 0;
- case RSL_BCCH_CCCH_CONF_4_NC:
- return 0;
- default:
- return -1;
- }
-}
-
-/* From Table 10.5.33 of GSM 04.08 */
-int rsl_number_of_paging_subchannels(struct gsm_bts *bts)
-{
- if (bts->chan_desc.ccch_conf == RSL_BCCH_CCCH_CONF_1_C) {
- return MAX(1, (3 - bts->chan_desc.bs_ag_blks_res))
- * (bts->chan_desc.bs_pa_mfrms + 2);
- } else {
- return (9 - bts->chan_desc.bs_ag_blks_res)
- * (bts->chan_desc.bs_pa_mfrms + 2);
- }
-}
diff --git a/src/bs11_config.c b/src/bs11_config.c
deleted file mode 100644
index 656feb453..000000000
--- a/src/bs11_config.c
+++ /dev/null
@@ -1,805 +0,0 @@
-/* Siemens BS-11 microBTS configuration tool */
-
-/* (C) 2009 by Harald Welte <laforge@gnumonks.org>
- * All Rights Reserved
- *
- * This software is based on ideas (but not code) of BS11Config
- * (C) 2009 by Dieter Spaar <spaar@mirider.augusta.de>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- */
-
-#include <unistd.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <errno.h>
-#include <string.h>
-#include <getopt.h>
-#include <fcntl.h>
-#include <signal.h>
-
-#include <sys/types.h>
-#include <sys/stat.h>
-
-#include <openbsc/gsm_data.h>
-#include <openbsc/abis_nm.h>
-#include <openbsc/msgb.h>
-#include <openbsc/tlv.h>
-#include <openbsc/debug.h>
-#include <openbsc/select.h>
-#include <openbsc/rs232.h>
-
-/* state of our bs11_config application */
-enum bs11cfg_state {
- STATE_NONE,
- STATE_LOGON_WAIT,
- STATE_LOGON_ACK,
- STATE_SWLOAD,
- STATE_QUERY,
-};
-static enum bs11cfg_state bs11cfg_state = STATE_NONE;
-static char *command;
-struct timer_list status_timer;
-
-static const u_int8_t obj_li_attr[] = {
- NM_ATT_BS11_BIT_ERR_THESH, 0x09, 0x00,
- NM_ATT_BS11_L1_PROT_TYPE, 0x00,
- NM_ATT_BS11_LINE_CFG, 0x00,
-};
-static const u_int8_t obj_bbsig0_attr[] = {
- NM_ATT_BS11_RSSI_OFFS, 0x02, 0x00, 0x00,
- NM_ATT_BS11_DIVERSITY, 0x01, 0x00,
-};
-static const u_int8_t obj_pa0_attr[] = {
- NM_ATT_BS11_TXPWR, 0x01, BS11_TRX_POWER_GSM_30mW,
-};
-static const char *trx1_password = "1111111111";
-#define TEI_OML 25
-
-static const u_int8_t too_fast[] = { 0x12, 0x80, 0x00, 0x00, 0x02, 0x02 };
-
-
-int handle_serial_msg(struct msgb *rx_msg);
-
-/* create all objects for an initial configuration */
-static int create_objects(struct gsm_bts *bts)
-{
- fprintf(stdout, "Crating Objects for minimal config\n");
- abis_nm_bs11_create_object(bts, BS11_OBJ_LI, 0, sizeof(obj_li_attr),
- obj_li_attr);
- abis_nm_bs11_create_object(bts, BS11_OBJ_GPSU, 0, 0, NULL);
- abis_nm_bs11_create_object(bts, BS11_OBJ_ALCO, 0, 0, NULL);
- abis_nm_bs11_create_object(bts, BS11_OBJ_CCLK, 0, 0, NULL);
- abis_nm_bs11_create_object(bts, BS11_OBJ_BBSIG, 0,
- sizeof(obj_bbsig0_attr), obj_bbsig0_attr);
- abis_nm_bs11_create_object(bts, BS11_OBJ_PA, 0,
- sizeof(obj_pa0_attr), obj_pa0_attr);
- abis_nm_bs11_create_envaBTSE(bts, 0);
- abis_nm_bs11_create_envaBTSE(bts, 1);
- abis_nm_bs11_create_envaBTSE(bts, 2);
- abis_nm_bs11_create_envaBTSE(bts, 3);
-
- abis_nm_bs11_conn_oml_tei(bts, 0, 1, 0xff, TEI_OML);
-
- abis_nm_bs11_set_trx_power(&bts->trx[0], BS11_TRX_POWER_GSM_30mW);
-
- sleep(1);
-
- abis_nm_bs11_set_trx1_pw(bts, trx1_password);
-
- sleep(1);
-
- return 0;
-}
-
-static int create_trx1(struct gsm_bts *bts)
-{
- u_int8_t bbsig1_attr[sizeof(obj_bbsig0_attr)+12];
- u_int8_t *cur = bbsig1_attr;
-
- fprintf(stdout, "Crating Objects for TRX1\n");
-
- abis_nm_bs11_set_trx1_pw(bts, trx1_password);
-
- sleep(1);
-
- cur = tlv_put(cur, NM_ATT_BS11_PASSWORD, 10,
- (u_int8_t *)trx1_password);
- memcpy(cur, obj_bbsig0_attr, sizeof(obj_bbsig0_attr));
- abis_nm_bs11_create_object(bts, BS11_OBJ_BBSIG, 1,
- sizeof(bbsig1_attr), bbsig1_attr);
- abis_nm_bs11_create_object(bts, BS11_OBJ_PA, 1,
- sizeof(obj_pa0_attr), obj_pa0_attr);
- abis_nm_bs11_set_trx_power(&bts->trx[1], BS11_TRX_POWER_GSM_30mW);
-
- return 0;
-}
-
-static char *serial_port = "/dev/ttyUSB0";
-static char *fname_safety = "BTSBMC76.SWI";
-static char *fname_software = "HS011106.SWL";
-static int delay_ms = 0;
-static int win_size = 8;
-static int param_disconnect = 0;
-static int param_restart = 0;
-static int param_forced = 0;
-static struct gsm_bts *g_bts;
-
-static int file_is_readable(const char *fname)
-{
- int rc;
- struct stat st;
-
- rc = stat(fname, &st);
- if (rc < 0)
- return 0;
-
- if (S_ISREG(st.st_mode) && (st.st_mode & S_IRUSR))
- return 1;
-
- return 0;
-}
-
-static int percent;
-static int percent_old;
-
-/* callback function passed to the ABIS OML code */
-static int swload_cbfn(unsigned int hook, unsigned int event, struct msgb *msg,
- void *data, void *param)
-{
- if (hook != GSM_HOOK_NM_SWLOAD)
- return 0;
-
- switch (event) {
- case NM_MT_LOAD_INIT_ACK:
- fprintf(stdout, "Software Load Initiate ACK\n");
- break;
- case NM_MT_LOAD_INIT_NACK:
- fprintf(stderr, "ERROR: Software Load Initiate NACK\n");
- exit(5);
- break;
- case NM_MT_LOAD_END_ACK:
- if (data) {
- /* we did a safety load and must activate it */
- abis_nm_software_activate(g_bts, fname_safety,
- swload_cbfn, g_bts);
- sleep(5);
- }
- break;
- case NM_MT_LOAD_END_NACK:
- fprintf(stderr, "ERROR: Software Load End NACK\n");
- exit(3);
- break;
- case NM_MT_ACTIVATE_SW_NACK:
- fprintf(stderr, "ERROR: Activate Software NACK\n");
- exit(4);
- break;
- case NM_MT_ACTIVATE_SW_ACK:
- bs11cfg_state = STATE_NONE;
-
- break;
- case NM_MT_LOAD_SEG_ACK:
- percent = abis_nm_software_load_status(g_bts);
- if (percent > percent_old)
- printf("Software Download Progress: %d%%\n", percent);
- percent_old = percent;
- break;
- }
- return 0;
-}
-
-static const char *bs11_link_state[] = {
- [0x00] = "Down",
- [0x01] = "Up",
- [0x02] = "Restoring",
-};
-
-static const char *linkstate_name(u_int8_t linkstate)
-{
- if (linkstate > ARRAY_SIZE(bs11_link_state))
- return "Unknown";
-
- return bs11_link_state[linkstate];
-}
-
-static const char *mbccu_load[] = {
- [0] = "No Load",
- [1] = "Load BTSCAC",
- [2] = "Load BTSDRX",
- [3] = "Load BTSBBX",
- [4] = "Load BTSARC",
- [5] = "Load",
-};
-
-static const char *mbccu_load_name(u_int8_t linkstate)
-{
- if (linkstate > ARRAY_SIZE(mbccu_load))
- return "Unknown";
-
- return mbccu_load[linkstate];
-}
-
-static const char *bts_phase_name(u_int8_t phase)
-{
- switch (phase) {
- case BS11_STATE_WARM_UP:
- case BS11_STATE_WARM_UP_2:
- return "Warm Up";
- break;
- case BS11_STATE_LOAD_SMU_SAFETY:
- return "Load SMU Safety";
- break;
- case BS11_STATE_LOAD_SMU_INTENDED:
- return "Load SMU Intended";
- break;
- case BS11_STATE_LOAD_MBCCU:
- return "Load MBCCU";
- break;
- case BS11_STATE_SOFTWARE_RQD:
- return "Software required";
- break;
- case BS11_STATE_WAIT_MIN_CFG:
- case BS11_STATE_WAIT_MIN_CFG_2:
- return "Wait minimal config";
- break;
- case BS11_STATE_MAINTENANCE:
- return "Maintenance";
- break;
- case BS11_STATE_NORMAL:
- return "Normal";
- break;
- case BS11_STATE_ABIS_LOAD:
- return "Abis load";
- break;
- default:
- return "Unknown";
- break;
- }
-}
-
-static const char *trx_power_name(u_int8_t pwr)
-{
- switch (pwr) {
- case BS11_TRX_POWER_GSM_2W:
- return "2W (GSM)";
- case BS11_TRX_POWER_GSM_250mW:
- return "250mW (GSM)";
- case BS11_TRX_POWER_GSM_80mW:
- return "80mW (GSM)";
- case BS11_TRX_POWER_GSM_30mW:
- return "30mW (GSM)";
- case BS11_TRX_POWER_DCS_3W:
- return "3W (DCS)";
- case BS11_TRX_POWER_DCS_1W6:
- return "1.6W (DCS)";
- case BS11_TRX_POWER_DCS_500mW:
- return "500mW (DCS)";
- case BS11_TRX_POWER_DCS_160mW:
- return "160mW (DCS)";
- default:
- return "unknown value";
- }
-}
-
-static const char *pll_mode_name(u_int8_t mode)
-{
- switch (mode) {
- case BS11_LI_PLL_LOCKED:
- return "E1 Locked";
- case BS11_LI_PLL_STANDALONE:
- return "Standalone";
- default:
- return "unknown";
- }
-}
-
-static const char *cclk_acc_name(u_int8_t acc)
-{
- switch (acc) {
- case 0:
- /* Out of the demanded +/- 0.05ppm */
- return "Medium";
- case 1:
- /* Synchronized with Abis, within demanded tolerance +/- 0.05ppm */
- return "High";
- default:
- return "unknown";
- }
-}
-
-static const char *obj_name(struct abis_om_fom_hdr *foh)
-{
- static char retbuf[256];
-
- retbuf[0] = 0;
-
- switch (foh->obj_class) {
- case NM_OC_BS11:
- strcat(retbuf, "BS11 ");
- switch (foh->obj_inst.bts_nr) {
- case BS11_OBJ_PA:
- sprintf(retbuf+strlen(retbuf), "Power Amplifier %d ",
- foh->obj_inst.ts_nr);
- break;
- case BS11_OBJ_LI:
- sprintf(retbuf+strlen(retbuf), "Line Interface ");
- break;
- case BS11_OBJ_CCLK:
- sprintf(retbuf+strlen(retbuf), "CCLK ");
- break;
- }
- break;
- case NM_OC_SITE_MANAGER:
- strcat(retbuf, "SITE MANAGER ");
- break;
- }
- return retbuf;
-}
-
-static void print_state(struct tlv_parsed *tp)
-{
- if (TLVP_PRESENT(tp, NM_ATT_BS11_BTS_STATE)) {
- u_int8_t phase, mbccu;
- if (TLVP_LEN(tp, NM_ATT_BS11_BTS_STATE) >= 1) {
- phase = *TLVP_VAL(tp, NM_ATT_BS11_BTS_STATE);
- printf("PHASE: %u %-20s ", phase & 0xf,
- bts_phase_name(phase));
- }
- if (TLVP_LEN(tp, NM_ATT_BS11_BTS_STATE) >= 2) {
- mbccu = *(TLVP_VAL(tp, NM_ATT_BS11_BTS_STATE)+1);
- printf("MBCCU0: %-11s MBCCU1: %-11s ",
- mbccu_load_name(mbccu & 0xf), mbccu_load_name(mbccu >> 4));
- }
- }
- if (TLVP_PRESENT(tp, NM_ATT_BS11_E1_STATE) &&
- TLVP_LEN(tp, NM_ATT_BS11_E1_STATE) >= 1) {
- u_int8_t e1_state = *TLVP_VAL(tp, NM_ATT_BS11_E1_STATE);
- printf("Abis-link: %-9s ", linkstate_name(e1_state & 0xf));
- }
- printf("\n");
-}
-
-static int print_attr(struct tlv_parsed *tp)
-{
- if (TLVP_PRESENT(tp, NM_ATT_BS11_ESN_PCB_SERIAL)) {
- printf("\tBS-11 ESN PCB Serial Number: %s\n",
- TLVP_VAL(tp, NM_ATT_BS11_ESN_PCB_SERIAL));
- }
- if (TLVP_PRESENT(tp, NM_ATT_BS11_ESN_HW_CODE_NO)) {
- printf("\tBS-11 ESN Hardware Code Number: %s\n",
- TLVP_VAL(tp, NM_ATT_BS11_ESN_HW_CODE_NO)+6);
- }
- if (TLVP_PRESENT(tp, NM_ATT_BS11_ESN_FW_CODE_NO)) {
- printf("\tBS-11 ESN Firmware Code Number: %s\n",
- TLVP_VAL(tp, NM_ATT_BS11_ESN_FW_CODE_NO)+6);
- }
-#if 0
- if (TLVP_PRESENT(tp, NM_ATT_BS11_BOOT_SW_VERS)) {
- printf("BS-11 Boot Software Version: %s\n",
- TLVP_VAL(tp, NM_ATT_BS11_BOOT_SW_VERS)+6);
- }
-#endif
- if (TLVP_PRESENT(tp, NM_ATT_ABIS_CHANNEL) &&
- TLVP_LEN(tp, NM_ATT_ABIS_CHANNEL) >= 3) {
- const u_int8_t *chan = TLVP_VAL(tp, NM_ATT_ABIS_CHANNEL);
- printf("\tE1 Channel: Port=%u Timeslot=%u ",
- chan[0], chan[1]);
- if (chan[2] == 0xff)
- printf("(Full Slot)\n");
- else
- printf("Subslot=%u\n", chan[2]);
- }
- if (TLVP_PRESENT(tp, NM_ATT_TEI))
- printf("\tTEI: %d\n", *TLVP_VAL(tp, NM_ATT_TEI));
- if (TLVP_PRESENT(tp, NM_ATT_BS11_TXPWR) &&
- TLVP_LEN(tp, NM_ATT_BS11_TXPWR) >= 1) {
- printf("\tTRX Power: %s\n",
- trx_power_name(*TLVP_VAL(tp, NM_ATT_BS11_TXPWR)));
- }
- if (TLVP_PRESENT(tp, NM_ATT_BS11_PLL_MODE) &&
- TLVP_LEN(tp, NM_ATT_BS11_PLL_MODE) >= 1) {
- printf("\tPLL Mode: %s\n",
- pll_mode_name(*TLVP_VAL(tp, NM_ATT_BS11_PLL_MODE)));
- }
- if (TLVP_PRESENT(tp, NM_ATT_BS11_PLL) &&
- TLVP_LEN(tp, NM_ATT_BS11_PLL) >= 4) {
- const u_int8_t *vp = TLVP_VAL(tp, NM_ATT_BS11_PLL);
- printf("\tPLL Set Value=%d, Work Value=%d\n",
- vp[0] << 8 | vp[1], vp[2] << 8 | vp[3]);
- }
- if (TLVP_PRESENT(tp, NM_ATT_BS11_CCLK_ACCURACY) &&
- TLVP_LEN(tp, NM_ATT_BS11_CCLK_ACCURACY) >= 1) {
- const u_int8_t *acc = TLVP_VAL(tp, NM_ATT_BS11_CCLK_ACCURACY);
- printf("\tCCLK Accuracy: %s (%d)\n", cclk_acc_name(*acc), *acc);
- }
- if (TLVP_PRESENT(tp, NM_ATT_BS11_CCLK_TYPE) &&
- TLVP_LEN(tp, NM_ATT_BS11_CCLK_TYPE) >= 1) {
- const u_int8_t *acc = TLVP_VAL(tp, NM_ATT_BS11_CCLK_TYPE);
- printf("\tCCLK Type=%d\n", *acc);
- }
-
-
- return 0;
-}
-
-static void cmd_query(void)
-{
- bs11cfg_state = STATE_QUERY;
- abis_nm_bs11_get_serno(g_bts);
- abis_nm_bs11_get_oml_tei_ts(g_bts);
- abis_nm_bs11_get_pll_mode(g_bts);
- abis_nm_bs11_get_cclk(g_bts);
- abis_nm_bs11_get_trx_power(&g_bts->trx[0]);
- abis_nm_bs11_get_trx_power(&g_bts->trx[1]);
- sleep(1);
- abis_nm_bs11_factory_logon(g_bts, 0);
- command = NULL;
-}
-
-/* handle a response from the BTS to a GET STATE command */
-static int handle_state_resp(enum abis_bs11_phase state)
-{
- int rc = 0;
-
- switch (state) {
- case BS11_STATE_WARM_UP:
- case BS11_STATE_LOAD_SMU_SAFETY:
- case BS11_STATE_LOAD_SMU_INTENDED:
- case BS11_STATE_LOAD_MBCCU:
- break;
- case BS11_STATE_SOFTWARE_RQD:
- bs11cfg_state = STATE_SWLOAD;
- /* send safety load. Use g_bts as private 'param'
- * argument, so our swload_cbfn can distinguish
- * a safety load from a regular software */
- if (file_is_readable(fname_safety))
- rc = abis_nm_software_load(g_bts, fname_safety,
- win_size, param_forced,
- swload_cbfn, g_bts);
- else
- fprintf(stderr, "No valid Safety Load file \"%s\"\n",
- fname_safety);
- break;
- case BS11_STATE_WAIT_MIN_CFG:
- case BS11_STATE_WAIT_MIN_CFG_2:
- bs11cfg_state = STATE_SWLOAD;
- rc = create_objects(g_bts);
- break;
- case BS11_STATE_MAINTENANCE:
- if (command) {
- if (!strcmp(command, "disconnect"))
- abis_nm_bs11_factory_logon(g_bts, 0);
- else if (!strcmp(command, "reconnect"))
- rc = abis_nm_bs11_bsc_disconnect(g_bts, 1);
- else if (!strcmp(command, "software")
- && bs11cfg_state != STATE_SWLOAD) {
- bs11cfg_state = STATE_SWLOAD;
- /* send software (FIXME: over A-bis?) */
- if (file_is_readable(fname_software))
- rc = abis_nm_bs11_load_swl(g_bts, fname_software,
- win_size, param_forced,
- swload_cbfn);
- else
- fprintf(stderr, "No valid Software file \"%s\"\n",
- fname_software);
- } else if (!strcmp(command, "delete-trx1")) {
- printf("Locing BBSIG and PA objects of TRX1\n");
- abis_nm_chg_adm_state(g_bts, NM_OC_BS11,
- BS11_OBJ_BBSIG, 0, 1,
- NM_STATE_LOCKED);
- abis_nm_chg_adm_state(g_bts, NM_OC_BS11,
- BS11_OBJ_PA, 0, 1,
- NM_STATE_LOCKED);
- sleep(1);
- printf("Deleting BBSIG and PA objects of TRX1\n");
- abis_nm_bs11_delete_object(g_bts, BS11_OBJ_BBSIG, 1);
- abis_nm_bs11_delete_object(g_bts, BS11_OBJ_PA, 1);
- sleep(1);
- abis_nm_bs11_factory_logon(g_bts, 0);
- command = NULL;
- } else if (!strcmp(command, "create-trx1")) {
- create_trx1(g_bts);
- sleep(1);
- abis_nm_bs11_factory_logon(g_bts, 0);
- command = NULL;
- } else if (!strcmp(command, "pll-e1-locked")) {
- abis_nm_bs11_set_pll_locked(g_bts, 1);
- sleep(1);
- abis_nm_bs11_factory_logon(g_bts, 0);
- command = NULL;
- } else if (!strcmp(command, "pll-standalone")) {
- abis_nm_bs11_set_pll_locked(g_bts, 0);
- sleep(1);
- abis_nm_bs11_factory_logon(g_bts, 0);
- command = NULL;
- } else if (!strcmp(command, "oml-tei")) {
- abis_nm_bs11_conn_oml_tei(g_bts, 0, 1, 0xff, TEI_OML);
- command = NULL;
- } else if (!strcmp(command, "restart")) {
- abis_nm_bs11_restart(g_bts);
- command = NULL;
- } else if (!strcmp(command, "query")) {
- cmd_query();
- }
- }
- break;
- case BS11_STATE_NORMAL:
- if (command) {
- if (!strcmp(command, "reconnect"))
- abis_nm_bs11_factory_logon(g_bts, 0);
- else if (!strcmp(command, "disconnect"))
- abis_nm_bs11_bsc_disconnect(g_bts, 0);
- else if (!strcmp(command, "query")) {
- cmd_query();
- }
- } else if (param_disconnect) {
- param_disconnect = 0;
- abis_nm_bs11_bsc_disconnect(g_bts, 0);
- if (param_restart) {
- param_restart = 0;
- abis_nm_bs11_restart(g_bts);
- }
- }
- break;
- default:
- break;
- }
- return rc;
-}
-
-/* handle a fully-received message/packet from the RS232 port */
-int handle_serial_msg(struct msgb *rx_msg)
-{
- struct abis_om_hdr *oh;
- struct abis_om_fom_hdr *foh;
- struct tlv_parsed tp;
- int rc = -1;
-
-#if 0
- if (rx_msg->len < LAPD_HDR_LEN
- + sizeof(struct abis_om_fom_hdr)
- + sizeof(struct abis_om_hdr)) {
- if (!memcmp(rx_msg->data + 2, too_fast,
- sizeof(too_fast))) {
- fprintf(stderr, "BS11 tells us we're too "
- "fast, try --delay bigger than %u\n",
- delay_ms);
- return -E2BIG;
- } else
- fprintf(stderr, "unknown BS11 message\n");
- }
-#endif
-
- oh = (struct abis_om_hdr *) msgb_l2(rx_msg);
- foh = (struct abis_om_fom_hdr *) oh->data;
- switch (foh->msg_type) {
- case NM_MT_BS11_LMT_LOGON_ACK:
- printf("LMT LOGON: ACK\n\n");
- if (bs11cfg_state == STATE_NONE)
- bs11cfg_state = STATE_LOGON_ACK;
- rc = abis_nm_bs11_get_state(g_bts);
- break;
- case NM_MT_BS11_LMT_LOGOFF_ACK:
- printf("LMT LOGOFF: ACK\n");
- exit(0);
- break;
- case NM_MT_BS11_GET_STATE_ACK:
- rc = abis_nm_tlv_parse(&tp, foh->data, oh->length-sizeof(*foh));
- print_state(&tp);
- if (TLVP_PRESENT(&tp, NM_ATT_BS11_BTS_STATE) &&
- TLVP_LEN(&tp, NM_ATT_BS11_BTS_STATE) >= 1)
- rc = handle_state_resp(*TLVP_VAL(&tp, NM_ATT_BS11_BTS_STATE));
- break;
- case NM_MT_GET_ATTR_RESP:
- printf("\n%sATTRIBUTES:\n", obj_name(foh));
- abis_nm_tlv_parse(&tp, foh->data, oh->length-sizeof(*foh));
- rc = print_attr(&tp);
- //hexdump(foh->data, oh->length-sizeof(*foh));
- break;
- case NM_MT_BS11_SET_ATTR_ACK:
- printf("SET ATTRIBUTE ObjClass=0x%02x ObjInst=(%d,%d,%d) ACK\n",
- foh->obj_class, foh->obj_inst.bts_nr,
- foh->obj_inst.trx_nr, foh->obj_inst.ts_nr);
- rc = 0;
- break;
- case NM_MT_BS11_SET_ATTR_NACK:
- printf("SET ATTRIBUTE ObjClass=0x%02x ObjInst=(%d,%d,%d) NACK\n",
- foh->obj_class, foh->obj_inst.bts_nr,
- foh->obj_inst.trx_nr, foh->obj_inst.ts_nr);
- break;
- default:
- rc = abis_nm_rcvmsg(rx_msg);
- }
- if (rc < 0) {
- perror("ERROR in main loop");
- //break;
- }
- if (rc == 1)
- return rc;
-
- switch (bs11cfg_state) {
- case STATE_NONE:
- abis_nm_bs11_factory_logon(g_bts, 1);
- break;
- case STATE_LOGON_ACK:
- bsc_schedule_timer(&status_timer, 5, 0);
- break;
- default:
- break;
- }
-
- return rc;
-}
-
-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)
-{
- return 0;
-}
-
-void status_timer_cb(void *data)
-{
- abis_nm_bs11_get_state(g_bts);
-}
-
-static void print_banner(void)
-{
- printf("bs11_config (C) 2009 by Harald Welte and Dieter Spaar\n");
- printf("This is FREE SOFTWARE with ABSOLUTELY NO WARRANTY\n\n");
-}
-
-static void print_help(void)
-{
- printf("bs11_config [options] [command]\n");
- printf("\nSupported options:\n");
- printf("\t-h --help\t\t\tPrint this help text\n");
- printf("\t-p --port </dev/ttyXXX>\t\tSpecify serial port\n");
- printf("\t-s --software <file>\t\tSpecify Software file\n");
- printf("\t-S --safety <file>\t\tSpecify Safety Load file\n");
- printf("\t-d --delay <ms>\t\tSpecify delay in milliseconds\n");
- printf("\t-D --disconnect\t\t\tDisconnect BTS from BSC\n");
- printf("\t-w --win-size <num>\t\tSpecify Window Size\n");
- printf("\t-f --forced\t\t\tForce Software Load\n");
- printf("\nSupported commands:\n");
- printf("\tquery\t\tQuery the BS-11 about serial number and configuration\n");
- printf("\tdisconnect\tDisconnect A-bis link (go into administrative state)\n");
- printf("\tresconnect\tReconnect A-bis link (go into normal state)\n");
- printf("\trestart\t\tRestart the BTS\n");
- printf("\tsoftware\tDownload Software (only in administrative state)\n");
- printf("\tcreate-trx1\tCreate objects for TRX1 (Danger: Your BS-11 might overheat)\n");
- printf("\tdelete-trx1\tDelete objects for TRX1\n");
- printf("\tpll-e1-locked\tSet the PLL to be locked to E1 clock\n");
- printf("\tpll-standalone\tSet the PLL to be in standalone mode\n");
- printf("\toml-tei\tSet OML E1 TS and TEI\n");
-}
-
-static void handle_options(int argc, char **argv)
-{
- int option_index = 0;
- print_banner();
-
- while (1) {
- int c;
- static struct option long_options[] = {
- { "help", 0, 0, 'h' },
- { "port", 1, 0, 'p' },
- { "software", 1, 0, 's' },
- { "safety", 1, 0, 'S' },
- { "delay", 1, 0, 'd' },
- { "disconnect", 0, 0, 'D' },
- { "win-size", 1, 0, 'w' },
- { "forced", 0, 0, 'f' },
- { "restart", 0, 0, 'r' },
- { "debug", 1, 0, 'b'},
- };
-
- c = getopt_long(argc, argv, "hp:s:S:td:Dw:fra:",
- long_options, &option_index);
-
- if (c == -1)
- break;
-
- switch (c) {
- case 'h':
- print_help();
- exit(0);
- case 'p':
- serial_port = optarg;
- break;
- case 'b':
- debug_parse_category_mask(optarg);
- break;
- case 's':
- fname_software = optarg;
- break;
- case 'S':
- fname_safety = optarg;
- break;
- case 'd':
- delay_ms = atoi(optarg);
- break;
- case 'w':
- win_size = atoi(optarg);
- break;
- case 'D':
- param_disconnect = 1;
- break;
- case 'f':
- param_forced = 1;
- break;
- case 'r':
- param_disconnect = 1;
- param_restart = 1;
- break;
- default:
- break;
- }
- }
- if (optind < argc)
- command = argv[optind];
-}
-
-static int num_sigint;
-
-static void signal_handler(int signal)
-{
- fprintf(stdout, "\nsignal %u received\n", signal);
-
- switch (signal) {
- case SIGINT:
- num_sigint++;
- abis_nm_bs11_factory_logon(g_bts, 0);
- if (num_sigint >= 3)
- exit(0);
- break;
- }
-}
-
-int main(int argc, char **argv)
-{
- struct gsm_network *gsmnet;
- int rc;
-
- handle_options(argc, argv);
-
- gsmnet = gsm_network_init(1, 1, 1, GSM_BTS_TYPE_BS11);
- if (!gsmnet) {
- fprintf(stderr, "Unable to allocate gsm network\n");
- exit(1);
- }
- g_bts = &gsmnet->bts[0];
-
- rc = rs232_setup(serial_port, delay_ms, g_bts);
- if (rc < 0) {
- fprintf(stderr, "Problem setting up serial port\n");
- exit(1);
- }
-
- signal(SIGINT, &signal_handler);
-
- abis_nm_bs11_factory_logon(g_bts, 1);
- //abis_nm_bs11_get_serno(g_bts);
-
- status_timer.cb = status_timer_cb;
-
- while (1) {
- bsc_select_main(0);
- }
-
- abis_nm_bs11_factory_logon(g_bts, 0);
-
- exit(0);
-}
diff --git a/src/bsc_hack.c b/src/bsc_hack.c
deleted file mode 100644
index 7aa8b9aef..000000000
--- a/src/bsc_hack.c
+++ /dev/null
@@ -1,1159 +0,0 @@
-/* A hackish minimal BSC (+MSC +HLR) implementation */
-
-/* (C) 2008-2009 by Harald Welte <laforge@gnumonks.org>
- * (C) 2009 by Holger Hans Peter Freyther <zecke@selfish.org>
- * All Rights Reserved
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- */
-
-#include <unistd.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <stdarg.h>
-#include <time.h>
-#include <string.h>
-#include <errno.h>
-#include <signal.h>
-#include <fcntl.h>
-#include <sys/stat.h>
-
-#define _GNU_SOURCE
-#include <getopt.h>
-
-#include <openbsc/db.h>
-#include <openbsc/timer.h>
-#include <openbsc/gsm_data.h>
-#include <openbsc/gsm_04_08.h>
-#include <openbsc/select.h>
-#include <openbsc/abis_rsl.h>
-#include <openbsc/abis_nm.h>
-#include <openbsc/debug.h>
-#include <openbsc/misdn.h>
-#include <openbsc/telnet_interface.h>
-#include <openbsc/paging.h>
-#include <openbsc/e1_input.h>
-#include <openbsc/signal.h>
-
-/* global pointer to the gsm network data structure */
-static struct gsm_network *gsmnet;
-
-/* MCC and MNC for the Location Area Identifier */
-static int MCC = 1;
-static int MNC = 1;
-static int LAC = 1;
-static int ARFCN = HARDCODED_ARFCN;
-static int cardnr = 0;
-static int release_l2 = 0;
-static enum gsm_bts_type BTS_TYPE = GSM_BTS_TYPE_BS11;
-static const char *database_name = "hlr.sqlite3";
-
-/* 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,
- NM_ATT_BS11_SH_LAPD_INT_TIMER,
- 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, NM_OC_BTS, 0x00, 0xFF, 0xFF,
- NM_ATT_BSIC, HARDCODED_BSIC,
- 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, NM_BS11_CANR_GSM,
- NM_ATT_BS11_ENA_INTERF_CLASS, 0x01,
- NM_ATT_BS11_FACCH_QUAL, 0x06,
- /* interference avg. period in numbers of SACCH multifr */
- 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, NM_OC_BS11_HANDOVER, 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, NM_OC_BS11_PWR_CTRL, 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, NM_OC_RADIO_CARRIER, 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,
- /* interference avg. period in numbers of SACCH multifr */
- NM_ATT_INTAVE_PARAM, 0x06,
- /* conn fail based on SACCH error rate */
- 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, 10, /* busy threshold in - dBm */
- NM_ATT_LDAVG_SLOTS, 0x03, 0xe8, /* rach load averaging 1000 slots */
- NM_ATT_BTS_AIR_TIMER, 128, /* miliseconds */
- NM_ATT_NY1, 10, /* 10 retransmissions of physical config */
- NM_ATT_BCCH_ARFCN, HARDCODED_ARFCN >> 8, HARDCODED_ARFCN & 0xff,
- NM_ATT_BSIC, HARDCODED_BSIC,
-};
-
-static unsigned char nanobts_attr_radio[] = {
- NM_ATT_RF_MAXPOWR_R, 0x0c, /* number of -2dB reduction steps / Pn */
- 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 */
-};
-
-/* Callback function to be called whenever we get a GSM 12.21 state change event */
-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 = 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->bts_nr, 0xff, 0xff);
- abis_nm_chg_adm_state(bts, NM_OC_BTS,
- bts->bts_nr, 0xff, 0xff,
- NM_STATE_UNLOCKED);
- }
- break;
- case NM_OC_CHANNEL:
- ts = obj;
- 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->bts_nr, trx->nr, ts->nr);
- abis_nm_chg_adm_state(trx->bts, NM_OC_CHANNEL,
- trx->bts->bts_nr, trx->nr, ts->nr,
- NM_STATE_UNLOCKED);
- }
- break;
- default:
- break;
- }
- break;
- default:
- //DEBUGP(DMM, "Unhandled state change in %s:%d\n", __func__, __LINE__);
- break;
- }
- return 0;
-}
-
-/* Callback function to be called every time we receive a 12.21 SW activated report */
-static int sw_activ_rep(struct msgb *mb)
-{
- struct abis_om_fom_hdr *foh = msgb_l3(mb);
- struct gsm_bts_trx *trx = mb->trx;
-
- switch (foh->obj_class) {
- case NM_OC_BASEB_TRANSC:
- /* TRX software is active, tell it to initiate RSL Link */
- abis_nm_ipaccess_msg(trx->bts, 0xe0, NM_OC_BASEB_TRANSC,
- trx->bts->bts_nr, trx->nr, 0xff,
- nanobts_attr_e0, sizeof(nanobts_attr_e0));
- abis_nm_opstart(trx->bts, NM_OC_BASEB_TRANSC,
- trx->bts->bts_nr, trx->nr, 0xff);
- abis_nm_chg_adm_state(trx->bts, NM_OC_BASEB_TRANSC,
- trx->bts->bts_nr, trx->nr, 0xff,
- NM_STATE_UNLOCKED);
- break;
- case NM_OC_RADIO_CARRIER:
- abis_nm_set_radio_attr(trx, nanobts_attr_radio,
- sizeof(nanobts_attr_radio));
- abis_nm_opstart(trx->bts, NM_OC_RADIO_CARRIER,
- trx->bts->bts_nr, trx->nr, 0xff);
- abis_nm_chg_adm_state(trx->bts, NM_OC_RADIO_CARRIER,
- trx->bts->bts_nr, trx->nr, 0xff,
- NM_STATE_UNLOCKED);
- break;
- }
- return 0;
-}
-
-/* Callback function to be called every time we receive a signal from NM */
-static int nm_sig_cb(unsigned int subsys, unsigned int signal,
- void *handler_data, void *signal_data)
-{
- switch (signal) {
- case S_NM_SW_ACTIV_REP:
- return sw_activ_rep(signal_data);
- default:
- 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);
- 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 */
- 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 */
- 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 */
- 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 */
- 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 */
- 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 */
- 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 */
- 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 for BTS %u\n", bts->nr);
-
- 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;
-}
-
-static int shutdown_net(struct gsm_network *net)
-{
- 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;
-}
-
-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[] = {
- {
- .type = RSL_SYSTEM_INFO_1,
- .len = sizeof(si1),
- .data = si1,
- }, {
- .type = RSL_SYSTEM_INFO_2,
- .len = sizeof(si2),
- .data = si2,
- }, {
- .type = RSL_SYSTEM_INFO_3,
- .len = sizeof(si3),
- .data = si3,
- }, {
- .type = RSL_SYSTEM_INFO_4,
- .len = sizeof(si4),
- .data = 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)
-{
- 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;
-}
-
-/*
- * 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;
-
- /* patch BSIC */
- msg_2[6] = bts->bsic;
- nanobts_attr_bts[sizeof(nanobts_attr_bts)-1] = bts->bsic;
-}
-
-
-static void bootstrap_rsl(struct gsm_bts_trx *trx)
-{
- fprintf(stdout, "bootstrapping RSL for BTS/TRX (%u/%u) "
- "using MCC=%u MNC=%u\n", trx->nr, trx->bts->nr, MCC, MNC);
- 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;
- }
-}
-
-static int bootstrap_bts(struct gsm_bts *bts)
-{
- 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);
-
- if (bts->type == GSM_BTS_TYPE_BS11) {
- struct gsm_bts_trx *trx = &bts->trx[0];
- set_ts_e1link(&trx->ts[0], 0, 1, 0xff);
- set_ts_e1link(&trx->ts[1], 0, 2, 1);
- set_ts_e1link(&trx->ts[2], 0, 2, 2);
- set_ts_e1link(&trx->ts[3], 0, 2, 3);
- set_ts_e1link(&trx->ts[4], 0, 3, 0);
- set_ts_e1link(&trx->ts[5], 0, 3, 1);
- set_ts_e1link(&trx->ts[6], 0, 3, 2);
- set_ts_e1link(&trx->ts[7], 0, 3, 3);
-#ifdef HAVE_TRX1
- /* TRX 1 */
- trx = &bts->trx[1];
- set_ts_e1link(&trx->ts[0], 0, 1, 0xff);
- set_ts_e1link(&trx->ts[1], 0, 2, 1);
- set_ts_e1link(&trx->ts[2], 0, 2, 2);
- set_ts_e1link(&trx->ts[3], 0, 2, 3);
- set_ts_e1link(&trx->ts[4], 0, 3, 0);
- set_ts_e1link(&trx->ts[5], 0, 3, 1);
- set_ts_e1link(&trx->ts[6], 0, 3, 2);
- set_ts_e1link(&trx->ts[7], 0, 3, 3);
-#endif
- }
-
- return 0;
-}
-
-static int bootstrap_network(void)
-{
- struct gsm_bts *bts;
-
- /* initialize our data structures */
- gsmnet = gsm_network_init(2, BTS_TYPE, MCC, MNC);
- if (!gsmnet)
- return -ENOMEM;
-
- gsmnet->name_long = "OpenBSC";
- gsmnet->name_short = "OpenBSC";
-
- bts = &gsmnet->bts[0];
- bootstrap_bts(bts);
-
- if (db_init(database_name)) {
- printf("DB: Failed to init database. Please check the option settings.\n");
- return -1;
- }
- printf("DB: Database initialized.\n");
-
- if (db_prepare()) {
- printf("DB: Failed to prepare database.\n");
- return -1;
- }
- printf("DB: Database prepared.\n");
-
- telnet_init(gsmnet, 4242);
-
- register_signal_handler(SS_NM, nm_sig_cb, NULL);
-
- /* E1 mISDN input setup */
- if (BTS_TYPE == GSM_BTS_TYPE_BS11) {
- gsmnet->num_bts = 1;
- return e1_config(bts, cardnr, release_l2);
- } else {
- /* FIXME: do this dynamic */
- bts->ip_access.site_id = 1801;
- bts->ip_access.bts_id = 0;
- bts = &gsmnet->bts[1];
- bootstrap_bts(bts);
- bts->ip_access.site_id = 1800;
- bts->ip_access.bts_id = 0;
- return ipaccess_setup(gsmnet);
- }
-}
-
-static void create_pcap_file(char *file)
-{
- mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
- int fd = open(file, O_WRONLY|O_TRUNC|O_CREAT, mode);
-
- if (fd < 0) {
- perror("Failed to open file for pcap");
- return;
- }
-
- e1_set_pcap_fd(fd);
-}
-
-static void print_usage()
-{
- printf("Usage: bsc_hack\n");
-}
-
-static void print_help()
-{
- printf(" Some useful help...\n");
- printf(" -d option --debug=DRLL:DCC:DMM:DRR:DRSL:DNM enable debugging\n");
- printf(" -s --disable-color\n");
- printf(" -n --network-code number(MNC) \n");
- printf(" -c --country-code number (MCC) \n");
- printf(" -L --location-area-code number (LAC) \n");
- printf(" -f --arfcn number The frequency ARFCN\n");
- printf(" -l --database db-name The database to use\n");
- printf(" -a --authorize-everyone Allow everyone into the network.\n");
- printf(" -r --reject-cause number The reject cause for LOCATION UPDATING REJECT.\n");
- printf(" -p --pcap file The filename of the pcap file\n");
- printf(" -t --bts-type type The BTS type (bs11, nanobts900, nanobts1800)\n");
- printf(" -C --cardnr number For bs11 select E1 card number other than 0\n");
- printf(" -R --release-l2 Releases mISDN layer 2 after exit, to unload driver.\n");
- printf(" -h --help this text\n");
-}
-
-static void handle_options(int argc, char** argv)
-{
- while (1) {
- int option_index = 0, c;
- static struct option long_options[] = {
- {"help", 0, 0, 'h'},
- {"debug", 1, 0, 'd'},
- {"disable-color", 0, 0, 's'},
- {"network-code", 1, 0, 'n'},
- {"country-code", 1, 0, 'c'},
- {"location-area-code", 1, 0, 'L'},
- {"database", 1, 0, 'l'},
- {"authorize-everyone", 0, 0, 'a'},
- {"reject-cause", 1, 0, 'r'},
- {"pcap", 1, 0, 'p'},
- {"arfcn", 1, 0, 'f'},
- {"bts-type", 1, 0, 't'},
- {"cardnr", 1, 0, 'C'},
- {"release-l2", 0, 0, 'R'},
- {"timestamp", 0, 0, 'T'},
- {0, 0, 0, 0}
- };
-
- c = getopt_long(argc, argv, "hc:n:d:sar:p:f:t:C:RL:l:T",
- long_options, &option_index);
- if (c == -1)
- break;
-
- switch (c) {
- case 'h':
- print_usage();
- print_help();
- exit(0);
- case 's':
- debug_use_color(0);
- break;
- case 'd':
- debug_parse_category_mask(optarg);
- break;
- case 'n':
- MNC = atoi(optarg);
- break;
- case 'c':
- MCC = atoi(optarg);
- break;
- case 'L':
- LAC = atoi(optarg);
- break;
- case 'f':
- ARFCN = atoi(optarg);
- break;
- case 'l':
- database_name = strdup(optarg);
- break;
- case 'a':
- gsm0408_allow_everyone(1);
- break;
- case 'r':
- gsm0408_set_reject_cause(atoi(optarg));
- break;
- case 'p':
- create_pcap_file(optarg);
- break;
- case 't':
- BTS_TYPE = parse_btstype(optarg);
- break;
- case 'C':
- cardnr = atoi(optarg);
- break;
- case 'R':
- release_l2 = 1;
- break;
- case 'T':
- debug_timestamp(1);
- break;
- default:
- /* ignore */
- break;
- }
- }
-}
-
-static void signal_handler(int signal)
-{
- fprintf(stdout, "signal %u received\n", signal);
-
- switch (signal) {
- case SIGHUP:
- case SIGABRT:
- shutdown_net(gsmnet);
- break;
- default:
- break;
- }
-}
-
-int main(int argc, char **argv)
-{
- int rc;
-
- /* parse options */
- handle_options(argc, argv);
-
- /* seed the PRNG */
- srand(time(NULL));
-
- rc = bootstrap_network();
- if (rc < 0)
- exit(1);
-
- signal(SIGHUP, &signal_handler);
- signal(SIGABRT, &signal_handler);
-
- while (1) {
- bsc_select_main(0);
- }
-}
diff --git a/src/chan_alloc.c b/src/chan_alloc.c
deleted file mode 100644
index 77a4f57bc..000000000
--- a/src/chan_alloc.c
+++ /dev/null
@@ -1,256 +0,0 @@
-/* GSM Channel allocation routines
- *
- * (C) 2008 by Harald Welte <laforge@gnumonks.org>
- * (C) 2008, 2009 by Holger Hans Peter Freyther <zecke@selfish.org>
- *
- * All Rights Reserved
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-
-#include <openbsc/gsm_data.h>
-#include <openbsc/chan_alloc.h>
-#include <openbsc/abis_nm.h>
-#include <openbsc/abis_rsl.h>
-#include <openbsc/debug.h>
-#include <openbsc/signal.h>
-
-static void auto_release_channel(void *_lchan);
-
-struct gsm_bts_trx_ts *ts_c0_alloc(struct gsm_bts *bts,
- enum gsm_phys_chan_config pchan)
-{
- struct gsm_bts_trx *trx = &bts->trx[0];
- struct gsm_bts_trx_ts *ts = &trx->ts[0];
-
- if (pchan != GSM_PCHAN_CCCH &&
- pchan != GSM_PCHAN_CCCH_SDCCH4)
- return NULL;
-
- if (ts->pchan != GSM_PCHAN_NONE)
- return NULL;
-
- ts->pchan = pchan;
-
- return ts;
-}
-
-static const enum abis_nm_chan_comb chcomb4pchan[] = {
- [GSM_PCHAN_CCCH] = NM_CHANC_mainBCCH,
- [GSM_PCHAN_CCCH_SDCCH4] = NM_CHANC_BCCCHComb,
- [GSM_PCHAN_TCH_F] = NM_CHANC_TCHFull,
- [GSM_PCHAN_TCH_H] = NM_CHANC_TCHHalf,
- [GSM_PCHAN_SDCCH8_SACCH8C] = NM_CHANC_SDCCH,
- /* FIXME: bounds check */
-};
-
-/* Allocate a logical channel (TS) */
-struct gsm_bts_trx_ts *ts_alloc(struct gsm_bts *bts,
- enum gsm_phys_chan_config pchan)
-{
- int i, j;
- for (i = 0; i < bts->num_trx; i++) {
- struct gsm_bts_trx *trx = &bts->trx[i];
- int from, to;
-
- /* the following constraints are pure policy,
- * no requirement to put this restriction in place */
- switch (pchan) {
- case GSM_PCHAN_CCCH:
- case GSM_PCHAN_CCCH_SDCCH4:
- from = 0; to = 0;
- break;
- case GSM_PCHAN_SDCCH8_SACCH8C:
- from = 1; to = 1;
- break;
- case GSM_PCHAN_TCH_F:
- case GSM_PCHAN_TCH_H:
- from = 2; to = 7;
- break;
- default:
- return NULL;
- }
-
- for (j = from; j <= to; j++) {
- struct gsm_bts_trx_ts *ts = &trx->ts[j];
- if (ts->pchan == GSM_PCHAN_NONE) {
- ts->pchan = pchan;
- /* set channel attribute on OML */
- abis_nm_set_channel_attr(ts, chcomb4pchan[pchan]);
- return ts;
- }
- }
- }
- return NULL;
-}
-
-/* Free a physical channel (TS) */
-void ts_free(struct gsm_bts_trx_ts *ts)
-{
- ts->pchan = GSM_PCHAN_NONE;
-}
-
-static const u_int8_t subslots_per_pchan[] = {
- [GSM_PCHAN_NONE] = 0,
- [GSM_PCHAN_CCCH] = 0,
- [GSM_PCHAN_CCCH_SDCCH4] = 4,
- [GSM_PCHAN_TCH_F] = 1,
- [GSM_PCHAN_TCH_H] = 2,
- [GSM_PCHAN_SDCCH8_SACCH8C] = 8.
-};
-
-static struct gsm_lchan *
-_lc_find(struct gsm_bts *bts, enum gsm_phys_chan_config pchan)
-{
- struct gsm_bts_trx *trx;
- struct gsm_bts_trx_ts *ts;
- int i, j, ss;
- for (i = 0; i < bts->num_trx; i++) {
- trx = &bts->trx[i];
- for (j = 0; j < 8; j++) {
- ts = &trx->ts[j];
- if (ts->pchan != pchan)
- continue;
- /* check if all sub-slots are allocated yet */
- for (ss = 0; ss < subslots_per_pchan[pchan]; ss++) {
- struct gsm_lchan *lc = &ts->lchan[ss];
- if (lc->type == GSM_LCHAN_NONE)
- return lc;
- }
- }
- }
- /* we cannot allocate more of these */
- if (pchan == GSM_PCHAN_CCCH_SDCCH4)
- return NULL;
-
- /* if we've reached here, we need to allocate a new physical
- * channel for the logical channel type requested */
- ts = ts_alloc(bts, pchan);
- if (!ts) {
- /* no more radio resources */
- return NULL;
- }
- return &ts->lchan[0];
-}
-
-/* Allocate a logical channel */
-struct gsm_lchan *lchan_alloc(struct gsm_bts *bts, enum gsm_chan_t type)
-{
- struct gsm_lchan *lchan = NULL;
-
- switch (type) {
- case GSM_LCHAN_SDCCH:
- lchan = _lc_find(bts, GSM_PCHAN_CCCH_SDCCH4);
- if (lchan == NULL)
- lchan = _lc_find(bts, GSM_PCHAN_SDCCH8_SACCH8C);
- break;
- case GSM_LCHAN_TCH_F:
- lchan = _lc_find(bts, GSM_PCHAN_TCH_F);
- break;
- case GSM_LCHAN_TCH_H:
- lchan =_lc_find(bts, GSM_PCHAN_TCH_H);
- break;
- default:
- fprintf(stderr, "Unknown gsm_chan_t %u\n", type);
- }
-
- if (lchan) {
- lchan->type = type;
- lchan->use_count = 0;
-
- /* Configure the time and start it so it will be closed */
- lchan->release_timer.cb = auto_release_channel;
- lchan->release_timer.data = lchan;
- bsc_schedule_timer(&lchan->release_timer, LCHAN_RELEASE_TIMEOUT);
- }
-
- return lchan;
-}
-
-/* Free a logical channel */
-void lchan_free(struct gsm_lchan *lchan)
-{
- lchan->type = GSM_LCHAN_NONE;
- if (lchan->subscr) {
- subscr_put(lchan->subscr);
- lchan->subscr = 0;
- }
-
- /* We might kill an active channel... */
- if (lchan->use_count != 0) {
- dispatch_signal(SS_LCHAN, S_LCHAN_UNEXPECTED_RELEASE, lchan);
- lchan->use_count = 0;
- }
-
- /* stop the timer */
- bsc_del_timer(&lchan->release_timer);
-
- /* FIXME: ts_free() the timeslot, if we're the last logical
- * channel using it */
-}
-
-/* Consider releasing the channel now */
-int lchan_auto_release(struct gsm_lchan *lchan)
-{
- if (lchan->use_count > 0) {
- return 0;
- }
-
- /* Assume we have GSM04.08 running and send a release */
- if (lchan->subscr) {
- gsm48_send_rr_release(lchan);
- }
-
- /* spoofed? message */
- if (lchan->use_count < 0) {
- DEBUGP(DRLL, "Channel count is negative: %d\n", lchan->use_count);
- }
-
- DEBUGP(DRLL, "Recycling the channel with: %d (%x)\n", lchan->nr, lchan->nr);
- rsl_chan_release(lchan);
- return 1;
-}
-
-/* Auto release the channel when the use count is zero */
-static void auto_release_channel(void *_lchan)
-{
- struct gsm_lchan *lchan = _lchan;
-
- if (!lchan_auto_release(lchan))
- bsc_schedule_timer(&lchan->release_timer, LCHAN_RELEASE_TIMEOUT);
-}
-
-struct gsm_lchan* lchan_find(struct gsm_bts *bts, struct gsm_subscriber *subscr) {
- int trx, ts_no, lchan_no;
-
- for (trx = 0; trx < bts->num_trx; ++trx) {
- for (ts_no = 0; ts_no < 8; ++ts_no) {
- for (lchan_no = 0; lchan_no < TS_MAX_LCHAN; ++lchan_no) {
- struct gsm_lchan *lchan =
- &bts->trx[trx].ts[ts_no].lchan[lchan_no];
- if (subscr == lchan->subscr)
- return lchan;
- }
- }
- }
-
- return NULL;
-}
diff --git a/src/db.c b/src/db.c
deleted file mode 100644
index 600699ae7..000000000
--- a/src/db.c
+++ /dev/null
@@ -1,464 +0,0 @@
-/* Simple HLR/VLR database backend using dbi */
-/* (C) 2008 by Jan Luebbe <jluebbe@debian.org>
- * (C) 2009 by Holger Hans Peter Freyther <zecke@selfish.org>
- * All Rights Reserved
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- */
-
-#include <openbsc/gsm_data.h>
-#include <openbsc/db.h>
-
-#include <libgen.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-#include <dbi/dbi.h>
-
-static char *db_basename = NULL;
-static char *db_dirname = NULL;
-static dbi_conn conn;
-
-static char *create_stmts[] = {
- "CREATE TABLE IF NOT EXISTS Meta ("
- "id INTEGER PRIMARY KEY AUTOINCREMENT, "
- "key TEXT UNIQUE NOT NULL, "
- "value TEXT NOT NULL"
- ")",
- "INSERT OR IGNORE INTO Meta "
- "(key, value) "
- "VALUES "
- "('revision', '1')",
- "CREATE TABLE IF NOT EXISTS Subscriber ("
- "id INTEGER PRIMARY KEY AUTOINCREMENT, "
- "created TIMESTAMP NOT NULL, "
- "updated TIMESTAMP NOT NULL, "
- "imsi NUMERIC UNIQUE NOT NULL, "
- "name TEXT, "
- "extension TEXT UNIQUE, "
- "authorized INTEGER NOT NULL DEFAULT 0, "
- "tmsi TEXT UNIQUE, "
- "lac INTEGER NOT NULL DEFAULT 0"
- ")",
- "CREATE TABLE IF NOT EXISTS Equipment ("
- "id INTEGER PRIMARY KEY AUTOINCREMENT, "
- "created TIMESTAMP NOT NULL, "
- "updated TIMESTAMP NOT NULL, "
- "name TEXT, "
- "imei NUMERIC UNIQUE NOT NULL"
- ")",
- "CREATE TABLE IF NOT EXISTS EquipmentWatch ("
- "id INTEGER PRIMARY KEY AUTOINCREMENT, "
- "created TIMESTAMP NOT NULL, "
- "updated TIMESTAMP NOT NULL, "
- "subscriber_id NUMERIC NOT NULL, "
- "equipment_id NUMERIC NOT NULL, "
- "UNIQUE (subscriber_id, equipment_id) "
- ")",
- "CREATE TABLE IF NOT EXISTS SMS ("
- "id INTEGER PRIMARY KEY AUTOINCREMENT, "
- "created TIMESTAMP NOT NULL, "
- "sent TIMESTAMP, "
- "sender_id NUMERIC NOT NULL, "
- "receiver_id NUMERIC NOT NULL, "
- "header NUMERIC, "
- "text TEXT NOT NULL "
- ")",
- "CREATE TABLE IF NOT EXISTS VLR ("
- "id INTEGER PRIMARY KEY AUTOINCREMENT, "
- "created TIMESTAMP NOT NULL, "
- "updated TIMESTAMP NOT NULL, "
- "subscriber_id NUMERIC UNIQUE NOT NULL, "
- "last_bts NUMERIC NOT NULL "
- ")",
-};
-
-void db_error_func(dbi_conn conn, void* data) {
- const char* msg;
- dbi_conn_error(conn, &msg);
- printf("DBI: %s\n", msg);
-}
-
-int db_init(const char *name) {
- dbi_initialize(NULL);
- conn = dbi_conn_new("sqlite3");
- if (conn==NULL) {
- printf("DB: Failed to create connection.\n");
- return 1;
- }
-
- dbi_conn_error_handler( conn, db_error_func, NULL );
-
- /* MySQL
- dbi_conn_set_option(conn, "host", "localhost");
- dbi_conn_set_option(conn, "username", "your_name");
- dbi_conn_set_option(conn, "password", "your_password");
- dbi_conn_set_option(conn, "dbname", "your_dbname");
- dbi_conn_set_option(conn, "encoding", "UTF-8");
- */
-
- /* SqLite 3 */
- db_basename = strdup(name);
- db_dirname = strdup(name);
- dbi_conn_set_option(conn, "sqlite3_dbdir", dirname(db_dirname));
- dbi_conn_set_option(conn, "dbname", basename(db_basename));
-
- if (dbi_conn_connect(conn) < 0) {
- free(db_dirname);
- free(db_basename);
- db_dirname = db_basename = NULL;
- return 1;
- }
-
- return 0;
-}
-
-int db_prepare() {
- dbi_result result;
- int i;
-
- for (i = 0; i < ARRAY_SIZE(create_stmts); i++) {
- result = dbi_conn_query(conn, create_stmts[i]);
- if (result==NULL) {
- printf("DB: Failed to create some table.\n");
- return 1;
- }
- dbi_result_free(result);
- }
-
- return 0;
-}
-
-int db_fini() {
- dbi_conn_close(conn);
- dbi_shutdown();
-
- if (db_dirname)
- free(db_dirname);
- if (db_basename)
- free(db_basename);
- return 0;
-}
-
-struct gsm_subscriber* db_create_subscriber(char *imsi) {
- dbi_result result;
- struct gsm_subscriber* subscr;
-
- /* Is this subscriber known in the db? */
- subscr = db_get_subscriber(GSM_SUBSCRIBER_IMSI, imsi);
- if (subscr) {
- result = dbi_conn_queryf(conn,
- "UPDATE Subscriber set updated = datetime('now') "
- "WHERE imsi = %s " , imsi);
- if (result==NULL) {
- printf("DB: failed to update timestamp\n");
- } else {
- dbi_result_free(result);
- }
- return subscr;
- }
-
- subscr = subscr_alloc();
- if (!subscr)
- return NULL;
- result = dbi_conn_queryf(conn,
- "INSERT INTO Subscriber "
- "(imsi, created, updated) "
- "VALUES "
- "(%s, datetime('now'), datetime('now')) ",
- imsi
- );
- if (result==NULL) {
- printf("DB: Failed to create Subscriber by IMSI.\n");
- }
- subscr->id = dbi_conn_sequence_last(conn, NULL);
- strncpy(subscr->imsi, imsi, GSM_IMSI_LENGTH-1);
- dbi_result_free(result);
- printf("DB: New Subscriber: ID %llu, IMSI %s\n", subscr->id, subscr->imsi);
- return subscr;
-}
-
-struct gsm_subscriber *db_get_subscriber(enum gsm_subscriber_field field, const char *id) {
- dbi_result result;
- const char *string;
- char *quoted;
- struct gsm_subscriber *subscr;
-
- switch (field) {
- case GSM_SUBSCRIBER_IMSI:
- dbi_conn_quote_string_copy(conn, id, &quoted);
- result = dbi_conn_queryf(conn,
- "SELECT * FROM Subscriber "
- "WHERE imsi = %s ",
- quoted
- );
- free(quoted);
- break;
- case GSM_SUBSCRIBER_TMSI:
- dbi_conn_quote_string_copy(conn, id, &quoted);
- result = dbi_conn_queryf(conn,
- "SELECT * FROM Subscriber "
- "WHERE tmsi = %s ",
- quoted
- );
- free(quoted);
- break;
- case GSM_SUBSCRIBER_EXTENSION:
- dbi_conn_quote_string_copy(conn, id, &quoted);
- result = dbi_conn_queryf(conn,
- "SELECT * FROM Subscriber "
- "WHERE extension = %s ",
- quoted
- );
- free(quoted);
- break;
- default:
- printf("DB: Unknown query selector for Subscriber.\n");
- return NULL;
- }
- if (result==NULL) {
- printf("DB: Failed to query Subscriber.\n");
- return NULL;
- }
- if (!dbi_result_next_row(result)) {
- printf("DB: Failed to find the Subscriber. '%u' '%s'\n",
- field, id);
- dbi_result_free(result);
- return NULL;
- }
-
- subscr = subscr_alloc();
- subscr->id = dbi_result_get_ulonglong(result, "id");
- string = dbi_result_get_string(result, "imsi");
- if (string)
- strncpy(subscr->imsi, string, GSM_IMSI_LENGTH);
-
- string = dbi_result_get_string(result, "tmsi");
- if (string)
- strncpy(subscr->tmsi, string, GSM_TMSI_LENGTH);
-
- string = dbi_result_get_string(result, "name");
- if (string)
- strncpy(subscr->name, string, GSM_NAME_LENGTH);
-
- string = dbi_result_get_string(result, "extension");
- if (string)
- strncpy(subscr->extension, string, GSM_EXTENSION_LENGTH);
-
- subscr->lac = dbi_result_get_uint(result, "lac");
- subscr->authorized = dbi_result_get_uint(result, "authorized");
- printf("DB: Found Subscriber: ID %llu, IMSI %s, NAME '%s', TMSI %s, EXTEN '%s', LAC %hu, AUTH %u\n",
- subscr->id, subscr->imsi, subscr->name, subscr->tmsi, subscr->extension,
- subscr->lac, subscr->authorized);
- dbi_result_free(result);
- return subscr;
-}
-
-int db_sync_subscriber(struct gsm_subscriber* subscriber) {
- dbi_result result;
- result = dbi_conn_queryf(conn,
- "UPDATE Subscriber "
- "SET updated = datetime('now'), "
- "tmsi = '%s', "
- "lac = %i, "
- "authorized = %i "
- "WHERE imsi = %s ",
- subscriber->tmsi, subscriber->lac, subscriber->authorized, subscriber->imsi
- );
-
- if (result==NULL) {
- printf("DB: Failed to update Subscriber (by IMSI).\n");
- return 1;
- }
- dbi_result_free(result);
- return 0;
-}
-
-int db_subscriber_alloc_tmsi(struct gsm_subscriber* subscriber) {
- dbi_result result=NULL;
- char* tmsi_quoted;
- for (;;) {
- sprintf(subscriber->tmsi, "%i", rand());
- dbi_conn_quote_string_copy(conn, subscriber->tmsi, &tmsi_quoted);
- result = dbi_conn_queryf(conn,
- "SELECT * FROM Subscriber "
- "WHERE tmsi = %s ",
- tmsi_quoted
- );
- free(tmsi_quoted);
- if (result==NULL) {
- printf("DB: Failed to query Subscriber while allocating new TMSI.\n");
- return 1;
- }
- if (dbi_result_get_numrows(result)){
- dbi_result_free(result);
- continue;
- }
- if (!dbi_result_next_row(result)) {
- dbi_result_free(result);
- printf("DB: Allocated TMSI %s for IMSI %s.\n", subscriber->tmsi, subscriber->imsi);
- return db_sync_subscriber(subscriber);
- }
- dbi_result_free(result);
- }
- return 0;
-}
-
-int db_subscriber_assoc_imei(struct gsm_subscriber* subscriber, char imei[GSM_IMEI_LENGTH]) {
- u_int64_t equipment_id, watch_id;
- dbi_result result;
-
- result = dbi_conn_queryf(conn,
- "INSERT OR IGNORE INTO Equipment "
- "(imei, created, updated) "
- "VALUES "
- "(%s, datetime('now'), datetime('now')) ",
- imei
- );
- if (result==NULL) {
- printf("DB: Failed to create Equipment by IMEI.\n");
- return 1;
- }
- equipment_id = 0;
- if (dbi_result_get_numrows_affected(result)) {
- equipment_id = dbi_conn_sequence_last(conn, NULL);
- }
- dbi_result_free(result);
- if (equipment_id) {
- printf("DB: New Equipment: ID %llu, IMEI %s\n", equipment_id, imei);
- }
- else {
- result = dbi_conn_queryf(conn,
- "SELECT id FROM Equipment "
- "WHERE imei = %s ",
- imei
- );
- if (result==NULL) {
- printf("DB: Failed to query Equipment by IMEI.\n");
- return 1;
- }
- if (!dbi_result_next_row(result)) {
- printf("DB: Failed to find the Equipment.\n");
- dbi_result_free(result);
- return 1;
- }
- equipment_id = dbi_result_get_ulonglong(result, "id");
- dbi_result_free(result);
- }
-
- result = dbi_conn_queryf(conn,
- "INSERT OR IGNORE INTO EquipmentWatch "
- "(subscriber_id, equipment_id, created, updated) "
- "VALUES "
- "(%llu, %llu, datetime('now'), datetime('now')) ",
- subscriber->id, equipment_id
- );
- if (result==NULL) {
- printf("DB: Failed to create EquipmentWatch.\n");
- return 1;
- }
- watch_id = 0;
- if (dbi_result_get_numrows_affected(result)) {
- watch_id = dbi_conn_sequence_last(conn, NULL);
- }
- dbi_result_free(result);
- if (watch_id) {
- printf("DB: New EquipmentWatch: ID %llu, IMSI %s, IMEI %s\n", equipment_id, subscriber->imsi, imei);
- }
- else {
- result = dbi_conn_queryf(conn,
- "UPDATE EquipmentWatch "
- "SET updated = datetime('now') "
- "WHERE subscriber_id = %llu AND equipment_id = %llu ",
- subscriber->id, equipment_id
- );
- if (result==NULL) {
- printf("DB: Failed to update EquipmentWatch.\n");
- return 1;
- }
- dbi_result_free(result);
- printf("DB: Updated EquipmentWatch: ID %llu, IMSI %s, IMEI %s\n", equipment_id, subscriber->imsi, imei);
- }
-
- return 0;
-}
-
-/* store an [unsent] SMS to the database */
-int db_sms_store(struct gsm_sms *sms)
-{
- dbi_result result;
- char *q_text;
-
- dbi_conn_quote_string_copy(conn, (char *)sms->text, &q_text);
- result = dbi_conn_queryf(conn,
- "INSERT INTO SMS "
- "(created,sender_id,receiver_id,header,text) VALUES "
- "(datetime('now'),%llu,%llu,%s,%s)",
- sms->sender->id,
- sms->receiver ? sms->receiver->id : 0,
- NULL, q_text);
- free(q_text);
-
- if (!result)
- return -EIO;
-
- dbi_result_free(result);
- return 0;
-}
-
-/* retrieve the next unsent SMS with ID >= min_id */
-struct gsm_sms *db_sms_get_unsent(int min_id)
-{
- dbi_result result;
- struct gsm_sms *sms = malloc(sizeof(*sms));
-
- if (!sms) {
- free(sms);
- return NULL;
- }
-
- result = dbi_conn_queryf(conn,
- "SELECT * FROM SMS "
- "WHERE id >= %llu ORDER BY id", min_id);
- if (!result) {
- free(sms);
- return NULL;
- }
-
- /* FIXME: fill gsm_sms from database */
-
- dbi_result_free(result);
- return sms;
-}
-
-/* mark a given SMS as read */
-int db_sms_mark_sent(struct gsm_sms *sms)
-{
- dbi_result result;
-
- result = dbi_conn_queryf(conn,
- "UPDATE SMS "
- "SET sent = datetime('now') "
- "WHERE id = %llu", sms->id);
- if (!result) {
- printf("DB: Failed to mark SMS %llu as sent.\n", sms->id);
- return 1;
- }
-
- dbi_result_free(result);
- return 0;
-}
diff --git a/src/debug.c b/src/debug.c
deleted file mode 100644
index aeb993097..000000000
--- a/src/debug.c
+++ /dev/null
@@ -1,161 +0,0 @@
-/* Debugging/Logging support code */
-/* (C) 2008 by Harald Welte <laforge@gnumonks.org>
- * (C) 2008 by Holger Hans Peter Freyther <zecke@selfish.org>
- * All Rights Reserved
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- */
-
-#include <stdarg.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <strings.h>
-#include <time.h>
-
-#include <openbsc/debug.h>
-
-unsigned int debug_mask = 0xffffffff & ~(DMI|DMIB);
-
-struct debug_info {
- const char *name;
- const char *color;
- const char *description;
- int number;
-};
-
-#define DEBUG_CATEGORY(NUMBER, NAME, COLOR, DESCRIPTION) \
- { .name = NAME, .color = COLOR, .description = DESCRIPTION, .number = NUMBER },
-
-#define ARRAY_SIZE(array) (sizeof(array)/sizeof(array[0]))
-
-static const struct debug_info debug_info[] = {
- DEBUG_CATEGORY(DRLL, "DRLL", "\033[1;31m", "")
- DEBUG_CATEGORY(DCC, "DCC", "\033[1;32m", "")
- DEBUG_CATEGORY(DMM, "DMM", "\033[1;33m", "")
- DEBUG_CATEGORY(DRR, "DRR", "\033[1;34m", "")
- DEBUG_CATEGORY(DRSL, "DRSL", "\033[1;35m", "")
- DEBUG_CATEGORY(DNM, "DNM", "\033[1;36m", "")
- DEBUG_CATEGORY(DSMS, "DSMS", "\033[1;37m", "")
- DEBUG_CATEGORY(DPAG, "DPAG", "\033[1;38m", "")
- DEBUG_CATEGORY(DMNCC, "DMNCC","\033[1;39m", "")
- DEBUG_CATEGORY(DINP, "DINP", "", "")
- DEBUG_CATEGORY(DMI, "DMI", "", "")
- DEBUG_CATEGORY(DMIB, "DMIB", "", "")
- DEBUG_CATEGORY(DMUX, "DMUX", "", "")
-};
-
-static int use_color = 1;
-
-void debug_use_color(int color)
-{
- use_color = color;
-}
-
-static int print_timestamp = 0;
-
-void debug_timestamp(int enable)
-{
- print_timestamp = enable;
-}
-
-
-/*
- * Parse the category mask.
- * category1:category2:category3
- */
-void debug_parse_category_mask(const char *_mask)
-{
- unsigned int new_mask = 0;
- int i = 0;
- char *mask = strdup(_mask);
- char *category_token = NULL;
-
- category_token = strtok(mask, ":");
- do {
- for (i = 0; i < ARRAY_SIZE(debug_info); ++i) {
- if (strcasecmp(debug_info[i].name, category_token) == 0)
- new_mask |= debug_info[i].number;
- }
- } while ((category_token = strtok(NULL, ":")));
-
-
- free(mask);
- debug_mask = new_mask;
-}
-
-const char* color(int subsys)
-{
- int i = 0;
-
- for (i = 0; use_color && i < ARRAY_SIZE(debug_info); ++i) {
- if (debug_info[i].number == subsys)
- return debug_info[i].color;
- }
-
- return "";
-}
-
-void debugp(unsigned int subsys, char *file, int line, int cont, const char *format, ...)
-{
- va_list ap;
- FILE *outfd = stderr;
-
- if (!(debug_mask & subsys))
- return;
-
- va_start(ap, format);
-
- fprintf(outfd, "%s", color(subsys));
-
- if (!cont) {
- if (print_timestamp) {
- char *timestr;
- time_t tm;
- tm = time(NULL);
- timestr = ctime(&tm);
- timestr[strlen(timestr)-1] = '\0';
- fprintf(outfd, "%s ", timestr);
- }
- fprintf(outfd, "<%4.4x> %s:%d ", subsys, file, line);
- }
- vfprintf(outfd, format, ap);
- fprintf(outfd, "\033[0;m");
-
- va_end(ap);
-
- fflush(outfd);
-}
-
-static char hexd_buff[4096];
-
-char *hexdump(unsigned char *buf, int len)
-{
- int i;
- char *cur = hexd_buff;
-
- hexd_buff[0] = 0;
- for (i = 0; i < len; i++) {
- int len_remain = sizeof(hexd_buff) - (cur - hexd_buff);
- int rc = snprintf(cur, len_remain, "%02x ", buf[i]);
- if (rc <= 0)
- break;
- cur += rc;
- }
- hexd_buff[sizeof(hexd_buff)-1] = 0;
- return hexd_buff;
-}
-
diff --git a/src/e1_config.c b/src/e1_config.c
deleted file mode 100644
index fc23b55e1..000000000
--- a/src/e1_config.c
+++ /dev/null
@@ -1,108 +0,0 @@
-#include <string.h>
-#include <errno.h>
-
-#include <netinet/in.h>
-
-#include <openbsc/gsm_data.h>
-#include <openbsc/e1_input.h>
-#include <openbsc/trau_frame.h>
-#include <openbsc/trau_mux.h>
-#include <openbsc/misdn.h>
-
-#define SAPI_L2ML 0
-#define SAPI_OML 62
-#define SAPI_RSL 0 /* 63 ? */
-
-#define TEI_L2ML 127
-#define TEI_OML 25
-#define TEI_RSL 1
-
-/* do some compiled-in configuration for our BTS/E1 setup */
-int e1_config(struct gsm_bts *bts, int cardnr, int release_l2)
-{
- struct e1inp_line *line;
- struct e1inp_ts *sign_ts;
- struct e1inp_sign_link *oml_link, *rsl_link;
-
- line = malloc(sizeof(*line));
- if (!line)
- return -ENOMEM;
- memset(line, 0, sizeof(*line));
-
- /* create E1 timeslots for signalling and TRAU frames */
- e1inp_ts_config(&line->ts[1-1], line, E1INP_TS_TYPE_SIGN);
- e1inp_ts_config(&line->ts[2-1], line, E1INP_TS_TYPE_TRAU);
- e1inp_ts_config(&line->ts[3-1], line, E1INP_TS_TYPE_TRAU);
-
- /* create signalling links for TS1 */
- sign_ts = &line->ts[1-1];
- oml_link = e1inp_sign_link_create(sign_ts, E1INP_SIGN_OML,
- bts->c0, TEI_OML, SAPI_OML);
- rsl_link = e1inp_sign_link_create(sign_ts, E1INP_SIGN_RSL,
- bts->c0, TEI_RSL, SAPI_RSL);
-
- /* create back-links from bts/trx */
- bts->oml_link = oml_link;
- bts->c0->rsl_link = rsl_link;
-
- /* enable subchannel demuxer on TS2 */
- subch_demux_activate(&line->ts[2-1].trau.demux, 1);
- subch_demux_activate(&line->ts[2-1].trau.demux, 2);
- subch_demux_activate(&line->ts[2-1].trau.demux, 3);
-
- /* enable subchannel demuxer on TS3 */
- subch_demux_activate(&line->ts[3-1].trau.demux, 0);
- subch_demux_activate(&line->ts[3-1].trau.demux, 1);
- subch_demux_activate(&line->ts[3-1].trau.demux, 2);
- subch_demux_activate(&line->ts[3-1].trau.demux, 3);
-
-#ifdef HAVE_TRX1
- /* create E1 timeslots for TRAU frames of TRX1 */
- e1inp_ts_config(&line->ts[4-1], line, E1INP_TS_TYPE_TRAU);
- e1inp_ts_config(&line->ts[5-1], line, E1INP_TS_TYPE_TRAU);
-
- /* create RSL signalling link for TRX1 */
- sign_ts = &line->ts[1-1];
- rsl_link = e1inp_sign_link_create(sign_ts, E1INP_SIGN_RSL,
- &bts->trx[1], TEI_RSL+1, SAPI_RSL);
- /* create back-links from trx */
- bts->trx[1].rsl_link = rsl_link;
-#endif
-
- return mi_setup(cardnr, line, release_l2);
-}
-
-/* configure pseudo E1 line in ip.access style and connect to BTS */
-int ia_config_connect(struct gsm_bts *bts, struct sockaddr_in *sin)
-{
- struct e1inp_line *line;
- struct e1inp_ts *sign_ts, *rsl_ts;
- struct e1inp_sign_link *oml_link, *rsl_link;
-
- line = malloc(sizeof(*line));
- if (!line)
- return NULL;
- memset(line, 0, sizeof(*line));
-
- /* create E1 timeslots for signalling and TRAU frames */
- e1inp_ts_config(&line->ts[1-1], line, E1INP_TS_TYPE_SIGN);
- e1inp_ts_config(&line->ts[2-1], line, E1INP_TS_TYPE_SIGN);
-
- /* create signalling links for TS1 */
- sign_ts = &line->ts[1-1];
- rsl_ts = &line->ts[2-1];
- oml_link = e1inp_sign_link_create(sign_ts, E1INP_SIGN_OML,
- bts->c0, 0, 0xff);
- rsl_link = e1inp_sign_link_create(rsl_ts, E1INP_SIGN_RSL,
- bts->c0, 0, 0);
-
- /* create back-links from bts/trx */
- bts->oml_link = oml_link;
- bts->c0->rsl_link = rsl_link;
-
- /* default port at BTS for incoming connections is 3006 */
- if (sin->sin_port == 0)
- sin->sin_port = htons(3006);
-
- return ipaccess_connect(line, sin);
-}
diff --git a/src/e1_input.c b/src/e1_input.c
deleted file mode 100644
index c3c7c7597..000000000
--- a/src/e1_input.c
+++ /dev/null
@@ -1,498 +0,0 @@
-/* OpenBSC Abis interface to E1 */
-
-/* (C) 2008-2009 by Harald Welte <laforge@gnumonks.org>
- *
- * All Rights Reserved
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- */
-
-#include <stdio.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <string.h>
-#include <time.h>
-#include <sys/fcntl.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <sys/ioctl.h>
-#include <arpa/inet.h>
-#include <mISDNif.h>
-
-//#define AF_COMPATIBILITY_FUNC
-//#include <compat_af_isdn.h>
-#ifndef AF_ISDN
-#define AF_ISDN 34
-#define PF_ISDN AF_ISDN
-#endif
-
-#include <openbsc/select.h>
-#include <openbsc/msgb.h>
-#include <openbsc/debug.h>
-#include <openbsc/gsm_data.h>
-#include <openbsc/e1_input.h>
-#include <openbsc/abis_nm.h>
-#include <openbsc/abis_rsl.h>
-#include <openbsc/linuxlist.h>
-#include <openbsc/subchan_demux.h>
-#include <openbsc/trau_frame.h>
-#include <openbsc/trau_mux.h>
-
-#define NUM_E1_TS 32
-
-/* list of all E1 drivers */
-LLIST_HEAD(e1inp_driver_list);
-
-/* list of all E1 lines */
-LLIST_HEAD(e1inp_line_list);
-
-/* to be implemented, e.g. by bsc_hack.c */
-void input_event(int event, enum e1inp_sign_type type, struct gsm_bts_trx *trx);
-
-/*
- * pcap writing of the misdn load
- * pcap format is from http://wiki.wireshark.org/Development/LibpcapFileFormat
- */
-#define DLT_LINUX_LAPD 177
-#define PCAP_INPUT 0
-#define PCAP_OUTPUT 1
-
-struct pcap_hdr {
- u_int32_t magic_number;
- u_int16_t version_major;
- u_int16_t version_minor;
- int32_t thiszone;
- u_int32_t sigfigs;
- u_int32_t snaplen;
- u_int32_t network;
-} __attribute__((packed));
-
-struct pcaprec_hdr {
- u_int32_t ts_sec;
- u_int32_t ts_usec;
- u_int32_t incl_len;
- u_int32_t orig_len;
-} __attribute__((packed));
-
-struct fake_linux_lapd_header {
- u_int16_t pkttype;
- u_int16_t hatype;
- u_int16_t halen;
- u_int64_t addr;
- int16_t protocol;
-} __attribute__((packed));
-
-struct lapd_header {
- u_int8_t ea1 : 1;
- u_int8_t cr : 1;
- u_int8_t sapi : 6;
- u_int8_t ea2 : 1;
- u_int8_t tei : 7;
- u_int8_t control_foo; /* fake UM's ... */
-} __attribute__((packed));
-
-static_assert((int)&((struct fake_linux_lapd_header*)NULL)->hatype == 2, hatype_offset);
-static_assert((int)&((struct fake_linux_lapd_header*)NULL)->halen == 4, halen_offset);
-static_assert((int)&((struct fake_linux_lapd_header*)NULL)->addr == 6, addr_offset);
-static_assert((int)&((struct fake_linux_lapd_header*)NULL)->protocol == 14, proto_offset);
-static_assert(sizeof(struct fake_linux_lapd_header) == 16, lapd_header_size);
-
-
-static int pcap_fd = -1;
-
-void e1_set_pcap_fd(int fd)
-{
- int ret;
- struct pcap_hdr header = {
- .magic_number = 0xa1b2c3d4,
- .version_major = 2,
- .version_minor = 4,
- .thiszone = 0,
- .sigfigs = 0,
- .snaplen = 65535,
- .network = DLT_LINUX_LAPD,
- };
-
- pcap_fd = fd;
- ret = write(pcap_fd, &header, sizeof(header));
-}
-
-/* This currently only works for the D-Channel */
-static void write_pcap_packet(int direction, int sapi, int tei,
- struct msgb *msg) {
- if (pcap_fd < 0)
- return;
-
- int ret;
- time_t cur_time;
- struct tm *tm;
-
- struct fake_linux_lapd_header header = {
- .pkttype = 4,
- .hatype = 0,
- .halen = 0,
- .addr = direction == PCAP_OUTPUT ? 0x0 : 0x1,
- .protocol = ntohs(48),
- };
-
- struct lapd_header lapd_header = {
- .ea1 = 0,
- .cr = direction == PCAP_OUTPUT ? 1 : 0,
- .sapi = sapi & 0x3F,
- .ea2 = 1,
- .tei = tei & 0x7F,
- .control_foo = 0x03 /* UI */,
- };
-
- struct pcaprec_hdr payload_header = {
- .ts_sec = 0,
- .ts_usec = 0,
- .incl_len = msg->len + sizeof(struct fake_linux_lapd_header)
- + sizeof(struct lapd_header)
- - MISDN_HEADER_LEN,
- .orig_len = msg->len + sizeof(struct fake_linux_lapd_header)
- + sizeof(struct lapd_header)
- - MISDN_HEADER_LEN,
- };
-
-
- cur_time = time(NULL);
- tm = localtime(&cur_time);
- payload_header.ts_sec = mktime(tm);
-
- ret = write(pcap_fd, &payload_header, sizeof(payload_header));
- ret = write(pcap_fd, &header, sizeof(header));
- ret = write(pcap_fd, &lapd_header, sizeof(lapd_header));
- ret = write(pcap_fd, msg->data + MISDN_HEADER_LEN,
- msg->len - MISDN_HEADER_LEN);
-}
-
-static const char *sign_types[] = {
- [E1INP_SIGN_NONE] = "None",
- [E1INP_SIGN_OML] = "OML",
- [E1INP_SIGN_RSL] = "RSL",
-};
-const char *e1inp_signtype_name(enum e1inp_sign_type tp)
-{
- if (tp >= ARRAY_SIZE(sign_types))
- return "undefined";
- return sign_types[tp];
-}
-
-static const char *ts_types[] = {
- [E1INP_TS_TYPE_NONE] = "None",
- [E1INP_TS_TYPE_SIGN] = "Signalling",
- [E1INP_TS_TYPE_TRAU] = "TRAU",
-};
-
-const char *e1inp_tstype_name(enum e1inp_ts_type tp)
-{
- if (tp >= ARRAY_SIZE(ts_types))
- return "undefined";
- return ts_types[tp];
-}
-
-/* callback when a TRAU frame was received */
-static int subch_cb(struct subch_demux *dmx, int ch, u_int8_t *data, int len,
- void *_priv)
-{
- struct e1inp_ts *e1i_ts = _priv;
- struct gsm_e1_subslot src_ss;
-
- src_ss.e1_nr = e1i_ts->line->num;
- src_ss.e1_ts = e1i_ts->num;
- src_ss.e1_ts_ss = ch;
-
- return trau_mux_input(&src_ss, data, len);
-}
-
-int abis_rsl_sendmsg(struct msgb *msg)
-{
- struct e1inp_sign_link *sign_link;
- struct e1inp_driver *e1inp_driver;
- struct e1inp_ts *e1i_ts;
-
- msg->l2h = msg->data;
-
- if (!msg->trx || !msg->trx->rsl_link) {
- fprintf(stderr, "rsl_sendmsg: msg->trx == NULL\n");
- return -EINVAL;
- }
-
- sign_link = msg->trx->rsl_link;
- e1i_ts = sign_link->ts;
- if (!bsc_timer_pending(&e1i_ts->sign.tx_timer)) {
- /* notify the driver we have something to write */
- e1inp_driver = sign_link->ts->line->driver;
- e1inp_driver->want_write(e1i_ts);
- }
- msgb_enqueue(&sign_link->tx_list, msg);
-
- /* dump it */
- write_pcap_packet(PCAP_OUTPUT, sign_link->sapi, sign_link->tei, msg);
-
- return 0;
-}
-
-int _abis_nm_sendmsg(struct msgb *msg)
-{
- struct e1inp_sign_link *sign_link;
- struct e1inp_driver *e1inp_driver;
- struct e1inp_ts *e1i_ts;
-
- msg->l2h = msg->data;
-
- if (!msg->trx || !msg->trx->bts || !msg->trx->bts->oml_link) {
- fprintf(stderr, "nm_sendmsg: msg->trx == NULL\n");
- return -EINVAL;
- }
-
- sign_link = msg->trx->bts->oml_link;
- e1i_ts = sign_link->ts;
- if (!bsc_timer_pending(&e1i_ts->sign.tx_timer)) {
- /* notify the driver we have something to write */
- e1inp_driver = sign_link->ts->line->driver;
- e1inp_driver->want_write(e1i_ts);
- }
- msgb_enqueue(&sign_link->tx_list, msg);
-
- /* dump it */
- write_pcap_packet(PCAP_OUTPUT, sign_link->sapi, sign_link->tei, msg);
-
- return 0;
-}
-
-/* Timeslot */
-
-/* configure and initialize one e1inp_ts */
-int e1inp_ts_config(struct e1inp_ts *ts, struct e1inp_line *line,
- enum e1inp_ts_type type)
-{
- ts->type = type;
- ts->line = line;
-
- switch (type) {
- case E1INP_TS_TYPE_SIGN:
- INIT_LLIST_HEAD(&ts->sign.sign_links);
- break;
- case E1INP_TS_TYPE_TRAU:
- subchan_mux_init(&ts->trau.mux);
- ts->trau.demux.out_cb = subch_cb;
- ts->trau.demux.data = ts;
- subch_demux_init(&ts->trau.demux);
- break;
- default:
- fprintf(stderr, "unsupported E1 timeslot type %u\n",
- ts->type);
- return -EINVAL;
- }
- return 0;
-}
-
-static struct e1inp_line *e1inp_line_get(u_int8_t e1_nr)
-{
- struct e1inp_line *e1i_line;
-
- /* iterate over global list of e1 lines */
- llist_for_each_entry(e1i_line, &e1inp_line_list, list) {
- if (e1i_line->num == e1_nr)
- return e1i_line;
- }
- return NULL;
-}
-
-static struct e1inp_ts *e1inp_ts_get(u_int8_t e1_nr, u_int8_t ts_nr)
-{
- struct e1inp_line *e1i_line;
-
- e1i_line = e1inp_line_get(e1_nr);
- if (!e1i_line)
- return NULL;
-
- return &e1i_line->ts[ts_nr-1];
-}
-
-struct subch_mux *e1inp_get_mux(u_int8_t e1_nr, u_int8_t ts_nr)
-{
- struct e1inp_ts *e1i_ts = e1inp_ts_get(e1_nr, ts_nr);
-
- if (!e1i_ts)
- return NULL;
-
- return &e1i_ts->trau.mux;
-}
-
-/* Signalling Link */
-
-struct e1inp_sign_link *e1inp_lookup_sign_link(struct e1inp_ts *e1i,
- u_int8_t tei, u_int8_t sapi)
-{
- struct e1inp_sign_link *link;
-
- llist_for_each_entry(link, &e1i->sign.sign_links, list) {
- if (link->sapi == sapi && link->tei == tei)
- return link;
- }
-
- return NULL;
-}
-
-/* create a new signalling link in a E1 timeslot */
-
-struct e1inp_sign_link *
-e1inp_sign_link_create(struct e1inp_ts *ts, enum e1inp_sign_type type,
- struct gsm_bts_trx *trx, u_int8_t tei,
- u_int8_t sapi)
-{
- struct e1inp_sign_link *link;
-
- if (ts->type != E1INP_TS_TYPE_SIGN)
- return NULL;
-
- link = malloc(sizeof(*link));
- if (!link)
- return NULL;
-
- memset(link, 0, sizeof(*link));
-
- link->ts = ts;
- link->type = type;
- INIT_LLIST_HEAD(&link->tx_list);
- link->trx = trx;
- link->tei = tei;
- link->sapi = sapi;
-
- llist_add_tail(&link->list, &ts->sign.sign_links);
-
- return link;
-}
-
-/* the E1 driver tells us he has received something on a TS */
-int e1inp_rx_ts(struct e1inp_ts *ts, struct msgb *msg,
- u_int8_t tei, u_int8_t sapi)
-{
- struct e1inp_sign_link *link;
- int ret;
-
- switch (ts->type) {
- case E1INP_TS_TYPE_SIGN:
- /* consult the list of signalling links */
- write_pcap_packet(PCAP_INPUT, sapi, tei, msg);
- link = e1inp_lookup_sign_link(ts, tei, sapi);
- if (!link) {
- fprintf(stderr, "didn't find singalling link for "
- "tei %d, sapi %d\n", tei, sapi);
- return -EINVAL;
- }
- switch (link->type) {
- case E1INP_SIGN_OML:
- msg->trx = link->trx;
- ret = abis_nm_rcvmsg(msg);
- break;
- case E1INP_SIGN_RSL:
- msg->trx = link->trx;
- ret = abis_rsl_rcvmsg(msg);
- break;
- default:
- ret = -EINVAL;
- fprintf(stderr, "unknown link type %u\n", link->type);
- break;
- }
- break;
- case E1INP_TS_TYPE_TRAU:
- ret = subch_demux_in(&ts->trau.demux, msg->l2h, msgb_l2len(msg));
- break;
- default:
- ret = -EINVAL;
- fprintf(stderr, "unknown TS type %u\n", ts->type);
- break;
- }
-
- return ret;
-}
-
-#define TSX_ALLOC_SIZE 4096
-
-/* called by driver if it wants to transmit on a given TS */
-struct msgb *e1inp_tx_ts(struct e1inp_ts *e1i_ts,
- struct e1inp_sign_link **sign_link)
-{
- struct e1inp_sign_link *link;
- struct msgb *msg = NULL;
- int len;
-
- switch (e1i_ts->type) {
- case E1INP_TS_TYPE_SIGN:
- /* FIXME: implement this round robin */
- llist_for_each_entry(link, &e1i_ts->sign.sign_links, list) {
- msg = msgb_dequeue(&link->tx_list);
- if (msg) {
- if (sign_link)
- *sign_link = link;
- break;
- }
- }
- break;
- case E1INP_TS_TYPE_TRAU:
- msg = msgb_alloc(TSX_ALLOC_SIZE);
- if (!msg)
- return NULL;
- len = subchan_mux_out(&e1i_ts->trau.mux, msg->data, 40);
- msgb_put(msg, 40);
- break;
- default:
- fprintf(stderr, "unsupported E1 TS type %u\n", e1i_ts->type);
- return NULL;
- }
- return msg;
-}
-
-/* called by driver in case some kind of link state event */
-int e1inp_event(struct e1inp_ts *ts, int evt, u_int8_t tei, u_int8_t sapi)
-{
- struct e1inp_sign_link *link;
-
- link = e1inp_lookup_sign_link(ts, tei, sapi);
- if (!link)
- return -EINVAL;
-
- /* FIXME: report further upwards */
- input_event(evt, link->type, link->trx);
- return 0;
-}
-
-/* register a driver with the E1 core */
-int e1inp_driver_register(struct e1inp_driver *drv)
-{
- llist_add_tail(&drv->list, &e1inp_driver_list);
- return 0;
-}
-
-/* register a line with the E1 core */
-int e1inp_line_register(struct e1inp_line *line)
-{
- int i;
-
- for (i = 0; i < NUM_E1_TS; i++) {
- line->ts[i].num = i+1;
- line->ts[i].line = line;
- }
-
- llist_add_tail(&line->list, &e1inp_line_list);
-
- return 0;
-}
diff --git a/src/gsm_04_08.c b/src/gsm_04_08.c
deleted file mode 100644
index 274d3b6bf..000000000
--- a/src/gsm_04_08.c
+++ /dev/null
@@ -1,1723 +0,0 @@
-/* GSM Mobile Radio Interface Layer 3 messages on the A-bis interface
- * 3GPP TS 04.08 version 7.21.0 Release 1998 / ETSI TS 100 940 V7.21.0 */
-
-/* (C) 2008-2009 by Harald Welte <laforge@gnumonks.org>
- * (C) 2008, 2009 by Holger Hans Peter Freyther <zecke@selfish.org>
- *
- * All Rights Reserved
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- */
-
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-#include <time.h>
-#include <netinet/in.h>
-
-#include <openbsc/db.h>
-#include <openbsc/msgb.h>
-#include <openbsc/tlv.h>
-#include <openbsc/debug.h>
-#include <openbsc/gsm_data.h>
-#include <openbsc/gsm_subscriber.h>
-#include <openbsc/gsm_04_11.h>
-#include <openbsc/gsm_04_08.h>
-#include <openbsc/abis_rsl.h>
-#include <openbsc/chan_alloc.h>
-#include <openbsc/paging.h>
-#include <openbsc/signal.h>
-#include <openbsc/trau_frame.h>
-#include <openbsc/trau_mux.h>
-
-#define GSM48_ALLOC_SIZE 1024
-#define GSM48_ALLOC_HEADROOM 128
-
-static const struct tlv_definition rsl_att_tlvdef = {
- .def = {
- [GSM48_IE_MOBILE_ID] = { TLV_TYPE_TLV },
- [GSM48_IE_NAME_LONG] = { TLV_TYPE_TLV },
- [GSM48_IE_NAME_SHORT] = { TLV_TYPE_TLV },
- [GSM48_IE_UTC] = { TLV_TYPE_TV },
- [GSM48_IE_NET_TIME_TZ] = { TLV_TYPE_FIXED, 7 },
- [GSM48_IE_LSA_IDENT] = { TLV_TYPE_TLV },
-
- [GSM48_IE_BEARER_CAP] = { TLV_TYPE_TLV },
- [GSM48_IE_CAUSE] = { TLV_TYPE_TLV },
- [GSM48_IE_CC_CAP] = { TLV_TYPE_TLV },
- [GSM48_IE_ALERT] = { TLV_TYPE_TLV },
- [GSM48_IE_FACILITY] = { TLV_TYPE_TLV },
- [GSM48_IE_PROGR_IND] = { TLV_TYPE_TLV },
- [GSM48_IE_AUX_STATUS] = { TLV_TYPE_TLV },
- [GSM48_IE_KPD_FACILITY] = { TLV_TYPE_TV },
- [GSM48_IE_SIGNAL] = { TLV_TYPE_TV },
- [GSM48_IE_CONN_NUM] = { TLV_TYPE_TLV },
- [GSM48_IE_CONN_SUBADDR] = { TLV_TYPE_TLV },
- [GSM48_IE_CALLING_BCD] = { TLV_TYPE_TLV },
- [GSM48_IE_CALLING_SUB] = { TLV_TYPE_TLV },
- [GSM48_IE_CALLED_BCD] = { TLV_TYPE_TLV },
- [GSM48_IE_CALLED_SUB] = { TLV_TYPE_TLV },
- [GSM48_IE_REDIR_BCD] = { TLV_TYPE_TLV },
- [GSM48_IE_REDIR_SUB] = { TLV_TYPE_TLV },
- [GSM48_IE_LOWL_COMPAT] = { TLV_TYPE_TLV },
- [GSM48_IE_HIGHL_COMPAT] = { TLV_TYPE_TLV },
- [GSM48_IE_USER_USER] = { TLV_TYPE_TLV },
- [GSM48_IE_SS_VERS] = { TLV_TYPE_TLV },
- [GSM48_IE_MORE_DATA] = { TLV_TYPE_T },
- [GSM48_IE_CLIR_SUPP] = { TLV_TYPE_T },
- [GSM48_IE_CLIR_INVOC] = { TLV_TYPE_T },
- [GSM48_IE_REV_C_SETUP] = { TLV_TYPE_T },
- /* FIXME: more elements */
- },
-};
-
-static const char *rr_cause_names[] = {
- [GSM48_RR_CAUSE_NORMAL] = "Normal event",
- [GSM48_RR_CAUSE_ABNORMAL_UNSPEC] = "Abnormal release, unspecified",
- [GSM48_RR_CAUSE_ABNORMAL_UNACCT] = "Abnormal release, channel unacceptable",
- [GSM48_RR_CAUSE_ABNORMAL_TIMER] = "Abnormal release, timer expired",
- [GSM48_RR_CAUSE_ABNORMAL_NOACT] = "Abnormal release, no activity on radio path",
- [GSM48_RR_CAUSE_PREMPTIVE_REL] = "Preemptive release",
- [GSM48_RR_CAUSE_HNDOVER_IMP] = "Handover impossible, timing advance out of range",
- [GSM48_RR_CAUSE_CHAN_MODE_UNACCT] = "Channel mode unacceptable",
- [GSM48_RR_CAUSE_FREQ_NOT_IMPL] = "Frequency not implemented",
- [GSM48_RR_CAUSE_CALL_CLEARED] = "Call already cleared",
- [GSM48_RR_CAUSE_SEMANT_INCORR] = "Semantically incorrect message",
- [GSM48_RR_CAUSE_INVALID_MAND_INF] = "Invalid mandatory information",
- [GSM48_RR_CAUSE_MSG_TYPE_N] = "Message type non-existant or not implemented",
- [GSM48_RR_CAUSE_MSG_TYPE_N_COMPAT] = "Message type not compatible with protocol state",
- [GSM48_RR_CAUSE_COND_IE_ERROR] = "Conditional IE error",
- [GSM48_RR_CAUSE_NO_CELL_ALLOC_A] = "No cell allocation available",
- [GSM48_RR_CAUSE_PROT_ERROR_UNSPC] = "Protocol error unspecified",
-};
-
-static char strbuf[64];
-
-static const char *rr_cause_name(u_int8_t cause)
-{
- if (cause < ARRAY_SIZE(rr_cause_names) &&
- rr_cause_names[cause])
- return rr_cause_names[cause];
-
- snprintf(strbuf, sizeof(strbuf), "0x%02x", cause);
- return strbuf;
-}
-
-static void parse_meas_rep(struct gsm_meas_rep *rep, const u_int8_t *data,
- int len)
-{
- memset(rep, 0, sizeof(*rep));
-
- if (data[0] & 0x80)
- rep->flags |= MEAS_REP_F_BA1;
- if (data[0] & 0x40)
- rep->flags |= MEAS_REP_F_DTX;
- if (data[1] & 0x40)
- rep->flags |= MEAS_REP_F_VALID;
-
- rep->rxlev_full = data[0] & 0x3f;
- rep->rxlev_sub = data[1] & 0x3f;
- rep->rxqual_full = (data[3] >> 4) & 0x7;
- rep->rxqual_sub = (data[3] >> 1) & 0x7;
- rep->num_cell = data[4] >> 6 | ((data[3] & 0x01) << 2);
- if (rep->num_cell < 1)
- return;
-
- /* an encoding nightmare in perfection */
-
- rep->cell[0].rxlev = data[4] & 0x3f;
- rep->cell[0].bcch_freq = data[5] >> 2;
- rep->cell[0].bsic = ((data[5] & 0x03) << 3) | (data[6] >> 5);
- if (rep->num_cell < 2)
- return;
-
- rep->cell[1].rxlev = ((data[6] & 0x1f) << 1) | (data[7] >> 7);
- rep->cell[1].bcch_freq = (data[7] >> 2) & 0x1f;
- rep->cell[1].bsic = ((data[7] & 0x03) << 4) | (data[8] >> 4);
- if (rep->num_cell < 3)
- return;
-
- rep->cell[2].rxlev = ((data[8] & 0x0f) << 2) | (data[9] >> 6);
- rep->cell[2].bcch_freq = (data[9] >> 1) & 0x1f;
- rep->cell[2].bsic = ((data[9] & 0x01) << 6) | (data[10] >> 3);
- if (rep->num_cell < 4)
- return;
-
- rep->cell[3].rxlev = ((data[10] & 0x07) << 3) | (data[11] >> 5);
- rep->cell[3].bcch_freq = data[11] & 0x1f;
- rep->cell[3].bsic = data[12] >> 2;
- if (rep->num_cell < 5)
- return;
-
- rep->cell[4].rxlev = ((data[12] & 0x03) << 4) | (data[13] >> 4);
- rep->cell[4].bcch_freq = ((data[13] & 0xf) << 1) | (data[14] >> 7);
- rep->cell[4].bsic = (data[14] >> 1) & 0x3f;
- if (rep->num_cell < 6)
- return;
-
- rep->cell[5].rxlev = ((data[14] & 0x01) << 5) | (data[15] >> 3);
- rep->cell[5].bcch_freq = ((data[15] & 0x07) << 2) | (data[16] >> 6);
- rep->cell[5].bsic = data[16] & 0x3f;
-}
-
-int gsm0408_loc_upd_acc(struct gsm_lchan *lchan, u_int32_t tmsi);
-static int gsm48_tx_simple(struct gsm_lchan *lchan,
- u_int8_t pdisc, u_int8_t msg_type);
-static void schedule_reject(struct gsm_lchan *lchan);
-
-struct gsm_lai {
- u_int16_t mcc;
- u_int16_t mnc;
- u_int16_t lac;
-};
-
-static int authorize_everonye = 0;
-void gsm0408_allow_everyone(int everyone)
-{
- printf("Allowing everyone?\n");
- authorize_everonye = everyone;
-}
-
-static int reject_cause = 0;
-void gsm0408_set_reject_cause(int cause)
-{
- reject_cause = cause;
-}
-
-static int authorize_subscriber(struct gsm_loc_updating_operation *loc,
- struct gsm_subscriber *subscriber)
-{
- if (!subscriber)
- return 0;
-
- /*
- * Do not send accept yet as more information should arrive. Some
- * phones will not send us the information and we will have to check
- * what we want to do with that.
- */
- if (loc && (loc->waiting_for_imsi || loc->waiting_for_imei))
- return 0;
-
- if (authorize_everonye)
- return 1;
-
- return subscriber->authorized;
-}
-
-static void release_loc_updating_req(struct gsm_lchan *lchan)
-{
- if (!lchan->loc_operation)
- return;
-
- bsc_del_timer(&lchan->loc_operation->updating_timer);
- free(lchan->loc_operation);
- lchan->loc_operation = 0;
- put_lchan(lchan);
-}
-
-static void allocate_loc_updating_req(struct gsm_lchan *lchan)
-{
- use_lchan(lchan);
- release_loc_updating_req(lchan);
-
- lchan->loc_operation = (struct gsm_loc_updating_operation *)
- malloc(sizeof(*lchan->loc_operation));
- memset(lchan->loc_operation, 0, sizeof(*lchan->loc_operation));
-}
-
-static int gsm0408_authorize(struct gsm_lchan *lchan, struct msgb *msg)
-{
- u_int32_t tmsi;
-
- if (authorize_subscriber(lchan->loc_operation, lchan->subscr)) {
- db_subscriber_alloc_tmsi(lchan->subscr);
- subscr_update(lchan->subscr, msg->trx->bts, GSM_SUBSCRIBER_UPDATE_ATTACHED);
- tmsi = strtoul(lchan->subscr->tmsi, NULL, 10);
- release_loc_updating_req(lchan);
- return gsm0408_loc_upd_acc(msg->lchan, tmsi);
- }
-
- return 0;
-}
-
-static int gsm0408_handle_lchan_signal(unsigned int subsys, unsigned int signal,
- void *handler_data, void *signal_data)
-{
- if (subsys != SS_LCHAN || signal != S_LCHAN_UNEXPECTED_RELEASE)
- return 0;
-
- /*
- * Cancel any outstanding location updating request
- * operation taking place on the lchan.
- */
- struct gsm_lchan *lchan = (struct gsm_lchan *)handler_data;
- release_loc_updating_req(lchan);
-
- return 0;
-}
-
-/*
- * This will be ran by the linker when loading the DSO. We use it to
- * do system initialization, e.g. registration of signal handlers.
- */
-static __attribute__((constructor)) void on_dso_load_0408(void)
-{
- register_signal_handler(SS_LCHAN, gsm0408_handle_lchan_signal, NULL);
-}
-
-static void to_bcd(u_int8_t *bcd, u_int16_t val)
-{
- bcd[2] = val % 10;
- val = val / 10;
- bcd[1] = val % 10;
- val = val / 10;
- bcd[0] = val % 10;
- val = val / 10;
-}
-
-void gsm0408_generate_lai(struct gsm48_loc_area_id *lai48, u_int16_t mcc,
- u_int16_t mnc, u_int16_t lac)
-{
- u_int8_t bcd[3];
-
- to_bcd(bcd, mcc);
- lai48->digits[0] = bcd[0] | (bcd[1] << 4);
- lai48->digits[1] = bcd[2];
-
- to_bcd(bcd, mnc);
- /* FIXME: do we need three-digit MNC? See Table 10.5.3 */
-#if 0
- lai48->digits[1] |= bcd[2] << 4;
- lai48->digits[2] = bcd[0] | (bcd[1] << 4);
-#else
- lai48->digits[1] |= 0xf << 4;
- lai48->digits[2] = bcd[1] | (bcd[2] << 4);
-#endif
-
- lai48->lac = htons(lac);
-}
-
-#define TMSI_LEN 5
-#define MID_TMSI_LEN (TMSI_LEN + 2)
-
-int generate_mid_from_tmsi(u_int8_t *buf, u_int32_t tmsi)
-{
- u_int32_t *tptr = (u_int32_t *) &buf[3];
-
- buf[0] = GSM48_IE_MOBILE_ID;
- buf[1] = TMSI_LEN;
- buf[2] = 0xf0 | GSM_MI_TYPE_TMSI;
- *tptr = htonl(tmsi);
-
- return 7;
-}
-
-static const char bcd_num_digits[] = {
- '0', '1', '2', '3', '4', '5', '6', '7',
- '8', '9', '*', '#', 'a', 'b', 'c', '\0'
-};
-
-/* decode a 'called party BCD number' as in 10.5.4.7 */
-u_int8_t decode_bcd_number(char *output, int output_len, const u_int8_t *bcd_lv)
-{
- u_int8_t in_len = bcd_lv[0];
- int i;
-
- if (in_len < 1)
- return 0;
-
- for (i = 2; i <= in_len; i++) {
- /* lower nibble */
- output_len--;
- if (output_len <= 1)
- break;
- *output++ = bcd_num_digits[bcd_lv[i] & 0xf];
-
- /* higher nibble */
- output_len--;
- if (output_len <= 1)
- break;
- *output++ = bcd_num_digits[bcd_lv[i] >> 4];
- }
- if (output_len >= 1)
- *output++ = '\0';
-
- /* return number type / calling plan */
- return bcd_lv[1] & 0x3f;
-}
-
-/* convert a single ASCII character to call-control BCD */
-static int asc_to_bcd(const char asc)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(bcd_num_digits); i++) {
- if (bcd_num_digits[i] == asc)
- return i;
- }
- return -EINVAL;
-}
-
-/* convert a ASCII phone number to 'called party BCD number' */
-int encode_bcd_number(u_int8_t *bcd_lv, u_int8_t max_len,
- u_int8_t type, const char *input)
-{
- int in_len = strlen(input);
- int i;
- u_int8_t *bcd_cur = bcd_lv + 2;
-
- if (in_len/2 + 1 > max_len)
- return -EIO;
-
- /* two digits per byte, plus type byte */
- bcd_lv[0] = in_len/2 + 1;
- if (in_len % 2)
- bcd_lv[0]++;
-
- /* if the caller wants to create a valid 'calling party BCD
- * number', then the extension bit MUST NOT be set. For the
- * 'called party BCD number' it MUST be set. *sigh */
- bcd_lv[1] = type;
-
- for (i = 0; i < in_len; i++) {
- int rc = asc_to_bcd(input[i]);
- if (rc < 0)
- return rc;
- if (i % 2 == 0)
- *bcd_cur = rc;
- else
- *bcd_cur++ |= (rc << 4);
- }
- /* append padding nibble in case of odd length */
- if (i % 2)
- *bcd_cur++ |= 0xf0;
-
- /* return how many bytes we used */
- return (bcd_cur - bcd_lv);
-}
-
-struct msgb *gsm48_msgb_alloc(void)
-{
- return msgb_alloc_headroom(GSM48_ALLOC_SIZE, GSM48_ALLOC_HEADROOM);
-}
-
-int gsm48_sendmsg(struct msgb *msg)
-{
- struct gsm48_hdr *gh = (struct gsm48_hdr *) msg->data;
-
- if (msg->lchan) {
- msg->trx = msg->lchan->ts->trx;
-
- if ((gh->proto_discr & GSM48_PDISC_MASK) == GSM48_PDISC_CC) {
- /* Send a 04.08 call control message, add transaction
- * ID and TI flag */
- gh->proto_discr |= msg->lchan->call.transaction_id;
-
- /* GSM 04.07 Section 11.2.3.1.3 */
- switch (msg->lchan->call.type) {
- case GSM_CT_MO:
- gh->proto_discr |= 0x80;
- break;
- case GSM_CT_MT:
- break;
- case GSM_CT_NONE:
- break;
- }
- }
- }
-
- msg->l3h = msg->data;
-
- return rsl_data_request(msg, 0);
-}
-
-
-/* Chapter 9.2.14 : Send LOCATION UPDATING REJECT */
-int gsm0408_loc_upd_rej(struct gsm_lchan *lchan, u_int8_t cause)
-{
- struct msgb *msg = gsm48_msgb_alloc();
- struct gsm48_hdr *gh;
-
- msg->lchan = lchan;
-
- gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh) + 1);
- gh->proto_discr = GSM48_PDISC_MM;
- gh->msg_type = GSM48_MT_MM_LOC_UPD_REJECT;
- gh->data[0] = cause;
-
- DEBUGP(DMM, "-> LOCATION UPDATING REJECT on channel: %d\n", lchan->nr);
-
- return gsm48_sendmsg(msg);
-}
-
-/* Chapter 9.2.13 : Send LOCATION UPDATE ACCEPT */
-int gsm0408_loc_upd_acc(struct gsm_lchan *lchan, u_int32_t tmsi)
-{
- struct gsm_bts *bts = lchan->ts->trx->bts;
- struct msgb *msg = gsm48_msgb_alloc();
- struct gsm48_hdr *gh;
- struct gsm48_loc_area_id *lai;
- u_int8_t *mid;
- int ret;
-
- msg->lchan = lchan;
-
- gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
- gh->proto_discr = GSM48_PDISC_MM;
- gh->msg_type = GSM48_MT_MM_LOC_UPD_ACCEPT;
-
- lai = (struct gsm48_loc_area_id *) msgb_put(msg, sizeof(*lai));
- gsm0408_generate_lai(lai, bts->network->country_code,
- bts->network->network_code, bts->location_area_code);
-
- mid = msgb_put(msg, MID_TMSI_LEN);
- generate_mid_from_tmsi(mid, tmsi);
-
- DEBUGP(DMM, "-> LOCATION UPDATE ACCEPT\n");
-
- ret = gsm48_sendmsg(msg);
-
- ret = gsm48_tx_mm_info(lchan);
-
- return ret;
-}
-
-static char bcd2char(u_int8_t bcd)
-{
- if (bcd < 0xa)
- return '0' + bcd;
- else
- return 'A' + (bcd - 0xa);
-}
-
-/* Convert Mobile Identity (10.5.1.4) to string */
-static int mi_to_string(char *string, int str_len, u_int8_t *mi, int mi_len)
-{
- int i;
- u_int8_t mi_type;
- char *str_cur = string;
- u_int32_t tmsi;
-
- mi_type = mi[0] & GSM_MI_TYPE_MASK;
-
- switch (mi_type) {
- case GSM_MI_TYPE_NONE:
- break;
- case GSM_MI_TYPE_TMSI:
- /* Table 10.5.4.3, reverse generate_mid_from_tmsi */
- if (mi_len == TMSI_LEN && mi[0] == (0xf0 | GSM_MI_TYPE_TMSI)) {
- memcpy(&tmsi, &mi[1], 4);
- tmsi = ntohl(tmsi);
- return snprintf(string, str_len, "%u", tmsi);
- }
- break;
- case GSM_MI_TYPE_IMSI:
- case GSM_MI_TYPE_IMEI:
- case GSM_MI_TYPE_IMEISV:
- *str_cur++ = bcd2char(mi[0] >> 4);
-
- for (i = 1; i < mi_len; i++) {
- if (str_cur + 2 >= string + str_len)
- return str_cur - string;
- *str_cur++ = bcd2char(mi[i] & 0xf);
- /* skip last nibble in last input byte when GSM_EVEN */
- if( (i != mi_len-1) || (mi[0] & GSM_MI_ODD))
- *str_cur++ = bcd2char(mi[i] >> 4);
- }
- break;
- default:
- break;
- }
- *str_cur++ = '\0';
-
- return str_cur - string;
-}
-
-/* Transmit Chapter 9.2.10 Identity Request */
-static int mm_tx_identity_req(struct gsm_lchan *lchan, u_int8_t id_type)
-{
- struct msgb *msg = gsm48_msgb_alloc();
- struct gsm48_hdr *gh;
-
- msg->lchan = lchan;
-
- gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh) + 1);
- gh->proto_discr = GSM48_PDISC_MM;
- gh->msg_type = GSM48_MT_MM_ID_REQ;
- gh->data[0] = id_type;
-
- return gsm48_sendmsg(msg);
-}
-
-#define MI_SIZE 32
-
-/* Parse Chapter 9.2.11 Identity Response */
-static int mm_rx_id_resp(struct msgb *msg)
-{
- struct gsm48_hdr *gh = msgb_l3(msg);
- struct gsm_lchan *lchan = msg->lchan;
- u_int8_t mi_type = gh->data[1] & GSM_MI_TYPE_MASK;
- char mi_string[MI_SIZE];
-
- mi_to_string(mi_string, sizeof(mi_string), &gh->data[1], gh->data[0]);
- DEBUGP(DMM, "IDENTITY RESPONSE: mi_type=0x%02x MI(%s)\n",
- mi_type, mi_string);
-
- /*
- * Rogue messages could trick us but so is life
- */
- put_lchan(lchan);
-
- switch (mi_type) {
- case GSM_MI_TYPE_IMSI:
- if (!lchan->subscr)
- lchan->subscr = db_create_subscriber(mi_string);
- if (lchan->loc_operation)
- lchan->loc_operation->waiting_for_imsi = 0;
- break;
- case GSM_MI_TYPE_IMEI:
- case GSM_MI_TYPE_IMEISV:
- /* update subscribe <-> IMEI mapping */
- if (lchan->subscr)
- db_subscriber_assoc_imei(lchan->subscr, mi_string);
- if (lchan->loc_operation)
- lchan->loc_operation->waiting_for_imei = 0;
- break;
- }
-
- /* Check if we can let the mobile station enter */
- return gsm0408_authorize(lchan, msg);
-}
-
-
-static void loc_upd_rej_cb(void *data)
-{
- struct gsm_lchan *lchan = data;
-
- release_loc_updating_req(lchan);
- gsm0408_loc_upd_rej(lchan, reject_cause);
- lchan_auto_release(lchan);
-}
-
-static void schedule_reject(struct gsm_lchan *lchan)
-{
- lchan->loc_operation->updating_timer.cb = loc_upd_rej_cb;
- lchan->loc_operation->updating_timer.data = lchan;
- bsc_schedule_timer(&lchan->loc_operation->updating_timer, 5, 0);
-}
-
-static const char *lupd_name(u_int8_t type)
-{
- switch (type) {
- case GSM48_LUPD_NORMAL:
- return "NORMAL";
- case GSM48_LUPD_PERIODIC:
- return "PEROIDOC";
- case GSM48_LUPD_IMSI_ATT:
- return "IMSI ATTACH";
- default:
- return "UNKNOWN";
- }
-}
-
-#define MI_SIZE 32
-/* Chapter 9.2.15: Receive Location Updating Request */
-static int mm_rx_loc_upd_req(struct msgb *msg)
-{
- struct gsm48_hdr *gh = msgb_l3(msg);
- struct gsm48_loc_upd_req *lu;
- struct gsm_subscriber *subscr;
- struct gsm_lchan *lchan = msg->lchan;
- u_int8_t mi_type;
- char mi_string[MI_SIZE];
- int rc;
-
- lu = (struct gsm48_loc_upd_req *) gh->data;
-
- mi_type = lu->mi[0] & GSM_MI_TYPE_MASK;
-
- mi_to_string(mi_string, sizeof(mi_string), lu->mi, lu->mi_len);
-
- DEBUGP(DMM, "LUPDREQ: mi_type=0x%02x MI(%s) type=%s\n", mi_type, mi_string,
- lupd_name(lu->type));
-
- /*
- * Pseudo Spoof detection: Just drop a second/concurrent
- * location updating request.
- */
- if (lchan->loc_operation) {
- DEBUGP(DMM, "LUPDREQ: ignoring request due an existing one: %p.\n",
- lchan->loc_operation);
- gsm0408_loc_upd_rej(lchan, GSM48_REJECT_PROTOCOL_ERROR);
- return 0;
- }
-
- allocate_loc_updating_req(lchan);
-
- switch (mi_type) {
- case GSM_MI_TYPE_IMSI:
- /* we always want the IMEI, too */
- use_lchan(lchan);
- rc = mm_tx_identity_req(lchan, GSM_MI_TYPE_IMEI);
- lchan->loc_operation->waiting_for_imei = 1;
-
- /* look up subscriber based on IMSI */
- subscr = db_create_subscriber(mi_string);
- break;
- case GSM_MI_TYPE_TMSI:
- /* we always want the IMEI, too */
- use_lchan(lchan);
- rc = mm_tx_identity_req(lchan, GSM_MI_TYPE_IMEI);
- lchan->loc_operation->waiting_for_imei = 1;
-
- /* look up the subscriber based on TMSI, request IMSI if it fails */
- subscr = subscr_get_by_tmsi(mi_string);
- if (!subscr) {
- /* send IDENTITY REQUEST message to get IMSI */
- use_lchan(lchan);
- rc = mm_tx_identity_req(lchan, GSM_MI_TYPE_IMSI);
- lchan->loc_operation->waiting_for_imsi = 1;
- }
- break;
- case GSM_MI_TYPE_IMEI:
- case GSM_MI_TYPE_IMEISV:
- /* no sim card... FIXME: what to do ? */
- DEBUGP(DMM, "unimplemented mobile identity type\n");
- break;
- default:
- DEBUGP(DMM, "unknown mobile identity type\n");
- break;
- }
-
- lchan->subscr = subscr;
-
- /*
- * Schedule the reject timer and check if we can let the
- * subscriber into our network immediately or if we need to wait
- * for identity responses.
- */
- schedule_reject(lchan);
- return gsm0408_authorize(lchan, msg);
-}
-
-/* 9.1.5 Channel mode modify */
-int gsm48_tx_chan_mode_modify(struct gsm_lchan *lchan, u_int8_t mode)
-{
- struct msgb *msg = gsm48_msgb_alloc();
- struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
- struct gsm48_chan_mode_modify *cmm =
- (struct gsm48_chan_mode_modify *) msgb_put(msg, sizeof(*cmm));
- u_int16_t arfcn = lchan->ts->trx->arfcn & 0x3ff;
-
- DEBUGP(DRR, "-> CHANNEL MODE MODIFY mode=0x%02x\n", mode);
-
- lchan->tch_mode = mode;
- msg->lchan = lchan;
- gh->proto_discr = GSM48_PDISC_RR;
- gh->msg_type = GSM48_MT_RR_CHAN_MODE_MODIF;
-
- /* fill the channel information element, this code
- * should probably be shared with rsl_rx_chan_rqd() */
- cmm->chan_desc.chan_nr = lchan2chan_nr(lchan);
- cmm->chan_desc.h0.tsc = lchan->ts->trx->bts->tsc;
- cmm->chan_desc.h0.h = 0;
- cmm->chan_desc.h0.arfcn_high = arfcn >> 8;
- cmm->chan_desc.h0.arfcn_low = arfcn & 0xff;
- cmm->mode = mode;
-
- return gsm48_sendmsg(msg);
-}
-
-/* Section 9.2.15a */
-int gsm48_tx_mm_info(struct gsm_lchan *lchan)
-{
- struct msgb *msg = gsm48_msgb_alloc();
- struct gsm48_hdr *gh;
- struct gsm_network *net = lchan->ts->trx->bts->network;
- u_int8_t *ptr8;
- u_int16_t *ptr16;
- int name_len;
- int i;
-
- msg->lchan = lchan;
-
- gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
- gh->proto_discr = GSM48_PDISC_MM;
- gh->msg_type = GSM48_MT_MM_INFO;
-
- if (net->name_long) {
- name_len = strlen(net->name_long);
- /* 10.5.3.5a */
- ptr8 = msgb_put(msg, 3);
- ptr8[0] = GSM48_IE_NAME_LONG;
- ptr8[1] = name_len*2 +1;
- ptr8[2] = 0x90; /* UCS2, no spare bits, no CI */
-
- ptr16 = (u_int16_t *) msgb_put(msg, name_len*2);
- for (i = 0; i < name_len; i++)
- ptr16[i] = htons(net->name_long[i]);
-
- /* FIXME: Use Cell Broadcast, not UCS-2, since
- * UCS-2 is only supported by later revisions of the spec */
- }
-
- if (net->name_short) {
- name_len = strlen(net->name_short);
- /* 10.5.3.5a */
- ptr8 = (u_int8_t *) msgb_put(msg, 3);
- ptr8[0] = GSM48_IE_NAME_LONG;
- ptr8[1] = name_len*2 + 1;
- ptr8[2] = 0x90; /* UCS2, no spare bits, no CI */
-
- ptr16 = (u_int16_t *) msgb_put(msg, name_len*2);
- for (i = 0; i < name_len; i++)
- ptr16[i] = htons(net->name_short[i]);
- }
-
-#if 0
- /* move back to the top */
- time_t cur_t;
- struct tm* cur_time;
- int tz15min;
- /* Section 10.5.3.9 */
- cur_t = time(NULL);
- cur_time = gmtime(cur_t);
- ptr8 = msgb_put(msg, 8);
- ptr8[0] = GSM48_IE_NET_TIME_TZ;
- ptr8[1] = to_bcd8(cur_time->tm_year % 100);
- ptr8[2] = to_bcd8(cur_time->tm_mon);
- ptr8[3] = to_bcd8(cur_time->tm_mday);
- ptr8[4] = to_bcd8(cur_time->tm_hour);
- ptr8[5] = to_bcd8(cur_time->tm_min);
- ptr8[6] = to_bcd8(cur_time->tm_sec);
- /* 02.42: coded as BCD encoded signed value in units of 15 minutes */
- tz15min = (cur_time->tm_gmtoff)/(60*15);
- ptr8[6] = to_bcd8(tz15min);
- if (tz15min < 0)
- ptr8[6] |= 0x80;
-#endif
-
- return gsm48_sendmsg(msg);
-}
-
-static int gsm48_tx_mm_serv_ack(struct gsm_lchan *lchan)
-{
- DEBUGP(DMM, "-> CM SERVICE ACK\n");
- return gsm48_tx_simple(lchan, GSM48_PDISC_MM, GSM48_MT_MM_CM_SERV_ACC);
-}
-
-/* 9.2.6 CM service reject */
-static int gsm48_tx_mm_serv_rej(struct gsm_lchan *lchan,
- enum gsm48_reject_value value)
-{
- struct msgb *msg = gsm48_msgb_alloc();
- struct gsm48_hdr *gh;
-
- gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh) + 1);
-
- msg->lchan = lchan;
- use_lchan(lchan);
-
- gh->proto_discr = GSM48_PDISC_MM;
- gh->msg_type = GSM48_MT_MM_CM_SERV_REJ;
- gh->data[0] = value;
- DEBUGP(DMM, "-> CM SERVICE Reject cause: %d\n", value);
-
- return gsm48_sendmsg(msg);
-}
-
-
-/*
- * Handle CM Service Requests
- * a) Verify that the packet is long enough to contain the information
- * we require otherwsie reject with INCORRECT_MESSAGE
- * b) Try to parse the TMSI. If we do not have one reject
- * c) Check that we know the subscriber with the TMSI otherwise reject
- * with a HLR cause
- * d) Set the subscriber on the gsm_lchan and accept
- */
-static int gsm48_rx_mm_serv_req(struct msgb *msg)
-{
- u_int8_t mi_type;
- char mi_string[MI_SIZE];
-
- struct gsm_subscriber *subscr;
- struct gsm48_hdr *gh = msgb_l3(msg);
- struct gsm48_service_request *req =
- (struct gsm48_service_request *)gh->data;
- /* unfortunately in Phase1 the classmar2 length is variable */
- u_int8_t classmark2_len = gh->data[1];
- u_int8_t *classmark2 = gh->data+2;
- u_int8_t mi_len = *(classmark2 + classmark2_len);
- u_int8_t *mi = (classmark2 + classmark2_len + 1);
-
- DEBUGP(DMM, "<- CM SERVICE REQUEST ");
- if (msg->data_len < sizeof(struct gsm48_service_request*)) {
- DEBUGPC(DMM, "wrong sized message\n");
- return gsm48_tx_mm_serv_rej(msg->lchan,
- GSM48_REJECT_INCORRECT_MESSAGE);
- }
-
- if (msg->data_len < req->mi_len + 6) {
- DEBUGPC(DMM, "does not fit in packet\n");
- return gsm48_tx_mm_serv_rej(msg->lchan,
- GSM48_REJECT_INCORRECT_MESSAGE);
- }
-
- mi_type = mi[0] & GSM_MI_TYPE_MASK;
- if (mi_type != GSM_MI_TYPE_TMSI) {
- DEBUGPC(DMM, "mi_type is not TMSI: %d\n", mi_type);
- return gsm48_tx_mm_serv_rej(msg->lchan,
- GSM48_REJECT_INCORRECT_MESSAGE);
- }
-
- mi_to_string(mi_string, sizeof(mi_string), mi, mi_len);
- DEBUGPC(DMM, "serv_type=0x%02x mi_type=0x%02x M(%s)\n",
- req->cm_service_type, mi_type, mi_string);
-
- subscr = subscr_get_by_tmsi(mi_string);
-
- /* FIXME: if we don't know the TMSI, inquire abit IMSI and allocate new TMSI */
- if (!subscr)
- return gsm48_tx_mm_serv_rej(msg->lchan,
- GSM48_REJECT_IMSI_UNKNOWN_IN_HLR);
-
- if (!msg->lchan->subscr)
- msg->lchan->subscr = subscr;
- else if (msg->lchan->subscr != subscr) {
- DEBUGP(DMM, "<- CM Channel already owned by someone else?\n");
- subscr_put(subscr);
- }
-
- subscr->classmark2_len = classmark2_len;
- memcpy(subscr->classmark2, classmark2, classmark2_len);
-
- return gsm48_tx_mm_serv_ack(msg->lchan);
-}
-
-static int gsm48_rx_mm_imsi_detach_ind(struct msgb *msg)
-{
- struct gsm48_hdr *gh = msgb_l3(msg);
- struct gsm48_imsi_detach_ind *idi =
- (struct gsm48_imsi_detach_ind *) gh->data;
- u_int8_t mi_type = idi->mi[0] & GSM_MI_TYPE_MASK;
- char mi_string[MI_SIZE];
- struct gsm_subscriber *subscr;
-
- mi_to_string(mi_string, sizeof(mi_string), idi->mi, idi->mi_len);
- DEBUGP(DMM, "IMSI DETACH INDICATION: mi_type=0x%02x MI(%s): ",
- mi_type, mi_string);
-
- switch (mi_type) {
- case GSM_MI_TYPE_TMSI:
- subscr = subscr_get_by_tmsi(mi_string);
- break;
- case GSM_MI_TYPE_IMSI:
- subscr = subscr_get_by_imsi(mi_string);
- break;
- case GSM_MI_TYPE_IMEI:
- case GSM_MI_TYPE_IMEISV:
- /* no sim card... FIXME: what to do ? */
- DEBUGPC(DMM, "unimplemented mobile identity type\n");
- break;
- default:
- DEBUGPC(DMM, "unknown mobile identity type\n");
- break;
- }
-
- if (subscr) {
- subscr_update(subscr, msg->trx->bts,
- GSM_SUBSCRIBER_UPDATE_DETACHED);
- DEBUGP(DMM, "Subscriber: %s\n",
- subscr->name ? subscr->name : subscr->imsi);
- subscr_put(subscr);
- } else
- DEBUGP(DMM, "Unknown Subscriber ?!?\n");
-
- put_lchan(msg->lchan);
-
- return 0;
-}
-
-static int gsm48_rx_mm_status(struct msgb *msg)
-{
- struct gsm48_hdr *gh = msgb_l3(msg);
-
- DEBUGP(DMM, "MM STATUS (reject cause 0x%02x)\n", gh->data[0]);
-
- return 0;
-}
-
-/* Receive a GSM 04.08 Mobility Management (MM) message */
-static int gsm0408_rcv_mm(struct msgb *msg)
-{
- struct gsm48_hdr *gh = msgb_l3(msg);
- int rc;
-
- switch (gh->msg_type & 0xbf) {
- case GSM48_MT_MM_LOC_UPD_REQUEST:
- DEBUGP(DMM, "LOCATION UPDATING REQUEST\n");
- rc = mm_rx_loc_upd_req(msg);
- break;
- case GSM48_MT_MM_ID_RESP:
- rc = mm_rx_id_resp(msg);
- break;
- case GSM48_MT_MM_CM_SERV_REQ:
- rc = gsm48_rx_mm_serv_req(msg);
- break;
- case GSM48_MT_MM_STATUS:
- rc = gsm48_rx_mm_status(msg);
- break;
- case GSM48_MT_MM_TMSI_REALL_COMPL:
- DEBUGP(DMM, "TMSI Reallocation Completed. Subscriber: %s\n",
- msg->lchan->subscr ?
- msg->lchan->subscr->imsi :
- "unknown subscriber");
- break;
- case GSM48_MT_MM_IMSI_DETACH_IND:
- rc = gsm48_rx_mm_imsi_detach_ind(msg);
- break;
- case GSM48_MT_MM_CM_REEST_REQ:
- DEBUGP(DMM, "CM REESTABLISH REQUEST: Not implemented\n");
- break;
- case GSM48_MT_MM_AUTH_RESP:
- DEBUGP(DMM, "AUTHENTICATION RESPONSE: Not implemented\n");
- break;
- default:
- fprintf(stderr, "Unknown GSM 04.08 MM msg type 0x%02x\n",
- gh->msg_type);
- break;
- }
-
- return rc;
-}
-
-/* Receive a PAGING RESPONSE message from the MS */
-static int gsm48_rr_rx_pag_resp(struct msgb *msg)
-{
- struct gsm48_hdr *gh = msgb_l3(msg);
- u_int8_t *classmark2_lv = gh->data + 1;
- u_int8_t *mi_lv = gh->data + 2 + *classmark2_lv;
- u_int8_t mi_type = mi_lv[1] & GSM_MI_TYPE_MASK;
- char mi_string[MI_SIZE];
- struct gsm_subscriber *subscr;
- struct paging_signal_data sig_data;
- int rc = 0;
-
- mi_to_string(mi_string, sizeof(mi_string), mi_lv+1, *mi_lv);
- DEBUGP(DRR, "PAGING RESPONSE: mi_type=0x%02x MI(%s)\n",
- mi_type, mi_string);
- switch (mi_type) {
- case GSM_MI_TYPE_TMSI:
- subscr = subscr_get_by_tmsi(mi_string);
- break;
- case GSM_MI_TYPE_IMSI:
- subscr = subscr_get_by_imsi(mi_string);
- break;
- }
-
- if (!subscr) {
- DEBUGP(DRR, "<- Can't find any subscriber for this ID\n");
- /* FIXME: request id? close channel? */
- return -EINVAL;
- }
- DEBUGP(DRR, "<- Channel was requested by %s\n",
- subscr->name ? subscr->name : subscr->imsi);
-
- subscr->classmark2_len = *classmark2_lv;
- memcpy(subscr->classmark2, classmark2_lv+1, *classmark2_lv);
-
- if (!msg->lchan->subscr) {
- msg->lchan->subscr = subscr;
- } else if (msg->lchan->subscr != subscr) {
- DEBUGP(DRR, "<- Channel already owned by someone else?\n");
- subscr_put(subscr);
- return -EINVAL;
- } else {
- DEBUGP(DRR, "<- Channel already owned by us\n");
- subscr_put(subscr);
- subscr = msg->lchan->subscr;
- }
-
- sig_data.subscr = subscr;
- sig_data.bts = msg->lchan->ts->trx->bts;
- sig_data.lchan = msg->lchan;
-
- dispatch_signal(SS_PAGING, S_PAGING_COMPLETED, &sig_data);
- paging_request_stop(msg->trx->bts, subscr, msg->lchan);
-
- /* FIXME: somehow signal the completion of the PAGING to
- * the entity that requested the paging */
-
- return rc;
-}
-
-static int gsm48_rx_rr_classmark(struct msgb *msg)
-{
- struct gsm48_hdr *gh = msgb_l3(msg);
- struct gsm_subscriber *subscr = msg->lchan->subscr;
- unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
- u_int8_t cm2_len, cm3_len = 0;
- u_int8_t *cm2, *cm3 = NULL;
-
- DEBUGP(DRR, "CLASSMARK CHANGE ");
-
- /* classmark 2 */
- cm2_len = gh->data[0];
- cm2 = &gh->data[1];
- DEBUGPC(DRR, "CM2(len=%u) ", cm2_len);
-
- if (payload_len > cm2_len + 1) {
- /* we must have a classmark3 */
- if (gh->data[cm2_len+1] != 0x20) {
- DEBUGPC(DRR, "ERR CM3 TAG\n");
- return -EINVAL;
- }
- if (cm2_len > 3) {
- DEBUGPC(DRR, "CM2 too long!\n");
- return -EINVAL;
- }
-
- cm3_len = gh->data[cm2_len+2];
- cm3 = &gh->data[cm2_len+3];
- if (cm3_len > 14) {
- DEBUGPC(DRR, "CM3 len %u too long!\n", cm3_len);
- return -EINVAL;
- }
- DEBUGPC(DRR, "CM3(len=%u)\n", cm3_len);
- }
- if (subscr) {
- subscr->classmark2_len = cm2_len;
- memcpy(subscr->classmark2, cm2, cm2_len);
- if (cm3) {
- subscr->classmark3_len = cm3_len;
- memcpy(subscr->classmark3, cm3, cm3_len);
- }
- }
-
- /* FIXME: store the classmark2/3 values with the equipment register */
-
- return 0;
-}
-
-static int gsm48_rx_rr_status(struct msgb *msg)
-{
- struct gsm48_hdr *gh = msgb_l3(msg);
-
- DEBUGP(DRR, "STATUS rr_cause = %s\n",
- rr_cause_name(gh->data[0]));
-
- return 0;
-}
-
-static int gsm48_rx_rr_meas_rep(struct msgb *msg)
-{
- struct gsm48_hdr *gh = msgb_l3(msg);
- unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
- static struct gsm_meas_rep meas_rep;
-
- DEBUGP(DRR, "MEASUREMENT REPORT ");
- parse_meas_rep(&meas_rep, gh->data, payload_len);
- if (meas_rep.flags & MEAS_REP_F_DTX)
- DEBUGPC(DRR, "DTX ");
- if (meas_rep.flags & MEAS_REP_F_BA1)
- DEBUGPC(DRR, "BA1 ");
- if (!(meas_rep.flags & MEAS_REP_F_VALID))
- DEBUGPC(DRR, "NOT VALID ");
- else
- DEBUGPC(DRR, "FULL(lev=%u, qual=%u) SUB(lev=%u, qual=%u) ",
- meas_rep.rxlev_full, meas_rep.rxqual_full, meas_rep.rxlev_sub,
- meas_rep.rxqual_sub);
-
- DEBUGPC(DRR, "NUM_NEIGH=%u\n", meas_rep.num_cell);
-
- /* FIXME: put the results somwhere */
-
- return 0;
-}
-
-/* Receive a GSM 04.08 Radio Resource (RR) message */
-static int gsm0408_rcv_rr(struct msgb *msg)
-{
- struct gsm48_hdr *gh = msgb_l3(msg);
- int rc = 0;
-
- switch (gh->msg_type) {
- case GSM48_MT_RR_CLSM_CHG:
- rc = gsm48_rx_rr_classmark(msg);
- break;
- case GSM48_MT_RR_GPRS_SUSP_REQ:
- DEBUGP(DRR, "GRPS SUSPEND REQUEST\n");
- break;
- case GSM48_MT_RR_PAG_RESP:
- rc = gsm48_rr_rx_pag_resp(msg);
- break;
- case GSM48_MT_RR_CHAN_MODE_MODIF_ACK:
- DEBUGP(DRR, "CHANNEL MODE MODIFY ACK\n");
- rc = rsl_chan_mode_modify_req(msg->lchan);
- break;
- case GSM48_MT_RR_STATUS:
- rc = gsm48_rx_rr_status(msg);
- break;
- case GSM48_MT_RR_MEAS_REP:
- rc = gsm48_rx_rr_meas_rep(msg);
- break;
- default:
- fprintf(stderr, "Unimplemented GSM 04.08 RR msg type 0x%02x\n",
- gh->msg_type);
- break;
- }
-
- return rc;
-}
-
-/* 7.1.7 and 9.1.7 Channel release*/
-int gsm48_send_rr_release(struct gsm_lchan *lchan)
-{
- struct msgb *msg = gsm48_msgb_alloc();
- struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
- u_int8_t *cause;
-
- msg->lchan = lchan;
- gh->proto_discr = GSM48_PDISC_RR;
- gh->msg_type = GSM48_MT_RR_CHAN_REL;
-
- cause = msgb_put(msg, 1);
- cause[0] = GSM48_RR_CAUSE_NORMAL;
-
- DEBUGP(DRR, "Sending Channel Release: Chan: Number: %d Type: %d\n",
- lchan->nr, lchan->type);
-
- return gsm48_sendmsg(msg);
-}
-
-/* Call Control */
-
-/* The entire call control code is written in accordance with Figure 7.10c
- * for 'very early assignment', i.e. we allocate a TCH/F during IMMEDIATE
- * ASSIGN, then first use that TCH/F for signalling and later MODE MODIFY
- * it for voice */
-
-static int gsm48_cc_tx_status(struct gsm_lchan *lchan)
-{
- struct msgb *msg = gsm48_msgb_alloc();
- struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
- u_int8_t *cause, *call_state;
-
- gh->proto_discr = GSM48_PDISC_CC;
-
- msg->lchan = lchan;
-
- gh->msg_type = GSM48_MT_CC_STATUS;
-
- cause = msgb_put(msg, 3);
- cause[0] = 2;
- cause[1] = GSM48_CAUSE_CS_GSM | GSM48_CAUSE_LOC_USER;
- cause[2] = 0x80 | 30; /* response to status inquiry */
-
- call_state = msgb_put(msg, 1);
- call_state[0] = 0xc0 | 0x00;
-
- return gsm48_sendmsg(msg);
-}
-
-static int gsm48_tx_simple(struct gsm_lchan *lchan,
- u_int8_t pdisc, u_int8_t msg_type)
-{
- struct msgb *msg = gsm48_msgb_alloc();
- struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
-
- msg->lchan = lchan;
-
- gh->proto_discr = pdisc;
- gh->msg_type = msg_type;
-
- return gsm48_sendmsg(msg);
-}
-
-/* call-back from paging the B-end of the connection */
-static int setup_trig_pag_evt(unsigned int hooknum, unsigned int event,
- struct msgb *msg, void *_lchan, void *param)
-{
- struct gsm_lchan *lchan = _lchan;
- struct gsm_call *remote_call = param;
- struct gsm_call *call = &lchan->call;
- int rc = 0;
-
- if (hooknum != GSM_HOOK_RR_PAGING)
- return -EINVAL;
-
- switch (event) {
- case GSM_PAGING_SUCCEEDED:
- DEBUGP(DCC, "paging succeeded!\n");
- remote_call->remote_lchan = lchan;
- call->remote_lchan = remote_call->local_lchan;
- /* send SETUP request to called party */
- rc = gsm48_cc_tx_setup(lchan, call->remote_lchan->subscr);
- if (is_ipaccess_bts(lchan->ts->trx->bts))
- rsl_ipacc_bind(lchan);
- break;
- case GSM_PAGING_EXPIRED:
- DEBUGP(DCC, "paging expired!\n");
- /* notify caller that we cannot reach called party */
- /* FIXME: correct cause, etc */
- rc = gsm48_tx_simple(remote_call->local_lchan, GSM48_PDISC_CC,
- GSM48_MT_CC_RELEASE_COMPL);
- break;
- }
- return rc;
-}
-
-static int gsm48_cc_rx_status_enq(struct msgb *msg)
-{
- DEBUGP(DCC, "-> STATUS ENQ\n");
- return gsm48_cc_tx_status(msg->lchan);
-}
-
-static int gsm48_cc_rx_setup(struct msgb *msg)
-{
- struct gsm_call *call = &msg->lchan->call;
- struct gsm48_hdr *gh = msgb_l3(msg);
- unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
- struct gsm_subscriber *called_subscr;
- char called_number[(43-2)*2 + 1] = "\0";
- struct tlv_parsed tp;
- u_int8_t num_type;
- int ret;
-
- if (call->state == GSM_CSTATE_NULL ||
- call->state == GSM_CSTATE_RELEASE_REQ)
- use_lchan(msg->lchan);
-
- call->type = GSM_CT_MO;
- call->state = GSM_CSTATE_INITIATED;
- call->local_lchan = msg->lchan;
- call->transaction_id = gh->proto_discr & 0xf0;
-
- tlv_parse(&tp, &rsl_att_tlvdef, gh->data, payload_len, 0, 0);
- if (!TLVP_PRESENT(&tp, GSM48_IE_CALLED_BCD))
- goto err;
-
- /* Parse the number that was dialed and lookup subscriber */
- num_type = decode_bcd_number(called_number, sizeof(called_number),
- TLVP_VAL(&tp, GSM48_IE_CALLED_BCD)-1);
-
- DEBUGP(DCC, "A -> SETUP(tid=0x%02x,number='%s')\n", call->transaction_id,
- called_number);
-
- called_subscr = subscr_get_by_extension(called_number);
- if (!called_subscr) {
- DEBUGP(DCC, "could not find subscriber, RELEASE\n");
- put_lchan(msg->lchan);
- return gsm48_tx_simple(msg->lchan, GSM48_PDISC_CC,
- GSM48_MT_CC_RELEASE_COMPL);
- }
- if (called_subscr == msg->lchan->subscr) {
- DEBUGP(DCC, "subscriber calling himself ?!?\n");
- put_lchan(msg->lchan);
- subscr_put(called_subscr);
- return gsm48_tx_simple(msg->lchan, GSM48_PDISC_CC,
- GSM48_MT_CC_RELEASE_COMPL);
- }
-
- subscr_get(msg->lchan->subscr);
- call->called_subscr = called_subscr;
-
- /* start paging of the receiving end of the call */
- /* FIXME: we're assuming that the receiver is at the same BTS
- * than we are, which is obviously a wrong assumption in multi-BTS
- * case */
- paging_request(msg->trx->bts, called_subscr, RSL_CHANNEED_TCH_F,
- setup_trig_pag_evt, call);
-
- /* send a CALL PROCEEDING message to the MO */
- ret = gsm48_tx_simple(msg->lchan, GSM48_PDISC_CC,
- GSM48_MT_CC_CALL_PROC);
-
- if (is_ipaccess_bts(msg->trx->bts))
- rsl_ipacc_bind(msg->lchan);
-
- /* change TCH/F mode to voice */
- return gsm48_tx_chan_mode_modify(msg->lchan, GSM48_CMODE_SPEECH_EFR);
-
-err:
- /* FIXME: send some kind of RELEASE */
- return 0;
-}
-
-static int gsm48_cc_rx_alerting(struct msgb *msg)
-{
- struct gsm_call *call = &msg->lchan->call;
-
- DEBUGP(DCC, "A -> ALERTING\n");
-
- /* forward ALERTING to other party */
- if (!call->remote_lchan)
- return -EIO;
-
- DEBUGP(DCC, "B <- ALERTING\n");
- return gsm48_tx_simple(call->remote_lchan, GSM48_PDISC_CC,
- GSM48_MT_CC_ALERTING);
-}
-
-/* map two ipaccess RTP streams onto each other */
-static int tch_map(struct gsm_lchan *lchan, struct gsm_lchan *remote_lchan)
-{
- struct gsm_bts *bts = lchan->ts->trx->bts;
- struct gsm_bts *remote_bts = remote_lchan->ts->trx->bts;
- struct gsm_bts_trx_ts *ts;
-
- DEBUGP(DCC, "Setting up TCH map between (bts=%u,trx=%u,ts=%u) and (bts=%u,trx=%u,ts=%u)\n",
- bts->nr, lchan->ts->trx->nr, lchan->ts->nr,
- remote_bts->nr, remote_lchan->ts->trx->nr, remote_lchan->ts->nr);
-
- if (bts->type != remote_bts->type) {
- DEBUGP(DCC, "Cannot switch calls between different BTS types yet\n");
- return -EINVAL;
- }
-
- switch (bts->type) {
- case GSM_BTS_TYPE_NANOBTS_900:
- case GSM_BTS_TYPE_NANOBTS_1800:
- ts = remote_lchan->ts;
- rsl_ipacc_connect(lchan, ts->abis_ip.bound_ip, ts->abis_ip.bound_port,
- lchan->ts->abis_ip.attr_f8, ts->abis_ip.attr_fc);
-
- ts = lchan->ts;
- rsl_ipacc_connect(remote_lchan, ts->abis_ip.bound_ip, ts->abis_ip.bound_port,
- remote_lchan->ts->abis_ip.attr_f8, ts->abis_ip.attr_fc);
- break;
- case GSM_BTS_TYPE_BS11:
- trau_mux_map_lchan(lchan, remote_lchan);
- break;
- default:
- DEBUGP(DCC, "Unknown BTS type %u\n", bts->type);
- break;
- }
-
- return 0;
-}
-
-static int gsm48_cc_rx_connect(struct msgb *msg)
-{
- struct gsm_call *call = &msg->lchan->call;
- int rc;
-
- DEBUGP(DCC, "A -> CONNECT\n");
-
- rc = tch_map(msg->lchan, call->remote_lchan);
- if (rc)
- return -EIO;
-
- if (!call->remote_lchan)
- return -EIO;
-
- DEBUGP(DCC, "A <- CONNECT ACK\n");
- /* MT+MO: need to respond with CONNECT_ACK and pass on */
- rc = gsm48_tx_simple(msg->lchan, GSM48_PDISC_CC,
- GSM48_MT_CC_CONNECT_ACK);
-
-
- /* forward CONNECT to other party */
- DEBUGP(DCC, "B <- CONNECT\n");
- return gsm48_tx_simple(call->remote_lchan, GSM48_PDISC_CC,
- GSM48_MT_CC_CONNECT);
-}
-
-static int gsm48_cc_rx_disconnect(struct msgb *msg)
-{
- struct gsm_call *call = &msg->lchan->call;
- int rc;
-
-
- /* Section 5.4.3.2 */
- DEBUGP(DCC, "A -> DISCONNECT (state->RELEASE_REQ)\n");
- call->state = GSM_CSTATE_RELEASE_REQ;
- /* FIXME: clear the network connection */
- DEBUGP(DCC, "A <- RELEASE\n");
- rc = gsm48_tx_simple(msg->lchan, GSM48_PDISC_CC,
- GSM48_MT_CC_RELEASE);
-
- /*
- * FIXME: This looks wrong! We should have a single
- * place to do MMCC-REL-CNF/-REQ/-IND and then switch
- * to the NULL state and relase the call
- */
- subscr_put_channel(msg->lchan);
-
- /* forward DISCONNECT to other party */
- if (!call->remote_lchan)
- return -EIO;
-
- DEBUGP(DCC, "B <- DISCONNECT\n");
- return gsm48_tx_simple(call->remote_lchan, GSM48_PDISC_CC,
- GSM48_MT_CC_DISCONNECT);
-}
-
-static const u_int8_t calling_bcd[] = { 0xb9, 0x32, 0x24 };
-
-int gsm48_cc_tx_setup(struct gsm_lchan *lchan,
- struct gsm_subscriber *calling_subscr)
-{
- struct msgb *msg = gsm48_msgb_alloc();
- struct gsm48_hdr *gh;
- struct gsm_call *call = &lchan->call;
- u_int8_t bcd_lv[19];
-
- gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
-
- call->type = GSM_CT_MT;
-
- call->local_lchan = msg->lchan = lchan;
- use_lchan(lchan);
-
- gh->proto_discr = GSM48_PDISC_CC;
- gh->msg_type = GSM48_MT_CC_SETUP;
-
- msgb_tv_put(msg, GSM48_IE_SIGNAL, GSM48_SIGNAL_DIALTONE);
- if (calling_subscr) {
- encode_bcd_number(bcd_lv, sizeof(bcd_lv), 0xb9,
- calling_subscr->extension);
- msgb_tlv_put(msg, GSM48_IE_CALLING_BCD,
- bcd_lv[0], bcd_lv+1);
- }
- if (lchan->subscr) {
- encode_bcd_number(bcd_lv, sizeof(bcd_lv), 0xb9,
- lchan->subscr->extension);
- msgb_tlv_put(msg, GSM48_IE_CALLED_BCD,
- bcd_lv[0], bcd_lv+1);
- }
-
- DEBUGP(DCC, "B <- SETUP\n");
-
- return gsm48_sendmsg(msg);
-}
-
-static int gsm0408_rcv_cc(struct msgb *msg)
-{
- struct gsm48_hdr *gh = msgb_l3(msg);
- u_int8_t msg_type = gh->msg_type & 0xbf;
- struct gsm_call *call = &msg->lchan->call;
- int rc = 0;
-
- switch (msg_type) {
- case GSM48_MT_CC_CALL_CONF:
- /* Response to SETUP */
- DEBUGP(DCC, "-> CALL CONFIRM\n");
- /* we now need to MODIFY the channel */
- rc = gsm48_tx_chan_mode_modify(msg->lchan, GSM48_CMODE_SPEECH_EFR);
- break;
- case GSM48_MT_CC_RELEASE_COMPL:
- /* Answer from MS to RELEASE */
- DEBUGP(DCC, "-> RELEASE COMPLETE (state->NULL)\n");
- call->state = GSM_CSTATE_NULL;
- break;
- case GSM48_MT_CC_ALERTING:
- rc = gsm48_cc_rx_alerting(msg);
- break;
- case GSM48_MT_CC_CONNECT:
- rc = gsm48_cc_rx_connect(msg);
- break;
- case GSM48_MT_CC_CONNECT_ACK:
- /* MO: Answer to CONNECT */
- call->state = GSM_CSTATE_ACTIVE;
- DEBUGP(DCC, "-> CONNECT_ACK (state->ACTIVE)\n");
- break;
- case GSM48_MT_CC_RELEASE:
- DEBUGP(DCC, "-> RELEASE\n");
- DEBUGP(DCC, "<- RELEASE_COMPLETE\n");
- /* need to respond with RELEASE_COMPLETE */
- rc = gsm48_tx_simple(msg->lchan, GSM48_PDISC_CC,
- GSM48_MT_CC_RELEASE_COMPL);
- subscr_put_channel(msg->lchan);
- call->state = GSM_CSTATE_NULL;
- break;
- case GSM48_MT_CC_STATUS_ENQ:
- rc = gsm48_cc_rx_status_enq(msg);
- break;
- case GSM48_MT_CC_DISCONNECT:
- rc = gsm48_cc_rx_disconnect(msg);
- break;
- case GSM48_MT_CC_SETUP:
- /* MO: wants to establish a call */
- rc = gsm48_cc_rx_setup(msg);
- break;
- case GSM48_MT_CC_EMERG_SETUP:
- DEBUGP(DCC, "-> EMERGENCY SETUP\n");
- /* FIXME: continue with CALL_PROCEEDING, ALERTING, CONNECT, RELEASE_COMPLETE */
- break;
- case GSM48_MT_CC_HOLD:
- DEBUGP(DCC, "-> HOLD (rejecting)\n");
- rc = gsm48_tx_simple(msg->lchan, GSM48_PDISC_CC,
- GSM48_MT_CC_HOLD_REJ);
- break;
- case GSM48_MT_CC_RETR:
- DEBUGP(DCC, "-> RETR (rejecting)\n");
- rc = gsm48_tx_simple(msg->lchan, GSM48_PDISC_CC,
- GSM48_MT_CC_RETR_REJ);
- break;
- default:
- fprintf(stderr, "Unimplemented GSM 04.08 CC msg type 0x%02x\n",
- msg_type);
- break;
- }
-
- return rc;
-}
-
-/* here we pass in a msgb from the RSL->RLL. We expect the l3 pointer to be set */
-int gsm0408_rcvmsg(struct msgb *msg)
-{
- struct gsm48_hdr *gh = msgb_l3(msg);
- u_int8_t pdisc = gh->proto_discr & 0x0f;
- int rc = 0;
-
- switch (pdisc) {
- case GSM48_PDISC_CC:
- rc = gsm0408_rcv_cc(msg);
- break;
- case GSM48_PDISC_MM:
- rc = gsm0408_rcv_mm(msg);
- break;
- case GSM48_PDISC_RR:
- rc = gsm0408_rcv_rr(msg);
- break;
- case GSM48_PDISC_SMS:
- rc = gsm0411_rcv_sms(msg);
- break;
- case GSM48_PDISC_MM_GPRS:
- case GSM48_PDISC_SM_GPRS:
- fprintf(stderr, "Unimplemented GSM 04.08 discriminator 0x%02d\n",
- pdisc);
- break;
- default:
- fprintf(stderr, "Unknown GSM 04.08 discriminator 0x%02d\n",
- pdisc);
- break;
- }
-
- return rc;
-}
-
-enum chreq_type {
- CHREQ_T_EMERG_CALL,
- CHREQ_T_CALL_REEST_TCH_F,
- CHREQ_T_CALL_REEST_TCH_H,
- CHREQ_T_CALL_REEST_TCH_H_DBL,
- CHREQ_T_SDCCH,
- CHREQ_T_TCH_F,
- CHREQ_T_VOICE_CALL_TCH_H,
- CHREQ_T_DATA_CALL_TCH_H,
- CHREQ_T_LOCATION_UPD,
- CHREQ_T_PAG_R_ANY,
- CHREQ_T_PAG_R_TCH_F,
- CHREQ_T_PAG_R_TCH_FH,
-};
-
-/* Section 9.1.8 / Table 9.9 */
-struct chreq {
- u_int8_t val;
- u_int8_t mask;
- enum chreq_type type;
-};
-
-/* If SYSTEM INFORMATION TYPE 4 NECI bit == 1 */
-static const struct chreq chreq_type_neci1[] = {
- { 0xa0, 0xe0, CHREQ_T_EMERG_CALL },
- { 0xc0, 0xe0, CHREQ_T_CALL_REEST_TCH_F },
- { 0x68, 0xfc, CHREQ_T_CALL_REEST_TCH_H },
- { 0x6c, 0xfc, CHREQ_T_CALL_REEST_TCH_H_DBL },
- { 0xe0, 0xe0, CHREQ_T_SDCCH },
- { 0x40, 0xf0, CHREQ_T_VOICE_CALL_TCH_H },
- { 0x50, 0xf0, CHREQ_T_DATA_CALL_TCH_H },
- { 0x00, 0xf0, CHREQ_T_LOCATION_UPD },
- { 0x10, 0xf0, CHREQ_T_SDCCH },
- { 0x80, 0xe0, CHREQ_T_PAG_R_ANY },
- { 0x20, 0xf0, CHREQ_T_PAG_R_TCH_F },
- { 0x30, 0xf0, CHREQ_T_PAG_R_TCH_FH },
-};
-
-/* If SYSTEM INFORMATION TYPE 4 NECI bit == 0 */
-static const struct chreq chreq_type_neci0[] = {
- { 0xa0, 0xe0, CHREQ_T_EMERG_CALL },
- { 0xc0, 0xe0, CHREQ_T_CALL_REEST_TCH_H },
- { 0xe0, 0xe0, CHREQ_T_TCH_F },
- { 0x50, 0xf0, CHREQ_T_DATA_CALL_TCH_H },
- { 0x00, 0xe0, CHREQ_T_LOCATION_UPD },
- { 0x80, 0xe0, CHREQ_T_PAG_R_ANY },
- { 0x20, 0xf0, CHREQ_T_PAG_R_TCH_F },
- { 0x30, 0xf0, CHREQ_T_PAG_R_TCH_FH },
-};
-
-static const enum gsm_chan_t ctype_by_chreq[] = {
- [CHREQ_T_EMERG_CALL] = GSM_LCHAN_TCH_F,
- [CHREQ_T_CALL_REEST_TCH_F] = GSM_LCHAN_TCH_F,
- [CHREQ_T_CALL_REEST_TCH_H] = GSM_LCHAN_TCH_H,
- [CHREQ_T_CALL_REEST_TCH_H_DBL] = GSM_LCHAN_TCH_H,
- [CHREQ_T_SDCCH] = GSM_LCHAN_SDCCH,
- [CHREQ_T_TCH_F] = GSM_LCHAN_TCH_F,
- [CHREQ_T_VOICE_CALL_TCH_H] = GSM_LCHAN_TCH_H,
- [CHREQ_T_DATA_CALL_TCH_H] = GSM_LCHAN_TCH_H,
- [CHREQ_T_LOCATION_UPD] = GSM_LCHAN_SDCCH,
- [CHREQ_T_PAG_R_ANY] = GSM_LCHAN_SDCCH,
- [CHREQ_T_PAG_R_TCH_F] = GSM_LCHAN_TCH_F,
- [CHREQ_T_PAG_R_TCH_FH] = GSM_LCHAN_TCH_F,
-};
-
-static const enum gsm_chreq_reason_t reason_by_chreq[] = {
- [CHREQ_T_EMERG_CALL] = GSM_CHREQ_REASON_EMERG,
- [CHREQ_T_CALL_REEST_TCH_F] = GSM_CHREQ_REASON_CALL,
- [CHREQ_T_CALL_REEST_TCH_H] = GSM_CHREQ_REASON_CALL,
- [CHREQ_T_CALL_REEST_TCH_H_DBL] = GSM_CHREQ_REASON_CALL,
- [CHREQ_T_SDCCH] = GSM_CHREQ_REASON_OTHER,
- [CHREQ_T_TCH_F] = GSM_CHREQ_REASON_OTHER,
- [CHREQ_T_VOICE_CALL_TCH_H] = GSM_CHREQ_REASON_OTHER,
- [CHREQ_T_DATA_CALL_TCH_H] = GSM_CHREQ_REASON_OTHER,
- [CHREQ_T_LOCATION_UPD] = GSM_CHREQ_REASON_LOCATION_UPD,
- [CHREQ_T_PAG_R_ANY] = GSM_CHREQ_REASON_PAG,
- [CHREQ_T_PAG_R_TCH_F] = GSM_CHREQ_REASON_PAG,
- [CHREQ_T_PAG_R_TCH_FH] = GSM_CHREQ_REASON_PAG,
-};
-
-enum gsm_chan_t get_ctype_by_chreq(struct gsm_bts *bts, u_int8_t ra)
-{
- int i;
- /* FIXME: determine if we set NECI = 0 in the BTS SI4 */
-
- for (i = 0; i < ARRAY_SIZE(chreq_type_neci0); i++) {
- const struct chreq *chr = &chreq_type_neci0[i];
- if ((ra & chr->mask) == chr->val)
- return ctype_by_chreq[chr->type];
- }
- fprintf(stderr, "Unknown CHANNEL REQUEST RQD 0x%02x\n", ra);
- return GSM_LCHAN_SDCCH;
-}
-
-enum gsm_chreq_reason_t get_reason_by_chreq(struct gsm_bts *bts, u_int8_t ra)
-{
- int i;
- /* FIXME: determine if we set NECI = 0 in the BTS SI4 */
-
- for (i = 0; i < ARRAY_SIZE(chreq_type_neci0); i++) {
- const struct chreq *chr = &chreq_type_neci0[i];
- if ((ra & chr->mask) == chr->val)
- return reason_by_chreq[chr->type];
- }
- fprintf(stderr, "Unknown CHANNEL REQUEST REASON 0x%02x\n", ra);
- return GSM_CHREQ_REASON_OTHER;
-}
diff --git a/src/gsm_04_11.c b/src/gsm_04_11.c
deleted file mode 100644
index c29953806..000000000
--- a/src/gsm_04_11.c
+++ /dev/null
@@ -1,500 +0,0 @@
-/* Point-to-Point (PP) Short Message Service (SMS)
- * Support on Mobile Radio Interface
- * 3GPP TS 04.11 version 7.1.0 Release 1998 / ETSI TS 100 942 V7.1.0 */
-
-/* (C) 2008 by Daniel Willmann <daniel@totalueberwachung.de>
- * (C) 2009 by Harald Welte <laforge@gnumonks.org>
- *
- * All Rights Reserved
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- */
-
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-#include <netinet/in.h>
-
-#include <openbsc/msgb.h>
-#include <openbsc/tlv.h>
-#include <openbsc/debug.h>
-#include <openbsc/gsm_data.h>
-#include <openbsc/gsm_subscriber.h>
-#include <openbsc/gsm_04_11.h>
-#include <openbsc/gsm_04_08.h>
-#include <openbsc/gsm_utils.h>
-#include <openbsc/abis_rsl.h>
-#include <openbsc/signal.h>
-#include <openbsc/db.h>
-
-#define GSM411_ALLOC_SIZE 1024
-#define GSM411_ALLOC_HEADROOM 128
-
-struct msgb *gsm411_msgb_alloc(void)
-{
- return msgb_alloc_headroom(GSM411_ALLOC_SIZE, GSM411_ALLOC_HEADROOM);
-}
-
-int gsm0411_sendmsg(struct msgb *msg)
-{
- if (msg->lchan)
- msg->trx = msg->lchan->ts->trx;
-
- msg->l3h = msg->data;
-
- return rsl_data_request(msg, 0);
-}
-
-
-#if 0
-static u_int8_t gsm0411_tpdu_from_sms(u_int8_t *tpdu, struct sms_deliver *sms)
-{
-}
-#endif
-
-static unsigned long gsm340_validity_period(struct sms_submit *sms)
-{
- u_int8_t vp;
- unsigned long minutes;
-
- switch (sms->vpf) {
- case GSM340_TP_VPF_RELATIVE:
- /* Chapter 9.2.3.12.1 */
- vp = *(sms->vp);
- if (vp <= 143)
- minutes = vp + 1 * 5;
- else if (vp <= 167)
- minutes = 12*60 + (vp-143) * 30;
- else if (vp <= 196)
- minutes = vp-166 * 60 * 24;
- else
- minutes = vp-192 * 60 * 24 * 7;
- break;
- case GSM340_TP_VPF_ABSOLUTE:
- /* Chapter 9.2.3.12.2 */
- /* FIXME: like service center time stamp */
- DEBUGP(DSMS, "VPI absolute not implemented yet\n");
- break;
- case GSM340_TP_VPF_ENHANCED:
- /* Chapter 9.2.3.12.3 */
- /* FIXME: implementation */
- DEBUGP(DSMS, "VPI enhanced not implemented yet\n");
- break;
- }
- return minutes;
-}
-
-/* determine coding alphabet dependent on GSM 03.38 Section 4 DCS */
-enum sms_alphabet gsm338_get_sms_alphabet(u_int8_t dcs)
-{
- u_int8_t cgbits = dcs >> 4;
- enum sms_alphabet alpha = DCS_NONE;
-
- if ((cgbits & 0xc) == 0) {
- if (cgbits & 2)
- DEBUGP(DSMS, "Compressed SMS not supported yet\n");
-
- switch (dcs & 3) {
- case 0:
- alpha = DCS_7BIT_DEFAULT;
- break;
- case 1:
- alpha = DCS_8BIT_DATA;
- break;
- case 2:
- alpha = DCS_UCS2;
- break;
- }
- } else if (cgbits == 0xc || cgbits == 0xd)
- alpha = DCS_7BIT_DEFAULT;
- else if (cgbits == 0xe)
- alpha = DCS_UCS2;
- else if (cgbits == 0xf) {
- if (dcs & 4)
- alpha = DCS_8BIT_DATA;
- else
- alpha = DCS_7BIT_DEFAULT;
- }
-
- return alpha;
-}
-
-static int gsm340_rx_sms_submit(struct msgb *msg, struct sms_submit *sms,
- struct gsm_sms *gsms)
-{
- if (db_sms_store(gsms) != 0) {
- DEBUGP(DSMS, "Failed to store SMS in Database\n");
- free(sms);
- free(gsms);
- return -EIO;
- }
- return 0;
-}
-
-/* process an incoming TPDU (called from RP-DATA) */
-static int gsm340_rx_tpdu(struct msgb *msg)
-{
- u_int8_t *smsp = msgb_sms(msg);
- struct sms_submit *sms;
- struct gsm_sms *gsms;
- u_int8_t da_len_bytes;
- u_int8_t address_lv[12]; /* according to 03.40 / 9.1.2.5 */
- int rc = 0;
-
- sms = malloc(sizeof(*sms));
- if (!sms)
- return -ENOMEM;
- memset(sms, 0, sizeof(*sms));
-
- gsms = malloc(sizeof(*gsms));
- if (!gsms) {
- free(sms);
- return -ENOMEM;
- }
- memset(gsms, 0, sizeof(*gsms));
-
- /* invert those fields where 0 means active/present */
- sms->mti = *smsp & 0x03;
- sms->mms = !!(*smsp & 0x04);
- sms->vpf = (*smsp & 0x18) >> 3;
- sms->sri = !!(*smsp & 0x20);
- sms->udhi= !!(*smsp & 0x40);
- sms->rp = !!(*smsp & 0x80);
-
- smsp++;
- sms->msg_ref = *smsp++;
-
- /* length in bytes of the destination address */
- da_len_bytes = 2 + *smsp/2 + *smsp%2;
- if (da_len_bytes > 12) {
- DEBUGP(DSMS, "Destination Address > 12 bytes ?!?\n");
- rc = -EIO;
- goto out;
- }
- memcpy(address_lv, smsp, da_len_bytes);
- /* mangle first byte to reflect length in bytes, not digits */
- address_lv[0] = da_len_bytes;
- /* convert to real number */
- decode_bcd_number(sms->dest_addr, sizeof(sms->dest_addr), address_lv);
-
- smsp += da_len_bytes;
-
- sms->pid = *smsp++;
-
- sms->dcs = *smsp++;
- sms->alphabet = gsm338_get_sms_alphabet(sms->dcs);
-
- switch (sms->vpf) {
- case GSM340_TP_VPF_RELATIVE:
- sms->vp = smsp++;
- break;
- case GSM340_TP_VPF_ABSOLUTE:
- case GSM340_TP_VPF_ENHANCED:
- sms->vp = smsp;
- smsp += 7;
- break;
- default:
- DEBUGP(DSMS, "SMS Validity period not implemented: 0x%02x\n",
- sms->vpf);
- }
- sms->ud_len = *smsp++;
- if (sms->ud_len)
- sms->user_data = smsp;
- else
- sms->user_data = NULL;
-
- if (sms->ud_len) {
- switch (sms->alphabet) {
- case DCS_7BIT_DEFAULT:
- gsm_7bit_decode(sms->decoded, smsp, sms->ud_len);
- break;
- case DCS_8BIT_DATA:
- case DCS_UCS2:
- case DCS_NONE:
- memcpy(sms->decoded, sms->user_data, sms->ud_len);
- break;
- }
- }
-
- DEBUGP(DSMS, "SMS:\nMTI: 0x%02x, VPF: 0x%02x, MR: 0x%02x "
- "PID: 0x%02x, DCS: 0x%02x, DA: %s, UserDataLength: 0x%02x "
- "UserData: \"%s\"\n", sms->mti, sms->vpf, sms->msg_ref,
- sms->pid, sms->dcs, sms->dest_addr, sms->ud_len,
- sms->alphabet == DCS_7BIT_DEFAULT ? sms->decoded : hexdump(sms->user_data, sms->ud_len));
-
- dispatch_signal(SS_SMS, 0, sms);
-
- gsms->sender = msg->lchan->subscr;
- /* FIXME: sender refcount */
-
- /* determine gsms->receiver based on dialled number */
- gsms->receiver = subscr_get_by_extension(sms->dest_addr);
- if (!gsms->receiver) {
- rc = 1; /* cause 1: unknown subscriber */
- goto out;
- }
-
- if (sms->user_data)
- strncpy(gsms->text, sms->decoded, sizeof(gsms->text));
-
- switch (sms->mti) {
- case GSM340_SMS_SUBMIT_MS2SC:
- /* MS is submitting a SMS */
- rc = gsm340_rx_sms_submit(msg, sms, gsms);
- break;
- case GSM340_SMS_COMMAND_MS2SC:
- case GSM340_SMS_DELIVER_REP_MS2SC:
- DEBUGP(DSMS, "Unimplemented MTI 0x%02x\n", sms->mti);
- break;
- default:
- DEBUGP(DSMS, "Undefined MTI 0x%02x\n", sms->mti);
- break;
- }
-
-out:
- free(gsms);
- free(sms);
-
- return rc;
-}
-
-static int gsm411_send_rp_ack(struct gsm_lchan *lchan, u_int8_t trans_id,
- u_int8_t msg_ref)
-{
- struct msgb *msg = gsm411_msgb_alloc();
- struct gsm48_hdr *gh;
- struct gsm411_rp_hdr *rp;
-
- msg->lchan = lchan;
-
- gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
- // Outgoing needs the highest bit set
- gh->proto_discr = GSM48_PDISC_SMS | trans_id<<4 | 0x80;
- gh->msg_type = GSM411_MT_CP_DATA;
-
- rp = (struct gsm411_rp_hdr *)msgb_put(msg, sizeof(*rp));
- rp->len = 2;
- rp->msg_type = GSM411_MT_RP_ACK_MT;
- rp->msg_ref = msg_ref;
-
- DEBUGP(DSMS, "TX: SMS RP ACK\n");
-
- return gsm0411_sendmsg(msg);
-}
-
-static int gsm411_send_rp_error(struct gsm_lchan *lchan, u_int8_t trans_id,
- u_int8_t msg_ref, u_int8_t cause)
-{
- struct msgb *msg = gsm411_msgb_alloc();
- struct gsm48_hdr *gh;
- struct gsm411_rp_hdr *rp;
-
- msg->lchan = lchan;
-
- gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
- // Outgoing needs the highest bit set
- gh->proto_discr = GSM48_PDISC_SMS | trans_id<<4 | 0x80;
- gh->msg_type = GSM411_MT_CP_DATA;
-
- rp = (struct gsm411_rp_hdr *)msgb_put(msg, sizeof(*rp));
- rp->msg_type = GSM411_MT_RP_ERROR_MT;
- rp->msg_ref = msg_ref;
- msgb_tv_put(msg, 1, cause);
-
- DEBUGP(DSMS, "TX: SMS RP ERROR (cause %02d)\n", cause);
-
- return gsm0411_sendmsg(msg);
-}
-
-/* Receive a 04.11 TPDU inside RP-DATA / user data */
-static int gsm411_rx_rp_ud(struct msgb *msg, struct gsm411_rp_hdr *rph,
- u_int8_t src_len, u_int8_t *src,
- u_int8_t dst_len, u_int8_t *dst,
- u_int8_t tpdu_len, u_int8_t *tpdu)
-{
- struct gsm48_hdr *gh = msgb_l3(msg);
- u_int8_t trans_id = gh->proto_discr >> 4;
- int rc = 0;
-
- if (src_len && src)
- DEBUGP(DSMS, "RP-DATA (MO) with SRC ?!?\n");
-
- if (!dst_len || !dst || !tpdu_len || !tpdu) {
- DEBUGP(DSMS, "RP-DATA (MO) without DST or TPDU ?!?\n");
- return -EIO;
- }
- msg->smsh = tpdu;
-
- DEBUGP(DSMS, "DST(%u,%s)\n", dst_len, hexdump(dst, dst_len));
- //return gsm411_send_rp_error(msg->lchan, trans_id, rph->msg_ref, rc);
-
- rc = gsm340_rx_tpdu(msg);
- if (rc == 0)
- return gsm411_send_rp_ack(msg->lchan, trans_id, rph->msg_ref);
- else if (rc > 0)
- return gsm411_send_rp_error(msg->lchan, trans_id, rph->msg_ref, rc);
- else
- return rc;
-}
-
-/* Receive a 04.11 RP-DATA message in accordance with Section 7.3.1.2 */
-static int gsm411_rx_rp_data(struct msgb *msg, struct gsm411_rp_hdr *rph)
-{
- u_int8_t src_len, dst_len, rpud_len;
- u_int8_t *src = NULL, *dst = NULL , *rp_ud = NULL;
-
- /* in the MO case, this should always be zero length */
- src_len = rph->data[0];
- if (src_len)
- src = &rph->data[1];
-
- dst_len = rph->data[1+src_len];
- if (dst_len)
- dst = &rph->data[1+src_len+1];
-
- rpud_len = rph->data[1+src_len+1+dst_len];
- if (rpud_len)
- rp_ud = &rph->data[1+src_len+1+dst_len+1];
-
- DEBUGP(DSMS, "RX_RP-DATA: src_len=%u, dst_len=%u ud_len=%u\n", src_len, dst_len, rpud_len);
- return gsm411_rx_rp_ud(msg, rph, src_len, src, dst_len, dst,
- rpud_len, rp_ud);
-}
-
-static int gsm411_rx_cp_data(struct msgb *msg, struct gsm48_hdr *gh)
-{
- struct gsm411_rp_hdr *rp_data = (struct gsm411_rp_hdr*)&gh->data;
- u_int8_t msg_type = rp_data->msg_type & 0x07;
- int rc = 0;
-
- switch (msg_type) {
- case GSM411_MT_RP_DATA_MO:
- DEBUGP(DSMS, "SMS RP-DATA (MO)\n");
- rc = gsm411_rx_rp_data(msg, rp_data);
- break;
- case GSM411_MT_RP_ACK_MO:
- /* Acnkowledgement to MT RP_DATA */
- case GSM411_MT_RP_ERROR_MO:
- /* Error in response to MT RP_DATA */
- case GSM411_MT_RP_SMMA_MO:
- /* MS tells us that it has memory for more SMS, we need
- * to check if we have any pending messages for it and then
- * transfer those */
- DEBUGP(DSMS, "Unimplemented RP type 0x%02x\n", msg_type);
- break;
- default:
- DEBUGP(DSMS, "Invalid RP type 0x%02x\n", msg_type);
- break;
- }
-
- return rc;
-}
-
-int gsm0411_rcv_sms(struct msgb *msg)
-{
- struct gsm48_hdr *gh = msgb_l3(msg);
- u_int8_t msg_type = gh->msg_type;
- int rc = 0;
-
- switch(msg_type) {
- case GSM411_MT_CP_DATA:
- DEBUGP(DSMS, "SMS CP-DATA\n");
- rc = gsm411_rx_cp_data(msg, gh);
- break;
- case GSM411_MT_CP_ACK:
- DEBUGP(DSMS, "SMS CP-ACK\n");
- break;
- case GSM411_MT_CP_ERROR:
- DEBUGP(DSMS, "SMS CP-ERROR, cause 0x%02x\n", gh->data[0]);
- break;
- default:
- DEBUGP(DSMS, "Unimplemented CP msg_type: 0x%02x\n", msg_type);
- break;
- }
-
-
- return rc;
-}
-
-/* Test TPDU - 25c3 welcome */
-#if 0
-static u_int8_t tpdu_test[] = {
- 0x04, 0x04, 0x81, 0x32, 0x24, 0x00, 0x00, 0x80, 0x21, 0x92, 0x90, 0x32,
- 0x24, 0x40, 0x4D, 0xB2, 0xDA, 0x70, 0xD6, 0x9A, 0x97, 0xE5, 0xF6, 0xF4,
- 0xB8, 0x0C, 0x0A, 0xBB, 0xDD, 0xEF, 0xBA, 0x7B, 0x5C, 0x6E, 0x97, 0xDD,
- 0x74, 0x1D, 0x08, 0xCA, 0x2E, 0x87, 0xE7, 0x65, 0x50, 0x98, 0x4E, 0x2F,
- 0xBB, 0xC9, 0x20, 0x3A, 0xBA, 0x0C, 0x3A, 0x4E, 0x9B, 0x20, 0x7A, 0x98,
- 0xBD, 0x06, 0x85, 0xE9, 0xA0, 0x58, 0x4C, 0x37, 0x83, 0x81, 0xD2, 0x6E,
- 0xD0, 0x34, 0x1C, 0x66, 0x83, 0x62, 0x21, 0x90, 0xAE, 0x95, 0x02
-};
-#else
-/* Test TPDU - ALL YOUR */
-static u_int8_t tpdu_test[] = {
- 0x04, 0x04, 0x81, 0x32, 0x24, 0x00, 0x00, 0x80, 0x21, 0x03, 0x41, 0x24,
- 0x32, 0x40, 0x1F, 0x41, 0x26, 0x13, 0x94, 0x7D, 0x56, 0xA5, 0x20, 0x28,
- 0xF2, 0xE9, 0x2C, 0x82, 0x82, 0xD2, 0x22, 0x48, 0x58, 0x64, 0x3E, 0x9D,
- 0x47, 0x10, 0xF5, 0x09, 0xAA, 0x4E, 0x01
-};
-#endif
-
-int gsm0411_send_sms(struct gsm_lchan *lchan, struct sms_deliver *sms)
-{
- struct msgb *msg = gsm411_msgb_alloc();
- struct gsm48_hdr *gh;
- struct gsm411_rp_hdr *rp;
- u_int8_t *data;
-
- msg->lchan = lchan;
-
- gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
- gh->proto_discr = GSM48_PDISC_SMS;
- gh->msg_type = GSM411_MT_CP_DATA;
-
- rp = (struct gsm411_rp_hdr *)msgb_put(msg, sizeof(*rp));
- rp->len = sizeof(tpdu_test) + 10;
- rp->msg_type = GSM411_MT_RP_DATA_MT;
- rp->msg_ref = 42; /* FIXME: Choose randomly */
- /* Hardcode OA for now */
- data = (u_int8_t *)msgb_put(msg, 8);
- data[0] = 0x07;
- data[1] = 0x91;
- data[2] = 0x44;
- data[3] = 0x77;
- data[4] = 0x58;
- data[5] = 0x10;
- data[6] = 0x06;
- data[7] = 0x50;
- data = (u_int8_t *)msgb_put(msg, 1);
- data[0] = 0;
-
- /* FIXME: Hardcoded for now */
- //smslen = gsm0411_tpdu_from_sms(tpdu, sms);
-
- /* RPDU length */
- data = (u_int8_t *)msgb_put(msg, 1);
- data[0] = sizeof(tpdu_test);
-
- data = (u_int8_t *)msgb_put(msg, sizeof(tpdu_test));
-
- //memcpy(data, tpdu, smslen);
- memcpy(data, tpdu_test, sizeof(tpdu_test));
-
- DEBUGP(DSMS, "TX: SMS SUBMIT\n");
-
- return gsm0411_sendmsg(msg);
-}
diff --git a/src/gsm_data.c b/src/gsm_data.c
deleted file mode 100644
index a78425f95..000000000
--- a/src/gsm_data.c
+++ /dev/null
@@ -1,209 +0,0 @@
-/* (C) 2008-2009 by Harald Welte <laforge@gnumonks.org>
- *
- * All Rights Reserved
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- */
-
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-
-#include <openbsc/gsm_data.h>
-
-void set_ts_e1link(struct gsm_bts_trx_ts *ts, u_int8_t e1_nr,
- u_int8_t e1_ts, u_int8_t e1_ts_ss)
-{
- ts->e1_link.e1_nr = e1_nr;
- ts->e1_link.e1_ts = e1_ts;
- ts->e1_link.e1_ts_ss = e1_ts_ss;
-}
-
-static const char *pchan_names[] = {
- [GSM_PCHAN_NONE] = "NONE",
- [GSM_PCHAN_CCCH] = "CCCH",
- [GSM_PCHAN_CCCH_SDCCH4] = "CCCH+SDCCH4",
- [GSM_PCHAN_TCH_F] = "TCH/F",
- [GSM_PCHAN_TCH_H] = "TCH/H",
- [GSM_PCHAN_SDCCH8_SACCH8C] = "SDCCH8",
- [GSM_PCHAN_UNKNOWN] = "UNKNOWN",
-};
-
-const char *gsm_pchan_name(enum gsm_phys_chan_config c)
-{
- if (c >= ARRAY_SIZE(pchan_names))
- return "INVALID";
-
- return pchan_names[c];
-}
-
-static const char *lchan_names[] = {
- [GSM_LCHAN_NONE] = "NONE",
- [GSM_LCHAN_SDCCH] = "SDCCH",
- [GSM_LCHAN_TCH_F] = "TCH/F",
- [GSM_LCHAN_TCH_H] = "TCH/H",
- [GSM_LCHAN_UNKNOWN] = "UNKNOWN",
-};
-
-const char *gsm_lchan_name(enum gsm_chan_t c)
-{
- if (c >= ARRAY_SIZE(lchan_names))
- return "INVALID";
-
- return lchan_names[c];
-}
-
-static const char *chreq_names[] = {
- [GSM_CHREQ_REASON_EMERG] = "EMERGENCY",
- [GSM_CHREQ_REASON_PAG] = "PAGING",
- [GSM_CHREQ_REASON_CALL] = "CALL",
- [GSM_CHREQ_REASON_LOCATION_UPD] = "LOCATION_UPDATE",
- [GSM_CHREQ_REASON_OTHER] = "OTHER",
-};
-
-const char *gsm_chreq_name(enum gsm_chreq_reason_t c)
-{
- if (c >= ARRAY_SIZE(chreq_names))
- return "INVALID";
-
- return chreq_names[c];
-}
-
-struct gsm_network *gsm_network_init(unsigned int num_bts, enum gsm_bts_type bts_type,
- u_int16_t country_code, u_int16_t network_code)
-{
- int i;
- struct gsm_network *net;
-
- if (num_bts > GSM_MAX_BTS)
- return NULL;
-
- net = malloc(sizeof(*net));
- if (!net)
- return NULL;
- memset(net, 0, sizeof(*net));
-
- net->country_code = country_code;
- net->network_code = network_code;
- net->num_bts = num_bts;
-
- for (i = 0; i < num_bts; i++) {
- struct gsm_bts *bts = &net->bts[i];
- int j;
-
- bts->network = net;
- bts->nr = i;
- bts->type = bts_type;
- bts->tsc = HARDCODED_TSC;
- bts->bsic = HARDCODED_BSIC;
-
- for (j = 0; j < BTS_MAX_TRX; j++) {
- struct gsm_bts_trx *trx = &bts->trx[j];
- int k;
-
- trx->bts = bts;
- trx->nr = j;
-
- for (k = 0; k < 8; k++) {
- struct gsm_bts_trx_ts *ts = &trx->ts[k];
- int l;
-
- ts->trx = trx;
- ts->nr = k;
- ts->pchan = GSM_PCHAN_NONE;
-
- for (l = 0; l < TS_MAX_LCHAN; l++) {
- struct gsm_lchan *lchan;
- lchan = &ts->lchan[l];
-
- lchan->ts = ts;
- lchan->nr = l;
- lchan->type = GSM_LCHAN_NONE;
- }
- }
- }
-
- bts->num_trx = 1; /* FIXME */
-#ifdef HAVE_TRX1
- bts->num_trx++;
-#endif
- bts->c0 = &bts->trx[0];
- bts->c0->ts[0].pchan = GSM_PCHAN_CCCH_SDCCH4;
- }
- return net;
-}
-
-static char ts2str[255];
-
-char *gsm_ts_name(struct gsm_bts_trx_ts *ts)
-{
- snprintf(ts2str, sizeof(ts2str), "(bts=%d,trx=%d,ts=%d)",
- ts->trx->bts->bts_nr, ts->trx->nr, ts->nr);
-
- return ts2str;
-}
-
-static const char *bts_types[] = {
- [GSM_BTS_TYPE_UNKNOWN] = "unknown",
- [GSM_BTS_TYPE_BS11] = "bs11",
- [GSM_BTS_TYPE_NANOBTS_900] = "nanobts900",
- [GSM_BTS_TYPE_NANOBTS_1800] = "nanobts1800",
-};
-
-enum gsm_bts_type parse_btstype(char *arg)
-{
- int i;
- for (i = 0; i < ARRAY_SIZE(bts_types); i++) {
- if (!strcmp(arg, bts_types[i]))
- return i;
- }
- return GSM_BTS_TYPE_BS11; /* Default: BS11 */
-}
-
-char *btstype2str(enum gsm_bts_type type)
-{
- if (type > ARRAY_SIZE(bts_types))
- return "undefined";
- return bts_types[type];
-}
-
-/* Search for a BTS in the given Location Area; optionally start searching
- * with start_bts (for continuing to search after the first result) */
-struct gsm_bts *gsm_bts_by_lac(struct gsm_network *net, unsigned int lac,
- struct gsm_bts *start_bts)
-{
- int i;
- struct gsm_bts *bts;
- int skip = 0;
-
- if (start_bts)
- skip = 1;
-
- for (i = 0; i < net->num_bts; i++) {
- bts = &net->bts[i];
-
- if (skip) {
- if (start_bts == bts)
- skip = 0;
- continue;
- }
-
- if (bts->location_area_code == lac)
- return bts;
- }
- return NULL;
-}
diff --git a/src/gsm_subscriber.c b/src/gsm_subscriber.c
deleted file mode 100644
index 3f608ec30..000000000
--- a/src/gsm_subscriber.c
+++ /dev/null
@@ -1,143 +0,0 @@
-/* Dummy implementation of a subscriber database, roghly HLR/VLR functionality */
-
-/* (C) 2008 by Harald Welte <laforge@gnumonks.org>
- * (C) 2009 by Holger Hans Peter Freyther <zecke@selfish.org>
- *
- * All Rights Reserved
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- */
-
-#include <unistd.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-
-#include <openbsc/gsm_subscriber.h>
-#include <openbsc/debug.h>
-#include <openbsc/db.h>
-
-
-LLIST_HEAD(active_subscribers);
-
-struct gsm_subscriber *subscr_alloc(void)
-{
- struct gsm_subscriber *s;
-
- s = malloc(sizeof(struct gsm_subscriber));
- if (!s)
- return NULL;
-
- memset(s, 0, sizeof(*s));
- llist_add_tail(&s->entry, &active_subscribers);
- s->use_count = 1;
-
- return s;
-}
-
-static void subscr_free(struct gsm_subscriber *subscr)
-{
- llist_del(&subscr->entry);
- free(subscr);
-}
-
-struct gsm_subscriber *subscr_get_by_tmsi(const char *tmsi)
-{
- struct gsm_subscriber *subscr;
-
- /* we might have a record in memory already */
- llist_for_each_entry(subscr, &active_subscribers, entry) {
- if (strcmp(subscr->tmsi, tmsi) == 0)
- return subscr_get(subscr);
- }
-
- return db_get_subscriber(GSM_SUBSCRIBER_TMSI, tmsi);
-}
-
-struct gsm_subscriber *subscr_get_by_imsi(const char *imsi)
-{
- struct gsm_subscriber *subscr;
-
- llist_for_each_entry(subscr, &active_subscribers, entry) {
- if (strcmp(subscr->imsi, imsi) == 0)
- return subscr_get(subscr);
- }
-
- return db_get_subscriber(GSM_SUBSCRIBER_IMSI, imsi);
-}
-
-struct gsm_subscriber *subscr_get_by_extension(const char *ext)
-{
- struct gsm_subscriber *subscr;
-
- llist_for_each_entry(subscr, &active_subscribers, entry) {
- if (strcmp(subscr->extension, ext) == 0)
- return subscr_get(subscr);
- }
-
- return db_get_subscriber(GSM_SUBSCRIBER_EXTENSION, ext);
-}
-
-int subscr_update(struct gsm_subscriber *s, struct gsm_bts *bts, int reason)
-{
- /* FIXME: Migrate pending requests from one BSC to another */
- switch (reason) {
- case GSM_SUBSCRIBER_UPDATE_ATTACHED:
- /* Indicate "attached to LAC" */
- s->lac = bts->location_area_code;
- break;
- case GSM_SUBSCRIBER_UPDATE_DETACHED:
- /* Only detach if we are currently in this area */
- if (bts->location_area_code == s->lac)
- s->lac = 0;
-
- break;
- default:
- fprintf(stderr, "subscr_update with unknown reason: %d\n",
- reason);
- break;
- };
- return db_sync_subscriber(s);
-}
-
-struct gsm_subscriber *subscr_get(struct gsm_subscriber *subscr)
-{
- subscr->use_count++;
- DEBUGP(DCC, "subscr %s usage increases usage to: %d\n",
- subscr->extension, subscr->use_count);
- return subscr;
-}
-
-struct gsm_subscriber *subscr_put(struct gsm_subscriber *subscr)
-{
- subscr->use_count--;
- DEBUGP(DCC, "subscr %s usage decreased usage to: %d\n",
- subscr->extension, subscr->use_count);
- if (subscr->use_count <= 0)
- subscr_free(subscr);
- return NULL;
-}
-
-void subscr_put_channel(struct gsm_lchan *lchan)
-{
- /*
- * FIXME: Continue with other requests now... by checking
- * the gsm_subscriber inside the gsm_lchan. Drop the ref count
- * of the lchan after having asked the next requestee to handle
- * the channel.
- */
- put_lchan(lchan);
-}
diff --git a/src/gsm_utils.c b/src/gsm_utils.c
deleted file mode 100644
index 0c25b28c6..000000000
--- a/src/gsm_utils.c
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * (C) 2008 by Daniel Willmann <daniel@totalueberwachung.de>
- * (C) 2009 by Holger Hans Peter Freyther <zecke@selfish.org>
- * (C) 2009 by Harald Welte <laforge@gnumonks.org>
- *
- * All Rights Reserved
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- */
-
-#include <openbsc/gsm_utils.h>
-#include <stdlib.h>
-#include <string.h>
-
-/* GSM 03.38 6.2.1 Charachter packing */
-int gsm_7bit_decode(char *text, const u_int8_t *user_data, u_int8_t length)
-{
- u_int8_t d_off = 0, b_off = 0;
- u_int8_t i;
-
- for (i=0;i<length;i++) {
- text[i] = ((user_data[d_off] + (user_data[d_off+1]<<8)) & (0x7f<<b_off))>>b_off;
- b_off += 7;
- if (b_off >= 8) {
- d_off += 1;
- b_off -= 8;
- }
- }
- text[i] = '\0';
- return 0;
-}
-
-/* GSM 03.38 6.2.1 Charachter packing */
-int gsm_7bit_encode(u_int8_t *result, const char *data)
-{
- int i;
- u_int8_t d_off = 0, b_off = 0;
- const int length = strlen(data);
- int out_length = (length * 8)/7;
-
- memset(result, 0, out_length);
-
- for (i = 0; i < length; ++i) {
- u_int8_t first = (data[i] & 0x7f) << b_off;
- u_int8_t second = (data[i] & 0x7f) >> (8 - b_off);
-
- result[d_off] |= first;
- if (second != 0)
- result[d_off + 1] = second;
-
- b_off += 7;
-
- if (b_off >= 8) {
- d_off += 1;
- b_off -= 8;
- }
- }
-
- return out_length;
-}
diff --git a/src/input/ipaccess.c b/src/input/ipaccess.c
deleted file mode 100644
index ea7f847c2..000000000
--- a/src/input/ipaccess.c
+++ /dev/null
@@ -1,597 +0,0 @@
-/* OpenBSC Abis input driver for ip.access */
-
-/* (C) 2009 by Harald Welte <laforge@gnumonks.org>
- *
- * All Rights Reserved
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- */
-
-#include <stdio.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <string.h>
-#include <time.h>
-#include <sys/fcntl.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <sys/ioctl.h>
-#include <arpa/inet.h>
-
-#include <openbsc/select.h>
-#include <openbsc/tlv.h>
-#include <openbsc/msgb.h>
-#include <openbsc/debug.h>
-#include <openbsc/gsm_data.h>
-#include <openbsc/abis_nm.h>
-#include <openbsc/abis_rsl.h>
-#include <openbsc/subchan_demux.h>
-#include <openbsc/e1_input.h>
-#include <openbsc/ipaccess.h>
-
-/* data structure for one E1 interface with A-bis */
-struct ia_e1_handle {
- struct bsc_fd listen_fd;
- struct bsc_fd rsl_listen_fd;
- struct gsm_network *gsmnet;
-};
-
-static struct ia_e1_handle *e1h;
-
-
-#define TS1_ALLOC_SIZE 300
-
-static const u_int8_t pong[] = { 0, 1, IPAC_PROTO_IPACCESS, IPAC_MSGT_PONG };
-static const u_int8_t id_ack[] = { 0, 1, IPAC_PROTO_IPACCESS, IPAC_MSGT_ID_ACK };
-static const u_int8_t id_req[] = { 0, 17, IPAC_PROTO_IPACCESS, IPAC_MSGT_ID_GET,
- 0x01, IPAC_IDTAG_UNIT,
- 0x01, IPAC_IDTAG_MACADDR,
- 0x01, IPAC_IDTAG_LOCATION1,
- 0x01, IPAC_IDTAG_LOCATION2,
- 0x01, IPAC_IDTAG_EQUIPVERS,
- 0x01, IPAC_IDTAG_SWVERSION,
- 0x01, IPAC_IDTAG_UNITNAME,
- 0x01, IPAC_IDTAG_SERNR,
- };
-
-static const char *idtag_names[] = {
- [IPAC_IDTAG_SERNR] = "Serial_Number",
- [IPAC_IDTAG_UNITNAME] = "Unit_Name",
- [IPAC_IDTAG_LOCATION1] = "Location_1",
- [IPAC_IDTAG_LOCATION2] = "Location_2",
- [IPAC_IDTAG_EQUIPVERS] = "Equipment_Version",
- [IPAC_IDTAG_SWVERSION] = "Software_Version",
- [IPAC_IDTAG_IPADDR] = "IP_Address",
- [IPAC_IDTAG_MACADDR] = "MAC_Address",
- [IPAC_IDTAG_UNIT] = "Unit_ID",
-};
-
-static const char *ipac_idtag_name(int tag)
-{
- if (tag >= ARRAY_SIZE(idtag_names))
- return "unknown";
-
- return idtag_names[tag];
-}
-
-static int ipac_idtag_parse(struct tlv_parsed *dec, unsigned char *buf, int len)
-{
- u_int8_t t_len;
- u_int8_t t_tag;
- u_int8_t *cur = buf;
-
- while (cur < buf + len) {
- t_len = *cur++;
- t_tag = *cur++;
-
- DEBUGPC(DMI, "%s='%s' ", ipac_idtag_name(t_tag), cur);
-
- dec->lv[t_tag].len = t_len;
- dec->lv[t_tag].val = cur;
-
- cur += t_len;
- }
- return 0;
-}
-
-struct gsm_bts *find_bts_by_unitid(struct gsm_network *net,
- u_int16_t site_id, u_int16_t bts_id)
-{
- int i;
-
- for (i = 0; i < net->num_bts; i++) {
- struct gsm_bts *bts = &net->bts[i];
-
- if (!is_ipaccess_bts(bts))
- continue;
-
- if (bts->ip_access.site_id == site_id &&
- bts->ip_access.bts_id == bts_id)
- return bts;
- }
-
- return NULL;
-}
-
-static int parse_unitid(const char *str, u_int16_t *site_id, u_int16_t *bts_id,
- u_int16_t *trx_id)
-{
- unsigned long ul;
- char *endptr;
- const char *nptr;
-
- nptr = str;
- ul = strtoul(nptr, &endptr, 10);
- if (endptr <= nptr)
- return -EINVAL;
- if (site_id)
- *site_id = ul & 0xffff;
-
- if (*endptr++ != '/')
- return -EINVAL;
-
- nptr = endptr;
- ul = strtoul(nptr, &endptr, 10);
- if (endptr <= nptr)
- return -EINVAL;
- if (bts_id)
- *bts_id = ul & 0xffff;
-
- if (*endptr++ != '/')
- return -EINVAL;
-
- nptr = endptr;
- ul = strtoul(nptr, &endptr, 10);
- if (endptr <= nptr)
- return -EINVAL;
- if (trx_id)
- *trx_id = ul & 0xffff;
-
- return 0;
-}
-
-static int ipaccess_rcvmsg(struct e1inp_line *line, struct msgb *msg,
- struct bsc_fd *bfd)
-{
- struct tlv_parsed tlvp;
- u_int8_t msg_type = *(msg->l2h);
- u_int16_t site_id, bts_id, trx_id;
- struct gsm_bts *bts;
- int ret = 0;
-
- switch (msg_type) {
- case IPAC_MSGT_PING:
- ret = write(bfd->fd, pong, sizeof(pong));
- break;
- case IPAC_MSGT_PONG:
- DEBUGP(DMI, "PONG!\n");
- break;
- case IPAC_MSGT_ID_RESP:
- DEBUGP(DMI, "ID_RESP ");
- /* parse tags, search for Unit ID */
- ipac_idtag_parse(&tlvp, (u_int8_t *)msg->l2h + 2,
- msgb_l2len(msg)-2);
- DEBUGP(DMI, "\n");
-
- if (!TLVP_PRESENT(&tlvp, IPAC_IDTAG_UNIT))
- break;
-
- /* lookup BTS, create sign_link, ... */
- parse_unitid((char *)TLVP_VAL(&tlvp, IPAC_IDTAG_UNIT),
- &site_id, &bts_id, &trx_id);
- bts = find_bts_by_unitid(e1h->gsmnet, site_id, bts_id);
- if (!bts) {
- DEBUGP(DINP, "Unable to find BTS configuration for "
- " %u/%u/%u, disconnecting\n", site_id, bts_id,
- trx_id);
- return -EIO;
- }
- DEBUGP(DINP, "Identified BTS %u/%u/%u\n", site_id, bts_id, trx_id);
- if (bfd->priv_nr == 1) {
- bts->oml_link = e1inp_sign_link_create(&line->ts[1-1],
- E1INP_SIGN_OML, bts->c0,
- 0, 0xff);
- } else if (bfd->priv_nr == 2) {
- struct e1inp_ts *e1i_ts;
- struct bsc_fd *newbfd;
-
- /* FIXME: implement this for non-0 TRX */
- bfd->data = line = bts->oml_link->ts->line;
- e1i_ts = &line->ts[2-1];
- newbfd = &e1i_ts->driver.ipaccess.fd;
-
- bts->c0->rsl_link =
- e1inp_sign_link_create(e1i_ts,
- E1INP_SIGN_RSL, bts->c0,
- 0, 0);
- /* get rid of our old temporary bfd */
- memcpy(newbfd, bfd, sizeof(*newbfd));
- bsc_unregister_fd(bfd);
- bsc_register_fd(newbfd);
- free(bfd);
- }
- break;
- case IPAC_MSGT_ID_ACK:
- DEBUGP(DMI, "ID_ACK? -> ACK!\n");
- ret = write(bfd->fd, id_ack, sizeof(id_ack));
- break;
- }
- return 0;
-}
-
-/* FIXME: this is per BTS */
-static int oml_up = 0;
-static int rsl_up = 0;
-
-static int handle_ts1_read(struct bsc_fd *bfd)
-{
- struct e1inp_line *line = bfd->data;
- unsigned int ts_nr = bfd->priv_nr;
- struct e1inp_ts *e1i_ts = &line->ts[ts_nr-1];
- struct e1inp_sign_link *link;
- struct msgb *msg = msgb_alloc(TS1_ALLOC_SIZE);
- struct ipaccess_head *hh;
- int ret;
-
- if (!msg)
- return -ENOMEM;
-
- /* first read our 3-byte header */
- hh = (struct ipaccess_head *) msg->data;
- ret = recv(bfd->fd, msg->data, 3, 0);
- if (ret < 0) {
- fprintf(stderr, "recv error %s\n", strerror(errno));
- return ret;
- }
- if (ret == 0) {
- fprintf(stderr, "BTS disappeared, dead socket\n");
- e1inp_event(e1i_ts, EVT_E1_TEI_DN, 0, IPAC_PROTO_RSL);
- e1inp_event(e1i_ts, EVT_E1_TEI_DN, 0, IPAC_PROTO_OML);
- bsc_unregister_fd(bfd);
- close(bfd->fd);
- bfd->fd = -1;
- }
- msgb_put(msg, ret);
-
- /* then read te length as specified in header */
- msg->l2h = msg->data + sizeof(*hh);
- ret = recv(bfd->fd, msg->l2h, hh->len, 0);
- if (ret < hh->len) {
- fprintf(stderr, "short read!\n");
- msgb_free(msg);
- return -EIO;
- }
- msgb_put(msg, ret);
- DEBUGP(DMI, "RX %u: %s\n", ts_nr, hexdump(msgb_l2(msg), ret));
-
- if (hh->proto == IPAC_PROTO_IPACCESS) {
- ret = ipaccess_rcvmsg(line, msg, bfd);
- if (ret < 0) {
- e1inp_event(e1i_ts, EVT_E1_TEI_DN, 0, IPAC_PROTO_RSL);
- e1inp_event(e1i_ts, EVT_E1_TEI_DN, 0, IPAC_PROTO_OML);
- bsc_unregister_fd(bfd);
- close(bfd->fd);
- bfd->fd = -1;
- }
- msgb_free(msg);
- return ret;
- }
- /* BIG FAT WARNING: bfd might no longer exist here, since ipaccess_rcvmsg()
- * might have free'd it !!! */
-
- link = e1inp_lookup_sign_link(e1i_ts, 0, hh->proto);
- if (!link) {
- printf("no matching signalling link for hh->proto=0x%02x\n", hh->proto);
- msgb_free(msg);
- return -EIO;
- }
- msg->trx = link->trx;
-
- switch (hh->proto) {
- case IPAC_PROTO_RSL:
- if (!rsl_up) {
- e1inp_event(e1i_ts, EVT_E1_TEI_UP, 0, IPAC_PROTO_RSL);
- rsl_up = 1;
- }
- ret = abis_rsl_rcvmsg(msg);
- break;
- case IPAC_PROTO_OML:
- if (!oml_up) {
- e1inp_event(e1i_ts, EVT_E1_TEI_UP, 0, IPAC_PROTO_OML);
- oml_up = 1;
- }
- ret = abis_nm_rcvmsg(msg);
- break;
- default:
- DEBUGP(DMI, "Unknown IP.access protocol proto=0x%02x\n", hh->proto);
- msgb_free(msg);
- break;
- }
- return ret;
-}
-
-static int handle_ts1_write(struct bsc_fd *bfd)
-{
- struct e1inp_line *line = bfd->data;
- unsigned int ts_nr = bfd->priv_nr;
- struct e1inp_ts *e1i_ts = &line->ts[ts_nr-1];
- struct e1inp_sign_link *sign_link;
- struct msgb *msg;
- struct ipaccess_head *hh;
- u_int8_t *l2_data;
- int ret;
-
- /* get the next msg for this timeslot */
- msg = e1inp_tx_ts(e1i_ts, &sign_link);
- if (!msg) {
- bfd->when &= ~BSC_FD_WRITE;
- return 0;
- }
-
- l2_data = msg->data;
-
- /* prepend the ip.access header */
- hh = (struct ipaccess_head *) msgb_push(msg, sizeof(*hh));
- hh->zero = 0;
- hh->len = msg->len - sizeof(*hh);
-
- switch (sign_link->type) {
- case E1INP_SIGN_OML:
- hh->proto = IPAC_PROTO_OML;
- break;
- case E1INP_SIGN_RSL:
- hh->proto = IPAC_PROTO_RSL;
- break;
- default:
- msgb_free(msg);
- return -EINVAL;
- }
-
- DEBUGP(DMI, "TX %u: %s\n", ts_nr, hexdump(l2_data, hh->len));
-
- ret = send(bfd->fd, msg->data, msg->len, 0);
- msgb_free(msg);
- usleep(100000);
-
- return ret;
-}
-
-/* callback from select.c in case one of the fd's can be read/written */
-static int ipaccess_fd_cb(struct bsc_fd *bfd, unsigned int what)
-{
- struct e1inp_line *line = bfd->data;
- unsigned int ts_nr = bfd->priv_nr;
- unsigned int idx = ts_nr-1;
- struct e1inp_ts *e1i_ts;
- int rc = 0;
-
- /* In case of early RSL we might not yet have a line */
-
- if (line)
- e1i_ts = &line->ts[idx];
-
- if (!line || e1i_ts->type == E1INP_TS_TYPE_SIGN) {
- if (what & BSC_FD_READ)
- rc = handle_ts1_read(bfd);
- if (what & BSC_FD_WRITE)
- rc = handle_ts1_write(bfd);
- } else
- fprintf(stderr, "unknown E1 TS type %u\n", e1i_ts->type);
-
- return rc;
-}
-
-
-static int ts_want_write(struct e1inp_ts *e1i_ts)
-{
- e1i_ts->driver.ipaccess.fd.when |= BSC_FD_WRITE;
-
- return 0;
-}
-
-struct e1inp_driver ipaccess_driver = {
- .name = "ip.access",
- .want_write = ts_want_write,
-};
-
-/* callback of the OML listening filedescriptor */
-static int listen_fd_cb(struct bsc_fd *listen_bfd, unsigned int what)
-{
- int ret;
- int idx = 0;
- struct e1inp_line *line;
- struct e1inp_ts *e1i_ts;
- struct bsc_fd *bfd;
- struct sockaddr_in sa;
- socklen_t sa_len = sizeof(sa);
-
- if (!(what & BSC_FD_READ))
- return 0;
-
- ret = accept(listen_bfd->fd, (struct sockaddr *) &sa, &sa_len);
- if (ret < 0) {
- perror("accept");
- return ret;
- }
- DEBUGP(DINP, "accept()ed new OML link from %s\n", inet_ntoa(sa.sin_addr));
-
- line = malloc(sizeof(*line));
- if (!line) {
- close(ret);
- return -ENOMEM;
- }
- memset(line, 0, sizeof(*line));
- line->driver = &ipaccess_driver;
- //line->driver_data = e1h;
- /* create virrtual E1 timeslots for signalling */
- e1inp_ts_config(&line->ts[1-1], line, E1INP_TS_TYPE_SIGN);
- e1inp_ts_config(&line->ts[2-1], line, E1INP_TS_TYPE_SIGN);
-
- e1i_ts = &line->ts[idx];
-
- bfd = &e1i_ts->driver.ipaccess.fd;
- bfd->fd = ret;
- bfd->data = line;
- bfd->priv_nr = 1;
- bfd->cb = ipaccess_fd_cb;
- bfd->when = BSC_FD_READ;
- ret = bsc_register_fd(bfd);
- if (ret < 0) {
- fprintf(stderr, "could not register FD\n");
- close(bfd->fd);
- free(line);
- return ret;
- }
-
- /* Request ID. FIXME: request LOCATION, HW/SW VErsion, Unit Name, Serno */
- ret = write(bfd->fd, id_req, sizeof(id_req));
-
- return e1inp_line_register(line);
-}
-
-static int rsl_listen_fd_cb(struct bsc_fd *listen_bfd, unsigned int what)
-{
- struct sockaddr_in sa;
- socklen_t sa_len = sizeof(sa);
- struct bsc_fd *bfd = malloc(sizeof(*bfd));
- int ret;
-
- if (!(what & BSC_FD_READ))
- return 0;
-
- /* Some BTS has connected to us, but we don't know yet which line
- * (as created by the OML link) to associate it with. Thus, we
- * aloocate a temporary bfd until we have received ID from BTS */
-
- bfd->fd = accept(listen_bfd->fd, (struct sockaddr *) &sa, &sa_len);
- if (bfd->fd < 0) {
- perror("accept");
- return bfd->fd;
- }
- DEBUGP(DINP, "accept()ed new RSL link from %s\n", inet_ntoa(sa.sin_addr));
- bfd->priv_nr = 2;
- bfd->cb = ipaccess_fd_cb;
- bfd->when = BSC_FD_READ;
- ret = bsc_register_fd(bfd);
- if (ret < 0) {
- fprintf(stderr, "could not register FD\n");
- close(bfd->fd);
- free(bfd);
- return ret;
- }
- /* Request ID. FIXME: request LOCATION, HW/SW VErsion, Unit Name, Serno */
- ret = write(bfd->fd, id_req, sizeof(id_req));
-
- return 0;
-}
-
-static int make_sock(struct bsc_fd *bfd, u_int16_t port,
- int (*cb)(struct bsc_fd *fd, unsigned int what))
-{
- struct sockaddr_in addr;
- int ret, on = 1;
-
- bfd->fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
- bfd->cb = cb;
- bfd->when = BSC_FD_READ;
- //bfd->data = line;
-
- memset(&addr, 0, sizeof(addr));
- addr.sin_family = AF_INET;
- addr.sin_port = htons(port);
- addr.sin_addr.s_addr = INADDR_ANY;
-
- setsockopt(bfd->fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
-
- ret = bind(bfd->fd, (struct sockaddr *) &addr, sizeof(addr));
- if (ret < 0) {
- fprintf(stderr, "could not bind l2 socket %s\n",
- strerror(errno));
- return -EIO;
- }
-
- ret = listen(bfd->fd, 1);
- if (ret < 0) {
- perror("listen");
- return ret;
- }
-
- ret = bsc_register_fd(bfd);
- if (ret < 0) {
- perror("register_listen_fd");
- return ret;
- }
- return 0;
-}
-
-/* Actively connect to a BTS. Currently used by ipaccess-config.c */
-int ipaccess_connect(struct e1inp_line *line, struct sockaddr_in *sa)
-{
- struct e1inp_ts *e1i_ts = &line->ts[0];
- struct bsc_fd *bfd = &e1i_ts->driver.ipaccess.fd;
- int ret, on = 1;
-
- bfd->fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
- bfd->cb = ipaccess_fd_cb;
- bfd->when = BSC_FD_READ | BSC_FD_WRITE;
- bfd->data = line;
- bfd->priv_nr = 1;
-
- setsockopt(bfd->fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
-
- ret = connect(bfd->fd, (struct sockaddr *) sa, sizeof(*sa));
- if (ret < 0) {
- fprintf(stderr, "could not connect socket\n");
- close(bfd->fd);
- return ret;
- }
-
- ret = bsc_register_fd(bfd);
- if (ret < 0) {
- close(bfd->fd);
- return ret;
- }
-
- line->driver = &ipaccess_driver;
-
- return e1inp_line_register(line);
-}
-
-int ipaccess_setup(struct gsm_network *gsmnet)
-{
- int ret;
-
- /* register the driver with the core */
- /* FIXME: do this in the plugin initializer function */
- ret = e1inp_driver_register(&ipaccess_driver);
- if (ret)
- return ret;
-
- e1h = malloc(sizeof(*e1h));
- memset(e1h, 0, sizeof(*e1h));
- e1h->gsmnet = gsmnet;
-
- /* Listen for OML connections */
- ret = make_sock(&e1h->listen_fd, 3002, listen_fd_cb);
- if (ret < 0)
- return ret;
-
- /* Listen for RSL connections */
- ret = make_sock(&e1h->rsl_listen_fd, 3003, rsl_listen_fd_cb);
-
- return ret;
-}
diff --git a/src/input/misdn.c b/src/input/misdn.c
deleted file mode 100644
index de8d41f21..000000000
--- a/src/input/misdn.c
+++ /dev/null
@@ -1,542 +0,0 @@
-/* OpenBSC Abis input driver for mISDNuser */
-
-/* (C) 2008-2009 by Harald Welte <laforge@gnumonks.org>
- * (C) 2009 by Holger Hans Peter Freyther <zecke@selfish.org>
- *
- * All Rights Reserved
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- */
-
-#include <stdio.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <string.h>
-#include <time.h>
-#include <sys/fcntl.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <sys/ioctl.h>
-#include <arpa/inet.h>
-#include <mISDNif.h>
-
-//#define AF_COMPATIBILITY_FUNC
-//#include <compat_af_isdn.h>
-#define AF_ISDN 34
-#define PF_ISDN AF_ISDN
-
-#include <openbsc/select.h>
-#include <openbsc/msgb.h>
-#include <openbsc/debug.h>
-#include <openbsc/gsm_data.h>
-#include <openbsc/abis_nm.h>
-#include <openbsc/abis_rsl.h>
-#include <openbsc/subchan_demux.h>
-#include <openbsc/e1_input.h>
-
-/* data structure for one E1 interface with A-bis */
-struct mi_e1_handle {
- /* The mISDN card number of the card we use */
- int cardnr;
-};
-
-#define TS1_ALLOC_SIZE 300
-
-struct prim_name {
- unsigned int prim;
- const char *name;
-};
-
-const struct prim_name prim_names[] = {
- { PH_CONTROL_IND, "PH_CONTROL_IND" },
- { PH_DATA_IND, "PH_DATA_IND" },
- { PH_DATA_CNF, "PH_DATA_CNF" },
- { PH_ACTIVATE_IND, "PH_ACTIVATE_IND" },
- { DL_ESTABLISH_IND, "DL_ESTABLISH_IND" },
- { DL_ESTABLISH_CNF, "DL_ESTABLISH_CNF" },
- { DL_RELEASE_IND, "DL_RELEASE_IND" },
- { DL_RELEASE_CNF, "DL_RELEASE_CNF" },
- { DL_DATA_IND, "DL_DATA_IND" },
- { DL_UNITDATA_IND, "DL_UNITDATA_IND" },
- { DL_INFORMATION_IND, "DL_INFORMATION_IND" },
- { MPH_ACTIVATE_IND, "MPH_ACTIVATE_IND" },
- { MPH_DEACTIVATE_IND, "MPH_DEACTIVATE_IND" },
-};
-
-const char *get_prim_name(unsigned int prim)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(prim_names); i++) {
- if (prim_names[i].prim == prim)
- return prim_names[i].name;
- }
-
- return "UNKNOWN";
-}
-
-static int handle_ts1_read(struct bsc_fd *bfd)
-{
- struct e1inp_line *line = bfd->data;
- unsigned int ts_nr = bfd->priv_nr;
- struct e1inp_ts *e1i_ts = &line->ts[ts_nr-1];
- struct e1inp_sign_link *link;
- struct msgb *msg = msgb_alloc(TS1_ALLOC_SIZE);
- struct sockaddr_mISDN l2addr;
- struct mISDNhead *hh;
- socklen_t alen;
- int ret;
-
- if (!msg)
- return -ENOMEM;
-
- hh = (struct mISDNhead *) msg->data;
-
- alen = sizeof(l2addr);
- ret = recvfrom(bfd->fd, msg->data, 300, 0,
- (struct sockaddr *) &l2addr, &alen);
- if (ret < 0) {
- fprintf(stderr, "recvfrom error %s\n", strerror(errno));
- return ret;
- }
-
- if (alen != sizeof(l2addr)) {
- fprintf(stderr, "%s error len\n", __func__);
- return -EINVAL;
- }
-
- msgb_put(msg, ret);
-
- DEBUGP(DMI, "alen =%d, dev(%d) channel(%d) sapi(%d) tei(%d)\n",
- alen, l2addr.dev, l2addr.channel, l2addr.sapi, l2addr.tei);
-
- DEBUGP(DMI, "<= len = %d, prim(0x%x) id(0x%x): %s\n",
- ret, hh->prim, hh->id, get_prim_name(hh->prim));
-
- switch (hh->prim) {
- case DL_INFORMATION_IND:
- /* mISDN tells us which channel number is allocated for this
- * tuple of (SAPI, TEI). */
- DEBUGP(DMI, "DL_INFORMATION_IND: use channel(%d) sapi(%d) tei(%d) for now\n",
- l2addr.channel, l2addr.sapi, l2addr.tei);
- link = e1inp_lookup_sign_link(e1i_ts, l2addr.tei, l2addr.sapi);
- if (!link) {
- DEBUGPC(DMI, "mISDN message for unknown sign_link\n");
- free(msg);
- return -EINVAL;
- }
- /* save the channel number in the driver private struct */
- link->driver.misdn.channel = l2addr.channel;
- break;
- case DL_ESTABLISH_IND:
- DEBUGP(DMI, "DL_ESTABLISH_IND: channel(%d) sapi(%d) tei(%d)\n",
- l2addr.channel, l2addr.sapi, l2addr.tei);
- ret = e1inp_event(e1i_ts, EVT_E1_TEI_UP, l2addr.tei, l2addr.sapi);
- break;
- case DL_RELEASE_IND:
- DEBUGP(DMI, "DL_RELEASE_IND: channel(%d) sapi(%d) tei(%d)\n",
- l2addr.channel, l2addr.sapi, l2addr.tei);
- ret = e1inp_event(e1i_ts, EVT_E1_TEI_DN, l2addr.tei, l2addr.sapi);
- break;
- case DL_DATA_IND:
- msg->l2h = msg->data + MISDN_HEADER_LEN;
- DEBUGP(DMI, "RX: %s\n", hexdump(msgb_l2(msg), ret - MISDN_HEADER_LEN));
- ret = e1inp_rx_ts(e1i_ts, msg, l2addr.tei, l2addr.sapi);
- break;
- case PH_ACTIVATE_IND:
- DEBUGP(DMI, "PH_ACTIVATE_IND: channel(%d) sapi(%d) tei(%d)\n",
- l2addr.channel, l2addr.sapi, l2addr.tei);
- break;
- case PH_DEACTIVATE_IND:
- DEBUGP(DMI, "PH_DEACTIVATE_IND: channel(%d) sapi(%d) tei(%d)\n",
- l2addr.channel, l2addr.sapi, l2addr.tei);
- break;
- default:
- break;
- }
- return ret;
-}
-
-static int ts_want_write(struct e1inp_ts *e1i_ts)
-{
- /* We never include the mISDN B-Channel FD into the
- * writeset, since it doesn't support poll() based
- * write flow control */
- if (e1i_ts->type == E1INP_TS_TYPE_TRAU)
- return 0;
-
- e1i_ts->driver.misdn.fd.when |= BSC_FD_WRITE;
-
- return 0;
-}
-
-static void timeout_ts1_write(void *data)
-{
- struct e1inp_ts *e1i_ts = (struct e1inp_ts *)data;
-
- /* trigger write of ts1, due to tx delay timer */
- ts_want_write(e1i_ts);
-}
-
-static int handle_ts1_write(struct bsc_fd *bfd)
-{
- struct e1inp_line *line = bfd->data;
- unsigned int ts_nr = bfd->priv_nr;
- struct e1inp_ts *e1i_ts = &line->ts[ts_nr-1];
- struct e1inp_sign_link *sign_link;
- struct sockaddr_mISDN sa;
- struct msgb *msg;
- struct mISDNhead *hh;
- u_int8_t *l2_data;
- int ret;
-
- bfd->when &= ~BSC_FD_WRITE;
-
- /* get the next msg for this timeslot */
- msg = e1inp_tx_ts(e1i_ts, &sign_link);
- if (!msg) {
- /* no message after tx delay timer */
- return 0;
- }
-
- l2_data = msg->data;
-
- /* prepend the mISDNhead */
- hh = (struct mISDNhead *) msgb_push(msg, sizeof(*hh));
- hh->prim = DL_DATA_REQ;
-
- DEBUGP(DMI, "TX TEI(%d) SAPI(%d): %s\n", sign_link->tei,
- sign_link->sapi, hexdump(l2_data, msg->len - MISDN_HEADER_LEN));
-
- /* construct the sockaddr */
- sa.family = AF_ISDN;
- sa.sapi = sign_link->sapi;
- sa.dev = sign_link->tei;
- sa.channel = sign_link->driver.misdn.channel;
-
- ret = sendto(bfd->fd, msg->data, msg->len, 0,
- (struct sockaddr *)&sa, sizeof(sa));
- if (ret < 0)
- fprintf(stderr, "%s sendto failed %d\n", __func__, ret);
- msgb_free(msg);
-
- /* set tx delay timer for next event */
- e1i_ts->sign.tx_timer.cb = timeout_ts1_write;
- e1i_ts->sign.tx_timer.data = e1i_ts;
- bsc_schedule_timer(&e1i_ts->sign.tx_timer, 0, 50000);
-
- return ret;
-}
-
-#define BCHAN_TX_GRAN 160
-/* write to a B channel TS */
-static int handle_tsX_write(struct bsc_fd *bfd)
-{
- struct e1inp_line *line = bfd->data;
- unsigned int ts_nr = bfd->priv_nr;
- struct e1inp_ts *e1i_ts = &line->ts[ts_nr-1];
- struct mISDNhead *hh;
- u_int8_t tx_buf[BCHAN_TX_GRAN + sizeof(*hh)];
- struct subch_mux *mx = &e1i_ts->trau.mux;
- int ret;
-
- hh = (struct mISDNhead *) tx_buf;
- hh->prim = PH_DATA_REQ;
-
- subchan_mux_out(mx, tx_buf+sizeof(*hh), BCHAN_TX_GRAN);
-
- DEBUGP(DMIB, "BCHAN TX: %s\n",
- hexdump(tx_buf+sizeof(*hh), BCHAN_TX_GRAN));
-
- ret = send(bfd->fd, tx_buf, sizeof(*hh) + BCHAN_TX_GRAN, 0);
- if (ret < sizeof(*hh) + BCHAN_TX_GRAN)
- DEBUGP(DMIB, "send returns %d instead of %u\n", ret,
- sizeof(*hh) + BCHAN_TX_GRAN);
-
- return ret;
-}
-
-#define TSX_ALLOC_SIZE 4096
-/* FIXME: read from a B channel TS */
-static int handle_tsX_read(struct bsc_fd *bfd)
-{
- struct e1inp_line *line = bfd->data;
- unsigned int ts_nr = bfd->priv_nr;
- struct e1inp_ts *e1i_ts = &line->ts[ts_nr-1];
- struct msgb *msg = msgb_alloc(TSX_ALLOC_SIZE);
- struct mISDNhead *hh;
- int ret;
-
- if (!msg)
- return -ENOMEM;
-
- hh = (struct mISDNhead *) msg->data;
-
- ret = recv(bfd->fd, msg->data, TSX_ALLOC_SIZE, 0);
- if (ret < 0) {
- fprintf(stderr, "recvfrom error %s\n", strerror(errno));
- return ret;
- }
-
- msgb_put(msg, ret);
-
- if (hh->prim != PH_CONTROL_IND)
- DEBUGP(DMIB, "<= BCHAN len = %d, prim(0x%x) id(0x%x): %s\n",
- ret, hh->prim, hh->id, get_prim_name(hh->prim));
-
- switch (hh->prim) {
- case PH_DATA_IND:
- msg->l2h = msg->data + MISDN_HEADER_LEN;
- DEBUGP(DMIB, "BCHAN RX: %s\n",
- hexdump(msgb_l2(msg), ret - MISDN_HEADER_LEN));
- ret = e1inp_rx_ts(e1i_ts, msg, 0, 0);
- break;
- case PH_ACTIVATE_IND:
- case PH_DATA_CNF:
- /* physical layer indicates that data has been sent,
- * we thus can send some more data */
- ret = handle_tsX_write(bfd);
- default:
- break;
- }
- /* FIXME: why do we free signalling msgs in the caller, and trau not? */
- msgb_free(msg);
-
- return ret;
-}
-
-/* callback from select.c in case one of the fd's can be read/written */
-static int misdn_fd_cb(struct bsc_fd *bfd, unsigned int what)
-{
- struct e1inp_line *line = bfd->data;
- unsigned int ts_nr = bfd->priv_nr;
- unsigned int idx = ts_nr-1;
- struct e1inp_ts *e1i_ts = &line->ts[idx];
- int rc = 0;
-
- switch (e1i_ts->type) {
- case E1INP_TS_TYPE_SIGN:
- if (what & BSC_FD_READ)
- rc = handle_ts1_read(bfd);
- if (what & BSC_FD_WRITE)
- rc = handle_ts1_write(bfd);
- break;
- case E1INP_TS_TYPE_TRAU:
- if (what & BSC_FD_READ)
- rc = handle_tsX_read(bfd);
- /* We never include the mISDN B-Channel FD into the
- * writeset, since it doesn't support poll() based
- * write flow control */
- break;
- default:
- fprintf(stderr, "unknown E1 TS type %u\n", e1i_ts->type);
- break;
- }
-
- return rc;
-}
-
-static int activate_bchan(struct e1inp_line *line, int ts, int act)
-{
- struct mISDNhead hh;
- int ret;
- unsigned int idx = ts-1;
- struct e1inp_ts *e1i_ts = &line->ts[idx];
- struct bsc_fd *bfd = &e1i_ts->driver.misdn.fd;
-
- fprintf(stdout, "activate bchan\n");
- if (act)
- hh.prim = PH_ACTIVATE_REQ;
- else
- hh.prim = PH_DEACTIVATE_REQ;
-
- hh.id = MISDN_ID_ANY;
- ret = sendto(bfd->fd, &hh, sizeof(hh), 0, NULL, 0);
- if (ret < 0) {
- fprintf(stdout, "could not send ACTIVATE_RQ %s\n",
- strerror(errno));
- }
-
- return ret;
-}
-
-struct e1inp_driver misdn_driver = {
- .name = "mISDNuser",
- .want_write = ts_want_write,
-};
-
-static int mi_e1_setup(struct e1inp_line *line, int release_l2)
-{
- struct mi_e1_handle *e1h = line->driver_data;
- int ts, ret;
-
- /* TS0 is CRC4, don't need any fd for it */
- for (ts = 1; ts < NUM_E1_TS; ts++) {
- unsigned int idx = ts-1;
- struct e1inp_ts *e1i_ts = &line->ts[idx];
- struct bsc_fd *bfd = &e1i_ts->driver.misdn.fd;
- struct sockaddr_mISDN addr;
-
- bfd->data = line;
- bfd->priv_nr = ts;
- bfd->cb = misdn_fd_cb;
-
- switch (e1i_ts->type) {
- case E1INP_TS_TYPE_NONE:
- continue;
- break;
- case E1INP_TS_TYPE_SIGN:
- bfd->fd = socket(PF_ISDN, SOCK_DGRAM, ISDN_P_LAPD_NT);
- bfd->when = BSC_FD_READ;
- break;
- case E1INP_TS_TYPE_TRAU:
- bfd->fd = socket(PF_ISDN, SOCK_DGRAM, ISDN_P_B_RAW);
- /* We never include the mISDN B-Channel FD into the
- * writeset, since it doesn't support poll() based
- * write flow control */
- bfd->when = BSC_FD_READ;
- break;
- }
-
- if (bfd->fd < 0) {
- fprintf(stderr, "%s could not open socket %s\n",
- __func__, strerror(errno));
- return bfd->fd;
- }
-
- memset(&addr, 0, sizeof(addr));
- addr.family = AF_ISDN;
- addr.dev = e1h->cardnr;
- switch (e1i_ts->type) {
- case E1INP_TS_TYPE_SIGN:
- addr.channel = 0;
- /* SAPI not supported yet in kernel */
- //addr.sapi = e1inp_ts->sign.sapi;
- addr.sapi = 0;
- addr.tei = GROUP_TEI;
- break;
- case E1INP_TS_TYPE_TRAU:
- addr.channel = ts;
- break;
- default:
- DEBUGP(DMI, "unsupported E1 TS type: %u\n",
- e1i_ts->type);
- break;
- }
-
- ret = bind(bfd->fd, (struct sockaddr *) &addr, sizeof(addr));
- if (ret < 0) {
- fprintf(stderr, "could not bind l2 socket %s\n",
- strerror(errno));
- return -EIO;
- }
-
- if (e1i_ts->type == E1INP_TS_TYPE_SIGN) {
- ret = ioctl(bfd->fd, IMCLEAR_L2, &release_l2);
- if (ret < 0) {
- fprintf(stderr, "could not send IOCTL IMCLEAN_L2 %s\n", strerror(errno));
- return -EIO;
- }
- }
-
- /* FIXME: only activate B-Channels once we start to
- * use them to conserve CPU power */
- if (e1i_ts->type == E1INP_TS_TYPE_TRAU)
- activate_bchan(line, ts, 1);
-
- ret = bsc_register_fd(bfd);
- if (ret < 0) {
- fprintf(stderr, "could not register FD: %s\n",
- strerror(ret));
- return ret;
- }
- }
-
- return 0;
-}
-
-int mi_setup(int cardnr, struct e1inp_line *line, int release_l2)
-{
- struct mi_e1_handle *e1h;
- int sk, ret, cnt;
- struct mISDN_devinfo devinfo;
-
- /* register the driver with the core */
- /* FIXME: do this in the plugin initializer function */
- ret = e1inp_driver_register(&misdn_driver);
- if (ret)
- return ret;
-
- /* create the actual line instance */
- /* FIXME: do this independent of driver registration */
- e1h = malloc(sizeof(*e1h));
- memset(e1h, 0, sizeof(*e1h));
-
- e1h->cardnr = cardnr;
-
- line->driver = &misdn_driver;
- line->driver_data = e1h;
-
- /* open the ISDN card device */
- sk = socket(PF_ISDN, SOCK_RAW, ISDN_P_BASE);
- if (sk < 0) {
- fprintf(stderr, "%s could not open socket %s\n",
- __func__, strerror(errno));
- return sk;
- }
-
- ret = ioctl(sk, IMGETCOUNT, &cnt);
- if (ret) {
- fprintf(stderr, "%s error getting interf count: %s\n",
- __func__, strerror(errno));
- close(sk);
- return -ENODEV;
- }
- //DEBUGP(DMI,"%d device%s found\n", cnt, (cnt==1)?"":"s");
- printf("%d device%s found\n", cnt, (cnt==1)?"":"s");
-#if 1
- devinfo.id = e1h->cardnr;
- ret = ioctl(sk, IMGETDEVINFO, &devinfo);
- if (ret < 0) {
- fprintf(stdout, "error getting info for device %d: %s\n",
- e1h->cardnr, strerror(errno));
- return -ENODEV;
- }
- fprintf(stdout, " id: %d\n", devinfo.id);
- fprintf(stdout, " Dprotocols: %08x\n", devinfo.Dprotocols);
- fprintf(stdout, " Bprotocols: %08x\n", devinfo.Bprotocols);
- fprintf(stdout, " protocol: %d\n", devinfo.protocol);
- fprintf(stdout, " nrbchan: %d\n", devinfo.nrbchan);
- fprintf(stdout, " name: %s\n", devinfo.name);
-#endif
-
- if (!(devinfo.Dprotocols & (1 << ISDN_P_NT_E1))) {
- fprintf(stderr, "error: card is not of type E1 (NT-mode)\n");
- return -EINVAL;
- }
-
- if (devinfo.nrbchan != 30) {
- fprintf(stderr, "error: E1 card has no 30 B-channels\n");
- return -EINVAL;
- }
-
- ret = mi_e1_setup(line, release_l2);
- if (ret)
- return ret;
-
- return e1inp_line_register(line);
-}
diff --git a/src/ipaccess-config.c b/src/ipaccess-config.c
deleted file mode 100644
index b74e46e89..000000000
--- a/src/ipaccess-config.c
+++ /dev/null
@@ -1,198 +0,0 @@
-/* ip.access nanoBTS configuration tool */
-
-/* (C) 2009 by Harald Welte <laforge@gnumonks.org>
- * All Rights Reserved
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- */
-
-#include <unistd.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <getopt.h>
-#include <sys/types.h>
-
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-
-
-#include <openbsc/select.h>
-#include <openbsc/timer.h>
-#include <openbsc/ipaccess.h>
-#include <openbsc/gsm_data.h>
-#include <openbsc/e1_input.h>
-#include <openbsc/abis_nm.h>
-
-static struct gsm_network *gsmnet;
-
-static int restart;
-static char *prim_oml_ip;
-static char *unit_id;
-
-/*
-static u_int8_t prim_oml_attr[] = { 0x95, 0x00, 7, 0x88, 192, 168, 100, 11, 0x00, 0x00 };
-static u_int8_t unit_id_attr[] = { 0x91, 0x00, 9, '2', '3', '4', '2', '/' , '0', '/', '0', 0x00 };
-*/
-
-static void bootstrap_om(struct gsm_bts *bts)
-{
- int len;
- static u_int8_t buf[1024];
-
- printf("OML link established\n");
-
- if (unit_id) {
- len = strlen(unit_id);
- if (len > sizeof(buf)-10)
- return;
- buf[0] = NM_ATT_IPACC_UNIT_ID;
- buf[1] = (len+1) >> 8;
- buf[2] = (len+1) & 0xff;
- memcpy(buf+3, unit_id, len);
- buf[3+len] = 0;
- printf("setting Unit ID to '%s'\n", unit_id);
- abis_nm_ipaccess_set_nvattr(bts, buf, 3+len+1);
- }
- if (prim_oml_ip) {
- struct in_addr ia;
- u_int8_t *cur = buf;
-
- if (!inet_aton(prim_oml_ip, &ia)) {
- fprintf(stderr, "invalid IP address: %s\n",
- prim_oml_ip);
- return;
- }
-
- /* 0x88 + IP + port */
- len = 1 + sizeof(ia) + 2;
-
- *cur++ = NM_ATT_IPACC_PRIM_OML_IP;
- *cur++ = (len) >> 8;
- *cur++ = (len) & 0xff;
- *cur++ = 0x88;
- memcpy(cur, &ia, sizeof(ia));
- cur += sizeof(ia);
- *cur++ = 0;
- *cur++ = 0;
- printf("setting primary OML link IP to '%s'\n", inet_ntoa(ia));
- abis_nm_ipaccess_set_nvattr(bts, buf, 3+len);
- }
-
- if (restart) {
- printf("restarting BTS\n");
- abis_nm_ipaccess_restart(bts);
- }
-}
-
-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:
- /* FIXME */
- 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;
- }
-}
-
-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)
-{
- return 0;
-}
-
-int main(int argc, char **argv)
-{
- struct gsm_bts *bts;
- struct sockaddr_in sin;
- int rc, option_index = 0;
-
- printf("ipaccess-config (C) 2009 by Harald Welte\n");
- printf("This is FREE SOFTWARE with ABSOLUTELY NO WARRANTY\n\n");
-
- while (1) {
- int c;
- static struct option long_options[] = {
- { "unit-id", 1, 0, 'u' },
- { "oml-ip", 1, 0, 'o' },
- { "restart", 0, 0, 'r' },
- };
-
- c = getopt_long(argc, argv, "u:o:r", long_options,
- &option_index);
-
- if (c == -1)
- break;
-
- switch (c) {
- case 'u':
- unit_id = optarg;
- break;
- case 'o':
- prim_oml_ip = optarg;
- break;
- case 'r':
- restart = 1;
- break;
- }
- };
-
- if (optind >= argc) {
- fprintf(stderr, "you have to specify the IP address of the BTS\n");
- exit(2);
- }
-
- gsmnet = gsm_network_init( 1, GSM_BTS_TYPE_NANOBTS_900, 1, 1);
- if (!gsmnet)
- exit(1);
-
- bts = &gsmnet->bts[0];
-
- printf("Trying to connect to ip.access BTS ...\n");
-
- memset(&sin, 0, sizeof(sin));
- sin.sin_family = AF_INET;
- inet_aton(argv[optind], &sin.sin_addr);
- rc = ia_config_connect(bts, &sin);
- if (rc < 0) {
- perror("Error connecting to the BTS");
- exit(1);
- }
-
- while (1) {
- rc = bsc_select_main(0);
- if (rc < 0)
- exit(3);
- }
-
- exit(0);
-}
-
diff --git a/src/ipaccess-find.c b/src/ipaccess-find.c
deleted file mode 100644
index b3e9814a9..000000000
--- a/src/ipaccess-find.c
+++ /dev/null
@@ -1,180 +0,0 @@
-
-#include <unistd.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-
-
-#include <openbsc/select.h>
-#include <openbsc/timer.h>
-#include <openbsc/ipaccess.h>
-#include <openbsc/gsm_data.h>
-
-static const char *idtag_names[] = {
- [IPAC_IDTAG_SERNR] = "Serial Number",
- [IPAC_IDTAG_UNITNAME] = "Unit Name",
- [IPAC_IDTAG_LOCATION1] = "Location 1",
- [IPAC_IDTAG_LOCATION2] = "Location 2",
- [IPAC_IDTAG_EQUIPVERS] = "Equipment Version",
- [IPAC_IDTAG_SWVERSION] = "Software Version",
- [IPAC_IDTAG_IPADDR] = "IP Address",
- [IPAC_IDTAG_MACADDR] = "MAC Address",
- [IPAC_IDTAG_UNIT] = "Unit ID",
-};
-
-static const char *ipac_idtag_name(int tag)
-{
- if (tag >= ARRAY_SIZE(idtag_names))
- return "unknown";
-
- return idtag_names[tag];
-}
-
-static int udp_sock(void)
-{
- int fd, rc, bc = 1;
- struct sockaddr_in sa;
-
- fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
- if (fd < 0)
- return fd;
-
- sa.sin_family = AF_INET;
- sa.sin_port = htons(3006);
- sa.sin_addr.s_addr = INADDR_ANY;
- inet_aton("192.168.100.11", &sa.sin_addr);
-
- rc = bind(fd, (struct sockaddr *)&sa, sizeof(sa));
- if (rc < 0)
- goto err;
-
- rc = setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &bc, sizeof(bc));
- if (rc < 0)
- goto err;
-
-#if 0
- rc = connect(fd, (struct sockaddr *)&sa, sizeof(sa));
- if (rc < 0)
- goto err;
-#endif
- return fd;
-
-err:
- close(fd);
- return rc;
-}
-
-const unsigned char find_pkt[] = { 0x00, 0x0b+8, IPAC_PROTO_IPACCESS, 0x00,
- IPAC_MSGT_ID_GET,
- 0x01, IPAC_IDTAG_MACADDR,
- 0x01, IPAC_IDTAG_IPADDR,
- 0x01, IPAC_IDTAG_UNIT,
- 0x01, IPAC_IDTAG_LOCATION1,
- 0x01, IPAC_IDTAG_LOCATION2,
- 0x01, IPAC_IDTAG_EQUIPVERS,
- 0x01, IPAC_IDTAG_SWVERSION,
- 0x01, IPAC_IDTAG_UNITNAME,
- 0x01, IPAC_IDTAG_SERNR,
- };
-
-
-static int bcast_find(int fd)
-{
- struct sockaddr_in sa;
-
- sa.sin_family = AF_INET;
- sa.sin_port = htons(3006);
- inet_aton("255.255.255.255", &sa.sin_addr);
-
- return sendto(fd, find_pkt, sizeof(find_pkt), 0, (struct sockaddr *) &sa, sizeof(sa));
-}
-
-static int parse_response(unsigned char *buf, int len)
-{
- u_int8_t t_len;
- u_int8_t t_tag;
- u_int8_t *cur = buf;
-
- while (cur < buf + len) {
- t_len = *cur++;
- t_tag = *cur++;
-
- printf("%s='%s' ", ipac_idtag_name(t_tag), cur);
-
- cur += t_len;
- }
- printf("\n");
- return 0;
-}
-
-static int read_response(int fd)
-{
- unsigned char buf[255];
- struct sockaddr_in sa;
- int len;
- socklen_t sa_len = sizeof(sa);
-
- len = recvfrom(fd, buf, sizeof(buf), 0, (struct sockaddr *)&sa, &sa_len);
- if (len < 0)
- return len;
-
- return parse_response(buf+6, len-6);
-}
-
-static int bfd_cb(struct bsc_fd *bfd, unsigned int flags)
-{
- if (flags & BSC_FD_READ)
- return read_response(bfd->fd);
- if (flags & BSC_FD_WRITE) {
- bfd->when &= ~BSC_FD_WRITE;
- return bcast_find(bfd->fd);
- }
- return 0;
-}
-
-static struct timer_list timer;
-
-static void timer_cb(void *_data)
-{
- struct bsc_fd *bfd = _data;
-
- bfd->when |= BSC_FD_WRITE;
-
- bsc_schedule_timer(&timer, 5, 0);
-}
-
-int main(int argc, char **argv)
-{
- struct bsc_fd bfd;
- int rc;
-
- printf("ipaccess-find (C) 2009 by Harald Welte\n");
- printf("This is FREE SOFTWARE with ABSOLUTELY NO WARRANTY\n\n");
-
- bfd.cb = bfd_cb;
- bfd.when = BSC_FD_READ | BSC_FD_WRITE;
- bfd.fd = udp_sock();
- if (bfd.fd < 0)
- exit(2);
-
- bsc_register_fd(&bfd);
-
- timer.cb = timer_cb;
- timer.data = &bfd;
-
- bsc_schedule_timer(&timer, 5, 0);
-
- printf("Trying to find ip.access BTS by broadcast UDP...\n");
-
- while (1) {
- rc = bsc_select_main(0);
- if (rc < 0)
- exit(3);
- }
-
- exit(0);
-}
-
diff --git a/src/isdnsync.c b/src/isdnsync.c
deleted file mode 100644
index d8819ac6b..000000000
--- a/src/isdnsync.c
+++ /dev/null
@@ -1,192 +0,0 @@
-/* isdnsync.c
- *
- * Author Andreas Eversberg <jolly@eversberg.eu>
- *
- * 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 <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <sys/ioctl.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <sys/socket.h>
-#include "mISDNif.h"
-#define MISDN_OLD_AF_COMPATIBILITY
-#define AF_COMPATIBILITY_FUNC
-#include "compat_af_isdn.h"
-
-int card = 0;
-int sock = -1;
-
-int mISDN_open(void)
-{
- int fd, ret;
- struct mISDN_devinfo devinfo;
- struct sockaddr_mISDN l2addr;
-
- fd = socket(PF_ISDN, SOCK_RAW, ISDN_P_BASE);
- if (fd < 0) {
- fprintf(stderr, "could not open socket (%s)\n", strerror(errno));
- return fd;
- }
- devinfo.id = card;
- ret = ioctl(fd, IMGETDEVINFO, &devinfo);
- if (ret < 0) {
- fprintf(stderr,"could not send IOCTL IMGETCOUNT (%s)\n", strerror(errno));
- close(fd);
- return ret;
- }
- close(fd);
- if (!(devinfo.Dprotocols & (1 << ISDN_P_TE_S0))
- && !(devinfo.Dprotocols & (1 << ISDN_P_TE_E1))) {
- fprintf(stderr,"Interface does not support TE mode (%s)\n", strerror(errno));
- close(fd);
- return ret;
- }
- fd = socket(PF_ISDN, SOCK_DGRAM, ISDN_P_LAPD_TE);
- if (fd < 0) {
- fprintf(stderr,"could not open ISDN_P_LAPD_TE socket (%s)\n", strerror(errno));
- return fd;
- }
- l2addr.family = AF_ISDN;
- l2addr.dev = card;
- l2addr.channel = 0;
- l2addr.sapi = 0;
- l2addr.tei = 0;
- ret = bind(fd, (struct sockaddr *)&l2addr, sizeof(l2addr));
- if (ret < 0) {
- fprintf(stderr,"could not bind socket for card %d (%s)\n", card, strerror(errno));
- close(fd);
- return ret;
- }
- sock = fd;
-
- return sock;
-}
-
-
-void mISDN_handle(void)
-{
- int ret;
- fd_set rfd;
- struct timeval tv;
- struct sockaddr_mISDN addr;
- socklen_t alen;
- unsigned char buffer[2048];
- struct mISDNhead *hh = (struct mISDNhead *)buffer;
- int l1 = 0, l2 = 0, tei = 0;
-
- while(1) {
-again:
- FD_ZERO(&rfd);
- FD_SET(sock, &rfd);
- tv.tv_sec = 2;
- tv.tv_usec = 0;
- ret = select(sock+1, &rfd, NULL, NULL, &tv);
- if (ret < 0) {
- if (errno == EINTR)
- continue;
- fprintf(stderr, "%s aborted: %s\n", __FUNCTION__, strerror(errno));
- break;
- }
- if (FD_ISSET(sock, &rfd)) {
- alen = sizeof(addr);
- ret = recvfrom(sock, buffer, sizeof(buffer), 0, (struct sockaddr *) &addr, &alen);
- if (ret < 0) {
- fprintf(stderr, "%s read socket error %s\n", __FUNCTION__, strerror(errno));
- } else if (ret < MISDN_HEADER_LEN) {
- fprintf(stderr, "%s read socket shor frame\n", __FUNCTION__);
- } else {
- switch(hh->prim) {
- case MPH_ACTIVATE_IND:
- case PH_ACTIVATE_IND:
- if (!l1) {
- printf("PH_ACTIVATE\n");
- printf("*** Sync available from interface :-)\n");
- l1 = 1;
- }
- goto again;
- break;
- case MPH_DEACTIVATE_IND:
- case PH_DEACTIVATE_IND:
- if (l1) {
- printf("PH_DEACTIVATE\n");
- printf("*** Lost sync on interface :-(\n");
- l1 = 0;
- }
- goto again;
- break;
- case DL_ESTABLISH_IND:
- case DL_ESTABLISH_CNF:
- printf("DL_ESTABLISH\n");
- l2 = 1;
- goto again;
- break;
- case DL_RELEASE_IND:
- case DL_RELEASE_CNF:
- printf("DL_RELEASE\n");
- l2 = 0;
- goto again;
- break;
- case DL_INFORMATION_IND:
- printf("DL_INFORMATION (tei %d sapi %d)\n", addr.tei, addr.sapi);
- tei = 1;
- break;
- default:
-// printf("prim %x\n", hh->prim);
- goto again;
- }
- }
- }
- if (tei && !l2) {
- hh->prim = DL_ESTABLISH_REQ;
- printf("-> activating layer 2\n");
- sendto(sock, buffer, MISDN_HEADER_LEN, 0, (struct sockaddr *) &addr, alen);
- }
- }
-}
-
-int main(int argc, char *argv[])
-{
- int ret;
-
- if (argc <= 1)
- {
- printf("Usage: %s <card>\n\n", argv[0]);
- printf("Opens given card number in TE-mode PTP and tries to keep layer 2 established.\n");
- printf("This keeps layer 1 activated to retrieve a steady sync signal from network.\n");
- return(0);
- }
-
- card = atoi(argv[1]);
-
- init_af_isdn();
-
- if ((ret = mISDN_open() < 0))
- return(ret);
-
- mISDN_handle();
-
- close(sock);
-
- return 0;
-}
diff --git a/src/msgb.c b/src/msgb.c
deleted file mode 100644
index ce390e84a..000000000
--- a/src/msgb.c
+++ /dev/null
@@ -1,70 +0,0 @@
-/* (C) 2008 by Harald Welte <laforge@gnumonks.org>
- * All Rights Reserved
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- */
-
-
-#include <unistd.h>
-#include <string.h>
-#include <stdlib.h>
-#include <sys/types.h>
-
-#include <openbsc/msgb.h>
-
-struct msgb *msgb_alloc(u_int16_t size)
-{
- struct msgb *msg = malloc(sizeof(*msg) + size);
-
- if (!msg)
- return NULL;
- memset(msg, 0, sizeof(*msg)+size);
-
- msg->data_len = size;
- msg->len = 0;
- msg->data = msg->_data;
-
- msg->head = msg->data;
- msg->data = msg->data;
- /* reset tail pointer */
- msg->tail = msg->data;
- //msg->end = msg->tail + size;
-
- return msg;
-}
-
-void msgb_free(struct msgb *m)
-{
- free(m);
-}
-
-void msgb_enqueue(struct llist_head *queue, struct msgb *msg)
-{
- llist_add_tail(&msg->list, queue);
-}
-
-struct msgb *msgb_dequeue(struct llist_head *queue)
-{
- struct llist_head *lh;
-
- if (llist_empty(queue))
- return NULL;
-
- lh = queue->next;
- llist_del(lh);
-
- return llist_entry(lh, struct msgb, list);
-}
diff --git a/src/paging.c b/src/paging.c
deleted file mode 100644
index d777d6642..000000000
--- a/src/paging.c
+++ /dev/null
@@ -1,262 +0,0 @@
-/* Paging helper and manager.... */
-/* (C) 2009 by Holger Hans Peter Freyther <zecke@selfish.org>
- * All Rights Reserved
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- */
-
-/*
- * Relevant specs:
- * 12.21:
- * - 9.4.12 for CCCH Local Threshold
- *
- * 05.58:
- * - 8.5.2 CCCH Load indication
- * - 9.3.15 Paging Load
- *
- * Approach:
- * - Send paging command to subscriber
- * - On Channel Request we will remember the reason
- * - After the ACK we will request the identity
- * - Then we will send assign the gsm_subscriber and
- * - and call a callback
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <assert.h>
-
-#include <openbsc/paging.h>
-#include <openbsc/debug.h>
-#include <openbsc/signal.h>
-#include <openbsc/abis_rsl.h>
-#include <openbsc/gsm_data.h>
-
-#define PAGING_TIMEOUT 1, 75000
-#define MAX_PAGING_REQUEST 750
-
-static unsigned int calculate_group(struct gsm_bts *bts, struct gsm_subscriber *subscr)
-{
- int ccch_conf;
- int bs_cc_chans;
- int blocks;
- unsigned int group;
-
- ccch_conf = bts->chan_desc.ccch_conf;
- bs_cc_chans = rsl_ccch_conf_to_bs_cc_chans(ccch_conf);
- /* code word + 2, as 2 channels equals 0x0 */
- blocks = rsl_number_of_paging_subchannels(bts);
- group = get_paging_group(str_to_imsi(subscr->imsi),
- bs_cc_chans, blocks);
- return group;
-}
-
-/*
- * Kill one paging request update the internal list...
- */
-static void paging_remove_request(struct gsm_bts_paging_state *paging_bts,
- struct gsm_paging_request *to_be_deleted)
-{
- /* Update the last_request if that is necessary */
- if (to_be_deleted == paging_bts->last_request) {
- paging_bts->last_request =
- (struct gsm_paging_request *)paging_bts->last_request->entry.next;
- if (&to_be_deleted->entry == &paging_bts->pending_requests)
- paging_bts->last_request = NULL;
- }
-
- bsc_del_timer(&to_be_deleted->T3113);
- llist_del(&to_be_deleted->entry);
- subscr_put(to_be_deleted->subscr);
- free(to_be_deleted);
-}
-
-static void page_ms(struct gsm_paging_request *request)
-{
- u_int8_t mi[128];
- unsigned long int tmsi;
- unsigned int mi_len;
- unsigned int page_group;
-
- DEBUGP(DPAG, "Going to send paging commands: '%s'\n",
- request->subscr->imsi);
-
- page_group = calculate_group(request->bts, request->subscr);
- tmsi = strtoul(request->subscr->tmsi, NULL, 10);
- mi_len = generate_mid_from_tmsi(mi, tmsi);
- rsl_paging_cmd(request->bts, page_group, mi_len, mi,
- request->chan_type);
-}
-
-static void paging_move_to_next(struct gsm_bts_paging_state *paging_bts)
-{
- paging_bts->last_request =
- (struct gsm_paging_request *)paging_bts->last_request->entry.next;
- if (&paging_bts->last_request->entry == &paging_bts->pending_requests)
- paging_bts->last_request = NULL;
-}
-
-/*
- * This is kicked by the periodic PAGING LOAD Indicator
- * coming from abis_rsl.c
- *
- * We attempt to iterate once over the list of items but
- * only upto available_slots.
- */
-static void paging_handle_pending_requests(struct gsm_bts_paging_state *paging_bts)
-{
- struct gsm_paging_request *initial_request = NULL;
- struct gsm_paging_request *current_request = NULL;
-
- /*
- * Determine if the pending_requests list is empty and
- * return then.
- */
- if (llist_empty(&paging_bts->pending_requests)) {
- paging_bts->last_request = NULL;
- /* since the list is empty, no need to reschedule the timer */
- return;
- }
-
- if (!paging_bts->last_request)
- paging_bts->last_request =
- (struct gsm_paging_request *)paging_bts->pending_requests.next;
-
- assert(paging_bts->last_request);
- initial_request = paging_bts->last_request;
- current_request = initial_request;
-
- do {
- /* handle the paging request now */
- page_ms(current_request);
- paging_bts->available_slots--;
-
- /*
- * move to the next item. We might wrap around
- * this means last_request will be NULL and we just
- * call paging_page_to_next again. It it guranteed
- * that the list is not empty.
- */
- paging_move_to_next(paging_bts);
- if (!paging_bts->last_request)
- paging_bts->last_request =
- (struct gsm_paging_request *)paging_bts->pending_requests.next;
- current_request = paging_bts->last_request;
- } while (paging_bts->available_slots > 0
- && initial_request != current_request);
-
- bsc_schedule_timer(&paging_bts->work_timer, 1, 0);
-}
-
-static void paging_worker(void *data)
-{
- struct gsm_bts_paging_state *paging_bts = data;
-
- paging_handle_pending_requests(paging_bts);
-}
-
-void paging_init(struct gsm_bts *bts)
-{
- bts->paging.bts = bts;
- INIT_LLIST_HEAD(&bts->paging.pending_requests);
- bts->paging.work_timer.cb = paging_worker;
- bts->paging.work_timer.data = &bts->paging;
-
- /* Large number, until we get a proper message */
- bts->paging.available_slots = 100;
-}
-
-static int paging_pending_request(struct gsm_bts_paging_state *bts,
- struct gsm_subscriber *subscr) {
- struct gsm_paging_request *req;
-
- llist_for_each_entry(req, &bts->pending_requests, entry) {
- if (subscr == req->subscr)
- return 1;
- }
-
- return 0;
-}
-
-static void paging_T3113_expired(void *data)
-{
- struct gsm_paging_request *req = (struct gsm_paging_request *)data;
- struct paging_signal_data sig_data;
-
- DEBUGP(DPAG, "T3113 expired for request %p (%s)\n",
- req, req->subscr->imsi);
-
- sig_data.subscr = req->subscr,
- sig_data.bts = req->bts,
- sig_data.lchan = NULL,
-
- dispatch_signal(SS_PAGING, S_PAGING_COMPLETED, &sig_data);
- if (req->cbfn)
- req->cbfn(GSM_HOOK_RR_PAGING, GSM_PAGING_EXPIRED, NULL, NULL,
- req->cbfn_param);
- paging_remove_request(&req->bts->paging, req);
-}
-
-void paging_request(struct gsm_bts *bts, struct gsm_subscriber *subscr,
- int type, gsm_cbfn *cbfn, void *data)
-{
- struct gsm_bts_paging_state *bts_entry = &bts->paging;
- struct gsm_paging_request *req;
-
- if (paging_pending_request(bts_entry, subscr)) {
- DEBUGP(DPAG, "Paging request already pending\n");
- return;
- }
-
- req = (struct gsm_paging_request *)malloc(sizeof(*req));
- memset(req, 0, sizeof(*req));
- req->subscr = subscr_get(subscr);
- req->bts = bts;
- req->chan_type = type;
- req->cbfn = cbfn;
- req->cbfn_param = data;
- req->T3113.cb = paging_T3113_expired;
- req->T3113.data = req;
- bsc_schedule_timer(&req->T3113, T3113_VALUE);
- llist_add_tail(&req->entry, &bts_entry->pending_requests);
-
- if (!bsc_timer_pending(&bts_entry->work_timer))
- bsc_schedule_timer(&bts_entry->work_timer, 1, 0);
-}
-
-/* we consciously ignore the type of the request here */
-void paging_request_stop(struct gsm_bts *bts, struct gsm_subscriber *subscr,
- struct gsm_lchan *lchan)
-{
- struct gsm_bts_paging_state *bts_entry = &bts->paging;
- struct gsm_paging_request *req, *req2;
-
- llist_for_each_entry_safe(req, req2, &bts_entry->pending_requests,
- entry) {
- if (req->subscr == subscr) {
- if (req->cbfn)
- req->cbfn(GSM_HOOK_RR_PAGING, GSM_PAGING_SUCCEEDED,
- NULL, lchan, req->cbfn_param);
- paging_remove_request(&bts->paging, req);
- break;
- }
- }
-}
-
-void paging_update_buffer_space(struct gsm_bts *bts, u_int16_t free_slots)
-{
- bts->paging.available_slots = free_slots;
-}
diff --git a/src/rs232.c b/src/rs232.c
deleted file mode 100644
index 2a64de5ef..000000000
--- a/src/rs232.c
+++ /dev/null
@@ -1,249 +0,0 @@
-/* OpenBSC BS-11 T-Link interface using POSIX serial port */
-
-/* (C) 2008-2009 by Harald Welte <laforge@gnumonks.org>
- *
- * All Rights Reserved
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- */
-
-#include <unistd.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <errno.h>
-#include <string.h>
-#include <termios.h>
-#include <fcntl.h>
-
-#include <openbsc/select.h>
-#include <openbsc/msgb.h>
-#include <openbsc/debug.h>
-#include <openbsc/gsm_data.h>
-#include <openbsc/rs232.h>
-
-/* adaption layer from GSM 08.59 + 12.21 to RS232 */
-
-struct serial_handle {
- struct bsc_fd fd;
- struct llist_head tx_queue;
-
- struct msgb *rx_msg;
- unsigned int rxmsg_bytes_missing;
-
- unsigned int delay_ms;
- struct gsm_bts *bts;
-};
-
-/* FIXME: this needs to go */
-static struct serial_handle _ser_handle, *ser_handle = &_ser_handle;
-
-#define LAPD_HDR_LEN 10
-
-static int handle_ser_write(struct bsc_fd *bfd);
-
-/* callback from abis_nm */
-int _abis_nm_sendmsg(struct msgb *msg)
-{
- struct serial_handle *sh = ser_handle;
- u_int8_t *lapd;
- unsigned int len;
-
- msg->l2h = msg->data;
-
- /* prepend LAPD header */
- lapd = msgb_push(msg, LAPD_HDR_LEN);
-
- len = msg->len - 2;
-
- lapd[0] = (len >> 8) & 0xff;
- lapd[1] = len & 0xff; /* length of bytes startign at lapd[2] */
- lapd[2] = 0x00;
- lapd[3] = 0x07;
- lapd[4] = 0x01;
- lapd[5] = 0x3e;
- lapd[6] = 0x00;
- lapd[7] = 0x00;
- lapd[8] = msg->len - 10; /* length of bytes starting at lapd[10] */
- lapd[9] = lapd[8] ^ 0x38;
-
- msgb_enqueue(&sh->tx_queue, msg);
- sh->fd.when |= BSC_FD_WRITE;
-
- /* we try to immediately send */
- handle_ser_write(&sh->fd);
-
- return 0;
-}
-
-/* select.c callback in case we can write to the RS232 */
-static int handle_ser_write(struct bsc_fd *bfd)
-{
- struct serial_handle *sh = bfd->data;
- struct msgb *msg;
- int written;
-
- msg = msgb_dequeue(&sh->tx_queue);
- if (!msg) {
- bfd->when &= ~BSC_FD_WRITE;
- return 0;
- }
-
- DEBUGP(DMI, "RS232 TX: %s\n", hexdump(msg->data, msg->len));
-
- /* send over serial line */
- written = write(bfd->fd, msg->data, msg->len);
- if (written < msg->len) {
- perror("short write:");
- msgb_free(msg);
- return -1;
- }
-
- msgb_free(msg);
- usleep(sh->delay_ms*1000);
-
- return 0;
-}
-
-#define SERIAL_ALLOC_SIZE 300
-
-/* select.c callback in case we can read from the RS232 */
-static int handle_ser_read(struct bsc_fd *bfd)
-{
- struct serial_handle *sh = bfd->data;
- struct msgb *msg;
- int rc = 0;
-
- if (!sh->rx_msg) {
- sh->rx_msg = msgb_alloc(SERIAL_ALLOC_SIZE);
- sh->rx_msg->l2h = NULL;
- sh->rx_msg->trx = sh->bts->c0;
- }
- msg = sh->rx_msg;
-
- /* first read two byes to obtain length */
- if (msg->len < 2) {
- rc = read(sh->fd.fd, msg->tail, 2 - msg->len);
- if (rc < 0) {
- perror("ERROR reading from serial port");
- msgb_free(msg);
- return rc;
- }
- msgb_put(msg, rc);
-
- if (msg->len >= 2) {
- /* parse LAPD payload length */
- if (msg->data[0] != 0)
- fprintf(stderr, "Suspicious header byte 0: 0x%02x\n",
- msg->data[0]);
-
- sh->rxmsg_bytes_missing = msg->data[0] << 8;
- sh->rxmsg_bytes_missing += msg->data[1];
-
- if (sh->rxmsg_bytes_missing < LAPD_HDR_LEN -2)
- fprintf(stderr, "Invalid length in hdr: %u\n",
- sh->rxmsg_bytes_missing);
- }
- } else {
- /* try to read as many of the missing bytes as are available */
- rc = read(sh->fd.fd, msg->tail, sh->rxmsg_bytes_missing);
- if (rc < 0) {
- perror("ERROR reading from serial port");
- msgb_free(msg);
- return rc;
- }
- msgb_put(msg, rc);
- sh->rxmsg_bytes_missing -= rc;
-
- if (sh->rxmsg_bytes_missing == 0) {
- /* we have one complete message now */
- sh->rx_msg = NULL;
-
- if (msg->len > LAPD_HDR_LEN)
- msg->l2h = msg->data + LAPD_HDR_LEN;
-
- DEBUGP(DMI, "RS232 RX: %s\n", hexdump(msg->data, msg->len));
- rc = handle_serial_msg(msg);
- }
- }
-
- return rc;
-}
-
-/* select.c callback */
-static int serial_fd_cb(struct bsc_fd *bfd, unsigned int what)
-{
- int rc = 0;
-
- if (what & BSC_FD_READ)
- rc = handle_ser_read(bfd);
-
- if (rc < 0)
- return rc;
-
- if (what & BSC_FD_WRITE)
- rc = handle_ser_write(bfd);
-
- return rc;
-}
-
-int rs232_setup(const char *serial_port, unsigned int delay_ms,
- struct gsm_bts *bts)
-{
- int rc, serial_fd;
- struct termios tio;
-
- serial_fd = open(serial_port, O_RDWR);
- if (serial_fd < 0) {
- perror("cannot open serial port:");
- return serial_fd;
- }
-
- /* set baudrate */
- rc = tcgetattr(serial_fd, &tio);
- if (rc < 0) {
- perror("tcgetattr()");
- return rc;
- }
- cfsetispeed(&tio, B19200);
- cfsetospeed(&tio, B19200);
- tio.c_cflag |= (CREAD | CLOCAL | CS8);
- tio.c_cflag &= ~(PARENB | CSTOPB | CSIZE | CRTSCTS);
- tio.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
- tio.c_iflag |= (INPCK | ISTRIP);
- tio.c_iflag &= ~(ISTRIP | IXON | IXOFF | IGNBRK | INLCR | ICRNL | IGNCR);
- tio.c_oflag &= ~(OPOST);
- rc = tcsetattr(serial_fd, TCSADRAIN, &tio);
- if (rc < 0) {
- perror("tcsetattr()");
- return rc;
- }
-
- INIT_LLIST_HEAD(&ser_handle->tx_queue);
- ser_handle->fd.fd = serial_fd;
- ser_handle->fd.when = BSC_FD_READ;
- ser_handle->fd.cb = serial_fd_cb;
- ser_handle->fd.data = ser_handle;
- ser_handle->delay_ms = delay_ms;
- ser_handle->bts = bts;
- rc = bsc_register_fd(&ser_handle->fd);
- if (rc < 0) {
- fprintf(stderr, "could not register FD: %s\n",
- strerror(rc));
- return rc;
- }
-
- return 0;
-}
diff --git a/src/select.c b/src/select.c
deleted file mode 100644
index 11b7e6b49..000000000
--- a/src/select.c
+++ /dev/null
@@ -1,107 +0,0 @@
-/* select filedescriptor handling, taken from:
- * userspace logging daemon for the iptables ULOG target
- * of the linux 2.4 netfilter subsystem.
- *
- * (C) 2000-2009 by Harald Welte <laforge@gnumonks.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2
- * as published by the Free Software Foundation
- *
- * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#include <fcntl.h>
-#include <openbsc/select.h>
-#include <openbsc/linuxlist.h>
-#include <openbsc/timer.h>
-
-static int maxfd = 0;
-static LLIST_HEAD(bsc_fds);
-
-int bsc_register_fd(struct bsc_fd *fd)
-{
- int flags;
-
- /* make FD nonblocking */
- flags = fcntl(fd->fd, F_GETFL);
- if (flags < 0)
- return flags;
- flags |= O_NONBLOCK;
- flags = fcntl(fd->fd, F_SETFL, flags);
- if (flags < 0)
- return flags;
-
- /* Register FD */
- if (fd->fd > maxfd)
- maxfd = fd->fd;
-
- llist_add_tail(&fd->list, &bsc_fds);
-
- return 0;
-}
-
-void bsc_unregister_fd(struct bsc_fd *fd)
-{
- llist_del(&fd->list);
-}
-
-int bsc_select_main(int polling)
-{
- struct bsc_fd *ufd, *tmp;
- fd_set readset, writeset, exceptset;
- int work = 0, rc;
- struct timeval no_time = {0, 0};
-
- FD_ZERO(&readset);
- FD_ZERO(&writeset);
- FD_ZERO(&exceptset);
-
- /* prepare read and write fdsets */
- llist_for_each_entry(ufd, &bsc_fds, list) {
- if (ufd->when & BSC_FD_READ)
- FD_SET(ufd->fd, &readset);
-
- if (ufd->when & BSC_FD_WRITE)
- FD_SET(ufd->fd, &writeset);
-
- if (ufd->when & BSC_FD_EXCEPT)
- FD_SET(ufd->fd, &exceptset);
- }
-
- if (!polling)
- bsc_prepare_timers();
- rc = select(maxfd+1, &readset, &writeset, &exceptset, polling ? &no_time : bsc_nearest_timer());
- if (rc < 0)
- return 0;
-
- /* fire timers */
- bsc_update_timers();
-
- /* call registered callback functions */
- llist_for_each_entry_safe(ufd, tmp, &bsc_fds, list) {
- int flags = 0;
-
- if (FD_ISSET(ufd->fd, &readset))
- flags |= BSC_FD_READ;
-
- if (FD_ISSET(ufd->fd, &writeset))
- flags |= BSC_FD_WRITE;
-
- if (FD_ISSET(ufd->fd, &exceptset))
- flags |= BSC_FD_EXCEPT;
-
- if (flags) {
- work = 1;
- ufd->cb(ufd, flags);
- }
- }
- return work;
-}
diff --git a/src/signal.c b/src/signal.c
deleted file mode 100644
index 4227c6dc1..000000000
--- a/src/signal.c
+++ /dev/null
@@ -1,80 +0,0 @@
-/* Generic signalling/notification infrastructure */
-/* (C) 2009 by Holger Hans Peter Freyther <zecke@selfish.org>
- * All Rights Reserved
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- */
-
-#include <openbsc/signal.h>
-#include <stdlib.h>
-#include <string.h>
-
-
-static LLIST_HEAD(signal_handler_list);
-
-struct signal_handler {
- struct llist_head entry;
- unsigned int subsys;
- signal_cbfn *cbfn;
- void *data;
-};
-
-
-int register_signal_handler(unsigned int subsys, signal_cbfn *cbfn, void *data)
-{
- struct signal_handler *sig_data = malloc(sizeof(*sig_data));
-
- if (!sig_data)
- return -ENOMEM;
-
- memset(sig_data, 0, sizeof(*sig_data));
-
- sig_data->subsys = subsys;
- sig_data->data = data;
- sig_data->cbfn = cbfn;
-
- /* FIXME: check if we already have a handler for this subsys/cbfn/data */
-
- llist_add_tail(&sig_data->entry, &signal_handler_list);
-
- return 0;
-}
-
-void unregister_signal_handler(unsigned int subsys, signal_cbfn *cbfn, void *data)
-{
- struct signal_handler *handler;
-
- llist_for_each_entry(handler, &signal_handler_list, entry) {
- if (handler->cbfn == cbfn && handler->data == data
- && subsys == handler->subsys) {
- llist_del(&handler->entry);
- free(handler);
- break;
- }
- }
-}
-
-
-void dispatch_signal(unsigned int subsys, unsigned int signal, void *signal_data)
-{
- struct signal_handler *handler;
-
- llist_for_each_entry(handler, &signal_handler_list, entry) {
- if (handler->subsys != subsys)
- continue;
- (*handler->cbfn)(subsys, signal, handler->data, signal_data);
- }
-}
diff --git a/src/subchan_demux.c b/src/subchan_demux.c
deleted file mode 100644
index c662bcd0e..000000000
--- a/src/subchan_demux.c
+++ /dev/null
@@ -1,319 +0,0 @@
-/* A E1 sub-channel (de)multiplexer with TRAU frame sync */
-
-/* (C) 2009 by Harald Welte <laforge@gnumonks.org>
- * All Rights Reserved
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- */
-
-#include <unistd.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <errno.h>
-
-#include <openbsc/subchan_demux.h>
-#include <openbsc/trau_frame.h>
-#include <openbsc/debug.h>
-
-static inline void append_bit(struct demux_subch *sch, u_int8_t bit)
-{
- sch->out_bitbuf[sch->out_idx++] = bit;
-}
-
-#define SYNC_HDR_BITS 16
-static const u_int8_t nullbytes[SYNC_HDR_BITS];
-
-/* check if we have just completed the 16 bit zero sync header,
- * in accordance with GSM TS 08.60 Chapter 4.8.1 */
-static int sync_hdr_complete(struct demux_subch *sch, u_int8_t bit)
-{
- if (bit == 0)
- sch->consecutive_zeros++;
- else
- sch->consecutive_zeros = 0;
-
- if (sch->consecutive_zeros >= SYNC_HDR_BITS) {
- sch->consecutive_zeros = 0;
- return 1;
- }
-
- return 0;
-}
-
-/* resynchronize to current location */
-static void resync_to_here(struct demux_subch *sch)
-{
- memset(sch->out_bitbuf, 0, SYNC_HDR_BITS);
-
- /* set index in a way that we can continue receiving bits after
- * the end of the SYNC header */
- sch->out_idx = SYNC_HDR_BITS;
- sch->in_sync = 1;
-}
-
-int subch_demux_init(struct subch_demux *dmx)
-{
- int i;
-
- dmx->chan_activ = 0;
- for (i = 0; i < NR_SUBCH; i++) {
- struct demux_subch *sch = &dmx->subch[i];
- sch->out_idx = 0;
- memset(sch->out_bitbuf, 0xff, sizeof(sch->out_bitbuf));
- }
- return 0;
-}
-
-/* input some arbitrary (modulo 4) number of bytes of a 64k E1 channel,
- * split it into the 16k subchannels */
-int subch_demux_in(struct subch_demux *dmx, u_int8_t *data, int len)
-{
- int i, c;
-
- /* we avoid partially filled bytes in outbuf */
- if (len % 4)
- return -EINVAL;
-
- for (i = 0; i < len; i++) {
- u_int8_t inbyte = data[i];
-
- for (c = 0; c < NR_SUBCH; c++) {
- struct demux_subch *sch = &dmx->subch[c];
- u_int8_t inbits;
- u_int8_t bit;
-
- /* ignore inactive subchannels */
- if (!(dmx->chan_activ & (1 << c)))
- continue;
-
- inbits = inbyte >> (c << 1);
-
- /* two bits for each subchannel */
- if (inbits & 0x01)
- bit = 1;
- else
- bit = 0;
- append_bit(sch, bit);
-
- if (sync_hdr_complete(sch, bit))
- resync_to_here(sch);
-
- if (inbits & 0x02)
- bit = 1;
- else
- bit = 0;
- append_bit(sch, bit);
-
- if (sync_hdr_complete(sch, bit))
- resync_to_here(sch);
-
- /* FIXME: verify the first bit in octet 2, 4, 6, ...
- * according to TS 08.60 4.8.1 */
-
- /* once we have reached TRAU_FRAME_BITS, call
- * the TRAU frame handler callback function */
- if (sch->out_idx >= TRAU_FRAME_BITS) {
- if (sch->in_sync) {
- dmx->out_cb(dmx, c, sch->out_bitbuf,
- sch->out_idx, dmx->data);
- sch->in_sync = 0;
- }
- sch->out_idx = 0;
- }
- }
- }
- return i;
-}
-
-int subch_demux_activate(struct subch_demux *dmx, int subch)
-{
- if (subch >= NR_SUBCH)
- return -EINVAL;
-
- dmx->chan_activ |= (1 << subch);
- return 0;
-}
-
-int subch_demux_deactivate(struct subch_demux *dmx, int subch)
-{
- if (subch >= NR_SUBCH)
- return -EINVAL;
-
- dmx->chan_activ &= ~(1 << subch);
- return 0;
-}
-
-/* MULTIPLEXER */
-
-static int alloc_add_idle_frame(struct subch_mux *mx, int sch_nr)
-{
- /* allocate and initialize with idle pattern */
- return subchan_mux_enqueue(mx, sch_nr, trau_idle_frame(),
- TRAU_FRAME_BITS);
-}
-
-/* return the requested number of bits from the specified subchannel */
-static int get_subch_bits(struct subch_mux *mx, int subch,
- u_int8_t *bits, int num_requested)
-{
- struct mux_subch *sch = &mx->subch[subch];
- int num_bits = 0;
-
- while (num_bits < num_requested) {
- struct subch_txq_entry *txe;
- int num_bits_left;
- int num_bits_thistime;
-
- /* make sure we have a valid entry at top of tx queue.
- * if not, add an idle frame */
- if (llist_empty(&sch->tx_queue))
- alloc_add_idle_frame(mx, subch);
-
- if (llist_empty(&sch->tx_queue))
- return -EIO;
-
- txe = llist_entry(sch->tx_queue.next, struct subch_txq_entry, list);
- num_bits_left = txe->bit_len - txe->next_bit;
-
- if (num_bits_left < num_requested)
- num_bits_thistime = num_bits_left;
- else
- num_bits_thistime = num_requested;
-
- /* pull the bits from the txe */
- memcpy(bits + num_bits, txe->bits + txe->next_bit, num_bits_thistime);
- txe->next_bit += num_bits_thistime;
-
- /* free the tx_queue entry if it is fully consumed */
- if (txe->next_bit >= txe->bit_len) {
- llist_del(&txe->list);
- free(txe);
- }
-
- /* increment global number of bits dequeued */
- num_bits += num_bits_thistime;
- }
-
- return num_requested;
-}
-
-/* compact an array of 8 single-bit bytes into one byte of 8 bits */
-static u_int8_t compact_bits(const u_int8_t *bits)
-{
- u_int8_t ret = 0;
- int i;
-
- for (i = 0; i < 8; i++)
- ret |= (bits[i] ? 1 : 0) << i;
-
- return ret;
-}
-
-/* obtain a single output byte from the subchannel muxer */
-static int mux_output_byte(struct subch_mux *mx, u_int8_t *byte)
-{
- u_int8_t bits[8];
- int rc;
-
- /* combine two bits of every subchan */
- rc = get_subch_bits(mx, 0, &bits[0], 2);
- rc = get_subch_bits(mx, 1, &bits[2], 2);
- rc = get_subch_bits(mx, 2, &bits[4], 2);
- rc = get_subch_bits(mx, 3, &bits[6], 2);
-
- *byte = compact_bits(bits);
-
- return rc;
-}
-
-/* Request the output of some muxed bytes from the subchan muxer */
-int subchan_mux_out(struct subch_mux *mx, u_int8_t *data, int len)
-{
- int i;
-
- for (i = 0; i < len; i++) {
- int rc;
- rc = mux_output_byte(mx, &data[i]);
- if (rc < 0)
- break;
- }
- return i;
-}
-
-static int llist_len(struct llist_head *head)
-{
- struct llist_head *entry;
- int i = 0;
-
- llist_for_each(entry, head)
- i++;
-
- return i;
-}
-
-/* evict the 'num_evict' number of oldest entries in the queue */
-static void tx_queue_evict(struct mux_subch *sch, int num_evict)
-{
- struct subch_txq_entry *tqe;
- int i;
-
- for (i = 0; i < num_evict; i++) {
- if (llist_empty(&sch->tx_queue))
- return;
-
- tqe = llist_entry(sch->tx_queue.next, struct subch_txq_entry, list);
- llist_del(&tqe->list);
- free(tqe);
- }
-}
-
-/* enqueue some data into the tx_queue of a given subchannel */
-int subchan_mux_enqueue(struct subch_mux *mx, int s_nr, const u_int8_t *data,
- int len)
-{
- struct mux_subch *sch = &mx->subch[s_nr];
- struct subch_txq_entry *tqe = malloc(sizeof(*tqe) + len);
- int list_len = llist_len(&sch->tx_queue);
-
- if (!tqe)
- return -ENOMEM;
-
- memset(tqe, 0, sizeof(*tqe));
- tqe->bit_len = len;
- memcpy(tqe->bits, data, len);
-
- if (list_len > 2)
- tx_queue_evict(sch, list_len-2);
-
- llist_add_tail(&tqe->list, &sch->tx_queue);
-
- return 0;
-}
-
-/* initialize one subchannel muxer instance */
-int subchan_mux_init(struct subch_mux *mx)
-{
- int i;
-
- memset(mx, 0, sizeof(*mx));
- for (i = 0; i < NR_SUBCH; i++) {
- struct mux_subch *sch = &mx->subch[i];
- INIT_LLIST_HEAD(&sch->tx_queue);
- }
-
- return 0;
-}
diff --git a/src/telnet_interface.c b/src/telnet_interface.c
deleted file mode 100644
index f4ffb529e..000000000
--- a/src/telnet_interface.c
+++ /dev/null
@@ -1,236 +0,0 @@
-/* minimalistic telnet/network interface it might turn into a wire interface */
-/* (C) 2009 by Holger Hans Peter Freyther <zecke@selfish.org>
- * All Rights Reserved
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- */
-
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
-
-#include <openbsc/telnet_interface.h>
-#include <openbsc/gsm_subscriber.h>
-#include <openbsc/chan_alloc.h>
-#include <openbsc/gsm_04_08.h>
-#include <openbsc/gsm_04_11.h>
-#include <openbsc/msgb.h>
-#include <openbsc/abis_rsl.h>
-#include <openbsc/paging.h>
-#include <openbsc/signal.h>
-
-#include <vty/buffer.h>
-
-#define WRITE_CONNECTION(fd, msg...) \
- int ret; \
- char buf[4096]; \
- snprintf(buf, sizeof(buf), msg); \
- ret = write(fd, buf, strlen(buf));
-
-
-/* per connection data */
-LLIST_HEAD(active_connections);
-
-/* per network data */
-static int telnet_new_connection(struct bsc_fd *fd, unsigned int what);
-#if 0
-static int telnet_paging_callback(unsigned int subsys, unsigned int signal,
- void *handler_data, void *signal_data);
-static int telnet_sms_callback(unsigned int subsys, unsigned int signal,
- void *handler_data, void *signal_data);
-#endif
-
-static struct bsc_fd server_socket = {
- .when = BSC_FD_READ,
- .cb = telnet_new_connection,
- .priv_nr = 0,
-};
-
-void telnet_init(struct gsm_network *network, int port) {
- struct sockaddr_in sock_addr;
- int fd, on = 1;
-
- bsc_vty_init(network);
-
- fd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
-
- if (fd < 0) {
- perror("Telnet interface socket creation failed");
- return;
- }
-
- setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
-
- memset(&sock_addr, 0, sizeof(sock_addr));
- sock_addr.sin_family = AF_INET;
- sock_addr.sin_port = htons(port);
- sock_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
-
- if (bind(fd, (struct sockaddr*)&sock_addr, sizeof(sock_addr)) < 0) {
- perror("Telnet interface failed to bind");
- return;
- }
-
- if (listen(fd, 0) < 0) {
- perror("Telnet interface failed to listen");
- return;
- }
-
- server_socket.data = network;
- server_socket.fd = fd;
- bsc_register_fd(&server_socket);
-
- /* register callbacks */
-#if 0
- register_signal_handler(SS_PAGING, telnet_paging_callback, network);
- register_signal_handler(SS_SMS, telnet_sms_callback, network);
-#endif
-}
-
-static void print_welcome(int fd) {
- int ret;
- static char *msg =
- "Welcome to the OpenBSC Control interface\n"
- "Copyright (C) 2008, 2009 Harald Welte\n"
- "Contributions by Daniel Willmann, Jan Lübbe, "
- "Stefan Schmidt, Holger Freyther\n\n"
- "License GPLv2+: GNU GPL version 2 or later "
- "<http://gnu.org/licenses/gpl.html>\n"
- "This is free software: you are free to change "
- "and redistribute it.\n"
- "There is NO WARRANTY, to the extent permitted "
- "by law.\nType \"help\" to get a short introduction.\n";
-
- ret = write(fd, msg, strlen(msg));
-}
-
-int telnet_close_client(struct bsc_fd *fd) {
- struct telnet_connection *conn = (struct telnet_connection*)fd->data;
-
- close(fd->fd);
- bsc_unregister_fd(fd);
- llist_del(&conn->entry);
- free(conn);
- return 0;
-}
-
-static int client_data(struct bsc_fd *fd, unsigned int what)
-{
- struct telnet_connection *conn = fd->data;
- int rc = 0;
-
- if (what & BSC_FD_READ) {
- conn->fd.when &= ~BSC_FD_READ;
- rc = vty_read(conn->vty);
- }
-
- if (what & BSC_FD_WRITE) {
- rc = buffer_flush_all(conn->vty->obuf, fd->fd);
- if (rc == BUFFER_EMPTY)
- conn->fd.when &= ~BSC_FD_WRITE;
- }
-
- return rc;
-}
-
-static int telnet_new_connection(struct bsc_fd *fd, unsigned int what) {
- struct telnet_connection *connection;
- struct sockaddr_in sockaddr;
- socklen_t len = sizeof(sockaddr);
- int new_connection = accept(fd->fd, (struct sockaddr*)&sockaddr, &len);
-
- if (new_connection < 0) {
- perror("telnet accept failed");
- return -1;
- }
-
-
- connection = (struct telnet_connection*)malloc(sizeof(*connection));
- memset(connection, 0, sizeof(*connection));
- connection->network = (struct gsm_network*)fd->data;
- connection->fd.data = connection;
- connection->fd.fd = new_connection;
- connection->fd.when = BSC_FD_READ;
- connection->fd.cb = client_data;
- connection->bts = 0;
- bsc_register_fd(&connection->fd);
- llist_add_tail(&connection->entry, &active_connections);
-
- print_welcome(new_connection);
-
- connection->vty = vty_create(new_connection, connection);
- if (!connection->vty)
- return -1;
-
- return 0;
-}
-
-/* callback from VTY code */
-void vty_event(enum event event, int sock, struct vty *vty)
-{
- struct telnet_connection *connection = vty->priv;
- struct bsc_fd *bfd = &connection->fd;
-
- switch (event) {
- case VTY_READ:
- bfd->when |= BSC_FD_READ;
- break;
- case VTY_WRITE:
- bfd->when |= BSC_FD_WRITE;
- break;
- default:
- break;
- }
-}
-
-#if 0
-static int telnet_paging_callback(unsigned int subsys, unsigned int singal,
- void *handler_data, void *signal_data)
-{
- struct paging_signal_data *paging = signal_data;
- struct telnet_connection *con;
-
- llist_for_each_entry(con, &active_connections, entry) {
- if (paging->lchan) {
- WRITE_CONNECTION(con->fd.fd, "Paging succeeded\n");
- show_lchan(con->fd.fd, paging->lchan);
- } else {
- WRITE_CONNECTION(con->fd.fd, "Paging failed for subscriber: %s/%s/%s\n",
- paging->subscr->imsi,
- paging->subscr->tmsi,
- paging->subscr->name);
- }
- }
-
- return 0;
-}
-
-static int telnet_sms_callback(unsigned int subsys, unsigned int signal,
- void *handler_data, void *signal_data)
-{
- struct sms_submit *sms = signal_data;
- struct telnet_connection *con;
-
- llist_for_each_entry(con, &active_connections, entry) {
- WRITE_CONNECTION(con->fd.fd, "Incoming SMS: %s\n", sms->user_data);
- }
-
- return 0;
-}
-#endif
diff --git a/src/timer.c b/src/timer.c
deleted file mode 100644
index a942ffd6d..000000000
--- a/src/timer.c
+++ /dev/null
@@ -1,174 +0,0 @@
-/*
- * (C) 2008,2009 by Holger Hans Peter Freyther <zecke@selfish.org>
- * All Rights Reserved
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- */
-
-#include <assert.h>
-#include <string.h>
-#include <openbsc/timer.h>
-
-static LLIST_HEAD(timer_list);
-static struct timeval s_nearest_time;
-static struct timeval s_select_time;
-
-#define MICRO_SECONDS 1000000LL
-
-#define TIME_SMALLER(left, right) \
- (left.tv_sec*MICRO_SECONDS+left.tv_usec) <= (right.tv_sec*MICRO_SECONDS+right.tv_usec)
-
-void bsc_add_timer(struct timer_list *timer)
-{
- struct timer_list *list_timer;
-
- /* TODO: Optimize and remember the closest item... */
- timer->active = 1;
-
- /* this might be called from within update_timers */
- llist_for_each_entry(list_timer, &timer_list, entry)
- if (timer == list_timer)
- return;
-
- timer->in_list = 1;
- llist_add(&timer->entry, &timer_list);
-}
-
-void bsc_schedule_timer(struct timer_list *timer, int seconds, int microseconds)
-{
- struct timeval current_time;
-
- gettimeofday(&current_time, NULL);
- unsigned long long currentTime = current_time.tv_sec * MICRO_SECONDS + current_time.tv_usec;
- currentTime += seconds * MICRO_SECONDS + microseconds;
- timer->timeout.tv_sec = currentTime / MICRO_SECONDS;
- timer->timeout.tv_usec = currentTime % MICRO_SECONDS;
- bsc_add_timer(timer);
-}
-
-void bsc_del_timer(struct timer_list *timer)
-{
- if (timer->in_list) {
- timer->active = 0;
- timer->in_list = 0;
- llist_del(&timer->entry);
- }
-}
-
-int bsc_timer_pending(struct timer_list *timer)
-{
- return timer->active;
-}
-
-/*
- * if we have a nearest time return the delta between the current
- * time and the time of the nearest timer.
- * If the nearest timer timed out return NULL and then we will
- * dispatch everything after the select
- */
-struct timeval *bsc_nearest_timer()
-{
- struct timeval current_time;
-
- if (s_nearest_time.tv_sec == 0 && s_nearest_time.tv_usec == 0)
- return NULL;
-
- if (gettimeofday(&current_time, NULL) == -1)
- return NULL;
-
- unsigned long long nearestTime = s_nearest_time.tv_sec * MICRO_SECONDS + s_nearest_time.tv_usec;
- unsigned long long currentTime = current_time.tv_sec * MICRO_SECONDS + current_time.tv_usec;
-
- if (nearestTime < currentTime) {
- s_select_time.tv_sec = 0;
- s_select_time.tv_usec = 0;
- } else {
- s_select_time.tv_sec = (nearestTime - currentTime) / MICRO_SECONDS;
- s_select_time.tv_usec = (nearestTime - currentTime) % MICRO_SECONDS;
- }
-
- return &s_select_time;
-}
-
-/*
- * Find the nearest time and update s_nearest_time
- */
-void bsc_prepare_timers()
-{
- struct timer_list *timer, *nearest_timer = NULL;
- llist_for_each_entry(timer, &timer_list, entry) {
- if (!nearest_timer || TIME_SMALLER(timer->timeout, nearest_timer->timeout)) {
- nearest_timer = timer;
- }
- }
-
- if (nearest_timer) {
- s_nearest_time = nearest_timer->timeout;
- } else {
- memset(&s_nearest_time, 0, sizeof(struct timeval));
- }
-}
-
-/*
- * fire all timers... and remove them
- */
-int bsc_update_timers()
-{
- struct timeval current_time;
- struct timer_list *timer, *tmp;
- int work = 0;
-
- gettimeofday(&current_time, NULL);
-
- /*
- * The callbacks might mess with our list and in this case
- * even llist_for_each_entry_safe is not safe to use. To allow
- * del_timer, add_timer, schedule_timer to be called from within
- * the callback we jump through some loops.
- *
- * First we set the handled flag of each active timer to zero,
- * then we iterate over the list and execute the callbacks. As the
- * list might have been changed (specially the next) from within
- * the callback we have to start over again. Once every callback
- * is dispatched we will remove the non-active from the list.
- *
- * TODO: If this is a performance issue we can poison a global
- * variable in add_timer and del_timer and only then restart.
- */
- llist_for_each_entry(timer, &timer_list, entry) {
- timer->handled = 0;
- }
-
-restart:
- llist_for_each_entry(timer, &timer_list, entry) {
- if (!timer->handled && TIME_SMALLER(timer->timeout, current_time)) {
- timer->handled = 1;
- timer->active = 0;
- (*timer->cb)(timer->data);
- work = 1;
- goto restart;
- }
- }
-
- llist_for_each_entry_safe(timer, tmp, &timer_list, entry) {
- timer->handled = 0;
- if (!timer->active) {
- bsc_del_timer(timer);
- }
- }
-
- return work;
-}
diff --git a/src/tlv_parser.c b/src/tlv_parser.c
deleted file mode 100644
index e835f951f..000000000
--- a/src/tlv_parser.c
+++ /dev/null
@@ -1,105 +0,0 @@
-#include <stdio.h>
-#include <openbsc/tlv.h>
-
-int tlv_dump(struct tlv_parsed *dec)
-{
- int i;
-
- for (i = 0; i <= 0xff; i++) {
- if (!dec->lv[i].val)
- continue;
- printf("T=%02x L=%d\n", i, dec->lv[i].len);
- }
- return 0;
-}
-
-/* dec: output: a caller-allocated pointer to a struct tlv_parsed,
- * def: input: a structure defining the valid TLV tags / configurations
- * buf: input: the input data buffer to be parsed
- * buf_len: input: the length of the input data buffer
- * lv_tag: input: an initial LV tag at the start of the buffer
- * lv_tag2: input: a second initial LV tag following lv_tag
- */
-int tlv_parse(struct tlv_parsed *dec, const struct tlv_definition *def,
- const u_int8_t *buf, int buf_len, u_int8_t lv_tag,
- u_int8_t lv_tag2)
-{
- u_int8_t tag, len = 1;
- const u_int8_t *pos = buf;
- int num_parsed = 0;
-
- memset(dec, 0, sizeof(*dec));
-
- if (lv_tag) {
- if (pos > buf + buf_len)
- return -1;
- dec->lv[lv_tag].val = pos+1;
- dec->lv[lv_tag].len = *pos;
- len = dec->lv[lv_tag].len + 1;
- if (pos + len > buf + buf_len)
- return -2;
- num_parsed++;
- pos += len;
- }
- if (lv_tag2) {
- if (pos > buf + buf_len)
- return -1;
- dec->lv[lv_tag2].val = pos+1;
- dec->lv[lv_tag2].len = *pos;
- len = dec->lv[lv_tag2].len + 1;
- if (pos + len > buf + buf_len)
- return -2;
- num_parsed++;
- pos += len;
- }
-
- for (; pos < buf+buf_len; pos += len) {
- tag = *pos;
- /* FIXME: use tables for knwon IEI */
- switch (def->def[tag].type) {
- case TLV_TYPE_T:
- /* GSM TS 04.07 11.2.4: Type 1 TV or Type 2 T */
- dec->lv[tag].val = pos;
- dec->lv[tag].len = 0;
- len = 1;
- num_parsed++;
- break;
- case TLV_TYPE_TV:
- dec->lv[tag].val = pos+1;
- dec->lv[tag].len = 1;
- len = 2;
- num_parsed++;
- break;
- case TLV_TYPE_FIXED:
- dec->lv[tag].val = pos+1;
- dec->lv[tag].len = def->def[tag].fixed_len;
- len = def->def[tag].fixed_len + 1;
- num_parsed++;
- break;
- case TLV_TYPE_TLV:
- /* GSM TS 04.07 11.2.4: Type 4 TLV */
- if (pos + 1 > buf + buf_len)
- return -1;
- dec->lv[tag].val = pos+2;
- dec->lv[tag].len = *(pos+1);
- len = dec->lv[tag].len + 2;
- if (pos + len > buf + buf_len)
- return -2;
- num_parsed++;
- break;
- case TLV_TYPE_TL16V:
- if (pos + 2 > buf + buf_len)
- return -1;
- dec->lv[tag].val = pos+3;
- dec->lv[tag].len = *(pos+1) << 8 | *(pos+2);
- len = dec->lv[tag].len + 3;
- if (pos + len > buf + buf_len)
- return -2;
- num_parsed++;
- break;
- }
- }
- //tlv_dump(dec);
- return num_parsed;
-}
-
diff --git a/src/trau_frame.c b/src/trau_frame.c
deleted file mode 100644
index aa039574b..000000000
--- a/src/trau_frame.c
+++ /dev/null
@@ -1,255 +0,0 @@
-/* TRAU frame handling according to GSM TS 08.60 */
-
-/* (C) 2009 by Harald Welte <laforge@gnumonks.org>
- * All Rights Reserved
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- */
-
-#include <unistd.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <errno.h>
-
-#include <openbsc/trau_frame.h>
-#include <openbsc/subchan_demux.h>
-#include <openbsc/debug.h>
-
-static u_int32_t get_bits(const u_int8_t *bitbuf, int offset, int num)
-{
- int i;
- u_int32_t ret = 0;
-
- for (i = offset; i < offset + num; i++) {
- ret = ret << 1;
- if (bitbuf[i])
- ret |= 1;
- }
- return ret;
-}
-
-/* Decode according to 3.1.1 */
-static void decode_fr(struct decoded_trau_frame *fr, const u_int8_t *trau_bits)
-{
- int i;
- int d_idx = 0;
-
- /* C1 .. C15 */
- memcpy(fr->c_bits+0, trau_bits+17, 15);
- /* C16 .. C21 */
- memcpy(fr->c_bits+15, trau_bits+310, 6);
- /* T1 .. T4 */
- memcpy(fr->t_bits+0, trau_bits+316, 4);
- /* D1 .. D255 */
- for (i = 32; i < 304; i+= 16) {
- memcpy(fr->d_bits + d_idx, trau_bits+i+1, 15);
- d_idx += 15;
- }
- /* D256 .. D260 */
- memcpy(fr->d_bits + d_idx, trau_bits + 305, 5);
-}
-
-/* Decode according to 3.1.2 */
-static void decode_amr(struct decoded_trau_frame *fr, const u_int8_t *trau_bits)
-{
- int i;
- int d_idx = 0;
-
- /* C1 .. C15 */
- memcpy(fr->c_bits+0, trau_bits+17, 15);
- /* C16 .. C25 */
- memcpy(fr->c_bits+15, trau_bits+33, 10);
- /* T1 .. T4 */
- memcpy(fr->t_bits+0, trau_bits+316, 4);
- /* D1 .. D5 */
- memcpy(fr->d_bits, trau_bits+43, 5);
- /* D6 .. D245 */
- for (i = 48; i < 304; i += 16) {
- memcpy(fr->d_bits + d_idx, trau_bits+i+1, 15);
- d_idx += 15;
- }
- /* D246 .. D256 */
- memcpy(fr->d_bits + d_idx, trau_bits + 305, 11);
-}
-
-int decode_trau_frame(struct decoded_trau_frame *fr, const u_int8_t *trau_bits)
-{
- u_int8_t cbits5 = get_bits(trau_bits, 17, 5);
-
- switch (cbits5) {
- case TRAU_FT_FR_UP:
- case TRAU_FT_FR_DOWN:
- case TRAU_FT_IDLE_UP:
- case TRAU_FT_IDLE_DOWN:
- case TRAU_FT_EFR:
- decode_fr(fr, trau_bits);
- break;
- case TRAU_FT_AMR:
- decode_amr(fr, trau_bits);
- break;
- case TRAU_FT_OM_UP:
- case TRAU_FT_OM_DOWN:
- case TRAU_FT_DATA_UP:
- case TRAU_FT_DATA_DOWN:
- case TRAU_FT_D145_SYNC:
- case TRAU_FT_EDATA:
- DEBUGP(DMUX, "can't decode unimplemented TRAU Frame Type 0x%02x\n", cbits5);
- return -1;
- break;
- default:
- DEBUGP(DMUX, "can't decode unknown TRAU Frame Type 0x%02x\n", cbits5);
- return -1;
- break;
- }
-
- return 0;
-}
-
-const u_int8_t ft_fr_down_bits[] = { 1, 1, 1, 0, 0 };
-const u_int8_t ft_idle_down_bits[] = { 0, 1, 1, 1, 0 };
-
-/* modify an uplink TRAU frame so we can send it downlink */
-int trau_frame_up2down(struct decoded_trau_frame *fr)
-{
- u_int8_t cbits5 = get_bits(fr->c_bits, 0, 5);
-
- switch (cbits5) {
- case TRAU_FT_FR_UP:
- memcpy(fr->c_bits, ft_fr_down_bits, 5);
- /* clear time alignment */
- memset(fr->c_bits+5, 0, 6);
- /* FIXME: SP / BFI in case of DTx */
- /* C12 .. C21 are spare and coded as '1' */
- memset(fr->c_bits+11, 0x01, 10);
- break;
- case TRAU_FT_EFR:
- /* clear time alignment */
- memset(fr->c_bits+5, 0, 6);
- /* FIXME: set UFE appropriately */
- /* FIXME: SP / BFI in case of DTx */
- break;
- case TRAU_FT_IDLE_UP:
- memcpy(fr->c_bits, ft_idle_down_bits, 5);
- /* clear time alignment */
- memset(fr->c_bits+5, 0, 6);
- /* FIXME: SP / BFI in case of DTx */
- /* C12 .. C21 are spare and coded as '1' */
- memset(fr->c_bits+11, 0x01, 10);
- break;
- case TRAU_FT_FR_DOWN:
- case TRAU_FT_IDLE_DOWN:
- case TRAU_FT_OM_DOWN:
- case TRAU_FT_DATA_DOWN:
- /* we cannot convert a downlink to a downlink frame */
- return -EINVAL;
- break;
- case TRAU_FT_AMR:
- case TRAU_FT_OM_UP:
- case TRAU_FT_DATA_UP:
- case TRAU_FT_D145_SYNC:
- case TRAU_FT_EDATA:
- DEBUGP(DMUX, "unimplemented TRAU Frame Type 0x%02x\n", cbits5);
- return -1;
- break;
- default:
- DEBUGP(DMUX, "unknown TRAU Frame Type 0x%02x\n", cbits5);
- return -1;
- break;
- }
-
- return 0;
-
-}
-
-static void encode_fr(u_int8_t *trau_bits, const struct decoded_trau_frame *fr)
-{
- int i;
- int d_idx = 0;
-
- trau_bits[16] = 1;
- /* C1 .. C15 */
- memcpy(trau_bits+17, fr->c_bits+0, 15);
- /* D1 .. D255 */
- for (i = 32; i < 304; i+= 16) {
- trau_bits[i] = 1;
- memcpy(trau_bits+i+1, fr->d_bits + d_idx, 15);
- d_idx += 15;
- }
- /* D256 .. D260 */
- trau_bits[304] = 1;
- memcpy(trau_bits + 305, fr->d_bits + d_idx, 5);
- /* C16 .. C21 */
- memcpy(trau_bits+310, fr->c_bits+15, 6);
-
- /* FIXME: handle timing adjustment */
-
- /* T1 .. T4 */
- memcpy(trau_bits+316, fr->t_bits+0, 4);
-}
-
-
-int encode_trau_frame(u_int8_t *trau_bits, const struct decoded_trau_frame *fr)
-{
- u_int8_t cbits5 = get_bits(fr->c_bits, 0, 5);
-
- /* 16 bits of sync header */
- memset(trau_bits, 0, 16);
-
- switch (cbits5) {
- case TRAU_FT_FR_UP:
- case TRAU_FT_FR_DOWN:
- case TRAU_FT_IDLE_UP:
- case TRAU_FT_IDLE_DOWN:
- case TRAU_FT_EFR:
- encode_fr(trau_bits, fr);
- break;
- case TRAU_FT_AMR:
- case TRAU_FT_OM_UP:
- case TRAU_FT_OM_DOWN:
- case TRAU_FT_DATA_UP:
- case TRAU_FT_DATA_DOWN:
- case TRAU_FT_D145_SYNC:
- case TRAU_FT_EDATA:
- DEBUGP(DMUX, "unimplemented TRAU Frame Type 0x%02x\n", cbits5);
- return -1;
- break;
- default:
- DEBUGP(DMUX, "unknown TRAU Frame Type 0x%02x\n", cbits5);
- return -1;
- break;
- }
-
- return 0;
-}
-
-static struct decoded_trau_frame fr_idle_frame = {
- .c_bits = { 0, 1, 1, 1, 0 }, /* IDLE DOWNLINK 3.5.5 */
- .t_bits = { 1, 1, 1, 1 },
-};
-static u_int8_t encoded_idle_frame[TRAU_FRAME_BITS];
-static int dbits_initted;
-
-u_int8_t *trau_idle_frame(void)
-{
- /* only initialize during the first call */
- if (!dbits_initted) {
- /* set all D-bits to 1 */
- memset(&fr_idle_frame.d_bits, 0x01, 260);
- encode_fr(encoded_idle_frame, &fr_idle_frame);
- }
- return encoded_idle_frame;
-}
diff --git a/src/trau_mux.c b/src/trau_mux.c
deleted file mode 100644
index 96f858992..000000000
--- a/src/trau_mux.c
+++ /dev/null
@@ -1,212 +0,0 @@
-/* Simple TRAU frame reflector to route voice calls */
-
-/* (C) 2009 by Harald Welte <laforge@gnumonks.org>
- * All Rights Reserved
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- */
-
-#include <errno.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-
-#include <openbsc/gsm_data.h>
-#include <openbsc/trau_frame.h>
-#include <openbsc/trau_mux.h>
-#include <openbsc/subchan_demux.h>
-#include <openbsc/e1_input.h>
-#include <openbsc/debug.h>
-
-struct map_entry {
- struct llist_head list;
- struct gsm_e1_subslot src, dst;
-};
-
-struct upqueue_entry {
- struct llist_head list;
- struct gsm_network *net;
- struct gsm_e1_subslot src;
- u_int32_t callref;
-};
-
-static LLIST_HEAD(ss_map);
-static LLIST_HEAD(ss_upqueue);
-
-/* map one particular subslot to another subslot */
-int trau_mux_map(const struct gsm_e1_subslot *src,
- const struct gsm_e1_subslot *dst)
-{
- struct map_entry *me = malloc(sizeof(*me));
- if (!me)
- return -ENOMEM;
-
- DEBUGP(DCC, "Setting up TRAU mux map between (e1=%u,ts=%u,ss=%u) "
- "and (e1=%u,ts=%u,ss=%u)\n",
- src->e1_nr, src->e1_ts, src->e1_ts_ss,
- dst->e1_nr, dst->e1_ts, dst->e1_ts_ss);
-
- /* make sure to get rid of any stale old mappings */
- trau_mux_unmap(src, 0);
- trau_mux_unmap(dst, 0);
-
- memcpy(&me->src, src, sizeof(me->src));
- memcpy(&me->dst, dst, sizeof(me->dst));
- llist_add(&me->list, &ss_map);
-
- return 0;
-}
-
-int trau_mux_map_lchan(const struct gsm_lchan *src,
- const struct gsm_lchan *dst)
-{
- struct gsm_e1_subslot *src_ss, *dst_ss;
-
- src_ss = &src->ts->e1_link;
- dst_ss = &dst->ts->e1_link;
-
- return trau_mux_map(src_ss, dst_ss);
-}
-
-
-/* unmap one particular subslot from another subslot */
-int trau_mux_unmap(const struct gsm_e1_subslot *ss, u_int32_t callref)
-{
- struct map_entry *me, *me2;
- struct upqueue_entry *ue, *ue2;
-
- if (ss)
- llist_for_each_entry_safe(me, me2, &ss_map, list) {
- if (!memcmp(&me->src, ss, sizeof(*ss)) ||
- !memcmp(&me->dst, ss, sizeof(*ss))) {
- llist_del(&me->list);
- return 0;
- }
- }
- llist_for_each_entry_safe(ue, ue2, &ss_upqueue, list) {
- if (ue->callref == callref) {
- llist_del(&ue->list);
- return 0;
- }
- if (ss && !memcmp(&ue->src, ss, sizeof(*ss))) {
- llist_del(&ue->list);
- return 0;
- }
- }
- return -ENOENT;
-}
-
-/* look-up an enty in the TRAU mux map */
-static struct gsm_e1_subslot *
-lookup_trau_mux_map(const struct gsm_e1_subslot *src)
-{
- struct map_entry *me;
-
- llist_for_each_entry(me, &ss_map, list) {
- if (!memcmp(&me->src, src, sizeof(*src)))
- return &me->dst;
- if (!memcmp(&me->dst, src, sizeof(*src)))
- return &me->src;
- }
- return NULL;
-}
-
-/* look-up an enty in the TRAU upqueue */
-struct upqueue_entry *
-lookup_trau_upqueue(const struct gsm_e1_subslot *src)
-{
- struct upqueue_entry *ue;
-
- llist_for_each_entry(ue, &ss_upqueue, list) {
- if (!memcmp(&ue->src, src, sizeof(*src)))
- return ue;
- }
- return NULL;
-}
-
-/* we get called by subchan_demux */
-int trau_mux_input(struct gsm_e1_subslot *src_e1_ss,
- const u_int8_t *trau_bits, int num_bits)
-{
- struct decoded_trau_frame tf;
- u_int8_t trau_bits_out[TRAU_FRAME_BITS];
- struct gsm_e1_subslot *dst_e1_ss = lookup_trau_mux_map(src_e1_ss);
- struct subch_mux *mx;
- int rc;
-
- /* decode TRAU, change it to downlink, re-encode */
- rc = decode_trau_frame(&tf, trau_bits);
- if (rc)
- return rc;
-
- if (!dst_e1_ss)
- return -EINVAL;
-
- mx = e1inp_get_mux(dst_e1_ss->e1_nr, dst_e1_ss->e1_ts);
- if (!mx)
- return -EINVAL;
-
- trau_frame_up2down(&tf);
- encode_trau_frame(trau_bits_out, &tf);
-
- /* and send it to the muxer */
- return subchan_mux_enqueue(mx, dst_e1_ss->e1_ts_ss, trau_bits_out,
- TRAU_FRAME_BITS);
-}
-
-/* add receiver instance for lchan and callref */
-int trau_recv_lchan(struct gsm_lchan *lchan, u_int32_t callref)
-{
- struct gsm_e1_subslot *src_ss;
- struct upqueue_entry *ue = malloc(sizeof(*ue));
-
- if (!ue)
- return -ENOMEM;
-
- src_ss = &lchan->ts->e1_link;
-
- DEBUGP(DCC, "Setting up TRAU receiver (e1=%u,ts=%u,ss=%u) "
- "and (callref 0x%x)\n",
- src_ss->e1_nr, src_ss->e1_ts, src_ss->e1_ts_ss,
- callref);
-
- /* make sure to get rid of any stale old mappings */
- trau_mux_unmap(src_ss, callref);
-
- memcpy(&ue->src, src_ss, sizeof(ue->src));
- ue->net = lchan->ts->trx->bts->network;
- ue->callref = callref;
- llist_add(&ue->list, &ss_upqueue);
-
- return 0;
-}
-
-int trau_send_lchan(struct gsm_lchan *lchan, struct decoded_trau_frame *tf)
-{
- u_int8_t trau_bits_out[TRAU_FRAME_BITS];
- struct gsm_e1_subslot *dst_e1_ss = &lchan->ts->e1_link;
- struct subch_mux *mx;
-
- mx = e1inp_get_mux(dst_e1_ss->e1_nr, dst_e1_ss->e1_ts);
- if (!mx)
- return -EINVAL;
-
- encode_trau_frame(trau_bits_out, tf);
-
- /* and send it to the muxer */
- return subchan_mux_enqueue(mx, dst_e1_ss->e1_ts_ss, trau_bits_out,
- TRAU_FRAME_BITS);
-}
diff --git a/src/vty/buffer.c b/src/vty/buffer.c
deleted file mode 100644
index 63661004d..000000000
--- a/src/vty/buffer.c
+++ /dev/null
@@ -1,460 +0,0 @@
-/*
- * Buffering of output and input.
- * Copyright (C) 1998 Kunihiro Ishiguro
- *
- * This file is part of GNU Zebra.
- *
- * GNU Zebra 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, or (at your
- * option) any later version.
- *
- * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-#include <errno.h>
-#include <stddef.h>
-#include <sys/uio.h>
-
-#include <vty/buffer.h>
-#include <vty/vty.h>
-
-/* Buffer master. */
-struct buffer {
- /* Data list. */
- struct buffer_data *head;
- struct buffer_data *tail;
-
- /* Size of each buffer_data chunk. */
- size_t size;
-};
-
-/* Data container. */
-struct buffer_data {
- struct buffer_data *next;
-
- /* Location to add new data. */
- size_t cp;
-
- /* Pointer to data not yet flushed. */
- size_t sp;
-
- /* Actual data stream (variable length). */
- unsigned char data[0]; /* real dimension is buffer->size */
-};
-
-/* It should always be true that: 0 <= sp <= cp <= size */
-
-/* Default buffer size (used if none specified). It is rounded up to the
- next page boundery. */
-#define BUFFER_SIZE_DEFAULT 4096
-
-#define BUFFER_DATA_FREE(D) free((D))
-
-/* Make new buffer. */
-struct buffer *buffer_new(size_t size)
-{
- struct buffer *b;
-
- b = calloc(1, sizeof(struct buffer));
-
- if (size)
- b->size = size;
- else {
- static size_t default_size;
- if (!default_size) {
- long pgsz = sysconf(_SC_PAGESIZE);
- default_size =
- ((((BUFFER_SIZE_DEFAULT - 1) / pgsz) + 1) * pgsz);
- }
- b->size = default_size;
- }
-
- return b;
-}
-
-/* Free buffer. */
-void buffer_free(struct buffer *b)
-{
- buffer_reset(b);
- free(b);
-}
-
-/* Make string clone. */
-char *buffer_getstr(struct buffer *b)
-{
- size_t totlen = 0;
- struct buffer_data *data;
- char *s;
- char *p;
-
- for (data = b->head; data; data = data->next)
- totlen += data->cp - data->sp;
- if (!(s = malloc(totlen + 1)))
- return NULL;
- p = s;
- for (data = b->head; data; data = data->next) {
- memcpy(p, data->data + data->sp, data->cp - data->sp);
- p += data->cp - data->sp;
- }
- *p = '\0';
- return s;
-}
-
-/* Return 1 if buffer is empty. */
-int buffer_empty(struct buffer *b)
-{
- return (b->head == NULL);
-}
-
-/* Clear and free all allocated data. */
-void buffer_reset(struct buffer *b)
-{
- struct buffer_data *data;
- struct buffer_data *next;
-
- for (data = b->head; data; data = next) {
- next = data->next;
- BUFFER_DATA_FREE(data);
- }
- b->head = b->tail = NULL;
-}
-
-/* Add buffer_data to the end of buffer. */
-static struct buffer_data *buffer_add(struct buffer *b)
-{
- struct buffer_data *d;
-
- d = malloc(offsetof(struct buffer_data, data[b->size]));
- if (!d)
- return NULL;
- d->cp = d->sp = 0;
- d->next = NULL;
-
- if (b->tail)
- b->tail->next = d;
- else
- b->head = d;
- b->tail = d;
-
- return d;
-}
-
-/* Write data to buffer. */
-void buffer_put(struct buffer *b, const void *p, size_t size)
-{
- struct buffer_data *data = b->tail;
- const char *ptr = p;
-
- /* We use even last one byte of data buffer. */
- while (size) {
- size_t chunk;
-
- /* If there is no data buffer add it. */
- if (data == NULL || data->cp == b->size)
- data = buffer_add(b);
-
- chunk =
- ((size <=
- (b->size - data->cp)) ? size : (b->size - data->cp));
- memcpy((data->data + data->cp), ptr, chunk);
- size -= chunk;
- ptr += chunk;
- data->cp += chunk;
- }
-}
-
-/* Insert character into the buffer. */
-void buffer_putc(struct buffer *b, u_char c)
-{
- buffer_put(b, &c, 1);
-}
-
-/* Put string to the buffer. */
-void buffer_putstr(struct buffer *b, const char *c)
-{
- buffer_put(b, c, strlen(c));
-}
-
-/* Keep flushing data to the fd until the buffer is empty or an error is
- encountered or the operation would block. */
-buffer_status_t buffer_flush_all(struct buffer *b, int fd)
-{
- buffer_status_t ret;
- struct buffer_data *head;
- size_t head_sp;
-
- if (!b->head)
- return BUFFER_EMPTY;
- head_sp = (head = b->head)->sp;
- /* Flush all data. */
- while ((ret = buffer_flush_available(b, fd)) == BUFFER_PENDING) {
- if ((b->head == head) && (head_sp == head->sp)
- && (errno != EINTR))
- /* No data was flushed, so kernel buffer must be full. */
- return ret;
- head_sp = (head = b->head)->sp;
- }
-
- return ret;
-}
-
-#if 0
-/* Flush enough data to fill a terminal window of the given scene (used only
- by vty telnet interface). */
-buffer_status_t
-buffer_flush_window(struct buffer * b, int fd, int width, int height,
- int erase_flag, int no_more_flag)
-{
- int nbytes;
- int iov_alloc;
- int iov_index;
- struct iovec *iov;
- struct iovec small_iov[3];
- char more[] = " --More-- ";
- char erase[] =
- { 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
- ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
- 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08
- };
- struct buffer_data *data;
- int column;
-
- if (!b->head)
- return BUFFER_EMPTY;
-
- if (height < 1) {
- zlog_warn
- ("%s called with non-positive window height %d, forcing to 1",
- __func__, height);
- height = 1;
- } else if (height >= 2)
- height--;
- if (width < 1) {
- zlog_warn
- ("%s called with non-positive window width %d, forcing to 1",
- __func__, width);
- width = 1;
- }
-
- /* For erase and more data add two to b's buffer_data count. */
- if (b->head->next == NULL) {
- iov_alloc = sizeof(small_iov) / sizeof(small_iov[0]);
- iov = small_iov;
- } else {
- iov_alloc = ((height * (width + 2)) / b->size) + 10;
- iov = XMALLOC(MTYPE_TMP, iov_alloc * sizeof(*iov));
- }
- iov_index = 0;
-
- /* Previously print out is performed. */
- if (erase_flag) {
- iov[iov_index].iov_base = erase;
- iov[iov_index].iov_len = sizeof erase;
- iov_index++;
- }
-
- /* Output data. */
- column = 1; /* Column position of next character displayed. */
- for (data = b->head; data && (height > 0); data = data->next) {
- size_t cp;
-
- cp = data->sp;
- while ((cp < data->cp) && (height > 0)) {
- /* Calculate lines remaining and column position after displaying
- this character. */
- if (data->data[cp] == '\r')
- column = 1;
- else if ((data->data[cp] == '\n') || (column == width)) {
- column = 1;
- height--;
- } else
- column++;
- cp++;
- }
- iov[iov_index].iov_base = (char *)(data->data + data->sp);
- iov[iov_index++].iov_len = cp - data->sp;
- data->sp = cp;
-
- if (iov_index == iov_alloc)
- /* This should not ordinarily happen. */
- {
- iov_alloc *= 2;
- if (iov != small_iov) {
- zlog_warn("%s: growing iov array to %d; "
- "width %d, height %d, size %lu",
- __func__, iov_alloc, width, height,
- (u_long) b->size);
- iov =
- XREALLOC(MTYPE_TMP, iov,
- iov_alloc * sizeof(*iov));
- } else {
- /* This should absolutely never occur. */
- zlog_err
- ("%s: corruption detected: iov_small overflowed; "
- "head %p, tail %p, head->next %p",
- __func__, b->head, b->tail, b->head->next);
- iov =
- XMALLOC(MTYPE_TMP,
- iov_alloc * sizeof(*iov));
- memcpy(iov, small_iov, sizeof(small_iov));
- }
- }
- }
-
- /* In case of `more' display need. */
- if (b->tail && (b->tail->sp < b->tail->cp) && !no_more_flag) {
- iov[iov_index].iov_base = more;
- iov[iov_index].iov_len = sizeof more;
- iov_index++;
- }
-#ifdef IOV_MAX
- /* IOV_MAX are normally defined in <sys/uio.h> , Posix.1g.
- example: Solaris2.6 are defined IOV_MAX size at 16. */
- {
- struct iovec *c_iov = iov;
- nbytes = 0; /* Make sure it's initialized. */
-
- while (iov_index > 0) {
- int iov_size;
-
- iov_size =
- ((iov_index > IOV_MAX) ? IOV_MAX : iov_index);
- if ((nbytes = writev(fd, c_iov, iov_size)) < 0) {
- zlog_warn("%s: writev to fd %d failed: %s",
- __func__, fd, safe_strerror(errno));
- break;
- }
-
- /* move pointer io-vector */
- c_iov += iov_size;
- iov_index -= iov_size;
- }
- }
-#else /* IOV_MAX */
- if ((nbytes = writev(fd, iov, iov_index)) < 0)
- zlog_warn("%s: writev to fd %d failed: %s",
- __func__, fd, safe_strerror(errno));
-#endif /* IOV_MAX */
-
- /* Free printed buffer data. */
- while (b->head && (b->head->sp == b->head->cp)) {
- struct buffer_data *del;
- if (!(b->head = (del = b->head)->next))
- b->tail = NULL;
- BUFFER_DATA_FREE(del);
- }
-
- if (iov != small_iov)
- XFREE(MTYPE_TMP, iov);
-
- return (nbytes < 0) ? BUFFER_ERROR :
- (b->head ? BUFFER_PENDING : BUFFER_EMPTY);
-}
-#endif
-
-/* This function (unlike other buffer_flush* functions above) is designed
-to work with non-blocking sockets. It does not attempt to write out
-all of the queued data, just a "big" chunk. It returns 0 if it was
-able to empty out the buffers completely, 1 if more flushing is
-required later, or -1 on a fatal write error. */
-buffer_status_t buffer_flush_available(struct buffer * b, int fd)
-{
-
-/* These are just reasonable values to make sure a significant amount of
-data is written. There's no need to go crazy and try to write it all
-in one shot. */
-#ifdef IOV_MAX
-#define MAX_CHUNKS ((IOV_MAX >= 16) ? 16 : IOV_MAX)
-#else
-#define MAX_CHUNKS 16
-#endif
-#define MAX_FLUSH 131072
-
- struct buffer_data *d;
- size_t written;
- struct iovec iov[MAX_CHUNKS];
- size_t iovcnt = 0;
- size_t nbyte = 0;
-
- for (d = b->head; d && (iovcnt < MAX_CHUNKS) && (nbyte < MAX_FLUSH);
- d = d->next, iovcnt++) {
- iov[iovcnt].iov_base = d->data + d->sp;
- nbyte += (iov[iovcnt].iov_len = d->cp - d->sp);
- }
-
- if (!nbyte)
- /* No data to flush: should we issue a warning message? */
- return BUFFER_EMPTY;
-
- /* only place where written should be sign compared */
- if ((ssize_t) (written = writev(fd, iov, iovcnt)) < 0) {
- if (ERRNO_IO_RETRY(errno))
- /* Calling code should try again later. */
- return BUFFER_PENDING;
- return BUFFER_ERROR;
- }
-
- /* Free printed buffer data. */
- while (written > 0) {
- struct buffer_data *d;
- if (!(d = b->head))
- break;
- if (written < d->cp - d->sp) {
- d->sp += written;
- return BUFFER_PENDING;
- }
-
- written -= (d->cp - d->sp);
- if (!(b->head = d->next))
- b->tail = NULL;
- BUFFER_DATA_FREE(d);
- }
-
- return b->head ? BUFFER_PENDING : BUFFER_EMPTY;
-
-#undef MAX_CHUNKS
-#undef MAX_FLUSH
-}
-
-buffer_status_t
-buffer_write(struct buffer * b, int fd, const void *p, size_t size)
-{
- ssize_t nbytes;
-
-#if 0
- /* Should we attempt to drain any previously buffered data? This could help reduce latency in pushing out the data if we are stuck in a long-running thread that is preventing the main select loop from calling the flush thread... */
-
- if (b->head && (buffer_flush_available(b, fd) == BUFFER_ERROR))
- return BUFFER_ERROR;
-#endif
- if (b->head)
- /* Buffer is not empty, so do not attempt to write the new data. */
- nbytes = 0;
- else if ((nbytes = write(fd, p, size)) < 0) {
- if (ERRNO_IO_RETRY(errno))
- nbytes = 0;
- else
- return BUFFER_ERROR;
- }
- /* Add any remaining data to the buffer. */
- {
- size_t written = nbytes;
- if (written < size)
- buffer_put(b, ((const char *)p) + written,
- size - written);
- }
- return b->head ? BUFFER_PENDING : BUFFER_EMPTY;
-}
diff --git a/src/vty/cardshell.h b/src/vty/cardshell.h
deleted file mode 100644
index d963a3810..000000000
--- a/src/vty/cardshell.h
+++ /dev/null
@@ -1,5 +0,0 @@
-#define QUAGGA_PROGNAME "OpenBSC"
-#define QUAGGA_VERSION "0.01"
-#define QUAGGA_COPYRIGHT "Harald Welte <laforge@gnumonks.org>"
-#define CONFIGFILE_MASK 022
-#define SYSCONFDIR "/usr/local/etc"
diff --git a/src/vty/command.c b/src/vty/command.c
deleted file mode 100644
index 94a5c2af2..000000000
--- a/src/vty/command.c
+++ /dev/null
@@ -1,3416 +0,0 @@
-/*
- $Id: command.c,v 1.47 2005/04/25 16:26:42 paul Exp $
-
- Command interpreter routine for virtual terminal [aka TeletYpe]
- Copyright (C) 1997, 98, 99 Kunihiro Ishiguro
-
-This file is part of GNU Zebra.
-
-GNU Zebra 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, or (at your
-option) any later version.
-
-GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the
-Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA. */
-
-#include "cardshell.h"
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <syslog.h>
-#include <errno.h>
-#define _XOPEN_SOURCE
-#include <unistd.h>
-#include <assert.h>
-#include <ctype.h>
-#include <time.h>
-#include <sys/time.h>
-
-//#include "memory.h"
-//#include "log.h"
-//#include <lib/version.h>
-//#include "thread.h"
-#include <vty/vector.h>
-#include <vty/vty.h>
-#include <vty/command.h>
-//#include "workqueue.h"
-
-#include <openbsc/gsm_data.h>
-
-/* Command vector which includes some level of command lists. Normally
- each daemon maintains each own cmdvec. */
-vector cmdvec;
-
-/* Host information structure. */
-struct host host;
-
-/* Standard command node structures. */
-struct cmd_node auth_node = {
- AUTH_NODE,
- "Password: ",
-};
-
-struct cmd_node view_node = {
- VIEW_NODE,
- "%s> ",
-};
-
-struct cmd_node auth_enable_node = {
- AUTH_ENABLE_NODE,
- "Password: ",
-};
-
-struct cmd_node enable_node = {
- ENABLE_NODE,
- "%s# ",
-};
-
-struct cmd_node config_node = {
- CONFIG_NODE,
- "%s(config)# ",
- 1
-};
-
-/* Default motd string. */
-const char *default_motd = "\r\n\
-Hello, this is " QUAGGA_PROGNAME " (version " QUAGGA_VERSION ").\r\n\
-" QUAGGA_COPYRIGHT "\r\n\
-\r\n";
-
-#if 0
-static struct facility_map {
- int facility;
- const char *name;
- size_t match;
-} syslog_facilities[] = {
- {
- LOG_KERN, "kern", 1}, {
- LOG_USER, "user", 2}, {
- LOG_MAIL, "mail", 1}, {
- LOG_DAEMON, "daemon", 1}, {
- LOG_AUTH, "auth", 1}, {
- LOG_SYSLOG, "syslog", 1}, {
- LOG_LPR, "lpr", 2}, {
- LOG_NEWS, "news", 1}, {
- LOG_UUCP, "uucp", 2}, {
- LOG_CRON, "cron", 1},
-#ifdef LOG_FTP
- {
- LOG_FTP, "ftp", 1},
-#endif
- {
- LOG_LOCAL0, "local0", 6}, {
- LOG_LOCAL1, "local1", 6}, {
- LOG_LOCAL2, "local2", 6}, {
- LOG_LOCAL3, "local3", 6}, {
- LOG_LOCAL4, "local4", 6}, {
- LOG_LOCAL5, "local5", 6}, {
- LOG_LOCAL6, "local6", 6}, {
- LOG_LOCAL7, "local7", 6}, {
-0, NULL, 0},};
-
-static const char *facility_name(int facility)
-{
- struct facility_map *fm;
-
- for (fm = syslog_facilities; fm->name; fm++)
- if (fm->facility == facility)
- return fm->name;
- return "";
-}
-
-static int facility_match(const char *str)
-{
- struct facility_map *fm;
-
- for (fm = syslog_facilities; fm->name; fm++)
- if (!strncmp(str, fm->name, fm->match))
- return fm->facility;
- return -1;
-}
-
-static int level_match(const char *s)
-{
- int level;
-
- for (level = 0; zlog_priority[level] != NULL; level++)
- if (!strncmp(s, zlog_priority[level], 2))
- return level;
- return ZLOG_DISABLED;
-}
-#endif
-
-/* This is called from main when a daemon is invoked with -v or --version. */
-void print_version(const char *progname)
-{
- printf("%s version %s\n", progname, QUAGGA_VERSION);
- printf("%s\n", QUAGGA_COPYRIGHT);
-}
-
-/* Utility function to concatenate argv argument into a single string
- with inserting ' ' character between each argument. */
-char *argv_concat(const char **argv, int argc, int shift)
-{
- int i;
- size_t len;
- char *str;
- char *p;
-
- len = 0;
- for (i = shift; i < argc; i++)
- len += strlen(argv[i]) + 1;
- if (!len)
- return NULL;
- p = str = malloc(len);
- for (i = shift; i < argc; i++) {
- size_t arglen;
- memcpy(p, argv[i], (arglen = strlen(argv[i])));
- p += arglen;
- *p++ = ' ';
- }
- *(p - 1) = '\0';
- return str;
-}
-
-/* Install top node of command vector. */
-void install_node(struct cmd_node *node, int (*func) (struct vty *))
-{
- vector_set_index(cmdvec, node->node, node);
- node->func = func;
- node->cmd_vector = vector_init(VECTOR_MIN_SIZE);
-}
-
-/* Compare two command's string. Used in sort_node (). */
-static int cmp_node(const void *p, const void *q)
-{
- struct cmd_element *a = *(struct cmd_element **)p;
- struct cmd_element *b = *(struct cmd_element **)q;
-
- return strcmp(a->string, b->string);
-}
-
-static int cmp_desc(const void *p, const void *q)
-{
- struct desc *a = *(struct desc **)p;
- struct desc *b = *(struct desc **)q;
-
- return strcmp(a->cmd, b->cmd);
-}
-
-/* Sort each node's command element according to command string. */
-void sort_node()
-{
- unsigned int i, j;
- struct cmd_node *cnode;
- vector descvec;
- struct cmd_element *cmd_element;
-
- for (i = 0; i < vector_active(cmdvec); i++)
- if ((cnode = vector_slot(cmdvec, i)) != NULL) {
- vector cmd_vector = cnode->cmd_vector;
- qsort(cmd_vector->index, vector_active(cmd_vector),
- sizeof(void *), cmp_node);
-
- for (j = 0; j < vector_active(cmd_vector); j++)
- if ((cmd_element =
- vector_slot(cmd_vector, j)) != NULL
- && vector_active(cmd_element->strvec)) {
- descvec =
- vector_slot(cmd_element->strvec,
- vector_active
- (cmd_element->strvec) -
- 1);
- qsort(descvec->index,
- vector_active(descvec),
- sizeof(void *), cmp_desc);
- }
- }
-}
-
-/* Breaking up string into each command piece. I assume given
- character is separated by a space character. Return value is a
- vector which includes char ** data element. */
-vector cmd_make_strvec(const char *string)
-{
- const char *cp, *start;
- char *token;
- int strlen;
- vector strvec;
-
- if (string == NULL)
- return NULL;
-
- cp = string;
-
- /* Skip white spaces. */
- while (isspace((int)*cp) && *cp != '\0')
- cp++;
-
- /* Return if there is only white spaces */
- if (*cp == '\0')
- return NULL;
-
- if (*cp == '!' || *cp == '#')
- return NULL;
-
- /* Prepare return vector. */
- strvec = vector_init(VECTOR_MIN_SIZE);
-
- /* Copy each command piece and set into vector. */
- while (1) {
- start = cp;
- while (!(isspace((int)*cp) || *cp == '\r' || *cp == '\n') &&
- *cp != '\0')
- cp++;
- strlen = cp - start;
- token = malloc(strlen + 1);
- memcpy(token, start, strlen);
- *(token + strlen) = '\0';
- vector_set(strvec, token);
-
- while ((isspace((int)*cp) || *cp == '\n' || *cp == '\r') &&
- *cp != '\0')
- cp++;
-
- if (*cp == '\0')
- return strvec;
- }
-}
-
-/* Free allocated string vector. */
-void cmd_free_strvec(vector v)
-{
- unsigned int i;
- char *cp;
-
- if (!v)
- return;
-
- for (i = 0; i < vector_active(v); i++)
- if ((cp = vector_slot(v, i)) != NULL)
- free(cp);
-
- vector_free(v);
-}
-
-/* Fetch next description. Used in cmd_make_descvec(). */
-static char *cmd_desc_str(const char **string)
-{
- const char *cp, *start;
- char *token;
- int strlen;
-
- cp = *string;
-
- if (cp == NULL)
- return NULL;
-
- /* Skip white spaces. */
- while (isspace((int)*cp) && *cp != '\0')
- cp++;
-
- /* Return if there is only white spaces */
- if (*cp == '\0')
- return NULL;
-
- start = cp;
-
- while (!(*cp == '\r' || *cp == '\n') && *cp != '\0')
- cp++;
-
- strlen = cp - start;
- token = malloc(strlen + 1);
- memcpy(token, start, strlen);
- *(token + strlen) = '\0';
-
- *string = cp;
-
- return token;
-}
-
-/* New string vector. */
-static vector cmd_make_descvec(const char *string, const char *descstr)
-{
- int multiple = 0;
- const char *sp;
- char *token;
- int len;
- const char *cp;
- const char *dp;
- vector allvec;
- vector strvec = NULL;
- struct desc *desc;
-
- cp = string;
- dp = descstr;
-
- if (cp == NULL)
- return NULL;
-
- allvec = vector_init(VECTOR_MIN_SIZE);
-
- while (1) {
- while (isspace((int)*cp) && *cp != '\0')
- cp++;
-
- if (*cp == '(') {
- multiple = 1;
- cp++;
- }
- if (*cp == ')') {
- multiple = 0;
- cp++;
- }
- if (*cp == '|') {
- if (!multiple) {
- fprintf(stderr, "Command parse error!: %s\n",
- string);
- exit(1);
- }
- cp++;
- }
-
- while (isspace((int)*cp) && *cp != '\0')
- cp++;
-
- if (*cp == '(') {
- multiple = 1;
- cp++;
- }
-
- if (*cp == '\0')
- return allvec;
-
- sp = cp;
-
- while (!
- (isspace((int)*cp) || *cp == '\r' || *cp == '\n'
- || *cp == ')' || *cp == '|') && *cp != '\0')
- cp++;
-
- len = cp - sp;
-
- token = malloc(len + 1);
- memcpy(token, sp, len);
- *(token + len) = '\0';
-
- desc = calloc(1, sizeof(struct desc));
- desc->cmd = token;
- desc->str = cmd_desc_str(&dp);
-
- if (multiple) {
- if (multiple == 1) {
- strvec = vector_init(VECTOR_MIN_SIZE);
- vector_set(allvec, strvec);
- }
- multiple++;
- } else {
- strvec = vector_init(VECTOR_MIN_SIZE);
- vector_set(allvec, strvec);
- }
- vector_set(strvec, desc);
- }
-}
-
-/* Count mandantory string vector size. This is to determine inputed
- command has enough command length. */
-static int cmd_cmdsize(vector strvec)
-{
- unsigned int i;
- int size = 0;
- vector descvec;
- struct desc *desc;
-
- for (i = 0; i < vector_active(strvec); i++)
- if ((descvec = vector_slot(strvec, i)) != NULL) {
- if ((vector_active(descvec)) == 1
- && (desc = vector_slot(descvec, 0)) != NULL) {
- if (desc->cmd == NULL || CMD_OPTION(desc->cmd))
- return size;
- else
- size++;
- } else
- size++;
- }
- return size;
-}
-
-/* Return prompt character of specified node. */
-const char *cmd_prompt(enum node_type node)
-{
- struct cmd_node *cnode;
-
- cnode = vector_slot(cmdvec, node);
- return cnode->prompt;
-}
-
-/* Install a command into a node. */
-void install_element(enum node_type ntype, struct cmd_element *cmd)
-{
- struct cmd_node *cnode;
-
- cnode = vector_slot(cmdvec, ntype);
-
- if (cnode == NULL) {
- fprintf(stderr,
- "Command node %d doesn't exist, please check it\n",
- ntype);
- exit(1);
- }
-
- vector_set(cnode->cmd_vector, cmd);
-
- cmd->strvec = cmd_make_descvec(cmd->string, cmd->doc);
- cmd->cmdsize = cmd_cmdsize(cmd->strvec);
-}
-
-static unsigned char itoa64[] =
- "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
-
-static void to64(char *s, long v, int n)
-{
- while (--n >= 0) {
- *s++ = itoa64[v & 0x3f];
- v >>= 6;
- }
-}
-
-static char *zencrypt(const char *passwd)
-{
- char salt[6];
- struct timeval tv;
- char *crypt(const char *, const char *);
-
- gettimeofday(&tv, 0);
-
- to64(&salt[0], random(), 3);
- to64(&salt[3], tv.tv_usec, 3);
- salt[5] = '\0';
-
- return crypt(passwd, salt);
-}
-
-/* This function write configuration of this host. */
-static int config_write_host(struct vty *vty)
-{
-#if 0
- if (host.name)
- vty_out(vty, "hostname %s%s", host.name, VTY_NEWLINE);
-
- if (host.encrypt) {
- if (host.password_encrypt)
- vty_out(vty, "password 8 %s%s", host.password_encrypt,
- VTY_NEWLINE);
- if (host.enable_encrypt)
- vty_out(vty, "enable password 8 %s%s",
- host.enable_encrypt, VTY_NEWLINE);
- } else {
- if (host.password)
- vty_out(vty, "password %s%s", host.password,
- VTY_NEWLINE);
- if (host.enable)
- vty_out(vty, "enable password %s%s", host.enable,
- VTY_NEWLINE);
- }
-
- if (zlog_default->default_lvl != LOG_DEBUG) {
- vty_out(vty, "! N.B. The 'log trap' command is deprecated.%s",
- VTY_NEWLINE);
- vty_out(vty, "log trap %s%s",
- zlog_priority[zlog_default->default_lvl], VTY_NEWLINE);
- }
-
- if (host.logfile
- && (zlog_default->maxlvl[ZLOG_DEST_FILE] != ZLOG_DISABLED)) {
- vty_out(vty, "log file %s", host.logfile);
- if (zlog_default->maxlvl[ZLOG_DEST_FILE] !=
- zlog_default->default_lvl)
- vty_out(vty, " %s",
- zlog_priority[zlog_default->
- maxlvl[ZLOG_DEST_FILE]]);
- vty_out(vty, "%s", VTY_NEWLINE);
- }
-
- if (zlog_default->maxlvl[ZLOG_DEST_STDOUT] != ZLOG_DISABLED) {
- vty_out(vty, "log stdout");
- if (zlog_default->maxlvl[ZLOG_DEST_STDOUT] !=
- zlog_default->default_lvl)
- vty_out(vty, " %s",
- zlog_priority[zlog_default->
- maxlvl[ZLOG_DEST_STDOUT]]);
- vty_out(vty, "%s", VTY_NEWLINE);
- }
-
- if (zlog_default->maxlvl[ZLOG_DEST_MONITOR] == ZLOG_DISABLED)
- vty_out(vty, "no log monitor%s", VTY_NEWLINE);
- else if (zlog_default->maxlvl[ZLOG_DEST_MONITOR] !=
- zlog_default->default_lvl)
- vty_out(vty, "log monitor %s%s",
- zlog_priority[zlog_default->maxlvl[ZLOG_DEST_MONITOR]],
- VTY_NEWLINE);
-
- if (zlog_default->maxlvl[ZLOG_DEST_SYSLOG] != ZLOG_DISABLED) {
- vty_out(vty, "log syslog");
- if (zlog_default->maxlvl[ZLOG_DEST_SYSLOG] !=
- zlog_default->default_lvl)
- vty_out(vty, " %s",
- zlog_priority[zlog_default->
- maxlvl[ZLOG_DEST_SYSLOG]]);
- vty_out(vty, "%s", VTY_NEWLINE);
- }
-
- if (zlog_default->facility != LOG_DAEMON)
- vty_out(vty, "log facility %s%s",
- facility_name(zlog_default->facility), VTY_NEWLINE);
-
- if (zlog_default->record_priority == 1)
- vty_out(vty, "log record-priority%s", VTY_NEWLINE);
-
- if (host.advanced)
- vty_out(vty, "service advanced-vty%s", VTY_NEWLINE);
-
- if (host.encrypt)
- vty_out(vty, "service password-encryption%s", VTY_NEWLINE);
-
- if (host.lines >= 0)
- vty_out(vty, "service terminal-length %d%s", host.lines,
- VTY_NEWLINE);
-
- if (host.motdfile)
- vty_out(vty, "banner motd file %s%s", host.motdfile,
- VTY_NEWLINE);
- else if (!host.motd)
- vty_out(vty, "no banner motd%s", VTY_NEWLINE);
-
-#endif
- return 1;
-}
-
-/* Utility function for getting command vector. */
-static vector cmd_node_vector(vector v, enum node_type ntype)
-{
- struct cmd_node *cnode = vector_slot(v, ntype);
- return cnode->cmd_vector;
-}
-
-#if 0
-/* Filter command vector by symbol. This function is not actually used;
- * should it be deleted? */
-static int cmd_filter_by_symbol(char *command, char *symbol)
-{
- int i, lim;
-
- if (strcmp(symbol, "IPV4_ADDRESS") == 0) {
- i = 0;
- lim = strlen(command);
- while (i < lim) {
- if (!
- (isdigit((int)command[i]) || command[i] == '.'
- || command[i] == '/'))
- return 1;
- i++;
- }
- return 0;
- }
- if (strcmp(symbol, "STRING") == 0) {
- i = 0;
- lim = strlen(command);
- while (i < lim) {
- if (!
- (isalpha((int)command[i]) || command[i] == '_'
- || command[i] == '-'))
- return 1;
- i++;
- }
- return 0;
- }
- if (strcmp(symbol, "IFNAME") == 0) {
- i = 0;
- lim = strlen(command);
- while (i < lim) {
- if (!isalnum((int)command[i]))
- return 1;
- i++;
- }
- return 0;
- }
- return 0;
-}
-#endif
-
-/* Completion match types. */
-enum match_type {
- no_match,
- extend_match,
- ipv4_prefix_match,
- ipv4_match,
- ipv6_prefix_match,
- ipv6_match,
- range_match,
- vararg_match,
- partly_match,
- exact_match
-};
-
-static enum match_type cmd_ipv4_match(const char *str)
-{
- const char *sp;
- int dots = 0, nums = 0;
- char buf[4];
-
- if (str == NULL)
- return partly_match;
-
- for (;;) {
- memset(buf, 0, sizeof(buf));
- sp = str;
- while (*str != '\0') {
- if (*str == '.') {
- if (dots >= 3)
- return no_match;
-
- if (*(str + 1) == '.')
- return no_match;
-
- if (*(str + 1) == '\0')
- return partly_match;
-
- dots++;
- break;
- }
- if (!isdigit((int)*str))
- return no_match;
-
- str++;
- }
-
- if (str - sp > 3)
- return no_match;
-
- strncpy(buf, sp, str - sp);
- if (atoi(buf) > 255)
- return no_match;
-
- nums++;
-
- if (*str == '\0')
- break;
-
- str++;
- }
-
- if (nums < 4)
- return partly_match;
-
- return exact_match;
-}
-
-static enum match_type cmd_ipv4_prefix_match(const char *str)
-{
- const char *sp;
- int dots = 0;
- char buf[4];
-
- if (str == NULL)
- return partly_match;
-
- for (;;) {
- memset(buf, 0, sizeof(buf));
- sp = str;
- while (*str != '\0' && *str != '/') {
- if (*str == '.') {
- if (dots == 3)
- return no_match;
-
- if (*(str + 1) == '.' || *(str + 1) == '/')
- return no_match;
-
- if (*(str + 1) == '\0')
- return partly_match;
-
- dots++;
- break;
- }
-
- if (!isdigit((int)*str))
- return no_match;
-
- str++;
- }
-
- if (str - sp > 3)
- return no_match;
-
- strncpy(buf, sp, str - sp);
- if (atoi(buf) > 255)
- return no_match;
-
- if (dots == 3) {
- if (*str == '/') {
- if (*(str + 1) == '\0')
- return partly_match;
-
- str++;
- break;
- } else if (*str == '\0')
- return partly_match;
- }
-
- if (*str == '\0')
- return partly_match;
-
- str++;
- }
-
- sp = str;
- while (*str != '\0') {
- if (!isdigit((int)*str))
- return no_match;
-
- str++;
- }
-
- if (atoi(sp) > 32)
- return no_match;
-
- return exact_match;
-}
-
-#define IPV6_ADDR_STR "0123456789abcdefABCDEF:.%"
-#define IPV6_PREFIX_STR "0123456789abcdefABCDEF:.%/"
-#define STATE_START 1
-#define STATE_COLON 2
-#define STATE_DOUBLE 3
-#define STATE_ADDR 4
-#define STATE_DOT 5
-#define STATE_SLASH 6
-#define STATE_MASK 7
-
-#ifdef HAVE_IPV6
-
-static enum match_type cmd_ipv6_match(const char *str)
-{
- int state = STATE_START;
- int colons = 0, nums = 0, double_colon = 0;
- const char *sp = NULL;
- struct sockaddr_in6 sin6_dummy;
- int ret;
-
- if (str == NULL)
- return partly_match;
-
- if (strspn(str, IPV6_ADDR_STR) != strlen(str))
- return no_match;
-
- /* use inet_pton that has a better support,
- * for example inet_pton can support the automatic addresses:
- * ::1.2.3.4
- */
- ret = inet_pton(AF_INET6, str, &sin6_dummy.sin6_addr);
-
- if (ret == 1)
- return exact_match;
-
- while (*str != '\0') {
- switch (state) {
- case STATE_START:
- if (*str == ':') {
- if (*(str + 1) != ':' && *(str + 1) != '\0')
- return no_match;
- colons--;
- state = STATE_COLON;
- } else {
- sp = str;
- state = STATE_ADDR;
- }
-
- continue;
- case STATE_COLON:
- colons++;
- if (*(str + 1) == ':')
- state = STATE_DOUBLE;
- else {
- sp = str + 1;
- state = STATE_ADDR;
- }
- break;
- case STATE_DOUBLE:
- if (double_colon)
- return no_match;
-
- if (*(str + 1) == ':')
- return no_match;
- else {
- if (*(str + 1) != '\0')
- colons++;
- sp = str + 1;
- state = STATE_ADDR;
- }
-
- double_colon++;
- nums++;
- break;
- case STATE_ADDR:
- if (*(str + 1) == ':' || *(str + 1) == '\0') {
- if (str - sp > 3)
- return no_match;
-
- nums++;
- state = STATE_COLON;
- }
- if (*(str + 1) == '.')
- state = STATE_DOT;
- break;
- case STATE_DOT:
- state = STATE_ADDR;
- break;
- default:
- break;
- }
-
- if (nums > 8)
- return no_match;
-
- if (colons > 7)
- return no_match;
-
- str++;
- }
-
-#if 0
- if (nums < 11)
- return partly_match;
-#endif /* 0 */
-
- return exact_match;
-}
-
-static enum match_type cmd_ipv6_prefix_match(const char *str)
-{
- int state = STATE_START;
- int colons = 0, nums = 0, double_colon = 0;
- int mask;
- const char *sp = NULL;
- char *endptr = NULL;
-
- if (str == NULL)
- return partly_match;
-
- if (strspn(str, IPV6_PREFIX_STR) != strlen(str))
- return no_match;
-
- while (*str != '\0' && state != STATE_MASK) {
- switch (state) {
- case STATE_START:
- if (*str == ':') {
- if (*(str + 1) != ':' && *(str + 1) != '\0')
- return no_match;
- colons--;
- state = STATE_COLON;
- } else {
- sp = str;
- state = STATE_ADDR;
- }
-
- continue;
- case STATE_COLON:
- colons++;
- if (*(str + 1) == '/')
- return no_match;
- else if (*(str + 1) == ':')
- state = STATE_DOUBLE;
- else {
- sp = str + 1;
- state = STATE_ADDR;
- }
- break;
- case STATE_DOUBLE:
- if (double_colon)
- return no_match;
-
- if (*(str + 1) == ':')
- return no_match;
- else {
- if (*(str + 1) != '\0' && *(str + 1) != '/')
- colons++;
- sp = str + 1;
-
- if (*(str + 1) == '/')
- state = STATE_SLASH;
- else
- state = STATE_ADDR;
- }
-
- double_colon++;
- nums += 1;
- break;
- case STATE_ADDR:
- if (*(str + 1) == ':' || *(str + 1) == '.'
- || *(str + 1) == '\0' || *(str + 1) == '/') {
- if (str - sp > 3)
- return no_match;
-
- for (; sp <= str; sp++)
- if (*sp == '/')
- return no_match;
-
- nums++;
-
- if (*(str + 1) == ':')
- state = STATE_COLON;
- else if (*(str + 1) == '.')
- state = STATE_DOT;
- else if (*(str + 1) == '/')
- state = STATE_SLASH;
- }
- break;
- case STATE_DOT:
- state = STATE_ADDR;
- break;
- case STATE_SLASH:
- if (*(str + 1) == '\0')
- return partly_match;
-
- state = STATE_MASK;
- break;
- default:
- break;
- }
-
- if (nums > 11)
- return no_match;
-
- if (colons > 7)
- return no_match;
-
- str++;
- }
-
- if (state < STATE_MASK)
- return partly_match;
-
- mask = strtol(str, &endptr, 10);
- if (*endptr != '\0')
- return no_match;
-
- if (mask < 0 || mask > 128)
- return no_match;
-
-/* I don't know why mask < 13 makes command match partly.
- Forgive me to make this comments. I Want to set static default route
- because of lack of function to originate default in ospf6d; sorry
- yasu
- if (mask < 13)
- return partly_match;
-*/
-
- return exact_match;
-}
-
-#endif /* HAVE_IPV6 */
-
-#define DECIMAL_STRLEN_MAX 10
-
-static int cmd_range_match(const char *range, const char *str)
-{
- char *p;
- char buf[DECIMAL_STRLEN_MAX + 1];
- char *endptr = NULL;
- unsigned long min, max, val;
-
- if (str == NULL)
- return 1;
-
- val = strtoul(str, &endptr, 10);
- if (*endptr != '\0')
- return 0;
-
- range++;
- p = strchr(range, '-');
- if (p == NULL)
- return 0;
- if (p - range > DECIMAL_STRLEN_MAX)
- return 0;
- strncpy(buf, range, p - range);
- buf[p - range] = '\0';
- min = strtoul(buf, &endptr, 10);
- if (*endptr != '\0')
- return 0;
-
- range = p + 1;
- p = strchr(range, '>');
- if (p == NULL)
- return 0;
- if (p - range > DECIMAL_STRLEN_MAX)
- return 0;
- strncpy(buf, range, p - range);
- buf[p - range] = '\0';
- max = strtoul(buf, &endptr, 10);
- if (*endptr != '\0')
- return 0;
-
- if (val < min || val > max)
- return 0;
-
- return 1;
-}
-
-/* Make completion match and return match type flag. */
-static enum match_type
-cmd_filter_by_completion(char *command, vector v, unsigned int index)
-{
- unsigned int i;
- const char *str;
- struct cmd_element *cmd_element;
- enum match_type match_type;
- vector descvec;
- struct desc *desc;
-
- match_type = no_match;
-
- /* If command and cmd_element string does not match set NULL to vector */
- for (i = 0; i < vector_active(v); i++)
- if ((cmd_element = vector_slot(v, i)) != NULL) {
- if (index >= vector_active(cmd_element->strvec))
- vector_slot(v, i) = NULL;
- else {
- unsigned int j;
- int matched = 0;
-
- descvec =
- vector_slot(cmd_element->strvec, index);
-
- for (j = 0; j < vector_active(descvec); j++)
- if ((desc = vector_slot(descvec, j))) {
- str = desc->cmd;
-
- if (CMD_VARARG(str)) {
- if (match_type <
- vararg_match)
- match_type =
- vararg_match;
- matched++;
- } else if (CMD_RANGE(str)) {
- if (cmd_range_match
- (str, command)) {
- if (match_type <
- range_match)
- match_type
- =
- range_match;
-
- matched++;
- }
- }
-#ifdef HAVE_IPV6
- else if (CMD_IPV6(str)) {
- if (cmd_ipv6_match
- (command)) {
- if (match_type <
- ipv6_match)
- match_type
- =
- ipv6_match;
-
- matched++;
- }
- } else if (CMD_IPV6_PREFIX(str)) {
- if (cmd_ipv6_prefix_match(command)) {
- if (match_type <
- ipv6_prefix_match)
- match_type
- =
- ipv6_prefix_match;
-
- matched++;
- }
- }
-#endif /* HAVE_IPV6 */
- else if (CMD_IPV4(str)) {
- if (cmd_ipv4_match
- (command)) {
- if (match_type <
- ipv4_match)
- match_type
- =
- ipv4_match;
-
- matched++;
- }
- } else if (CMD_IPV4_PREFIX(str)) {
- if (cmd_ipv4_prefix_match(command)) {
- if (match_type <
- ipv4_prefix_match)
- match_type
- =
- ipv4_prefix_match;
- matched++;
- }
- } else
- /* Check is this point's argument optional ? */
- if (CMD_OPTION(str)
- ||
- CMD_VARIABLE(str)) {
- if (match_type <
- extend_match)
- match_type =
- extend_match;
- matched++;
- } else
- if (strncmp
- (command, str,
- strlen(command)) ==
- 0) {
- if (strcmp(command, str)
- == 0)
- match_type =
- exact_match;
- else {
- if (match_type <
- partly_match)
- match_type
- =
- partly_match;
- }
- matched++;
- }
- }
- if (!matched)
- vector_slot(v, i) = NULL;
- }
- }
- return match_type;
-}
-
-/* Filter vector by command character with index. */
-static enum match_type
-cmd_filter_by_string(char *command, vector v, unsigned int index)
-{
- unsigned int i;
- const char *str;
- struct cmd_element *cmd_element;
- enum match_type match_type;
- vector descvec;
- struct desc *desc;
-
- match_type = no_match;
-
- /* If command and cmd_element string does not match set NULL to vector */
- for (i = 0; i < vector_active(v); i++)
- if ((cmd_element = vector_slot(v, i)) != NULL) {
- /* If given index is bigger than max string vector of command,
- set NULL */
- if (index >= vector_active(cmd_element->strvec))
- vector_slot(v, i) = NULL;
- else {
- unsigned int j;
- int matched = 0;
-
- descvec =
- vector_slot(cmd_element->strvec, index);
-
- for (j = 0; j < vector_active(descvec); j++)
- if ((desc = vector_slot(descvec, j))) {
- str = desc->cmd;
-
- if (CMD_VARARG(str)) {
- if (match_type <
- vararg_match)
- match_type =
- vararg_match;
- matched++;
- } else if (CMD_RANGE(str)) {
- if (cmd_range_match
- (str, command)) {
- if (match_type <
- range_match)
- match_type
- =
- range_match;
- matched++;
- }
- }
-#ifdef HAVE_IPV6
- else if (CMD_IPV6(str)) {
- if (cmd_ipv6_match
- (command) ==
- exact_match) {
- if (match_type <
- ipv6_match)
- match_type
- =
- ipv6_match;
- matched++;
- }
- } else if (CMD_IPV6_PREFIX(str)) {
- if (cmd_ipv6_prefix_match(command) == exact_match) {
- if (match_type <
- ipv6_prefix_match)
- match_type
- =
- ipv6_prefix_match;
- matched++;
- }
- }
-#endif /* HAVE_IPV6 */
- else if (CMD_IPV4(str)) {
- if (cmd_ipv4_match
- (command) ==
- exact_match) {
- if (match_type <
- ipv4_match)
- match_type
- =
- ipv4_match;
- matched++;
- }
- } else if (CMD_IPV4_PREFIX(str)) {
- if (cmd_ipv4_prefix_match(command) == exact_match) {
- if (match_type <
- ipv4_prefix_match)
- match_type
- =
- ipv4_prefix_match;
- matched++;
- }
- } else if (CMD_OPTION(str)
- || CMD_VARIABLE(str))
- {
- if (match_type <
- extend_match)
- match_type =
- extend_match;
- matched++;
- } else {
- if (strcmp(command, str)
- == 0) {
- match_type =
- exact_match;
- matched++;
- }
- }
- }
- if (!matched)
- vector_slot(v, i) = NULL;
- }
- }
- return match_type;
-}
-
-/* Check ambiguous match */
-static int
-is_cmd_ambiguous(char *command, vector v, int index, enum match_type type)
-{
- unsigned int i;
- unsigned int j;
- const char *str = NULL;
- struct cmd_element *cmd_element;
- const char *matched = NULL;
- vector descvec;
- struct desc *desc;
-
- for (i = 0; i < vector_active(v); i++)
- if ((cmd_element = vector_slot(v, i)) != NULL) {
- int match = 0;
-
- descvec = vector_slot(cmd_element->strvec, index);
-
- for (j = 0; j < vector_active(descvec); j++)
- if ((desc = vector_slot(descvec, j))) {
- enum match_type ret;
-
- str = desc->cmd;
-
- switch (type) {
- case exact_match:
- if (!
- (CMD_OPTION(str)
- || CMD_VARIABLE(str))
-&& strcmp(command, str) == 0)
- match++;
- break;
- case partly_match:
- if (!
- (CMD_OPTION(str)
- || CMD_VARIABLE(str))
-&& strncmp(command, str, strlen(command)) == 0) {
- if (matched
- && strcmp(matched,
- str) != 0)
- return 1; /* There is ambiguous match. */
- else
- matched = str;
- match++;
- }
- break;
- case range_match:
- if (cmd_range_match
- (str, command)) {
- if (matched
- && strcmp(matched,
- str) != 0)
- return 1;
- else
- matched = str;
- match++;
- }
- break;
-#ifdef HAVE_IPV6
- case ipv6_match:
- if (CMD_IPV6(str))
- match++;
- break;
- case ipv6_prefix_match:
- if ((ret =
- cmd_ipv6_prefix_match
- (command)) != no_match) {
- if (ret == partly_match)
- return 2; /* There is incomplete match. */
-
- match++;
- }
- break;
-#endif /* HAVE_IPV6 */
- case ipv4_match:
- if (CMD_IPV4(str))
- match++;
- break;
- case ipv4_prefix_match:
- if ((ret =
- cmd_ipv4_prefix_match
- (command)) != no_match) {
- if (ret == partly_match)
- return 2; /* There is incomplete match. */
-
- match++;
- }
- break;
- case extend_match:
- if (CMD_OPTION(str)
- || CMD_VARIABLE(str))
- match++;
- break;
- case no_match:
- default:
- break;
- }
- }
- if (!match)
- vector_slot(v, i) = NULL;
- }
- return 0;
-}
-
-/* If src matches dst return dst string, otherwise return NULL */
-static const char *cmd_entry_function(const char *src, const char *dst)
-{
- /* Skip variable arguments. */
- if (CMD_OPTION(dst) || CMD_VARIABLE(dst) || CMD_VARARG(dst) ||
- CMD_IPV4(dst) || CMD_IPV4_PREFIX(dst) || CMD_RANGE(dst))
- return NULL;
-
- /* In case of 'command \t', given src is NULL string. */
- if (src == NULL)
- return dst;
-
- /* Matched with input string. */
- if (strncmp(src, dst, strlen(src)) == 0)
- return dst;
-
- return NULL;
-}
-
-/* If src matches dst return dst string, otherwise return NULL */
-/* This version will return the dst string always if it is
- CMD_VARIABLE for '?' key processing */
-static const char *cmd_entry_function_desc(const char *src, const char *dst)
-{
- if (CMD_VARARG(dst))
- return dst;
-
- if (CMD_RANGE(dst)) {
- if (cmd_range_match(dst, src))
- return dst;
- else
- return NULL;
- }
-#ifdef HAVE_IPV6
- if (CMD_IPV6(dst)) {
- if (cmd_ipv6_match(src))
- return dst;
- else
- return NULL;
- }
-
- if (CMD_IPV6_PREFIX(dst)) {
- if (cmd_ipv6_prefix_match(src))
- return dst;
- else
- return NULL;
- }
-#endif /* HAVE_IPV6 */
-
- if (CMD_IPV4(dst)) {
- if (cmd_ipv4_match(src))
- return dst;
- else
- return NULL;
- }
-
- if (CMD_IPV4_PREFIX(dst)) {
- if (cmd_ipv4_prefix_match(src))
- return dst;
- else
- return NULL;
- }
-
- /* Optional or variable commands always match on '?' */
- if (CMD_OPTION(dst) || CMD_VARIABLE(dst))
- return dst;
-
- /* In case of 'command \t', given src is NULL string. */
- if (src == NULL)
- return dst;
-
- if (strncmp(src, dst, strlen(src)) == 0)
- return dst;
- else
- return NULL;
-}
-
-/* Check same string element existence. If it isn't there return
- 1. */
-static int cmd_unique_string(vector v, const char *str)
-{
- unsigned int i;
- char *match;
-
- for (i = 0; i < vector_active(v); i++)
- if ((match = vector_slot(v, i)) != NULL)
- if (strcmp(match, str) == 0)
- return 0;
- return 1;
-}
-
-/* Compare string to description vector. If there is same string
- return 1 else return 0. */
-static int desc_unique_string(vector v, const char *str)
-{
- unsigned int i;
- struct desc *desc;
-
- for (i = 0; i < vector_active(v); i++)
- if ((desc = vector_slot(v, i)) != NULL)
- if (strcmp(desc->cmd, str) == 0)
- return 1;
- return 0;
-}
-
-static int cmd_try_do_shortcut(enum node_type node, char *first_word)
-{
- if (first_word != NULL &&
- node != AUTH_NODE &&
- node != VIEW_NODE &&
- node != AUTH_ENABLE_NODE &&
- node != ENABLE_NODE && 0 == strcmp("do", first_word))
- return 1;
- return 0;
-}
-
-/* '?' describe command support. */
-static vector
-cmd_describe_command_real(vector vline, struct vty *vty, int *status)
-{
- unsigned int i;
- vector cmd_vector;
-#define INIT_MATCHVEC_SIZE 10
- vector matchvec;
- struct cmd_element *cmd_element;
- unsigned int index;
- int ret;
- enum match_type match;
- char *command;
- static struct desc desc_cr = { "<cr>", "" };
-
- /* Set index. */
- if (vector_active(vline) == 0) {
- *status = CMD_ERR_NO_MATCH;
- return NULL;
- } else
- index = vector_active(vline) - 1;
-
- /* Make copy vector of current node's command vector. */
- cmd_vector = vector_copy(cmd_node_vector(cmdvec, vty->node));
-
- /* Prepare match vector */
- matchvec = vector_init(INIT_MATCHVEC_SIZE);
-
- /* Filter commands. */
- /* Only words precedes current word will be checked in this loop. */
- for (i = 0; i < index; i++)
- if ((command = vector_slot(vline, i))) {
- match =
- cmd_filter_by_completion(command, cmd_vector, i);
-
- if (match == vararg_match) {
- struct cmd_element *cmd_element;
- vector descvec;
- unsigned int j, k;
-
- for (j = 0; j < vector_active(cmd_vector); j++)
- if ((cmd_element =
- vector_slot(cmd_vector, j)) != NULL
- &&
- (vector_active
- (cmd_element->strvec))) {
- descvec =
- vector_slot(cmd_element->
- strvec,
- vector_active
- (cmd_element->
- strvec) - 1);
- for (k = 0;
- k < vector_active(descvec);
- k++) {
- struct desc *desc =
- vector_slot(descvec,
- k);
- vector_set(matchvec,
- desc);
- }
- }
-
- vector_set(matchvec, &desc_cr);
- vector_free(cmd_vector);
-
- return matchvec;
- }
-
- if ((ret =
- is_cmd_ambiguous(command, cmd_vector, i,
- match)) == 1) {
- vector_free(cmd_vector);
- *status = CMD_ERR_AMBIGUOUS;
- return NULL;
- } else if (ret == 2) {
- vector_free(cmd_vector);
- *status = CMD_ERR_NO_MATCH;
- return NULL;
- }
- }
-
- /* Prepare match vector */
- /* matchvec = vector_init (INIT_MATCHVEC_SIZE); */
-
- /* Make sure that cmd_vector is filtered based on current word */
- command = vector_slot(vline, index);
- if (command)
- match = cmd_filter_by_completion(command, cmd_vector, index);
-
- /* Make description vector. */
- for (i = 0; i < vector_active(cmd_vector); i++)
- if ((cmd_element = vector_slot(cmd_vector, i)) != NULL) {
- const char *string = NULL;
- vector strvec = cmd_element->strvec;
-
- /* if command is NULL, index may be equal to vector_active */
- if (command && index >= vector_active(strvec))
- vector_slot(cmd_vector, i) = NULL;
- else {
- /* Check if command is completed. */
- if (command == NULL
- && index == vector_active(strvec)) {
- string = "<cr>";
- if (!desc_unique_string
- (matchvec, string))
- vector_set(matchvec, &desc_cr);
- } else {
- unsigned int j;
- vector descvec =
- vector_slot(strvec, index);
- struct desc *desc;
-
- for (j = 0; j < vector_active(descvec);
- j++)
- if ((desc =
- vector_slot(descvec, j))) {
- string =
- cmd_entry_function_desc
- (command,
- desc->cmd);
- if (string) {
- /* Uniqueness check */
- if (!desc_unique_string(matchvec, string))
- vector_set
- (matchvec,
- desc);
- }
- }
- }
- }
- }
- vector_free(cmd_vector);
-
- if (vector_slot(matchvec, 0) == NULL) {
- vector_free(matchvec);
- *status = CMD_ERR_NO_MATCH;
- } else
- *status = CMD_SUCCESS;
-
- return matchvec;
-}
-
-vector cmd_describe_command(vector vline, struct vty * vty, int *status)
-{
- vector ret;
-
- if (cmd_try_do_shortcut(vty->node, vector_slot(vline, 0))) {
- enum node_type onode;
- vector shifted_vline;
- unsigned int index;
-
- onode = vty->node;
- vty->node = ENABLE_NODE;
- /* We can try it on enable node, cos' the vty is authenticated */
-
- shifted_vline = vector_init(vector_count(vline));
- /* use memcpy? */
- for (index = 1; index < vector_active(vline); index++) {
- vector_set_index(shifted_vline, index - 1,
- vector_lookup(vline, index));
- }
-
- ret = cmd_describe_command_real(shifted_vline, vty, status);
-
- vector_free(shifted_vline);
- vty->node = onode;
- return ret;
- }
-
- return cmd_describe_command_real(vline, vty, status);
-}
-
-/* Check LCD of matched command. */
-static int cmd_lcd(char **matched)
-{
- int i;
- int j;
- int lcd = -1;
- char *s1, *s2;
- char c1, c2;
-
- if (matched[0] == NULL || matched[1] == NULL)
- return 0;
-
- for (i = 1; matched[i] != NULL; i++) {
- s1 = matched[i - 1];
- s2 = matched[i];
-
- for (j = 0; (c1 = s1[j]) && (c2 = s2[j]); j++)
- if (c1 != c2)
- break;
-
- if (lcd < 0)
- lcd = j;
- else {
- if (lcd > j)
- lcd = j;
- }
- }
- return lcd;
-}
-
-/* Command line completion support. */
-static char **cmd_complete_command_real(vector vline, struct vty *vty,
- int *status)
-{
- unsigned int i;
- vector cmd_vector = vector_copy(cmd_node_vector(cmdvec, vty->node));
-#define INIT_MATCHVEC_SIZE 10
- vector matchvec;
- struct cmd_element *cmd_element;
- unsigned int index;
- char **match_str;
- struct desc *desc;
- vector descvec;
- char *command;
- int lcd;
-
- if (vector_active(vline) == 0) {
- *status = CMD_ERR_NO_MATCH;
- return NULL;
- } else
- index = vector_active(vline) - 1;
-
- /* First, filter by preceeding command string */
- for (i = 0; i < index; i++)
- if ((command = vector_slot(vline, i))) {
- enum match_type match;
- int ret;
-
- /* First try completion match, if there is exactly match return 1 */
- match =
- cmd_filter_by_completion(command, cmd_vector, i);
-
- /* If there is exact match then filter ambiguous match else check
- ambiguousness. */
- if ((ret =
- is_cmd_ambiguous(command, cmd_vector, i,
- match)) == 1) {
- vector_free(cmd_vector);
- *status = CMD_ERR_AMBIGUOUS;
- return NULL;
- }
- /*
- else if (ret == 2)
- {
- vector_free (cmd_vector);
- *status = CMD_ERR_NO_MATCH;
- return NULL;
- }
- */
- }
-
- /* Prepare match vector. */
- matchvec = vector_init(INIT_MATCHVEC_SIZE);
-
- /* Now we got into completion */
- for (i = 0; i < vector_active(cmd_vector); i++)
- if ((cmd_element = vector_slot(cmd_vector, i))) {
- const char *string;
- vector strvec = cmd_element->strvec;
-
- /* Check field length */
- if (index >= vector_active(strvec))
- vector_slot(cmd_vector, i) = NULL;
- else {
- unsigned int j;
-
- descvec = vector_slot(strvec, index);
- for (j = 0; j < vector_active(descvec); j++)
- if ((desc = vector_slot(descvec, j))) {
- if ((string =
- cmd_entry_function
- (vector_slot(vline, index),
- desc->cmd)))
- if (cmd_unique_string
- (matchvec, string))
- vector_set
- (matchvec,
- strdup
- (string));
- }
- }
- }
-
- /* We don't need cmd_vector any more. */
- vector_free(cmd_vector);
-
- /* No matched command */
- if (vector_slot(matchvec, 0) == NULL) {
- vector_free(matchvec);
-
- /* In case of 'command \t' pattern. Do you need '?' command at
- the end of the line. */
- if (vector_slot(vline, index) == '\0')
- *status = CMD_ERR_NOTHING_TODO;
- else
- *status = CMD_ERR_NO_MATCH;
- return NULL;
- }
-
- /* Only one matched */
- if (vector_slot(matchvec, 1) == NULL) {
- match_str = (char **)matchvec->index;
- vector_only_wrapper_free(matchvec);
- *status = CMD_COMPLETE_FULL_MATCH;
- return match_str;
- }
- /* Make it sure last element is NULL. */
- vector_set(matchvec, NULL);
-
- /* Check LCD of matched strings. */
- if (vector_slot(vline, index) != NULL) {
- lcd = cmd_lcd((char **)matchvec->index);
-
- if (lcd) {
- int len = strlen(vector_slot(vline, index));
-
- if (len < lcd) {
- char *lcdstr;
-
- lcdstr = malloc(lcd + 1);
- memcpy(lcdstr, matchvec->index[0], lcd);
- lcdstr[lcd] = '\0';
-
- /* match_str = (char **) &lcdstr; */
-
- /* Free matchvec. */
- for (i = 0; i < vector_active(matchvec); i++) {
- if (vector_slot(matchvec, i))
- free(vector_slot(matchvec, i));
- }
- vector_free(matchvec);
-
- /* Make new matchvec. */
- matchvec = vector_init(INIT_MATCHVEC_SIZE);
- vector_set(matchvec, lcdstr);
- match_str = (char **)matchvec->index;
- vector_only_wrapper_free(matchvec);
-
- *status = CMD_COMPLETE_MATCH;
- return match_str;
- }
- }
- }
-
- match_str = (char **)matchvec->index;
- vector_only_wrapper_free(matchvec);
- *status = CMD_COMPLETE_LIST_MATCH;
- return match_str;
-}
-
-char **cmd_complete_command(vector vline, struct vty *vty, int *status)
-{
- char **ret;
-
- if (cmd_try_do_shortcut(vty->node, vector_slot(vline, 0))) {
- enum node_type onode;
- vector shifted_vline;
- unsigned int index;
-
- onode = vty->node;
- vty->node = ENABLE_NODE;
- /* We can try it on enable node, cos' the vty is authenticated */
-
- shifted_vline = vector_init(vector_count(vline));
- /* use memcpy? */
- for (index = 1; index < vector_active(vline); index++) {
- vector_set_index(shifted_vline, index - 1,
- vector_lookup(vline, index));
- }
-
- ret = cmd_complete_command_real(shifted_vline, vty, status);
-
- vector_free(shifted_vline);
- vty->node = onode;
- return ret;
- }
-
- return cmd_complete_command_real(vline, vty, status);
-}
-
-/* return parent node */
-/* MUST eventually converge on CONFIG_NODE */
-enum node_type node_parent(enum node_type node)
-{
- enum node_type ret;
-
- assert(node > CONFIG_NODE);
-
- switch (node) {
- case BGP_VPNV4_NODE:
- case BGP_IPV4_NODE:
- case BGP_IPV4M_NODE:
- case BGP_IPV6_NODE:
- ret = BGP_NODE;
- break;
- case KEYCHAIN_KEY_NODE:
- ret = KEYCHAIN_NODE;
- break;
- default:
- ret = CONFIG_NODE;
- }
-
- return ret;
-}
-
-/* Execute command by argument vline vector. */
-static int
-cmd_execute_command_real(vector vline, struct vty *vty,
- struct cmd_element **cmd)
-{
- unsigned int i;
- unsigned int index;
- vector cmd_vector;
- struct cmd_element *cmd_element;
- struct cmd_element *matched_element;
- unsigned int matched_count, incomplete_count;
- int argc;
- const char *argv[CMD_ARGC_MAX];
- enum match_type match = 0;
- int varflag;
- char *command;
-
- /* Make copy of command elements. */
- cmd_vector = vector_copy(cmd_node_vector(cmdvec, vty->node));
-
- for (index = 0; index < vector_active(vline); index++)
- if ((command = vector_slot(vline, index))) {
- int ret;
-
- match =
- cmd_filter_by_completion(command, cmd_vector,
- index);
-
- if (match == vararg_match)
- break;
-
- ret =
- is_cmd_ambiguous(command, cmd_vector, index, match);
-
- if (ret == 1) {
- vector_free(cmd_vector);
- return CMD_ERR_AMBIGUOUS;
- } else if (ret == 2) {
- vector_free(cmd_vector);
- return CMD_ERR_NO_MATCH;
- }
- }
-
- /* Check matched count. */
- matched_element = NULL;
- matched_count = 0;
- incomplete_count = 0;
-
- for (i = 0; i < vector_active(cmd_vector); i++)
- if ((cmd_element = vector_slot(cmd_vector, i))) {
- if (match == vararg_match
- || index >= cmd_element->cmdsize) {
- matched_element = cmd_element;
-#if 0
- printf("DEBUG: %s\n", cmd_element->string);
-#endif
- matched_count++;
- } else {
- incomplete_count++;
- }
- }
-
- /* Finish of using cmd_vector. */
- vector_free(cmd_vector);
-
- /* To execute command, matched_count must be 1. */
- if (matched_count == 0) {
- if (incomplete_count)
- return CMD_ERR_INCOMPLETE;
- else
- return CMD_ERR_NO_MATCH;
- }
-
- if (matched_count > 1)
- return CMD_ERR_AMBIGUOUS;
-
- /* Argument treatment */
- varflag = 0;
- argc = 0;
-
- for (i = 0; i < vector_active(vline); i++) {
- if (varflag)
- argv[argc++] = vector_slot(vline, i);
- else {
- vector descvec =
- vector_slot(matched_element->strvec, i);
-
- if (vector_active(descvec) == 1) {
- struct desc *desc = vector_slot(descvec, 0);
-
- if (CMD_VARARG(desc->cmd))
- varflag = 1;
-
- if (varflag || CMD_VARIABLE(desc->cmd)
- || CMD_OPTION(desc->cmd))
- argv[argc++] = vector_slot(vline, i);
- } else
- argv[argc++] = vector_slot(vline, i);
- }
-
- if (argc >= CMD_ARGC_MAX)
- return CMD_ERR_EXEED_ARGC_MAX;
- }
-
- /* For vtysh execution. */
- if (cmd)
- *cmd = matched_element;
-
- if (matched_element->daemon)
- return CMD_SUCCESS_DAEMON;
-
- /* Execute matched command. */
- return (*matched_element->func) (matched_element, vty, argc, argv);
-}
-
-int
-cmd_execute_command(vector vline, struct vty *vty, struct cmd_element **cmd,
- int vtysh)
-{
- int ret, saved_ret, tried = 0;
- enum node_type onode, try_node;
-
- onode = try_node = vty->node;
-
- if (cmd_try_do_shortcut(vty->node, vector_slot(vline, 0))) {
- vector shifted_vline;
- unsigned int index;
-
- vty->node = ENABLE_NODE;
- /* We can try it on enable node, cos' the vty is authenticated */
-
- shifted_vline = vector_init(vector_count(vline));
- /* use memcpy? */
- for (index = 1; index < vector_active(vline); index++) {
- vector_set_index(shifted_vline, index - 1,
- vector_lookup(vline, index));
- }
-
- ret = cmd_execute_command_real(shifted_vline, vty, cmd);
-
- vector_free(shifted_vline);
- vty->node = onode;
- return ret;
- }
-
- saved_ret = ret = cmd_execute_command_real(vline, vty, cmd);
-
- if (vtysh)
- return saved_ret;
-
- /* This assumes all nodes above CONFIG_NODE are childs of CONFIG_NODE */
- while (ret != CMD_SUCCESS && ret != CMD_WARNING
- && vty->node > CONFIG_NODE) {
- try_node = node_parent(try_node);
- vty->node = try_node;
- ret = cmd_execute_command_real(vline, vty, cmd);
- tried = 1;
- if (ret == CMD_SUCCESS || ret == CMD_WARNING) {
- /* succesfull command, leave the node as is */
- return ret;
- }
- }
- /* no command succeeded, reset the vty to the original node and
- return the error for this node */
- if (tried)
- vty->node = onode;
- return saved_ret;
-}
-
-/* Execute command by argument readline. */
-int
-cmd_execute_command_strict(vector vline, struct vty *vty,
- struct cmd_element **cmd)
-{
- unsigned int i;
- unsigned int index;
- vector cmd_vector;
- struct cmd_element *cmd_element;
- struct cmd_element *matched_element;
- unsigned int matched_count, incomplete_count;
- int argc;
- const char *argv[CMD_ARGC_MAX];
- int varflag;
- enum match_type match = 0;
- char *command;
-
- /* Make copy of command element */
- cmd_vector = vector_copy(cmd_node_vector(cmdvec, vty->node));
-
- for (index = 0; index < vector_active(vline); index++)
- if ((command = vector_slot(vline, index))) {
- int ret;
-
- match = cmd_filter_by_string(vector_slot(vline, index),
- cmd_vector, index);
-
- /* If command meets '.VARARG' then finish matching. */
- if (match == vararg_match)
- break;
-
- ret =
- is_cmd_ambiguous(command, cmd_vector, index, match);
- if (ret == 1) {
- vector_free(cmd_vector);
- return CMD_ERR_AMBIGUOUS;
- }
- if (ret == 2) {
- vector_free(cmd_vector);
- return CMD_ERR_NO_MATCH;
- }
- }
-
- /* Check matched count. */
- matched_element = NULL;
- matched_count = 0;
- incomplete_count = 0;
- for (i = 0; i < vector_active(cmd_vector); i++)
- if (vector_slot(cmd_vector, i) != NULL) {
- cmd_element = vector_slot(cmd_vector, i);
-
- if (match == vararg_match
- || index >= cmd_element->cmdsize) {
- matched_element = cmd_element;
- matched_count++;
- } else
- incomplete_count++;
- }
-
- /* Finish of using cmd_vector. */
- vector_free(cmd_vector);
-
- /* To execute command, matched_count must be 1. */
- if (matched_count == 0) {
- if (incomplete_count)
- return CMD_ERR_INCOMPLETE;
- else
- return CMD_ERR_NO_MATCH;
- }
-
- if (matched_count > 1)
- return CMD_ERR_AMBIGUOUS;
-
- /* Argument treatment */
- varflag = 0;
- argc = 0;
-
- for (i = 0; i < vector_active(vline); i++) {
- if (varflag)
- argv[argc++] = vector_slot(vline, i);
- else {
- vector descvec =
- vector_slot(matched_element->strvec, i);
-
- if (vector_active(descvec) == 1) {
- struct desc *desc = vector_slot(descvec, 0);
-
- if (CMD_VARARG(desc->cmd))
- varflag = 1;
-
- if (varflag || CMD_VARIABLE(desc->cmd)
- || CMD_OPTION(desc->cmd))
- argv[argc++] = vector_slot(vline, i);
- } else
- argv[argc++] = vector_slot(vline, i);
- }
-
- if (argc >= CMD_ARGC_MAX)
- return CMD_ERR_EXEED_ARGC_MAX;
- }
-
- /* For vtysh execution. */
- if (cmd)
- *cmd = matched_element;
-
- if (matched_element->daemon)
- return CMD_SUCCESS_DAEMON;
-
- /* Now execute matched command */
- return (*matched_element->func) (matched_element, vty, argc, argv);
-}
-
-#if 0
-/* Configration make from file. */
-int config_from_file(struct vty *vty, FILE * fp)
-{
- int ret;
- vector vline;
-
- while (fgets(vty->buf, VTY_BUFSIZ, fp)) {
- vline = cmd_make_strvec(vty->buf);
-
- /* In case of comment line */
- if (vline == NULL)
- continue;
- /* Execute configuration command : this is strict match */
- ret = cmd_execute_command_strict(vline, vty, NULL);
-
- /* Try again with setting node to CONFIG_NODE */
- while (ret != CMD_SUCCESS && ret != CMD_WARNING
- && ret != CMD_ERR_NOTHING_TODO
- && vty->node != CONFIG_NODE) {
- vty->node = node_parent(vty->node);
- ret = cmd_execute_command_strict(vline, vty, NULL);
- }
-
- cmd_free_strvec(vline);
-
- if (ret != CMD_SUCCESS && ret != CMD_WARNING
- && ret != CMD_ERR_NOTHING_TODO)
- return ret;
- }
- return CMD_SUCCESS;
-}
-#endif
-
-/* Configration from terminal */
-DEFUN(config_terminal,
- config_terminal_cmd,
- "configure terminal",
- "Configuration from vty interface\n" "Configuration terminal\n")
-{
- if (vty_config_lock(vty))
- vty->node = CONFIG_NODE;
- else {
- vty_out(vty, "VTY configuration is locked by other VTY%s",
- VTY_NEWLINE);
- return CMD_WARNING;
- }
- return CMD_SUCCESS;
-}
-
-/* Enable command */
-DEFUN(enable, config_enable_cmd, "enable", "Turn on privileged mode command\n")
-{
- /* If enable password is NULL, change to ENABLE_NODE */
- if ((host.enable == NULL && host.enable_encrypt == NULL) ||
- vty->type == VTY_SHELL_SERV)
- vty->node = ENABLE_NODE;
- else
- vty->node = AUTH_ENABLE_NODE;
-
- return CMD_SUCCESS;
-}
-
-/* Disable command */
-DEFUN(disable,
- config_disable_cmd, "disable", "Turn off privileged mode command\n")
-{
- if (vty->node == ENABLE_NODE)
- vty->node = VIEW_NODE;
- return CMD_SUCCESS;
-}
-
-/* Down vty node level. */
-DEFUN(config_exit,
- config_exit_cmd, "exit", "Exit current mode and down to previous mode\n")
-{
- switch (vty->node) {
- case BTS_NODE:
- vty->node = VIEW_NODE;
- vty->index = NULL;
- break;
- case TRX_NODE:
- vty->node = BTS_NODE;
- {
- /* set vty->index correctly ! */
- struct gsm_bts_trx *trx = vty->index;
- vty->index = trx->bts;
- }
- break;
- case TS_NODE:
- vty->node = TRX_NODE;
- {
- /* set vty->index correctly ! */
- struct gsm_bts_trx_ts *ts = vty->index;
- vty->index = ts->trx;
- }
- break;
- case SUBSCR_NODE:
- vty->node = VIEW_NODE;
- subscr_put(vty->index);
- vty->index = NULL;
- break;
- case VIEW_NODE:
- case ENABLE_NODE:
- if (0) //vty_shell (vty))
- exit(0);
- else
- vty->status = VTY_CLOSE;
- break;
- case CONFIG_NODE:
- vty->node = ENABLE_NODE;
- vty_config_unlock(vty);
- break;
- case INTERFACE_NODE:
- case ZEBRA_NODE:
- case BGP_NODE:
- case RIP_NODE:
- case RIPNG_NODE:
- case OSPF_NODE:
- case OSPF6_NODE:
- case ISIS_NODE:
- case KEYCHAIN_NODE:
- case MASC_NODE:
- case RMAP_NODE:
- case VTY_NODE:
- vty->node = CONFIG_NODE;
- break;
- case BGP_VPNV4_NODE:
- case BGP_IPV4_NODE:
- case BGP_IPV4M_NODE:
- case BGP_IPV6_NODE:
- vty->node = BGP_NODE;
- break;
- case KEYCHAIN_KEY_NODE:
- vty->node = KEYCHAIN_NODE;
- break;
- default:
- break;
- }
- return CMD_SUCCESS;
-}
-
-/* quit is alias of exit. */
-ALIAS(config_exit,
- config_quit_cmd, "quit", "Exit current mode and down to previous mode\n")
-
-/* End of configuration. */
- DEFUN(config_end,
- config_end_cmd, "end", "End current mode and change to enable mode.")
-{
- switch (vty->node) {
- case VIEW_NODE:
- case ENABLE_NODE:
- /* Nothing to do. */
- break;
- case CONFIG_NODE:
- case INTERFACE_NODE:
- case ZEBRA_NODE:
- case RIP_NODE:
- case RIPNG_NODE:
- case BGP_NODE:
- case BGP_VPNV4_NODE:
- case BGP_IPV4_NODE:
- case BGP_IPV4M_NODE:
- case BGP_IPV6_NODE:
- case RMAP_NODE:
- case OSPF_NODE:
- case OSPF6_NODE:
- case ISIS_NODE:
- case KEYCHAIN_NODE:
- case KEYCHAIN_KEY_NODE:
- case MASC_NODE:
- case VTY_NODE:
- vty_config_unlock(vty);
- vty->node = ENABLE_NODE;
- break;
- default:
- break;
- }
- return CMD_SUCCESS;
-}
-
-/* Show version. */
-DEFUN(show_version,
- show_version_cmd, "show version", SHOW_STR "Displays program version\n")
-{
- vty_out(vty, "%s %s (%s).%s", QUAGGA_PROGNAME, QUAGGA_VERSION,
- host.name ? host.name : "", VTY_NEWLINE);
- vty_out(vty, "%s%s", QUAGGA_COPYRIGHT, VTY_NEWLINE);
-
- return CMD_SUCCESS;
-}
-
-/* Help display function for all node. */
-DEFUN(config_help,
- config_help_cmd, "help", "Description of the interactive help system\n")
-{
- vty_out(vty,
- "This VTY provides advanced help features. When you need help,%s\
-anytime at the command line please press '?'.%s\
-%s\
-If nothing matches, the help list will be empty and you must backup%s\
- until entering a '?' shows the available options.%s\
-Two styles of help are provided:%s\
-1. Full help is available when you are ready to enter a%s\
-command argument (e.g. 'show ?') and describes each possible%s\
-argument.%s\
-2. Partial help is provided when an abbreviated argument is entered%s\
- and you want to know what arguments match the input%s\
- (e.g. 'show me?'.)%s%s", VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE,
- VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
- return CMD_SUCCESS;
-}
-
-/* Help display function for all node. */
-DEFUN(config_list, config_list_cmd, "list", "Print command list\n")
-{
- unsigned int i;
- struct cmd_node *cnode = vector_slot(cmdvec, vty->node);
- struct cmd_element *cmd;
-
- for (i = 0; i < vector_active(cnode->cmd_vector); i++)
- if ((cmd = vector_slot(cnode->cmd_vector, i)) != NULL
- && !(cmd->attr == CMD_ATTR_DEPRECATED
- || cmd->attr == CMD_ATTR_HIDDEN))
- vty_out(vty, " %s%s", cmd->string, VTY_NEWLINE);
- return CMD_SUCCESS;
-}
-
-#if 0
-/* Write current configuration into file. */
-DEFUN(config_write_file,
- config_write_file_cmd,
- "write file",
- "Write running configuration to memory, network, or terminal\n"
- "Write to configuration file\n")
-{
- unsigned int i;
- int fd;
- struct cmd_node *node;
- char *config_file;
- char *config_file_tmp = NULL;
- char *config_file_sav = NULL;
- struct vty *file_vty;
-
- /* Check and see if we are operating under vtysh configuration */
- if (host.config == NULL) {
- vty_out(vty, "Can't save to configuration file, using vtysh.%s",
- VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- /* Get filename. */
- config_file = host.config;
-
- config_file_sav =
- malloc(strlen(config_file) + strlen(CONF_BACKUP_EXT) + 1);
- strcpy(config_file_sav, config_file);
- strcat(config_file_sav, CONF_BACKUP_EXT);
-
- config_file_tmp = malloc(strlen(config_file) + 8);
- sprintf(config_file_tmp, "%s.XXXXXX", config_file);
-
- /* Open file to configuration write. */
- fd = mkstemp(config_file_tmp);
- if (fd < 0) {
- vty_out(vty, "Can't open configuration file %s.%s",
- config_file_tmp, VTY_NEWLINE);
- free(config_file_tmp);
- free(config_file_sav);
- return CMD_WARNING;
- }
-
- /* Make vty for configuration file. */
- file_vty = vty_new();
- file_vty->fd = fd;
- file_vty->type = VTY_FILE;
-
- /* Config file header print. */
- vty_out(file_vty, "!\n! Zebra configuration saved from vty\n! ");
- //vty_time_print (file_vty, 1);
- vty_out(file_vty, "!\n");
-
- for (i = 0; i < vector_active(cmdvec); i++)
- if ((node = vector_slot(cmdvec, i)) && node->func) {
- if ((*node->func) (file_vty))
- vty_out(file_vty, "!\n");
- }
- vty_close(file_vty);
-
- if (unlink(config_file_sav) != 0)
- if (errno != ENOENT) {
- vty_out(vty,
- "Can't unlink backup configuration file %s.%s",
- config_file_sav, VTY_NEWLINE);
- free(config_file_sav);
- free(config_file_tmp);
- unlink(config_file_tmp);
- return CMD_WARNING;
- }
- if (link(config_file, config_file_sav) != 0) {
- vty_out(vty, "Can't backup old configuration file %s.%s",
- config_file_sav, VTY_NEWLINE);
- free(config_file_sav);
- free(config_file_tmp);
- unlink(config_file_tmp);
- return CMD_WARNING;
- }
- sync();
- if (unlink(config_file) != 0) {
- vty_out(vty, "Can't unlink configuration file %s.%s",
- config_file, VTY_NEWLINE);
- free(config_file_sav);
- free(config_file_tmp);
- unlink(config_file_tmp);
- return CMD_WARNING;
- }
- if (link(config_file_tmp, config_file) != 0) {
- vty_out(vty, "Can't save configuration file %s.%s", config_file,
- VTY_NEWLINE);
- free(config_file_sav);
- free(config_file_tmp);
- unlink(config_file_tmp);
- return CMD_WARNING;
- }
- unlink(config_file_tmp);
- sync();
-
- free(config_file_sav);
- free(config_file_tmp);
-
- if (chmod(config_file, CONFIGFILE_MASK) != 0) {
- vty_out(vty, "Can't chmod configuration file %s: %s (%d).%s",
- config_file, safe_strerror(errno), errno, VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- vty_out(vty, "Configuration saved to %s%s", config_file, VTY_NEWLINE);
- return CMD_SUCCESS;
-}
-
-ALIAS(config_write_file,
- config_write_cmd,
- "write", "Write running configuration to memory, network, or terminal\n")
-
- ALIAS(config_write_file,
- config_write_memory_cmd,
- "write memory",
- "Write running configuration to memory, network, or terminal\n"
- "Write configuration to the file (same as write file)\n")
-
- ALIAS(config_write_file,
- copy_runningconfig_startupconfig_cmd,
- "copy running-config startup-config",
- "Copy configuration\n"
- "Copy running config to... \n"
- "Copy running config to startup config (same as write file)\n")
-
-/* Write current configuration into the terminal. */
- DEFUN(config_write_terminal,
- config_write_terminal_cmd,
- "write terminal",
- "Write running configuration to memory, network, or terminal\n"
- "Write to terminal\n")
-{
- unsigned int i;
- struct cmd_node *node;
-
- if (vty->type == VTY_SHELL_SERV) {
- for (i = 0; i < vector_active(cmdvec); i++)
- if ((node = vector_slot(cmdvec, i)) && node->func
- && node->vtysh) {
- if ((*node->func) (vty))
- vty_out(vty, "!%s", VTY_NEWLINE);
- }
- } else {
- vty_out(vty, "%sCurrent configuration:%s", VTY_NEWLINE,
- VTY_NEWLINE);
- vty_out(vty, "!%s", VTY_NEWLINE);
-
- for (i = 0; i < vector_active(cmdvec); i++)
- if ((node = vector_slot(cmdvec, i)) && node->func) {
- if ((*node->func) (vty))
- vty_out(vty, "!%s", VTY_NEWLINE);
- }
- vty_out(vty, "end%s", VTY_NEWLINE);
- }
- return CMD_SUCCESS;
-}
-
-/* Write current configuration into the terminal. */
-ALIAS(config_write_terminal,
- show_running_config_cmd,
- "show running-config", SHOW_STR "running configuration\n")
-
-/* Write startup configuration into the terminal. */
- DEFUN(show_startup_config,
- show_startup_config_cmd,
- "show startup-config", SHOW_STR "Contentes of startup configuration\n")
-{
- char buf[BUFSIZ];
- FILE *confp;
-
- confp = fopen(host.config, "r");
- if (confp == NULL) {
- vty_out(vty, "Can't open configuration file [%s]%s",
- host.config, VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- while (fgets(buf, BUFSIZ, confp)) {
- char *cp = buf;
-
- while (*cp != '\r' && *cp != '\n' && *cp != '\0')
- cp++;
- *cp = '\0';
-
- vty_out(vty, "%s%s", buf, VTY_NEWLINE);
- }
-
- fclose(confp);
-
- return CMD_SUCCESS;
-}
-#endif
-
-/* Hostname configuration */
-DEFUN(config_hostname,
- hostname_cmd,
- "hostname WORD",
- "Set system's network name\n" "This system's network name\n")
-{
- if (!isalpha((int)*argv[0])) {
- vty_out(vty, "Please specify string starting with alphabet%s",
- VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- if (host.name)
- free(host.name);
-
- host.name = strdup(argv[0]);
- return CMD_SUCCESS;
-}
-
-DEFUN(config_no_hostname,
- no_hostname_cmd,
- "no hostname [HOSTNAME]",
- NO_STR "Reset system's network name\n" "Host name of this router\n")
-{
- if (host.name)
- free(host.name);
- host.name = NULL;
- return CMD_SUCCESS;
-}
-
-/* VTY interface password set. */
-DEFUN(config_password, password_cmd,
- "password (8|) WORD",
- "Assign the terminal connection password\n"
- "Specifies a HIDDEN password will follow\n"
- "dummy string \n" "The HIDDEN line password string\n")
-{
- /* Argument check. */
- if (argc == 0) {
- vty_out(vty, "Please specify password.%s", VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- if (argc == 2) {
- if (*argv[0] == '8') {
- if (host.password)
- free(host.password);
- host.password = NULL;
- if (host.password_encrypt)
- free(host.password_encrypt);
- host.password_encrypt = strdup(strdup(argv[1]));
- return CMD_SUCCESS;
- } else {
- vty_out(vty, "Unknown encryption type.%s", VTY_NEWLINE);
- return CMD_WARNING;
- }
- }
-
- if (!isalnum((int)*argv[0])) {
- vty_out(vty,
- "Please specify string starting with alphanumeric%s",
- VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- if (host.password)
- free(host.password);
- host.password = NULL;
-
-#ifdef VTY_CRYPT_PW
- if (host.encrypt) {
- if (host.password_encrypt)
- free(host.password_encrypt);
- host.password_encrypt = strdup(zencrypt(argv[0]));
- } else
-#endif
- host.password = strdup(argv[0]);
-
- return CMD_SUCCESS;
-}
-
-ALIAS(config_password, password_text_cmd,
- "password LINE",
- "Assign the terminal connection password\n"
- "The UNENCRYPTED (cleartext) line password\n")
-
-/* VTY enable password set. */
- DEFUN(config_enable_password, enable_password_cmd,
- "enable password (8|) WORD",
- "Modify enable password parameters\n"
- "Assign the privileged level password\n"
- "Specifies a HIDDEN password will follow\n"
- "dummy string \n" "The HIDDEN 'enable' password string\n")
-{
- /* Argument check. */
- if (argc == 0) {
- vty_out(vty, "Please specify password.%s", VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- /* Crypt type is specified. */
- if (argc == 2) {
- if (*argv[0] == '8') {
- if (host.enable)
- free(host.enable);
- host.enable = NULL;
-
- if (host.enable_encrypt)
- free(host.enable_encrypt);
- host.enable_encrypt = strdup(argv[1]);
-
- return CMD_SUCCESS;
- } else {
- vty_out(vty, "Unknown encryption type.%s", VTY_NEWLINE);
- return CMD_WARNING;
- }
- }
-
- if (!isalnum((int)*argv[0])) {
- vty_out(vty,
- "Please specify string starting with alphanumeric%s",
- VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- if (host.enable)
- free(host.enable);
- host.enable = NULL;
-
- /* Plain password input. */
-#ifdef VTY_CRYPT_PW
- if (host.encrypt) {
- if (host.enable_encrypt)
- free(host.enable_encrypt);
- host.enable_encrypt = strdup(zencrypt(argv[0]));
- } else
-#endif
- host.enable = strdup(argv[0]);
-
- return CMD_SUCCESS;
-}
-
-ALIAS(config_enable_password,
- enable_password_text_cmd,
- "enable password LINE",
- "Modify enable password parameters\n"
- "Assign the privileged level password\n"
- "The UNENCRYPTED (cleartext) 'enable' password\n")
-
-/* VTY enable password delete. */
- DEFUN(no_config_enable_password, no_enable_password_cmd,
- "no enable password",
- NO_STR
- "Modify enable password parameters\n"
- "Assign the privileged level password\n")
-{
- if (host.enable)
- free(host.enable);
- host.enable = NULL;
-
- if (host.enable_encrypt)
- free(host.enable_encrypt);
- host.enable_encrypt = NULL;
-
- return CMD_SUCCESS;
-}
-
-#ifdef VTY_CRYPT_PW
-DEFUN(service_password_encrypt,
- service_password_encrypt_cmd,
- "service password-encryption",
- "Set up miscellaneous service\n" "Enable encrypted passwords\n")
-{
- if (host.encrypt)
- return CMD_SUCCESS;
-
- host.encrypt = 1;
-
- if (host.password) {
- if (host.password_encrypt)
- free(host.password_encrypt);
- host.password_encrypt = strdup(zencrypt(host.password));
- }
- if (host.enable) {
- if (host.enable_encrypt)
- free(host.enable_encrypt);
- host.enable_encrypt = strdup(zencrypt(host.enable));
- }
-
- return CMD_SUCCESS;
-}
-
-DEFUN(no_service_password_encrypt,
- no_service_password_encrypt_cmd,
- "no service password-encryption",
- NO_STR "Set up miscellaneous service\n" "Enable encrypted passwords\n")
-{
- if (!host.encrypt)
- return CMD_SUCCESS;
-
- host.encrypt = 0;
-
- if (host.password_encrypt)
- free(host.password_encrypt);
- host.password_encrypt = NULL;
-
- if (host.enable_encrypt)
- free(host.enable_encrypt);
- host.enable_encrypt = NULL;
-
- return CMD_SUCCESS;
-}
-#endif
-
-DEFUN(config_terminal_length, config_terminal_length_cmd,
- "terminal length <0-512>",
- "Set terminal line parameters\n"
- "Set number of lines on a screen\n"
- "Number of lines on screen (0 for no pausing)\n")
-{
- int lines;
- char *endptr = NULL;
-
- lines = strtol(argv[0], &endptr, 10);
- if (lines < 0 || lines > 512 || *endptr != '\0') {
- vty_out(vty, "length is malformed%s", VTY_NEWLINE);
- return CMD_WARNING;
- }
- vty->lines = lines;
-
- return CMD_SUCCESS;
-}
-
-DEFUN(config_terminal_no_length, config_terminal_no_length_cmd,
- "terminal no length",
- "Set terminal line parameters\n"
- NO_STR "Set number of lines on a screen\n")
-{
- vty->lines = -1;
- return CMD_SUCCESS;
-}
-
-DEFUN(service_terminal_length, service_terminal_length_cmd,
- "service terminal-length <0-512>",
- "Set up miscellaneous service\n"
- "System wide terminal length configuration\n"
- "Number of lines of VTY (0 means no line control)\n")
-{
- int lines;
- char *endptr = NULL;
-
- lines = strtol(argv[0], &endptr, 10);
- if (lines < 0 || lines > 512 || *endptr != '\0') {
- vty_out(vty, "length is malformed%s", VTY_NEWLINE);
- return CMD_WARNING;
- }
- host.lines = lines;
-
- return CMD_SUCCESS;
-}
-
-DEFUN(no_service_terminal_length, no_service_terminal_length_cmd,
- "no service terminal-length [<0-512>]",
- NO_STR
- "Set up miscellaneous service\n"
- "System wide terminal length configuration\n"
- "Number of lines of VTY (0 means no line control)\n")
-{
- host.lines = -1;
- return CMD_SUCCESS;
-}
-
-DEFUN_HIDDEN(do_echo,
- echo_cmd,
- "echo .MESSAGE",
- "Echo a message back to the vty\n" "The message to echo\n")
-{
- char *message;
-
- vty_out(vty, "%s%s",
- ((message =
- argv_concat(argv, argc, 0)) ? message : ""), VTY_NEWLINE);
- if (message)
- free(message);
- return CMD_SUCCESS;
-}
-
-#if 0
-DEFUN(config_logmsg,
- config_logmsg_cmd,
- "logmsg " LOG_LEVELS " .MESSAGE",
- "Send a message to enabled logging destinations\n"
- LOG_LEVEL_DESC "The message to send\n")
-{
- int level;
- char *message;
-
- if ((level = level_match(argv[0])) == ZLOG_DISABLED)
- return CMD_ERR_NO_MATCH;
-
- zlog(NULL, level,
- ((message = argv_concat(argv, argc, 1)) ? message : ""));
- if (message)
- free(message);
- return CMD_SUCCESS;
-}
-
-DEFUN(show_logging,
- show_logging_cmd,
- "show logging", SHOW_STR "Show current logging configuration\n")
-{
- struct zlog *zl = zlog_default;
-
- vty_out(vty, "Syslog logging: ");
- if (zl->maxlvl[ZLOG_DEST_SYSLOG] == ZLOG_DISABLED)
- vty_out(vty, "disabled");
- else
- vty_out(vty, "level %s, facility %s, ident %s",
- zlog_priority[zl->maxlvl[ZLOG_DEST_SYSLOG]],
- facility_name(zl->facility), zl->ident);
- vty_out(vty, "%s", VTY_NEWLINE);
-
- vty_out(vty, "Stdout logging: ");
- if (zl->maxlvl[ZLOG_DEST_STDOUT] == ZLOG_DISABLED)
- vty_out(vty, "disabled");
- else
- vty_out(vty, "level %s",
- zlog_priority[zl->maxlvl[ZLOG_DEST_STDOUT]]);
- vty_out(vty, "%s", VTY_NEWLINE);
-
- vty_out(vty, "Monitor logging: ");
- if (zl->maxlvl[ZLOG_DEST_MONITOR] == ZLOG_DISABLED)
- vty_out(vty, "disabled");
- else
- vty_out(vty, "level %s",
- zlog_priority[zl->maxlvl[ZLOG_DEST_MONITOR]]);
- vty_out(vty, "%s", VTY_NEWLINE);
-
- vty_out(vty, "File logging: ");
- if ((zl->maxlvl[ZLOG_DEST_FILE] == ZLOG_DISABLED) || !zl->fp)
- vty_out(vty, "disabled");
- else
- vty_out(vty, "level %s, filename %s",
- zlog_priority[zl->maxlvl[ZLOG_DEST_FILE]],
- zl->filename);
- vty_out(vty, "%s", VTY_NEWLINE);
-
- vty_out(vty, "Protocol name: %s%s",
- zlog_proto_names[zl->protocol], VTY_NEWLINE);
- vty_out(vty, "Record priority: %s%s",
- (zl->record_priority ? "enabled" : "disabled"), VTY_NEWLINE);
-
- return CMD_SUCCESS;
-}
-
-DEFUN(config_log_stdout,
- config_log_stdout_cmd,
- "log stdout", "Logging control\n" "Set stdout logging level\n")
-{
- zlog_set_level(NULL, ZLOG_DEST_STDOUT, zlog_default->default_lvl);
- return CMD_SUCCESS;
-}
-
-DEFUN(config_log_stdout_level,
- config_log_stdout_level_cmd,
- "log stdout " LOG_LEVELS,
- "Logging control\n" "Set stdout logging level\n" LOG_LEVEL_DESC)
-{
- int level;
-
- if ((level = level_match(argv[0])) == ZLOG_DISABLED)
- return CMD_ERR_NO_MATCH;
- zlog_set_level(NULL, ZLOG_DEST_STDOUT, level);
- return CMD_SUCCESS;
-}
-
-DEFUN(no_config_log_stdout,
- no_config_log_stdout_cmd,
- "no log stdout [LEVEL]",
- NO_STR "Logging control\n" "Cancel logging to stdout\n" "Logging level\n")
-{
- zlog_set_level(NULL, ZLOG_DEST_STDOUT, ZLOG_DISABLED);
- return CMD_SUCCESS;
-}
-
-DEFUN(config_log_monitor,
- config_log_monitor_cmd,
- "log monitor",
- "Logging control\n" "Set terminal line (monitor) logging level\n")
-{
- zlog_set_level(NULL, ZLOG_DEST_MONITOR, zlog_default->default_lvl);
- return CMD_SUCCESS;
-}
-
-DEFUN(config_log_monitor_level,
- config_log_monitor_level_cmd,
- "log monitor " LOG_LEVELS,
- "Logging control\n"
- "Set terminal line (monitor) logging level\n" LOG_LEVEL_DESC)
-{
- int level;
-
- if ((level = level_match(argv[0])) == ZLOG_DISABLED)
- return CMD_ERR_NO_MATCH;
- zlog_set_level(NULL, ZLOG_DEST_MONITOR, level);
- return CMD_SUCCESS;
-}
-
-DEFUN(no_config_log_monitor,
- no_config_log_monitor_cmd,
- "no log monitor [LEVEL]",
- NO_STR
- "Logging control\n"
- "Disable terminal line (monitor) logging\n" "Logging level\n")
-{
- zlog_set_level(NULL, ZLOG_DEST_MONITOR, ZLOG_DISABLED);
- return CMD_SUCCESS;
-}
-
-static int set_log_file(struct vty *vty, const char *fname, int loglevel)
-{
- int ret;
- char *p = NULL;
- const char *fullpath;
-
- /* Path detection. */
- if (!IS_DIRECTORY_SEP(*fname)) {
- char cwd[MAXPATHLEN + 1];
- cwd[MAXPATHLEN] = '\0';
-
- if (getcwd(cwd, MAXPATHLEN) == NULL) {
- zlog_err("config_log_file: Unable to alloc mem!");
- return CMD_WARNING;
- }
-
- if ((p = malloc(strlen(cwd) + strlen(fname) + 2))
- == NULL) {
- zlog_err("config_log_file: Unable to alloc mem!");
- return CMD_WARNING;
- }
- sprintf(p, "%s/%s", cwd, fname);
- fullpath = p;
- } else
- fullpath = fname;
-
- ret = zlog_set_file(NULL, fullpath, loglevel);
-
- if (p)
- free(p);
-
- if (!ret) {
- vty_out(vty, "can't open logfile %s\n", fname);
- return CMD_WARNING;
- }
-
- if (host.logfile)
- free(host.logfile);
-
- host.logfile = strdup(fname);
-
- return CMD_SUCCESS;
-}
-
-DEFUN(config_log_file,
- config_log_file_cmd,
- "log file FILENAME",
- "Logging control\n" "Logging to file\n" "Logging filename\n")
-{
- return set_log_file(vty, argv[0], zlog_default->default_lvl);
-}
-
-DEFUN(config_log_file_level,
- config_log_file_level_cmd,
- "log file FILENAME " LOG_LEVELS,
- "Logging control\n"
- "Logging to file\n" "Logging filename\n" LOG_LEVEL_DESC)
-{
- int level;
-
- if ((level = level_match(argv[1])) == ZLOG_DISABLED)
- return CMD_ERR_NO_MATCH;
- return set_log_file(vty, argv[0], level);
-}
-
-DEFUN(no_config_log_file,
- no_config_log_file_cmd,
- "no log file [FILENAME]",
- NO_STR
- "Logging control\n" "Cancel logging to file\n" "Logging file name\n")
-{
- zlog_reset_file(NULL);
-
- if (host.logfile)
- free(host.logfile);
-
- host.logfile = NULL;
-
- return CMD_SUCCESS;
-}
-
-ALIAS(no_config_log_file,
- no_config_log_file_level_cmd,
- "no log file FILENAME LEVEL",
- NO_STR
- "Logging control\n"
- "Cancel logging to file\n" "Logging file name\n" "Logging level\n")
-
- DEFUN(config_log_syslog,
- config_log_syslog_cmd,
- "log syslog", "Logging control\n" "Set syslog logging level\n")
-{
- zlog_set_level(NULL, ZLOG_DEST_SYSLOG, zlog_default->default_lvl);
- return CMD_SUCCESS;
-}
-
-DEFUN(config_log_syslog_level,
- config_log_syslog_level_cmd,
- "log syslog " LOG_LEVELS,
- "Logging control\n" "Set syslog logging level\n" LOG_LEVEL_DESC)
-{
- int level;
-
- if ((level = level_match(argv[0])) == ZLOG_DISABLED)
- return CMD_ERR_NO_MATCH;
- zlog_set_level(NULL, ZLOG_DEST_SYSLOG, level);
- return CMD_SUCCESS;
-}
-
-DEFUN_DEPRECATED(config_log_syslog_facility,
- config_log_syslog_facility_cmd,
- "log syslog facility " LOG_FACILITIES,
- "Logging control\n"
- "Logging goes to syslog\n"
- "(Deprecated) Facility parameter for syslog messages\n"
- LOG_FACILITY_DESC)
-{
- int facility;
-
- if ((facility = facility_match(argv[0])) < 0)
- return CMD_ERR_NO_MATCH;
-
- zlog_set_level(NULL, ZLOG_DEST_SYSLOG, zlog_default->default_lvl);
- zlog_default->facility = facility;
- return CMD_SUCCESS;
-}
-
-DEFUN(no_config_log_syslog,
- no_config_log_syslog_cmd,
- "no log syslog [LEVEL]",
- NO_STR "Logging control\n" "Cancel logging to syslog\n" "Logging level\n")
-{
- zlog_set_level(NULL, ZLOG_DEST_SYSLOG, ZLOG_DISABLED);
- return CMD_SUCCESS;
-}
-
-ALIAS(no_config_log_syslog,
- no_config_log_syslog_facility_cmd,
- "no log syslog facility " LOG_FACILITIES,
- NO_STR
- "Logging control\n"
- "Logging goes to syslog\n"
- "Facility parameter for syslog messages\n" LOG_FACILITY_DESC)
-
- DEFUN(config_log_facility,
- config_log_facility_cmd,
- "log facility " LOG_FACILITIES,
- "Logging control\n"
- "Facility parameter for syslog messages\n" LOG_FACILITY_DESC)
-{
- int facility;
-
- if ((facility = facility_match(argv[0])) < 0)
- return CMD_ERR_NO_MATCH;
- zlog_default->facility = facility;
- return CMD_SUCCESS;
-}
-
-DEFUN(no_config_log_facility,
- no_config_log_facility_cmd,
- "no log facility [FACILITY]",
- NO_STR
- "Logging control\n"
- "Reset syslog facility to default (daemon)\n" "Syslog facility\n")
-{
- zlog_default->facility = LOG_DAEMON;
- return CMD_SUCCESS;
-}
-
-DEFUN_DEPRECATED(config_log_trap,
- config_log_trap_cmd,
- "log trap " LOG_LEVELS,
- "Logging control\n"
- "(Deprecated) Set logging level and default for all destinations\n"
- LOG_LEVEL_DESC)
-{
- int new_level;
- int i;
-
- if ((new_level = level_match(argv[0])) == ZLOG_DISABLED)
- return CMD_ERR_NO_MATCH;
-
- zlog_default->default_lvl = new_level;
- for (i = 0; i < ZLOG_NUM_DESTS; i++)
- if (zlog_default->maxlvl[i] != ZLOG_DISABLED)
- zlog_default->maxlvl[i] = new_level;
- return CMD_SUCCESS;
-}
-
-DEFUN_DEPRECATED(no_config_log_trap,
- no_config_log_trap_cmd,
- "no log trap [LEVEL]",
- NO_STR
- "Logging control\n"
- "Permit all logging information\n" "Logging level\n")
-{
- zlog_default->default_lvl = LOG_DEBUG;
- return CMD_SUCCESS;
-}
-
-DEFUN(config_log_record_priority,
- config_log_record_priority_cmd,
- "log record-priority",
- "Logging control\n"
- "Log the priority of the message within the message\n")
-{
- zlog_default->record_priority = 1;
- return CMD_SUCCESS;
-}
-
-DEFUN(no_config_log_record_priority,
- no_config_log_record_priority_cmd,
- "no log record-priority",
- NO_STR
- "Logging control\n"
- "Do not log the priority of the message within the message\n")
-{
- zlog_default->record_priority = 0;
- return CMD_SUCCESS;
-}
-#endif
-
-DEFUN(banner_motd_file,
- banner_motd_file_cmd,
- "banner motd file [FILE]",
- "Set banner\n" "Banner for motd\n" "Banner from a file\n" "Filename\n")
-{
- if (host.motdfile)
- free(host.motdfile);
- host.motdfile = strdup(argv[0]);
-
- return CMD_SUCCESS;
-}
-
-DEFUN(banner_motd_default,
- banner_motd_default_cmd,
- "banner motd default",
- "Set banner string\n" "Strings for motd\n" "Default string\n")
-{
- host.motd = default_motd;
- return CMD_SUCCESS;
-}
-
-DEFUN(no_banner_motd,
- no_banner_motd_cmd,
- "no banner motd", NO_STR "Set banner string\n" "Strings for motd\n")
-{
- host.motd = NULL;
- if (host.motdfile)
- free(host.motdfile);
- host.motdfile = NULL;
- return CMD_SUCCESS;
-}
-
-/* Set config filename. Called from vty.c */
-void host_config_set(char *filename)
-{
- host.config = strdup(filename);
-}
-
-void install_default(enum node_type node)
-{
- install_element(node, &config_exit_cmd);
- install_element(node, &config_quit_cmd);
- install_element(node, &config_end_cmd);
- install_element(node, &config_help_cmd);
- install_element(node, &config_list_cmd);
-
-#if 0
- install_element(node, &config_write_terminal_cmd);
- install_element(node, &config_write_file_cmd);
- install_element(node, &config_write_memory_cmd);
- install_element(node, &config_write_cmd);
- install_element(node, &show_running_config_cmd);
-#endif
-}
-
-/* Initialize command interface. Install basic nodes and commands. */
-void cmd_init(int terminal)
-{
- /* Allocate initial top vector of commands. */
- cmdvec = vector_init(VECTOR_MIN_SIZE);
-
- /* Default host value settings. */
- host.name = NULL;
- //host.password = NULL;
- host.password = "foo";
- host.enable = NULL;
- host.logfile = NULL;
- host.config = NULL;
- host.lines = -1;
- host.motd = default_motd;
- host.motdfile = NULL;
-
- /* Install top nodes. */
- install_node(&view_node, NULL);
- install_node(&enable_node, NULL);
- install_node(&auth_node, NULL);
- install_node(&auth_enable_node, NULL);
- install_node(&config_node, config_write_host);
-
- /* Each node's basic commands. */
- install_element(VIEW_NODE, &show_version_cmd);
- if (terminal) {
- install_element(VIEW_NODE, &config_list_cmd);
- install_element(VIEW_NODE, &config_exit_cmd);
- install_element(VIEW_NODE, &config_quit_cmd);
- install_element(VIEW_NODE, &config_help_cmd);
- install_element(VIEW_NODE, &config_enable_cmd);
- install_element(VIEW_NODE, &config_terminal_length_cmd);
- install_element(VIEW_NODE, &config_terminal_no_length_cmd);
- install_element(VIEW_NODE, &echo_cmd);
- }
-
- if (terminal) {
- install_default(ENABLE_NODE);
- install_element(ENABLE_NODE, &config_disable_cmd);
- install_element(ENABLE_NODE, &config_terminal_cmd);
- //install_element (ENABLE_NODE, &copy_runningconfig_startupconfig_cmd);
- }
- //install_element (ENABLE_NODE, &show_startup_config_cmd);
- install_element(ENABLE_NODE, &show_version_cmd);
-
- if (terminal) {
- install_element(ENABLE_NODE, &config_terminal_length_cmd);
- install_element(ENABLE_NODE, &config_terminal_no_length_cmd);
- install_element(ENABLE_NODE, &echo_cmd);
-
- install_default(CONFIG_NODE);
- }
-
- install_element(CONFIG_NODE, &hostname_cmd);
- install_element(CONFIG_NODE, &no_hostname_cmd);
-
- if (terminal) {
- install_element(CONFIG_NODE, &password_cmd);
- install_element(CONFIG_NODE, &password_text_cmd);
- install_element(CONFIG_NODE, &enable_password_cmd);
- install_element(CONFIG_NODE, &enable_password_text_cmd);
- install_element(CONFIG_NODE, &no_enable_password_cmd);
-
-#ifdef VTY_CRYPT_PW
- install_element(CONFIG_NODE, &service_password_encrypt_cmd);
- install_element(CONFIG_NODE, &no_service_password_encrypt_cmd);
-#endif
- install_element(CONFIG_NODE, &banner_motd_default_cmd);
- install_element(CONFIG_NODE, &banner_motd_file_cmd);
- install_element(CONFIG_NODE, &no_banner_motd_cmd);
- install_element(CONFIG_NODE, &service_terminal_length_cmd);
- install_element(CONFIG_NODE, &no_service_terminal_length_cmd);
-
- }
- srand(time(NULL));
-}
diff --git a/src/vty/vector.c b/src/vty/vector.c
deleted file mode 100644
index 76870105b..000000000
--- a/src/vty/vector.c
+++ /dev/null
@@ -1,186 +0,0 @@
-/* Generic vector interface routine
- * Copyright (C) 1997 Kunihiro Ishiguro
- *
- * This file is part of GNU Zebra.
- *
- * GNU Zebra 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, or (at your option) any
- * later version.
- *
- * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the Free
- * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
- */
-
-#include <stdlib.h>
-#include <unistd.h>
-
-#include <vty/vector.h>
-#include <memory.h>
-
-/* Initialize vector : allocate memory and return vector. */
-vector vector_init(unsigned int size)
-{
- vector v = calloc(1, sizeof(struct _vector));
- if (!v)
- return NULL;
-
- /* allocate at least one slot */
- if (size == 0)
- size = 1;
-
- v->alloced = size;
- v->active = 0;
- v->index = calloc(1, sizeof(void *) * size);
- if (!v->index) {
- free(v);
- return NULL;
- }
- return v;
-}
-
-void vector_only_wrapper_free(vector v)
-{
- free(v);
-}
-
-void vector_only_index_free(void *index)
-{
- free(index);
-}
-
-void vector_free(vector v)
-{
- free(v->index);
- free(v);
-}
-
-vector vector_copy(vector v)
-{
- unsigned int size;
- vector new = calloc(1, sizeof(struct _vector));
- if (!new)
- return NULL;
-
- new->active = v->active;
- new->alloced = v->alloced;
-
- size = sizeof(void *) * (v->alloced);
- new->index = calloc(1, size);
- if (!new->index) {
- free(new);
- return NULL;
- }
- memcpy(new->index, v->index, size);
-
- return new;
-}
-
-/* Check assigned index, and if it runs short double index pointer */
-void vector_ensure(vector v, unsigned int num)
-{
- if (v->alloced > num)
- return;
-
- v->index = realloc(v->index, sizeof(void *) * (v->alloced * 2));
- memset(&v->index[v->alloced], 0, sizeof(void *) * v->alloced);
- v->alloced *= 2;
-
- if (v->alloced <= num)
- vector_ensure(v, num);
-}
-
-/* This function only returns next empty slot index. It dose not mean
- the slot's index memory is assigned, please call vector_ensure()
- after calling this function. */
-int vector_empty_slot(vector v)
-{
- unsigned int i;
-
- if (v->active == 0)
- return 0;
-
- for (i = 0; i < v->active; i++)
- if (v->index[i] == 0)
- return i;
-
- return i;
-}
-
-/* Set value to the smallest empty slot. */
-int vector_set(vector v, void *val)
-{
- unsigned int i;
-
- i = vector_empty_slot(v);
- vector_ensure(v, i);
-
- v->index[i] = val;
-
- if (v->active <= i)
- v->active = i + 1;
-
- return i;
-}
-
-/* Set value to specified index slot. */
-int vector_set_index(vector v, unsigned int i, void *val)
-{
- vector_ensure(v, i);
-
- v->index[i] = val;
-
- if (v->active <= i)
- v->active = i + 1;
-
- return i;
-}
-
-/* Look up vector. */
-void *vector_lookup(vector v, unsigned int i)
-{
- if (i >= v->active)
- return NULL;
- return v->index[i];
-}
-
-/* Lookup vector, ensure it. */
-void *vector_lookup_ensure(vector v, unsigned int i)
-{
- vector_ensure(v, i);
- return v->index[i];
-}
-
-/* Unset value at specified index slot. */
-void vector_unset(vector v, unsigned int i)
-{
- if (i >= v->alloced)
- return;
-
- v->index[i] = NULL;
-
- if (i + 1 == v->active) {
- v->active--;
- while (i && v->index[--i] == NULL && v->active--) ; /* Is this ugly ? */
- }
-}
-
-/* Count the number of not emplty slot. */
-unsigned int vector_count(vector v)
-{
- unsigned int i;
- unsigned count = 0;
-
- for (i = 0; i < v->active; i++)
- if (v->index[i] != NULL)
- count++;
-
- return count;
-}
diff --git a/src/vty/vty.c b/src/vty/vty.c
deleted file mode 100644
index ca6fff73c..000000000
--- a/src/vty/vty.c
+++ /dev/null
@@ -1,1634 +0,0 @@
-
-#include <stdio.h>
-#include <stdarg.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-#include <errno.h>
-#include <ctype.h>
-#include <termios.h>
-
-#include <sys/utsname.h>
-#include <sys/param.h>
-
-#include <arpa/telnet.h>
-
-#include "cardshell.h"
-#include <vty/vty.h>
-#include <vty/command.h>
-#include <vty/buffer.h>
-
-extern struct host host;
-
-/* Vector which store each vty structure. */
-static vector vtyvec;
-
-vector Vvty_serv_thread;
-
-char *vty_cwd = NULL;
-
-/* Configure lock. */
-static int vty_config;
-
-static int no_password_check = 1;
-
-static void vty_clear_buf(struct vty *vty)
-{
- memset(vty->buf, 0, vty->max);
-}
-
-/* Allocate new vty struct. */
-struct vty *vty_new()
-{
- struct vty *new = malloc(sizeof(struct vty));
-
- if (!new)
- goto out;
-
- new->obuf = buffer_new(0); /* Use default buffer size. */
- if (!new->obuf)
- goto out_new;
- new->buf = calloc(1, VTY_BUFSIZ);
- if (!new->buf)
- goto out_obuf;
-
- new->max = VTY_BUFSIZ;
-
- return new;
-
-out_obuf:
- free(new->obuf);
-out_new:
- free(new);
- new = NULL;
-out:
- return new;
-}
-
-/* Authentication of vty */
-static void vty_auth(struct vty *vty, char *buf)
-{
- char *passwd = NULL;
- enum node_type next_node = 0;
- int fail;
- char *crypt(const char *, const char *);
-
- switch (vty->node) {
- case AUTH_NODE:
-#ifdef VTY_CRYPT_PW
- if (host.encrypt)
- passwd = host.password_encrypt;
- else
-#endif
- passwd = host.password;
- if (host.advanced)
- next_node = host.enable ? VIEW_NODE : ENABLE_NODE;
- else
- next_node = VIEW_NODE;
- break;
- case AUTH_ENABLE_NODE:
-#ifdef VTY_CRYPT_PW
- if (host.encrypt)
- passwd = host.enable_encrypt;
- else
-#endif
- passwd = host.enable;
- next_node = ENABLE_NODE;
- break;
- }
-
- if (passwd) {
-#ifdef VTY_CRYPT_PW
- if (host.encrypt)
- fail = strcmp(crypt(buf, passwd), passwd);
- else
-#endif
- fail = strcmp(buf, passwd);
- } else
- fail = 1;
-
- if (!fail) {
- vty->fail = 0;
- vty->node = next_node; /* Success ! */
- } else {
- vty->fail++;
- if (vty->fail >= 3) {
- if (vty->node == AUTH_NODE) {
- vty_out(vty,
- "%% Bad passwords, too many failures!%s",
- VTY_NEWLINE);
- vty->status = VTY_CLOSE;
- } else {
- /* AUTH_ENABLE_NODE */
- vty->fail = 0;
- vty_out(vty,
- "%% Bad enable passwords, too many failures!%s",
- VTY_NEWLINE);
- vty->node = VIEW_NODE;
- }
- }
- }
-}
-
-/* Close vty interface. */
-void vty_close(struct vty *vty)
-{
- int i;
-
- /* Flush buffer. */
- buffer_flush_all(vty->obuf, vty->fd);
-
- /* Free input buffer. */
- buffer_free(vty->obuf);
-
- /* Free command history. */
- for (i = 0; i < VTY_MAXHIST; i++)
- if (vty->hist[i])
- free(vty->hist[i]);
-
- /* Unset vector. */
- vector_unset(vtyvec, vty->fd);
-
- /* Close socket. */
- if (vty->fd > 0)
- close(vty->fd);
-
- if (vty->buf)
- free(vty->buf);
-
- /* Check configure. */
- vty_config_unlock(vty);
-
- /* OK free vty. */
- free(vty);
-}
-
-int vty_shell(struct vty *vty)
-{
- return vty->type == VTY_SHELL ? 1 : 0;
-}
-
-
-/* VTY standard output function. */
-int vty_out(struct vty *vty, const char *format, ...)
-{
- va_list args;
- int len = 0;
- int size = 1024;
- char buf[1024];
- char *p = NULL;
-
- if (vty_shell(vty)) {
- va_start(args, format);
- vprintf(format, args);
- va_end(args);
- } else {
- /* Try to write to initial buffer. */
- va_start(args, format);
- len = vsnprintf(buf, sizeof buf, format, args);
- va_end(args);
-
- /* Initial buffer is not enough. */
- if (len < 0 || len >= size) {
- while (1) {
- if (len > -1)
- size = len + 1;
- else
- size = size * 2;
-
- p = realloc(p, size);
- if (!p)
- return -1;
-
- va_start(args, format);
- len = vsnprintf(p, size, format, args);
- va_end(args);
-
- if (len > -1 && len < size)
- break;
- }
- }
-
- /* When initial buffer is enough to store all output. */
- if (!p)
- p = buf;
-
- /* Pointer p must point out buffer. */
- buffer_put(vty->obuf, (u_char *) p, len);
-
- /* If p is not different with buf, it is allocated buffer. */
- if (p != buf)
- free(p);
- }
-
- return len;
-}
-
-int vty_out_newline(struct vty *vty)
-{
- char *p = vty_newline(vty);
- buffer_put(vty->obuf, p, strlen(p));
- return 0;
-}
-
-int vty_config_lock(struct vty *vty)
-{
- if (vty_config == 0) {
- vty->config = 1;
- vty_config = 1;
- }
- return vty->config;
-}
-
-int vty_config_unlock(struct vty *vty)
-{
- if (vty_config == 1 && vty->config == 1) {
- vty->config = 0;
- vty_config = 0;
- }
- return vty->config;
-}
-
-/* Say hello to vty interface. */
-void vty_hello(struct vty *vty)
-{
- if (host.motdfile) {
- FILE *f;
- char buf[4096];
-
- f = fopen(host.motdfile, "r");
- if (f) {
- while (fgets(buf, sizeof(buf), f)) {
- char *s;
- /* work backwards to ignore trailling isspace() */
- for (s = buf + strlen(buf);
- (s > buf) && isspace(*(s - 1)); s--) ;
- *s = '\0';
- vty_out(vty, "%s%s", buf, VTY_NEWLINE);
- }
- fclose(f);
- } else
- vty_out(vty, "MOTD file not found%s", VTY_NEWLINE);
- } else if (host.motd)
- vty_out(vty, host.motd);
-}
-
-/* Put out prompt and wait input from user. */
-static void vty_prompt(struct vty *vty)
-{
- struct utsname names;
- const char *hostname;
-
- if (vty->type == VTY_TERM) {
- hostname = host.name;
- if (!hostname) {
- uname(&names);
- hostname = names.nodename;
- }
- vty_out(vty, cmd_prompt(vty->node), hostname);
- }
-}
-
-/* Command execution over the vty interface. */
-static int vty_command(struct vty *vty, char *buf)
-{
- int ret;
- vector vline;
-
- /* Split readline string up into the vector */
- vline = cmd_make_strvec(buf);
-
- if (vline == NULL)
- return CMD_SUCCESS;
-
- ret = cmd_execute_command(vline, vty, NULL, 0);
- if (ret != CMD_SUCCESS)
- switch (ret) {
- case CMD_WARNING:
- if (vty->type == VTY_FILE)
- vty_out(vty, "Warning...%s", VTY_NEWLINE);
- break;
- case CMD_ERR_AMBIGUOUS:
- vty_out(vty, "%% Ambiguous command.%s", VTY_NEWLINE);
- break;
- case CMD_ERR_NO_MATCH:
- vty_out(vty, "%% Unknown command.%s", VTY_NEWLINE);
- break;
- case CMD_ERR_INCOMPLETE:
- vty_out(vty, "%% Command incomplete.%s", VTY_NEWLINE);
- break;
- }
- cmd_free_strvec(vline);
-
- return ret;
-}
-
-static const char telnet_backward_char = 0x08;
-static const char telnet_space_char = ' ';
-
-/* Basic function to write buffer to vty. */
-static void vty_write(struct vty *vty, const char *buf, size_t nbytes)
-{
- if ((vty->node == AUTH_NODE) || (vty->node == AUTH_ENABLE_NODE))
- return;
-
- /* Should we do buffering here ? And make vty_flush (vty) ? */
- buffer_put(vty->obuf, buf, nbytes);
-}
-
-/* Ensure length of input buffer. Is buffer is short, double it. */
-static void vty_ensure(struct vty *vty, int length)
-{
- if (vty->max <= length) {
- vty->max *= 2;
- vty->buf = realloc(vty->buf, vty->max);
- // FIXME: check return
- }
-}
-
-/* Basic function to insert character into vty. */
-static void vty_self_insert(struct vty *vty, char c)
-{
- int i;
- int length;
-
- vty_ensure(vty, vty->length + 1);
- length = vty->length - vty->cp;
- memmove(&vty->buf[vty->cp + 1], &vty->buf[vty->cp], length);
- vty->buf[vty->cp] = c;
-
- vty_write(vty, &vty->buf[vty->cp], length + 1);
- for (i = 0; i < length; i++)
- vty_write(vty, &telnet_backward_char, 1);
-
- vty->cp++;
- vty->length++;
-}
-
-/* Self insert character 'c' in overwrite mode. */
-static void vty_self_insert_overwrite(struct vty *vty, char c)
-{
- vty_ensure(vty, vty->length + 1);
- vty->buf[vty->cp++] = c;
-
- if (vty->cp > vty->length)
- vty->length++;
-
- if ((vty->node == AUTH_NODE) || (vty->node == AUTH_ENABLE_NODE))
- return;
-
- vty_write(vty, &c, 1);
-}
-
-/* Insert a word into vty interface with overwrite mode. */
-static void vty_insert_word_overwrite(struct vty *vty, char *str)
-{
- int len = strlen(str);
- vty_write(vty, str, len);
- strcpy(&vty->buf[vty->cp], str);
- vty->cp += len;
- vty->length = vty->cp;
-}
-
-/* Forward character. */
-static void vty_forward_char(struct vty *vty)
-{
- if (vty->cp < vty->length) {
- vty_write(vty, &vty->buf[vty->cp], 1);
- vty->cp++;
- }
-}
-
-/* Backward character. */
-static void vty_backward_char(struct vty *vty)
-{
- if (vty->cp > 0) {
- vty->cp--;
- vty_write(vty, &telnet_backward_char, 1);
- }
-}
-
-/* Move to the beginning of the line. */
-static void vty_beginning_of_line(struct vty *vty)
-{
- while (vty->cp)
- vty_backward_char(vty);
-}
-
-/* Move to the end of the line. */
-static void vty_end_of_line(struct vty *vty)
-{
- while (vty->cp < vty->length)
- vty_forward_char(vty);
-}
-
-/* Add current command line to the history buffer. */
-static void vty_hist_add(struct vty *vty)
-{
- int index;
-
- if (vty->length == 0)
- return;
-
- index = vty->hindex ? vty->hindex - 1 : VTY_MAXHIST - 1;
-
- /* Ignore the same string as previous one. */
- if (vty->hist[index])
- if (strcmp(vty->buf, vty->hist[index]) == 0) {
- vty->hp = vty->hindex;
- return;
- }
-
- /* Insert history entry. */
- if (vty->hist[vty->hindex])
- free(vty->hist[vty->hindex]);
- vty->hist[vty->hindex] = strdup(vty->buf);
-
- /* History index rotation. */
- vty->hindex++;
- if (vty->hindex == VTY_MAXHIST)
- vty->hindex = 0;
-
- vty->hp = vty->hindex;
-}
-
-/* Get telnet window size. */
-static int
-vty_telnet_option (struct vty *vty, unsigned char *buf, int nbytes)
-{
-#ifdef TELNET_OPTION_DEBUG
- int i;
-
- for (i = 0; i < nbytes; i++)
- {
- switch (buf[i])
- {
- case IAC:
- vty_out (vty, "IAC ");
- break;
- case WILL:
- vty_out (vty, "WILL ");
- break;
- case WONT:
- vty_out (vty, "WONT ");
- break;
- case DO:
- vty_out (vty, "DO ");
- break;
- case DONT:
- vty_out (vty, "DONT ");
- break;
- case SB:
- vty_out (vty, "SB ");
- break;
- case SE:
- vty_out (vty, "SE ");
- break;
- case TELOPT_ECHO:
- vty_out (vty, "TELOPT_ECHO %s", VTY_NEWLINE);
- break;
- case TELOPT_SGA:
- vty_out (vty, "TELOPT_SGA %s", VTY_NEWLINE);
- break;
- case TELOPT_NAWS:
- vty_out (vty, "TELOPT_NAWS %s", VTY_NEWLINE);
- break;
- default:
- vty_out (vty, "%x ", buf[i]);
- break;
- }
- }
- vty_out (vty, "%s", VTY_NEWLINE);
-
-#endif /* TELNET_OPTION_DEBUG */
-
- switch (buf[0])
- {
- case SB:
- vty->sb_len = 0;
- vty->iac_sb_in_progress = 1;
- return 0;
- break;
- case SE:
- {
- if (!vty->iac_sb_in_progress)
- return 0;
-
- if ((vty->sb_len == 0) || (vty->sb_buf[0] == '\0'))
- {
- vty->iac_sb_in_progress = 0;
- return 0;
- }
- switch (vty->sb_buf[0])
- {
- case TELOPT_NAWS:
- if (vty->sb_len != TELNET_NAWS_SB_LEN)
- vty_out(vty,"RFC 1073 violation detected: telnet NAWS option "
- "should send %d characters, but we received %lu",
- TELNET_NAWS_SB_LEN, (u_long)vty->sb_len);
- else if (sizeof(vty->sb_buf) < TELNET_NAWS_SB_LEN)
- vty_out(vty, "Bug detected: sizeof(vty->sb_buf) %lu < %d, "
- "too small to handle the telnet NAWS option",
- (u_long)sizeof(vty->sb_buf), TELNET_NAWS_SB_LEN);
- else
- {
- vty->width = ((vty->sb_buf[1] << 8)|vty->sb_buf[2]);
- vty->height = ((vty->sb_buf[3] << 8)|vty->sb_buf[4]);
-#ifdef TELNET_OPTION_DEBUG
- vty_out(vty, "TELNET NAWS window size negotiation completed: "
- "width %d, height %d%s",
- vty->width, vty->height, VTY_NEWLINE);
-#endif
- }
- break;
- }
- vty->iac_sb_in_progress = 0;
- return 0;
- break;
- }
- default:
- break;
- }
- return 1;
-}
-
-/* Execute current command line. */
-static int vty_execute(struct vty *vty)
-{
- int ret;
-
- ret = CMD_SUCCESS;
-
- switch (vty->node) {
- case AUTH_NODE:
- case AUTH_ENABLE_NODE:
- vty_auth(vty, vty->buf);
- break;
- default:
- ret = vty_command(vty, vty->buf);
- if (vty->type == VTY_TERM)
- vty_hist_add(vty);
- break;
- }
-
- /* Clear command line buffer. */
- vty->cp = vty->length = 0;
- vty_clear_buf(vty);
-
- if (vty->status != VTY_CLOSE)
- vty_prompt(vty);
-
- return ret;
-}
-
-/* Send WILL TELOPT_ECHO to remote server. */
-static void
-vty_will_echo (struct vty *vty)
-{
- unsigned char cmd[] = { IAC, WILL, TELOPT_ECHO, '\0' };
- vty_out (vty, "%s", cmd);
-}
-
-/* Make suppress Go-Ahead telnet option. */
-static void
-vty_will_suppress_go_ahead (struct vty *vty)
-{
- unsigned char cmd[] = { IAC, WILL, TELOPT_SGA, '\0' };
- vty_out (vty, "%s", cmd);
-}
-
-/* Make don't use linemode over telnet. */
-static void
-vty_dont_linemode (struct vty *vty)
-{
- unsigned char cmd[] = { IAC, DONT, TELOPT_LINEMODE, '\0' };
- vty_out (vty, "%s", cmd);
-}
-
-/* Use window size. */
-static void
-vty_do_window_size (struct vty *vty)
-{
- unsigned char cmd[] = { IAC, DO, TELOPT_NAWS, '\0' };
- vty_out (vty, "%s", cmd);
-}
-
-static void vty_kill_line_from_beginning(struct vty *);
-static void vty_redraw_line(struct vty *);
-
-/* Print command line history. This function is called from
- vty_next_line and vty_previous_line. */
-static void vty_history_print(struct vty *vty)
-{
- int length;
-
- vty_kill_line_from_beginning(vty);
-
- /* Get previous line from history buffer */
- length = strlen(vty->hist[vty->hp]);
- memcpy(vty->buf, vty->hist[vty->hp], length);
- vty->cp = vty->length = length;
-
- /* Redraw current line */
- vty_redraw_line(vty);
-}
-
-/* Show next command line history. */
-static void vty_next_line(struct vty *vty)
-{
- int try_index;
-
- if (vty->hp == vty->hindex)
- return;
-
- /* Try is there history exist or not. */
- try_index = vty->hp;
- if (try_index == (VTY_MAXHIST - 1))
- try_index = 0;
- else
- try_index++;
-
- /* If there is not history return. */
- if (vty->hist[try_index] == NULL)
- return;
- else
- vty->hp = try_index;
-
- vty_history_print(vty);
-}
-
-/* Show previous command line history. */
-static void vty_previous_line(struct vty *vty)
-{
- int try_index;
-
- try_index = vty->hp;
- if (try_index == 0)
- try_index = VTY_MAXHIST - 1;
- else
- try_index--;
-
- if (vty->hist[try_index] == NULL)
- return;
- else
- vty->hp = try_index;
-
- vty_history_print(vty);
-}
-
-/* This function redraw all of the command line character. */
-static void vty_redraw_line(struct vty *vty)
-{
- vty_write(vty, vty->buf, vty->length);
- vty->cp = vty->length;
-}
-
-/* Forward word. */
-static void vty_forward_word(struct vty *vty)
-{
- while (vty->cp != vty->length && vty->buf[vty->cp] != ' ')
- vty_forward_char(vty);
-
- while (vty->cp != vty->length && vty->buf[vty->cp] == ' ')
- vty_forward_char(vty);
-}
-
-/* Backward word without skipping training space. */
-static void vty_backward_pure_word(struct vty *vty)
-{
- while (vty->cp > 0 && vty->buf[vty->cp - 1] != ' ')
- vty_backward_char(vty);
-}
-
-/* Backward word. */
-static void vty_backward_word(struct vty *vty)
-{
- while (vty->cp > 0 && vty->buf[vty->cp - 1] == ' ')
- vty_backward_char(vty);
-
- while (vty->cp > 0 && vty->buf[vty->cp - 1] != ' ')
- vty_backward_char(vty);
-}
-
-/* When '^D' is typed at the beginning of the line we move to the down
- level. */
-static void vty_down_level(struct vty *vty)
-{
- vty_out(vty, "%s", VTY_NEWLINE);
- (*config_exit_cmd.func) (NULL, vty, 0, NULL);
- vty_prompt(vty);
- vty->cp = 0;
-}
-
-/* When '^Z' is received from vty, move down to the enable mode. */
-static void vty_end_config(struct vty *vty)
-{
- vty_out(vty, "%s", VTY_NEWLINE);
-
- switch (vty->node) {
- case VIEW_NODE:
- case ENABLE_NODE:
- /* Nothing to do. */
- break;
- case CONFIG_NODE:
- case INTERFACE_NODE:
- case ZEBRA_NODE:
- case RIP_NODE:
- case RIPNG_NODE:
- case BGP_NODE:
- case BGP_VPNV4_NODE:
- case BGP_IPV4_NODE:
- case BGP_IPV4M_NODE:
- case BGP_IPV6_NODE:
- case RMAP_NODE:
- case OSPF_NODE:
- case OSPF6_NODE:
- case ISIS_NODE:
- case KEYCHAIN_NODE:
- case KEYCHAIN_KEY_NODE:
- case MASC_NODE:
- case VTY_NODE:
- vty_config_unlock(vty);
- vty->node = ENABLE_NODE;
- break;
- default:
- /* Unknown node, we have to ignore it. */
- break;
- }
-
- vty_prompt(vty);
- vty->cp = 0;
-}
-
-/* Delete a charcter at the current point. */
-static void vty_delete_char(struct vty *vty)
-{
- int i;
- int size;
-
- if (vty->node == AUTH_NODE || vty->node == AUTH_ENABLE_NODE)
- return;
-
- if (vty->length == 0) {
- vty_down_level(vty);
- return;
- }
-
- if (vty->cp == vty->length)
- return; /* completion need here? */
-
- size = vty->length - vty->cp;
-
- vty->length--;
- memmove(&vty->buf[vty->cp], &vty->buf[vty->cp + 1], size - 1);
- vty->buf[vty->length] = '\0';
-
- vty_write(vty, &vty->buf[vty->cp], size - 1);
- vty_write(vty, &telnet_space_char, 1);
-
- for (i = 0; i < size; i++)
- vty_write(vty, &telnet_backward_char, 1);
-}
-
-/* Delete a character before the point. */
-static void vty_delete_backward_char(struct vty *vty)
-{
- if (vty->cp == 0)
- return;
-
- vty_backward_char(vty);
- vty_delete_char(vty);
-}
-
-/* Kill rest of line from current point. */
-static void vty_kill_line(struct vty *vty)
-{
- int i;
- int size;
-
- size = vty->length - vty->cp;
-
- if (size == 0)
- return;
-
- for (i = 0; i < size; i++)
- vty_write(vty, &telnet_space_char, 1);
- for (i = 0; i < size; i++)
- vty_write(vty, &telnet_backward_char, 1);
-
- memset(&vty->buf[vty->cp], 0, size);
- vty->length = vty->cp;
-}
-
-/* Kill line from the beginning. */
-static void vty_kill_line_from_beginning(struct vty *vty)
-{
- vty_beginning_of_line(vty);
- vty_kill_line(vty);
-}
-
-/* Delete a word before the point. */
-static void vty_forward_kill_word(struct vty *vty)
-{
- while (vty->cp != vty->length && vty->buf[vty->cp] == ' ')
- vty_delete_char(vty);
- while (vty->cp != vty->length && vty->buf[vty->cp] != ' ')
- vty_delete_char(vty);
-}
-
-/* Delete a word before the point. */
-static void vty_backward_kill_word(struct vty *vty)
-{
- while (vty->cp > 0 && vty->buf[vty->cp - 1] == ' ')
- vty_delete_backward_char(vty);
- while (vty->cp > 0 && vty->buf[vty->cp - 1] != ' ')
- vty_delete_backward_char(vty);
-}
-
-/* Transpose chars before or at the point. */
-static void vty_transpose_chars(struct vty *vty)
-{
- char c1, c2;
-
- /* If length is short or point is near by the beginning of line then
- return. */
- if (vty->length < 2 || vty->cp < 1)
- return;
-
- /* In case of point is located at the end of the line. */
- if (vty->cp == vty->length) {
- c1 = vty->buf[vty->cp - 1];
- c2 = vty->buf[vty->cp - 2];
-
- vty_backward_char(vty);
- vty_backward_char(vty);
- vty_self_insert_overwrite(vty, c1);
- vty_self_insert_overwrite(vty, c2);
- } else {
- c1 = vty->buf[vty->cp];
- c2 = vty->buf[vty->cp - 1];
-
- vty_backward_char(vty);
- vty_self_insert_overwrite(vty, c1);
- vty_self_insert_overwrite(vty, c2);
- }
-}
-
-/* Do completion at vty interface. */
-static void vty_complete_command(struct vty *vty)
-{
- int i;
- int ret;
- char **matched = NULL;
- vector vline;
-
- if (vty->node == AUTH_NODE || vty->node == AUTH_ENABLE_NODE)
- return;
-
- vline = cmd_make_strvec(vty->buf);
- if (vline == NULL)
- return;
-
- /* In case of 'help \t'. */
- if (isspace((int)vty->buf[vty->length - 1]))
- vector_set(vline, '\0');
-
- matched = cmd_complete_command(vline, vty, &ret);
-
- cmd_free_strvec(vline);
-
- vty_out(vty, "%s", VTY_NEWLINE);
- switch (ret) {
- case CMD_ERR_AMBIGUOUS:
- vty_out(vty, "%% Ambiguous command.%s", VTY_NEWLINE);
- vty_prompt(vty);
- vty_redraw_line(vty);
- break;
- case CMD_ERR_NO_MATCH:
- /* vty_out (vty, "%% There is no matched command.%s", VTY_NEWLINE); */
- vty_prompt(vty);
- vty_redraw_line(vty);
- break;
- case CMD_COMPLETE_FULL_MATCH:
- vty_prompt(vty);
- vty_redraw_line(vty);
- vty_backward_pure_word(vty);
- vty_insert_word_overwrite(vty, matched[0]);
- vty_self_insert(vty, ' ');
- free(matched[0]);
- break;
- case CMD_COMPLETE_MATCH:
- vty_prompt(vty);
- vty_redraw_line(vty);
- vty_backward_pure_word(vty);
- vty_insert_word_overwrite(vty, matched[0]);
- free(matched[0]);
- vector_only_index_free(matched);
- return;
- break;
- case CMD_COMPLETE_LIST_MATCH:
- for (i = 0; matched[i] != NULL; i++) {
- if (i != 0 && ((i % 6) == 0))
- vty_out(vty, "%s", VTY_NEWLINE);
- vty_out(vty, "%-10s ", matched[i]);
- free(matched[i]);
- }
- vty_out(vty, "%s", VTY_NEWLINE);
-
- vty_prompt(vty);
- vty_redraw_line(vty);
- break;
- case CMD_ERR_NOTHING_TODO:
- vty_prompt(vty);
- vty_redraw_line(vty);
- break;
- default:
- break;
- }
- if (matched)
- vector_only_index_free(matched);
-}
-
-static void
-vty_describe_fold(struct vty *vty, int cmd_width,
- unsigned int desc_width, struct desc *desc)
-{
- char *buf;
- const char *cmd, *p;
- int pos;
-
- cmd = desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd;
-
- if (desc_width <= 0) {
- vty_out(vty, " %-*s %s%s", cmd_width, cmd, desc->str,
- VTY_NEWLINE);
- return;
- }
-
- buf = calloc(1, strlen(desc->str) + 1);
- if (!buf)
- return;
-
- for (p = desc->str; strlen(p) > desc_width; p += pos + 1) {
- for (pos = desc_width; pos > 0; pos--)
- if (*(p + pos) == ' ')
- break;
-
- if (pos == 0)
- break;
-
- strncpy(buf, p, pos);
- buf[pos] = '\0';
- vty_out(vty, " %-*s %s%s", cmd_width, cmd, buf, VTY_NEWLINE);
-
- cmd = "";
- }
-
- vty_out(vty, " %-*s %s%s", cmd_width, cmd, p, VTY_NEWLINE);
-
- free(buf);
-}
-
-/* Describe matched command function. */
-static void vty_describe_command(struct vty *vty)
-{
- int ret;
- vector vline;
- vector describe;
- unsigned int i, width, desc_width;
- struct desc *desc, *desc_cr = NULL;
-
- vline = cmd_make_strvec(vty->buf);
-
- /* In case of '> ?'. */
- if (vline == NULL) {
- vline = vector_init(1);
- vector_set(vline, '\0');
- } else if (isspace((int)vty->buf[vty->length - 1]))
- vector_set(vline, '\0');
-
- describe = cmd_describe_command(vline, vty, &ret);
-
- vty_out(vty, "%s", VTY_NEWLINE);
-
- /* Ambiguous error. */
- switch (ret) {
- case CMD_ERR_AMBIGUOUS:
- cmd_free_strvec(vline);
- vty_out(vty, "%% Ambiguous command.%s", VTY_NEWLINE);
- vty_prompt(vty);
- vty_redraw_line(vty);
- return;
- break;
- case CMD_ERR_NO_MATCH:
- cmd_free_strvec(vline);
- vty_out(vty, "%% There is no matched command.%s", VTY_NEWLINE);
- vty_prompt(vty);
- vty_redraw_line(vty);
- return;
- break;
- }
-
- /* Get width of command string. */
- width = 0;
- for (i = 0; i < vector_active(describe); i++)
- if ((desc = vector_slot(describe, i)) != NULL) {
- unsigned int len;
-
- if (desc->cmd[0] == '\0')
- continue;
-
- len = strlen(desc->cmd);
- if (desc->cmd[0] == '.')
- len--;
-
- if (width < len)
- width = len;
- }
-
- /* Get width of description string. */
- desc_width = vty->width - (width + 6);
-
- /* Print out description. */
- for (i = 0; i < vector_active(describe); i++)
- if ((desc = vector_slot(describe, i)) != NULL) {
- if (desc->cmd[0] == '\0')
- continue;
-
- if (strcmp(desc->cmd, "<cr>") == 0) {
- desc_cr = desc;
- continue;
- }
-
- if (!desc->str)
- vty_out(vty, " %-s%s",
- desc->cmd[0] ==
- '.' ? desc->cmd + 1 : desc->cmd,
- VTY_NEWLINE);
- else if (desc_width >= strlen(desc->str))
- vty_out(vty, " %-*s %s%s", width,
- desc->cmd[0] ==
- '.' ? desc->cmd + 1 : desc->cmd,
- desc->str, VTY_NEWLINE);
- else
- vty_describe_fold(vty, width, desc_width, desc);
-
-#if 0
- vty_out(vty, " %-*s %s%s", width
- desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd,
- desc->str ? desc->str : "", VTY_NEWLINE);
-#endif /* 0 */
- }
-
- if ((desc = desc_cr)) {
- if (!desc->str)
- vty_out(vty, " %-s%s",
- desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd,
- VTY_NEWLINE);
- else if (desc_width >= strlen(desc->str))
- vty_out(vty, " %-*s %s%s", width,
- desc->cmd[0] == '.' ? desc->cmd + 1 : desc->cmd,
- desc->str, VTY_NEWLINE);
- else
- vty_describe_fold(vty, width, desc_width, desc);
- }
-
- cmd_free_strvec(vline);
- vector_free(describe);
-
- vty_prompt(vty);
- vty_redraw_line(vty);
-}
-
-/* ^C stop current input and do not add command line to the history. */
-static void vty_stop_input(struct vty *vty)
-{
- vty->cp = vty->length = 0;
- vty_clear_buf(vty);
- vty_out(vty, "%s", VTY_NEWLINE);
-
- switch (vty->node) {
- case VIEW_NODE:
- case ENABLE_NODE:
- /* Nothing to do. */
- break;
- case CONFIG_NODE:
- case INTERFACE_NODE:
- case ZEBRA_NODE:
- case RIP_NODE:
- case RIPNG_NODE:
- case BGP_NODE:
- case RMAP_NODE:
- case OSPF_NODE:
- case OSPF6_NODE:
- case ISIS_NODE:
- case KEYCHAIN_NODE:
- case KEYCHAIN_KEY_NODE:
- case MASC_NODE:
- case VTY_NODE:
- vty_config_unlock(vty);
- vty->node = ENABLE_NODE;
- break;
- default:
- /* Unknown node, we have to ignore it. */
- break;
- }
- vty_prompt(vty);
-
- /* Set history pointer to the latest one. */
- vty->hp = vty->hindex;
-}
-
-#define CONTROL(X) ((X) - '@')
-#define VTY_NORMAL 0
-#define VTY_PRE_ESCAPE 1
-#define VTY_ESCAPE 2
-
-/* Escape character command map. */
-static void vty_escape_map(unsigned char c, struct vty *vty)
-{
- switch (c) {
- case ('A'):
- vty_previous_line(vty);
- break;
- case ('B'):
- vty_next_line(vty);
- break;
- case ('C'):
- vty_forward_char(vty);
- break;
- case ('D'):
- vty_backward_char(vty);
- break;
- default:
- break;
- }
-
- /* Go back to normal mode. */
- vty->escape = VTY_NORMAL;
-}
-
-/* Quit print out to the buffer. */
-static void vty_buffer_reset(struct vty *vty)
-{
- buffer_reset(vty->obuf);
- vty_prompt(vty);
- vty_redraw_line(vty);
-}
-
-/* Read data via vty socket. */
-int vty_read(struct vty *vty)
-{
- int i;
- int nbytes;
- unsigned char buf[VTY_READ_BUFSIZ];
-
- int vty_sock = vty->fd;
-
- /* Read raw data from socket */
- if ((nbytes = read(vty->fd, buf, VTY_READ_BUFSIZ)) <= 0) {
- if (nbytes < 0) {
- if (ERRNO_IO_RETRY(errno)) {
- vty_event(VTY_READ, vty_sock, vty);
- return 0;
- }
- }
- buffer_reset(vty->obuf);
- vty->status = VTY_CLOSE;
- }
-
- for (i = 0; i < nbytes; i++) {
- if (buf[i] == IAC) {
- if (!vty->iac) {
- vty->iac = 1;
- continue;
- } else {
- vty->iac = 0;
- }
- }
-
- if (vty->iac_sb_in_progress && !vty->iac) {
- if (vty->sb_len < sizeof(vty->sb_buf))
- vty->sb_buf[vty->sb_len] = buf[i];
- vty->sb_len++;
- continue;
- }
-
- if (vty->iac) {
- /* In case of telnet command */
- int ret = 0;
- ret = vty_telnet_option(vty, buf + i, nbytes - i);
- vty->iac = 0;
- i += ret;
- continue;
- }
-
- if (vty->status == VTY_MORE) {
- switch (buf[i]) {
- case CONTROL('C'):
- case 'q':
- case 'Q':
- vty_buffer_reset(vty);
- break;
-#if 0 /* More line does not work for "show ip bgp". */
- case '\n':
- case '\r':
- vty->status = VTY_MORELINE;
- break;
-#endif
- default:
- break;
- }
- continue;
- }
-
- /* Escape character. */
- if (vty->escape == VTY_ESCAPE) {
- vty_escape_map(buf[i], vty);
- continue;
- }
-
- /* Pre-escape status. */
- if (vty->escape == VTY_PRE_ESCAPE) {
- switch (buf[i]) {
- case '[':
- vty->escape = VTY_ESCAPE;
- break;
- case 'b':
- vty_backward_word(vty);
- vty->escape = VTY_NORMAL;
- break;
- case 'f':
- vty_forward_word(vty);
- vty->escape = VTY_NORMAL;
- break;
- case 'd':
- vty_forward_kill_word(vty);
- vty->escape = VTY_NORMAL;
- break;
- case CONTROL('H'):
- case 0x7f:
- vty_backward_kill_word(vty);
- vty->escape = VTY_NORMAL;
- break;
- default:
- vty->escape = VTY_NORMAL;
- break;
- }
- continue;
- }
-
- switch (buf[i]) {
- case CONTROL('A'):
- vty_beginning_of_line(vty);
- break;
- case CONTROL('B'):
- vty_backward_char(vty);
- break;
- case CONTROL('C'):
- vty_stop_input(vty);
- break;
- case CONTROL('D'):
- vty_delete_char(vty);
- break;
- case CONTROL('E'):
- vty_end_of_line(vty);
- break;
- case CONTROL('F'):
- vty_forward_char(vty);
- break;
- case CONTROL('H'):
- case 0x7f:
- vty_delete_backward_char(vty);
- break;
- case CONTROL('K'):
- vty_kill_line(vty);
- break;
- case CONTROL('N'):
- vty_next_line(vty);
- break;
- case CONTROL('P'):
- vty_previous_line(vty);
- break;
- case CONTROL('T'):
- vty_transpose_chars(vty);
- break;
- case CONTROL('U'):
- vty_kill_line_from_beginning(vty);
- break;
- case CONTROL('W'):
- vty_backward_kill_word(vty);
- break;
- case CONTROL('Z'):
- vty_end_config(vty);
- break;
- case '\n':
- case '\r':
- vty_out(vty, "%s", VTY_NEWLINE);
- vty_execute(vty);
- break;
- case '\t':
- vty_complete_command(vty);
- break;
- case '?':
- if (vty->node == AUTH_NODE
- || vty->node == AUTH_ENABLE_NODE)
- vty_self_insert(vty, buf[i]);
- else
- vty_describe_command(vty);
- break;
- case '\033':
- if (i + 1 < nbytes && buf[i + 1] == '[') {
- vty->escape = VTY_ESCAPE;
- i++;
- } else
- vty->escape = VTY_PRE_ESCAPE;
- break;
- default:
- if (buf[i] > 31 && buf[i] < 127)
- vty_self_insert(vty, buf[i]);
- break;
- }
- }
-
- /* Check status. */
- if (vty->status == VTY_CLOSE)
- vty_close(vty);
- else {
- vty_event(VTY_WRITE, vty_sock, vty);
- vty_event(VTY_READ, vty_sock, vty);
- }
- return 0;
-}
-
-/* Create new vty structure. */
-struct vty *
-vty_create (int vty_sock, void *priv)
-{
- struct vty *vty;
-
- struct termios t;
-
- tcgetattr(vty_sock, &t);
- cfmakeraw(&t);
- tcsetattr(vty_sock, TCSANOW, &t);
-
- /* Allocate new vty structure and set up default values. */
- vty = vty_new ();
- vty->fd = vty_sock;
- vty->priv = priv;
- vty->type = VTY_TERM;
- if (no_password_check)
- {
- if (host.advanced)
- vty->node = ENABLE_NODE;
- else
- vty->node = VIEW_NODE;
- }
- else
- vty->node = AUTH_NODE;
- vty->fail = 0;
- vty->cp = 0;
- vty_clear_buf (vty);
- vty->length = 0;
- memset (vty->hist, 0, sizeof (vty->hist));
- vty->hp = 0;
- vty->hindex = 0;
- vector_set_index (vtyvec, vty_sock, vty);
- vty->status = VTY_NORMAL;
- if (host.lines >= 0)
- vty->lines = host.lines;
- else
- vty->lines = -1;
-
- if (! no_password_check)
- {
- /* Vty is not available if password isn't set. */
- if (host.password == NULL && host.password_encrypt == NULL)
- {
- vty_out (vty, "Vty password is not set.%s", VTY_NEWLINE);
- vty->status = VTY_CLOSE;
- vty_close (vty);
- return NULL;
- }
- }
-
- /* Say hello to the world. */
- vty_hello (vty);
- if (! no_password_check)
- vty_out (vty, "%sUser Access Verification%s%s", VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
-
- /* Setting up terminal. */
- vty_will_echo (vty);
- vty_will_suppress_go_ahead (vty);
-
- vty_dont_linemode (vty);
- vty_do_window_size (vty);
- /* vty_dont_lflow_ahead (vty); */
-
- vty_prompt (vty);
-
- /* Add read/write thread. */
- vty_event (VTY_WRITE, vty_sock, vty);
- vty_event (VTY_READ, vty_sock, vty);
-
- return vty;
-}
-
-DEFUN(config_who, config_who_cmd, "who", "Display who is on vty\n")
-{
- unsigned int i;
- struct vty *v;
-
- for (i = 0; i < vector_active(vtyvec); i++)
- if ((v = vector_slot(vtyvec, i)) != NULL)
- vty_out(vty, "%svty[%d] %s",
- v->config ? "*" : " ", i, VTY_NEWLINE);
- return CMD_SUCCESS;
-}
-
-/* Move to vty configuration mode. */
-DEFUN(line_vty,
- line_vty_cmd,
- "line vty", "Configure a terminal line\n" "Virtual terminal\n")
-{
- vty->node = VTY_NODE;
- return CMD_SUCCESS;
-}
-
-/* vty login. */
-DEFUN(vty_login, vty_login_cmd, "login", "Enable password checking\n")
-{
- no_password_check = 0;
- return CMD_SUCCESS;
-}
-
-DEFUN(no_vty_login,
- no_vty_login_cmd, "no login", NO_STR "Enable password checking\n")
-{
- no_password_check = 1;
- return CMD_SUCCESS;
-}
-
-DEFUN(service_advanced_vty,
- service_advanced_vty_cmd,
- "service advanced-vty",
- "Set up miscellaneous service\n" "Enable advanced mode vty interface\n")
-{
- host.advanced = 1;
- return CMD_SUCCESS;
-}
-
-DEFUN(no_service_advanced_vty,
- no_service_advanced_vty_cmd,
- "no service advanced-vty",
- NO_STR
- "Set up miscellaneous service\n" "Enable advanced mode vty interface\n")
-{
- host.advanced = 0;
- return CMD_SUCCESS;
-}
-
-DEFUN(terminal_monitor,
- terminal_monitor_cmd,
- "terminal monitor",
- "Set terminal line parameters\n"
- "Copy debug output to the current terminal line\n")
-{
- vty->monitor = 1;
- return CMD_SUCCESS;
-}
-
-DEFUN(terminal_no_monitor,
- terminal_no_monitor_cmd,
- "terminal no monitor",
- "Set terminal line parameters\n"
- NO_STR "Copy debug output to the current terminal line\n")
-{
- vty->monitor = 0;
- return CMD_SUCCESS;
-}
-
-DEFUN(show_history,
- show_history_cmd,
- "show history", SHOW_STR "Display the session command history\n")
-{
- int index;
-
- for (index = vty->hindex + 1; index != vty->hindex;) {
- if (index == VTY_MAXHIST) {
- index = 0;
- continue;
- }
-
- if (vty->hist[index] != NULL)
- vty_out(vty, " %s%s", vty->hist[index], VTY_NEWLINE);
-
- index++;
- }
-
- return CMD_SUCCESS;
-}
-
-/* Display current configuration. */
-static int vty_config_write(struct vty *vty)
-{
- vty_out(vty, "line vty%s", VTY_NEWLINE);
-
- /* login */
- if (no_password_check)
- vty_out(vty, " no login%s", VTY_NEWLINE);
-
- vty_out(vty, "!%s", VTY_NEWLINE);
-
- return CMD_SUCCESS;
-}
-
-struct cmd_node vty_node = {
- VTY_NODE,
- "%s(config-line)# ",
- 1,
-};
-
-/* Reset all VTY status. */
-void vty_reset()
-{
- unsigned int i;
- struct vty *vty;
- struct thread *vty_serv_thread;
-
- for (i = 0; i < vector_active(vtyvec); i++)
- if ((vty = vector_slot(vtyvec, i)) != NULL) {
- buffer_reset(vty->obuf);
- vty->status = VTY_CLOSE;
- vty_close(vty);
- }
-
- for (i = 0; i < vector_active(Vvty_serv_thread); i++)
- if ((vty_serv_thread =
- vector_slot(Vvty_serv_thread, i)) != NULL) {
- //thread_cancel (vty_serv_thread);
- vector_slot(Vvty_serv_thread, i) = NULL;
- close(i);
- }
-}
-
-static void vty_save_cwd(void)
-{
- char cwd[MAXPATHLEN];
- char *c;
-
- c = getcwd(cwd, MAXPATHLEN);
-
- if (!c) {
- chdir(SYSCONFDIR);
- getcwd(cwd, MAXPATHLEN);
- }
-
- vty_cwd = malloc(strlen(cwd) + 1);
- strcpy(vty_cwd, cwd);
-}
-
-char *vty_get_cwd()
-{
- return vty_cwd;
-}
-
-int vty_shell_serv(struct vty *vty)
-{
- return vty->type == VTY_SHELL_SERV ? 1 : 0;
-}
-
-void vty_init_vtysh()
-{
- vtyvec = vector_init(VECTOR_MIN_SIZE);
-}
-
-/* Install vty's own commands like `who' command. */
-void vty_init()
-{
- /* For further configuration read, preserve current directory. */
- vty_save_cwd();
-
- vtyvec = vector_init(VECTOR_MIN_SIZE);
-
- /* Install bgp top node. */
- install_node(&vty_node, vty_config_write);
-
- install_element(VIEW_NODE, &config_who_cmd);
- install_element(VIEW_NODE, &show_history_cmd);
- install_element(ENABLE_NODE, &config_who_cmd);
- install_element(CONFIG_NODE, &line_vty_cmd);
- install_element(CONFIG_NODE, &service_advanced_vty_cmd);
- install_element(CONFIG_NODE, &no_service_advanced_vty_cmd);
- install_element(CONFIG_NODE, &show_history_cmd);
- install_element(ENABLE_NODE, &terminal_monitor_cmd);
- install_element(ENABLE_NODE, &terminal_no_monitor_cmd);
- install_element(ENABLE_NODE, &show_history_cmd);
-
- install_default(VTY_NODE);
-#if 0
- install_element(VTY_NODE, &vty_login_cmd);
- install_element(VTY_NODE, &no_vty_login_cmd);
-#endif
-}
diff --git a/src/vty_interface.c b/src/vty_interface.c
deleted file mode 100644
index 44531dd50..000000000
--- a/src/vty_interface.c
+++ /dev/null
@@ -1,905 +0,0 @@
-/* OpenBSC interface to quagga VTY */
-/* (C) 2009 by Harald Welte <laforge@gnumonks.org>
- * All Rights Reserved
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- */
-
-#include <stdlib.h>
-#include <unistd.h>
-#include <sys/types.h>
-
-#include <vty/command.h>
-#include <vty/vty.h>
-
-#include <arpa/inet.h>
-
-#include <openbsc/linuxlist.h>
-#include <openbsc/gsm_data.h>
-#include <openbsc/gsm_subscriber.h>
-#include <openbsc/e1_input.h>
-#include <openbsc/abis_nm.h>
-#include <openbsc/db.h>
-
-static struct gsm_network *gsmnet;
-
-struct cmd_node bts_node = {
- BTS_NODE,
- "%s(bts)#",
- 1,
-};
-
-struct cmd_node trx_node = {
- TRX_NODE,
- "%s(trx)#",
- 1,
-};
-
-struct cmd_node ts_node = {
- TS_NODE,
- "%s(ts)#",
- 1,
-};
-
-struct cmd_node subscr_node = {
- SUBSCR_NODE,
- "%s(subscriber)#",
- 1,
-};
-
-static int dummy_config_write(struct vty *v)
-{
- return CMD_SUCCESS;
-}
-
-static void net_dump_nmstate(struct vty *vty, struct gsm_nm_state *nms)
-{
- vty_out(vty,"Oper '%s', Admin %u, Avail '%s'%s",
- nm_opstate_name(nms->operational), nms->administrative,
- nm_avail_name(nms->availability), VTY_NEWLINE);
-}
-
-static void net_dump_vty(struct vty *vty, struct gsm_network *net)
-{
- vty_out(vty, "BSC is on Country Code %u, Network Code %u "
- "and has %u BTS%s", net->country_code, net->network_code,
- net->num_bts, VTY_NEWLINE);
- vty_out(vty, " Long network name: '%s'%s",
- net->name_long, VTY_NEWLINE);
- vty_out(vty, " Short network name: '%s'%s",
- net->name_short, VTY_NEWLINE);
-}
-
-DEFUN(show_net, show_net_cmd, "show network",
- SHOW_STR "Display information about a GSM NETWORK\n")
-{
- struct gsm_network *net = gsmnet;
- net_dump_vty(vty, net);
-
- return CMD_SUCCESS;
-}
-
-static void e1isl_dump_vty(struct vty *vty, struct e1inp_sign_link *e1l)
-{
- struct e1inp_line *line;
-
- if (!e1l) {
- vty_out(vty, " None%s", VTY_NEWLINE);
- return;
- }
-
- line = e1l->ts->line;
-
- vty_out(vty, " E1 Line %u, Type %s: Timeslot %u, Mode %s%s",
- line->num, line->driver->name, e1l->ts->num,
- e1inp_signtype_name(e1l->type), VTY_NEWLINE);
- vty_out(vty, " E1 TEI %u, SAPI %u%s",
- e1l->tei, e1l->sapi, VTY_NEWLINE);
-}
-
-static void bts_dump_vty(struct vty *vty, struct gsm_bts *bts)
-{
- vty_out(vty, "BTS %u is of %s type, has LAC %u, BSIC %u, TSC %u and %u TRX%s",
- bts->nr, btstype2str(bts->type), bts->location_area_code,
- bts->bsic, bts->tsc, bts->num_trx, VTY_NEWLINE);
- if (is_ipaccess_bts(bts))
- vty_out(vty, " Unit ID: %u/%u/0%s",
- bts->ip_access.site_id, bts->ip_access.bts_id,
- VTY_NEWLINE);
- vty_out(vty, " NM State: ");
- net_dump_nmstate(vty, &bts->nm_state);
- vty_out(vty, " Site Mgr NM State: ");
- net_dump_nmstate(vty, &bts->site_mgr.nm_state);
- vty_out(vty, " Paging: FIXME pending requests, %u free slots%s",
- bts->paging.available_slots, VTY_NEWLINE);
- vty_out(vty, " E1 Signalling Link:%s", VTY_NEWLINE);
- e1isl_dump_vty(vty, bts->oml_link);
- /* FIXME: oml_link, chan_desc */
-}
-
-DEFUN(show_bts, show_bts_cmd, "show bts [number]",
- SHOW_STR "Display information about a BTS\n"
- "BTS number")
-{
- struct gsm_network *net = gsmnet;
- int bts_nr;
-
- if (argc != 0) {
- /* use the BTS number that the user has specified */
- bts_nr = atoi(argv[0]);
- if (bts_nr > net->num_bts) {
- vty_out(vty, "%% can't find BTS '%s'%s", argv[0],
- VTY_NEWLINE);
- return CMD_WARNING;
- }
- bts_dump_vty(vty, &net->bts[bts_nr]);
- return CMD_SUCCESS;
- }
- /* print all BTS's */
- for (bts_nr = 0; bts_nr < net->num_bts; bts_nr++)
- bts_dump_vty(vty, &net->bts[bts_nr]);
-
- return CMD_SUCCESS;
-}
-
-static void trx_dump_vty(struct vty *vty, struct gsm_bts_trx *trx)
-{
- vty_out(vty, "TRX %u of BTS %u is on ARFCN %u%s",
- trx->nr, trx->bts->nr, trx->arfcn, VTY_NEWLINE);
- vty_out(vty, " NM State: ");
- net_dump_nmstate(vty, &trx->nm_state);
- vty_out(vty, " Baseband Transceiver NM State: ");
- net_dump_nmstate(vty, &trx->bb_transc.nm_state);
- vty_out(vty, " E1 Signalling Link:%s", VTY_NEWLINE);
- e1isl_dump_vty(vty, trx->rsl_link);
-}
-
-DEFUN(show_trx,
- show_trx_cmd,
- "show trx [bts_nr] [trx_nr]",
- SHOW_STR "Display information about a TRX\n")
-{
- struct gsm_network *net = gsmnet;
- struct gsm_bts *bts = NULL;
- struct gsm_bts_trx *trx;
- int bts_nr, trx_nr;
-
- if (argc >= 1) {
- /* use the BTS number that the user has specified */
- bts_nr = atoi(argv[0]);
- if (bts_nr >= net->num_bts) {
- vty_out(vty, "%% can't find BTS '%s'%s", argv[0],
- VTY_NEWLINE);
- return CMD_WARNING;
- }
- bts = &net->bts[bts_nr];
- }
- if (argc >= 2) {
- trx_nr = atoi(argv[1]);
- if (trx_nr >= bts->num_trx) {
- vty_out(vty, "%% can't find TRX '%s'%s", argv[1],
- VTY_NEWLINE);
- return CMD_WARNING;
- }
- trx = &bts->trx[trx_nr];
- trx_dump_vty(vty, trx);
- return CMD_SUCCESS;
- }
- if (bts) {
- /* print all TRX in this BTS */
- for (trx_nr = 0; trx_nr < bts->num_trx; trx_nr++) {
- trx = &bts->trx[trx_nr];
- trx_dump_vty(vty, trx);
- }
- return CMD_SUCCESS;
- }
-
- for (bts_nr = 0; bts_nr < net->num_bts; bts_nr++) {
- bts = &net->bts[bts_nr];
- for (trx_nr = 0; trx_nr < bts->num_trx; trx_nr++) {
- trx = &bts->trx[trx_nr];
- trx_dump_vty(vty, trx);
- }
- }
-
- return CMD_SUCCESS;
-}
-
-static void ts_dump_vty(struct vty *vty, struct gsm_bts_trx_ts *ts)
-{
- struct in_addr ia;
-
- vty_out(vty, "Timeslot %u of TRX %u in BTS %u, phys cfg %s%s",
- ts->nr, ts->trx->nr, ts->trx->bts->nr,
- gsm_pchan_name(ts->pchan), VTY_NEWLINE);
- vty_out(vty, " NM State: ");
- net_dump_nmstate(vty, &ts->nm_state);
- if (is_ipaccess_bts(ts->trx->bts)) {
- ia.s_addr = ts->abis_ip.bound_ip;
- vty_out(vty, " Bound IP: %s Port %u FC=%u F8=%u%s",
- inet_ntoa(ia), ts->abis_ip.bound_port,
- ts->abis_ip.attr_fc, ts->abis_ip.attr_f8,
- VTY_NEWLINE);
- } else {
- vty_out(vty, " E1 Line %u, Timeslot %u, Subslot %u%s",
- ts->e1_link.e1_nr, ts->e1_link.e1_ts,
- ts->e1_link.e1_ts_ss, VTY_NEWLINE);
- }
-}
-
-DEFUN(show_ts,
- show_ts_cmd,
- "show timeslot [bts_nr] [trx_nr] [ts_nr]",
- SHOW_STR "Display information about a TS\n")
-{
- struct gsm_network *net = gsmnet;
- struct gsm_bts *bts;
- struct gsm_bts_trx *trx;
- struct gsm_bts_trx_ts *ts;
- int bts_nr, trx_nr, ts_nr;
-
- if (argc >= 1) {
- /* use the BTS number that the user has specified */
- bts_nr = atoi(argv[0]);
- if (bts_nr >= net->num_bts) {
- vty_out(vty, "%% can't find BTS '%s'%s", argv[0],
- VTY_NEWLINE);
- return CMD_WARNING;
- }
- bts = &net->bts[bts_nr];
- }
- if (argc >= 2) {
- trx_nr = atoi(argv[1]);
- if (trx_nr >= bts->num_trx) {
- vty_out(vty, "%% can't find TRX '%s'%s", argv[1],
- VTY_NEWLINE);
- return CMD_WARNING;
- }
- trx = &bts->trx[trx_nr];
- }
- if (argc >= 3) {
- ts_nr = atoi(argv[2]);
- if (ts_nr >= TRX_NR_TS) {
- vty_out(vty, "%% can't find TS '%s'%s", argv[2],
- VTY_NEWLINE);
- return CMD_WARNING;
- }
- ts = &trx->ts[ts_nr];
- ts_dump_vty(vty, ts);
- return CMD_SUCCESS;
- }
- for (bts_nr = 0; bts_nr < net->num_bts; bts_nr++) {
- bts = &net->bts[bts_nr];
- for (trx_nr = 0; trx_nr < bts->num_trx; trx_nr++) {
- trx = &bts->trx[trx_nr];
- for (ts_nr = 0; ts_nr < TRX_NR_TS; ts_nr++) {
- ts = &trx->ts[ts_nr];
- ts_dump_vty(vty, ts);
- }
- }
- }
-
- return CMD_SUCCESS;
-}
-
-static void subscr_dump_vty(struct vty *vty, struct gsm_subscriber *subscr)
-{
- vty_out(vty, " ID: %lu, Authorized: %d%s", subscr->id,
- subscr->authorized, VTY_NEWLINE);
- if (subscr->name)
- vty_out(vty, " Name: '%s'%s", subscr->name, VTY_NEWLINE);
- if (subscr->extension)
- vty_out(vty, " Extension: %s%s", subscr->extension,
- VTY_NEWLINE);
- if (subscr->imsi)
- vty_out(vty, " IMSI: %s%s", subscr->imsi, VTY_NEWLINE);
- if (subscr->tmsi)
- vty_out(vty, " TMSI: %s%s", subscr->tmsi, VTY_NEWLINE);
-}
-
-static void lchan_dump_vty(struct vty *vty, struct gsm_lchan *lchan)
-{
- vty_out(vty, "Lchan %u in Timeslot %u of TRX %u in BTS %u, Type %s%s",
- lchan->nr, lchan->ts->nr, lchan->ts->trx->nr,
- lchan->ts->trx->bts->nr, gsm_lchan_name(lchan->type),
- VTY_NEWLINE);
- vty_out(vty, " Use Count: %u%s", lchan->use_count, VTY_NEWLINE);
- vty_out(vty, " BS Power %u, MS Power %u%s", lchan->bs_power,
- lchan->ms_power, VTY_NEWLINE);
- if (lchan->subscr) {
- vty_out(vty, " Subscriber:%s", VTY_NEWLINE);
- subscr_dump_vty(vty, lchan->subscr);
- } else
- vty_out(vty, " No Subscriber%s", VTY_NEWLINE);
-}
-
-static void call_dump_vty(struct vty *vty, struct gsm_call *call)
-{
- vty_out(vty, "Call Type %u, State %u, Transaction ID %u%s",
- call->type, call->state, call->transaction_id, VTY_NEWLINE);
-
- if (call->local_lchan) {
- vty_out(vty, "Call Local Channel:%s", VTY_NEWLINE);
- lchan_dump_vty(vty, call->local_lchan);
- } else
- vty_out(vty, "Call has no Local Channel%s", VTY_NEWLINE);
-
- if (call->remote_lchan) {
- vty_out(vty, "Call Remote Channel:%s", VTY_NEWLINE);
- lchan_dump_vty(vty, call->remote_lchan);
- } else
- vty_out(vty, "Call has no Remote Channel%s", VTY_NEWLINE);
-
- if (call->called_subscr) {
- vty_out(vty, "Called Subscriber:%s", VTY_NEWLINE);
- subscr_dump_vty(vty, call->called_subscr);
- } else
- vty_out(vty, "Call has no Called Subscriber%s", VTY_NEWLINE);
-}
-
-DEFUN(show_lchan,
- show_lchan_cmd,
- "show lchan [bts_nr] [trx_nr] [ts_nr] [lchan_nr]",
- SHOW_STR "Display information about a logical channel\n")
-{
- struct gsm_network *net = gsmnet;
- struct gsm_bts *bts;
- struct gsm_bts_trx *trx;
- struct gsm_bts_trx_ts *ts;
- struct gsm_lchan *lchan;
- int bts_nr, trx_nr, ts_nr, lchan_nr;
-
- if (argc >= 1) {
- /* use the BTS number that the user has specified */
- bts_nr = atoi(argv[0]);
- if (bts_nr >= net->num_bts) {
- vty_out(vty, "%% can't find BTS %s%s", argv[0],
- VTY_NEWLINE);
- return CMD_WARNING;
- }
- bts = &net->bts[bts_nr];
- }
- if (argc >= 2) {
- trx_nr = atoi(argv[1]);
- if (trx_nr >= bts->num_trx) {
- vty_out(vty, "%% can't find TRX %s%s", argv[1],
- VTY_NEWLINE);
- return CMD_WARNING;
- }
- trx = &bts->trx[trx_nr];
- }
- if (argc >= 3) {
- ts_nr = atoi(argv[2]);
- if (ts_nr >= TRX_NR_TS) {
- vty_out(vty, "%% can't find TS %s%s", argv[2],
- VTY_NEWLINE);
- return CMD_WARNING;
- }
- ts = &trx->ts[ts_nr];
- }
- if (argc >= 4) {
- lchan_nr = atoi(argv[3]);
- if (lchan_nr >= TS_MAX_LCHAN) {
- vty_out(vty, "%% can't find LCHAN %s%s", argv[3],
- VTY_NEWLINE);
- return CMD_WARNING;
- }
- lchan = &ts->lchan[lchan_nr];
- lchan_dump_vty(vty, lchan);
- return CMD_SUCCESS;
- }
- for (bts_nr = 0; bts_nr < net->num_bts; bts_nr++) {
- bts = &net->bts[bts_nr];
- for (trx_nr = 0; trx_nr < bts->num_trx; trx_nr++) {
- trx = &bts->trx[trx_nr];
- for (ts_nr = 0; ts_nr < TRX_NR_TS; ts_nr++) {
- ts = &trx->ts[ts_nr];
- for (lchan_nr = 0; lchan_nr < TS_MAX_LCHAN;
- lchan_nr++) {
- lchan = &ts->lchan[lchan_nr];
- if (lchan->type == GSM_LCHAN_NONE)
- continue;
- lchan_dump_vty(vty, lchan);
- }
- }
- }
- }
-
- return CMD_SUCCESS;
-}
-
-static void e1drv_dump_vty(struct vty *vty, struct e1inp_driver *drv)
-{
- vty_out(vty, "E1 Input Driver %s%s", drv->name, VTY_NEWLINE);
-}
-
-DEFUN(show_e1drv,
- show_e1drv_cmd,
- "show e1_driver",
- SHOW_STR "Display information about available E1 drivers\n")
-{
- struct e1inp_driver *drv;
-
- llist_for_each_entry(drv, &e1inp_driver_list, list)
- e1drv_dump_vty(vty, drv);
-
- return CMD_SUCCESS;
-}
-
-static void e1line_dump_vty(struct vty *vty, struct e1inp_line *line)
-{
- vty_out(vty, "E1 Line Number %u, Name %s, Driver %s%s",
- line->num, line->name ? line->name : "",
- line->driver->name, VTY_NEWLINE);
-}
-
-DEFUN(show_e1line,
- show_e1line_cmd,
- "show e1_line [line_nr]",
- SHOW_STR "Display information about a E1 line\n")
-{
- struct e1inp_line *line;
-
- if (argc >= 1) {
- int num = atoi(argv[0]);
- llist_for_each_entry(line, &e1inp_line_list, list) {
- if (line->num == num) {
- e1line_dump_vty(vty, line);
- return CMD_SUCCESS;
- }
- }
- return CMD_WARNING;
- }
-
- llist_for_each_entry(line, &e1inp_line_list, list)
- e1line_dump_vty(vty, line);
-
- return CMD_SUCCESS;
-}
-
-static void e1ts_dump_vty(struct vty *vty, struct e1inp_ts *ts)
-{
- vty_out(vty, "E1 Timeslot %2u of Line %u is Type %s%s",
- ts->num, ts->line->num, e1inp_tstype_name(ts->type),
- VTY_NEWLINE);
-}
-
-DEFUN(show_e1ts,
- show_e1ts_cmd,
- "show e1_timeslot [line_nr] [ts_nr]",
- SHOW_STR "Display information about a E1 timeslot\n")
-{
- struct e1inp_line *line;
- struct e1inp_ts *ts;
- int ts_nr;
-
- if (argc == 0) {
- llist_for_each_entry(line, &e1inp_line_list, list) {
- for (ts_nr = 0; ts_nr < NUM_E1_TS; ts_nr++) {
- ts = &line->ts[ts_nr];
- e1ts_dump_vty(vty, ts);
- }
- }
- return CMD_SUCCESS;
- }
- if (argc >= 1) {
- int num = atoi(argv[0]);
- llist_for_each_entry(line, &e1inp_line_list, list) {
- if (line->num == num)
- break;
- }
- if (!line || line->num != num) {
- vty_out(vty, "E1 line %s is invalid%s",
- argv[0], VTY_NEWLINE);
- return CMD_WARNING;
- }
- }
- if (argc >= 2) {
- ts_nr = atoi(argv[1]);
- if (ts_nr > NUM_E1_TS) {
- vty_out(vty, "E1 timeslot %s is invalid%s",
- argv[1], VTY_NEWLINE);
- return CMD_WARNING;
- }
- ts = &line->ts[ts_nr];
- e1ts_dump_vty(vty, ts);
- return CMD_SUCCESS;
- } else {
- for (ts_nr = 0; ts_nr < NUM_E1_TS; ts_nr++) {
- ts = &line->ts[ts_nr];
- e1ts_dump_vty(vty, ts);
- }
- return CMD_SUCCESS;
- }
- return CMD_SUCCESS;
-}
-
-static void paging_dump_vty(struct vty *vty, struct gsm_paging_request *pag)
-{
- vty_out(vty, "Paging on BTS %u%s", pag->bts->nr, VTY_NEWLINE);
- subscr_dump_vty(vty, pag->subscr);
-}
-
-static void bts_paging_dump_vty(struct vty *vty, struct gsm_bts *bts)
-{
- struct gsm_paging_request *pag;
-
- llist_for_each_entry(pag, &bts->paging.pending_requests, entry)
- paging_dump_vty(vty, pag);
-}
-
-DEFUN(show_paging,
- show_paging_cmd,
- "show paging [bts_nr]",
- SHOW_STR "Display information about paging reuqests of a BTS\n")
-{
- struct gsm_network *net = gsmnet;
- struct gsm_bts *bts;
- int bts_nr;
-
- if (argc >= 1) {
- /* use the BTS number that the user has specified */
- bts_nr = atoi(argv[0]);
- if (bts_nr >= net->num_bts) {
- vty_out(vty, "%% can't find BTS %s%s", argv[0],
- VTY_NEWLINE);
- return CMD_WARNING;
- }
- bts = &net->bts[bts_nr];
- bts_paging_dump_vty(vty, bts);
-
- return CMD_SUCCESS;
- }
- for (bts_nr = 0; bts_nr < net->num_bts; bts_nr++) {
- bts = &net->bts[bts_nr];
- bts_paging_dump_vty(vty, bts);
- }
-
- return CMD_SUCCESS;
-}
-
-/* per-subscriber configuration */
-DEFUN(cfg_subscr,
- cfg_subscr_cmd,
- "subscriber IMSI",
- "Select a Subscriber to configure\n")
-{
- const char *imsi = argv[0];
- struct gsm_subscriber *subscr;
-
- subscr = subscr_get_by_imsi(imsi);
- if (!subscr) {
- vty_out(vty, "%% No subscriber for IMSI %s%s",
- imsi, VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- vty->index = subscr;
- vty->node = SUBSCR_NODE;
-
- return CMD_SUCCESS;
-}
-
-
-/* per-BTS configuration */
-DEFUN(cfg_bts,
- cfg_bts_cmd,
- "bts BTS_NR",
- "Select a BTS to configure\n")
-{
- int bts_nr = atoi(argv[0]);
- struct gsm_bts *bts;
-
- if (bts_nr >= GSM_MAX_BTS) {
- vty_out(vty, "%% This Version of OpenBSC only supports %u BTS%s",
- GSM_MAX_BTS, VTY_NEWLINE);
- return CMD_WARNING;
- }
- bts = &gsmnet->bts[bts_nr];
- if (bts_nr >= gsmnet->num_bts)
- gsmnet->num_bts = bts_nr + 1;
-
- vty->index = bts;
- vty->node = BTS_NODE;
-
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_bts_type,
- cfg_bts_type_cmd,
- "type TYPE",
- "Set the BTS type\n")
-{
- struct gsm_bts *bts = vty->index;
-
- //bts->type =
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_bts_lac,
- cfg_bts_lac_cmd,
- "location_area_code <0-255>",
- "Set the Location Area Code (LAC) of this BTS\n")
-{
- struct gsm_bts *bts = vty->index;
- int lac = atoi(argv[0]);
-
- if (lac < 0 || lac > 0xff) {
- vty_out(vty, "%% LAC %d is not in the valid range (0-255)%s",
- lac, VTY_NEWLINE);
- return CMD_WARNING;
- }
- bts->location_area_code = lac;
-
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_bts_tsc,
- cfg_bts_tsc_cmd,
- "training_sequence_code <0-255>",
- "Set the Training Sequence Code (TSC) of this BTS\n")
-{
- struct gsm_bts *bts = vty->index;
- int tsc = atoi(argv[0]);
-
- if (tsc < 0 || tsc > 0xff) {
- vty_out(vty, "%% TSC %d is not in the valid range (0-255)%s",
- tsc, VTY_NEWLINE);
- return CMD_WARNING;
- }
- bts->tsc = tsc;
-
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_bts_bsic,
- cfg_bts_bsic_cmd,
- "base_station_id_code <0-63>",
- "Set the Base Station Identity Code (BSIC) of this BTS\n")
-{
- struct gsm_bts *bts = vty->index;
- int bsic = atoi(argv[0]);
-
- if (bsic < 0 || bsic > 0x3f) {
- vty_out(vty, "%% TSC %d is not in the valid range (0-255)%s",
- bsic, VTY_NEWLINE);
- return CMD_WARNING;
- }
- bts->bsic = bsic;
-
- return CMD_SUCCESS;
-}
-
-
-DEFUN(cfg_bts_unit_id,
- cfg_bts_unit_id_cmd,
- "unit_id <0-65534> <0-255>",
- "Set the BTS Unit ID of this BTS\n")
-{
- struct gsm_bts *bts = vty->index;
- int site_id = atoi(argv[0]);
- int bts_id = atoi(argv[1]);
-
- if (site_id < 0 || site_id > 65534) {
- vty_out(vty, "%% Site ID %d is not in the valid range%s",
- site_id, VTY_NEWLINE);
- return CMD_WARNING;
- }
- if (site_id < 0 || site_id > 255) {
- vty_out(vty, "%% BTS ID %d is not in the valid range%s",
- bts_id, VTY_NEWLINE);
- return CMD_WARNING;
- }
- bts->ip_access.site_id = site_id;
- bts->ip_access.bts_id = bts_id;
-
- return CMD_SUCCESS;
-}
-
-/* per TRX configuration */
-DEFUN(cfg_trx,
- cfg_trx_cmd,
- "trx TRX_NR",
- "Select a TRX to configure")
-{
- int trx_nr = atoi(argv[0]);
- struct gsm_bts *bts = vty->index;
- struct gsm_bts_trx *trx;
-
- if (trx_nr > BTS_MAX_TRX) {
- vty_out(vty, "%% This version of OpenBSC only supports %u TRX%s",
- BTS_MAX_TRX+1, VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- if (trx_nr >= bts->num_trx)
- bts->num_trx = trx_nr+1;
-
- trx = &bts->trx[trx_nr];
-
- vty->index = trx;
- vty->node = TRX_NODE;
-
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_trx_arfcn,
- cfg_trx_arfcn_cmd,
- "arfcn <1-1024>",
- "Set the ARFCN for this TRX\n")
-{
- int arfcn = atoi(argv[0]);
- struct gsm_bts_trx *trx = vty->index;
-
- /* FIXME: check if this ARFCN is supported by this TRX */
-
- trx->arfcn = arfcn;
-
- /* FIXME: patch ARFCN into SYSTEM INFORMATION */
- /* FIXME: use OML layer to update the ARFCN */
- /* FIXME: use RSL layer to update SYSTEM INFORMATION */
-
- return CMD_SUCCESS;
-}
-
-/* per TS configuration */
-DEFUN(cfg_ts,
- cfg_ts_cmd,
- "timeslot TS_NR",
- "Select a Timeslot to configure")
-{
- int ts_nr = atoi(argv[0]);
- struct gsm_bts_trx *trx = vty->index;
- struct gsm_bts_trx_ts *ts;
-
- if (ts_nr >= TRX_NR_TS) {
- vty_out(vty, "%% A GSM TRX only has %u Timeslots per TRX%s",
- TRX_NR_TS, VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- ts = &trx->ts[ts_nr];
-
- vty->index = ts;
- vty->node = TS_NODE;
-
- return CMD_SUCCESS;
-}
-
-
-/* Subscriber */
-DEFUN(show_subscr,
- show_subscr_cmd,
- "show subscriber [IMSI]",
- SHOW_STR "Display information about a subscriber\n")
-{
- const char *imsi;
- struct gsm_subscriber *subscr;
-
- if (argc >= 1) {
- imsi = argv[0];
- subscr = subscr_get_by_imsi(imsi);
- if (!subscr) {
- vty_out(vty, "%% unknown subscriber%s",
- VTY_NEWLINE);
- return CMD_WARNING;
- }
- subscr_dump_vty(vty, subscr);
-
- return CMD_SUCCESS;
- }
-
- /* FIXME: iterate over all subscribers ? */
- return CMD_WARNING;
-
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_subscr_name,
- cfg_subscr_name_cmd,
- "name NAME",
- "Set the name of the subscriber")
-{
- const char *name = argv[0];
- struct gsm_subscriber *subscr = vty->index;
-
- strncpy(subscr->name, name, sizeof(subscr->name));
-
- db_sync_subscriber(subscr);
-
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_subscr_extension,
- cfg_subscr_extension_cmd,
- "extension EXTENSION",
- "Set the extension of the subscriber")
-{
- const char *name = argv[0];
- struct gsm_subscriber *subscr = vty->index;
-
- strncpy(subscr->extension, name, sizeof(subscr->extension));
-
- db_sync_subscriber(subscr);
-
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_subscr_authorized,
- cfg_subscr_authorized_cmd,
- "auth <0-1>",
- "Set the authorization status of the subscriber")
-{
- int auth = atoi(argv[0]);
- struct gsm_subscriber *subscr = vty->index;
-
- if (auth)
- subscr->authorized = 1;
- else
- subscr->authorized = 0;
-
- db_sync_subscriber(subscr);
-
- return CMD_SUCCESS;
-}
-
-int bsc_vty_init(struct gsm_network *net)
-{
- gsmnet = net;
-
- cmd_init(1);
- vty_init();
-
- install_element(VIEW_NODE, &show_net_cmd);
- install_element(VIEW_NODE, &show_bts_cmd);
- install_element(VIEW_NODE, &show_trx_cmd);
- install_element(VIEW_NODE, &show_ts_cmd);
- install_element(VIEW_NODE, &show_lchan_cmd);
-
- install_element(VIEW_NODE, &show_e1drv_cmd);
- install_element(VIEW_NODE, &show_e1line_cmd);
- install_element(VIEW_NODE, &show_e1ts_cmd);
-
- install_element(VIEW_NODE, &show_paging_cmd);
-
- install_element(VIEW_NODE, &show_subscr_cmd);
-
- install_element(CONFIG_NODE, &cfg_bts_cmd);
- install_node(&bts_node, dummy_config_write);
- install_default(BTS_NODE);
- install_element(BTS_NODE, &cfg_bts_type_cmd);
- install_element(BTS_NODE, &cfg_bts_lac_cmd);
- install_element(BTS_NODE, &cfg_bts_tsc_cmd);
- install_element(BTS_NODE, &cfg_bts_unit_id_cmd);
-
- install_element(BTS_NODE, &cfg_trx_cmd);
- install_node(&trx_node, dummy_config_write);
- install_default(TRX_NODE);
- install_element(TRX_NODE, &cfg_trx_arfcn_cmd);
-
- install_element(TRX_NODE, &cfg_ts_cmd);
- install_node(&ts_node, dummy_config_write);
- install_default(TS_NODE);
-
- install_element(CONFIG_NODE, &cfg_subscr_cmd);
- install_node(&subscr_node, dummy_config_write);
- install_default(SUBSCR_NODE);
- install_element(SUBSCR_NODE, &cfg_subscr_name_cmd);
- install_element(SUBSCR_NODE, &cfg_subscr_extension_cmd);
- install_element(SUBSCR_NODE, &cfg_subscr_authorized_cmd);
-
- return 0;
-}