aboutsummaryrefslogtreecommitdiffstats
path: root/openbsc/src/bsc
diff options
context:
space:
mode:
Diffstat (limited to 'openbsc/src/bsc')
-rw-r--r--openbsc/src/bsc/Makefile.am21
-rw-r--r--openbsc/src/bsc/abis_nm.c3126
-rw-r--r--openbsc/src/bsc/abis_nm_ipaccess.c87
-rw-r--r--openbsc/src/bsc/abis_nm_vty.c197
-rw-r--r--openbsc/src/bsc/abis_om2000.c878
-rw-r--r--openbsc/src/bsc/abis_om2000_vty.c456
-rw-r--r--openbsc/src/bsc/abis_rsl.c1960
-rw-r--r--openbsc/src/bsc/bsc_api.c675
-rw-r--r--openbsc/src/bsc/bsc_init.c440
-rw-r--r--openbsc/src/bsc/bsc_msc.c259
-rw-r--r--openbsc/src/bsc/bsc_rll.c141
-rw-r--r--openbsc/src/bsc/bsc_vty.c2773
-rw-r--r--openbsc/src/bsc/bts_ericsson_rbs2000.c164
-rw-r--r--openbsc/src/bsc/bts_ipaccess_nanobts.c447
-rw-r--r--openbsc/src/bsc/bts_siemens_bs11.c591
-rw-r--r--openbsc/src/bsc/bts_unknown.c41
-rw-r--r--openbsc/src/bsc/chan_alloc.c507
-rw-r--r--openbsc/src/bsc/e1_config.c296
-rw-r--r--openbsc/src/bsc/gsm_04_08_utils.c655
-rw-r--r--openbsc/src/bsc/gsm_subscriber_base.c149
-rw-r--r--openbsc/src/bsc/handover_decision.c297
-rw-r--r--openbsc/src/bsc/handover_logic.c393
-rw-r--r--openbsc/src/bsc/meas_proc.c84
-rw-r--r--openbsc/src/bsc/meas_rep.c116
-rw-r--r--openbsc/src/bsc/paging.c395
-rw-r--r--openbsc/src/bsc/rest_octets.c432
-rw-r--r--openbsc/src/bsc/system_information.c606
-rw-r--r--openbsc/src/bsc/transaction.c152
28 files changed, 0 insertions, 16338 deletions
diff --git a/openbsc/src/bsc/Makefile.am b/openbsc/src/bsc/Makefile.am
deleted file mode 100644
index 91be7fa62..000000000
--- a/openbsc/src/bsc/Makefile.am
+++ /dev/null
@@ -1,21 +0,0 @@
-INCLUDES = $(all_includes) -I$(top_srcdir)/include -I$(top_builddir)
-AM_CFLAGS=-Wall $(LIBOSMOCORE_CFLAGS) $(LIBOSMOVTY_CFLAGS) $(COVERAGE_CFLAGS)
-AM_LDFLAGS = $(LIBOSMOCORE_LIBS) $(COVERAGE_LDFLAGS)
-
-noinst_LIBRARIES = libbsc.a
-
-libbsc_a_SOURCES = abis_nm.c abis_nm_vty.c \
- abis_om2000.c abis_om2000_vty.c \
- abis_rsl.c bsc_rll.c \
- paging.c \
- bts_ericsson_rbs2000.c bts_ipaccess_nanobts.c bts_siemens_bs11.c bts_unknown.c \
- chan_alloc.c \
- gsm_subscriber_base.c \
- handover_decision.c handover_logic.c meas_rep.c \
- rest_octets.c system_information.c \
- e1_config.c \
- transaction.c \
- bsc_api.c bsc_msc.c bsc_vty.c \
- gsm_04_08_utils.c \
- bsc_init.c
-
diff --git a/openbsc/src/bsc/abis_nm.c b/openbsc/src/bsc/abis_nm.c
deleted file mode 100644
index 45db8bac5..000000000
--- a/openbsc/src/bsc/abis_nm.c
+++ /dev/null
@@ -1,3126 +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 Affero General Public License as published by
- * the Free Software Foundation; either version 3 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 Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-
-#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 <osmocore/msgb.h>
-#include <osmocore/tlv.h>
-#include <osmocore/talloc.h>
-#include <openbsc/abis_nm.h>
-#include <openbsc/misdn.h>
-#include <openbsc/signal.h>
-
-#define OM_ALLOC_SIZE 1024
-#define OM_HEADROOM_SIZE 128
-#define IPACC_SEGMENT_SIZE 245
-
-/* 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 struct value_string nack_names[] = {
- { 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" },
- { 0, NULL }
-};
-
-/* Chapter 9.4.36 */
-static const struct value_string 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" },
- { NM_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" },
- { 0, NULL }
-};
-
-static const char *nack_cause_name(u_int8_t cause)
-{
- return get_value_string(nack_cause_names, cause);
-}
-
-/* Chapter 9.4.16: Event Type */
-static const struct value_string 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" },
- { 0, NULL }
-};
-
-static const char *event_type_name(u_int8_t cause)
-{
- return get_value_string(event_type_names, cause);
-}
-
-/* Chapter 9.4.63: Perceived Severity */
-static const struct value_string 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" },
- { 0, NULL }
-};
-
-static const char *severity_name(u_int8_t cause)
-{
- return get_value_string(severity_names, cause);
-}
-
-/* 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,
-};
-
-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_MEAS_RES] = { TLV_TYPE_TL16V },
- },
-};
-
-static const enum abis_nm_chan_comb chcomb4pchan[] = {
- [GSM_PCHAN_CCCH] = NM_CHANC_mainBCCH,
- [GSM_PCHAN_CCCH_SDCCH4] = NM_CHANC_BCCHComb,
- [GSM_PCHAN_TCH_F] = NM_CHANC_TCHFull,
- [GSM_PCHAN_TCH_H] = NM_CHANC_TCHHalf,
- [GSM_PCHAN_SDCCH8_SACCH8C] = NM_CHANC_SDCCH,
- [GSM_PCHAN_PDCH] = NM_CHANC_IPAC_PDCH,
- [GSM_PCHAN_TCH_F_PDCH] = NM_CHANC_IPAC_TCHFull_PDCH,
- /* FIXME: bounds check */
-};
-
-int abis_nm_chcomb4pchan(enum gsm_phys_chan_config pchan)
-{
- if (pchan < ARRAY_SIZE(chcomb4pchan))
- return chcomb4pchan[pchan];
-
- return -EINVAL;
-}
-
-int abis_nm_tlv_parse(struct tlv_parsed *tp, struct gsm_bts *bts, const u_int8_t *buf, int len)
-{
- if (!bts->model)
- return -EIO;
- return tlv_parse(tp, &bts->model->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,
- "OML");
-}
-
-/* Send a OML NM Message from BSC to BTS */
-static int abis_nm_queue_msg(struct gsm_bts *bts, struct msgb *msg)
-{
- msg->trx = bts->c0;
-
- /* queue OML messages */
- if (llist_empty(&bts->abis_queue) && !bts->abis_nm_pend) {
- bts->abis_nm_pend = OBSC_NM_W_ACK_CB(msg);
- return _abis_nm_sendmsg(msg, 0);
- } else {
- msgb_enqueue(&bts->abis_queue, msg);
- return 0;
- }
-
-}
-
-int abis_nm_sendmsg(struct gsm_bts *bts, struct msgb *msg)
-{
- OBSC_NM_W_ACK_CB(msg) = 1;
- return abis_nm_queue_msg(bts, msg);
-}
-
-static int abis_nm_sendmsg_direct(struct gsm_bts *bts, struct msgb *msg)
-{
- OBSC_NM_W_ACK_CB(msg) = 0;
- return abis_nm_queue_msg(bts, msg);
-}
-
-static int abis_nm_rcvmsg_sw(struct msgb *mb);
-
-const struct value_string abis_nm_obj_class_names[] = {
- { NM_OC_SITE_MANAGER, "SITE-MANAGER" },
- { NM_OC_BTS, "BTS" },
- { NM_OC_RADIO_CARRIER, "RADIO-CARRIER" },
- { NM_OC_BASEB_TRANSC, "BASEBAND-TRANSCEIVER" },
- { NM_OC_CHANNEL, "CHANNEL" },
- { NM_OC_BS11_ADJC, "ADJC" },
- { NM_OC_BS11_HANDOVER, "HANDOVER" },
- { NM_OC_BS11_PWR_CTRL, "POWER-CONTROL" },
- { NM_OC_BS11_BTSE, "BTSE" },
- { NM_OC_BS11_RACK, "RACK" },
- { NM_OC_BS11_TEST, "TEST" },
- { NM_OC_BS11_ENVABTSE, "ENVABTSE" },
- { NM_OC_BS11_BPORT, "BPORT" },
- { NM_OC_GPRS_NSE, "GPRS-NSE" },
- { NM_OC_GPRS_CELL, "GPRS-CELL" },
- { NM_OC_GPRS_NSVC, "GPRS-NSVC" },
- { NM_OC_BS11, "SIEMENSHW" },
- { 0, NULL }
-};
-
-static const char *obj_class_name(u_int8_t oc)
-{
- return get_value_string(abis_nm_obj_class_names, oc);
-}
-
-const char *nm_opstate_name(u_int8_t os)
-{
- switch (os) {
- case NM_OPSTATE_DISABLED:
- return "Disabled";
- case NM_OPSTATE_ENABLED:
- return "Enabled";
- case NM_OPSTATE_NULL:
- return "NULL";
- default:
- return "RFU";
- }
-}
-
-/* Chapter 9.4.7 */
-static const struct value_string avail_names[] = {
- { 0, "In test" },
- { 1, "Failed" },
- { 2, "Power off" },
- { 3, "Off line" },
- /* Not used */
- { 5, "Dependency" },
- { 6, "Degraded" },
- { 7, "Not installed" },
- { 0xff, "OK" },
- { 0, NULL }
-};
-
-const char *nm_avail_name(u_int8_t avail)
-{
- return get_value_string(avail_names, avail);
-}
-
-static struct value_string test_names[] = {
- /* FIXME: standard test names */
- { NM_IPACC_TESTNO_CHAN_USAGE, "Channel Usage" },
- { NM_IPACC_TESTNO_BCCH_CHAN_USAGE, "BCCH Channel Usage" },
- { NM_IPACC_TESTNO_FREQ_SYNC, "Frequency Synchronization" },
- { NM_IPACC_TESTNO_BCCH_INFO, "BCCH Info" },
- { NM_IPACC_TESTNO_TX_BEACON, "Transmit Beacon" },
- { NM_IPACC_TESTNO_SYSINFO_MONITOR, "System Info Monitor" },
- { NM_IPACC_TESTNO_BCCCH_MONITOR, "BCCH Monitor" },
- { 0, NULL }
-};
-
-const struct value_string abis_nm_adm_state_names[] = {
- { NM_STATE_LOCKED, "Locked" },
- { NM_STATE_UNLOCKED, "Unlocked" },
- { NM_STATE_SHUTDOWN, "Shutdown" },
- { NM_STATE_NULL, "NULL" },
- { 0, NULL }
-};
-
-const char *nm_adm_name(u_int8_t adm)
-{
- return get_value_string(abis_nm_adm_state_names, adm);
-}
-
-int nm_is_running(struct gsm_nm_state *s) {
- return (s->operational == NM_OPSTATE_ENABLED) && (
- (s->availability == NM_AVSTATE_OK) ||
- (s->availability == 0xff)
- );
-}
-
-static void debugp_foh(struct abis_om_fom_hdr *foh)
-{
- 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);
-}
-
-/* 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) {
- DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
- return NULL;
- }
- trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
- nm_state = &trx->nm_state;
- break;
- case NM_OC_BASEB_TRANSC:
- if (obj_inst->trx_nr >= bts->num_trx) {
- DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
- return NULL;
- }
- trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
- nm_state = &trx->bb_transc.nm_state;
- break;
- case NM_OC_CHANNEL:
- if (obj_inst->trx_nr >= bts->num_trx) {
- DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
- return NULL;
- }
- trx = gsm_bts_trx_num(bts, 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 = gsm_bts_trx_num(bts, obj_inst->trx_nr);
- nm_state = &trx->bs11.bbsig.nm_state;
- break;
- case BS11_OBJ_PA:
- if (obj_inst->ts_nr > bts->num_trx)
- return NULL;
- trx = gsm_bts_trx_num(bts, obj_inst->trx_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;
- case NM_OC_GPRS_NSE:
- nm_state = &bts->gprs.nse.nm_state;
- break;
- case NM_OC_GPRS_CELL:
- nm_state = &bts->gprs.cell.nm_state;
- break;
- case NM_OC_GPRS_NSVC:
- if (obj_inst->trx_nr >= ARRAY_SIZE(bts->gprs.nsvc))
- return NULL;
- nm_state = &bts->gprs.nsvc[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) {
- DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
- return NULL;
- }
- trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
- obj = trx;
- break;
- case NM_OC_BASEB_TRANSC:
- if (obj_inst->trx_nr >= bts->num_trx) {
- DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
- return NULL;
- }
- trx = gsm_bts_trx_num(bts, obj_inst->trx_nr);
- obj = &trx->bb_transc;
- break;
- case NM_OC_CHANNEL:
- if (obj_inst->trx_nr >= bts->num_trx) {
- DEBUGPC(DNM, "TRX %u does not exist ", obj_inst->trx_nr);
- return NULL;
- }
- trx = gsm_bts_trx_num(bts, 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;
- case NM_OC_GPRS_NSE:
- obj = &bts->gprs.nse;
- break;
- case NM_OC_GPRS_CELL:
- obj = &bts->gprs.cell;
- break;
- case NM_OC_GPRS_NSVC:
- if (obj_inst->trx_nr >= ARRAY_SIZE(bts->gprs.nsvc))
- return NULL;
- obj = &bts->gprs.nsvc[obj_inst->trx_nr];
- 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;
- struct nm_statechg_signal_data nsd;
-
- nsd.obj = objclass2obj(bts, obj_class, obj_inst);
- if (!nsd.obj)
- return -EINVAL;
- nm_state = objclass2nmstate(bts, obj_class, obj_inst);
- if (!nm_state)
- return -1;
-
- new_state = *nm_state;
- new_state.administrative = adm_state;
-
- nsd.obj_class = obj_class;
- nsd.old_state = nm_state;
- nsd.new_state = &new_state;
- nsd.obj_inst = obj_inst;
- dispatch_signal(SS_NM, S_NM_STATECHG_ADM, &nsd);
-
- nm_state->administrative = adm_state;
-
- return 0;
-}
-
-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;
-
- 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, "unknown object class\n");
- return -EINVAL;
- }
-
- new_state = *nm_state;
-
- abis_nm_tlv_parse(&tp, bts, 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);
- } else
- new_state.availability = 0xff;
- if (TLVP_PRESENT(&tp, NM_ATT_ADM_STATE)) {
- new_state.administrative = *TLVP_VAL(&tp, NM_ATT_ADM_STATE);
- DEBUGPC(DNM, "ADM=%2s ", nm_adm_name(new_state.administrative));
- }
- DEBUGPC(DNM, "\n");
-
- if ((new_state.administrative != 0 && nm_state->administrative == 0) ||
- new_state.operational != nm_state->operational ||
- new_state.availability != nm_state->availability) {
- /* Update the operational state of a given object in our in-memory data
- * structures and send an event to the higher layer */
- struct nm_statechg_signal_data nsd;
- nsd.obj = objclass2obj(bts, foh->obj_class, &foh->obj_inst);
- nsd.obj_class = foh->obj_class;
- nsd.old_state = nm_state;
- nsd.new_state = &new_state;
- nsd.obj_inst = &foh->obj_inst;
- dispatch_signal(SS_NM, S_NM_STATECHG_OPER, &nsd);
- nm_state->operational = new_state.operational;
- nm_state->availability = new_state.availability;
- if (nm_state->administrative == 0)
- nm_state->administrative = new_state.administrative;
- }
-#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;
- const uint8_t *p_val;
- char *p_text;
-
- DEBUGPC(DNM, "Failure Event Report ");
-
- abis_nm_tlv_parse(&tp, mb->trx->bts, 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)));
- if (TLVP_PRESENT(&tp, NM_ATT_PROB_CAUSE)) {
- p_val = TLVP_VAL(&tp, NM_ATT_PROB_CAUSE);
- DEBUGPC(DNM, "Probable cause= %02X %02X %02X ", p_val[0], p_val[1], p_val[2]);
- }
- if (TLVP_PRESENT(&tp, NM_ATT_ADD_TEXT)) {
- p_val = TLVP_VAL(&tp, NM_ATT_ADD_TEXT);
- p_text = talloc_strndup(tall_bsc_ctx, (const char *) p_val, TLVP_LEN(&tp, NM_ATT_ADD_TEXT));
- if (p_text) {
- DEBUGPC(DNM, "Additional Text=%s ", p_text);
- talloc_free(p_text);
- }
- }
-
- 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_foh(foh);
-
- //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;
- case NM_MT_TEST_REP:
- DEBUGPC(DNM, "Test Report\n");
- dispatch_signal(SS_NM, S_NM_TEST_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, const 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_parse_sw_descr(const u_int8_t *sw_descr, int sw_descr_len)
-{
- static const struct tlv_definition sw_descr_def = {
- .def = {
- [NM_ATT_FILE_ID] = { TLV_TYPE_TL16V, },
- [NM_ATT_FILE_VERSION] = { TLV_TYPE_TL16V, },
- },
- };
-
- u_int8_t tag;
- u_int16_t tag_len;
- const u_int8_t *val;
- int ofs = 0, len;
-
- /* Classic TLV parsing doesn't work well with SW_DESCR because of it's
- * nested nature and the fact you have to assume it contains only two sub
- * tags NM_ATT_FILE_VERSION & NM_ATT_FILE_ID to parse it */
-
- if (sw_descr[0] != NM_ATT_SW_DESCR) {
- DEBUGP(DNM, "SW_DESCR attribute identifier not found!\n");
- return -1;
- }
- ofs += 1;
-
- len = tlv_parse_one(&tag, &tag_len, &val,
- &sw_descr_def, &sw_descr[ofs], sw_descr_len-ofs);
- if (len < 0 || (tag != NM_ATT_FILE_ID)) {
- DEBUGP(DNM, "FILE_ID attribute identifier not found!\n");
- return -2;
- }
- ofs += len;
-
- len = tlv_parse_one(&tag, &tag_len, &val,
- &sw_descr_def, &sw_descr[ofs], sw_descr_len-ofs);
- if (len < 0 || (tag != NM_ATT_FILE_VERSION)) {
- DEBUGP(DNM, "FILE_VERSION attribute identifier not found!\n");
- return -3;
- }
- ofs += len;
-
- return ofs;
-}
-
-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);
- struct tlv_parsed tp;
- const u_int8_t *sw_config;
- int ret, sw_config_len, sw_descr_len;
-
- debugp_foh(foh);
-
- DEBUGPC(DNM, "SW Activate Request: ");
-
- DEBUGP(DNM, "Software Activate Request, 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, 0,
- foh->data, oh->length-sizeof(*foh));
-
- abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
- sw_config = TLVP_VAL(&tp, NM_ATT_SW_CONFIG);
- sw_config_len = TLVP_LEN(&tp, NM_ATT_SW_CONFIG);
- if (!TLVP_PRESENT(&tp, NM_ATT_SW_CONFIG)) {
- DEBUGP(DNM, "SW config not found! Can't continue.\n");
- return -EINVAL;
- } else {
- DEBUGP(DNM, "Found SW config: %s\n", hexdump(sw_config, sw_config_len));
- }
-
- /* Use the first SW_DESCR present in SW config */
- sw_descr_len = abis_nm_parse_sw_descr(sw_config, sw_config_len);
- if (sw_descr_len < 0)
- return -EINVAL;
-
- 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,
- sw_config, sw_descr_len);
-}
-
-/* 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, mb->trx->bts, 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, mb->trx->bts, 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;
-}
-
-static void abis_nm_queue_send_next(struct gsm_bts *bts)
-{
- int wait = 0;
- struct msgb *msg;
- /* the queue is empty */
- while (!llist_empty(&bts->abis_queue)) {
- msg = msgb_dequeue(&bts->abis_queue);
- wait = OBSC_NM_W_ACK_CB(msg);
- _abis_nm_sendmsg(msg, 0);
-
- if (wait)
- break;
- }
-
- bts->abis_nm_pend = wait;
-}
-
-/* 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;
- int ret = 0;
-
- /* 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 nm_nack_signal_data nack_data;
- struct tlv_parsed tp;
-
- debugp_foh(foh);
-
- DEBUGPC(DNM, "%s NACK ", get_value_string(nack_names, mt));
-
- abis_nm_tlv_parse(&tp, mb->trx->bts, 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");
-
- nack_data.msg = mb;
- nack_data.mt = mt;
- dispatch_signal(SS_NM, S_NM_NACK, &nack_data);
- abis_nm_queue_send_next(mb->trx->bts);
- return 0;
- }
-#if 0
- /* check if last message is to be acked */
- if (is_ack_nack(nmh->last_msgtype)) {
- if (mt == MT_ACK(nmh->last_msgtype)) {
- DEBUGP(DNM, "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 */
- DEBUGP(DNM, "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:
- ret = abis_nm_rx_chg_adm_state_ack(mb);
- break;
- case NM_MT_SW_ACT_REQ:
- ret = abis_nm_rx_sw_act_req(mb);
- break;
- case NM_MT_BS11_LMT_SESSION:
- ret = abis_nm_rx_lmt_event(mb);
- break;
- case NM_MT_CONN_MDROP_LINK_ACK:
- DEBUGP(DNM, "CONN MDROP LINK ACK\n");
- break;
- case NM_MT_IPACC_RESTART_ACK:
- dispatch_signal(SS_NM, S_NM_IPACC_RESTART_ACK, NULL);
- break;
- case NM_MT_IPACC_RESTART_NACK:
- dispatch_signal(SS_NM, S_NM_IPACC_RESTART_NACK, NULL);
- break;
- }
-
- abis_nm_queue_send_next(mb->trx->bts);
- return ret;
-}
-
-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:
- rc = abis_nm_rx_ipacc(mb);
- abis_nm_queue_send_next(mb->trx->bts);
- break;
- default:
- LOGP(DNM, LOGL_ERROR, "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) {
- LOGP(DNM, LOGL_ERROR, "ABIS OML placement 0x%x not supported\n",
- oh->placement);
- if (oh->placement != ABIS_OM_PLACEMENT_FIRST)
- return -EINVAL;
- }
- if (oh->sequence != 0) {
- LOGP(DNM, LOGL_ERROR, "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) {
- LOGP(DNM, LOGL_ERROR, "ABIS OML truncated message (%u > %u)\n",
- oh->length + sizeof(*oh), l2_len);
- return -EINVAL;
- }
- if (oh->length + hlen < l2_len)
- LOGP(DNM, LOGL_ERROR, "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:
- LOGP(DNM, LOGL_ERROR, "unimplemented ABIS OML message discriminator 0x%x\n",
- oh->mdisc);
- break;
- default:
- LOGP(DNM, LOGL_ERROR, "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;
- int trx_nr;
- 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;
-
-static void sw_add_file_id_and_ver(struct abis_nm_sw *sw, struct msgb *msg)
-{
- if (sw->bts->type == GSM_BTS_TYPE_NANOBTS) {
- msgb_v_put(msg, NM_ATT_SW_DESCR);
- msgb_tl16v_put(msg, NM_ATT_FILE_ID, sw->file_id_len, sw->file_id);
- msgb_tl16v_put(msg, NM_ATT_FILE_VERSION, sw->file_version_len,
- sw->file_version);
- } else if (sw->bts->type == GSM_BTS_TYPE_BS11) {
- 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);
- } else {
- LOGP(DNM, LOGL_ERROR, "Please implement this for the BTS.\n");
- }
-}
-
-/* 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]);
-
- sw_add_file_id_and_ver(sw, msg);
- 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;
- case GSM_BTS_TYPE_NANOBTS: {
- static_assert(sizeof(seg_buf) >= IPACC_SEGMENT_SIZE, buffer_big_enough);
- len = read(sw->fd, &seg_buf, IPACC_SEGMENT_SIZE);
- if (len < 0) {
- perror("read failed");
- return -EINVAL;
- }
-
- if (len != IPACC_SEGMENT_SIZE)
- sw->last_seg = 1;
-
- ++sw->seg_in_window;
- msgb_tl16v_put(msg, NM_ATT_IPACC_FILE_DATA, len, (const u_int8_t *) seg_buf);
- len += 3;
- break;
- }
- default:
- LOGP(DNM, LOGL_ERROR, "sw_load_segment needs implementation for the BTS.\n");
- /* 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_direct(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]);
-
- sw_add_file_id_and_ver(sw, msg);
- 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);
-}
-
-struct sdp_firmware {
- char magic[4];
- char more_magic[4];
- unsigned int header_length;
- unsigned int file_length;
-} __attribute__ ((packed));
-
-static int parse_sdp_header(struct abis_nm_sw *sw)
-{
- struct sdp_firmware firmware_header;
- int rc;
- struct stat stat;
-
- rc = read(sw->fd, &firmware_header, sizeof(firmware_header));
- if (rc != sizeof(firmware_header)) {
- LOGP(DNM, LOGL_ERROR, "Could not read SDP file header.\n");
- return -1;
- }
-
- if (strncmp(firmware_header.magic, " SDP", 4) != 0) {
- LOGP(DNM, LOGL_ERROR, "The magic number1 is wrong.\n");
- return -1;
- }
-
- if (firmware_header.more_magic[0] != 0x10 ||
- firmware_header.more_magic[1] != 0x02 ||
- firmware_header.more_magic[2] != 0x00 ||
- firmware_header.more_magic[3] != 0x00) {
- LOGP(DNM, LOGL_ERROR, "The more magic number is wrong.\n");
- return -1;
- }
-
-
- if (fstat(sw->fd, &stat) == -1) {
- LOGP(DNM, LOGL_ERROR, "Could not stat the file.\n");
- return -1;
- }
-
- if (ntohl(firmware_header.file_length) != stat.st_size) {
- LOGP(DNM, LOGL_ERROR, "The filesizes do not match.\n");
- return -1;
- }
-
- /* go back to the start as we checked the whole filesize.. */
- lseek(sw->fd, 0l, SEEK_SET);
- LOGP(DNM, LOGL_NOTICE, "The ipaccess SDP header is not fully understood.\n"
- "There might be checksums in the file that are not\n"
- "verified and incomplete firmware might be flashed.\n"
- "There is absolutely no WARRANTY that flashing will\n"
- "work.\n");
- return 0;
-}
-
-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;
- case GSM_BTS_TYPE_NANOBTS:
- /* TODO: extract that from the filename or content */
- rc = parse_sdp_header(sw);
- if (rc < 0) {
- fprintf(stderr, "Could not parse the ipaccess SDP header\n");
- return -1;
- }
-
- strcpy((char *)sw->file_id, "id");
- sw->file_id_len = 3;
- strcpy((char *)sw->file_version, "version");
- sw->file_version_len = 8;
- 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;
- abis_nm_queue_send_next(mb->trx->bts);
- 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;
- }
- abis_nm_queue_send_next(mb->trx->bts);
- 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);
- }
- abis_nm_queue_send_next(mb->trx->bts);
- break;
- case NM_MT_LOAD_ABORT:
- if (sw->cbfn)
- sw->cbfn(GSM_HOOK_NM_SWLOAD,
- NM_MT_LOAD_ABORT, mb,
- sw->cb_data, NULL);
- 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);
- rc = 0;
- abis_nm_queue_send_next(mb->trx->bts);
- 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);
- }
- abis_nm_queue_send_next(mb->trx->bts);
- 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);
- abis_nm_queue_send_next(mb->trx->bts);
- 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);
- abis_nm_queue_send_next(mb->trx->bts);
- 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, int trx_nr, 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->trx_nr = trx_nr;
-
- switch (bts->type) {
- case GSM_BTS_TYPE_BS11:
- sw->obj_class = NM_OC_SITE_MANAGER;
- sw->obj_instance[0] = 0xff;
- sw->obj_instance[1] = 0xff;
- sw->obj_instance[2] = 0xff;
- break;
- case GSM_BTS_TYPE_NANOBTS:
- sw->obj_class = NM_OC_BASEB_TRANSC;
- sw->obj_instance[0] = sw->bts->nr;
- sw->obj_instance[1] = sw->trx_nr;
- sw->obj_instance[2] = 0xff;
- break;
- case GSM_BTS_TYPE_UNKNOWN:
- default:
- LOGPC(DNM, LOGL_ERROR, "Software Load not properly implemented.\n");
- return -1;
- break;
- }
- 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;
- }
-
- if (sw->stream)
- percent = (ftell(sw->stream) * 100) / st.st_size;
- else
- percent = (lseek(sw->fd, 0, SEEK_CUR) * 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);
-}
-
-static int verify_chan_comb(struct gsm_bts_trx_ts *ts, u_int8_t chan_comb)
-{
- int i;
-
- /* As it turns out, the BS-11 has some very peculiar restrictions
- * on the channel combinations it allows */
- switch (ts->trx->bts->type) {
- case GSM_BTS_TYPE_BS11:
- switch (chan_comb) {
- case NM_CHANC_TCHHalf:
- case NM_CHANC_TCHHalf2:
- /* not supported */
- return -EINVAL;
- case NM_CHANC_SDCCH:
- /* only one SDCCH/8 per TRX */
- for (i = 0; i < TRX_NR_TS; i++) {
- if (i == ts->nr)
- continue;
- if (ts->trx->ts[i].nm_chan_comb ==
- NM_CHANC_SDCCH)
- return -EINVAL;
- }
- /* not allowed for TS0 of BCCH-TRX */
- if (ts->trx == ts->trx->bts->c0 &&
- ts->nr == 0)
- return -EINVAL;
- /* not on the same TRX that has a BCCH+SDCCH4
- * combination */
- if (ts->trx == ts->trx->bts->c0 &&
- (ts->trx->ts[0].nm_chan_comb == 5 ||
- ts->trx->ts[0].nm_chan_comb == 8))
- return -EINVAL;
- break;
- case NM_CHANC_mainBCCH:
- case NM_CHANC_BCCHComb:
- /* allowed only for TS0 of C0 */
- if (ts->trx != ts->trx->bts->c0 ||
- ts->nr != 0)
- return -EINVAL;
- break;
- case NM_CHANC_BCCH:
- /* allowed only for TS 2/4/6 of C0 */
- if (ts->trx != ts->trx->bts->c0)
- return -EINVAL;
- if (ts->nr != 2 && ts->nr != 4 &&
- ts->nr != 6)
- return -EINVAL;
- break;
- case 8: /* this is not like 08.58, but in fact
- * FCCH+SCH+BCCH+CCCH+SDCCH/4+SACCH/C4+CBCH */
- /* FIXME: only one CBCH allowed per cell */
- break;
- }
- break;
- case GSM_BTS_TYPE_NANOBTS:
- switch (ts->nr) {
- case 0:
- if (ts->trx->nr == 0) {
- /* only on TRX0 */
- switch (chan_comb) {
- case NM_CHANC_BCCH:
- case NM_CHANC_mainBCCH:
- case NM_CHANC_BCCHComb:
- return 0;
- break;
- default:
- return -EINVAL;
- }
- } else {
- switch (chan_comb) {
- case NM_CHANC_TCHFull:
- case NM_CHANC_TCHHalf:
- case NM_CHANC_IPAC_TCHFull_TCHHalf:
- return 0;
- default:
- return -EINVAL;
- }
- }
- break;
- case 1:
- if (ts->trx->nr == 0) {
- switch (chan_comb) {
- case NM_CHANC_SDCCH_CBCH:
- if (ts->trx->ts[0].nm_chan_comb ==
- NM_CHANC_mainBCCH)
- return 0;
- return -EINVAL;
- case NM_CHANC_SDCCH:
- case NM_CHANC_TCHFull:
- case NM_CHANC_TCHHalf:
- case NM_CHANC_IPAC_TCHFull_TCHHalf:
- case NM_CHANC_IPAC_TCHFull_PDCH:
- return 0;
- }
- } else {
- switch (chan_comb) {
- case NM_CHANC_SDCCH:
- case NM_CHANC_TCHFull:
- case NM_CHANC_TCHHalf:
- case NM_CHANC_IPAC_TCHFull_TCHHalf:
- return 0;
- default:
- return -EINVAL;
- }
- }
- break;
- case 2:
- case 3:
- case 4:
- case 5:
- case 6:
- case 7:
- switch (chan_comb) {
- case NM_CHANC_TCHFull:
- case NM_CHANC_TCHHalf:
- case NM_CHANC_IPAC_TCHFull_TCHHalf:
- return 0;
- case NM_CHANC_IPAC_PDCH:
- case NM_CHANC_IPAC_TCHFull_PDCH:
- if (ts->trx->nr == 0)
- return 0;
- else
- return -EINVAL;
- }
- break;
- }
- return -EINVAL;
- default:
- /* unknown BTS type */
- return 0;
- }
- return 0;
-}
-
-/* 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_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));
- if (verify_chan_comb(ts, chan_comb) < 0) {
- msgb_free(msg);
- DEBUGP(DNM, "Invalid Channel Combination!!!\n");
- return -EINVAL;
- }
- ts->nm_chan_comb = chan_comb;
-
- 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);
- msgb_tv_put(msg, NM_ATT_CHAN_COMB, chan_comb);
- if (ts->hopping.enabled) {
- unsigned int i;
- uint8_t *len;
-
- msgb_tv_put(msg, NM_ATT_HSN, ts->hopping.hsn);
- msgb_tv_put(msg, NM_ATT_MAIO, ts->hopping.maio);
-
- /* build the ARFCN list */
- msgb_put_u8(msg, NM_ATT_ARFCN_LIST);
- len = msgb_put(msg, 1);
- *len = 0;
- for (i = 0; i < ts->hopping.arfcns.data_len*8; i++) {
- if (bitvec_get_bit_pos(&ts->hopping.arfcns, i)) {
- msgb_put_u16(msg, i);
- /* At least BS-11 wants a TLV16 here */
- if (bts->type == GSM_BTS_TYPE_BS11)
- *len += 1;
- else
- *len += sizeof(uint16_t);
- }
- }
- }
- msgb_tv_put(msg, NM_ATT_TSC, bts->tsc); /* 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_direct(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();
-
- 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);
-
- debugp_foh((struct abis_om_fom_hdr *) oh->data);
- DEBUGPC(DNM, "Sending OPSTART\n");
-
- 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, enum abis_nm_adm_state 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_conn_mdrop_link(struct gsm_bts *bts, u_int8_t e1_port0, u_int8_t ts0,
- u_int8_t e1_port1, u_int8_t ts1)
-{
- struct abis_om_hdr *oh;
- struct msgb *msg = nm_msgb_alloc();
- u_int8_t *attr;
-
- DEBUGP(DNM, "CONNECT MDROP LINK E1=(%u,%u) -> E1=(%u, %u)\n",
- e1_port0, ts0, e1_port1, ts1);
-
- oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
- fill_om_fom_hdr(oh, 6, NM_MT_CONN_MDROP_LINK,
- NM_OC_SITE_MANAGER, 0x00, 0x00, 0x00);
-
- attr = msgb_put(msg, 3);
- attr[0] = NM_ATT_MDROP_LINK;
- attr[1] = e1_port0;
- attr[2] = ts0;
-
- attr = msgb_put(msg, 3);
- attr[0] = NM_ATT_MDROP_NEXT;
- attr[1] = e1_port1;
- attr[2] = ts1;
-
- return abis_nm_sendmsg(bts, msg);
-}
-
-/* Chapter 8.7.1 */
-int abis_nm_perform_test(struct gsm_bts *bts, u_int8_t obj_class,
- u_int8_t bts_nr, u_int8_t trx_nr, u_int8_t ts_nr,
- u_int8_t test_nr, u_int8_t auton_report, struct msgb *msg)
-{
- struct abis_om_hdr *oh;
-
- DEBUGP(DNM, "PEFORM TEST %s\n", get_value_string(test_names, test_nr));
-
- if (!msg)
- msg = nm_msgb_alloc();
-
- msgb_tv_push(msg, NM_ATT_AUTON_REPORT, auton_report);
- msgb_tv_push(msg, NM_ATT_TEST_NO, test_nr);
- oh = (struct abis_om_hdr *) msgb_push(msg, ABIS_OM_FOM_HDR_SIZE);
- fill_om_fom_hdr(oh, msgb_l3len(msg), NM_MT_PERF_TEST,
- obj_class, bts_nr, trx_nr, ts_nr);
-
- 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, 0xff, 0xff);
-
- return abis_nm_sendmsg(bts, msg);
-}
-
-int abis_nm_bs11_delete_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_DELETE_OBJ, NM_OC_BS11_BPORT,
- idx, 0xff, 0xff);
-
- 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 };
-
-int abis_nm_bs11_factory_logon(struct gsm_bts *bts, int on)
-{
- return abis_nm_bs11_logon(bts, 0x02, "FACTORY", on);
-}
-
-int abis_nm_bs11_infield_logon(struct gsm_bts *bts, int on)
-{
- return abis_nm_bs11_logon(bts, 0x03, "FIELD ", on);
-}
-
-int abis_nm_bs11_logon(struct gsm_bts *bts, u_int8_t level, const char *name, 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)
- + 1 + strlen(name);
- 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,
- 1, &level);
- msgb_tlv_put(msg, NM_ATT_BS11_LMT_USER_NAME,
- strlen(name), (u_int8_t *)name);
- } 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);
-}
-
-/* Set the calibration value of the PLL (work value/set value)
- * It depends on the login which one is changed */
-int abis_nm_bs11_set_pll(struct gsm_bts *bts, int value)
-{
- struct abis_om_hdr *oh;
- struct msgb *msg;
- u_int8_t tlv_value[2];
-
- 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_TRX1, 0x00, 0x00);
-
- tlv_value[0] = value>>8;
- tlv_value[1] = value&0xff;
-
- msgb_tlv_put(msg, NM_ATT_BS11_PLL, 2, 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 */
-
-void *tall_fle_ctx;
-
-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);
- talloc_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 = talloc_zero(tall_fle_ctx, struct file_list_entry);
- if (!fle) {
- rc = -ENOMEM;
- goto out;
- }
-
- /* 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, 0xff, fle->fname,
- bs11_sw->win_size,
- bs11_sw->forced,
- &bs11_swload_cbfn, bs11_sw);
- talloc_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, 0xff, fle->fname, win_size, forced,
- bs11_swload_cbfn, bs11_sw);
- talloc_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);
-}
-
-int abis_nm_bs11_get_bport_line_cfg(struct gsm_bts *bts, u_int8_t bport)
-{
- struct abis_om_hdr *oh;
- struct msgb *msg = nm_msgb_alloc();
- u_int8_t attr = NM_ATT_BS11_LINE_CFG;
-
- 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_BPORT, bport, 0xff, 0x02);
- msgb_tlv_put(msg, NM_ATT_LIST_REQ_ATTR, sizeof(attr), &attr);
-
- return abis_nm_sendmsg(bts, msg);
-}
-
-int abis_nm_bs11_set_bport_line_cfg(struct gsm_bts *bts, u_int8_t bport, enum abis_bs11_line_cfg line_cfg)
-{
- 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);
- fill_om_fom_hdr(oh, 2, NM_MT_BS11_SET_ATTR, NM_OC_BS11_BPORT,
- bport, 0xff, 0x02);
- msgb_tv_put(msg, NM_ATT_BS11_LINE_CFG, line_cfg);
-
- 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 in_addr addr;
- 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;
- struct ipacc_ack_signal_data signal;
-
- if (strncmp((char *)&oh->data[1], ipaccess_magic, idstrlen)) {
- LOGP(DNM, LOGL_ERROR, "id string is not com.ipaccess !?!\n");
- return -EINVAL;
- }
-
- foh = (struct abis_om_fom_hdr *) (oh->data + 1 + idstrlen);
- abis_nm_tlv_parse(&tp, msg->trx->bts, foh->data, oh->length-sizeof(*foh));
-
- debugp_foh(foh);
-
- DEBUGPC(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_DST_IP)) {
- memcpy(&addr,
- TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP), sizeof(addr));
-
- DEBUGPC(DNM, "IP=%s ", inet_ntoa(addr));
- }
- if (TLVP_PRESENT(&tp, NM_ATT_IPACC_DST_IP_PORT))
- DEBUGPC(DNM, "PORT=%u ",
- ntohs(*((u_int16_t *)
- TLVP_VAL(&tp, NM_ATT_IPACC_DST_IP_PORT))));
- if (TLVP_PRESENT(&tp, NM_ATT_IPACC_STREAM_ID))
- DEBUGPC(DNM, "STREAM=0x%02x ",
- *TLVP_VAL(&tp, NM_ATT_IPACC_STREAM_ID));
- DEBUGPC(DNM, "\n");
- break;
- case NM_MT_IPACC_RSL_CONNECT_NACK:
- LOGP(DNM, LOGL_ERROR, "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:
- LOGP(DNM, LOGL_ERROR, "SET NVATTR NACK ");
- if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
- LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
- nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
- else
- LOGPC(DNM, LOGL_ERROR, "\n");
- break;
- case NM_MT_IPACC_GET_NVATTR_ACK:
- DEBUGPC(DNM, "GET NVATTR ACK\n");
- /* FIXME: decode and show the actual attributes */
- break;
- case NM_MT_IPACC_GET_NVATTR_NACK:
- LOGPC(DNM, LOGL_ERROR, "GET NVATTR NACK ");
- if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
- LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
- nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
- else
- LOGPC(DNM, LOGL_ERROR, "\n");
- break;
- case NM_MT_IPACC_SET_ATTR_ACK:
- DEBUGPC(DNM, "SET ATTR ACK\n");
- break;
- case NM_MT_IPACC_SET_ATTR_NACK:
- LOGPC(DNM, LOGL_ERROR, "SET ATTR NACK ");
- if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
- LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
- nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
- else
- LOGPC(DNM, LOGL_ERROR, "\n");
- break;
- default:
- DEBUGPC(DNM, "unknown\n");
- break;
- }
-
- /* signal handling */
- switch (foh->msg_type) {
- case NM_MT_IPACC_RSL_CONNECT_NACK:
- case NM_MT_IPACC_SET_NVATTR_NACK:
- case NM_MT_IPACC_GET_NVATTR_NACK:
- signal.trx = gsm_bts_trx_by_nr(msg->trx->bts, foh->obj_inst.trx_nr);
- signal.msg_type = foh->msg_type;
- dispatch_signal(SS_NM, S_NM_IPACC_NACK, &signal);
- break;
- case NM_MT_IPACC_SET_NVATTR_ACK:
- signal.trx = gsm_bts_trx_by_nr(msg->trx->bts, foh->obj_inst.trx_nr);
- signal.msg_type = foh->msg_type;
- dispatch_signal(SS_NM, S_NM_IPACC_ACK, &signal);
- break;
- default:
- 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_trx *trx, u_int8_t *attr,
- int attr_len)
-{
- return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_SET_NVATTR,
- NM_OC_BASEB_TRANSC, 0, trx->nr, 0xff, attr,
- attr_len);
-}
-
-int abis_nm_ipaccess_rsl_connect(struct gsm_bts_trx *trx,
- u_int32_t ip, u_int16_t port, u_int8_t stream)
-{
- struct in_addr ia;
- u_int8_t attr[] = { NM_ATT_IPACC_STREAM_ID, 0,
- NM_ATT_IPACC_DST_IP_PORT, 0, 0,
- NM_ATT_IPACC_DST_IP, 0, 0, 0, 0 };
-
- int attr_len = sizeof(attr);
-
- ia.s_addr = htonl(ip);
- attr[1] = stream;
- attr[3] = port >> 8;
- attr[4] = port & 0xff;
- *(u_int32_t *)(attr+6) = ia.s_addr;
-
- /* if ip == 0, we use the default IP */
- if (ip == 0)
- attr_len -= 5;
-
- DEBUGP(DNM, "ip.access RSL CONNECT IP=%s PORT=%u STREAM=0x%02x\n",
- inet_ntoa(ia), port, stream);
-
- return abis_nm_ipaccess_msg(trx->bts, NM_MT_IPACC_RSL_CONNECT,
- NM_OC_BASEB_TRANSC, trx->bts->bts_nr,
- trx->nr, 0xff, attr, attr_len);
-}
-
-/* restart / reboot an ip.access nanoBTS */
-int abis_nm_ipaccess_restart(struct gsm_bts_trx *trx)
-{
- 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_IPACC_RESTART, NM_OC_BASEB_TRANSC,
- trx->bts->nr, trx->nr, 0xff);
-
- return abis_nm_sendmsg(trx->bts, msg);
-}
-
-int abis_nm_ipaccess_set_attr(struct gsm_bts *bts, u_int8_t obj_class,
- u_int8_t bts_nr, u_int8_t trx_nr, u_int8_t ts_nr,
- u_int8_t *attr, u_int8_t attr_len)
-{
- return abis_nm_ipaccess_msg(bts, NM_MT_IPACC_SET_ATTR,
- obj_class, bts_nr, trx_nr, ts_nr,
- attr, attr_len);
-}
-
-void abis_nm_ipaccess_cgi(u_int8_t *buf, struct gsm_bts *bts)
-{
- /* we simply reuse the GSM48 function and overwrite the RAC
- * with the Cell ID */
- gsm48_ra_id_by_bts(buf, bts);
- *((u_int16_t *)(buf + 5)) = htons(bts->cell_identity);
-}
-
-void gsm_trx_lock_rf(struct gsm_bts_trx *trx, int locked)
-{
- int new_state = locked ? NM_STATE_LOCKED : NM_STATE_UNLOCKED;
-
- trx->nm_state.administrative = new_state;
- if (!trx->bts || !trx->bts->oml_link)
- return;
-
- abis_nm_chg_adm_state(trx->bts, NM_OC_RADIO_CARRIER,
- trx->bts->bts_nr, trx->nr, 0xff,
- new_state);
-}
-
-static const struct value_string ipacc_testres_names[] = {
- { NM_IPACC_TESTRES_SUCCESS, "SUCCESS" },
- { NM_IPACC_TESTRES_TIMEOUT, "TIMEOUT" },
- { NM_IPACC_TESTRES_NO_CHANS, "NO CHANNELS" },
- { NM_IPACC_TESTRES_PARTIAL, "PARTIAL" },
- { NM_IPACC_TESTRES_STOPPED, "STOPPED" },
- { 0, NULL }
-};
-
-const char *ipacc_testres_name(u_int8_t res)
-{
- return get_value_string(ipacc_testres_names, res);
-}
-
-void ipac_parse_cgi(struct cell_global_id *cid, const u_int8_t *buf)
-{
- cid->mcc = (buf[0] & 0xf) * 100;
- cid->mcc += (buf[0] >> 4) * 10;
- cid->mcc += (buf[1] & 0xf) * 1;
-
- if (buf[1] >> 4 == 0xf) {
- cid->mnc = (buf[2] & 0xf) * 10;
- cid->mnc += (buf[2] >> 4) * 1;
- } else {
- cid->mnc = (buf[2] & 0xf) * 100;
- cid->mnc += (buf[2] >> 4) * 10;
- cid->mnc += (buf[1] >> 4) * 1;
- }
-
- cid->lac = ntohs(*((u_int16_t *)&buf[3]));
- cid->ci = ntohs(*((u_int16_t *)&buf[5]));
-}
-
-/* parse BCCH information IEI from wire format to struct ipac_bcch_info */
-int ipac_parse_bcch_info(struct ipac_bcch_info *binf, u_int8_t *buf)
-{
- u_int8_t *cur = buf;
- u_int16_t len;
-
- memset(binf, 0, sizeof(*binf));
-
- if (cur[0] != NM_IPAC_EIE_BCCH_INFO)
- return -EINVAL;
- cur++;
-
- len = ntohs(*(u_int16_t *)cur);
- cur += 2;
-
- binf->info_type = ntohs(*(u_int16_t *)cur);
- cur += 2;
-
- if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
- binf->freq_qual = *cur >> 2;
-
- binf->arfcn = (*cur++ & 3) << 8;
- binf->arfcn |= *cur++;
-
- if (binf->info_type & IPAC_BINF_RXLEV)
- binf->rx_lev = *cur & 0x3f;
- cur++;
-
- if (binf->info_type & IPAC_BINF_RXQUAL)
- binf->rx_qual = *cur & 0x7;
- cur++;
-
- if (binf->info_type & IPAC_BINF_FREQ_ERR_QUAL)
- binf->freq_err = ntohs(*(u_int16_t *)cur);
- cur += 2;
-
- if (binf->info_type & IPAC_BINF_FRAME_OFFSET)
- binf->frame_offset = ntohs(*(u_int16_t *)cur);
- cur += 2;
-
- if (binf->info_type & IPAC_BINF_FRAME_NR_OFFSET)
- binf->frame_nr_offset = ntohl(*(u_int32_t *)cur);
- cur += 4;
-
-#if 0
- /* Somehow this is not set correctly */
- if (binf->info_type & IPAC_BINF_BSIC)
-#endif
- binf->bsic = *cur & 0x3f;
- cur++;
-
- ipac_parse_cgi(&binf->cgi, cur);
- cur += 7;
-
- if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2) {
- memcpy(binf->ba_list_si2, cur, sizeof(binf->ba_list_si2));
- cur += sizeof(binf->ba_list_si2);
- }
-
- if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2bis) {
- memcpy(binf->ba_list_si2bis, cur,
- sizeof(binf->ba_list_si2bis));
- cur += sizeof(binf->ba_list_si2bis);
- }
-
- if (binf->info_type & IPAC_BINF_NEIGH_BA_SI2ter) {
- memcpy(binf->ba_list_si2ter, cur,
- sizeof(binf->ba_list_si2ter));
- cur += sizeof(binf->ba_list_si2ter);
- }
-
- return 0;
-}
-
-void abis_nm_clear_queue(struct gsm_bts *bts)
-{
- struct msgb *msg;
-
- while (!llist_empty(&bts->abis_queue)) {
- msg = msgb_dequeue(&bts->abis_queue);
- msgb_free(msg);
- }
-
- bts->abis_nm_pend = 0;
-}
diff --git a/openbsc/src/bsc/abis_nm_ipaccess.c b/openbsc/src/bsc/abis_nm_ipaccess.c
deleted file mode 100644
index 754efe28d..000000000
--- a/openbsc/src/bsc/abis_nm_ipaccess.c
+++ /dev/null
@@ -1,87 +0,0 @@
-/* GSM Network Management (OML) messages on the A-bis interface
- * Extensions for the ip.access A-bis over IP protocol*/
-
-/* (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 Affero General Public License as published by
- * the Free Software Foundation; either version 3 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 Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-/* A list of all the 'embedded' attributes of ip.access */
-enum ipa_embedded_att {
- IPA_ATT_ARFCN_WHITELIST = 0x01,
- IPA_ATT_ARFCN_BLACKLIST = 0x02,
- IPA_ATT_FREQ_ERR_LIST = 0x03,
- IPA_ATT_CHAN_USAGE_LIST = 0x04,
- IPA_ATT_BCCH_INF_TYPE = 0x05,
- IPA_ATT_BCCH_INF = 0x06,
- IPA_ATT_CONFIG = 0x07,
- IPA_ATT_RESULT_DETAILS = 0x08,
- IPA_ATT_RXLEV_THRESH = 0x09,
- IPA_ATT_FREQ_SYNC_OPT = 0x0a,
- IPA_ATT_MAC_ADDR = 0x0b,
- IPA_ATT_HW_SW_COMPAT_NR = 0x0c,
- IPA_ATT_MANUF_SER_NR = 0x0d,
- IPA_ATT_OEM_ID = 0x0e,
- IPA_ATT_DATETIME_MANUF = 0x0f,
- IPA_ATT_DATETIME_CALIB = 0x10,
- IPA_ATT_BEACON_INF = 0x11,
- IPA_ATT_FREQ_ERR = 0x12,
- IPA_ATT_SNMP_COMM_STRING = 0x13,
- IPA_ATT_SNMP_TRAP_ADDR = 0x14,
- IPA_ATT_SNMP_TRAP_PORT = 0x15,
- IPA_ATT_SNMP_MAN_ADDR = 0x16,
- IPA_ATT_SNMP_SYS_CONTACT = 0x17,
- IPA_ATT_FACTORY_ID = 0x18,
- IPA_ATT_FACTORY_SERIAL = 0x19,
- IPA_ATT_LOGGED_EVT_IND = 0x1a,
- IPA_ATT_LOCAL_ADD_TEXT = 0x1b,
- IPA_ATT_FREQ_BANDS = 0x1c,
- IPA_ATT_MAX_TA = 0x1d,
- IPA_ATT_CIPH_ALG = 0x1e,
- IPA_ATT_CHAN_TYPES = 0x1f,
- IPA_ATT_CHAN_MODES = 0x20,
- IPA_ATT_GPRS_CODING_SCHEMES = 0x21,
- IPA_ATT_RTP_FEATURES = 0x22,
- IPA_ATT_RSL_FEATURES = 0x23,
- IPA_ATT_BTS_HW_CLASS = 0x24,
- IPA_ATT_BTS_ID = 0x25,
- IPA_ATT_BCAST_L2_MSG = 0x26,
-};
-
-/* append an ip.access channel list to the given msgb */
-static int ipa_chan_list_append(struct msgb *msg, u_int8_t ie,
- u_int16_t *arfcns, int arfcn_count)
-{
- int i;
- u_int8_t *u8;
- u_int16_t *u16;
-
- /* tag */
- u8 = msgb_push(msg, 1);
- *u8 = ie;
-
- /* length in octets */
- u16 = msgb_push(msg, 2);
- *u16 = htons(arfcn_count * 2);
-
- for (i = 0; i < arfcn_count; i++) {
- u16 = msgb_push(msg, 2);
- *u16 = htons(arfcns[i]);
- }
-
- return 0;
-}
diff --git a/openbsc/src/bsc/abis_nm_vty.c b/openbsc/src/bsc/abis_nm_vty.c
deleted file mode 100644
index 996a85749..000000000
--- a/openbsc/src/bsc/abis_nm_vty.c
+++ /dev/null
@@ -1,197 +0,0 @@
-/* VTY interface for A-bis OML (Netowrk Management) */
-
-/* (C) 2009-2010 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 Affero General Public License as published by
- * the Free Software Foundation; either version 3 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 Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-#include <stdlib.h>
-#include <unistd.h>
-#include <errno.h>
-#include <stdint.h>
-
-#include <arpa/inet.h>
-
-#include <openbsc/gsm_data.h>
-#include <osmocore/msgb.h>
-#include <osmocore/tlv.h>
-#include <osmocore/talloc.h>
-#include <openbsc/debug.h>
-#include <openbsc/signal.h>
-#include <openbsc/abis_nm.h>
-#include <openbsc/vty.h>
-
-#include <osmocom/vty/vty.h>
-#include <osmocom/vty/command.h>
-#include <osmocom/vty/logging.h>
-#include <osmocom/vty/telnet_interface.h>
-
-extern struct gsm_network *bsc_gsmnet;
-
-static struct cmd_node oml_node = {
- OML_NODE,
- "%s(oml)# ",
- 1,
-};
-
-struct oml_node_state {
- struct gsm_bts *bts;
- uint8_t obj_class;
- uint8_t obj_inst[3];
-};
-
-static int dummy_config_write(struct vty *v)
-{
- return CMD_SUCCESS;
-}
-
-/* FIXME: auto-generate those strings from the value_string lists */
-#define NM_OBJCLASS_VTY "(site-manager|bts|radio-carrier|baseband-transceiver|channel|adjc|handover|power-contorl|btse|rack|test|envabtse|bport|gprs-nse|gprs-cell|gprs-nsvc|siemenshw)"
-#define NM_OBJCLASS_VTY_HELP "FIXME"
-
-DEFUN(oml_class_inst, oml_class_inst_cmd,
- "bts <0-255> oml class " NM_OBJCLASS_VTY
- " instance <0-255> <0-255> <0-255>",
- "BTS related commands\n" "BTS Number\n"
- "Manipulate the OML managed objects\n"
- "Object Class\n" NM_OBJCLASS_VTY_HELP
- "Object Instance\n" "BTS Number\n" "TRX Number\n" "TS Number\n")
-{
- struct gsm_bts *bts;
- struct oml_node_state *oms;
- int bts_nr = atoi(argv[0]);
-
- bts = gsm_bts_num(bsc_gsmnet, bts_nr);
- if (!bts) {
- vty_out(vty, "%% No such BTS (%d)%s", bts_nr, VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- oms = talloc_zero(tall_bsc_ctx, struct oml_node_state);
- if (!oms)
- return CMD_WARNING;
-
- oms->bts = bts;
- oms->obj_class = get_string_value(abis_nm_obj_class_names, argv[1]);
- oms->obj_inst[0] = atoi(argv[2]);
- oms->obj_inst[1] = atoi(argv[3]);
- oms->obj_inst[2] = atoi(argv[4]);
-
- vty->index = oms;
- vty->node = OML_NODE;
-
- return CMD_SUCCESS;
-
-}
-
-DEFUN(oml_classnum_inst, oml_classnum_inst_cmd,
- "bts <0-255> oml class <0-255> instance <0-255> <0-255> <0-255>",
- "BTS related commands\n" "BTS Number\n"
- "Manipulate the OML managed objects\n"
- "Object Class\n" "Object Class\n"
- "Object Instance\n" "BTS Number\n" "TRX Number\n" "TS Number\n")
-{
- struct gsm_bts *bts;
- struct oml_node_state *oms;
- int bts_nr = atoi(argv[0]);
-
- bts = gsm_bts_num(bsc_gsmnet, bts_nr);
- if (!bts) {
- vty_out(vty, "%% No such BTS (%d)%s", bts_nr, VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- oms = talloc_zero(tall_bsc_ctx, struct oml_node_state);
- if (!oms)
- return CMD_WARNING;
-
- oms->bts = bts;
- oms->obj_class = atoi(argv[1]);
- oms->obj_inst[0] = atoi(argv[2]);
- oms->obj_inst[1] = atoi(argv[3]);
- oms->obj_inst[2] = atoi(argv[4]);
-
- vty->index = oms;
- vty->node = OML_NODE;
-
- return CMD_SUCCESS;
-}
-
-DEFUN(oml_attrib_get, oml_attrib_get_cmd,
- "attribute get <0-255>",
- "OML Attribute Actions\n" "Get a single OML Attribute\n"
- "OML Attribute Number\n")
-{
- struct oml_node_state *oms = vty->index;
-
- /* FIXME */
- return CMD_SUCCESS;
-}
-
-DEFUN(oml_attrib_set, oml_attrib_set_cmd,
- "attribute set <0-255> .HEX",
- "OML Attribute Actions\n" "Set a single OML Attribute\n"
- "OML Attribute Number\n")
-{
- struct oml_node_state *oms = vty->index;
-
- /* FIXME */
- return CMD_SUCCESS;
-}
-
-DEFUN(oml_chg_adm_state, oml_chg_adm_state_cmd,
- "change-adm-state (locked|unlocked|shutdown|null)",
- "Change the Administrative State\n"
- "Locked\n" "Unlocked\n" "Shutdown\n" "NULL\n")
-{
- struct oml_node_state *oms = vty->index;
- enum abis_nm_adm_state state;
-
- state = get_string_value(abis_nm_adm_state_names, argv[0]);
-
- abis_nm_chg_adm_state(oms->bts, oms->obj_class, oms->obj_inst[0],
- oms->obj_inst[1], oms->obj_inst[2], state);
-
- return CMD_SUCCESS;
-}
-
-DEFUN(oml_opstart, oml_opstart_cmd,
- "opstart", "Send an OPSTART message to the object")
-{
- struct oml_node_state *oms = vty->index;
-
- abis_nm_opstart(oms->bts, oms->obj_class, oms->obj_inst[0],
- oms->obj_inst[1], oms->obj_inst[2]);
-
- return CMD_SUCCESS;
-}
-
-int abis_nm_vty_init(void)
-{
- install_element(ENABLE_NODE, &oml_class_inst_cmd);
- install_element(ENABLE_NODE, &oml_classnum_inst_cmd);
- install_node(&oml_node, dummy_config_write);
-
- install_default(OML_NODE);
- install_element(OML_NODE, &ournode_exit_cmd);
- install_element(OML_NODE, &oml_attrib_get_cmd);
- install_element(OML_NODE, &oml_attrib_set_cmd);
- install_element(OML_NODE, &oml_chg_adm_state_cmd);
- install_element(OML_NODE, &oml_opstart_cmd);
-
- return 0;
-}
diff --git a/openbsc/src/bsc/abis_om2000.c b/openbsc/src/bsc/abis_om2000.c
deleted file mode 100644
index e7a5f8386..000000000
--- a/openbsc/src/bsc/abis_om2000.c
+++ /dev/null
@@ -1,878 +0,0 @@
-/* Ericsson RBS 2xxx GSM O&M (OM2000) messages on the A-bis interface
- * implemented based on protocol trace analysis, no formal documentation */
-
-/* (C) 2010-2011 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 Affero General Public License as published by
- * the Free Software Foundation; either version 3 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 Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-
-#include <errno.h>
-#include <unistd.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <time.h>
-#include <stdint.h>
-
-#include <arpa/inet.h>
-
-#include <osmocore/msgb.h>
-#include <osmocore/tlv.h>
-#include <osmocore/talloc.h>
-#include <osmocore/utils.h>
-
-#include <openbsc/gsm_data.h>
-#include <openbsc/debug.h>
-#include <openbsc/abis_nm.h>
-#include <openbsc/abis_om2000.h>
-#include <openbsc/signal.h>
-#include <openbsc/e1_input.h>
-
-#define OM_ALLOC_SIZE 1024
-#define OM_HEADROOM_SIZE 128
-
-/* use following functions from abis_nm.c:
- * om2k_msgb_alloc()
- * abis_om2k_sendmsg()
- */
-
-struct abis_om2k_hdr {
- struct abis_om_hdr om;
- uint16_t msg_type;
- struct abis_om2k_mo mo;
- uint8_t data[0];
-} __attribute__ ((packed));
-
-enum abis_om2k_msgtype {
- OM2K_MSGT_ABORT_SP_CMD = 0x0000,
- OM2K_MSGT_ABORT_SP_COMPL = 0x0002,
- OM2K_MSGT_ALARM_REP_ACK = 0x0004,
- OM2K_MSGT_ALARM_REP_NACK = 0x0005,
- OM2K_MSGT_ALARM_REP = 0x0006,
- OM2K_MSGT_ALARM_STATUS_REQ = 0x0008,
- OM2K_MSGT_ALARM_STATUS_REQ_ACK = 0x000a,
- OM2K_MSGT_ALARM_STATUS_REQ_REJ = 0x000b,
- OM2K_MSGT_ALARM_STATUS_RES_ACK = 0x000c,
- OM2K_MSGT_ALARM_STATUS_RES_NACK = 0x000d,
- OM2K_MSGT_ALARM_STATUS_RES = 0x000e,
- OM2K_MSGT_CAL_TIME_RESP = 0x0010,
- OM2K_MSGT_CAL_TIME_REJ = 0x0011,
- OM2K_MSGT_CAL_TIME_REQ = 0x0012,
-
- OM2K_MSGT_CON_CONF_REQ = 0x0014,
- OM2K_MSGT_CON_CONF_REQ_ACK = 0x0016,
- OM2K_MSGT_CON_CONF_REQ_REJ = 0x0017,
- OM2K_MSGT_CON_CONF_RES_ACK = 0x0018,
- OM2K_MSGT_CON_CONF_RES_NACK = 0x0019,
- OM2K_MSGT_CON_CONF_RES = 0x001a,
-
- OM2K_MSGT_CONNECT_CMD = 0x001c,
- OM2K_MSGT_CONNECT_COMPL = 0x001e,
- OM2K_MSGT_CONNECT_REJ = 0x001f,
-
- OM2K_MSGT_DISABLE_REQ = 0x0028,
- OM2K_MSGT_DISABLE_REQ_ACK = 0x002a,
- OM2K_MSGT_DISABLE_REQ_REJ = 0x002b,
- OM2K_MSGT_DISABLE_RES_ACK = 0x002c,
- OM2K_MSGT_DISABLE_RES_NACK = 0x002d,
- OM2K_MSGT_DISABLE_RES = 0x002e,
- OM2K_MSGT_DISCONNECT_CMD = 0x0030,
- OM2K_MSGT_DISCONNECT_COMPL = 0x0032,
- OM2K_MSGT_DISCONNECT_REJ = 0x0033,
- OM2K_MSGT_ENABLE_REQ = 0x0034,
- OM2K_MSGT_ENABLE_REQ_ACK = 0x0036,
- OM2K_MSGT_ENABLE_REQ_REJ = 0x0037,
- OM2K_MSGT_ENABLE_RES_ACK = 0x0038,
- OM2K_MSGT_ENABLE_RES_NACK = 0x0039,
- OM2K_MSGT_ENABLE_RES = 0x003a,
-
- OM2K_MSGT_FAULT_REP_ACK = 0x0040,
- OM2K_MSGT_FAULT_REP_NACK = 0x0041,
- OM2K_MSGT_FAULT_REP = 0x0042,
-
- OM2K_MSGT_IS_CONF_REQ = 0x0060,
- OM2K_MSGT_IS_CONF_REQ_ACK = 0x0062,
- OM2K_MSGT_IS_CONF_REQ_REJ = 0x0063,
- OM2K_MSGT_IS_CONF_RES_ACK = 0x0064,
- OM2K_MSGT_IS_CONF_RES_NACK = 0x0065,
- OM2K_MSGT_IS_CONF_RES = 0x0066,
-
- OM2K_MSGT_OP_INFO = 0x0074,
- OM2K_MSGT_OP_INFO_ACK = 0x0076,
- OM2K_MSGT_OP_INFO_REJ = 0x0077,
- OM2K_MSGT_RESET_CMD = 0x0078,
- OM2K_MSGT_RESET_COMPL = 0x007a,
- OM2K_MSGT_RESET_REJ = 0x007b,
-
- OM2K_MSGT_START_REQ = 0x0084,
- OM2K_MSGT_START_REQ_ACK = 0x0086,
- OM2K_MSGT_START_REQ_REJ = 0x0087,
- OM2K_MSGT_START_RES_ACK = 0x0088,
- OM2K_MSGT_START_RES_NACK = 0x0089,
- OM2K_MSGT_START_RES = 0x008a,
- OM2K_MSGT_STATUS_REQ = 0x008c,
- OM2K_MSGT_STATUS_RESP = 0x008e,
- OM2K_MSGT_STATUS_REJ = 0x008f,
-
- OM2K_MSGT_TEST_REQ = 0x0094,
- OM2K_MSGT_TEST_REQ_ACK = 0x0096,
- OM2K_MSGT_TEST_REQ_REJ = 0x0097,
- OM2K_MSGT_TEST_RES_ACK = 0x0098,
- OM2K_MSGT_TEST_RES_NACK = 0x0099,
- OM2K_MSGT_TEST_RES = 0x009a,
-
- OM2K_MSGT_NEGOT_REQ_ACK = 0x0104,
- OM2K_MSGT_NEGOT_REQ_NACK = 0x0105,
- OM2K_MSGT_NEGOT_REQ = 0x0106,
-};
-
-enum abis_om2k_dei {
- OM2K_DEI_CAL_TIME = 0x0d,
- OM2K_DEI_CON_CONN_LIST = 0x10,
- OM2K_DEI_END_LIST_NR = 0x13,
- OM2K_DEI_IS_CONN_LIST = 0x27,
- OM2K_DEI_LIST_NR = 0x28,
- OM2K_DEI_OP_INFO = 0x2e,
- OM2K_DEI_NEGOT_REC1 = 0x90,
- OM2K_DEI_NEGOT_REC2 = 0x91,
-};
-
-enum abis_om2k_mo_cls {
- OM2K_MO_CLS_TRXC = 0x01,
- OM2K_MO_CLS_TS = 0x03,
- OM2K_MO_CLS_TF = 0x04,
- OM2K_MO_CLS_IS = 0x05,
- OM2K_MO_CLS_CON = 0x06,
- OM2K_MO_CLS_DP = 0x07,
- OM2K_MO_CLS_CF = 0x0a,
- OM2K_MO_CLS_TX = 0x0b,
- OM2K_MO_CLS_RX = 0x0c,
-};
-
-static const struct value_string om2k_msgcode_vals[] = {
- { 0x0000, "Abort SP Command" },
- { 0x0002, "Abort SP Complete" },
- { 0x0004, "Alarm Report ACK" },
- { 0x0005, "Alarm Report NACK" },
- { 0x0006, "Alarm Report" },
- { 0x0008, "Alarm Status Request" },
- { 0x000a, "Alarm Status Request Accept" },
- { 0x000b, "Alarm Status Request Reject" },
- { 0x000c, "Alarm Status Result ACK" },
- { 0x000d, "Alarm Status Result NACK" },
- { 0x000e, "Alarm Status Result" },
- { 0x0010, "Calendar Time Response" },
- { 0x0011, "Calendar Time Reject" },
- { 0x0012, "Calendar Time Request" },
- { 0x0014, "CON Configuration Request" },
- { 0x0016, "CON Configuration Request Accept" },
- { 0x0017, "CON Configuration Request Reject" },
- { 0x0018, "CON Configuration Result ACK" },
- { 0x0019, "CON Configuration Result NACK" },
- { 0x001a, "CON Configuration Result" },
- { 0x001c, "Connect Command" },
- { 0x001e, "Connect Complete" },
- { 0x001f, "Connect Rejecte" },
- { 0x0028, "Disable Request" },
- { 0x002a, "Disable Request Accept" },
- { 0x002b, "Disable Request Reject" },
- { 0x002c, "Disable Result ACK" },
- { 0x002d, "Disable Result NACK" },
- { 0x002e, "Disable Result" },
- { 0x0030, "Disconnect Command" },
- { 0x0032, "Disconnect Complete" },
- { 0x0033, "Disconnect Reject" },
- { 0x0034, "Enable Request" },
- { 0x0036, "Enable Request Accept" },
- { 0x0037, "Enable Request Reject" },
- { 0x0038, "Enable Result ACK" },
- { 0x0039, "Enable Result NACK" },
- { 0x003a, "Enable Result" },
- { 0x003c, "Escape Downlink Normal" },
- { 0x003d, "Escape Downlink NACK" },
- { 0x003e, "Escape Uplink Normal" },
- { 0x003f, "Escape Uplink NACK" },
- { 0x0040, "Fault Report ACK" },
- { 0x0041, "Fault Report NACK" },
- { 0x0042, "Fault Report" },
- { 0x0044, "File Package End Command" },
- { 0x0046, "File Package End Result" },
- { 0x0047, "File Package End Reject" },
- { 0x0048, "File Relation Request" },
- { 0x004a, "File Relation Response" },
- { 0x004b, "File Relation Request Reject" },
- { 0x004c, "File Segment Transfer" },
- { 0x004e, "File Segment Transfer Complete" },
- { 0x004f, "File Segment Transfer Reject" },
- { 0x0050, "HW Information Request" },
- { 0x0052, "HW Information Request Accept" },
- { 0x0053, "HW Information Request Reject" },
- { 0x0054, "HW Information Result ACK" },
- { 0x0055, "HW Information Result NACK" },
- { 0x0056, "HW Information Result" },
- { 0x0060, "IS Configuration Request" },
- { 0x0062, "IS Configuration Request Accept" },
- { 0x0063, "IS Configuration Request Reject" },
- { 0x0064, "IS Configuration Result ACK" },
- { 0x0065, "IS Configuration Result NACK" },
- { 0x0066, "IS Configuration Result" },
- { 0x0068, "Load Data End" },
- { 0x006a, "Load Data End Result" },
- { 0x006b, "Load Data End Reject" },
- { 0x006c, "Load Data Init" },
- { 0x006e, "Load Data Init Accept" },
- { 0x006f, "Load Data Init Reject" },
- { 0x0070, "Loop Control Command" },
- { 0x0072, "Loop Control Complete" },
- { 0x0073, "Loop Control Reject" },
- { 0x0074, "Operational Information" },
- { 0x0076, "Operational Information Accept" },
- { 0x0077, "Operational Information Reject" },
- { 0x0078, "Reset Command" },
- { 0x007a, "Reset Complete" },
- { 0x007b, "Reset Reject" },
- { 0x007c, "RX Configuration Request" },
- { 0x007e, "RX Configuration Request Accept" },
- { 0x007f, "RX Configuration Request Reject" },
- { 0x0080, "RX Configuration Result ACK" },
- { 0x0081, "RX Configuration Result NACK" },
- { 0x0082, "RX Configuration Result" },
- { 0x0084, "Start Request" },
- { 0x0086, "Start Request Accept" },
- { 0x0087, "Start Request Reject" },
- { 0x0088, "Start Result ACK" },
- { 0x0089, "Start Result NACK" },
- { 0x008a, "Start Result" },
- { 0x008c, "Status Request" },
- { 0x008e, "Status Response" },
- { 0x008f, "Status Reject" },
- { 0x0094, "Test Request" },
- { 0x0096, "Test Request Accept" },
- { 0x0097, "Test Request Reject" },
- { 0x0098, "Test Result ACK" },
- { 0x0099, "Test Result NACK" },
- { 0x009a, "Test Result" },
- { 0x00a0, "TF Configuration Request" },
- { 0x00a2, "TF Configuration Request Accept" },
- { 0x00a3, "TF Configuration Request Reject" },
- { 0x00a4, "TF Configuration Result ACK" },
- { 0x00a5, "TF Configuration Result NACK" },
- { 0x00a6, "TF Configuration Result" },
- { 0x00a8, "TS Configuration Request" },
- { 0x00aa, "TS Configuration Request Accept" },
- { 0x00ab, "TS Configuration Request Reject" },
- { 0x00ac, "TS Configuration Result ACK" },
- { 0x00ad, "TS Configuration Result NACK" },
- { 0x00ae, "TS Configuration Result" },
- { 0x00b0, "TX Configuration Request" },
- { 0x00b2, "TX Configuration Request Accept" },
- { 0x00b3, "TX Configuration Request Reject" },
- { 0x00b4, "TX Configuration Result ACK" },
- { 0x00b5, "TX Configuration Result NACK" },
- { 0x00b6, "TX Configuration Result" },
- { 0x00bc, "DIP Alarm Report ACK" },
- { 0x00bd, "DIP Alarm Report NACK" },
- { 0x00be, "DIP Alarm Report" },
- { 0x00c0, "DIP Alarm Status Request" },
- { 0x00c2, "DIP Alarm Status Response" },
- { 0x00c3, "DIP Alarm Status Reject" },
- { 0x00c4, "DIP Quality Report I ACK" },
- { 0x00c5, "DIP Quality Report I NACK" },
- { 0x00c6, "DIP Quality Report I" },
- { 0x00c8, "DIP Quality Report II ACK" },
- { 0x00c9, "DIP Quality Report II NACK" },
- { 0x00ca, "DIP Quality Report II" },
- { 0x00dc, "DP Configuration Request" },
- { 0x00de, "DP Configuration Request Accept" },
- { 0x00df, "DP Configuration Request Reject" },
- { 0x00e0, "DP Configuration Result ACK" },
- { 0x00e1, "DP Configuration Result NACK" },
- { 0x00e2, "DP Configuration Result" },
- { 0x00e4, "Capabilities HW Info Report ACK" },
- { 0x00e5, "Capabilities HW Info Report NACK" },
- { 0x00e6, "Capabilities HW Info Report" },
- { 0x00e8, "Capabilities Request" },
- { 0x00ea, "Capabilities Request Accept" },
- { 0x00eb, "Capabilities Request Reject" },
- { 0x00ec, "Capabilities Result ACK" },
- { 0x00ed, "Capabilities Result NACK" },
- { 0x00ee, "Capabilities Result" },
- { 0x00f0, "FM Configuration Request" },
- { 0x00f2, "FM Configuration Request Accept" },
- { 0x00f3, "FM Configuration Request Reject" },
- { 0x00f4, "FM Configuration Result ACK" },
- { 0x00f5, "FM Configuration Result NACK" },
- { 0x00f6, "FM Configuration Result" },
- { 0x00f8, "FM Report Request" },
- { 0x00fa, "FM Report Response" },
- { 0x00fb, "FM Report Reject" },
- { 0x00fc, "FM Start Command" },
- { 0x00fe, "FM Start Complete" },
- { 0x00ff, "FM Start Reject" },
- { 0x0100, "FM Stop Command" },
- { 0x0102, "FM Stop Complete" },
- { 0x0103, "FM Stop Reject" },
- { 0x0104, "Negotiation Request ACK" },
- { 0x0105, "Negotiation Request NACK" },
- { 0x0106, "Negotiation Request" },
- { 0x0108, "BTS Initiated Request ACK" },
- { 0x0109, "BTS Initiated Request NACK" },
- { 0x010a, "BTS Initiated Request" },
- { 0x010c, "Radio Channels Release Command" },
- { 0x010e, "Radio Channels Release Complete" },
- { 0x010f, "Radio Channels Release Reject" },
- { 0x0118, "Feature Control Command" },
- { 0x011a, "Feature Control Complete" },
- { 0x011b, "Feature Control Reject" },
-
- { 0, NULL }
-};
-
-/* TS 12.21 Section 9.4: Attributes */
-static const struct value_string om2k_attr_vals[] = {
- { 0x00, "Accordance indication" },
- { 0x01, "Alarm Id" },
- { 0x02, "Alarm Data" },
- { 0x03, "Alarm Severity" },
- { 0x04, "Alarm Status" },
- { 0x05, "Alarm Status Type" },
- { 0x06, "BCC" },
- { 0x07, "BS_AG_BKS_RES" },
- { 0x09, "BSIC" },
- { 0x0a, "BA_PA_MFRMS" },
- { 0x0b, "CBCH Indicator" },
- { 0x0c, "CCCH Options" },
- { 0x0d, "Calendar Time" },
- { 0x0f, "Channel Combination" },
- { 0x10, "CON Connection List" },
- { 0x11, "Data End Indication" },
- { 0x12, "DRX_DEV_MAX" },
- { 0x13, "End List Number" },
- { 0x14, "External Condition Map Class 1" },
- { 0x15, "External Condition Map Class 2" },
- { 0x16, "File Relation Indication" },
- { 0x17, "File Revision" },
- { 0x18, "File Segment Data" },
- { 0x19, "File Segment Length" },
- { 0x1a, "File Segment Sequence Number" },
- { 0x1b, "File Size" },
- { 0x1c, "Filling Marker" },
- { 0x1d, "FN Offset" },
- { 0x1e, "Frequency List" },
- { 0x1f, "Frequency Specifier RX" },
- { 0x20, "Frequency Specifier TX" },
- { 0x21, "HSN" },
- { 0x22, "ICM Indicator" },
- { 0x23, "Internal Fault Map Class 1A" },
- { 0x24, "Internal Fault Map Class 1B" },
- { 0x25, "Internal Fault Map Class 2A" },
- { 0x26, "Internal Fault Map Class 2A Extension" },
- { 0x27, "IS Connection List" },
- { 0x28, "List Number" },
- { 0x29, "File Package State Indication" },
- { 0x2a, "Local Access State" },
- { 0x2b, "MAIO" },
- { 0x2c, "MO State" },
- { 0x2d, "Ny1" },
- { 0x2e, "Operational Information" },
- { 0x2f, "Power" },
- { 0x30, "RU Position Data" },
- { 0x31, "Protocol Error" },
- { 0x32, "Reason Code" },
- { 0x33, "Receiver Diversity" },
- { 0x34, "Replacement Unit Map" },
- { 0x35, "Result Code" },
- { 0x36, "RU Revision Data" },
- { 0x38, "T3105" },
- { 0x39, "Test Loop Setting" },
- { 0x3a, "TF Mode" },
- { 0x3b, "TF Compensation Value" },
- { 0x3c, "Time Slot Number" },
- { 0x3d, "TSC" },
- { 0x3e, "RU Logical Id" },
- { 0x3f, "RU Serial Number Data" },
- { 0x40, "BTS Version" },
- { 0x41, "OML IWD Version" },
- { 0x42, "RWL IWD Version" },
- { 0x43, "OML Function Map 1" },
- { 0x44, "OML Function Map 2" },
- { 0x45, "RSL Function Map 1" },
- { 0x46, "RSL Function Map 2" },
- { 0x47, "Extended Range Indicator" },
- { 0x48, "Request Indicators" },
- { 0x49, "DIP Alarm Condition Map" },
- { 0x4a, "ES Incoming" },
- { 0x4b, "ES Outgoing" },
- { 0x4e, "SES Incoming" },
- { 0x4f, "SES Outgoing" },
- { 0x50, "Replacement Unit Map Extension" },
- { 0x52, "UAS Incoming" },
- { 0x53, "UAS Outgoing" },
- { 0x58, "DF Incoming" },
- { 0x5a, "DF Outgoing" },
- { 0x5c, "SF" },
- { 0x60, "S Bits Setting" },
- { 0x61, "CRC-4 Use Option" },
- { 0x62, "T Parameter" },
- { 0x63, "N Parameter" },
- { 0x64, "N1 Parameter" },
- { 0x65, "N3 Parameter" },
- { 0x66, "N4 Parameter" },
- { 0x67, "P Parameter" },
- { 0x68, "Q Parameter" },
- { 0x69, "BI_Q1" },
- { 0x6a, "BI_Q2" },
- { 0x74, "ICM Boundary Parameters" },
- { 0x77, "AFT" },
- { 0x78, "AFT RAI" },
- { 0x79, "Link Supervision Control" },
- { 0x7a, "Link Supervision Filtering Time" },
- { 0x7b, "Call Supervision Time" },
- { 0x7c, "Interval Length UAS Incoming" },
- { 0x7d, "Interval Length UAS Outgoing" },
- { 0x7e, "ICM Channel Rate" },
- { 0x7f, "Attribute Identifier" },
- { 0x80, "FM Frequency List" },
- { 0x81, "FM Frequency Report" },
- { 0x82, "FM Percentile" },
- { 0x83, "FM Clear Indication" },
- { 0x84, "HW Info Signature" },
- { 0x85, "MO Record" },
- { 0x86, "TF Synchronisation Source" },
- { 0x87, "TTA" },
- { 0x88, "End Segment Number" },
- { 0x89, "Segment Number" },
- { 0x8a, "Capabilities Signature" },
- { 0x8c, "File Relation List" },
- { 0x90, "Negotiation Record I" },
- { 0x91, "Negotiation Record II" },
- { 0x92, "Encryption Algorithm" },
- { 0x94, "Interference Rejection Combining" },
- { 0x95, "Dedication Information" },
- { 0x97, "Feature Code" },
- { 0x98, "FS Offset" },
- { 0x99, "ESB Timeslot" },
- { 0x9a, "Master TG Instance" },
- { 0x9b, "Master TX Chain Delay" },
- { 0x9c, "External Condition Class 2 Extension" },
- { 0x9d, "TSs MO State" },
- { 0, NULL }
-};
-
-const struct value_string om2k_mo_class_short_vals[] = {
- { 0x01, "TRXC" },
- { 0x03, "TS" },
- { 0x04, "TF" },
- { 0x05, "IS" },
- { 0x06, "CON" },
- { 0x07, "DP" },
- { 0x0a, "CF" },
- { 0x0b, "TX" },
- { 0x0c, "RX" },
- { 0, NULL }
-};
-
-static struct msgb *om2k_msgb_alloc(void)
-{
- return msgb_alloc_headroom(OM_ALLOC_SIZE, OM_HEADROOM_SIZE,
- "OM2000");
-}
-
-static char *om2k_mo_name(const struct abis_om2k_mo *mo)
-{
- static char mo_buf[64];
-
- memset(mo_buf, 0, sizeof(mo_buf));
- snprintf(mo_buf, sizeof(mo_buf), "%s/%02x/%02x/%02x",
- get_value_string(om2k_mo_class_short_vals, mo->class),
- mo->bts, mo->assoc_so, mo->inst);
- return mo_buf;
-}
-
-static int abis_om2k_sendmsg(struct gsm_bts *bts, struct msgb *msg)
-{
- struct abis_om2k_hdr *o2h;
- int to_trx_oml;
-
- msg->l2h = msg->data;
- o2h = (struct abis_om2k_hdr *) msg->l2h;
-
- switch (o2h->mo.class) {
- case OM2K_MO_CLS_TRXC:
- case OM2K_MO_CLS_TX:
- case OM2K_MO_CLS_RX:
- case OM2K_MO_CLS_TS:
- /* Route through per-TRX OML Link to the appropriate TRX */
- to_trx_oml = 1;
- msg->trx = gsm_bts_trx_by_nr(bts, o2h->mo.inst);
- if (!msg->trx) {
- LOGP(DNM, LOGL_ERROR, "MO=%s Tx Dropping msg to "
- "non-existing TRX\n", om2k_mo_name(&o2h->mo));
- return -ENODEV;
- }
- break;
- default:
- /* Route through the IXU/DXU OML Link */
- msg->trx = bts->c0;
- to_trx_oml = 0;
- break;
- }
-
- return _abis_nm_sendmsg(msg, to_trx_oml);
-}
-
-static void fill_om2k_hdr(struct abis_om2k_hdr *o2h, const struct abis_om2k_mo *mo,
- uint16_t msg_type, uint8_t attr_len)
-{
- o2h->om.mdisc = ABIS_OM_MDISC_FOM;
- o2h->om.placement = ABIS_OM_PLACEMENT_ONLY;
- o2h->om.sequence = 0;
- o2h->om.length = 6 + attr_len;
- o2h->msg_type = htons(msg_type);
- memcpy(&o2h->mo, mo, sizeof(o2h->mo));
-}
-
-const struct abis_om2k_mo om2k_mo_cf = { OM2K_MO_CLS_CF, 0, 0xFF, 0 };
-const struct abis_om2k_mo om2k_mo_is = { OM2K_MO_CLS_IS, 0, 0xFF, 0 };
-const struct abis_om2k_mo om2k_mo_con = { OM2K_MO_CLS_CON, 0, 0xFF, 0 };
-
-static int abis_om2k_cal_time_resp(struct gsm_bts *bts)
-{
- struct msgb *msg = om2k_msgb_alloc();
- struct abis_om2k_hdr *o2k;
- time_t tm_t;
- struct tm *tm;
-
- o2k = (struct abis_om2k_hdr *) msgb_put(msg, sizeof(*o2k));
- fill_om2k_hdr(o2k, &om2k_mo_cf, OM2K_MSGT_CAL_TIME_RESP, 7);
-
- tm_t = time(NULL);
- tm = localtime(&tm_t);
-
- msgb_put_u8(msg, OM2K_DEI_CAL_TIME);
- msgb_put_u8(msg, tm->tm_year % 100);
- msgb_put_u8(msg, tm->tm_mon + 1);
- msgb_put_u8(msg, tm->tm_mday);
- msgb_put_u8(msg, tm->tm_hour);
- msgb_put_u8(msg, tm->tm_min);
- msgb_put_u8(msg, tm->tm_sec);
-
- return abis_om2k_sendmsg(bts, msg);
-}
-
-static int abis_om2k_tx_simple(struct gsm_bts *bts, const struct abis_om2k_mo *mo,
- uint8_t msg_type)
-{
- struct msgb *msg = om2k_msgb_alloc();
- struct abis_om2k_hdr *o2k;
-
- o2k = (struct abis_om2k_hdr *) msgb_put(msg, sizeof(*o2k));
- fill_om2k_hdr(o2k, mo, msg_type, 0);
-
- DEBUGP(DNM, "Tx MO=%s %s\n", om2k_mo_name(mo),
- get_value_string(om2k_msgcode_vals, msg_type));
-
- return abis_om2k_sendmsg(bts, msg);
-}
-
-int abis_om2k_tx_reset_cmd(struct gsm_bts *bts, const struct abis_om2k_mo *mo)
-{
- return abis_om2k_tx_simple(bts, mo, OM2K_MSGT_RESET_CMD);
-}
-
-int abis_om2k_tx_start_req(struct gsm_bts *bts, const struct abis_om2k_mo *mo)
-{
- return abis_om2k_tx_simple(bts, mo, OM2K_MSGT_START_REQ);
-}
-
-int abis_om2k_tx_status_req(struct gsm_bts *bts, const struct abis_om2k_mo *mo)
-{
- return abis_om2k_tx_simple(bts, mo, OM2K_MSGT_STATUS_REQ);
-}
-
-int abis_om2k_tx_connect_cmd(struct gsm_bts *bts, const struct abis_om2k_mo *mo)
-{
- return abis_om2k_tx_simple(bts, mo, OM2K_MSGT_CONNECT_CMD);
-}
-
-int abis_om2k_tx_disconnect_cmd(struct gsm_bts *bts, const struct abis_om2k_mo *mo)
-{
- return abis_om2k_tx_simple(bts, mo, OM2K_MSGT_DISCONNECT_CMD);
-}
-
-int abis_om2k_tx_test_req(struct gsm_bts *bts, const struct abis_om2k_mo *mo)
-{
- return abis_om2k_tx_simple(bts, mo, OM2K_MSGT_TEST_REQ);
-}
-
-int abis_om2k_tx_enable_req(struct gsm_bts *bts, const struct abis_om2k_mo *mo)
-{
- return abis_om2k_tx_simple(bts, mo, OM2K_MSGT_ENABLE_REQ);
-}
-
-int abis_om2k_tx_disable_req(struct gsm_bts *bts, const struct abis_om2k_mo *mo)
-{
- return abis_om2k_tx_simple(bts, mo, OM2K_MSGT_DISABLE_REQ);
-}
-
-int abis_om2k_tx_op_info(struct gsm_bts *bts, const struct abis_om2k_mo *mo,
- uint8_t operational)
-{
- struct msgb *msg = om2k_msgb_alloc();
- struct abis_om2k_hdr *o2k;
-
- o2k = (struct abis_om2k_hdr *) msgb_put(msg, sizeof(*o2k));
- fill_om2k_hdr(o2k, mo, OM2K_MSGT_OP_INFO, 2);
-
- msgb_tv_put(msg, OM2K_DEI_OP_INFO, operational);
-
- DEBUGP(DNM, "Tx MO=%s %s\n", om2k_mo_name(mo),
- get_value_string(om2k_msgcode_vals, OM2K_MSGT_OP_INFO));
-
- return abis_om2k_sendmsg(bts, msg);
-}
-
-int abis_om2k_tx_is_conf_req(struct gsm_bts *bts, struct om2k_is_conn_grp *cg,
- unsigned int num_cg )
-{
- struct msgb *msg = om2k_msgb_alloc();
- struct abis_om2k_hdr *o2k;
-
- o2k = (struct abis_om2k_hdr *) msgb_put(msg, sizeof(*o2k));
- fill_om2k_hdr(o2k, &om2k_mo_is, OM2K_MSGT_IS_CONF_REQ,
- 2 + 2 + TLV_GROSS_LEN(num_cg * sizeof(*cg)));
-
- msgb_tv_put(msg, OM2K_DEI_LIST_NR, 1);
- msgb_tv_put(msg, OM2K_DEI_END_LIST_NR, 1);
-
- msgb_tlv_put(msg, OM2K_DEI_IS_CONN_LIST,
- num_cg * sizeof(*cg), (uint8_t *)cg);
-
- return abis_om2k_sendmsg(bts, msg);
-}
-
-int abis_om2k_tx_con_conf_req(struct gsm_bts *bts, uint8_t *data,
- unsigned int len)
-{
- struct msgb *msg = om2k_msgb_alloc();
- struct abis_om2k_hdr *o2k;
-
- o2k = (struct abis_om2k_hdr *) msgb_put(msg, sizeof(*o2k));
- fill_om2k_hdr(o2k, &om2k_mo_con, OM2K_MSGT_CON_CONF_REQ,
- 2 + 2 + TLV_GROSS_LEN(len));
-
- msgb_tv_put(msg, OM2K_DEI_LIST_NR, 1);
- msgb_tv_put(msg, OM2K_DEI_END_LIST_NR, 1);
-
- msgb_tlv_put(msg, OM2K_DEI_CON_CONN_LIST, len, data);
-
- return abis_om2k_sendmsg(bts, msg);
-}
-
-
-static int abis_om2k_tx_negot_req_ack(struct gsm_bts *bts, const struct abis_om2k_mo *mo,
- uint8_t *data, unsigned int len)
-{
- struct msgb *msg = om2k_msgb_alloc();
- struct abis_om2k_hdr *o2k;
-
- o2k = (struct abis_om2k_hdr *) msgb_put(msg, sizeof(*o2k));
- fill_om2k_hdr(o2k, mo, OM2K_MSGT_NEGOT_REQ_ACK, 2+len);
-
- msgb_tlv_put(msg, OM2K_DEI_NEGOT_REC2, len, data);
-
- DEBUGP(DNM, "Tx MO=%s %s\n", om2k_mo_name(mo),
- get_value_string(om2k_msgcode_vals, OM2K_MSGT_NEGOT_REQ_ACK));
-
- return abis_om2k_sendmsg(bts, msg);
-}
-
-struct iwd_version {
- uint8_t gen_char[3+1];
- uint8_t rev_char[3+1];
-};
-
-struct iwd_type {
- uint8_t num_vers;
- struct iwd_version v[8];
-};
-
-static int om2k_rx_negot_req(struct msgb *msg)
-{
- struct abis_om2k_hdr *o2h = msgb_l2(msg);
- struct iwd_type iwd_types[16];
- uint8_t num_iwd_types = o2h->data[2];
- uint8_t *cur = o2h->data+3;
- unsigned int i, v;
-
- uint8_t out_buf[1024];
- uint8_t *out_cur = out_buf+1;
- uint8_t out_num_types = 0;
-
- memset(iwd_types, 0, sizeof(iwd_types));
-
- /* Parse the RBS-supported IWD versions into iwd_types array */
- for (i = 0; i < num_iwd_types; i++) {
- uint8_t num_versions = *cur++;
- uint8_t iwd_type = *cur++;
-
- iwd_types[iwd_type].num_vers = num_versions;
-
- for (v = 0; v < num_versions; v++) {
- struct iwd_version *iwd_v = &iwd_types[iwd_type].v[v];
-
- memcpy(iwd_v->gen_char, cur, 3);
- cur += 3;
- memcpy(iwd_v->rev_char, cur, 3);
- cur += 3;
-
- DEBUGP(DNM, "\tIWD Type %u Gen %s Rev %s\n", iwd_type,
- iwd_v->gen_char, iwd_v->rev_char);
- }
- }
-
- /* Select the last version for each IWD type */
- for (i = 0; i < ARRAY_SIZE(iwd_types); i++) {
- struct iwd_type *type = &iwd_types[i];
- struct iwd_version *last_v;
-
- if (type->num_vers == 0)
- continue;
-
- out_num_types++;
-
- last_v = &type->v[type->num_vers-1];
-
- *out_cur++ = i;
- memcpy(out_cur, last_v->gen_char, 3);
- out_cur += 3;
- memcpy(out_cur, last_v->rev_char, 3);
- out_cur += 3;
- }
-
- out_buf[0] = out_num_types;
-
- return abis_om2k_tx_negot_req_ack(msg->trx->bts, &o2h->mo, out_buf, out_cur - out_buf);
-}
-
-static int om2k_rx_start_res(struct msgb *msg)
-{
- struct abis_om2k_hdr *o2h = msgb_l2(msg);
- int rc;
-
- rc = abis_om2k_tx_simple(msg->trx->bts, &o2h->mo, OM2K_MSGT_START_RES_ACK);
- rc = abis_om2k_tx_op_info(msg->trx->bts, &o2h->mo, 1);
-
- return rc;
-}
-
-static int om2k_rx_op_info_ack(struct msgb *msg)
-{
- struct abis_om2k_hdr *o2h = msgb_l2(msg);
-
- /* FIXME: update Operational state in our structures */
-
- return 0;
-}
-
-int abis_om2k_rcvmsg(struct msgb *msg)
-{
- struct gsm_bts *bts = msg->trx->bts;
- struct abis_om2k_hdr *o2h = msgb_l2(msg);
- struct abis_om_hdr *oh = &o2h->om;
- uint16_t msg_type = ntohs(o2h->msg_type);
- int rc = 0;
-
- /* Various consistency checks */
- if (oh->placement != ABIS_OM_PLACEMENT_ONLY) {
- LOGP(DNM, LOGL_ERROR, "ABIS OML placement 0x%x not supported\n",
- oh->placement);
- if (oh->placement != ABIS_OM_PLACEMENT_FIRST)
- return -EINVAL;
- }
- if (oh->sequence != 0) {
- LOGP(DNM, LOGL_ERROR, "ABIS OML sequence 0x%x != 0x00\n",
- oh->sequence);
- return -EINVAL;
- }
-
- msg->l3h = (unsigned char *)o2h + sizeof(*o2h);
-
- if (oh->mdisc != ABIS_OM_MDISC_FOM) {
- LOGP(DNM, LOGL_ERROR, "unknown ABIS OM2000 message discriminator 0x%x\n",
- oh->mdisc);
- return -EINVAL;
- }
-
- DEBUGP(DNM, "Rx MO=%s %s (%s)\n", om2k_mo_name(&o2h->mo),
- get_value_string(om2k_msgcode_vals, msg_type),
- hexdump(msg->l2h, msgb_l2len(msg)));
-
- switch (msg_type) {
- case OM2K_MSGT_CAL_TIME_REQ:
- rc = abis_om2k_cal_time_resp(bts);
- break;
- case OM2K_MSGT_FAULT_REP:
- rc = abis_om2k_tx_simple(bts, &o2h->mo, OM2K_MSGT_FAULT_REP_ACK);
- break;
- case OM2K_MSGT_NEGOT_REQ:
- rc = om2k_rx_negot_req(msg);
- break;
- case OM2K_MSGT_START_RES:
- rc = om2k_rx_start_res(msg);
- break;
- case OM2K_MSGT_OP_INFO_ACK:
- rc = om2k_rx_op_info_ack(msg);
- break;
- case OM2K_MSGT_IS_CONF_RES:
- rc = abis_om2k_tx_simple(bts, &o2h->mo, OM2K_MSGT_IS_CONF_RES_ACK);
- break;
- case OM2K_MSGT_CON_CONF_RES:
- rc = abis_om2k_tx_simple(bts, &o2h->mo, OM2K_MSGT_CON_CONF_RES_ACK);
- break;
- case OM2K_MSGT_CONNECT_COMPL:
- rc = abis_om2k_tx_simple(bts, &o2h->mo, OM2K_MSGT_RESET_CMD);
- break;
- case OM2K_MSGT_RESET_COMPL:
- rc = abis_om2k_tx_simple(bts, &o2h->mo, OM2K_MSGT_START_REQ);
- break;
- case OM2K_MSGT_ENABLE_RES:
- rc = abis_om2k_tx_simple(bts, &o2h->mo, OM2K_MSGT_ENABLE_RES_ACK);
- break;
- case OM2K_MSGT_DISABLE_RES:
- rc = abis_om2k_tx_simple(bts, &o2h->mo, OM2K_MSGT_DISABLE_RES_ACK);
- break;
- case OM2K_MSGT_TEST_RES:
- rc = abis_om2k_tx_simple(bts, &o2h->mo, OM2K_MSGT_TEST_RES_ACK);
- break;
- case OM2K_MSGT_STATUS_RESP:
- break;
- case OM2K_MSGT_START_REQ_ACK:
- case OM2K_MSGT_CON_CONF_REQ_ACK:
- case OM2K_MSGT_IS_CONF_REQ_ACK:
- case OM2K_MSGT_ENABLE_REQ_ACK:
- case OM2K_MSGT_ALARM_STATUS_REQ_ACK:
- case OM2K_MSGT_DISABLE_REQ_ACK:
- break;
- default:
- LOGP(DNM, LOGL_NOTICE, "Rx unhandled OM2000 msg %s\n",
- get_value_string(om2k_msgcode_vals, msg_type));
- }
-
- msgb_free(msg);
- return rc;
-}
diff --git a/openbsc/src/bsc/abis_om2000_vty.c b/openbsc/src/bsc/abis_om2000_vty.c
deleted file mode 100644
index 5949c869c..000000000
--- a/openbsc/src/bsc/abis_om2000_vty.c
+++ /dev/null
@@ -1,456 +0,0 @@
-/* VTY interface for A-bis OM2000 */
-
-/* (C) 2010-2011 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 Affero General Public License as published by
- * the Free Software Foundation; either version 3 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 Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-#include <stdlib.h>
-#include <unistd.h>
-#include <errno.h>
-#include <stdint.h>
-
-#include <arpa/inet.h>
-
-#include <openbsc/gsm_data.h>
-#include <osmocore/msgb.h>
-#include <osmocore/tlv.h>
-#include <osmocore/talloc.h>
-#include <openbsc/debug.h>
-#include <openbsc/signal.h>
-#include <openbsc/abis_om2000.h>
-#include <openbsc/vty.h>
-
-#include <osmocom/vty/vty.h>
-#include <osmocom/vty/command.h>
-#include <osmocom/vty/logging.h>
-#include <osmocom/vty/telnet_interface.h>
-
-extern struct gsm_network *bsc_gsmnet;
-
-static struct cmd_node om2k_node = {
- OM2K_NODE,
- "%s(om2k)# ",
- 1,
-};
-
-struct oml_node_state {
- struct gsm_bts *bts;
- struct abis_om2k_mo mo;
-};
-
-static int dummy_config_write(struct vty *v)
-{
- return CMD_SUCCESS;
-}
-
-/* FIXME: auto-generate those strings from the value_string lists */
-#define OM2K_OBJCLASS_VTY "(trxc|ts|tf|is|con|dp|cf|tx|rx)"
-#define OM2K_OBJCLASS_VTY_HELP "TRX Controller\n" \
- "Timeslot\n" \
- "Timing Function\n" \
- "Interface Switch\n" \
- "Abis Concentrator\n" \
- "Digital Path\n" \
- "Central Function\n" \
- "Transmitter\n" \
- "Receiver\n"
-
-DEFUN(om2k_class_inst, om2k_class_inst_cmd,
- "bts <0-255> om2000 class " OM2K_OBJCLASS_VTY
- " <0-255> <0-255> <0-255>",
- "BTS related commands\n" "BTS Number\n"
- "Manipulate the OM2000 managed objects\n"
- "Object Class\n" OM2K_OBJCLASS_VTY_HELP
- "BTS Number\n" "Associated SO Instance\n" "Instance Number\n")
-{
- struct gsm_bts *bts;
- struct oml_node_state *oms;
- int bts_nr = atoi(argv[0]);
-
- bts = gsm_bts_num(bsc_gsmnet, bts_nr);
- if (!bts) {
- vty_out(vty, "%% No such BTS (%d)%s", bts_nr, VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- if (bts->type != GSM_BTS_TYPE_RBS2000) {
- vty_out(vty, "%% BTS %d not an Ericsson RBS%s",
- bts_nr, VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- oms = talloc_zero(tall_bsc_ctx, struct oml_node_state);
- if (!oms)
- return CMD_WARNING;
-
- oms->bts = bts;
- oms->mo.class = get_string_value(om2k_mo_class_short_vals, argv[1]);
- oms->mo.bts = atoi(argv[2]);
- oms->mo.assoc_so = atoi(argv[3]);
- oms->mo.inst = atoi(argv[4]);
-
- vty->index = oms;
- vty->node = OM2K_NODE;
-
- return CMD_SUCCESS;
-
-}
-
-DEFUN(om2k_classnum_inst, om2k_classnum_inst_cmd,
- "bts <0-255> om2000 class <0-255> <0-255> <0-255> <0-255>",
- "BTS related commands\n" "BTS Number\n"
- "Manipulate the OML managed objects\n"
- "Object Class\n" "Object Class\n"
- "BTS Number\n" "Associated SO Instance\n" "Instance Number\n")
-{
- struct gsm_bts *bts;
- struct oml_node_state *oms;
- int bts_nr = atoi(argv[0]);
-
- bts = gsm_bts_num(bsc_gsmnet, bts_nr);
- if (!bts) {
- vty_out(vty, "%% No such BTS (%d)%s", bts_nr, VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- oms = talloc_zero(tall_bsc_ctx, struct oml_node_state);
- if (!oms)
- return CMD_WARNING;
-
- oms->bts = bts;
- oms->mo.class = atoi(argv[1]);
- oms->mo.bts = atoi(argv[2]);
- oms->mo.assoc_so = atoi(argv[3]);
- oms->mo.inst = atoi(argv[4]);
-
- vty->index = oms;
- vty->node = OM2K_NODE;
-
- return CMD_SUCCESS;
-}
-
-DEFUN(om2k_reset, om2k_reset_cmd,
- "reset-command",
- "Reset the MO\n")
-{
- struct oml_node_state *oms = vty->index;
-
- abis_om2k_tx_reset_cmd(oms->bts, &oms->mo);
- return CMD_SUCCESS;
-}
-
-DEFUN(om2k_start, om2k_start_cmd,
- "start-request",
- "Start the MO\n")
-{
- struct oml_node_state *oms = vty->index;
-
- abis_om2k_tx_start_req(oms->bts, &oms->mo);
- return CMD_SUCCESS;
-}
-
-DEFUN(om2k_status, om2k_status_cmd,
- "status-request",
- "Get the MO Status\n")
-{
- struct oml_node_state *oms = vty->index;
-
- abis_om2k_tx_status_req(oms->bts, &oms->mo);
- return CMD_SUCCESS;
-}
-
-DEFUN(om2k_connect, om2k_connect_cmd,
- "connect-command",
- "Connect the MO\n")
-{
- struct oml_node_state *oms = vty->index;
-
- abis_om2k_tx_connect_cmd(oms->bts, &oms->mo);
- return CMD_SUCCESS;
-}
-
-DEFUN(om2k_disconnect, om2k_disconnect_cmd,
- "disconnect-command",
- "Disconnect the MO\n")
-{
- struct oml_node_state *oms = vty->index;
-
- abis_om2k_tx_disconnect_cmd(oms->bts, &oms->mo);
- return CMD_SUCCESS;
-}
-
-DEFUN(om2k_enable, om2k_enable_cmd,
- "enable-request",
- "Enable the MO\n")
-{
- struct oml_node_state *oms = vty->index;
-
- abis_om2k_tx_enable_req(oms->bts, &oms->mo);
- return CMD_SUCCESS;
-}
-
-DEFUN(om2k_disable, om2k_disable_cmd,
- "disable-request",
- "Disable the MO\n")
-{
- struct oml_node_state *oms = vty->index;
-
- abis_om2k_tx_disable_req(oms->bts, &oms->mo);
- return CMD_SUCCESS;
-}
-
-DEFUN(om2k_op_info, om2k_op_info_cmd,
- "operational-info <0-1>",
- "Set operational information\n")
-{
- struct oml_node_state *oms = vty->index;
- int oper = atoi(argv[0]);
-
- abis_om2k_tx_op_info(oms->bts, &oms->mo, oper);
- return CMD_SUCCESS;
-}
-
-DEFUN(om2k_test, om2k_test_cmd,
- "test-request",
- "Test the MO\n")
-{
- struct oml_node_state *oms = vty->index;
-
- abis_om2k_tx_test_req(oms->bts, &oms->mo);
- return CMD_SUCCESS;
-}
-
-struct con_conn_group {
- struct llist_head list;
-
- uint8_t cg;
- uint16_t ccp;
- uint8_t tag;
- uint8_t tei;
-};
-
-static void add_con_list(struct gsm_bts *bts, uint8_t cg, uint16_t ccp,
- uint8_t tag, uint8_t tei)
-{
- struct con_conn_group *ent = talloc_zero(bts, struct con_conn_group);
-
- ent->cg = cg;
- ent->ccp = ccp;
- ent->tag = tag;
- ent->tei = tei;
-
- llist_add_tail(&ent->list, &bts->rbs2000.con.conn_groups);
-}
-
-static int del_con_list(struct gsm_bts *bts, uint8_t cg, uint16_t ccp,
- uint8_t tag, uint8_t tei)
-{
- struct con_conn_group *grp, *grp2;
-
- llist_for_each_entry_safe(grp, grp2, &bts->rbs2000.con.conn_groups, list) {
- if (grp->cg == cg && grp->ccp == ccp && grp->tag == tag
- && grp->tei == tei) {
- llist_del(&grp->list);
- talloc_free(grp);
- return 0;
- }
- }
- return -ENOENT;
-}
-
-#define CON_LIST_HELP "CON connetiton list\n" \
- "Add entry to CON list\n" \
- "Delete entry from CON list\n" \
- "Connection Group Number\n" \
- "CON Connection Point\n" \
-
-DEFUN(om2k_con_list_dec, om2k_con_list_dec_cmd,
- "con-connection-list (add|del) <1-255> <0-1023> deconcentrated",
- CON_LIST_HELP "De-concentrated in/outlet\n")
-{
- struct oml_node_state *oms = vty->index;
- struct gsm_bts *bts = oms->bts;
- uint8_t cg = atoi(argv[1]);
- uint16_t ccp = atoi(argv[2]);
-
- if (!strcmp(argv[0], "add"))
- add_con_list(bts, cg, ccp, 0, 0xff);
- else {
- if (del_con_list(bts, cg, ccp, 0, 0xff) < 0) {
- vty_out(vty, "%% No matching CON list entry%s",
- VTY_NEWLINE);
- return CMD_WARNING;
- }
- }
-
- return CMD_SUCCESS;
-}
-
-DEFUN(om2k_con_list_tei, om2k_con_list_tei_cmd,
- "con-connection-list (add|del) <1-255> <0-1023> tei <0-63>",
- CON_LIST_HELP "Concentrated in/outlet with TEI\n" "TEI Number\n")
-{
- struct oml_node_state *oms = vty->index;
- struct gsm_bts *bts = oms->bts;
- uint8_t cg = atoi(argv[1]);
- uint16_t ccp = atoi(argv[2]);
- uint8_t tei = atoi(argv[3]);
-
- if (!strcmp(argv[0], "add"))
- add_con_list(bts, cg, ccp, cg, tei);
- else {
- if (del_con_list(bts, cg, ccp, cg, tei) < 0) {
- vty_out(vty, "%% No matching CON list entry%s",
- VTY_NEWLINE);
- return CMD_WARNING;
- }
- }
-
- return CMD_SUCCESS;
-}
-
-static void om2k_fill_is_conn_grp(struct om2k_is_conn_grp *grp, uint16_t icp1,
- uint16_t icp2, uint8_t cont_idx)
-{
- grp->icp1 = htons(icp1);
- grp->icp2 = htons(icp2);
- grp->cont_idx = cont_idx;
-}
-
-struct is_conn_group {
- struct llist_head list;
- uint16_t icp1;
- uint16_t icp2;
- uint8_t ci;
-};
-
-DEFUN(cfg_bts_is_conn_list, cfg_bts_is_conn_list_cmd,
- "is-connection-list (add|del) <0-2047> <0-2047> <0-255>",
- "Interface Switch Connnection List\n"
- "Add to IS list\n" "Delete from IS list\n"
- "ICP1\n" "ICP2\n" "Contiguity Index\n")
-{
- struct gsm_bts *bts = vty->index;
- uint16_t icp1 = atoi(argv[1]);
- uint16_t icp2 = atoi(argv[2]);
- uint8_t ci = atoi(argv[3]);
- struct is_conn_group *grp, *grp2;
-
- if (!strcmp(argv[0], "add")) {
- grp = talloc_zero(bts, struct is_conn_group);
- grp->icp1 = icp1;
- grp->icp2 = icp2;
- grp->ci = ci;
- llist_add_tail(&grp->list, &bts->rbs2000.is.conn_groups);
- } else {
- llist_for_each_entry_safe(grp, grp2, &bts->rbs2000.is.conn_groups, list) {
- if (grp->icp1 == icp1 && grp->icp2 == icp2
- && grp->ci == ci) {
- llist_del(&grp->list);
- talloc_free(grp);
- return CMD_SUCCESS;
- }
- }
- vty_out(vty, "%% No matching IS Conn Group found!%s",
- VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- return CMD_SUCCESS;
-}
-
-
-DEFUN(om2k_is_conf_req, om2k_is_conf_req_cmd,
- "is-conf-req",
- "Send IS Configuration Request\n")
-{
- struct oml_node_state *oms = vty->index;
- struct gsm_bts *bts = oms->bts;
- struct is_conn_group *grp;
- unsigned int num_grps = 0, i = 0;
- struct om2k_is_conn_grp *o2grps;
-
- /* count number of groups in linked list */
- llist_for_each_entry(grp, &bts->rbs2000.is.conn_groups, list)
- num_grps++;
-
- if (!num_grps) {
- vty_out(vty, "%% No IS connection groups configured!%s",
- VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- /* allocate buffer for oml group array */
- o2grps = talloc_zero_array(bts, struct om2k_is_conn_grp, num_grps);
-
- /* fill array with data from linked list */
- llist_for_each_entry(grp, &bts->rbs2000.is.conn_groups, list)
- om2k_fill_is_conn_grp(&o2grps[i++], grp->icp1, grp->icp2, grp->ci);
-
- /* send the actual OML request */
- abis_om2k_tx_is_conf_req(oms->bts, o2grps, num_grps);
-
- talloc_free(o2grps);
-
- return CMD_SUCCESS;
-}
-
-void abis_om2k_config_write_bts(struct vty *vty, struct gsm_bts *bts)
-{
- struct is_conn_group *igrp;
- struct con_conn_group *cgrp;
-
- llist_for_each_entry(igrp, &bts->rbs2000.is.conn_groups, list)
- vty_out(vty, " is-connection-list add %u %u %u%s",
- igrp->icp1, igrp->icp2, igrp->ci, VTY_NEWLINE);
-
- llist_for_each_entry(cgrp, &bts->rbs2000.con.conn_groups, list) {
- vty_out(vty, " con-connection-list add %u %u ",
- cgrp->cg, cgrp->ccp);
- if (cgrp->tei == 0xff)
- vty_out(vty, "deconcentrated%s", VTY_NEWLINE);
- else
- vty_out(vty, "tei %u%s", cgrp->tei, VTY_NEWLINE);
- }
-}
-
-int abis_om2k_vty_init(void)
-{
- install_element(ENABLE_NODE, &om2k_class_inst_cmd);
- install_element(ENABLE_NODE, &om2k_classnum_inst_cmd);
- install_node(&om2k_node, dummy_config_write);
-
- install_default(OM2K_NODE);
- install_element(OM2K_NODE, &ournode_exit_cmd);
- install_element(OM2K_NODE, &om2k_reset_cmd);
- install_element(OM2K_NODE, &om2k_start_cmd);
- install_element(OM2K_NODE, &om2k_status_cmd);
- install_element(OM2K_NODE, &om2k_connect_cmd);
- install_element(OM2K_NODE, &om2k_disconnect_cmd);
- install_element(OM2K_NODE, &om2k_enable_cmd);
- install_element(OM2K_NODE, &om2k_disable_cmd);
- install_element(OM2K_NODE, &om2k_op_info_cmd);
- install_element(OM2K_NODE, &om2k_test_cmd);
- install_element(OM2K_NODE, &om2k_is_conf_req_cmd);
- install_element(OM2K_NODE, &om2k_con_list_dec_cmd);
- install_element(OM2K_NODE, &om2k_con_list_tei_cmd);
-
- install_element(BTS_NODE, &cfg_bts_is_conn_list_cmd);
-
- return 0;
-}
diff --git a/openbsc/src/bsc/abis_rsl.c b/openbsc/src/bsc/abis_rsl.c
deleted file mode 100644
index 07a7dc68c..000000000
--- a/openbsc/src/bsc/abis_rsl.c
+++ /dev/null
@@ -1,1960 +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-2010 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 Affero General Public License as published by
- * the Free Software Foundation; either version 3 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 Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-#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 <osmocore/gsm_utils.h>
-#include <openbsc/abis_rsl.h>
-#include <openbsc/chan_alloc.h>
-#include <openbsc/bsc_rll.h>
-#include <openbsc/debug.h>
-#include <osmocore/tlv.h>
-#include <openbsc/paging.h>
-#include <openbsc/signal.h>
-#include <openbsc/meas_rep.h>
-#include <openbsc/rtp_proxy.h>
-#include <osmocore/rsl.h>
-
-#include <osmocore/talloc.h>
-
-#define RSL_ALLOC_SIZE 1024
-#define RSL_ALLOC_HEADROOM 128
-
-#define MAX(a, b) (a) >= (b) ? (a) : (b)
-
-static int rsl_send_imm_assignment(struct gsm_lchan *lchan);
-
-static void send_lchan_signal(int sig_no, struct gsm_lchan *lchan,
- struct gsm_meas_rep *resp)
-{
- struct lchan_signal_data sig;
- sig.lchan = lchan;
- sig.mr = resp;
- dispatch_signal(SS_LCHAN, sig_no, &sig);
-}
-
-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;
-}
-
-/* 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 &&
- ts->pchan != GSM_PCHAN_PDCH &&
- ts->pchan != GSM_PCHAN_TCH_F_PDCH)
- LOGP(DRSL, LOGL_ERROR, "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)
- LOGP(DRSL, LOGL_ERROR, "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)
- LOGP(DRSL, LOGL_ERROR, "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)
- LOGP(DRSL, LOGL_ERROR, "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)
- LOGP(DRSL, LOGL_ERROR, "chan_nr=0x%02x but pchan=%u\n",
- chan_nr, ts->pchan);
- /* FIXME: we should not return first sdcch4 !!! */
- } else {
- LOGP(DRSL, LOGL_ERROR, "unknown chan_nr=0x%02x\n", chan_nr);
- return NULL;
- }
-
- lchan = &ts->lchan[lch_idx];
- log_set_context(BSC_CTX_LCHAN, lchan);
- if (lchan->conn)
- log_set_context(BSC_CTX_SUBSCR, lchan->conn->subscr);
-
- return lchan;
-}
-
-/* See Table 10.5.25 of GSM04.08 */
-static u_int8_t ts2chan_nr(const struct gsm_bts_trx_ts *ts, uint8_t lchan_nr)
-{
- u_int8_t cbits, chan_nr;
-
- switch (ts->pchan) {
- case GSM_PCHAN_TCH_F:
- case GSM_PCHAN_PDCH:
- case GSM_PCHAN_TCH_F_PDCH:
- 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;
-}
-
-u_int8_t lchan2chan_nr(const struct gsm_lchan *lchan)
-{
- return ts2chan_nr(lchan->ts, lchan->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,
- "RSL");
-}
-
-#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);
-}
-
-/* Chapter 9.3.7: Encryption Information */
-static int build_encr_info(u_int8_t *out, struct gsm_lchan *lchan)
-{
- *out++ = lchan->encr.alg_id & 0xff;
- if (lchan->encr.key_len)
- memcpy(out, lchan->encr.key, lchan->encr.key_len);
- return lchan->encr.key_len + 1;
-}
-
-static void print_rsl_cause(int lvl, const u_int8_t *cause_v, u_int8_t cause_len)
-{
- int i;
-
- LOGPC(DRSL, lvl, "CAUSE=0x%02x(%s) ",
- cause_v[0], rsl_err_name(cause_v[0]));
- for (i = 1; i < cause_len-1; i++)
- LOGPC(DRSL, lvl, "%02x ", cause_v[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);
-}
-
-int rsl_sacch_info_modify(struct gsm_lchan *lchan, u_int8_t type,
- const u_int8_t *data, int len)
-{
- struct abis_rsl_dchan_hdr *dh;
- struct msgb *msg = rsl_msgb_alloc();
- u_int8_t chan_nr = lchan2chan_nr(lchan);
-
- dh = (struct abis_rsl_dchan_hdr *) msgb_put(msg, sizeof(*dh));
- init_dchan_hdr(dh, RSL_MT_SACCH_INFO_MODIFY);
- dh->chan_nr = chan_nr;
-
- msgb_tv_put(msg, RSL_IE_SYSINFO_TYPE, type);
- msgb_tl16v_put(msg, RSL_IE_L3_INFO, len, data);
-
- msg->trx = lchan->ts->trx;
-
- return abis_rsl_sendmsg(msg);
-}
-
-int rsl_chan_bs_power_ctrl(struct gsm_lchan *lchan, unsigned int fpc, int db)
-{
- struct abis_rsl_dchan_hdr *dh;
- struct msgb *msg;
- u_int8_t chan_nr = lchan2chan_nr(lchan);
-
- db = abs(db);
- if (db > 30)
- return -EINVAL;
-
- msg = rsl_msgb_alloc();
-
- lchan->bs_power = db/2;
- if (fpc)
- lchan->bs_power |= 0x10;
-
- dh = (struct abis_rsl_dchan_hdr *) msgb_put(msg, sizeof(*dh));
- init_dchan_hdr(dh, RSL_MT_BS_POWER_CONTROL);
- dh->chan_nr = chan_nr;
-
- msgb_tv_put(msg, RSL_IE_BS_POWER, lchan->bs_power);
-
- msg->trx = lchan->ts->trx;
-
- return abis_rsl_sendmsg(msg);
-}
-
-int rsl_chan_ms_power_ctrl(struct gsm_lchan *lchan, unsigned int fpc, int dbm)
-{
- struct abis_rsl_dchan_hdr *dh;
- struct msgb *msg;
- u_int8_t chan_nr = lchan2chan_nr(lchan);
- int ctl_lvl;
-
- ctl_lvl = ms_pwr_ctl_lvl(lchan->ts->trx->bts->band, dbm);
- if (ctl_lvl < 0)
- return ctl_lvl;
-
- msg = rsl_msgb_alloc();
-
- lchan->ms_power = ctl_lvl;
-
- if (fpc)
- lchan->ms_power |= 0x20;
-
- dh = (struct abis_rsl_dchan_hdr *) msgb_put(msg, sizeof(*dh));
- init_dchan_hdr(dh, RSL_MT_MS_POWER_CONTROL);
- dh->chan_nr = chan_nr;
-
- msgb_tv_put(msg, RSL_IE_MS_POWER, lchan->ms_power);
-
- msg->trx = lchan->ts->trx;
-
- return abis_rsl_sendmsg(msg);
-}
-
-static int channel_mode_from_lchan(struct rsl_ie_chan_mode *cm,
- struct gsm_lchan *lchan)
-{
- memset(cm, 0, sizeof(cm));
-
- /* FIXME: what to do with data calls ? */
- if (lchan->ts->trx->bts->network->dtx_enabled)
- cm->dtx_dtu = 0x03;
- else
- cm->dtx_dtu = 0x00;
-
- /* set TCH Speech/Data */
- cm->spd_ind = lchan->rsl_cmode;
-
- if (lchan->rsl_cmode == RSL_CMOD_SPD_SIGN &&
- lchan->tch_mode != GSM48_CMODE_SIGN)
- LOGP(DRSL, LOGL_ERROR, "unsupported: rsl_mode == signalling, "
- "but tch_mode != signalling\n");
-
- switch (lchan->type) {
- case GSM_LCHAN_SDCCH:
- cm->chan_rt = RSL_CMOD_CRT_SDCCH;
- break;
- case GSM_LCHAN_TCH_F:
- cm->chan_rt = RSL_CMOD_CRT_TCH_Bm;
- break;
- case GSM_LCHAN_TCH_H:
- cm->chan_rt = RSL_CMOD_CRT_TCH_Lm;
- break;
- case GSM_LCHAN_NONE:
- case GSM_LCHAN_UNKNOWN:
- default:
- return -EINVAL;
- }
-
- switch (lchan->tch_mode) {
- case GSM48_CMODE_SIGN:
- cm->chan_rate = 0;
- break;
- 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;
- case GSM48_CMODE_SPEECH_AMR:
- cm->chan_rate = RSL_CMOD_SP_GSM3;
- break;
- case GSM48_CMODE_DATA_14k5:
- cm->chan_rate = RSL_CMOD_SP_NT_14k5;
- break;
- case GSM48_CMODE_DATA_12k0:
- cm->chan_rate = RSL_CMOD_SP_NT_12k0;
- break;
- case GSM48_CMODE_DATA_6k0:
- cm->chan_rate = RSL_CMOD_SP_NT_6k0;
- break;
- default:
- return -EINVAL;
- }
-
- return 0;
-}
-
-/* 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 ho_ref)
-{
- struct abis_rsl_dchan_hdr *dh;
- struct msgb *msg;
- int rc;
- uint8_t *len;
-
- u_int8_t chan_nr = lchan2chan_nr(lchan);
- struct rsl_ie_chan_mode cm;
- struct gsm48_chan_desc cd;
-
- rc = channel_mode_from_lchan(&cm, lchan);
- if (rc < 0)
- return rc;
-
- memset(&cd, 0, sizeof(cd));
- gsm48_lchan2chan_desc(&cd, lchan);
-
- 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);
- msgb_tlv_put(msg, RSL_IE_CHAN_MODE, sizeof(cm),
- (u_int8_t *) &cm);
-
- /*
- * The Channel Identification is needed for Phase1 phones
- * and it contains the GSM48 Channel Description and the
- * Mobile Allocation. The GSM 08.58 asks for the Mobile
- * Allocation to have a length of zero. We are using the
- * msgb_l3len to calculate the length of both messages.
- */
- msgb_v_put(msg, RSL_IE_CHAN_IDENT);
- len = msgb_put(msg, 1);
- msgb_tlv_put(msg, GSM48_IE_CHANDESC_2, sizeof(cd), (const uint8_t *) &cd);
-
- if (lchan->ts->hopping.enabled)
- msgb_tlv_put(msg, GSM48_IE_MA_AFTER, lchan->ts->hopping.ma_len,
- lchan->ts->hopping.ma_data);
- else
- msgb_tlv_put(msg, GSM48_IE_MA_AFTER, 0, NULL);
-
- /* update the calculated size */
- msg->l3h = len + 1;
- *len = msgb_l3len(msg);
-
- if (lchan->encr.alg_id > RSL_ENC_ALG_A5(0)) {
- u_int8_t encr_info[MAX_A5_KEY_LEN+2];
- rc = build_encr_info(encr_info, lchan);
- if (rc > 0)
- msgb_tlv_put(msg, RSL_IE_ENCR_INFO, rc, encr_info);
- }
-
- switch (act_type) {
- case RSL_ACT_INTER_ASYNC:
- case RSL_ACT_INTER_SYNC:
- msgb_tv_put(msg, RSL_IE_HANDO_REF, ho_ref);
- break;
- default:
- break;
- }
-
- 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);
-
- if (lchan->tch_mode == GSM48_CMODE_SPEECH_AMR)
- msgb_tlv_put(msg, RSL_IE_MR_CONFIG, sizeof(lchan->mr_conf),
- (u_int8_t *) &lchan->mr_conf);
-
- msg->trx = lchan->ts->trx;
-
- return abis_rsl_sendmsg(msg);
-}
-
-/* Chapter 8.4.9: Modify channel mode on BTS side */
-int rsl_chan_mode_modify_req(struct gsm_lchan *lchan)
-{
- struct abis_rsl_dchan_hdr *dh;
- struct msgb *msg;
- int rc;
-
- u_int8_t chan_nr = lchan2chan_nr(lchan);
- struct rsl_ie_chan_mode cm;
-
- rc = channel_mode_from_lchan(&cm, lchan);
- if (rc < 0)
- return rc;
-
- msg = rsl_msgb_alloc();
- 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 (lchan->encr.alg_id > RSL_ENC_ALG_A5(0)) {
- u_int8_t encr_info[MAX_A5_KEY_LEN+2];
- rc = build_encr_info(encr_info, lchan);
- if (rc > 0)
- msgb_tlv_put(msg, RSL_IE_ENCR_INFO, rc, encr_info);
- }
-
- if (lchan->tch_mode == GSM48_CMODE_SPEECH_AMR) {
- msgb_tlv_put(msg, RSL_IE_MR_CONFIG, sizeof(lchan->mr_conf),
- (u_int8_t *) &lchan->mr_conf);
- }
-
- msg->trx = lchan->ts->trx;
-
- return abis_rsl_sendmsg(msg);
-}
-
-/* Chapter 8.4.6: Send the encryption command with given L3 info */
-int rsl_encryption_cmd(struct msgb *msg)
-{
- struct abis_rsl_dchan_hdr *dh;
- struct gsm_lchan *lchan = msg->lchan;
- u_int8_t chan_nr = lchan2chan_nr(lchan);
- u_int8_t encr_info[MAX_A5_KEY_LEN+2];
- u_int8_t l3_len = msg->len;
- int rc;
-
- /* First push the L3 IE tag and length */
- msgb_tv16_push(msg, RSL_IE_L3_INFO, l3_len);
-
- /* then the link identifier (SAPI0, main sign link) */
- msgb_tv_push(msg, RSL_IE_LINK_IDENT, 0);
-
- /* then encryption information */
- rc = build_encr_info(encr_info, lchan);
- if (rc <= 0)
- return rc;
- msgb_tlv_push(msg, RSL_IE_ENCR_INFO, rc, encr_info);
-
- /* and finally the DCHAN header */
- dh = (struct abis_rsl_dchan_hdr *) msgb_push(msg, sizeof(*dh));
- init_dchan_hdr(dh, RSL_MT_ENCR_CMD);
- dh->chan_nr = chan_nr;
-
- msg->trx = lchan->ts->trx;
-
- return abis_rsl_sendmsg(msg);
-}
-
-/* Chapter 8.4.5 / 4.6: Deactivate the SACCH after 04.08 RR CHAN RELEASE */
-int rsl_deact_sacch(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_DEACTIVATE_SACCH);
- dh->chan_nr = lchan2chan_nr(lchan);
-
- msg->lchan = lchan;
- msg->trx = lchan->ts->trx;
-
- DEBUGP(DRSL, "%s DEACTivate SACCH CMD\n", gsm_lchan_name(lchan));
-
- return abis_rsl_sendmsg(msg);
-}
-
-static void error_timeout_cb(void *data)
-{
- struct gsm_lchan *lchan = data;
- if (lchan->state != LCHAN_S_REL_ERR) {
- LOGP(DRSL, LOGL_ERROR, "%s error timeout but not in error state: %d\n",
- gsm_lchan_name(lchan), lchan->state);
- return;
- }
-
- /* go back to the none state */
- LOGP(DRSL, LOGL_NOTICE, "%s is back in operation.\n", gsm_lchan_name(lchan));
- rsl_lchan_set_state(lchan, LCHAN_S_NONE);
-}
-
-/* Chapter 8.4.14 / 4.7: Tell BTS to release the radio channel */
-static int rsl_rf_chan_release(struct gsm_lchan *lchan, int error)
-{
- struct abis_rsl_dchan_hdr *dh;
- struct msgb *msg;
-
- if (lchan->state == LCHAN_S_REL_ERR) {
- LOGP(DRSL, LOGL_NOTICE, "%s is in error state not sending release.\n",
- gsm_lchan_name(lchan));
- return -1;
- }
-
- 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, "%s RF Channel Release CMD due error %d\n", gsm_lchan_name(lchan), error);
-
- if (error) {
- /*
- * the nanoBTS sends RLL release indications after the channel release. This can
- * be a problem when we have reassigned the channel to someone else and then can
- * not figure out who used this channel.
- */
- rsl_lchan_set_state(lchan, LCHAN_S_REL_ERR);
- lchan->error_timer.data = lchan;
- lchan->error_timer.cb = error_timeout_cb;
- bsc_schedule_timer(&lchan->error_timer,
- msg->trx->bts->network->T3111 + 2, 0);
- }
-
- /* BTS will respond by RF CHAN REL ACK */
- return abis_rsl_sendmsg(msg);
-}
-
-static int rsl_rx_rf_chan_rel_ack(struct gsm_lchan *lchan)
-{
-
- DEBUGP(DRSL, "%s RF CHANNEL RELEASE ACK\n", gsm_lchan_name(lchan));
-
- if (lchan->state != LCHAN_S_REL_REQ && lchan->state != LCHAN_S_REL_ERR)
- LOGP(DRSL, LOGL_NOTICE, "%s CHAN REL ACK but state %s\n",
- gsm_lchan_name(lchan),
- gsm_lchans_name(lchan->state));
- bsc_del_timer(&lchan->T3111);
- /* we have an error timer pending to release that */
- if (lchan->state != LCHAN_S_REL_ERR)
- rsl_lchan_set_state(lchan, LCHAN_S_NONE);
- lchan_free(lchan);
-
- return 0;
-}
-
-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 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 Siemens specific MS RF Power Capability Indication */
-int rsl_siemens_mrpci(struct gsm_lchan *lchan, struct rsl_mrpci *mrpci)
-{
- 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_SIEMENS_MRPCI);
- dh->c.msg_discr = ABIS_RSL_MDISC_DED_CHAN;
- dh->chan_nr = lchan2chan_nr(lchan);
- msgb_tv_put(msg, RSL_IE_SIEMENS_MRPCI, *(u_int8_t *)mrpci);
-
- DEBUGP(DRSL, "%s TX Siemens MRPCI 0x%02x\n",
- gsm_lchan_name(lchan), *(u_int8_t *)mrpci);
-
- msg->trx = lchan->ts->trx;
-
- 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)
-{
- if (msg->lchan == NULL) {
- LOGP(DRSL, LOGL_ERROR, "cannot send DATA REQUEST to unknown lchan\n");
- return -EINVAL;
- }
-
- rsl_rll_push_l3(msg, RSL_MT_DATA_REQ, lchan2chan_nr(msg->lchan),
- link_id, 1);
-
- msg->trx = msg->lchan->ts->trx;
-
- return abis_rsl_sendmsg(msg);
-}
-
-/* Send "ESTABLISH REQUEST" message with given L3 Info payload */
-/* Chapter 8.3.1 */
-int rsl_establish_request(struct gsm_lchan *lchan, u_int8_t link_id)
-{
- struct msgb *msg;
-
- msg = rsl_rll_simple(RSL_MT_EST_REQ, lchan2chan_nr(lchan),
- link_id, 0);
- msg->trx = lchan->ts->trx;
-
- return abis_rsl_sendmsg(msg);
-}
-
-/* Chapter 8.3.7 Request the release of multiframe mode of RLL connection.
- This is what higher layers should call. The BTS then responds with
- RELEASE CONFIRM, which we in turn use to trigger RSL CHANNEL RELEASE,
- which in turn is acknowledged by RSL CHANNEL RELEASE ACK, which calls
- lchan_free() */
-int rsl_release_request(struct gsm_lchan *lchan, u_int8_t link_id, u_int8_t reason)
-{
-
- struct msgb *msg;
-
- msg = rsl_rll_simple(RSL_MT_REL_REQ, lchan2chan_nr(lchan),
- link_id, 0);
- /* 0 is normal release, 1 is local end */
- msgb_tv_put(msg, RSL_IE_RELEASE_MODE, reason);
-
- /* FIXME: start some timer in case we don't receive a REL ACK ? */
-
- msg->trx = lchan->ts->trx;
-
- return abis_rsl_sendmsg(msg);
-}
-
-int rsl_lchan_set_state(struct gsm_lchan *lchan, int state)
-{
- lchan->state = state;
- return 0;
-}
-
-/* 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;
-
- if (msg->lchan->state != LCHAN_S_ACT_REQ)
- LOGP(DRSL, LOGL_NOTICE, "%s CHAN ACT ACK, but state %s\n",
- gsm_lchan_name(msg->lchan),
- gsm_lchans_name(msg->lchan->state));
- rsl_lchan_set_state(msg->lchan, LCHAN_S_ACTIVE);
-
- if (msg->lchan->rqd_ref) {
- rsl_send_imm_assignment(msg->lchan);
- talloc_free(msg->lchan->rqd_ref);
- msg->lchan->rqd_ref = NULL;
- msg->lchan->rqd_ta = 0;
- }
-
- send_lchan_signal(S_LCHAN_ACTIVATE_ACK, msg->lchan, NULL);
-
- 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;
-
- LOGP(DRSL, LOGL_ERROR, "%s CHANNEL ACTIVATE NACK",
- gsm_lchan_name(msg->lchan));
-
- /* 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)) {
- const u_int8_t *cause = TLVP_VAL(&tp, RSL_IE_CAUSE);
- print_rsl_cause(LOGL_ERROR, cause,
- TLVP_LEN(&tp, RSL_IE_CAUSE));
- if (*cause != RSL_ERR_RCH_ALR_ACTV_ALLOC)
- rsl_lchan_set_state(msg->lchan, LCHAN_S_NONE);
- } else
- rsl_lchan_set_state(msg->lchan, LCHAN_S_NONE);
-
- LOGPC(DRSL, LOGL_ERROR, "\n");
-
- send_lchan_signal(S_LCHAN_ACTIVATE_NACK, msg->lchan, NULL);
-
- lchan_free(msg->lchan);
- 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;
-
- /* FIXME: print which channel */
- LOGP(DRSL, LOGL_NOTICE, "%s CONNECTION FAIL: RELEASING ",
- gsm_lchan_name(msg->lchan));
-
- rsl_tlv_parse(&tp, dh->data, msgb_l2len(msg)-sizeof(*dh));
-
- if (TLVP_PRESENT(&tp, RSL_IE_CAUSE))
- print_rsl_cause(LOGL_NOTICE, TLVP_VAL(&tp, RSL_IE_CAUSE),
- TLVP_LEN(&tp, RSL_IE_CAUSE));
-
- LOGPC(DRSL, LOGL_NOTICE, "\n");
- /* FIXME: only free it after channel release ACK */
- counter_inc(msg->lchan->ts->trx->bts->network->stats.chan.rf_fail);
- return rsl_rf_chan_release(msg->lchan, 1);
-}
-
-static void print_meas_rep_uni(struct gsm_meas_rep_unidir *mru,
- const char *prefix)
-{
- DEBUGPC(DMEAS, "RXL-FULL-%s=%3ddBm RXL-SUB-%s=%3ddBm ",
- prefix, rxlev2dbm(mru->full.rx_lev),
- prefix, rxlev2dbm(mru->sub.rx_lev));
- DEBUGPC(DMEAS, "RXQ-FULL-%s=%d RXQ-SUB-%s=%d ",
- prefix, mru->full.rx_qual, prefix, mru->sub.rx_qual);
-}
-
-static void print_meas_rep(struct gsm_meas_rep *mr)
-{
- int i;
-
- DEBUGP(DMEAS, "MEASUREMENT RESULT NR=%d ", mr->nr);
-
- if (mr->flags & MEAS_REP_F_DL_DTX)
- DEBUGPC(DMEAS, "DTXd ");
-
- print_meas_rep_uni(&mr->ul, "ul");
- DEBUGPC(DMEAS, "BS_POWER=%d ", mr->bs_power);
- if (mr->flags & MEAS_REP_F_MS_TO)
- DEBUGPC(DMEAS, "MS_TO=%d ", mr->ms_timing_offset);
-
- if (mr->flags & MEAS_REP_F_MS_L1) {
- DEBUGPC(DMEAS, "L1_MS_PWR=%3ddBm ", mr->ms_l1.pwr);
- DEBUGPC(DMEAS, "L1_FPC=%u ",
- mr->flags & MEAS_REP_F_FPC ? 1 : 0);
- DEBUGPC(DMEAS, "L1_TA=%u ", mr->ms_l1.ta);
- }
-
- if (mr->flags & MEAS_REP_F_UL_DTX)
- DEBUGPC(DMEAS, "DTXu ");
- if (mr->flags & MEAS_REP_F_BA1)
- DEBUGPC(DMEAS, "BA1 ");
- if (!(mr->flags & MEAS_REP_F_DL_VALID))
- DEBUGPC(DMEAS, "NOT VALID ");
- else
- print_meas_rep_uni(&mr->dl, "dl");
-
- DEBUGPC(DMEAS, "NUM_NEIGH=%u\n", mr->num_cell);
- if (mr->num_cell == 7)
- return;
- for (i = 0; i < mr->num_cell; i++) {
- struct gsm_meas_rep_cell *mrc = &mr->cell[i];
- DEBUGP(DMEAS, "IDX=%u ARFCN=%u BSIC=%u => %d dBm\n",
- mrc->neigh_idx, mrc->arfcn, mrc->bsic, rxlev2dbm(mrc->rxlev));
- }
-}
-
-static int rsl_rx_meas_res(struct msgb *msg)
-{
- struct abis_rsl_dchan_hdr *dh = msgb_l2(msg);
- struct tlv_parsed tp;
- struct gsm_meas_rep *mr = lchan_next_meas_rep(msg->lchan);
- u_int8_t len;
- const u_int8_t *val;
- int rc;
-
- /* check if this channel is actually active */
- /* FIXME: maybe this check should be way more generic/centralized */
- if (msg->lchan->state != LCHAN_S_ACTIVE) {
- LOGP(DRSL, LOGL_DEBUG, "%s: MEAS RES for inactive channel\n",
- gsm_lchan_name(msg->lchan));
- return 0;
- }
-
- memset(mr, 0, sizeof(*mr));
- mr->lchan = msg->lchan;
-
- rsl_tlv_parse(&tp, dh->data, msgb_l2len(msg)-sizeof(*dh));
-
- if (!TLVP_PRESENT(&tp, RSL_IE_MEAS_RES_NR) ||
- !TLVP_PRESENT(&tp, RSL_IE_UPLINK_MEAS) ||
- !TLVP_PRESENT(&tp, RSL_IE_BS_POWER))
- return -EIO;
-
- /* Mandatory Parts */
- mr->nr = *TLVP_VAL(&tp, RSL_IE_MEAS_RES_NR);
-
- len = TLVP_LEN(&tp, RSL_IE_UPLINK_MEAS);
- val = TLVP_VAL(&tp, RSL_IE_UPLINK_MEAS);
- if (len >= 3) {
- if (val[0] & 0x40)
- mr->flags |= MEAS_REP_F_DL_DTX;
- mr->ul.full.rx_lev = val[0] & 0x3f;
- mr->ul.sub.rx_lev = val[1] & 0x3f;
- mr->ul.full.rx_qual = val[2]>>3 & 0x7;
- mr->ul.sub.rx_qual = val[2] & 0x7;
- }
-
- mr->bs_power = *TLVP_VAL(&tp, RSL_IE_BS_POWER);
-
- /* Optional Parts */
- if (TLVP_PRESENT(&tp, RSL_IE_MS_TIMING_OFFSET))
- mr->ms_timing_offset =
- *TLVP_VAL(&tp, RSL_IE_MS_TIMING_OFFSET);
-
- if (TLVP_PRESENT(&tp, RSL_IE_L1_INFO)) {
- val = TLVP_VAL(&tp, RSL_IE_L1_INFO);
- mr->flags |= MEAS_REP_F_MS_L1;
- mr->ms_l1.pwr = ms_pwr_dbm(msg->trx->bts->band, val[0] >> 3);
- if (val[0] & 0x04)
- mr->flags |= MEAS_REP_F_FPC;
- mr->ms_l1.ta = val[1];
- }
- if (TLVP_PRESENT(&tp, RSL_IE_L3_INFO)) {
- msg->l3h = (u_int8_t *) TLVP_VAL(&tp, RSL_IE_L3_INFO);
- rc = gsm48_parse_meas_rep(mr, msg);
- if (rc < 0)
- return rc;
- }
-
- print_meas_rep(mr);
-
- send_lchan_signal(S_LCHAN_MEAS_REP, msg->lchan, mr);
-
- return 0;
-}
-
-/* Chapter 8.4.7 */
-static int rsl_rx_hando_det(struct msgb *msg)
-{
- struct abis_rsl_dchan_hdr *dh = msgb_l2(msg);
- struct tlv_parsed tp;
-
- DEBUGP(DRSL, "%s HANDOVER DETECT ", gsm_lchan_name(msg->lchan));
-
- rsl_tlv_parse(&tp, dh->data, msgb_l2len(msg)-sizeof(*dh));
-
- if (TLVP_PRESENT(&tp, RSL_IE_ACCESS_DELAY))
- DEBUGPC(DRSL, "access delay = %u\n",
- *TLVP_VAL(&tp, RSL_IE_ACCESS_DELAY));
- else
- DEBUGPC(DRSL, "\n");
-
- send_lchan_signal(S_LCHAN_HANDOVER_DETECT, msg->lchan, NULL);
-
- 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_lchan_name(msg->lchan);
-
- switch (rslh->c.msg_type) {
- case RSL_MT_CHAN_ACTIV_ACK:
- DEBUGP(DRSL, "%s CHANNEL ACTIVATE ACK\n", ts_name);
- rc = rsl_rx_chan_act_ack(msg);
- break;
- case RSL_MT_CHAN_ACTIV_NACK:
- 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_HANDO_DET:
- rc = rsl_rx_hando_det(msg);
- break;
- case RSL_MT_RF_CHAN_REL_ACK:
- rc = rsl_rx_rf_chan_rel_ack(msg->lchan);
- break;
- case RSL_MT_MODE_MODIFY_ACK:
- DEBUGP(DRSL, "%s CHANNEL MODE MODIFY ACK\n", ts_name);
- break;
- case RSL_MT_MODE_MODIFY_NACK:
- LOGP(DRSL, LOGL_ERROR, "%s CHANNEL MODE MODIFY NACK\n", ts_name);
- break;
- case RSL_MT_IPAC_PDCH_ACT_ACK:
- DEBUGPC(DRSL, "%s IPAC PDCH ACT ACK\n", ts_name);
- msg->lchan->ts->flags |= TS_F_PDCH_MODE;
- break;
- case RSL_MT_IPAC_PDCH_ACT_NACK:
- LOGP(DRSL, LOGL_ERROR, "%s IPAC PDCH ACT NACK\n", ts_name);
- break;
- case RSL_MT_IPAC_PDCH_DEACT_ACK:
- DEBUGP(DRSL, "%s IPAC PDCH DEACT ACK\n", ts_name);
- msg->lchan->ts->flags &= ~TS_F_PDCH_MODE;
- break;
- case RSL_MT_IPAC_PDCH_DEACT_NACK:
- LOGP(DRSL, LOGL_ERROR, "%s IPAC PDCH DEACT NACK\n", ts_name);
- 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:
- LOGP(DRSL, LOGL_NOTICE, "%s Unimplemented Abis RSL DChan "
- "msg 0x%02x\n", ts_name, rslh->c.msg_type);
- break;
- default:
- LOGP(DRSL, LOGL_NOTICE, "%s unknown Abis RSL DChan msg 0x%02x\n",
- ts_name, 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);
- struct tlv_parsed tp;
-
- LOGP(DRSL, LOGL_ERROR, "%s ERROR REPORT ", gsm_trx_name(msg->trx));
-
- rsl_tlv_parse(&tp, rslh->data, msgb_l2len(msg)-sizeof(*rslh));
-
- if (TLVP_PRESENT(&tp, RSL_IE_CAUSE))
- print_rsl_cause(LOGL_ERROR, TLVP_VAL(&tp, RSL_IE_CAUSE),
- TLVP_LEN(&tp, RSL_IE_CAUSE));
-
- LOGPC(DRSL, LOGL_ERROR, "\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, "%s RF Resource Indication\n", gsm_trx_name(msg->trx));
- break;
- case RSL_MT_OVERLOAD:
- /* indicate CCCH / ACCH / processor overload */
- LOGP(DRSL, LOGL_ERROR, "%s CCCH/ACCH/CPU Overload\n",
- gsm_trx_name(msg->trx));
- break;
- default:
- LOGP(DRSL, LOGL_NOTICE, "%s Unknown Abis RSL TRX message "
- "type 0x%02x\n", gsm_trx_name(msg->trx), rslh->msg_type);
- return -EINVAL;
- }
- return rc;
-}
-
-/* If T3101 expires, we never received a response to IMMEDIATE ASSIGN */
-static void t3101_expired(void *data)
-{
- struct gsm_lchan *lchan = data;
-
- rsl_rf_chan_release(lchan, 1);
-}
-
-/* If T3111 expires, we will send the RF Channel Request */
-static void t3111_expired(void *data)
-{
- struct gsm_lchan *lchan = data;
-
- rsl_rf_chan_release(lchan, 0);
-}
-
-#define GSM48_LEN2PLEN(a) (((a) << 2) | 1)
-
-/* Format an IMM ASS REJ according to 04.08 Chapter 9.1.20 */
-static int rsl_send_imm_ass_rej(struct gsm_bts *bts,
- unsigned int num_req_refs,
- struct gsm48_req_ref *rqd_refs,
- uint8_t wait_ind)
-{
- uint8_t buf[GSM_MACBLOCK_LEN];
- struct gsm48_imm_ass_rej *iar = (struct gsm48_imm_ass_rej *)buf;
-
- /* create IMMEDIATE ASSIGN REJECT 04.08 message */
- memset(iar, 0, sizeof(*iar));
- iar->proto_discr = GSM48_PDISC_RR;
- iar->msg_type = GSM48_MT_RR_IMM_ASS;
- iar->page_mode = GSM48_PM_SAME;
-
- memcpy(&iar->req_ref1, &rqd_refs[0], sizeof(iar->req_ref1));
- iar->wait_ind1 = wait_ind;
-
- if (num_req_refs >= 2)
- memcpy(&iar->req_ref2, &rqd_refs[1], sizeof(iar->req_ref2));
- else
- memcpy(&iar->req_ref2, &rqd_refs[0], sizeof(iar->req_ref2));
- iar->wait_ind2 = wait_ind;
-
- if (num_req_refs >= 3)
- memcpy(&iar->req_ref3, &rqd_refs[2], sizeof(iar->req_ref3));
- else
- memcpy(&iar->req_ref3, &rqd_refs[0], sizeof(iar->req_ref3));
- iar->wait_ind3 = wait_ind;
-
- if (num_req_refs >= 4)
- memcpy(&iar->req_ref4, &rqd_refs[3], sizeof(iar->req_ref4));
- else
- memcpy(&iar->req_ref4, &rqd_refs[0], sizeof(iar->req_ref4));
- iar->wait_ind4 = wait_ind;
-
- return rsl_imm_assign_cmd(bts, sizeof(iar), (uint8_t *) iar);
-}
-
-/* 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;
- enum gsm_chan_t lctype;
- enum gsm_chreq_reason_t chreq_reason;
- struct gsm_lchan *lchan;
- u_int8_t rqd_ta;
- int is_lu;
-
- 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->network, rqd_ref->ra);
- chreq_reason = get_reason_by_chreq(rqd_ref->ra, bts->network->neci);
-
- counter_inc(bts->network->stats.chreq.total);
-
- /*
- * We want LOCATION UPDATES to succeed and will assign a TCH
- * if we have no SDCCH available.
- */
- is_lu = !!(chreq_reason == GSM_CHREQ_REASON_LOCATION_UPD);
-
- /* check availability / allocate channel */
- lchan = lchan_alloc(bts, lctype, is_lu);
- if (!lchan) {
- LOGP(DRSL, LOGL_NOTICE, "BTS %d CHAN RQD: no resources for %s 0x%x\n",
- msg->lchan->ts->trx->bts->nr, gsm_lchant_name(lctype), rqd_ref->ra);
- counter_inc(bts->network->stats.chreq.no_channel);
- /* FIXME gather multiple CHAN RQD and reject up to 4 at the same time */
- if (bts->network->T3122)
- rsl_send_imm_ass_rej(bts, 1, rqd_ref, bts->network->T3122 & 0xff);
- return -ENOMEM;
- }
-
- if (lchan->state != LCHAN_S_NONE)
- LOGP(DRSL, LOGL_NOTICE, "%s lchan_alloc() returned channel "
- "in state %s\n", gsm_lchan_name(lchan),
- gsm_lchans_name(lchan->state));
- rsl_lchan_set_state(lchan, LCHAN_S_ACT_REQ);
-
- /* save the RACH data as we need it after the CHAN ACT ACK */
- lchan->rqd_ref = talloc_zero(bts, struct gsm48_req_ref);
- if (!lchan->rqd_ref) {
- LOGP(DRSL, LOGL_ERROR, "Failed to allocate gsm48_req_ref.\n");
- lchan_free(lchan);
- return -ENOMEM;
- }
-
- memcpy(lchan->rqd_ref, rqd_ref, sizeof(*rqd_ref));
- lchan->rqd_ta = rqd_ta;
-
- ts_number = lchan->ts->nr;
- arfcn = lchan->ts->trx->arfcn;
- subch = lchan->nr;
-
- lchan->encr.alg_id = RSL_ENC_ALG_A5(0); /* no encryption */
- lchan->ms_power = ms_pwr_ctl_lvl(bts->band, bts->ms_max_power);
- lchan->bs_power = 0; /* 0dB reduction, output power = Pn */
- lchan->rsl_cmode = RSL_CMOD_SPD_SIGN;
- lchan->tch_mode = GSM48_CMODE_SIGN;
-
- /* FIXME: Start another timer or assume the BTS sends a ACK/NACK? */
- rsl_chan_activate_lchan(lchan, 0x00, rqd_ta, 0);
-
- DEBUGP(DRSL, "%s Activating ARFCN(%u) SS(%u) lctype %s "
- "r=%s ra=0x%02x\n", gsm_lchan_name(lchan), arfcn, subch,
- gsm_lchant_name(lchan->type), gsm_chreq_name(chreq_reason),
- rqd_ref->ra);
- return 0;
-}
-
-static int rsl_send_imm_assignment(struct gsm_lchan *lchan)
-{
- struct gsm_bts *bts = lchan->ts->trx->bts;
- u_int8_t buf[GSM_MACBLOCK_LEN];
- struct gsm48_imm_ass *ia = (struct gsm48_imm_ass *) buf;
-
- /* create IMMEDIATE ASSIGN 04.08 messge */
- memset(ia, 0, sizeof(*ia));
- /* we set ia->l2_plen once we know the length of the MA below */
- ia->proto_discr = GSM48_PDISC_RR;
- ia->msg_type = GSM48_MT_RR_IMM_ASS;
- ia->page_mode = GSM48_PM_SAME;
- gsm48_lchan2chan_desc(&ia->chan_desc, lchan);
-
- /* use request reference extracted from CHAN_RQD */
- memcpy(&ia->req_ref, lchan->rqd_ref, sizeof(ia->req_ref));
- ia->timing_advance = lchan->rqd_ta;
- if (!lchan->ts->hopping.enabled) {
- ia->mob_alloc_len = 0;
- } else {
- ia->mob_alloc_len = lchan->ts->hopping.ma_len;
- memcpy(ia->mob_alloc, lchan->ts->hopping.ma_data, ia->mob_alloc_len);
- }
- /* we need to subtract 1 byte from sizeof(*ia) since ia includes the l2_plen field */
- ia->l2_plen = GSM48_LEN2PLEN((sizeof(*ia)-1) + ia->mob_alloc_len);
-
- /* Start timer T3101 to wait for GSM48_MT_RR_PAG_RESP */
- lchan->T3101.cb = t3101_expired;
- lchan->T3101.data = lchan;
- bsc_schedule_timer(&lchan->T3101, bts->network->T3101, 0);
-
- /* send IMMEDIATE ASSIGN CMD on RSL to BTS (to send on CCCH to MS) */
- return rsl_imm_assign_cmd(bts, sizeof(*ia)+ia->mob_alloc_len, (u_int8_t *) ia);
-}
-
-/* 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];
- if (is_ipaccess_bts(msg->trx->bts) && pg_buf_space == 0xffff) {
- /* paging load below configured threshold, use 50 as default */
- pg_buf_space = 50;
- }
- 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 */
- LOGP(DRSL, LOGL_NOTICE, "Unimplemented Abis RSL TRX message "
- "type 0x%02x\n", rslh->c.msg_type);
- break;
- default:
- LOGP(DRSL, LOGL_NOTICE, "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;
-
- LOGP(DRLL, LOGL_ERROR, "%s ERROR INDICATION cause=%s\n",
- gsm_lchan_name(msg->lchan),
- rsl_rlm_cause_name(rlm_cause[1]));
-
- rll_indication(msg->lchan, rllh->link_id, BSC_RLLR_IND_ERR_IND);
-
- if (rlm_cause[1] == RLL_CAUSE_T200_EXPIRED) {
- counter_inc(msg->lchan->ts->trx->bts->network->stats.chan.rll_err);
- return rsl_rf_chan_release(msg->lchan, 1);
- }
-
- return 0;
-}
-
-static void rsl_handle_release(struct gsm_lchan *lchan)
-{
- int sapi;
- struct gsm_bts *bts;
-
- /* maybe we have only brought down one RLL */
- if (lchan->state != LCHAN_S_REL_REQ)
- return;
-
- for (sapi = 0; sapi < ARRAY_SIZE(lchan->sapis); ++sapi) {
- if (lchan->sapis[sapi] == LCHAN_SAPI_UNUSED)
- continue;
- LOGP(DRSL, LOGL_DEBUG, "%s waiting for SAPI=%d to be released.\n",
- gsm_lchan_name(lchan), sapi);
- return;
- }
-
-
-
- /* wait a bit to send the RF Channel Release */
- lchan->T3111.cb = t3111_expired;
- lchan->T3111.data = lchan;
- bts = lchan->ts->trx->bts;
- bsc_schedule_timer(&lchan->T3111, bts->network->T3111, 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;
- u_int8_t sapi = rllh->link_id & 7;
-
- msg->lchan = lchan_lookup(msg->trx, rllh->chan_nr);
- ts_name = gsm_lchan_name(msg->lchan);
- DEBUGP(DRLL, "%s SAPI=%u ", ts_name, sapi);
-
- 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, rllh->link_id);
- }
- break;
- case RSL_MT_EST_IND:
- DEBUGPC(DRLL, "ESTABLISH INDICATION\n");
- /* lchan is established, stop T3101 */
- msg->lchan->sapis[rllh->link_id & 0x7] = LCHAN_SAPI_MS;
- bsc_del_timer(&msg->lchan->T3101);
- 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, rllh->link_id);
- }
- break;
- case RSL_MT_EST_CONF:
- DEBUGPC(DRLL, "ESTABLISH CONFIRM\n");
- msg->lchan->sapis[rllh->link_id & 0x7] = LCHAN_SAPI_NET;
- rll_indication(msg->lchan, rllh->link_id,
- BSC_RLLR_IND_EST_CONF);
- break;
- case RSL_MT_REL_IND:
- /* BTS informs us of having received DISC from MS */
- DEBUGPC(DRLL, "RELEASE INDICATION\n");
- msg->lchan->sapis[rllh->link_id & 0x7] = LCHAN_SAPI_UNUSED;
- rll_indication(msg->lchan, rllh->link_id,
- BSC_RLLR_IND_REL_IND);
- rsl_handle_release(msg->lchan);
- rsl_lchan_rll_release(msg->lchan, rllh->link_id);
- break;
- case RSL_MT_REL_CONF:
- /* BTS informs us of having received UA from MS,
- * in response to DISC that we've sent earlier */
- DEBUGPC(DRLL, "RELEASE CONFIRMATION\n");
- msg->lchan->sapis[rllh->link_id & 0x7] = LCHAN_SAPI_UNUSED;
- rsl_handle_release(msg->lchan);
- rsl_lchan_rll_release(msg->lchan, rllh->link_id);
- break;
- case RSL_MT_ERROR_IND:
- rc = rsl_rx_rll_err_ind(msg);
- break;
- case RSL_MT_UNIT_DATA_IND:
- LOGP(DRLL, LOGL_NOTICE, "unimplemented Abis RLL message "
- "type 0x%02x\n", rllh->c.msg_type);
- break;
- default:
- LOGP(DRLL, LOGL_NOTICE, "unknown Abis RLL message "
- "type 0x%02x\n", rllh->c.msg_type);
- }
- return rc;
-}
-
-static u_int8_t ipa_smod_s_for_lchan(struct gsm_lchan *lchan)
-{
- switch (lchan->tch_mode) {
- case GSM48_CMODE_SPEECH_V1:
- switch (lchan->type) {
- case GSM_LCHAN_TCH_F:
- return 0x00;
- case GSM_LCHAN_TCH_H:
- return 0x03;
- default:
- break;
- }
- case GSM48_CMODE_SPEECH_EFR:
- switch (lchan->type) {
- case GSM_LCHAN_TCH_F:
- return 0x01;
- /* there's no half-rate EFR */
- default:
- break;
- }
- case GSM48_CMODE_SPEECH_AMR:
- switch (lchan->type) {
- case GSM_LCHAN_TCH_F:
- return 0x02;
- case GSM_LCHAN_TCH_H:
- return 0x05;
- default:
- break;
- }
- default:
- break;
- }
- LOGP(DRSL, LOGL_ERROR, "Cannot determine ip.access speech mode for "
- "tch_mode == 0x%02x\n", lchan->tch_mode);
- return 0;
-}
-
-static u_int8_t ipa_rtp_pt_for_lchan(struct gsm_lchan *lchan)
-{
- struct gsm_network *net = lchan->ts->trx->bts->network;
-
- /* allow to hardcode the rtp payload */
- if (net->hardcoded_rtp_payload != 0)
- return net->hardcoded_rtp_payload;
-
- switch (lchan->tch_mode) {
- case GSM48_CMODE_SPEECH_V1:
- switch (lchan->type) {
- case GSM_LCHAN_TCH_F:
- return RTP_PT_GSM_FULL;
- case GSM_LCHAN_TCH_H:
- return RTP_PT_GSM_HALF;
- default:
- break;
- }
- case GSM48_CMODE_SPEECH_EFR:
- switch (lchan->type) {
- case GSM_LCHAN_TCH_F:
- return RTP_PT_GSM_EFR;
- /* there's no half-rate EFR */
- default:
- break;
- }
- case GSM48_CMODE_SPEECH_AMR:
- switch (lchan->type) {
- case GSM_LCHAN_TCH_F:
- return RTP_PT_AMR_FULL;
- case GSM_LCHAN_TCH_H:
- return RTP_PT_AMR_HALF;
- default:
- break;
- }
- default:
- break;
- }
- LOGP(DRSL, LOGL_ERROR, "Cannot determine ip.access rtp payload type for "
- "tch_mode == 0x%02x\n & lchan_type == %d",
- lchan->tch_mode, lchan->type);
- return 0;
-}
-
-/* ip.access specific RSL extensions */
-static void ipac_parse_rtp(struct gsm_lchan *lchan, struct tlv_parsed *tv)
-{
- struct in_addr ip;
- u_int16_t port, conn_id;
-
- if (TLVP_PRESENT(tv, RSL_IE_IPAC_LOCAL_IP)) {
- ip.s_addr = *((u_int32_t *) TLVP_VAL(tv, RSL_IE_IPAC_LOCAL_IP));
- DEBUGPC(DRSL, "LOCAL_IP=%s ", inet_ntoa(ip));
- lchan->abis_ip.bound_ip = ntohl(ip.s_addr);
- }
-
- if (TLVP_PRESENT(tv, RSL_IE_IPAC_LOCAL_PORT)) {
- port = *((u_int16_t *) TLVP_VAL(tv, RSL_IE_IPAC_LOCAL_PORT));
- port = ntohs(port);
- DEBUGPC(DRSL, "LOCAL_PORT=%u ", port);
- lchan->abis_ip.bound_port = port;
- }
-
- if (TLVP_PRESENT(tv, RSL_IE_IPAC_CONN_ID)) {
- conn_id = *((u_int16_t *) TLVP_VAL(tv, RSL_IE_IPAC_CONN_ID));
- conn_id = ntohs(conn_id);
- DEBUGPC(DRSL, "CON_ID=%u ", conn_id);
- lchan->abis_ip.conn_id = conn_id;
- }
-
- if (TLVP_PRESENT(tv, RSL_IE_IPAC_RTP_PAYLOAD2)) {
- lchan->abis_ip.rtp_payload2 =
- *TLVP_VAL(tv, RSL_IE_IPAC_RTP_PAYLOAD2);
- DEBUGPC(DRSL, "RTP_PAYLOAD2=0x%02x ",
- lchan->abis_ip.rtp_payload2);
- }
-
- if (TLVP_PRESENT(tv, RSL_IE_IPAC_SPEECH_MODE)) {
- lchan->abis_ip.speech_mode =
- *TLVP_VAL(tv, RSL_IE_IPAC_SPEECH_MODE);
- DEBUGPC(DRSL, "speech_mode=0x%02x ",
- lchan->abis_ip.speech_mode);
- }
-
- if (TLVP_PRESENT(tv, RSL_IE_IPAC_REMOTE_IP)) {
- ip.s_addr = *((u_int32_t *) TLVP_VAL(tv, RSL_IE_IPAC_REMOTE_IP));
- DEBUGPC(DRSL, "REMOTE_IP=%s ", inet_ntoa(ip));
- lchan->abis_ip.connect_ip = ntohl(ip.s_addr);
- }
-
- if (TLVP_PRESENT(tv, RSL_IE_IPAC_REMOTE_PORT)) {
- port = *((u_int16_t *) TLVP_VAL(tv, RSL_IE_IPAC_REMOTE_PORT));
- port = ntohs(port);
- DEBUGPC(DRSL, "REMOTE_PORT=%u ", port);
- lchan->abis_ip.connect_port = port;
- }
-}
-
-int rsl_ipacc_crcx(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_CRCX);
- dh->c.msg_discr = ABIS_RSL_MDISC_IPACCESS;
- dh->chan_nr = lchan2chan_nr(lchan);
-
- /* 0x1- == receive-only, 0x-1 == EFR codec */
- lchan->abis_ip.speech_mode = 0x10 | ipa_smod_s_for_lchan(lchan);
- lchan->abis_ip.rtp_payload = ipa_rtp_pt_for_lchan(lchan);
- msgb_tv_put(msg, RSL_IE_IPAC_SPEECH_MODE, lchan->abis_ip.speech_mode);
- msgb_tv_put(msg, RSL_IE_IPAC_RTP_PAYLOAD, lchan->abis_ip.rtp_payload);
-
- DEBUGP(DRSL, "%s IPAC_BIND speech_mode=0x%02x RTP_PAYLOAD=%d\n",
- gsm_lchan_name(lchan), lchan->abis_ip.speech_mode,
- lchan->abis_ip.rtp_payload);
-
- msg->trx = lchan->ts->trx;
-
- return abis_rsl_sendmsg(msg);
-}
-
-int rsl_ipacc_mdcx(struct gsm_lchan *lchan, u_int32_t ip, u_int16_t port,
- u_int8_t rtp_payload2)
-{
- struct msgb *msg = rsl_msgb_alloc();
- struct abis_rsl_dchan_hdr *dh;
- u_int32_t *att_ip;
- struct in_addr ia;
-
- dh = (struct abis_rsl_dchan_hdr *) msgb_put(msg, sizeof(*dh));
- init_dchan_hdr(dh, RSL_MT_IPAC_MDCX);
- dh->c.msg_discr = ABIS_RSL_MDISC_IPACCESS;
- dh->chan_nr = lchan2chan_nr(lchan);
-
- /* we need to store these now as MDCX_ACK does not return them :( */
- lchan->abis_ip.rtp_payload2 = rtp_payload2;
- lchan->abis_ip.connect_port = port;
- lchan->abis_ip.connect_ip = ip;
-
- /* 0x0- == both directions, 0x-1 == EFR codec */
- lchan->abis_ip.speech_mode = 0x00 | ipa_smod_s_for_lchan(lchan);
- lchan->abis_ip.rtp_payload = ipa_rtp_pt_for_lchan(lchan);
-
- ia.s_addr = htonl(ip);
- DEBUGP(DRSL, "%s IPAC_MDCX IP=%s PORT=%d RTP_PAYLOAD=%d RTP_PAYLOAD2=%d "
- "CONN_ID=%d speech_mode=0x%02x\n", gsm_lchan_name(lchan),
- inet_ntoa(ia), port, lchan->abis_ip.rtp_payload, rtp_payload2,
- lchan->abis_ip.conn_id, lchan->abis_ip.speech_mode);
-
- msgb_tv16_put(msg, RSL_IE_IPAC_CONN_ID, lchan->abis_ip.conn_id);
- msgb_v_put(msg, RSL_IE_IPAC_REMOTE_IP);
- att_ip = (u_int32_t *) msgb_put(msg, sizeof(ip));
- *att_ip = ia.s_addr;
- msgb_tv16_put(msg, RSL_IE_IPAC_REMOTE_PORT, port);
- msgb_tv_put(msg, RSL_IE_IPAC_SPEECH_MODE, lchan->abis_ip.speech_mode);
- msgb_tv_put(msg, RSL_IE_IPAC_RTP_PAYLOAD, lchan->abis_ip.rtp_payload);
- if (rtp_payload2)
- msgb_tv_put(msg, RSL_IE_IPAC_RTP_PAYLOAD2, rtp_payload2);
-
- msg->trx = lchan->ts->trx;
-
- return abis_rsl_sendmsg(msg);
-}
-
-/* tell BTS to connect RTP stream to our local RTP socket */
-int rsl_ipacc_mdcx_to_rtpsock(struct gsm_lchan *lchan)
-{
- struct rtp_socket *rs = lchan->abis_ip.rtp_socket;
- int rc;
-
- rc = rsl_ipacc_mdcx(lchan, ntohl(rs->rtp.sin_local.sin_addr.s_addr),
- ntohs(rs->rtp.sin_local.sin_port),
- /* FIXME: use RTP payload of bound socket, not BTS*/
- lchan->abis_ip.rtp_payload2);
-
- return rc;
-}
-
-int rsl_ipacc_pdch_activate(struct gsm_bts_trx_ts *ts, int act)
-{
- struct msgb *msg = rsl_msgb_alloc();
- struct abis_rsl_dchan_hdr *dh;
- u_int8_t msg_type;
-
- if (act)
- msg_type = RSL_MT_IPAC_PDCH_ACT;
- else
- msg_type = RSL_MT_IPAC_PDCH_DEACT;
-
- dh = (struct abis_rsl_dchan_hdr *) msgb_put(msg, sizeof(*dh));
- init_dchan_hdr(dh, msg_type);
- dh->c.msg_discr = ABIS_RSL_MDISC_DED_CHAN;
- dh->chan_nr = ts2chan_nr(ts, 0);
-
- DEBUGP(DRSL, "%s IPAC_PDCH_%sACT\n", gsm_ts_name(ts),
- act ? "" : "DE");
-
- msg->trx = ts->trx;
-
- return abis_rsl_sendmsg(msg);
-}
-
-static int abis_rsl_rx_ipacc_crcx_ack(struct msgb *msg)
-{
- struct abis_rsl_dchan_hdr *dh = msgb_l2(msg);
- struct tlv_parsed tv;
- struct gsm_lchan *lchan = msg->lchan;
-
- /* 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, RSL_IE_IPAC_CONN_ID)) {
- LOGP(DRSL, LOGL_NOTICE, "mandatory IE missing");
- return -EINVAL;
- }
-
- ipac_parse_rtp(lchan, &tv);
-
- dispatch_signal(SS_ABISIP, S_ABISIP_CRCX_ACK, msg->lchan);
-
- return 0;
-}
-
-static int abis_rsl_rx_ipacc_mdcx_ack(struct msgb *msg)
-{
- struct abis_rsl_dchan_hdr *dh = msgb_l2(msg);
- struct tlv_parsed tv;
- struct gsm_lchan *lchan = msg->lchan;
-
- /* the BTS has acknowledged a remote connect request and
- * it now tells us the IP address and port number to which it has
- * connected the given logical channel */
-
- rsl_tlv_parse(&tv, dh->data, msgb_l2len(msg)-sizeof(*dh));
- ipac_parse_rtp(lchan, &tv);
- dispatch_signal(SS_ABISIP, S_ABISIP_MDCX_ACK, msg->lchan);
-
- return 0;
-}
-
-static int abis_rsl_rx_ipacc_dlcx_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))
- print_rsl_cause(LOGL_DEBUG, TLVP_VAL(&tv, RSL_IE_CAUSE),
- TLVP_LEN(&tv, RSL_IE_CAUSE));
-
- dispatch_signal(SS_ABISIP, S_ABISIP_DLCX_IND, msg->lchan);
-
- return 0;
-}
-
-static int abis_rsl_rx_ipacc(struct msgb *msg)
-{
- struct abis_rsl_rll_hdr *rllh = msgb_l2(msg);
- char *ts_name;
- int rc = 0;
-
- msg->lchan = lchan_lookup(msg->trx, rllh->chan_nr);
- ts_name = gsm_lchan_name(msg->lchan);
-
- switch (rllh->c.msg_type) {
- case RSL_MT_IPAC_CRCX_ACK:
- DEBUGP(DRSL, "%s IPAC_CRCX_ACK ", ts_name);
- rc = abis_rsl_rx_ipacc_crcx_ack(msg);
- break;
- case RSL_MT_IPAC_CRCX_NACK:
- /* somehow the BTS was unable to bind the lchan to its local
- * port?!? */
- LOGP(DRSL, LOGL_ERROR, "%s IPAC_CRCX_NACK\n", ts_name);
- break;
- case RSL_MT_IPAC_MDCX_ACK:
- /* the BTS tells us that a connect operation was successful */
- DEBUGP(DRSL, "%s IPAC_MDCX_ACK ", ts_name);
- rc = abis_rsl_rx_ipacc_mdcx_ack(msg);
- break;
- case RSL_MT_IPAC_MDCX_NACK:
- /* somehow the BTS was unable to connect the lchan to a remote
- * port */
- LOGP(DRSL, LOGL_ERROR, "%s IPAC_MDCX_NACK\n", ts_name);
- break;
- case RSL_MT_IPAC_DLCX_IND:
- DEBUGP(DRSL, "%s IPAC_DLCX_IND ", ts_name);
- rc = abis_rsl_rx_ipacc_dlcx_ind(msg);
- break;
- default:
- LOGP(DRSL, LOGL_NOTICE, "Unknown ip.access msg_type 0x%02x\n",
- 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;
- int rc = 0;
-
- if (!msg) {
- DEBUGP(DRSL, "Empty RSL msg?..\n");
- return -1;
- }
-
- if (msgb_l2len(msg) < sizeof(*rslh)) {
- DEBUGP(DRSL, "Truncated RSL message with l2len: %u\n", msgb_l2len(msg));
- return -1;
- }
-
- rslh = msgb_l2(msg);
-
- 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:
- LOGP(DRSL, LOGL_NOTICE, "unimplemented RSL msg disc 0x%02x\n",
- rslh->msg_discr);
- break;
- case ABIS_RSL_MDISC_IPACCESS:
- rc = abis_rsl_rx_ipacc(msg);
- break;
- default:
- LOGP(DRSL, LOGL_NOTICE, "unknown RSL message discriminator "
- "0x%02x\n", rslh->msg_discr);
- return -EINVAL;
- }
- msgb_free(msg);
- return rc;
-}
-
-/* From Table 10.5.33 of GSM 04.08 */
-int rsl_number_of_paging_subchannels(struct gsm_bts *bts)
-{
- if (bts->si_common.chan_desc.ccch_conf == RSL_BCCH_CCCH_CONF_1_C) {
- return MAX(1, (3 - bts->si_common.chan_desc.bs_ag_blks_res))
- * (bts->si_common.chan_desc.bs_pa_mfrms + 2);
- } else {
- return (9 - bts->si_common.chan_desc.bs_ag_blks_res)
- * (bts->si_common.chan_desc.bs_pa_mfrms + 2);
- }
-}
-
-int rsl_sms_cb_command(struct gsm_bts *bts, uint8_t chan_number,
- uint8_t cb_command, const uint8_t *data, int len)
-{
- struct abis_rsl_dchan_hdr *dh;
- struct msgb *cb_cmd;
-
- cb_cmd = rsl_msgb_alloc();
- if (!cb_cmd)
- return -1;
-
- dh = (struct abis_rsl_dchan_hdr *) msgb_put(cb_cmd, sizeof*dh);
- init_dchan_hdr(dh, RSL_MT_SMS_BC_CMD);
- dh->chan_nr = RSL_CHAN_SDCCH4_ACCH; /* TODO: check the chan config */
-
- msgb_tv_put(cb_cmd, RSL_IE_CB_CMD_TYPE, cb_command);
- msgb_tlv_put(cb_cmd, RSL_IE_SMSCB_MSG, len, data);
-
- cb_cmd->trx = bts->c0;
-
- return abis_rsl_sendmsg(cb_cmd);
-}
diff --git a/openbsc/src/bsc/bsc_api.c b/openbsc/src/bsc/bsc_api.c
deleted file mode 100644
index 0f09aecd3..000000000
--- a/openbsc/src/bsc/bsc_api.c
+++ /dev/null
@@ -1,675 +0,0 @@
-/* GSM 08.08 like API for OpenBSC. The bridge from MSC to BSC */
-
-/* (C) 2010 by Holger Hans Peter Freyther
- * (C) 2010 by On-Waves
- * (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 Affero General Public License as published by
- * the Free Software Foundation; either version 3 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 Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-#include <openbsc/bsc_api.h>
-#include <openbsc/bsc_rll.h>
-#include <openbsc/gsm_data.h>
-#include <openbsc/gsm_subscriber.h>
-#include <openbsc/signal.h>
-#include <openbsc/abis_rsl.h>
-#include <openbsc/chan_alloc.h>
-#include <openbsc/handover.h>
-#include <openbsc/debug.h>
-#include <openbsc/gsm_04_08.h>
-
-#include <osmocore/protocol/gsm_08_08.h>
-
-#include <osmocore/talloc.h>
-
-#define GSM0808_T10_VALUE 6, 0
-
-static LLIST_HEAD(sub_connections);
-
-static void rll_ind_cb(struct gsm_lchan *, uint8_t, void *, enum bsc_rllr_ind);
-static void send_sapi_reject(struct gsm_subscriber_connection *conn, int link_id);
-static void handle_release(struct gsm_subscriber_connection *conn, struct bsc_api *bsc, struct gsm_lchan *lchan);
-static void handle_chan_ack(struct gsm_subscriber_connection *conn, struct bsc_api *bsc, struct gsm_lchan *lchan);
-static void handle_chan_nack(struct gsm_subscriber_connection *conn, struct bsc_api *bsc, struct gsm_lchan *lchan);
-
-/* GSM 08.08 3.2.2.33 */
-static u_int8_t lchan_to_chosen_channel(struct gsm_lchan *lchan)
-{
- u_int8_t channel_mode = 0, channel = 0;
-
- switch (lchan->tch_mode) {
- case GSM48_CMODE_SPEECH_V1:
- case GSM48_CMODE_SPEECH_EFR:
- case GSM48_CMODE_SPEECH_AMR:
- channel_mode = 0x9;
- break;
- case GSM48_CMODE_SIGN:
- channel_mode = 0x8;
- break;
- case GSM48_CMODE_DATA_14k5:
- channel_mode = 0xe;
- break;
- case GSM48_CMODE_DATA_12k0:
- channel_mode = 0xb;
- break;
- case GSM48_CMODE_DATA_6k0:
- channel_mode = 0xc;
- break;
- case GSM48_CMODE_DATA_3k6:
- channel_mode = 0xd;
- break;
- }
-
- switch (lchan->type) {
- case GSM_LCHAN_NONE:
- channel = 0x0;
- break;
- case GSM_LCHAN_SDCCH:
- channel = 0x1;
- break;
- case GSM_LCHAN_TCH_F:
- channel = 0x8;
- break;
- case GSM_LCHAN_TCH_H:
- channel = 0x9;
- break;
- case GSM_LCHAN_UNKNOWN:
- LOGP(DMSC, LOGL_ERROR, "Unknown lchan type: %p\n", lchan);
- break;
- }
-
- return channel_mode << 4 | channel;
-}
-
-static u_int8_t chan_mode_to_speech(struct gsm_lchan *lchan)
-{
- int mode = 0;
-
- switch (lchan->tch_mode) {
- case GSM48_CMODE_SPEECH_V1:
- mode = 1;
- break;
- case GSM48_CMODE_SPEECH_EFR:
- mode = 0x11;
- break;
- case GSM48_CMODE_SPEECH_AMR:
- mode = 0x21;
- break;
- case GSM48_CMODE_SIGN:
- case GSM48_CMODE_DATA_14k5:
- case GSM48_CMODE_DATA_12k0:
- case GSM48_CMODE_DATA_6k0:
- case GSM48_CMODE_DATA_3k6:
- default:
- LOGP(DMSC, LOGL_ERROR, "Using non speech mode: %d\n", mode);
- return 0;
- break;
- }
-
- /* assume to always do AMR HR on any TCH type */
- if (lchan->type == GSM_LCHAN_TCH_H ||
- lchan->tch_mode == GSM48_CMODE_SPEECH_AMR)
- mode |= 0x4;
-
- return mode;
-}
-
-static void assignment_t10_timeout(void *_conn)
-{
- struct bsc_api *api;
- struct gsm_subscriber_connection *conn =
- (struct gsm_subscriber_connection *) _conn;
-
- LOGP(DMSC, LOGL_ERROR, "Assigment T10 timeout on %p\n", conn);
-
- /* normal release on the secondary channel */
- lchan_release(conn->secondary_lchan, 0, 1);
- conn->secondary_lchan = NULL;
-
- /* inform them about the failure */
- api = conn->bts->network->bsc_api;
- api->assign_fail(conn, GSM0808_CAUSE_NO_RADIO_RESOURCE_AVAILABLE, NULL);
-}
-
-/*
- * Start a new assignment and make sure that it is completed within T10 either
- * positively, negatively or by the timeout.
- *
- * 1.) allocate a new lchan
- * 2.) copy the encryption key and other data from the
- * old to the new channel.
- * 3.) RSL Channel Activate this channel and wait
- *
- * -> Signal handler for the LCHAN
- * 4.) Send GSM 04.08 assignment command to the MS
- *
- * -> Assignment Complete/Assignment Failure
- * 5.) Release the SDCCH, continue signalling on the new link
- */
-static int handle_new_assignment(struct gsm_subscriber_connection *conn, int chan_mode, int full_rate)
-{
- struct gsm_lchan *new_lchan;
- int chan_type;
-
- chan_type = full_rate ? GSM_LCHAN_TCH_F : GSM_LCHAN_TCH_H;
-
- new_lchan = lchan_alloc(conn->bts, chan_type, 0);
-
- if (!new_lchan) {
- LOGP(DMSC, LOGL_NOTICE, "No free channel.\n");
- return -1;
- }
-
- /* copy old data to the new channel */
- memcpy(&new_lchan->encr, &conn->lchan->encr, sizeof(new_lchan->encr));
- new_lchan->ms_power = conn->lchan->ms_power;
- new_lchan->bs_power = conn->lchan->bs_power;
-
- /* copy new data to it */
- new_lchan->tch_mode = chan_mode;
- new_lchan->rsl_cmode = RSL_CMOD_SPD_SPEECH;
-
- /* handle AMR correctly */
- if (chan_mode == GSM48_CMODE_SPEECH_AMR) {
- new_lchan->mr_conf.ver = 1;
- new_lchan->mr_conf.icmi = 1;
- new_lchan->mr_conf.m5_90 = 1;
- }
-
- if (rsl_chan_activate_lchan(new_lchan, 0x1, 0, 0) < 0) {
- LOGP(DHO, LOGL_ERROR, "could not activate channel\n");
- lchan_free(new_lchan);
- return -1;
- }
-
- /* remember that we have the channel */
- conn->secondary_lchan = new_lchan;
- new_lchan->conn = conn;
-
- rsl_lchan_set_state(new_lchan, LCHAN_S_ACT_REQ);
- return 0;
-}
-
-struct gsm_subscriber_connection *subscr_con_allocate(struct gsm_lchan *lchan)
-{
- struct gsm_subscriber_connection *conn;
-
- conn = talloc_zero(lchan->ts->trx->bts->network, struct gsm_subscriber_connection);
- if (!conn)
- return NULL;
-
- /* Configure the time and start it so it will be closed */
- conn->lchan = lchan;
- conn->bts = lchan->ts->trx->bts;
- lchan->conn = conn;
- llist_add_tail(&conn->entry, &sub_connections);
- return conn;
-}
-
-/* TODO: move subscriber put here... */
-void subscr_con_free(struct gsm_subscriber_connection *conn)
-{
- if (!conn)
- return;
-
-
- if (conn->subscr) {
- subscr_put(conn->subscr);
- conn->subscr = NULL;
- }
-
-
- if (conn->ho_lchan) {
- LOGP(DNM, LOGL_ERROR, "The ho_lchan should have been cleared.\n");
- conn->ho_lchan->conn = NULL;
- }
-
- if (conn->lchan) {
- LOGP(DNM, LOGL_ERROR, "The lchan should have been cleared.\n");
- conn->lchan->conn = NULL;
- }
-
- if (conn->secondary_lchan) {
- LOGP(DNM, LOGL_ERROR, "The secondary_lchan should have been cleared.\n");
- conn->secondary_lchan->conn = NULL;
- }
-
- llist_del(&conn->entry);
- talloc_free(conn);
-}
-
-int bsc_api_init(struct gsm_network *network, struct bsc_api *api)
-{
- network->bsc_api = api;
- return 0;
-}
-
-int gsm0808_submit_dtap(struct gsm_subscriber_connection *conn,
- struct msgb *msg, int link_id, int allow_sach)
-{
- uint8_t sapi;
-
-
- if (!conn->lchan) {
- LOGP(DMSC, LOGL_ERROR,
- "Called submit dtap without an lchan.\n");
- msgb_free(msg);
- return -1;
- }
-
- sapi = link_id & 0x7;
- msg->lchan = conn->lchan;
- msg->trx = msg->lchan->ts->trx;
-
- /* If we are on a TCH and need to submit a SMS (on SAPI=3) we need to use the SACH */
- if (allow_sach && sapi != 0) {
- if (conn->lchan->type == GSM_LCHAN_TCH_F || conn->lchan->type == GSM_LCHAN_TCH_H)
- link_id |= 0x40;
- }
-
- msg->l3h = msg->data;
- if (conn->lchan->sapis[sapi] == LCHAN_SAPI_UNUSED) {
- OBSC_LINKID_CB(msg) = link_id;
- if (rll_establish(msg->lchan, sapi, rll_ind_cb, msg) != 0) {
- msgb_free(msg);
- send_sapi_reject(conn, link_id);
- return -1;
- }
- return 0;
- } else {
- return rsl_data_request(msg, link_id);
- }
-}
-
-/**
- * Send a GSM08.08 Assignment Request. Right now this does not contain the
- * audio codec type or the allowed rates for the config. It is assumed that
- * this is for audio handling and that when we have a TCH it is capable of
- * handling the audio codec. On top of that it is assumed that we are using
- * AMR 5.9 when assigning a TCH/H.
- */
-int gsm0808_assign_req(struct gsm_subscriber_connection *conn, int chan_mode, int full_rate)
-{
- struct bsc_api *api;
- api = conn->bts->network->bsc_api;
-
- if (conn->lchan->type == GSM_LCHAN_SDCCH) {
- if (handle_new_assignment(conn, chan_mode, full_rate) != 0)
- goto error;
- } else {
- LOGP(DMSC, LOGL_NOTICE,
- "Sending ChanModify for speech %d %d\n", chan_mode, full_rate);
- if (chan_mode == GSM48_CMODE_SPEECH_AMR) {
- conn->lchan->mr_conf.ver = 1;
- conn->lchan->mr_conf.icmi = 1;
- conn->lchan->mr_conf.m5_90 = 1;
- }
-
- gsm48_lchan_modify(conn->lchan, chan_mode);
- }
-
- /* we will now start the timer to complete the assignment */
- conn->T10.cb = assignment_t10_timeout;
- conn->T10.data = conn;
- bsc_schedule_timer(&conn->T10, GSM0808_T10_VALUE);
- return 0;
-
-error:
- api->assign_fail(conn, 0, NULL);
- return -1;
-}
-
-int gsm0808_page(struct gsm_bts *bts, unsigned int page_group, unsigned int mi_len,
- uint8_t *mi, int chan_type)
-{
- return rsl_paging_cmd(bts, page_group, mi_len, mi, chan_type);
-}
-
-static void handle_ass_compl(struct gsm_subscriber_connection *conn,
- struct msgb *msg)
-{
- struct gsm48_hdr *gh;
- struct bsc_api *api = conn->bts->network->bsc_api;
-
- if (conn->secondary_lchan != msg->lchan) {
- LOGP(DMSC, LOGL_ERROR, "Assignment Compl should occur on second lchan.\n");
- return;
- }
-
- gh = msgb_l3(msg);
- if (msgb_l3len(msg) - sizeof(*gh) != 1) {
- LOGP(DMSC, LOGL_ERROR, "Assignment Compl invalid: %lu\n",
- msgb_l3len(msg) - sizeof(*gh));
- return;
- }
-
- /* swap channels */
- bsc_del_timer(&conn->T10);
-
- lchan_release(conn->lchan, 0, 1);
- conn->lchan = conn->secondary_lchan;
- conn->secondary_lchan = NULL;
-
- if (is_ipaccess_bts(conn->bts) && conn->lchan->tch_mode != GSM48_CMODE_SIGN)
- rsl_ipacc_crcx(conn->lchan);
-
- api->assign_compl(conn, gh->data[0],
- lchan_to_chosen_channel(conn->lchan),
- conn->lchan->encr.alg_id,
- chan_mode_to_speech(conn->lchan));
-}
-
-static void handle_ass_fail(struct gsm_subscriber_connection *conn,
- struct msgb *msg)
-{
- struct bsc_api *api = conn->bts->network->bsc_api;
- uint8_t *rr_failure;
- struct gsm48_hdr *gh;
-
-
- if (conn->lchan != msg->lchan) {
- LOGP(DMSC, LOGL_ERROR, "Assignment failure should occur on primary lchan.\n");
- return;
- }
-
- /* stop the timer and release it */
- bsc_del_timer(&conn->T10);
- lchan_release(conn->secondary_lchan, 0, 1);
- conn->secondary_lchan = NULL;
-
- gh = msgb_l3(msg);
- if (msgb_l3len(msg) - sizeof(*gh) != 1) {
- LOGP(DMSC, LOGL_ERROR, "assignemnt failure unhandled: %lu\n",
- msgb_l3len(msg) - sizeof(*gh));
- rr_failure = NULL;
- } else {
- rr_failure = &gh->data[0];
- }
-
- api->assign_fail(conn,
- GSM0808_CAUSE_RADIO_INTERFACE_MESSAGE_FAILURE,
- rr_failure);
-}
-
-static void dispatch_dtap(struct gsm_subscriber_connection *conn,
- uint8_t link_id, struct msgb *msg)
-{
- struct bsc_api *api = msg->lchan->ts->trx->bts->network->bsc_api;
- struct gsm48_hdr *gh;
- uint8_t pdisc;
- int rc;
-
- if (msgb_l3len(msg) < sizeof(*gh)) {
- LOGP(DMSC, LOGL_ERROR, "Message too short for a GSM48 header.\n");
- return;
- }
-
- gh = msgb_l3(msg);
- pdisc = gh->proto_discr & 0x0f;
- switch (pdisc) {
- case GSM48_PDISC_RR:
- switch (gh->msg_type) {
- case GSM48_MT_RR_CIPH_M_COMPL:
- if (api->cipher_mode_compl)
- return api->cipher_mode_compl(conn, msg,
- conn->lchan->encr.alg_id);
- break;
- case GSM48_MT_RR_ASS_COMPL:
- handle_ass_compl(conn, msg);
- break;
- case GSM48_MT_RR_ASS_FAIL:
- handle_ass_fail(conn, msg);
- break;
- case GSM48_MT_RR_CHAN_MODE_MODIF_ACK:
- bsc_del_timer(&conn->T10);
- rc = gsm48_rx_rr_modif_ack(msg);
- if (rc < 0 && api->assign_fail) {
- api->assign_fail(conn,
- GSM0808_CAUSE_NO_RADIO_RESOURCE_AVAILABLE,
- NULL);
- } else if (rc >= 0 && api->assign_compl)
- api->assign_compl(conn, 0,
- lchan_to_chosen_channel(conn->lchan),
- conn->lchan->encr.alg_id,
- chan_mode_to_speech(conn->lchan));
- return;
- break;
- }
- break;
- case GSM48_PDISC_MM:
- break;
- }
-
- /* default case */
- if (api->dtap)
- api->dtap(conn, link_id, msg);
-}
-
-int gsm0408_rcvmsg(struct msgb *msg, uint8_t link_id)
-{
- int rc;
- struct bsc_api *api = msg->lchan->ts->trx->bts->network->bsc_api;
- struct gsm_lchan *lchan;
-
- lchan = msg->lchan;
- if (lchan->state != LCHAN_S_ACTIVE) {
- LOGP(DRSL, LOGL_INFO, "Got data in non active state(%s), "
- "discarding.\n", gsm_lchans_name(lchan->state));
- return -1;
- }
-
-
- if (lchan->conn) {
- dispatch_dtap(lchan->conn, link_id, msg);
- } else {
- rc = BSC_API_CONN_POL_REJECT;
- lchan->conn = subscr_con_allocate(msg->lchan);
- if (!lchan->conn) {
- lchan_release(lchan, 0, 0);
- return -1;
- }
-
- rc = api->compl_l3(lchan->conn, msg, 0);
-
- if (rc != BSC_API_CONN_POL_ACCEPT) {
- lchan->conn->lchan = NULL;
- subscr_con_free(lchan->conn);
- lchan_release(lchan, 0, 0);
- }
- }
-
- return 0;
-}
-
-int gsm0808_cipher_mode(struct gsm_subscriber_connection *conn, int cipher,
- const uint8_t *key, int len, int include_imeisv)
-{
- if (cipher > 0 && key == NULL) {
- LOGP(DRSL, LOGL_ERROR, "Need to have an encrytpion key.\n");
- return -1;
- }
-
- if (len > MAX_A5_KEY_LEN) {
- LOGP(DRSL, LOGL_ERROR, "The key is too long: %d\n", len);
- return -1;
- }
-
- conn->lchan->encr.alg_id = RSL_ENC_ALG_A5(cipher);
- if (key) {
- conn->lchan->encr.key_len = len;
- memcpy(conn->lchan->encr.key, key, len);
- }
-
- return gsm48_send_rr_ciph_mode(conn->lchan, include_imeisv);
-}
-
-/*
- * Release all occupied RF Channels but stay around for more.
- */
-int gsm0808_clear(struct gsm_subscriber_connection *conn)
-{
- if (conn->ho_lchan)
- bsc_clear_handover(conn, 1);
-
- if (conn->secondary_lchan)
- lchan_release(conn->secondary_lchan, 0, 1);
-
- if (conn->lchan)
- lchan_release(conn->lchan, 1, 0);
-
- conn->lchan = NULL;
- conn->secondary_lchan = NULL;
- conn->ho_lchan = NULL;
- conn->bts = NULL;
-
- bsc_del_timer(&conn->T10);
-
- return 0;
-}
-
-static void send_sapi_reject(struct gsm_subscriber_connection *conn, int link_id)
-{
- struct bsc_api *api;
-
- if (!conn)
- return;
-
- api = conn->bts->network->bsc_api;
- if (!api || !api->sapi_n_reject)
- return;
-
- api->sapi_n_reject(conn, link_id);
-}
-
-static void rll_ind_cb(struct gsm_lchan *lchan, uint8_t link_id, void *_data, enum bsc_rllr_ind rllr_ind)
-{
- struct msgb *msg = _data;
-
- /*
- * There seems to be a small window that the RLL timer can
- * fire after a lchan_release call and before the S_CHALLOC_FREED
- * is called. Check if a conn is set before proceeding.
- */
- if (!lchan->conn)
- return;
-
- switch (rllr_ind) {
- case BSC_RLLR_IND_EST_CONF:
- rsl_data_request(msg, OBSC_LINKID_CB(msg));
- break;
- case BSC_RLLR_IND_REL_IND:
- case BSC_RLLR_IND_ERR_IND:
- case BSC_RLLR_IND_TIMEOUT:
- send_sapi_reject(lchan->conn, OBSC_LINKID_CB(msg));
- msgb_free(msg);
- break;
- }
-}
-
-static int bsc_handle_lchan_signal(unsigned int subsys, unsigned int signal,
- void *handler_data, void *signal_data)
-{
- struct bsc_api *bsc;
- struct gsm_lchan *lchan;
- struct lchan_signal_data *lchan_data;
-
- if (subsys != SS_LCHAN)
- return 0;
-
-
- lchan_data = signal_data;
- if (!lchan_data->lchan || !lchan_data->lchan->conn)
- return 0;
-
- lchan = lchan_data->lchan;
- bsc = lchan->ts->trx->bts->network->bsc_api;
- if (!bsc)
- return 0;
-
- switch (signal) {
- case S_LCHAN_UNEXPECTED_RELEASE:
- handle_release(lchan->conn, bsc, lchan);
- break;
- case S_LCHAN_ACTIVATE_ACK:
- handle_chan_ack(lchan->conn, bsc, lchan);
- break;
- case S_LCHAN_ACTIVATE_NACK:
- handle_chan_nack(lchan->conn, bsc, lchan);
- break;
- }
-
- return 0;
-}
-
-static void handle_release(struct gsm_subscriber_connection *conn,
- struct bsc_api *bsc, struct gsm_lchan *lchan)
-{
- int destruct = 1;
-
- if (conn->secondary_lchan == lchan) {
- bsc_del_timer(&conn->T10);
- conn->secondary_lchan = NULL;
-
- bsc->assign_fail(conn,
- GSM0808_CAUSE_RADIO_INTERFACE_FAILURE,
- NULL);
- }
-
- /* clear the connection now */
- if (bsc->clear_request)
- destruct = bsc->clear_request(conn, 0);
-
- /* now give up all channels */
- if (conn->lchan == lchan)
- conn->lchan = NULL;
- if (conn->ho_lchan == lchan) {
- bsc_clear_handover(conn, 0);
- conn->ho_lchan = NULL;
- }
- lchan->conn = NULL;
-
- gsm0808_clear(conn);
-
- if (destruct)
- subscr_con_free(conn);
-}
-
-static void handle_chan_ack(struct gsm_subscriber_connection *conn,
- struct bsc_api *api, struct gsm_lchan *lchan)
-{
- if (conn->secondary_lchan != lchan)
- return;
-
- LOGP(DMSC, LOGL_NOTICE, "Sending assignment on chan: %p\n", lchan);
- gsm48_send_rr_ass_cmd(conn->lchan, lchan, 0x3);
-}
-
-static void handle_chan_nack(struct gsm_subscriber_connection *conn,
- struct bsc_api *api, struct gsm_lchan *lchan)
-{
- if (conn->secondary_lchan != lchan)
- return;
-
- LOGP(DMSC, LOGL_ERROR, "Channel activation failed. Waiting for timeout now\n");
- conn->secondary_lchan->conn = NULL;
- conn->secondary_lchan = NULL;
-}
-
-static __attribute__((constructor)) void on_dso_load_bsc(void)
-{
- register_signal_handler(SS_LCHAN, bsc_handle_lchan_signal, NULL);
-}
diff --git a/openbsc/src/bsc/bsc_init.c b/openbsc/src/bsc/bsc_init.c
deleted file mode 100644
index 752056c37..000000000
--- a/openbsc/src/bsc/bsc_init.c
+++ /dev/null
@@ -1,440 +0,0 @@
-/* A hackish minimal BSC (+MSC +HLR) implementation */
-
-/* (C) 2008-2010 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 Affero General Public License as published by
- * the Free Software Foundation; either version 3 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 Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-#include <openbsc/gsm_data.h>
-#include <osmocore/gsm_utils.h>
-#include <openbsc/gsm_04_08.h>
-#include <openbsc/abis_rsl.h>
-#include <openbsc/abis_nm.h>
-#include <openbsc/debug.h>
-#include <openbsc/misdn.h>
-#include <osmocom/vty/telnet_interface.h>
-#include <openbsc/system_information.h>
-#include <openbsc/paging.h>
-#include <openbsc/signal.h>
-#include <openbsc/chan_alloc.h>
-#include <osmocore/talloc.h>
-#include <openbsc/ipaccess.h>
-
-/* global pointer to the gsm network data structure */
-extern struct gsm_network *bsc_gsmnet;
-
-static void patch_nm_tables(struct gsm_bts *bts);
-
-/* Callback function for NACK on the OML NM */
-static int oml_msg_nack(struct nm_nack_signal_data *nack)
-{
- int i;
-
- if (nack->mt == NM_MT_SET_BTS_ATTR_NACK) {
-
- LOGP(DNM, LOGL_FATAL, "Failed to set BTS attributes. That is fatal. "
- "Was the bts type and frequency properly specified?\n");
- exit(-1);
- } else {
- LOGP(DNM, LOGL_ERROR, "Got a NACK going to drop the OML links.\n");
- for (i = 0; i < bsc_gsmnet->num_bts; ++i) {
- struct gsm_bts *bts = gsm_bts_num(bsc_gsmnet, i);
- if (is_ipaccess_bts(bts))
- ipaccess_drop_oml(bts);
- }
- }
-
- 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)
-{
- struct nm_nack_signal_data *nack;
-
- switch (signal) {
- case S_NM_NACK:
- nack = signal_data;
- return oml_msg_nack(nack);
- default:
- break;
- }
- return 0;
-}
-
-int bsc_shutdown_net(struct gsm_network *net)
-{
- struct gsm_bts *bts;
-
- llist_for_each_entry(bts, &net->bts_list, list) {
- LOGP(DNM, LOGL_NOTICE, "shutting down OML for BTS %u\n", bts->nr);
- dispatch_signal(SS_GLOBAL, S_GLOBAL_BTS_CLOSE_OM, bts);
- }
-
- return 0;
-}
-
-static int generate_and_rsl_si(struct gsm_bts_trx *trx, enum osmo_sysinfo_type i)
-{
- struct gsm_bts *bts = trx->bts;
- int rc;
-
- /* Only generate SI if this SI is not in "static" (user-defined) mode */
- if (!(bts->si_mode_static & (1 << i))) {
- rc = gsm_generate_si(bts, i);
- if (rc < 0)
- return rc;
- }
-
- DEBUGP(DRR, "SI%s: %s\n", gsm_sitype_name(i),
- hexdump(GSM_BTS_SI(bts, i), GSM_MACBLOCK_LEN));
-
- switch (i) {
- case SYSINFO_TYPE_5:
- case SYSINFO_TYPE_5bis:
- case SYSINFO_TYPE_5ter:
- case SYSINFO_TYPE_6:
- rc = rsl_sacch_filling(trx, gsm_sitype2rsl(i),
- GSM_BTS_SI(bts, i), rc);
- break;
- default:
- rc = rsl_bcch_info(trx, gsm_sitype2rsl(i),
- GSM_BTS_SI(bts, i), rc);
- break;
- }
-
- return rc;
-}
-
-/* set all system information types */
-static int set_system_infos(struct gsm_bts_trx *trx)
-{
- int i, rc;
- struct gsm_bts *bts = trx->bts;
-
- bts->si_common.cell_sel_par.ms_txpwr_max_ccch =
- ms_pwr_ctl_lvl(bts->band, bts->ms_max_power);
- bts->si_common.cell_sel_par.neci = bts->network->neci;
-
- /* First, we determine which of the SI messages we actually need */
-
- if (trx == bts->c0) {
- /* 1...4 are always present on a C0 TRX */
- for (i = SYSINFO_TYPE_1; i <= SYSINFO_TYPE_4; i++)
- bts->si_valid |= (1 << i);
-
- /* 13 is always present on a C0 TRX of a GPRS BTS */
- if (bts->gprs.mode != BTS_GPRS_NONE)
- bts->si_valid |= (1 << SYSINFO_TYPE_13);
- }
-
- /* 5 and 6 are always present on every TRX */
- bts->si_valid |= (1 << SYSINFO_TYPE_5);
- bts->si_valid |= (1 << SYSINFO_TYPE_6);
-
- /* Second, we generate and send the selected SI via RSL */
- for (i = SYSINFO_TYPE_1; i < _MAX_SYSINFO_TYPE; i++) {
- if (!(bts->si_valid & (1 << i)))
- continue;
-
- rc = generate_and_rsl_si(trx, i);
- if (rc < 0)
- goto err_out;
- }
-
- return 0;
-err_out:
- LOGP(DRR, LOGL_ERROR, "Cannot generate SI %u for BTS %u, most likely "
- "a problem with neighbor cell list generation\n",
- i, bts->nr);
- return rc;
-}
-
-/* Produce a MA as specified in 10.5.2.21 */
-static int generate_ma_for_ts(struct gsm_bts_trx_ts *ts)
-{
- /* we have three bitvecs: the per-timeslot ARFCNs, the cell chan ARFCNs
- * and the MA */
- struct bitvec *cell_chan = &ts->trx->bts->si_common.cell_alloc;
- struct bitvec *ts_arfcn = &ts->hopping.arfcns;
- struct bitvec *ma = &ts->hopping.ma;
- unsigned int num_cell_arfcns, bitnum, n_chan;
- int i;
-
- /* re-set the MA to all-zero */
- ma->cur_bit = 0;
- ts->hopping.ma_len = 0;
- memset(ma->data, 0, ma->data_len);
-
- if (!ts->hopping.enabled)
- return 0;
-
- /* count the number of ARFCNs in the cell channel allocation */
- num_cell_arfcns = 0;
- for (i = 1; i < 1024; i++) {
- if (bitvec_get_bit_pos(cell_chan, i))
- num_cell_arfcns++;
- }
-
- /* pad it to octet-aligned number of bits */
- ts->hopping.ma_len = num_cell_arfcns / 8;
- if (num_cell_arfcns % 8)
- ts->hopping.ma_len++;
-
- n_chan = 0;
- for (i = 1; i < 1024; i++) {
- if (!bitvec_get_bit_pos(cell_chan, i))
- continue;
- /* set the corresponding bit in the MA */
- bitnum = (ts->hopping.ma_len * 8) - 1 - n_chan;
- if (bitvec_get_bit_pos(ts_arfcn, i))
- bitvec_set_bit_pos(ma, bitnum, 1);
- else
- bitvec_set_bit_pos(ma, bitnum, 0);
- n_chan++;
- }
-
- /* ARFCN 0 is special: It is coded last in the bitmask */
- if (bitvec_get_bit_pos(cell_chan, 0)) {
- n_chan++;
- /* set the corresponding bit in the MA */
- bitnum = (ts->hopping.ma_len * 8) - 1 - n_chan;
- if (bitvec_get_bit_pos(ts_arfcn, 0))
- bitvec_set_bit_pos(ma, bitnum, 1);
- else
- bitvec_set_bit_pos(ma, bitnum, 0);
- }
-
- return 0;
-}
-
-static void bootstrap_rsl(struct gsm_bts_trx *trx)
-{
- unsigned int i;
-
- LOGP(DRSL, LOGL_NOTICE, "bootstrapping RSL for BTS/TRX (%u/%u) "
- "on ARFCN %u using MCC=%u MNC=%u LAC=%u CID=%u BSIC=%u TSC=%u\n",
- trx->bts->nr, trx->nr, trx->arfcn, bsc_gsmnet->country_code,
- bsc_gsmnet->network_code, trx->bts->location_area_code,
- trx->bts->cell_identity, trx->bts->bsic, trx->bts->tsc);
- set_system_infos(trx);
-
- for (i = 0; i < ARRAY_SIZE(trx->ts); i++)
- generate_ma_for_ts(&trx->ts[i]);
-}
-
-/* Callback function to be called every time we receive a signal from INPUT */
-static int inp_sig_cb(unsigned int subsys, unsigned int signal,
- void *handler_data, void *signal_data)
-{
- struct input_signal_data *isd = signal_data;
- struct gsm_bts_trx *trx = isd->trx;
- int ts_no, lchan_no;
-
- if (subsys != SS_INPUT)
- return -EINVAL;
-
- switch (signal) {
- case S_INP_TEI_UP:
- if (isd->link_type == E1INP_SIGN_RSL)
- bootstrap_rsl(trx);
- break;
- case S_INP_TEI_DN:
- LOGP(DMI, LOGL_ERROR, "Lost some E1 TEI link: %d %p\n", isd->link_type, trx);
-
- if (isd->link_type == E1INP_SIGN_OML)
- counter_inc(trx->bts->network->stats.bts.oml_fail);
- else if (isd->link_type == E1INP_SIGN_RSL)
- counter_inc(trx->bts->network->stats.bts.rsl_fail);
-
- /*
- * free all allocated channels. change the nm_state so the
- * trx and trx_ts becomes unusable and chan_alloc.c can not
- * allocate from it.
- */
- for (ts_no = 0; ts_no < ARRAY_SIZE(trx->ts); ++ts_no) {
- struct gsm_bts_trx_ts *ts = &trx->ts[ts_no];
-
- for (lchan_no = 0; lchan_no < ARRAY_SIZE(ts->lchan); ++lchan_no) {
- if (ts->lchan[lchan_no].state != LCHAN_S_NONE)
- lchan_free(&ts->lchan[lchan_no]);
- lchan_reset(&ts->lchan[lchan_no]);
- }
-
- ts->nm_state.operational = 0;
- ts->nm_state.availability = 0;
- }
-
- trx->nm_state.operational = 0;
- trx->nm_state.availability = 0;
- trx->bb_transc.nm_state.operational = 0;
- trx->bb_transc.nm_state.availability = 0;
-
- abis_nm_clear_queue(trx->bts);
- break;
- default:
- break;
- }
-
- return 0;
-}
-
-static int bootstrap_bts(struct gsm_bts *bts)
-{
- int i, n;
-
- /* FIXME: What about secondary TRX of a BTS? What about a BTS that has TRX
- * in different bands? Why is 'band' a parameter of the BTS and not of the TRX? */
- switch (bts->band) {
- case GSM_BAND_1800:
- if (bts->c0->arfcn < 512 || bts->c0->arfcn > 885) {
- LOGP(DNM, LOGL_ERROR, "GSM1800 channel must be between 512-885.\n");
- return -EINVAL;
- }
- break;
- case GSM_BAND_1900:
- if (bts->c0->arfcn < 512 || bts->c0->arfcn > 810) {
- LOGP(DNM, LOGL_ERROR, "GSM1900 channel must be between 512-810.\n");
- return -EINVAL;
- }
- break;
- case GSM_BAND_900:
- if (bts->c0->arfcn < 1 ||
- (bts->c0->arfcn > 124 && bts->c0->arfcn < 955) ||
- bts->c0->arfcn > 1023) {
- LOGP(DNM, LOGL_ERROR, "GSM900 channel must be between 1-124, 955-1023.\n");
- return -EINVAL;
- }
- break;
- case GSM_BAND_850:
- if (bts->c0->arfcn < 128 || bts->c0->arfcn > 251) {
- LOGP(DNM, LOGL_ERROR, "GSM850 channel must be between 128-251.\n");
- return -EINVAL;
- }
- break;
- default:
- LOGP(DNM, LOGL_ERROR, "Unsupported frequency band.\n");
- return -EINVAL;
- }
-
- if (bts->network->auth_policy == GSM_AUTH_POLICY_ACCEPT_ALL &&
- !bts->si_common.rach_control.cell_bar)
- LOGP(DNM, LOGL_ERROR, "\nWARNING: You are running an 'accept-all' "
- "network on a BTS that is not barred. This "
- "configuration is likely to interfere with production "
- "GSM networks and should only be used in a RF "
- "shielded environment such as a faraday cage!\n\n");
-
- /* Control Channel Description */
- bts->si_common.chan_desc.att = 1;
- bts->si_common.chan_desc.bs_pa_mfrms = RSL_BS_PA_MFRMS_5;
- bts->si_common.chan_desc.bs_ag_blks_res = 1;
-
- /* T3212 is set from vty/config */
-
- /* Set ccch config by looking at ts config */
- for (n=0, i=0; i<8; i++)
- n += bts->c0->ts[i].pchan == GSM_PCHAN_CCCH ? 1 : 0;
-
- switch (n) {
- case 0:
- bts->si_common.chan_desc.ccch_conf = RSL_BCCH_CCCH_CONF_1_C;
- break;
- case 1:
- bts->si_common.chan_desc.ccch_conf = RSL_BCCH_CCCH_CONF_1_NC;
- break;
- case 2:
- bts->si_common.chan_desc.ccch_conf = RSL_BCCH_CCCH_CONF_2_NC;
- break;
- case 3:
- bts->si_common.chan_desc.ccch_conf = RSL_BCCH_CCCH_CONF_3_NC;
- break;
- case 4:
- bts->si_common.chan_desc.ccch_conf = RSL_BCCH_CCCH_CONF_4_NC;
- break;
- default:
- LOGP(DNM, LOGL_ERROR, "Unsupported CCCH timeslot configuration\n");
- return -EINVAL;
- }
-
- /* some defaults for our system information */
- bts->si_common.cell_options.radio_link_timeout = 7; /* 12 */
-
- /* allow/disallow DTXu */
- if (bts->network->dtx_enabled)
- bts->si_common.cell_options.dtx = 0;
- else
- bts->si_common.cell_options.dtx = 2;
-
- bts->si_common.cell_options.pwrc = 0; /* PWRC not set */
-
- bts->si_common.cell_sel_par.acs = 0;
-
- bts->si_common.ncc_permitted = 0xff;
-
- paging_init(bts);
-
- return 0;
-}
-
-int bsc_bootstrap_network(int (*mncc_recv)(struct gsm_network *, struct msgb *),
- const char *config_file)
-{
- struct telnet_connection dummy_conn;
- struct gsm_bts *bts;
- int rc;
-
- /* initialize our data structures */
- bsc_gsmnet = gsm_network_init(1, 1, mncc_recv);
- if (!bsc_gsmnet)
- return -ENOMEM;
-
- bsc_gsmnet->name_long = talloc_strdup(bsc_gsmnet, "OpenBSC");
- bsc_gsmnet->name_short = talloc_strdup(bsc_gsmnet, "OpenBSC");
-
- /* our vty command code expects vty->priv to point to a telnet_connection */
- dummy_conn.priv = bsc_gsmnet;
- rc = vty_read_config_file(config_file, &dummy_conn);
- if (rc < 0) {
- LOGP(DNM, LOGL_FATAL, "Failed to parse the config file: '%s'\n", config_file);
- return rc;
- }
-
- rc = telnet_init(tall_bsc_ctx, bsc_gsmnet, 4242);
- if (rc < 0)
- return rc;
-
- register_signal_handler(SS_NM, nm_sig_cb, NULL);
- register_signal_handler(SS_INPUT, inp_sig_cb, NULL);
-
- llist_for_each_entry(bts, &bsc_gsmnet->bts_list, list) {
- bootstrap_bts(bts);
- if (!is_ipaccess_bts(bts))
- rc = e1_reconfig_bts(bts);
-
- if (rc < 0) {
- fprintf(stderr, "Error in E1 input driver setup\n");
- exit (1);
- }
- }
-
- /* initialize nanoBTS support omce */
- rc = ipaccess_setup(bsc_gsmnet);
-
- return 0;
-}
diff --git a/openbsc/src/bsc/bsc_msc.c b/openbsc/src/bsc/bsc_msc.c
deleted file mode 100644
index 508697ab1..000000000
--- a/openbsc/src/bsc/bsc_msc.c
+++ /dev/null
@@ -1,259 +0,0 @@
-/* Routines to talk to the MSC using the IPA Protocol */
-/*
- * (C) 2010 by Holger Hans Peter Freyther <zecke@selfish.org>
- * (C) 2010 by On-Waves
- * All Rights Reserved
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation; either version 3 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 Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-#include <openbsc/bsc_msc.h>
-#include <openbsc/debug.h>
-#include <openbsc/ipaccess.h>
-
-#include <osmocore/write_queue.h>
-#include <osmocore/talloc.h>
-
-#include <arpa/inet.h>
-#include <sys/socket.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
-
-static void connection_loss(struct bsc_msc_connection *con)
-{
- struct bsc_fd *fd;
-
- fd = &con->write_queue.bfd;
-
- close(fd->fd);
- fd->fd = -1;
- fd->cb = write_queue_bfd_cb;
- fd->when = 0;
-
- con->is_connected = 0;
- con->first_contact = 0;
- con->connection_loss(con);
-}
-
-static void msc_con_timeout(void *_con)
-{
- struct bsc_msc_connection *con = _con;
-
- LOGP(DMSC, LOGL_ERROR, "MSC Connection timeout.\n");
- bsc_msc_lost(con);
-}
-
-/* called in the case of a non blocking connect */
-static int msc_connection_connect(struct bsc_fd *fd, unsigned int what)
-{
- int rc;
- int val;
- struct bsc_msc_connection *con;
- struct write_queue *queue;
-
- socklen_t len = sizeof(val);
-
- if ((what & BSC_FD_WRITE) == 0) {
- LOGP(DMSC, LOGL_ERROR, "Callback but not writable.\n");
- return -1;
- }
-
- queue = container_of(fd, struct write_queue, bfd);
- con = container_of(queue, struct bsc_msc_connection, write_queue);
-
- /* From here on we will either be connected or reconnect */
- bsc_del_timer(&con->timeout_timer);
-
- /* check the socket state */
- rc = getsockopt(fd->fd, SOL_SOCKET, SO_ERROR, &val, &len);
- if (rc != 0) {
- LOGP(DMSC, LOGL_ERROR, "getsockopt for the MSC socket failed.\n");
- goto error;
- }
- if (val != 0) {
- LOGP(DMSC, LOGL_ERROR, "Not connected to the MSC: %d\n", val);
- goto error;
- }
-
-
- /* go to full operation */
- fd->cb = write_queue_bfd_cb;
- fd->when = BSC_FD_READ | BSC_FD_EXCEPT;
-
- con->is_connected = 1;
- LOGP(DMSC, LOGL_NOTICE, "(Re)Connected to the MSC.\n");
- if (con->connected)
- con->connected(con);
- return 0;
-
-error:
- bsc_unregister_fd(fd);
- connection_loss(con);
- return -1;
-}
-static void setnonblocking(struct bsc_fd *fd)
-{
- int flags;
-
- flags = fcntl(fd->fd, F_GETFL);
- if (flags < 0) {
- perror("fcntl get failed");
- close(fd->fd);
- fd->fd = -1;
- return;
- }
-
- flags |= O_NONBLOCK;
- flags = fcntl(fd->fd, F_SETFL, flags);
- if (flags < 0) {
- perror("fcntl get failed");
- close(fd->fd);
- fd->fd = -1;
- return;
- }
-}
-
-int bsc_msc_connect(struct bsc_msc_connection *con)
-{
- struct bsc_fd *fd;
- struct sockaddr_in sin;
- int on = 1, ret;
-
- LOGP(DMSC, LOGL_NOTICE, "Attempting to connect MSC at %s:%d\n", con->ip, con->port);
-
- con->is_connected = 0;
-
- fd = &con->write_queue.bfd;
- fd->fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
- fd->priv_nr = 1;
-
- if (fd->fd < 0) {
- perror("Creating TCP socket failed");
- return fd->fd;
- }
-
- /* make it non blocking */
- setnonblocking(fd);
-
- /* set the socket priority */
- ret = setsockopt(fd->fd, IPPROTO_IP, IP_TOS,
- &con->prio, sizeof(con->prio));
- if (ret != 0)
- LOGP(DMSC, LOGL_ERROR, "Failed to set prio to %d. %s\n",
- con->prio, strerror(errno));
-
- memset(&sin, 0, sizeof(sin));
- sin.sin_family = AF_INET;
- sin.sin_port = htons(con->port);
- inet_aton(con->ip, &sin.sin_addr);
-
- setsockopt(fd->fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
- ret = connect(fd->fd, (struct sockaddr *) &sin, sizeof(sin));
-
- if (ret == -1 && errno == EINPROGRESS) {
- LOGP(DMSC, LOGL_ERROR, "MSC Connection in progress\n");
- fd->when = BSC_FD_WRITE;
- fd->cb = msc_connection_connect;
- con->timeout_timer.cb = msc_con_timeout;
- con->timeout_timer.data = con;
- bsc_schedule_timer(&con->timeout_timer, 20, 0);
- } else if (ret < 0) {
- perror("Connection failed");
- connection_loss(con);
- return ret;
- } else {
- fd->when = BSC_FD_READ | BSC_FD_EXCEPT;
- fd->cb = write_queue_bfd_cb;
- con->is_connected = 1;
- if (con->connected)
- con->connected(con);
- }
-
- ret = bsc_register_fd(fd);
- if (ret < 0) {
- perror("Registering the fd failed");
- close(fd->fd);
- return ret;
- }
-
- return ret;
-}
-
-struct bsc_msc_connection *bsc_msc_create(const char *ip, int port, int prio)
-{
- struct bsc_msc_connection *con;
-
- con = talloc_zero(NULL, struct bsc_msc_connection);
- if (!con) {
- LOGP(DMSC, LOGL_FATAL, "Failed to create the MSC connection.\n");
- return NULL;
- }
-
- con->ip = ip;
- con->port = port;
- con->prio = prio;
- write_queue_init(&con->write_queue, 100);
- return con;
-}
-
-void bsc_msc_lost(struct bsc_msc_connection *con)
-{
- write_queue_clear(&con->write_queue);
- bsc_del_timer(&con->timeout_timer);
-
- if (con->write_queue.bfd.fd >= 0)
- bsc_unregister_fd(&con->write_queue.bfd);
- connection_loss(con);
-}
-
-static void reconnect_msc(void *_msc)
-{
- struct bsc_msc_connection *con = _msc;
-
- LOGP(DMSC, LOGL_NOTICE, "Attempting to reconnect to the MSC.\n");
- bsc_msc_connect(con);
-}
-
-void bsc_msc_schedule_connect(struct bsc_msc_connection *con)
-{
- LOGP(DMSC, LOGL_NOTICE, "Attempting to reconnect to the MSC.\n");
- con->reconnect_timer.cb = reconnect_msc;
- con->reconnect_timer.data = con;
- bsc_schedule_timer(&con->reconnect_timer, 5, 0);
-}
-
-struct msgb *bsc_msc_id_get_resp(const char *token)
-{
- struct msgb *msg;
-
- if (!token) {
- LOGP(DMSC, LOGL_ERROR, "No token specified.\n");
- return NULL;
- }
-
- msg = msgb_alloc_headroom(4096, 128, "id resp");
- if (!msg) {
- LOGP(DMSC, LOGL_ERROR, "Failed to create the message.\n");
- return NULL;
- }
-
- msg->l2h = msgb_v_put(msg, IPAC_MSGT_ID_RESP);
- msgb_l16tv_put(msg, strlen(token) + 1,
- IPAC_IDTAG_UNITNAME, (u_int8_t *) token);
- return msg;
-}
diff --git a/openbsc/src/bsc/bsc_rll.c b/openbsc/src/bsc/bsc_rll.c
deleted file mode 100644
index 722f3fafc..000000000
--- a/openbsc/src/bsc/bsc_rll.c
+++ /dev/null
@@ -1,141 +0,0 @@
-/* GSM BSC Radio Link Layer API
- * 3GPP TS 08.58 version 8.6.0 Release 1999 / ETSI TS 100 596 V8.6.0 */
-
-/* (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 Affero General Public License as published by
- * the Free Software Foundation; either version 3 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 Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-#include <errno.h>
-
-#include <openbsc/debug.h>
-#include <osmocore/talloc.h>
-#include <osmocore/timer.h>
-#include <osmocore/linuxlist.h>
-#include <openbsc/bsc_rll.h>
-#include <openbsc/gsm_data.h>
-#include <openbsc/chan_alloc.h>
-#include <openbsc/abis_rsl.h>
-#include <openbsc/signal.h>
-
-struct bsc_rll_req {
- struct llist_head list;
- struct timer_list timer;
-
- struct gsm_lchan *lchan;
- u_int8_t link_id;
-
- void (*cb)(struct gsm_lchan *lchan, u_int8_t link_id,
- void *data, enum bsc_rllr_ind);
- void *data;
-};
-
-/* we only compare C1, C2 and SAPI */
-#define LINKID_MASK 0xC7
-
-static LLIST_HEAD(bsc_rll_reqs);
-
-static void complete_rllr(struct bsc_rll_req *rllr, enum bsc_rllr_ind type)
-{
- llist_del(&rllr->list);
- rllr->cb(rllr->lchan, rllr->link_id, rllr->data, type);
- talloc_free(rllr);
-}
-
-static void timer_cb(void *_rllr)
-{
- struct bsc_rll_req *rllr = _rllr;
-
- complete_rllr(rllr, BSC_RLLR_IND_TIMEOUT);
-}
-
-/* establish a RLL connection with given SAPI / priority */
-int rll_establish(struct gsm_lchan *lchan, u_int8_t sapi,
- void (*cb)(struct gsm_lchan *, u_int8_t, void *,
- enum bsc_rllr_ind),
- void *data)
-{
- struct bsc_rll_req *rllr = talloc_zero(tall_bsc_ctx, struct bsc_rll_req);
- u_int8_t link_id;
- if (!rllr)
- return -ENOMEM;
-
- link_id = sapi;
-
- /* If we are a TCH and not in signalling mode, we need to
- * indicate that the new RLL connection is to be made on the SACCH */
- if ((lchan->type == GSM_LCHAN_TCH_F ||
- lchan->type == GSM_LCHAN_TCH_H) && sapi != 0)
- link_id |= 0x40;
-
- rllr->lchan = lchan;
- rllr->link_id = link_id;
- rllr->cb = cb;
- rllr->data = data;
-
- llist_add(&rllr->list, &bsc_rll_reqs);
-
- rllr->timer.cb = &timer_cb;
- rllr->timer.data = rllr;
-
- bsc_schedule_timer(&rllr->timer, 10, 0);
-
- /* send the RSL RLL ESTablish REQuest */
- return rsl_establish_request(rllr->lchan, rllr->link_id);
-}
-
-/* Called from RSL code in case we have received an indication regarding
- * any RLL link */
-void rll_indication(struct gsm_lchan *lchan, u_int8_t link_id, u_int8_t type)
-{
- struct bsc_rll_req *rllr, *rllr2;
-
- llist_for_each_entry_safe(rllr, rllr2, &bsc_rll_reqs, list) {
- if (rllr->lchan == lchan &&
- (rllr->link_id & LINKID_MASK) == (link_id & LINKID_MASK)) {
- bsc_del_timer(&rllr->timer);
- complete_rllr(rllr, type);
- return;
- }
- }
-}
-
-static int rll_lchan_signal(unsigned int subsys, unsigned int signal,
- void *handler_data, void *signal_data)
-{
- struct challoc_signal_data *challoc;
- struct bsc_rll_req *rllr, *rllr2;
-
- if (subsys != SS_CHALLOC || signal != S_CHALLOC_FREED)
- return 0;
-
- challoc = (struct challoc_signal_data *) signal_data;
-
- llist_for_each_entry_safe(rllr, rllr2, &bsc_rll_reqs, list) {
- if (rllr->lchan == challoc->lchan) {
- bsc_del_timer(&rllr->timer);
- complete_rllr(rllr, BSC_RLLR_IND_ERR_IND);
- }
- }
-
- return 0;
-}
-
-static __attribute__((constructor)) void on_dso_load_rll(void)
-{
- register_signal_handler(SS_CHALLOC, rll_lchan_signal, NULL);
-}
diff --git a/openbsc/src/bsc/bsc_vty.c b/openbsc/src/bsc/bsc_vty.c
deleted file mode 100644
index ed45afd4d..000000000
--- a/openbsc/src/bsc/bsc_vty.c
+++ /dev/null
@@ -1,2773 +0,0 @@
-/* OpenBSC interface to quagga VTY */
-/* (C) 2009-2010 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 Affero General Public License as published by
- * the Free Software Foundation; either version 3 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 Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-#include <stdlib.h>
-#include <unistd.h>
-#include <sys/types.h>
-
-#include <osmocom/vty/command.h>
-#include <osmocom/vty/buffer.h>
-#include <osmocom/vty/vty.h>
-#include <osmocom/vty/logging.h>
-#include <osmocom/vty/telnet_interface.h>
-
-#include <arpa/inet.h>
-
-#include <osmocore/linuxlist.h>
-#include <openbsc/gsm_data.h>
-#include <openbsc/e1_input.h>
-#include <openbsc/abis_nm.h>
-#include <openbsc/abis_om2000.h>
-#include <osmocore/utils.h>
-#include <osmocore/gsm_utils.h>
-#include <openbsc/chan_alloc.h>
-#include <openbsc/meas_rep.h>
-#include <openbsc/db.h>
-#include <osmocore/talloc.h>
-#include <openbsc/vty.h>
-#include <openbsc/gprs_ns.h>
-#include <openbsc/system_information.h>
-#include <openbsc/debug.h>
-#include <openbsc/paging.h>
-#include <openbsc/ipaccess.h>
-#include <openbsc/abis_rsl.h>
-#include <openbsc/osmo_msc_data.h>
-#include <openbsc/osmo_bsc_rf.h>
-
-#include "../bscconfig.h"
-
-/* FIXME: this should go to some common file */
-static const struct value_string gprs_ns_timer_strs[] = {
- { 0, "tns-block" },
- { 1, "tns-block-retries" },
- { 2, "tns-reset" },
- { 3, "tns-reset-retries" },
- { 4, "tns-test" },
- { 5, "tns-alive" },
- { 6, "tns-alive-retries" },
- { 0, NULL }
-};
-
-static const struct value_string gprs_bssgp_cfg_strs[] = {
- { 0, "blocking-timer" },
- { 1, "blocking-retries" },
- { 2, "unblocking-retries" },
- { 3, "reset-timer" },
- { 4, "reset-retries" },
- { 5, "suspend-timer" },
- { 6, "suspend-retries" },
- { 7, "resume-timer" },
- { 8, "resume-retries" },
- { 9, "capability-update-timer" },
- { 10, "capability-update-retries" },
- { 0, NULL }
-};
-
-static const struct value_string bts_neigh_mode_strs[] = {
- { NL_MODE_AUTOMATIC, "automatic" },
- { NL_MODE_MANUAL, "manual" },
- { NL_MODE_MANUAL_SI5SEP, "manual-si5" },
- { 0, NULL }
-};
-
-struct cmd_node net_node = {
- GSMNET_NODE,
- "%s(network)#",
- 1,
-};
-
-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,
-};
-
-extern struct gsm_network *bsc_gsmnet;
-
-struct gsm_network *gsmnet_from_vty(struct vty *v)
-{
- /* In case we read from the config file, the vty->priv cannot
- * point to a struct telnet_connection, and thus conn->priv
- * will not point to the gsm_network structure */
-#if 0
- struct telnet_connection *conn = v->priv;
- return (struct gsm_network *) conn->priv;
-#else
- return bsc_gsmnet;
-#endif
-}
-
-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 dump_pchan_load_vty(struct vty *vty, char *prefix,
- const struct pchan_load *pl)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(pl->pchan); i++) {
- const struct load_counter *lc = &pl->pchan[i];
- unsigned int percent;
-
- if (lc->total == 0)
- continue;
-
- percent = (lc->used * 100) / lc->total;
-
- vty_out(vty, "%s%20s: %3u%% (%u/%u)%s", prefix,
- gsm_pchan_name(i), percent, lc->used, lc->total,
- VTY_NEWLINE);
- }
-}
-
-static void net_dump_vty(struct vty *vty, struct gsm_network *net)
-{
- struct pchan_load pl;
-
- 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);
- vty_out(vty, " Authentication policy: %s%s",
- gsm_auth_policy_name(net->auth_policy), VTY_NEWLINE);
- vty_out(vty, " Location updating reject cause: %u%s",
- net->reject_cause, VTY_NEWLINE);
- vty_out(vty, " Encryption: A5/%u%s", net->a5_encryption,
- VTY_NEWLINE);
- vty_out(vty, " NECI (TCH/H): %u%s", net->neci,
- VTY_NEWLINE);
- vty_out(vty, " Use TCH for Paging any: %d%s", net->pag_any_tch,
- VTY_NEWLINE);
- vty_out(vty, " RRLP Mode: %s%s", rrlp_mode_name(net->rrlp.mode),
- VTY_NEWLINE);
- vty_out(vty, " MM Info: %s%s", net->send_mm_info ? "On" : "Off",
- VTY_NEWLINE);
- vty_out(vty, " Handover: %s%s", net->handover.active ? "On" : "Off",
- VTY_NEWLINE);
- network_chan_load(&pl, net);
- vty_out(vty, " Current Channel Load:%s", VTY_NEWLINE);
- dump_pchan_load_vty(vty, " ", &pl);
-
- /* show rf */
- if (net->msc_data)
- vty_out(vty, " Last RF Command: %s%s",
- net->msc_data->rf_ctl->last_state_command,
- VTY_NEWLINE);
-}
-
-DEFUN(show_net, show_net_cmd, "show network",
- SHOW_STR "Display information about a GSM NETWORK\n")
-{
- struct gsm_network *net = gsmnet_from_vty(vty);
- 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)
-{
- struct pchan_load pl;
-
- vty_out(vty, "BTS %u is of %s type in band %s, has CI %u LAC %u, "
- "BSIC %u, TSC %u and %u TRX%s",
- bts->nr, btstype2str(bts->type), gsm_band_name(bts->band),
- bts->cell_identity,
- bts->location_area_code, bts->bsic, bts->tsc,
- bts->num_trx, VTY_NEWLINE);
- vty_out(vty, "Description: %s%s",
- bts->description ? bts->description : "(null)", VTY_NEWLINE);
- vty_out(vty, "MS Max power: %u dBm%s", bts->ms_max_power, VTY_NEWLINE);
- vty_out(vty, "Minimum Rx Level for Access: %i dBm%s",
- rxlev2dbm(bts->si_common.cell_sel_par.rxlev_acc_min),
- VTY_NEWLINE);
- vty_out(vty, "Cell Reselection Hysteresis: %u dBm%s",
- bts->si_common.cell_sel_par.cell_resel_hyst*2, VTY_NEWLINE);
- vty_out(vty, "RACH TX-Integer: %u%s", bts->si_common.rach_control.tx_integer,
- VTY_NEWLINE);
- vty_out(vty, "RACH Max transmissions: %u%s",
- rach_max_trans_raw2val(bts->si_common.rach_control.max_trans),
- VTY_NEWLINE);
- if (bts->si_common.rach_control.cell_bar)
- vty_out(vty, " CELL IS BARRED%s", VTY_NEWLINE);
- vty_out(vty, "System Information present: 0x%08x, static: 0x%08x%s",
- bts->si_valid, bts->si_mode_static, VTY_NEWLINE);
- if (is_ipaccess_bts(bts))
- vty_out(vty, " Unit ID: %u/%u/0, OML Stream ID 0x%02x%s",
- bts->ip_access.site_id, bts->ip_access.bts_id,
- bts->oml_tei, 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);
- if (is_ipaccess_bts(bts)) {
- vty_out(vty, " OML Link state: %s.%s",
- bts->oml_link ? "connected" : "disconnected", VTY_NEWLINE);
- } else {
- vty_out(vty, " E1 Signalling Link:%s", VTY_NEWLINE);
- e1isl_dump_vty(vty, bts->oml_link);
- }
-
- /* FIXME: chan_desc */
- memset(&pl, 0, sizeof(pl));
- bts_chan_load(&pl, bts);
- vty_out(vty, " Current Channel Load:%s", VTY_NEWLINE);
- dump_pchan_load_vty(vty, " ", &pl);
-}
-
-DEFUN(show_bts, show_bts_cmd, "show bts [number]",
- SHOW_STR "Display information about a BTS\n"
- "BTS number")
-{
- struct gsm_network *net = gsmnet_from_vty(vty);
- 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, gsm_bts_num(net, bts_nr));
- return CMD_SUCCESS;
- }
- /* print all BTS's */
- for (bts_nr = 0; bts_nr < net->num_bts; bts_nr++)
- bts_dump_vty(vty, gsm_bts_num(net, bts_nr));
-
- return CMD_SUCCESS;
-}
-
-/* utility functions */
-static void parse_e1_link(struct gsm_e1_subslot *e1_link, const char *line,
- const char *ts, const char *ss)
-{
- e1_link->e1_nr = atoi(line);
- e1_link->e1_ts = atoi(ts);
- if (!strcmp(ss, "full"))
- e1_link->e1_ts_ss = 255;
- else
- e1_link->e1_ts_ss = atoi(ss);
-}
-
-static void config_write_e1_link(struct vty *vty, struct gsm_e1_subslot *e1_link,
- const char *prefix)
-{
- if (!e1_link->e1_ts)
- return;
-
- if (e1_link->e1_ts_ss == 255)
- vty_out(vty, "%se1 line %u timeslot %u sub-slot full%s",
- prefix, e1_link->e1_nr, e1_link->e1_ts, VTY_NEWLINE);
- else
- vty_out(vty, "%se1 line %u timeslot %u sub-slot %u%s",
- prefix, e1_link->e1_nr, e1_link->e1_ts,
- e1_link->e1_ts_ss, VTY_NEWLINE);
-}
-
-
-static void config_write_ts_single(struct vty *vty, struct gsm_bts_trx_ts *ts)
-{
- vty_out(vty, " timeslot %u%s", ts->nr, VTY_NEWLINE);
- if (ts->pchan != GSM_PCHAN_NONE)
- vty_out(vty, " phys_chan_config %s%s",
- gsm_pchan_name(ts->pchan), VTY_NEWLINE);
- vty_out(vty, " hopping enabled %u%s",
- ts->hopping.enabled, VTY_NEWLINE);
- if (ts->hopping.enabled) {
- unsigned int i;
- vty_out(vty, " hopping sequence-number %u%s",
- ts->hopping.hsn, VTY_NEWLINE);
- vty_out(vty, " hopping maio %u%s",
- ts->hopping.maio, VTY_NEWLINE);
- for (i = 0; i < ts->hopping.arfcns.data_len*8; i++) {
- if (!bitvec_get_bit_pos(&ts->hopping.arfcns, i))
- continue;
- vty_out(vty, " hopping arfcn add %u%s",
- i, VTY_NEWLINE);
- }
- }
- config_write_e1_link(vty, &ts->e1_link, " ");
-
- if (ts->trx->bts->model->config_write_ts)
- ts->trx->bts->model->config_write_ts(vty, ts);
-}
-
-static void config_write_trx_single(struct vty *vty, struct gsm_bts_trx *trx)
-{
- int i;
-
- vty_out(vty, " trx %u%s", trx->nr, VTY_NEWLINE);
- if (trx->description)
- vty_out(vty, " description %s%s", trx->description,
- VTY_NEWLINE);
- vty_out(vty, " rf_locked %u%s",
- trx->nm_state.administrative == NM_STATE_LOCKED ? 1 : 0,
- VTY_NEWLINE);
- vty_out(vty, " arfcn %u%s", trx->arfcn, VTY_NEWLINE);
- vty_out(vty, " nominal power %u%s", trx->nominal_power, VTY_NEWLINE);
- vty_out(vty, " max_power_red %u%s", trx->max_power_red, VTY_NEWLINE);
- config_write_e1_link(vty, &trx->rsl_e1_link, " rsl ");
- vty_out(vty, " rsl e1 tei %u%s", trx->rsl_tei, VTY_NEWLINE);
-
- if (trx->bts->model->config_write_trx)
- trx->bts->model->config_write_trx(vty, trx);
-
- for (i = 0; i < TRX_NR_TS; i++)
- config_write_ts_single(vty, &trx->ts[i]);
-}
-
-static void config_write_bts_gprs(struct vty *vty, struct gsm_bts *bts)
-{
- unsigned int i;
- vty_out(vty, " gprs mode %s%s", bts_gprs_mode_name(bts->gprs.mode),
- VTY_NEWLINE);
- if (bts->gprs.mode == BTS_GPRS_NONE)
- return;
-
- vty_out(vty, " gprs routing area %u%s", bts->gprs.rac,
- VTY_NEWLINE);
- vty_out(vty, " gprs cell bvci %u%s", bts->gprs.cell.bvci,
- VTY_NEWLINE);
- for (i = 0; i < ARRAY_SIZE(bts->gprs.cell.timer); i++)
- vty_out(vty, " gprs cell timer %s %u%s",
- get_value_string(gprs_bssgp_cfg_strs, i),
- bts->gprs.cell.timer[i], VTY_NEWLINE);
- vty_out(vty, " gprs nsei %u%s", bts->gprs.nse.nsei,
- VTY_NEWLINE);
- for (i = 0; i < ARRAY_SIZE(bts->gprs.nse.timer); i++)
- vty_out(vty, " gprs ns timer %s %u%s",
- get_value_string(gprs_ns_timer_strs, i),
- bts->gprs.nse.timer[i], VTY_NEWLINE);
- for (i = 0; i < ARRAY_SIZE(bts->gprs.nsvc); i++) {
- struct gsm_bts_gprs_nsvc *nsvc =
- &bts->gprs.nsvc[i];
- struct in_addr ia;
-
- ia.s_addr = htonl(nsvc->remote_ip);
- vty_out(vty, " gprs nsvc %u nsvci %u%s", i,
- nsvc->nsvci, VTY_NEWLINE);
- vty_out(vty, " gprs nsvc %u local udp port %u%s", i,
- nsvc->local_port, VTY_NEWLINE);
- vty_out(vty, " gprs nsvc %u remote udp port %u%s", i,
- nsvc->remote_port, VTY_NEWLINE);
- vty_out(vty, " gprs nsvc %u remote ip %s%s", i,
- inet_ntoa(ia), VTY_NEWLINE);
- }
-}
-
-static void config_write_bts_single(struct vty *vty, struct gsm_bts *bts)
-{
- struct gsm_bts_trx *trx;
- int i;
-
- vty_out(vty, " bts %u%s", bts->nr, VTY_NEWLINE);
- vty_out(vty, " type %s%s", btstype2str(bts->type), VTY_NEWLINE);
- if (bts->description)
- vty_out(vty, " description %s%s", bts->description, VTY_NEWLINE);
- vty_out(vty, " band %s%s", gsm_band_name(bts->band), VTY_NEWLINE);
- vty_out(vty, " cell_identity %u%s", bts->cell_identity, VTY_NEWLINE);
- vty_out(vty, " location_area_code %u%s", bts->location_area_code,
- VTY_NEWLINE);
- vty_out(vty, " training_sequence_code %u%s", bts->tsc, VTY_NEWLINE);
- vty_out(vty, " base_station_id_code %u%s", bts->bsic, VTY_NEWLINE);
- vty_out(vty, " ms max power %u%s", bts->ms_max_power, VTY_NEWLINE);
- vty_out(vty, " cell reselection hysteresis %u%s",
- bts->si_common.cell_sel_par.cell_resel_hyst*2, VTY_NEWLINE);
- vty_out(vty, " rxlev access min %u%s",
- bts->si_common.cell_sel_par.rxlev_acc_min, VTY_NEWLINE);
-
- if (bts->si_common.cell_ro_sel_par.present) {
- struct gsm48_si_selection_params *sp;
- sp = &bts->si_common.cell_ro_sel_par;
-
- if (sp->cbq)
- vty_out(vty, " cell bar qualify %u%s",
- sp->cbq, VTY_NEWLINE);
-
- if (sp->cell_resel_off)
- vty_out(vty, " cell reselection offset %u%s",
- sp->cell_resel_off*2, VTY_NEWLINE);
-
- if (sp->temp_offs == 7)
- vty_out(vty, " temporary offset infinite%s",
- VTY_NEWLINE);
- else if (sp->temp_offs)
- vty_out(vty, " temporary offset %u%s",
- sp->temp_offs*10, VTY_NEWLINE);
-
- if (sp->penalty_time == 31)
- vty_out(vty, " penalty time reserved%s",
- VTY_NEWLINE);
- else if (sp->penalty_time)
- vty_out(vty, " penalty time %u%s",
- (sp->penalty_time*20)+20, VTY_NEWLINE);
- }
-
- if (bts->si_common.chan_desc.t3212)
- vty_out(vty, " periodic location update %u%s",
- bts->si_common.chan_desc.t3212 * 6, VTY_NEWLINE);
- vty_out(vty, " channel allocator %s%s",
- bts->chan_alloc_reverse ? "descending" : "ascending",
- VTY_NEWLINE);
- vty_out(vty, " rach tx integer %u%s",
- bts->si_common.rach_control.tx_integer, VTY_NEWLINE);
- vty_out(vty, " rach max transmission %u%s",
- rach_max_trans_raw2val(bts->si_common.rach_control.max_trans),
- VTY_NEWLINE);
-
- if (bts->rach_b_thresh != -1)
- vty_out(vty, " rach nm busy threshold %u%s",
- bts->rach_b_thresh, VTY_NEWLINE);
- if (bts->rach_ldavg_slots != -1)
- vty_out(vty, " rach nm load average %u%s",
- bts->rach_ldavg_slots, VTY_NEWLINE);
- if (bts->si_common.rach_control.cell_bar)
- vty_out(vty, " cell barred 1%s", VTY_NEWLINE);
- if ((bts->si_common.rach_control.t2 & 0x4) == 0)
- vty_out(vty, " rach emergency call allowed 1%s", VTY_NEWLINE);
- for (i = SYSINFO_TYPE_1; i < _MAX_SYSINFO_TYPE; i++) {
- if (bts->si_mode_static & (1 << i)) {
- vty_out(vty, " system-information %s mode static%s",
- get_value_string(osmo_sitype_strs, i), VTY_NEWLINE);
- vty_out(vty, " system-information %s static %s%s",
- get_value_string(osmo_sitype_strs, i),
- hexdump_nospc(bts->si_buf[i], sizeof(bts->si_buf[i])),
- VTY_NEWLINE);
- }
- }
- if (is_ipaccess_bts(bts)) {
- vty_out(vty, " ip.access unit_id %u %u%s",
- bts->ip_access.site_id, bts->ip_access.bts_id, VTY_NEWLINE);
- vty_out(vty, " oml ip.access stream_id %u%s", bts->oml_tei, VTY_NEWLINE);
- } else {
- config_write_e1_link(vty, &bts->oml_e1_link, " oml ");
- vty_out(vty, " oml e1 tei %u%s", bts->oml_tei, VTY_NEWLINE);
- }
-
- /* if we have a limit, write it */
- if (bts->paging.free_chans_need >= 0)
- vty_out(vty, " paging free %d%s", bts->paging.free_chans_need, VTY_NEWLINE);
-
- vty_out(vty, " neighbor-list mode %s%s",
- get_value_string(bts_neigh_mode_strs, bts->neigh_list_manual_mode), VTY_NEWLINE);
- if (bts->neigh_list_manual_mode != NL_MODE_AUTOMATIC) {
- for (i = 0; i < 1024; i++) {
- if (bitvec_get_bit_pos(&bts->si_common.neigh_list, i))
- vty_out(vty, " neighbor-list add arfcn %u%s",
- i, VTY_NEWLINE);
- }
- }
- if (bts->neigh_list_manual_mode == NL_MODE_MANUAL_SI5SEP) {
- for (i = 0; i < 1024; i++) {
- if (bitvec_get_bit_pos(&bts->si_common.si5_neigh_list, i))
- vty_out(vty, " si5 neighbor-list add arfcn %u%s",
- i, VTY_NEWLINE);
- }
- }
-
- config_write_bts_gprs(vty, bts);
-
- if (bts->model->config_write_bts)
- bts->model->config_write_bts(vty, bts);
-
- llist_for_each_entry(trx, &bts->trx_list, list)
- config_write_trx_single(vty, trx);
-}
-
-static int config_write_bts(struct vty *v)
-{
- struct gsm_network *gsmnet = gsmnet_from_vty(v);
- struct gsm_bts *bts;
-
- llist_for_each_entry(bts, &gsmnet->bts_list, list)
- config_write_bts_single(v, bts);
-
- return CMD_SUCCESS;
-}
-
-static int config_write_net(struct vty *vty)
-{
- struct gsm_network *gsmnet = gsmnet_from_vty(vty);
-
- vty_out(vty, "network%s", VTY_NEWLINE);
- vty_out(vty, " network country code %u%s", gsmnet->country_code, VTY_NEWLINE);
- vty_out(vty, " mobile network code %u%s", gsmnet->network_code, VTY_NEWLINE);
- vty_out(vty, " short name %s%s", gsmnet->name_short, VTY_NEWLINE);
- vty_out(vty, " long name %s%s", gsmnet->name_long, VTY_NEWLINE);
- vty_out(vty, " auth policy %s%s", gsm_auth_policy_name(gsmnet->auth_policy), VTY_NEWLINE);
- vty_out(vty, " location updating reject cause %u%s",
- gsmnet->reject_cause, VTY_NEWLINE);
- vty_out(vty, " encryption a5 %u%s", gsmnet->a5_encryption, VTY_NEWLINE);
- vty_out(vty, " neci %u%s", gsmnet->neci, VTY_NEWLINE);
- vty_out(vty, " paging any use tch %d%s", gsmnet->pag_any_tch, VTY_NEWLINE);
- vty_out(vty, " rrlp mode %s%s", rrlp_mode_name(gsmnet->rrlp.mode),
- VTY_NEWLINE);
- vty_out(vty, " mm info %u%s", gsmnet->send_mm_info, VTY_NEWLINE);
- vty_out(vty, " handover %u%s", gsmnet->handover.active, VTY_NEWLINE);
- vty_out(vty, " handover window rxlev averaging %u%s",
- gsmnet->handover.win_rxlev_avg, VTY_NEWLINE);
- vty_out(vty, " handover window rxqual averaging %u%s",
- gsmnet->handover.win_rxqual_avg, VTY_NEWLINE);
- vty_out(vty, " handover window rxlev neighbor averaging %u%s",
- gsmnet->handover.win_rxlev_avg_neigh, VTY_NEWLINE);
- vty_out(vty, " handover power budget interval %u%s",
- gsmnet->handover.pwr_interval, VTY_NEWLINE);
- vty_out(vty, " handover power budget hysteresis %u%s",
- gsmnet->handover.pwr_hysteresis, VTY_NEWLINE);
- vty_out(vty, " handover maximum distance %u%s",
- gsmnet->handover.max_distance, VTY_NEWLINE);
- vty_out(vty, " timer t3101 %u%s", gsmnet->T3101, VTY_NEWLINE);
- vty_out(vty, " timer t3103 %u%s", gsmnet->T3103, VTY_NEWLINE);
- vty_out(vty, " timer t3105 %u%s", gsmnet->T3105, VTY_NEWLINE);
- vty_out(vty, " timer t3107 %u%s", gsmnet->T3107, VTY_NEWLINE);
- vty_out(vty, " timer t3109 %u%s", gsmnet->T3109, VTY_NEWLINE);
- vty_out(vty, " timer t3111 %u%s", gsmnet->T3111, VTY_NEWLINE);
- vty_out(vty, " timer t3113 %u%s", gsmnet->T3113, VTY_NEWLINE);
- vty_out(vty, " timer t3115 %u%s", gsmnet->T3115, VTY_NEWLINE);
- vty_out(vty, " timer t3117 %u%s", gsmnet->T3117, VTY_NEWLINE);
- vty_out(vty, " timer t3119 %u%s", gsmnet->T3119, VTY_NEWLINE);
- vty_out(vty, " timer t3122 %u%s", gsmnet->T3122, VTY_NEWLINE);
- vty_out(vty, " timer t3141 %u%s", gsmnet->T3141, VTY_NEWLINE);
- vty_out(vty, " dtx-used %u%s", gsmnet->dtx_enabled, VTY_NEWLINE);
- vty_out(vty, " subscriber-keep-in-ram %d%s",
- gsmnet->keep_subscr, VTY_NEWLINE);
-
- 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, "Description: %s%s",
- trx->description ? trx->description : "(null)", VTY_NEWLINE);
- vty_out(vty, " RF Nominal Power: %d dBm, reduced by %u dB, "
- "resulting BS power: %d dBm%s",
- trx->nominal_power, trx->max_power_red,
- trx->nominal_power - trx->max_power_red, 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);
- if (is_ipaccess_bts(trx->bts)) {
- vty_out(vty, " ip.access stream ID: 0x%02x%s",
- trx->rsl_tei, VTY_NEWLINE);
- } else {
- 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"
- "BTS Number\n"
- "TRX Number\n")
-{
- struct gsm_network *net = gsmnet_from_vty(vty);
- 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 = gsm_bts_num(net, 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 = gsm_bts_trx_num(bts, 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 = gsm_bts_trx_num(bts, trx_nr);
- trx_dump_vty(vty, trx);
- }
- return CMD_SUCCESS;
- }
-
- for (bts_nr = 0; bts_nr < net->num_bts; bts_nr++) {
- bts = gsm_bts_num(net, bts_nr);
- for (trx_nr = 0; trx_nr < bts->num_trx; trx_nr++) {
- trx = gsm_bts_trx_num(bts, trx_nr);
- trx_dump_vty(vty, trx);
- }
- }
-
- return CMD_SUCCESS;
-}
-
-
-static void ts_dump_vty(struct vty *vty, struct gsm_bts_trx_ts *ts)
-{
- vty_out(vty, "BTS %u, TRX %u, Timeslot %u, phys cfg %s",
- ts->trx->bts->nr, ts->trx->nr, ts->nr,
- gsm_pchan_name(ts->pchan));
- if (ts->pchan == GSM_PCHAN_TCH_F_PDCH)
- vty_out(vty, " (%s mode)",
- ts->flags & TS_F_PDCH_MODE ? "PDCH" : "TCH/F");
- vty_out(vty, "%s", VTY_NEWLINE);
- vty_out(vty, " NM State: ");
- net_dump_nmstate(vty, &ts->nm_state);
- if (!is_ipaccess_bts(ts->trx->bts))
- 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"
- "BTS Number\n" "TRX Number\n" "Timeslot Number\n")
-{
- struct gsm_network *net = gsmnet_from_vty(vty);
- struct gsm_bts *bts = NULL;
- struct gsm_bts_trx *trx = NULL;
- struct gsm_bts_trx_ts *ts = NULL;
- 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 = gsm_bts_num(net, 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 = gsm_bts_trx_num(bts, 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;
- }
- /* Fully Specified: print and exit */
- ts = &trx->ts[ts_nr];
- ts_dump_vty(vty, ts);
- return CMD_SUCCESS;
- }
-
- if (bts && trx) {
- /* Iterate over all TS in this TRX */
- for (ts_nr = 0; ts_nr < TRX_NR_TS; ts_nr++) {
- ts = &trx->ts[ts_nr];
- ts_dump_vty(vty, ts);
- }
- } else if (bts) {
- /* Iterate over all TRX in this BTS, TS in each TRX */
- for (trx_nr = 0; trx_nr < bts->num_trx; trx_nr++) {
- trx = gsm_bts_trx_num(bts, trx_nr);
- for (ts_nr = 0; ts_nr < TRX_NR_TS; ts_nr++) {
- ts = &trx->ts[ts_nr];
- ts_dump_vty(vty, ts);
- }
- }
- } else {
- /* Iterate over all BTS, TRX in each BTS, TS in each TRX */
- for (bts_nr = 0; bts_nr < net->num_bts; bts_nr++) {
- bts = gsm_bts_num(net, bts_nr);
- for (trx_nr = 0; trx_nr < bts->num_trx; trx_nr++) {
- trx = gsm_bts_trx_num(bts, 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: %llu, 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 != GSM_RESERVED_TMSI)
- vty_out(vty, " TMSI: %08X%s", subscr->tmsi,
- VTY_NEWLINE);
-
- vty_out(vty, " Use count: %u%s", subscr->use_count, VTY_NEWLINE);
-}
-
-static void meas_rep_dump_uni_vty(struct vty *vty,
- struct gsm_meas_rep_unidir *mru,
- const char *prefix,
- const char *dir)
-{
- vty_out(vty, "%s RXL-FULL-%s: %4d dBm, RXL-SUB-%s: %4d dBm ",
- prefix, dir, rxlev2dbm(mru->full.rx_lev),
- dir, rxlev2dbm(mru->sub.rx_lev));
- vty_out(vty, "RXQ-FULL-%s: %d, RXQ-SUB-%s: %d%s",
- dir, mru->full.rx_qual, dir, mru->sub.rx_qual,
- VTY_NEWLINE);
-}
-
-static void meas_rep_dump_vty(struct vty *vty, struct gsm_meas_rep *mr,
- const char *prefix)
-{
- vty_out(vty, "%sMeasurement Report:%s", prefix, VTY_NEWLINE);
- vty_out(vty, "%s Flags: %s%s%s%s%s", prefix,
- mr->flags & MEAS_REP_F_UL_DTX ? "DTXu " : "",
- mr->flags & MEAS_REP_F_DL_DTX ? "DTXd " : "",
- mr->flags & MEAS_REP_F_FPC ? "FPC " : "",
- mr->flags & MEAS_REP_F_DL_VALID ? " " : "DLinval ",
- VTY_NEWLINE);
- if (mr->flags & MEAS_REP_F_MS_TO)
- vty_out(vty, "%s MS Timing Offset: %u%s", prefix,
- mr->ms_timing_offset, VTY_NEWLINE);
- if (mr->flags & MEAS_REP_F_MS_L1)
- vty_out(vty, "%s L1 MS Power: %u dBm, Timing Advance: %u%s",
- prefix, mr->ms_l1.pwr, mr->ms_l1.ta, VTY_NEWLINE);
- if (mr->flags & MEAS_REP_F_DL_VALID)
- meas_rep_dump_uni_vty(vty, &mr->dl, prefix, "dl");
- meas_rep_dump_uni_vty(vty, &mr->ul, prefix, "ul");
-}
-
-static void lchan_dump_full_vty(struct vty *vty, struct gsm_lchan *lchan)
-{
- int idx;
-
- vty_out(vty, "BTS %u, TRX %u, Timeslot %u, Lchan %u: Type %s%s",
- lchan->ts->trx->bts->nr, lchan->ts->trx->nr, lchan->ts->nr,
- lchan->nr, gsm_lchant_name(lchan->type), VTY_NEWLINE);
- vty_out(vty, " Connection: %u, State: %s%s",
- lchan->conn ? 1: 0,
- gsm_lchans_name(lchan->state), VTY_NEWLINE);
- vty_out(vty, " BS Power: %u dBm, MS Power: %u dBm%s",
- lchan->ts->trx->nominal_power - lchan->ts->trx->max_power_red
- - lchan->bs_power*2,
- ms_pwr_dbm(lchan->ts->trx->bts->band, lchan->ms_power),
- VTY_NEWLINE);
- if (lchan->conn && lchan->conn->subscr) {
- vty_out(vty, " Subscriber:%s", VTY_NEWLINE);
- subscr_dump_vty(vty, lchan->conn->subscr);
- } else
- vty_out(vty, " No Subscriber%s", VTY_NEWLINE);
- if (is_ipaccess_bts(lchan->ts->trx->bts)) {
- struct in_addr ia;
- ia.s_addr = htonl(lchan->abis_ip.bound_ip);
- vty_out(vty, " Bound IP: %s Port %u RTP_TYPE2=%u CONN_ID=%u%s",
- inet_ntoa(ia), lchan->abis_ip.bound_port,
- lchan->abis_ip.rtp_payload2, lchan->abis_ip.conn_id,
- VTY_NEWLINE);
- }
-
- /* we want to report the last measurement report */
- idx = calc_initial_idx(ARRAY_SIZE(lchan->meas_rep),
- lchan->meas_rep_idx, 1);
- meas_rep_dump_vty(vty, &lchan->meas_rep[idx], " ");
-}
-
-static void lchan_dump_short_vty(struct vty *vty, struct gsm_lchan *lchan)
-{
- struct gsm_meas_rep *mr;
- int idx;
-
- /* we want to report the last measurement report */
- idx = calc_initial_idx(ARRAY_SIZE(lchan->meas_rep),
- lchan->meas_rep_idx, 1);
- mr = &lchan->meas_rep[idx];
-
- vty_out(vty, "BTS %u, TRX %u, Timeslot %u, Lchan %u, Type %s - "
- "L1 MS Power: %u dBm RXL-FULL-dl: %4d dBm RXL-FULL-ul: %4d dBm%s",
- lchan->ts->trx->bts->nr, lchan->ts->trx->nr, lchan->ts->nr,
- lchan->nr, gsm_lchant_name(lchan->type), mr->ms_l1.pwr,
- rxlev2dbm(mr->dl.full.rx_lev),
- rxlev2dbm(mr->ul.full.rx_lev),
- VTY_NEWLINE);
-}
-
-static int lchan_summary(struct vty *vty, int argc, const char **argv,
- void (*dump_cb)(struct vty *, struct gsm_lchan *))
-{
- struct gsm_network *net = gsmnet_from_vty(vty);
- 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 = gsm_bts_num(net, 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 = gsm_bts_trx_num(bts, 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];
- dump_cb(vty, lchan);
- return CMD_SUCCESS;
- }
- for (bts_nr = 0; bts_nr < net->num_bts; bts_nr++) {
- bts = gsm_bts_num(net, bts_nr);
- for (trx_nr = 0; trx_nr < bts->num_trx; trx_nr++) {
- trx = gsm_bts_trx_num(bts, 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;
- dump_cb(vty, lchan);
- }
- }
- }
- }
-
- return CMD_SUCCESS;
-}
-
-
-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"
- "BTS Number\n" "TRX Number\n" "Timeslot Number\n"
- "Logical Channel Number\n")
-
-{
- return lchan_summary(vty, argc, argv, lchan_dump_full_vty);
-}
-
-DEFUN(show_lchan_summary,
- show_lchan_summary_cmd,
- "show lchan summary [bts_nr] [trx_nr] [ts_nr] [lchan_nr]",
- SHOW_STR "Display information about a logical channel\n"
- "BTS Number\n" "TRX Number\n" "Timeslot Number\n"
- "Logical Channel Number\n")
-{
- return lchan_summary(vty, argc, argv, lchan_dump_short_vty);
-}
-
-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"
- "E1 Line Number\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)
-{
- if (ts->type == E1INP_TS_TYPE_NONE)
- return;
- 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"
- "E1 Line Number\n" "E1 Timeslot Number\n")
-{
- struct e1inp_line *line = NULL;
- 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"
- "BTS Number\n")
-{
- struct gsm_network *net = gsmnet_from_vty(vty);
- 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 = gsm_bts_num(net, bts_nr);
- bts_paging_dump_vty(vty, bts);
-
- return CMD_SUCCESS;
- }
- for (bts_nr = 0; bts_nr < net->num_bts; bts_nr++) {
- bts = gsm_bts_num(net, bts_nr);
- bts_paging_dump_vty(vty, bts);
- }
-
- return CMD_SUCCESS;
-}
-
-#define NETWORK_STR "Configure the GSM network\n"
-
-DEFUN(cfg_net,
- cfg_net_cmd,
- "network", NETWORK_STR)
-{
- vty->index = gsmnet_from_vty(vty);
- vty->node = GSMNET_NODE;
-
- return CMD_SUCCESS;
-}
-
-
-DEFUN(cfg_net_ncc,
- cfg_net_ncc_cmd,
- "network country code <1-999>",
- "Set the GSM network country code")
-{
- struct gsm_network *gsmnet = gsmnet_from_vty(vty);
-
- gsmnet->country_code = atoi(argv[0]);
-
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_net_mnc,
- cfg_net_mnc_cmd,
- "mobile network code <1-999>",
- "Set the GSM mobile network code")
-{
- struct gsm_network *gsmnet = gsmnet_from_vty(vty);
-
- gsmnet->network_code = atoi(argv[0]);
-
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_net_name_short,
- cfg_net_name_short_cmd,
- "short name NAME",
- "Set the short GSM network name")
-{
- struct gsm_network *gsmnet = gsmnet_from_vty(vty);
-
- bsc_replace_string(gsmnet, &gsmnet->name_short, argv[0]);
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_net_name_long,
- cfg_net_name_long_cmd,
- "long name NAME",
- "Set the long GSM network name")
-{
- struct gsm_network *gsmnet = gsmnet_from_vty(vty);
-
- bsc_replace_string(gsmnet, &gsmnet->name_long, argv[0]);
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_net_auth_policy,
- cfg_net_auth_policy_cmd,
- "auth policy (closed|accept-all|token)",
- "Authentication (not cryptographic)\n"
- "Set the GSM network authentication policy\n"
- "Require the MS to be activated in HLR\n"
- "Accept all MS, whether in HLR or not\n"
- "Use SMS-token based authentication\n")
-{
- enum gsm_auth_policy policy = gsm_auth_policy_parse(argv[0]);
- struct gsm_network *gsmnet = gsmnet_from_vty(vty);
-
- gsmnet->auth_policy = policy;
-
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_net_reject_cause,
- cfg_net_reject_cause_cmd,
- "location updating reject cause <2-111>",
- "Set the reject cause of location updating reject\n")
-{
- struct gsm_network *gsmnet = gsmnet_from_vty(vty);
-
- gsmnet->reject_cause = atoi(argv[0]);
-
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_net_encryption,
- cfg_net_encryption_cmd,
- "encryption a5 (0|1|2)",
- "Encryption options\n"
- "A5 encryption\n" "A5/0: No encryption\n"
- "A5/1: Encryption\n" "A5/2: Export-grade Encryption\n")
-{
- struct gsm_network *gsmnet = gsmnet_from_vty(vty);
-
- gsmnet->a5_encryption= atoi(argv[0]);
-
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_net_neci,
- cfg_net_neci_cmd,
- "neci (0|1)",
- "New Establish Cause Indication\n"
- "Don't set the NECI bit\n" "Set the NECI bit\n")
-{
- struct gsm_network *gsmnet = gsmnet_from_vty(vty);
-
- gsmnet->neci = atoi(argv[0]);
- gsm_net_update_ctype(gsmnet);
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_net_rrlp_mode, cfg_net_rrlp_mode_cmd,
- "rrlp mode (none|ms-based|ms-preferred|ass-preferred)",
- "Radio Resource Location Protocol\n"
- "Set the Radio Resource Location Protocol Mode\n"
- "Don't send RRLP request\n"
- "Request MS-based location\n"
- "Request any location, prefer MS-based\n"
- "Request any location, prefer MS-assisted\n")
-{
- struct gsm_network *gsmnet = gsmnet_from_vty(vty);
-
- gsmnet->rrlp.mode = rrlp_mode_parse(argv[0]);
-
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_net_mm_info, cfg_net_mm_info_cmd,
- "mm info (0|1)",
- "Whether to send MM INFO after LOC UPD ACCEPT")
-{
- struct gsm_network *gsmnet = gsmnet_from_vty(vty);
-
- gsmnet->send_mm_info = atoi(argv[0]);
-
- return CMD_SUCCESS;
-}
-
-#define HANDOVER_STR "Handover Options\n"
-
-DEFUN(cfg_net_handover, cfg_net_handover_cmd,
- "handover (0|1)",
- HANDOVER_STR
- "Don't perform in-call handover\n"
- "Perform in-call handover\n")
-{
- int enable = atoi(argv[0]);
- struct gsm_network *gsmnet = gsmnet_from_vty(vty);
-
- if (enable && ipacc_rtp_direct) {
- vty_out(vty, "%% Cannot enable handover unless RTP Proxy mode "
- "is enabled by using the -P command line option%s",
- VTY_NEWLINE);
- return CMD_WARNING;
- }
- gsmnet->handover.active = enable;
-
- return CMD_SUCCESS;
-}
-
-#define HO_WIN_STR HANDOVER_STR "Measurement Window\n"
-#define HO_WIN_RXLEV_STR HO_WIN_STR "Received Level Averaging\n"
-#define HO_WIN_RXQUAL_STR HO_WIN_STR "Received Quality Averaging\n"
-#define HO_PBUDGET_STR HANDOVER_STR "Power Budget\n"
-
-DEFUN(cfg_net_ho_win_rxlev_avg, cfg_net_ho_win_rxlev_avg_cmd,
- "handover window rxlev averaging <1-10>",
- HO_WIN_RXLEV_STR
- "How many RxLev measurements are used for averaging")
-{
- struct gsm_network *gsmnet = gsmnet_from_vty(vty);
- gsmnet->handover.win_rxlev_avg = atoi(argv[0]);
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_net_ho_win_rxqual_avg, cfg_net_ho_win_rxqual_avg_cmd,
- "handover window rxqual averaging <1-10>",
- HO_WIN_RXQUAL_STR
- "How many RxQual measurements are used for averaging")
-{
- struct gsm_network *gsmnet = gsmnet_from_vty(vty);
- gsmnet->handover.win_rxqual_avg = atoi(argv[0]);
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_net_ho_win_rxlev_neigh_avg, cfg_net_ho_win_rxlev_avg_neigh_cmd,
- "handover window rxlev neighbor averaging <1-10>",
- HO_WIN_RXLEV_STR
- "How many RxQual measurements are used for averaging")
-{
- struct gsm_network *gsmnet = gsmnet_from_vty(vty);
- gsmnet->handover.win_rxlev_avg_neigh = atoi(argv[0]);
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_net_ho_pwr_interval, cfg_net_ho_pwr_interval_cmd,
- "handover power budget interval <1-99>",
- HO_PBUDGET_STR
- "How often to check if we have a better cell (SACCH frames)")
-{
- struct gsm_network *gsmnet = gsmnet_from_vty(vty);
- gsmnet->handover.pwr_interval = atoi(argv[0]);
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_net_ho_pwr_hysteresis, cfg_net_ho_pwr_hysteresis_cmd,
- "handover power budget hysteresis <0-999>",
- HO_PBUDGET_STR
- "How many dB does a neighbor to be stronger to become a HO candidate")
-{
- struct gsm_network *gsmnet = gsmnet_from_vty(vty);
- gsmnet->handover.pwr_hysteresis = atoi(argv[0]);
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_net_ho_max_distance, cfg_net_ho_max_distance_cmd,
- "handover maximum distance <0-9999>",
- HANDOVER_STR
- "How big is the maximum timing advance before HO is forced")
-{
- struct gsm_network *gsmnet = gsmnet_from_vty(vty);
- gsmnet->handover.max_distance = atoi(argv[0]);
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_net_pag_any_tch,
- cfg_net_pag_any_tch_cmd,
- "paging any use tch (0|1)",
- "Assign a TCH when receiving a Paging Any request")
-{
- struct gsm_network *gsmnet = gsmnet_from_vty(vty);
- gsmnet->pag_any_tch = atoi(argv[0]);
- gsm_net_update_ctype(gsmnet);
- return CMD_SUCCESS;
-}
-
-#define DECLARE_TIMER(number, doc) \
- DEFUN(cfg_net_T##number, \
- cfg_net_T##number##_cmd, \
- "timer t" #number " <0-65535>", \
- "Configure GSM Timers\n" \
- doc) \
-{ \
- struct gsm_network *gsmnet = gsmnet_from_vty(vty); \
- int value = atoi(argv[0]); \
- \
- if (value < 0 || value > 65535) { \
- vty_out(vty, "Timer value %s out of range.%s", \
- argv[0], VTY_NEWLINE); \
- return CMD_WARNING; \
- } \
- \
- gsmnet->T##number = value; \
- return CMD_SUCCESS; \
-}
-
-DECLARE_TIMER(3101, "Set the timeout value for IMMEDIATE ASSIGNMENT.")
-DECLARE_TIMER(3103, "Set the timeout value for HANDOVER.")
-DECLARE_TIMER(3105, "Currently not used.")
-DECLARE_TIMER(3107, "Currently not used.")
-DECLARE_TIMER(3109, "Currently not used.")
-DECLARE_TIMER(3111, "Set the RSL timeout to wait before releasing the RF Channel.")
-DECLARE_TIMER(3113, "Set the time to try paging a subscriber.")
-DECLARE_TIMER(3115, "Currently not used.")
-DECLARE_TIMER(3117, "Currently not used.")
-DECLARE_TIMER(3119, "Currently not used.")
-DECLARE_TIMER(3122, "Waiting time (seconds) after IMM ASS REJECT")
-DECLARE_TIMER(3141, "Currently not used.")
-
-DEFUN(cfg_net_dtx,
- cfg_net_dtx_cmd,
- "dtx-used (0|1)",
- "Enable the usage of DTX.\n"
- "DTX is enabled/disabled")
-{
- struct gsm_network *gsmnet = gsmnet_from_vty(vty);
- gsmnet->dtx_enabled = atoi(argv[0]);
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_net_subscr_keep,
- cfg_net_subscr_keep_cmd,
- "subscriber-keep-in-ram (0|1)",
- "Keep unused subscribers in RAM.\n"
- "Delete unused subscribers\n" "Keep unused subscribers\n")
-{
- struct gsm_network *gsmnet = gsmnet_from_vty(vty);
- gsmnet->keep_subscr = atoi(argv[0]);
- return CMD_SUCCESS;
-}
-
-/* per-BTS configuration */
-DEFUN(cfg_bts,
- cfg_bts_cmd,
- "bts BTS_NR",
- "Select a BTS to configure\n"
- "BTS Number\n")
-{
- struct gsm_network *gsmnet = gsmnet_from_vty(vty);
- int bts_nr = atoi(argv[0]);
- struct gsm_bts *bts;
-
- if (bts_nr > gsmnet->num_bts) {
- vty_out(vty, "%% The next unused BTS number is %u%s",
- gsmnet->num_bts, VTY_NEWLINE);
- return CMD_WARNING;
- } else if (bts_nr == gsmnet->num_bts) {
- /* allocate a new one */
- bts = gsm_bts_alloc(gsmnet, GSM_BTS_TYPE_UNKNOWN,
- HARDCODED_TSC, HARDCODED_BSIC);
- } else
- bts = gsm_bts_num(gsmnet, bts_nr);
-
- if (!bts) {
- vty_out(vty, "%% Unable to allocate BTS %u%s",
- gsmnet->num_bts, VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- vty->index = bts;
- vty->index_sub = &bts->description;
- 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;
- int rc;
-
- rc = gsm_set_bts_type(bts, parse_btstype(argv[0]));
- if (rc < 0)
- return CMD_WARNING;
-
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_bts_band,
- cfg_bts_band_cmd,
- "band BAND",
- "Set the frequency band of this BTS\n")
-{
- struct gsm_bts *bts = vty->index;
- int band = gsm_band_parse(argv[0]);
-
- if (band < 0) {
- vty_out(vty, "%% BAND %d is not a valid GSM band%s",
- band, VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- bts->band = band;
-
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_bts_ci,
- cfg_bts_ci_cmd,
- "cell_identity <0-65535>",
- "Set the Cell identity of this BTS\n")
-{
- struct gsm_bts *bts = vty->index;
- int ci = atoi(argv[0]);
-
- if (ci < 0 || ci > 0xffff) {
- vty_out(vty, "%% CI %d is not in the valid range (0-65535)%s",
- ci, VTY_NEWLINE);
- return CMD_WARNING;
- }
- bts->cell_identity = ci;
-
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_bts_lac,
- cfg_bts_lac_cmd,
- "location_area_code <0-65535>",
- "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 > 0xffff) {
- vty_out(vty, "%% LAC %d is not in the valid range (0-65535)%s",
- lac, VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- if (lac == GSM_LAC_RESERVED_DETACHED || lac == GSM_LAC_RESERVED_ALL_BTS) {
- vty_out(vty, "%% LAC %d is reserved by GSM 04.08%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, "%% BSIC %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,
- "ip.access unit_id <0-65534> <0-255>",
- "Set the ip.access 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 (!is_ipaccess_bts(bts)) {
- vty_out(vty, "%% BTS is not of ip.access type%s", VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- bts->ip_access.site_id = site_id;
- bts->ip_access.bts_id = bts_id;
-
- return CMD_SUCCESS;
-}
-
-#define OML_STR "Organization & Maintenance Link\n"
-#define IPA_STR "ip.access Specific Options\n"
-
-DEFUN(cfg_bts_stream_id,
- cfg_bts_stream_id_cmd,
- "oml ip.access stream_id <0-255>",
- OML_STR IPA_STR
- "Set the ip.access Stream ID of the OML link of this BTS\n")
-{
- struct gsm_bts *bts = vty->index;
- int stream_id = atoi(argv[0]);
-
- if (!is_ipaccess_bts(bts)) {
- vty_out(vty, "%% BTS is not of ip.access type%s", VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- bts->oml_tei = stream_id;
-
- return CMD_SUCCESS;
-}
-
-#define OML_E1_STR OML_STR "E1 Line\n"
-
-DEFUN(cfg_bts_oml_e1,
- cfg_bts_oml_e1_cmd,
- "oml e1 line E1_LINE timeslot <1-31> sub-slot (0|1|2|3|full)",
- OML_E1_STR
- "E1 interface to be used for OML\n")
-{
- struct gsm_bts *bts = vty->index;
-
- parse_e1_link(&bts->oml_e1_link, argv[0], argv[1], argv[2]);
-
- return CMD_SUCCESS;
-}
-
-
-DEFUN(cfg_bts_oml_e1_tei,
- cfg_bts_oml_e1_tei_cmd,
- "oml e1 tei <0-63>",
- OML_E1_STR
- "Set the TEI to be used for OML")
-{
- struct gsm_bts *bts = vty->index;
-
- bts->oml_tei = atoi(argv[0]);
-
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_bts_challoc, cfg_bts_challoc_cmd,
- "channel allocator (ascending|descending)",
- "Channnel Allocator\n" "Channel Allocator\n"
- "Allocate Timeslots and Transceivers in ascending order\n"
- "Allocate Timeslots and Transceivers in descending order\n")
-{
- struct gsm_bts *bts = vty->index;
-
- if (!strcmp(argv[0], "ascending"))
- bts->chan_alloc_reverse = 0;
- else
- bts->chan_alloc_reverse = 1;
-
- return CMD_SUCCESS;
-}
-
-#define RACH_STR "Random Access Control Channel\n"
-
-DEFUN(cfg_bts_rach_tx_integer,
- cfg_bts_rach_tx_integer_cmd,
- "rach tx integer <0-15>",
- RACH_STR
- "Set the raw tx integer value in RACH Control parameters IE")
-{
- struct gsm_bts *bts = vty->index;
- bts->si_common.rach_control.tx_integer = atoi(argv[0]) & 0xf;
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_bts_rach_max_trans,
- cfg_bts_rach_max_trans_cmd,
- "rach max transmission (1|2|4|7)",
- RACH_STR
- "Set the maximum number of RACH burst transmissions")
-{
- struct gsm_bts *bts = vty->index;
- bts->si_common.rach_control.max_trans = rach_max_trans_val2raw(atoi(argv[0]));
- return CMD_SUCCESS;
-}
-
-#define NM_STR "Network Management\n"
-
-DEFUN(cfg_bts_rach_nm_b_thresh,
- cfg_bts_rach_nm_b_thresh_cmd,
- "rach nm busy threshold <0-255>",
- RACH_STR NM_STR
- "Set the NM Busy Threshold in dB")
-{
- struct gsm_bts *bts = vty->index;
- bts->rach_b_thresh = atoi(argv[0]);
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_bts_rach_nm_ldavg,
- cfg_bts_rach_nm_ldavg_cmd,
- "rach nm load average <0-65535>",
- RACH_STR NM_STR
- "Set the NM Loadaverage Slots value")
-{
- struct gsm_bts *bts = vty->index;
- bts->rach_ldavg_slots = atoi(argv[0]);
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_bts_cell_barred, cfg_bts_cell_barred_cmd,
- "cell barred (0|1)",
- "Should this cell be barred from access?")
-{
- struct gsm_bts *bts = vty->index;
-
- bts->si_common.rach_control.cell_bar = atoi(argv[0]);
-
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_bts_rach_ec_allowed, cfg_bts_rach_ec_allowed_cmd,
- "rach emergency call allowed (0|1)",
- "Should this cell allow emergency calls?")
-{
- struct gsm_bts *bts = vty->index;
-
- if (atoi(argv[0]) == 0)
- bts->si_common.rach_control.t2 |= 0x4;
- else
- bts->si_common.rach_control.t2 &= ~0x4;
-
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_bts_ms_max_power, cfg_bts_ms_max_power_cmd,
- "ms max power <0-40>",
- "Maximum transmit power of the MS")
-{
- struct gsm_bts *bts = vty->index;
-
- bts->ms_max_power = atoi(argv[0]);
-
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_bts_cell_resel_hyst, cfg_bts_cell_resel_hyst_cmd,
- "cell reselection hysteresis <0-14>",
- "Cell Re-Selection Hysteresis in dB")
-{
- struct gsm_bts *bts = vty->index;
-
- bts->si_common.cell_sel_par.cell_resel_hyst = atoi(argv[0])/2;
-
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_bts_rxlev_acc_min, cfg_bts_rxlev_acc_min_cmd,
- "rxlev access min <0-63>",
- "Minimum RxLev needed for cell access (better than -110dBm)")
-{
- struct gsm_bts *bts = vty->index;
-
- bts->si_common.cell_sel_par.rxlev_acc_min = atoi(argv[0]);
-
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_bts_cell_bar_qualify, cfg_bts_cell_bar_qualify_cmd,
- "cell bar qualify (0|1)",
- "Cell Bar Qualify")
-{
- struct gsm_bts *bts = vty->index;
-
- bts->si_common.cell_ro_sel_par.present = 1;
- bts->si_common.cell_ro_sel_par.cbq = atoi(argv[0]);
-
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_bts_cell_resel_ofs, cfg_bts_cell_resel_ofs_cmd,
- "cell reselection offset <0-126>",
- "Cell Re-Selection Offset in dB")
-{
- struct gsm_bts *bts = vty->index;
-
- bts->si_common.cell_ro_sel_par.present = 1;
- bts->si_common.cell_ro_sel_par.cell_resel_off = atoi(argv[0])/2;
-
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_bts_temp_ofs, cfg_bts_temp_ofs_cmd,
- "temporary offset <0-60>",
- "Cell selection temporary negative offset in dB")
-{
- struct gsm_bts *bts = vty->index;
-
- bts->si_common.cell_ro_sel_par.present = 1;
- bts->si_common.cell_ro_sel_par.temp_offs = atoi(argv[0])/10;
-
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_bts_temp_ofs_inf, cfg_bts_temp_ofs_inf_cmd,
- "temporary offset infinite",
- "Sets cell selection temporary negative offset to infinity")
-{
- struct gsm_bts *bts = vty->index;
-
- bts->si_common.cell_ro_sel_par.present = 1;
- bts->si_common.cell_ro_sel_par.temp_offs = 7;
-
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_bts_penalty_time, cfg_bts_penalty_time_cmd,
- "penalty time <20-620>",
- "Cell selection penalty time in seconds (by 20s increments)")
-{
- struct gsm_bts *bts = vty->index;
-
- bts->si_common.cell_ro_sel_par.present = 1;
- bts->si_common.cell_ro_sel_par.penalty_time = (atoi(argv[0])-20)/20;
-
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_bts_penalty_time_rsvd, cfg_bts_penalty_time_rsvd_cmd,
- "penalty time reserved",
- "Set cell selection penalty time to reserved value 31\n"
- "(indicate that CELL_RESELECT_OFFSET is subtracted from C2 "
- "and TEMPORARY_OFFSET is ignored)")
-{
- struct gsm_bts *bts = vty->index;
-
- bts->si_common.cell_ro_sel_par.present = 1;
- bts->si_common.cell_ro_sel_par.penalty_time = 31;
-
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_bts_per_loc_upd, cfg_bts_per_loc_upd_cmd,
- "periodic location update <0-1530>",
- "Periodic Location Updating Interval in Minutes")
-{
- struct gsm_bts *bts = vty->index;
-
- bts->si_common.chan_desc.t3212 = atoi(argv[0]) / 6;
-
- return CMD_SUCCESS;
-}
-
-#define GPRS_TEXT "GPRS Packet Network\n"
-
-DEFUN(cfg_bts_prs_bvci, cfg_bts_gprs_bvci_cmd,
- "gprs cell bvci <2-65535>",
- GPRS_TEXT
- "GPRS Cell Settings\n"
- "GPRS BSSGP VC Identifier")
-{
- struct gsm_bts *bts = vty->index;
-
- if (bts->gprs.mode == BTS_GPRS_NONE) {
- vty_out(vty, "%% GPRS not enabled on this BTS%s", VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- bts->gprs.cell.bvci = atoi(argv[0]);
-
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_bts_gprs_nsei, cfg_bts_gprs_nsei_cmd,
- "gprs nsei <0-65535>",
- GPRS_TEXT
- "GPRS NS Entity Identifier")
-{
- struct gsm_bts *bts = vty->index;
-
- if (bts->gprs.mode == BTS_GPRS_NONE) {
- vty_out(vty, "%% GPRS not enabled on this BTS%s", VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- bts->gprs.nse.nsei = atoi(argv[0]);
-
- return CMD_SUCCESS;
-}
-
-#define NSVC_TEXT "Network Service Virtual Connection (NS-VC)\n" \
- "NSVC Logical Number\n"
-
-DEFUN(cfg_bts_gprs_nsvci, cfg_bts_gprs_nsvci_cmd,
- "gprs nsvc <0-1> nsvci <0-65535>",
- GPRS_TEXT NSVC_TEXT
- "NS Virtual Connection Identifier\n"
- "GPRS NS VC Identifier")
-{
- struct gsm_bts *bts = vty->index;
- int idx = atoi(argv[0]);
-
- if (bts->gprs.mode == BTS_GPRS_NONE) {
- vty_out(vty, "%% GPRS not enabled on this BTS%s", VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- bts->gprs.nsvc[idx].nsvci = atoi(argv[1]);
-
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_bts_gprs_nsvc_lport, cfg_bts_gprs_nsvc_lport_cmd,
- "gprs nsvc <0-1> local udp port <0-65535>",
- GPRS_TEXT NSVC_TEXT
- "GPRS NS Local UDP Port")
-{
- struct gsm_bts *bts = vty->index;
- int idx = atoi(argv[0]);
-
- if (bts->gprs.mode == BTS_GPRS_NONE) {
- vty_out(vty, "%% GPRS not enabled on this BTS%s", VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- bts->gprs.nsvc[idx].local_port = atoi(argv[1]);
-
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_bts_gprs_nsvc_rport, cfg_bts_gprs_nsvc_rport_cmd,
- "gprs nsvc <0-1> remote udp port <0-65535>",
- GPRS_TEXT NSVC_TEXT
- "GPRS NS Remote UDP Port")
-{
- struct gsm_bts *bts = vty->index;
- int idx = atoi(argv[0]);
-
- if (bts->gprs.mode == BTS_GPRS_NONE) {
- vty_out(vty, "%% GPRS not enabled on this BTS%s", VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- bts->gprs.nsvc[idx].remote_port = atoi(argv[1]);
-
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_bts_gprs_nsvc_rip, cfg_bts_gprs_nsvc_rip_cmd,
- "gprs nsvc <0-1> remote ip A.B.C.D",
- GPRS_TEXT NSVC_TEXT
- "GPRS NS Remote IP Address")
-{
- struct gsm_bts *bts = vty->index;
- int idx = atoi(argv[0]);
- struct in_addr ia;
-
- if (bts->gprs.mode == BTS_GPRS_NONE) {
- vty_out(vty, "%% GPRS not enabled on this BTS%s", VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- inet_aton(argv[1], &ia);
- bts->gprs.nsvc[idx].remote_ip = ntohl(ia.s_addr);
-
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_bts_pag_free, cfg_bts_pag_free_cmd,
- "paging free FREE_NR",
- "Only page when having a certain amount of free slots. -1 to disable")
-{
- struct gsm_bts *bts = vty->index;
-
- bts->paging.free_chans_need = atoi(argv[0]);
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_bts_gprs_ns_timer, cfg_bts_gprs_ns_timer_cmd,
- "gprs ns timer " NS_TIMERS " <0-255>",
- GPRS_TEXT "Network Service\n"
- "Network Service Timer\n"
- NS_TIMERS_HELP "Timer Value\n")
-{
- struct gsm_bts *bts = vty->index;
- int idx = get_string_value(gprs_ns_timer_strs, argv[0]);
- int val = atoi(argv[1]);
-
- if (bts->gprs.mode == BTS_GPRS_NONE) {
- vty_out(vty, "%% GPRS not enabled on this BTS%s", VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- if (idx < 0 || idx >= ARRAY_SIZE(bts->gprs.nse.timer))
- return CMD_WARNING;
-
- bts->gprs.nse.timer[idx] = val;
-
- return CMD_SUCCESS;
-}
-
-#define BSSGP_TIMERS "(blocking-timer|blocking-retries|unblocking-retries|reset-timer|reset-retries|suspend-timer|suspend-retries|resume-timer|resume-retries|capability-update-timer|capability-update-retries)"
-#define BSSGP_TIMERS_HELP \
- "Tbvc-block timeout\n" \
- "Tbvc-block retries\n" \
- "Tbvc-unblock retries\n" \
- "Tbvcc-reset timeout\n" \
- "Tbvc-reset retries\n" \
- "Tbvc-suspend timeout\n" \
- "Tbvc-suspend retries\n" \
- "Tbvc-resume timeout\n" \
- "Tbvc-resume retries\n" \
- "Tbvc-capa-update timeout\n" \
- "Tbvc-capa-update retries\n"
-
-DEFUN(cfg_bts_gprs_cell_timer, cfg_bts_gprs_cell_timer_cmd,
- "gprs cell timer " BSSGP_TIMERS " <0-255>",
- GPRS_TEXT "Cell / BSSGP\n"
- "Cell/BSSGP Timer\n"
- BSSGP_TIMERS_HELP "Timer Value\n")
-{
- struct gsm_bts *bts = vty->index;
- int idx = get_string_value(gprs_bssgp_cfg_strs, argv[0]);
- int val = atoi(argv[1]);
-
- if (bts->gprs.mode == BTS_GPRS_NONE) {
- vty_out(vty, "%% GPRS not enabled on this BTS%s", VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- if (idx < 0 || idx >= ARRAY_SIZE(bts->gprs.cell.timer))
- return CMD_WARNING;
-
- bts->gprs.cell.timer[idx] = val;
-
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_bts_gprs_rac, cfg_bts_gprs_rac_cmd,
- "gprs routing area <0-255>",
- GPRS_TEXT
- "GPRS Routing Area Code")
-{
- struct gsm_bts *bts = vty->index;
-
- if (bts->gprs.mode == BTS_GPRS_NONE) {
- vty_out(vty, "%% GPRS not enabled on this BTS%s", VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- bts->gprs.rac = atoi(argv[0]);
-
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_bts_gprs_mode, cfg_bts_gprs_mode_cmd,
- "gprs mode (none|gprs|egprs)",
- GPRS_TEXT
- "GPRS Mode for this BTS\n"
- "GPRS Disabled on this BTS\n"
- "GPRS Enabled on this BTS\n"
- "EGPRS (EDGE) Enabled on this BTS\n")
-{
- struct gsm_bts *bts = vty->index;
- enum bts_gprs_mode mode = bts_gprs_mode_parse(argv[0]);
-
- if (mode != BTS_GPRS_NONE &&
- !gsm_bts_has_feature(bts, BTS_FEAT_GPRS)) {
- vty_out(vty, "This BTS type does not support %s%s", argv[0],
- VTY_NEWLINE);
- return CMD_WARNING;
- }
- if (mode == BTS_GPRS_EGPRS &&
- !gsm_bts_has_feature(bts, BTS_FEAT_EGPRS)) {
- vty_out(vty, "This BTS type does not support %s%s", argv[0],
- VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- bts->gprs.mode = mode;
-
- return CMD_SUCCESS;
-}
-
-#define SI_TEXT "System Information Messages\n"
-#define SI_TYPE_TEXT "(1|2|3|4|5|6|7|8|9|10|13|16|17|18|19|20|2bis|2ter|2quater|5bis|5ter)"
-#define SI_TYPE_HELP "System Information Type 1\n" \
- "System Information Type 2\n" \
- "System Information Type 3\n" \
- "System Information Type 4\n" \
- "System Information Type 5\n" \
- "System Information Type 6\n" \
- "System Information Type 7\n" \
- "System Information Type 8\n" \
- "System Information Type 9\n" \
- "System Information Type 10\n" \
- "System Information Type 13\n" \
- "System Information Type 16\n" \
- "System Information Type 17\n" \
- "System Information Type 18\n" \
- "System Information Type 19\n" \
- "System Information Type 20\n" \
- "System Information Type 2bis\n" \
- "System Information Type 2ter\n" \
- "System Information Type 2quater\n" \
- "System Information Type 5bis\n" \
- "System Information Type 5ter\n"
-
-DEFUN(cfg_bts_si_mode, cfg_bts_si_mode_cmd,
- "system-information " SI_TYPE_TEXT " mode (static|computed)",
- SI_TEXT SI_TYPE_HELP
- "System Information Mode\n"
- "Static user-specified\n"
- "Dynamic, BSC-computed\n")
-{
- struct gsm_bts *bts = vty->index;
- int type;
-
- type = get_string_value(osmo_sitype_strs, argv[0]);
- if (type < 0) {
- vty_out(vty, "Error SI Type%s", VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- if (!strcmp(argv[1], "static"))
- bts->si_mode_static |= (1 << type);
- else
- bts->si_mode_static &= ~(1 << type);
-
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_bts_si_static, cfg_bts_si_static_cmd,
- "system-information " SI_TYPE_TEXT " static HEXSTRING",
- SI_TEXT SI_TYPE_HELP
- "Static System Information filling\n"
- "Static user-specified SI content in HEX notation\n")
-{
- struct gsm_bts *bts = vty->index;
- int rc, type;
-
- type = get_string_value(osmo_sitype_strs, argv[0]);
- if (type < 0) {
- vty_out(vty, "Error SI Type%s", VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- if (!(bts->si_mode_static & (1 << type))) {
- vty_out(vty, "SI Type %s is not configured in static mode%s",
- get_value_string(osmo_sitype_strs, type), VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- /* Fill buffer with padding pattern */
- memset(bts->si_buf[type], 0x2b, sizeof(bts->si_buf[type]));
-
- /* Parse the user-specified SI in hex format, [partially] overwriting padding */
- rc = hexparse(argv[1], bts->si_buf[type], sizeof(bts->si_buf[0]));
- if (rc < 0 || rc > sizeof(bts->si_buf[0])) {
- vty_out(vty, "Error parsing HEXSTRING%s", VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- /* Mark this SI as present */
- bts->si_valid |= (1 << type);
-
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_bts_neigh_mode, cfg_bts_neigh_mode_cmd,
- "neighbor-list mode (automatic|manual|manual-si5)",
- "Neighbor List\n" "Mode of Neighbor List generation\n"
- "Automatically from all BTS in this OpenBSC\n" "Manual\n"
- "Manual with different lists for SI2 and SI5\n")
-{
- struct gsm_bts *bts = vty->index;
- int mode = get_string_value(bts_neigh_mode_strs, argv[0]);
-
- switch (mode) {
- case NL_MODE_MANUAL_SI5SEP:
- case NL_MODE_MANUAL:
- /* make sure we clear the current list when switching to
- * manual mode */
- if (bts->neigh_list_manual_mode == 0)
- memset(&bts->si_common.data.neigh_list, 0,
- sizeof(bts->si_common.data.neigh_list));
- break;
- default:
- break;
- }
-
- bts->neigh_list_manual_mode = mode;
-
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_bts_neigh, cfg_bts_neigh_cmd,
- "neighbor-list (add|del) arfcn <0-1024>",
- "Neighbor List\n" "Add to manual neighbor list\n"
- "Delete from manual neighbor list\n" "ARFCN of neighbor\n"
- "ARFCN of neighbor\n")
-{
- struct gsm_bts *bts = vty->index;
- struct bitvec *bv = &bts->si_common.neigh_list;
- uint16_t arfcn = atoi(argv[1]);
-
- if (!bts->neigh_list_manual_mode) {
- vty_out(vty, "%% Cannot configure neighbor list in "
- "automatic mode%s", VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- if (!strcmp(argv[0], "add"))
- bitvec_set_bit_pos(bv, arfcn, 1);
- else
- bitvec_set_bit_pos(bv, arfcn, 0);
-
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_bts_si5_neigh, cfg_bts_si5_neigh_cmd,
- "si5 neighbor-list (add|del) arfcn <0-1024>",
- "SI5 Neighbor List\n" "Add to manual SI5 neighbor list\n"
- "Delete from SI5 manual neighbor list\n" "ARFCN of neighbor\n"
- "ARFCN of neighbor\n")
-{
- struct gsm_bts *bts = vty->index;
- struct bitvec *bv = &bts->si_common.si5_neigh_list;
- uint16_t arfcn = atoi(argv[1]);
-
- if (!bts->neigh_list_manual_mode) {
- vty_out(vty, "%% Cannot configure neighbor list in "
- "automatic mode%s", VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- if (!strcmp(argv[0], "add"))
- bitvec_set_bit_pos(bv, arfcn, 1);
- else
- bitvec_set_bit_pos(bv, arfcn, 0);
-
- return CMD_SUCCESS;
-}
-
-#define TRX_TEXT "Radio Transceiver\n"
-
-/* per TRX configuration */
-DEFUN(cfg_trx,
- cfg_trx_cmd,
- "trx TRX_NR",
- TRX_TEXT
- "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->num_trx) {
- vty_out(vty, "%% The next unused TRX number in this BTS is %u%s",
- bts->num_trx, VTY_NEWLINE);
- return CMD_WARNING;
- } else if (trx_nr == bts->num_trx) {
- /* we need to allocate a new one */
- trx = gsm_bts_trx_alloc(bts);
- } else
- trx = gsm_bts_trx_num(bts, trx_nr);
-
- if (!trx)
- return CMD_WARNING;
-
- vty->index = trx;
- vty->index_sub = &trx->description;
- vty->node = TRX_NODE;
-
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_trx_arfcn,
- cfg_trx_arfcn_cmd,
- "arfcn <0-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;
-}
-
-DEFUN(cfg_trx_nominal_power,
- cfg_trx_nominal_power_cmd,
- "nominal power <0-100>",
- "Nominal TRX RF Power in dB\n")
-{
- struct gsm_bts_trx *trx = vty->index;
-
- trx->nominal_power = atoi(argv[0]);
-
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_trx_max_power_red,
- cfg_trx_max_power_red_cmd,
- "max_power_red <0-100>",
- "Reduction of maximum BS RF Power in dB\n")
-{
- int maxpwr_r = atoi(argv[0]);
- struct gsm_bts_trx *trx = vty->index;
- int upper_limit = 24; /* default 12.21 max power red. */
-
- /* FIXME: check if our BTS type supports more than 12 */
- if (maxpwr_r < 0 || maxpwr_r > upper_limit) {
- vty_out(vty, "%% Power %d dB is not in the valid range%s",
- maxpwr_r, VTY_NEWLINE);
- return CMD_WARNING;
- }
- if (maxpwr_r & 1) {
- vty_out(vty, "%% Power %d dB is not an even value%s",
- maxpwr_r, VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- trx->max_power_red = maxpwr_r;
-
- /* FIXME: make sure we update this using OML */
-
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_trx_rsl_e1,
- cfg_trx_rsl_e1_cmd,
- "rsl e1 line E1_LINE timeslot <1-31> sub-slot (0|1|2|3|full)",
- "E1 interface to be used for RSL\n")
-{
- struct gsm_bts_trx *trx = vty->index;
-
- parse_e1_link(&trx->rsl_e1_link, argv[0], argv[1], argv[2]);
-
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_trx_rsl_e1_tei,
- cfg_trx_rsl_e1_tei_cmd,
- "rsl e1 tei <0-63>",
- "Set the TEI to be used for RSL")
-{
- struct gsm_bts_trx *trx = vty->index;
-
- trx->rsl_tei = atoi(argv[0]);
-
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_trx_rf_locked,
- cfg_trx_rf_locked_cmd,
- "rf_locked (0|1)",
- "Turn off RF of the TRX.\n")
-{
- int locked = atoi(argv[0]);
- struct gsm_bts_trx *trx = vty->index;
-
- gsm_trx_lock_rf(trx, locked);
- return CMD_SUCCESS;
-}
-
-/* per TS configuration */
-DEFUN(cfg_ts,
- cfg_ts_cmd,
- "timeslot <0-7>",
- "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;
-}
-
-DEFUN(cfg_ts_pchan,
- cfg_ts_pchan_cmd,
- "phys_chan_config PCHAN",
- "Physical Channel configuration (TCH/SDCCH/...)")
-{
- struct gsm_bts_trx_ts *ts = vty->index;
- int pchanc;
-
- pchanc = gsm_pchan_parse(argv[0]);
- if (pchanc < 0)
- return CMD_WARNING;
-
- ts->pchan = pchanc;
-
- return CMD_SUCCESS;
-}
-
-#define HOPPING_STR "Configure frequency hopping\n"
-
-DEFUN(cfg_ts_hopping,
- cfg_ts_hopping_cmd,
- "hopping enabled (0|1)",
- HOPPING_STR "Enable or disable frequency hopping\n"
- "Disable frequency hopping\n" "Enable frequency hopping\n")
-{
- struct gsm_bts_trx_ts *ts = vty->index;
- int enabled = atoi(argv[0]);
-
- if (enabled && !gsm_bts_has_feature(ts->trx->bts, BTS_FEAT_HOPPING)) {
- vty_out(vty, "BTS model does not support hopping%s",
- VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- ts->hopping.enabled = enabled;
-
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_ts_hsn,
- cfg_ts_hsn_cmd,
- "hopping sequence-number <0-63>",
- HOPPING_STR
- "Which hopping sequence to use for this channel")
-{
- struct gsm_bts_trx_ts *ts = vty->index;
-
- ts->hopping.hsn = atoi(argv[0]);
-
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_ts_maio,
- cfg_ts_maio_cmd,
- "hopping maio <0-63>",
- HOPPING_STR
- "Which hopping MAIO to use for this channel")
-{
- struct gsm_bts_trx_ts *ts = vty->index;
-
- ts->hopping.maio = atoi(argv[0]);
-
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_ts_arfcn_add,
- cfg_ts_arfcn_add_cmd,
- "hopping arfcn add <0-1023>",
- HOPPING_STR "Configure hopping ARFCN list\n"
- "Add an entry to the hopping ARFCN list\n" "ARFCN\n")
-{
- struct gsm_bts_trx_ts *ts = vty->index;
- int arfcn = atoi(argv[0]);
-
- bitvec_set_bit_pos(&ts->hopping.arfcns, arfcn, 1);
-
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_ts_arfcn_del,
- cfg_ts_arfcn_del_cmd,
- "hopping arfcn del <0-1023>",
- HOPPING_STR "Configure hopping ARFCN list\n"
- "Delete an entry to the hopping ARFCN list\n" "ARFCN\n")
-{
- struct gsm_bts_trx_ts *ts = vty->index;
- int arfcn = atoi(argv[0]);
-
- bitvec_set_bit_pos(&ts->hopping.arfcns, arfcn, 0);
-
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_ts_e1_subslot,
- cfg_ts_e1_subslot_cmd,
- "e1 line E1_LINE timeslot <1-31> sub-slot (0|1|2|3|full)",
- "E1 sub-slot connected to this on-air timeslot")
-{
- struct gsm_bts_trx_ts *ts = vty->index;
-
- parse_e1_link(&ts->e1_link, argv[0], argv[1], argv[2]);
-
- return CMD_SUCCESS;
-}
-
-void openbsc_vty_print_statistics(struct vty *vty, struct gsm_network *net)
-{
- vty_out(vty, "Channel Requests : %lu total, %lu no channel%s",
- counter_get(net->stats.chreq.total),
- counter_get(net->stats.chreq.no_channel), VTY_NEWLINE);
- vty_out(vty, "Channel Failures : %lu rf_failures, %lu rll failures%s",
- counter_get(net->stats.chan.rf_fail),
- counter_get(net->stats.chan.rll_err), VTY_NEWLINE);
- vty_out(vty, "Paging : %lu attempted, %lu complete, %lu expired%s",
- counter_get(net->stats.paging.attempted),
- counter_get(net->stats.paging.completed),
- counter_get(net->stats.paging.expired), VTY_NEWLINE);
- vty_out(vty, "BTS failures : %lu OML, %lu RSL%s",
- counter_get(net->stats.bts.oml_fail),
- counter_get(net->stats.bts.rsl_fail), VTY_NEWLINE);
-}
-
-DEFUN(logging_fltr_imsi,
- logging_fltr_imsi_cmd,
- "logging filter imsi IMSI",
- LOGGING_STR FILTER_STR
- "Filter log messages by IMSI\n" "IMSI to be used as filter\n")
-{
- struct log_target *tgt = osmo_log_vty2tgt(vty);
-
- if (!tgt)
- return CMD_WARNING;
-
- log_set_imsi_filter(tgt, argv[0]);
- return CMD_SUCCESS;
-}
-
-
-DEFUN(drop_bts,
- drop_bts_cmd,
- "drop bts connection <0-65535> (oml|rsl)",
- "Debug/Simulation command to drop ipaccess BTS\n"
- "BTS NR\n" "Connection Type\n")
-{
- struct gsm_network *gsmnet;
- struct gsm_bts_trx *trx;
- struct gsm_bts *bts;
- unsigned int bts_nr;
-
- gsmnet = gsmnet_from_vty(vty);
-
- bts_nr = atoi(argv[0]);
- if (bts_nr >= gsmnet->num_bts) {
- vty_out(vty, "BTS number must be between 0 and %d. It was %d.%s",
- gsmnet->num_bts, bts_nr, VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- bts = gsm_bts_num(gsmnet, bts_nr);
- if (!bts) {
- vty_out(vty, "BTS Nr. %d could not be found.%s", bts_nr, VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- if (!is_ipaccess_bts(bts)) {
- vty_out(vty, "This command only works for ipaccess.%s", VTY_NEWLINE);
- return CMD_WARNING;
- }
-
-
- /* close all connections */
- if (strcmp(argv[1], "oml") == 0) {
- ipaccess_drop_oml(bts);
- } else if (strcmp(argv[1], "rsl") == 0) {
- /* close all rsl connections */
- llist_for_each_entry(trx, &bts->trx_list, list) {
- ipaccess_drop_rsl(trx);
- }
- } else {
- vty_out(vty, "Argument must be 'oml# or 'rsl'.%s", VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- return CMD_SUCCESS;
-}
-
-DEFUN(pdch_act, pdch_act_cmd,
- "bts <0-255> trx <0-255> timeslot <0-7> pdch (activate|deactivate)",
- "BTS related commands\n" "BTS Number\n" "Transceiver\n" "Transceiver Number\n"
- "TRX Timeslot\n" "Timeslot Number\n" "Packet Data Channel\n"
- "Activate Dynamic PDCH/TCH (-> PDCH mode)\n"
- "Deactivate Dynamic PDCH/TCH (-> TCH mode)\n")
-{
- struct gsm_bts *bts;
- struct gsm_bts_trx *trx;
- struct gsm_bts_trx_ts *ts;
- int bts_nr = atoi(argv[0]);
- int trx_nr = atoi(argv[1]);
- int ts_nr = atoi(argv[2]);
- int activate;
-
- bts = gsm_bts_num(bsc_gsmnet, bts_nr);
- if (!bts) {
- vty_out(vty, "%% No such BTS (%d)%s", bts_nr, VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- if (!is_ipaccess_bts(bts)) {
- vty_out(vty, "%% This command only works for ipaccess BTS%s",
- VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- trx = gsm_bts_trx_num(bts, trx_nr);
- if (!trx) {
- vty_out(vty, "%% No such TRX (%d)%s", trx_nr, VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- ts = &trx->ts[ts_nr];
- if (ts->pchan != GSM_PCHAN_TCH_F_PDCH) {
- vty_out(vty, "%% Timeslot %u is not in dynamic TCH_F/PDCH "
- "mode%s", ts_nr, VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- if (!strcmp(argv[3], "activate"))
- activate = 1;
- else
- activate = 0;
-
- rsl_ipacc_pdch_activate(ts, activate);
-
- return CMD_SUCCESS;
-
-}
-
-extern int bsc_vty_init_extra(void);
-extern const char *openbsc_copyright;
-
-int bsc_vty_init(void)
-{
- install_element_ve(&show_net_cmd);
- install_element_ve(&show_bts_cmd);
- install_element_ve(&show_trx_cmd);
- install_element_ve(&show_ts_cmd);
- install_element_ve(&show_lchan_cmd);
- install_element_ve(&show_lchan_summary_cmd);
- install_element_ve(&logging_fltr_imsi_cmd);
-
- install_element_ve(&show_e1drv_cmd);
- install_element_ve(&show_e1line_cmd);
- install_element_ve(&show_e1ts_cmd);
-
- install_element_ve(&show_paging_cmd);
-
- logging_vty_add_cmds();
- install_element(CFG_LOG_NODE, &logging_fltr_imsi_cmd);
-
- install_element(CONFIG_NODE, &cfg_net_cmd);
- install_node(&net_node, config_write_net);
- install_default(GSMNET_NODE);
- install_element(GSMNET_NODE, &ournode_exit_cmd);
- install_element(GSMNET_NODE, &ournode_end_cmd);
- install_element(GSMNET_NODE, &cfg_net_ncc_cmd);
- install_element(GSMNET_NODE, &cfg_net_mnc_cmd);
- install_element(GSMNET_NODE, &cfg_net_name_short_cmd);
- install_element(GSMNET_NODE, &cfg_net_name_long_cmd);
- install_element(GSMNET_NODE, &cfg_net_auth_policy_cmd);
- install_element(GSMNET_NODE, &cfg_net_reject_cause_cmd);
- install_element(GSMNET_NODE, &cfg_net_encryption_cmd);
- install_element(GSMNET_NODE, &cfg_net_neci_cmd);
- install_element(GSMNET_NODE, &cfg_net_rrlp_mode_cmd);
- install_element(GSMNET_NODE, &cfg_net_mm_info_cmd);
- install_element(GSMNET_NODE, &cfg_net_handover_cmd);
- install_element(GSMNET_NODE, &cfg_net_ho_win_rxlev_avg_cmd);
- install_element(GSMNET_NODE, &cfg_net_ho_win_rxqual_avg_cmd);
- install_element(GSMNET_NODE, &cfg_net_ho_win_rxlev_avg_neigh_cmd);
- install_element(GSMNET_NODE, &cfg_net_ho_pwr_interval_cmd);
- install_element(GSMNET_NODE, &cfg_net_ho_pwr_hysteresis_cmd);
- install_element(GSMNET_NODE, &cfg_net_ho_max_distance_cmd);
- install_element(GSMNET_NODE, &cfg_net_T3101_cmd);
- install_element(GSMNET_NODE, &cfg_net_T3103_cmd);
- install_element(GSMNET_NODE, &cfg_net_T3105_cmd);
- install_element(GSMNET_NODE, &cfg_net_T3107_cmd);
- install_element(GSMNET_NODE, &cfg_net_T3109_cmd);
- install_element(GSMNET_NODE, &cfg_net_T3111_cmd);
- install_element(GSMNET_NODE, &cfg_net_T3113_cmd);
- install_element(GSMNET_NODE, &cfg_net_T3115_cmd);
- install_element(GSMNET_NODE, &cfg_net_T3117_cmd);
- install_element(GSMNET_NODE, &cfg_net_T3119_cmd);
- install_element(GSMNET_NODE, &cfg_net_T3122_cmd);
- install_element(GSMNET_NODE, &cfg_net_T3141_cmd);
- install_element(GSMNET_NODE, &cfg_net_dtx_cmd);
- install_element(GSMNET_NODE, &cfg_net_subscr_keep_cmd);
- install_element(GSMNET_NODE, &cfg_net_pag_any_tch_cmd);
-
- install_element(GSMNET_NODE, &cfg_bts_cmd);
- install_node(&bts_node, config_write_bts);
- install_default(BTS_NODE);
- install_element(BTS_NODE, &ournode_exit_cmd);
- install_element(BTS_NODE, &ournode_end_cmd);
- install_element(BTS_NODE, &cfg_bts_type_cmd);
- install_element(BTS_NODE, &cfg_description_cmd);
- install_element(BTS_NODE, &cfg_no_description_cmd);
- install_element(BTS_NODE, &cfg_bts_band_cmd);
- install_element(BTS_NODE, &cfg_bts_ci_cmd);
- install_element(BTS_NODE, &cfg_bts_lac_cmd);
- install_element(BTS_NODE, &cfg_bts_tsc_cmd);
- install_element(BTS_NODE, &cfg_bts_bsic_cmd);
- install_element(BTS_NODE, &cfg_bts_unit_id_cmd);
- install_element(BTS_NODE, &cfg_bts_stream_id_cmd);
- install_element(BTS_NODE, &cfg_bts_oml_e1_cmd);
- install_element(BTS_NODE, &cfg_bts_oml_e1_tei_cmd);
- install_element(BTS_NODE, &cfg_bts_challoc_cmd);
- install_element(BTS_NODE, &cfg_bts_rach_tx_integer_cmd);
- install_element(BTS_NODE, &cfg_bts_rach_max_trans_cmd);
- install_element(BTS_NODE, &cfg_bts_rach_nm_b_thresh_cmd);
- install_element(BTS_NODE, &cfg_bts_rach_nm_ldavg_cmd);
- install_element(BTS_NODE, &cfg_bts_cell_barred_cmd);
- install_element(BTS_NODE, &cfg_bts_rach_ec_allowed_cmd);
- install_element(BTS_NODE, &cfg_bts_ms_max_power_cmd);
- install_element(BTS_NODE, &cfg_bts_per_loc_upd_cmd);
- install_element(BTS_NODE, &cfg_bts_cell_resel_hyst_cmd);
- install_element(BTS_NODE, &cfg_bts_rxlev_acc_min_cmd);
- install_element(BTS_NODE, &cfg_bts_cell_bar_qualify_cmd);
- install_element(BTS_NODE, &cfg_bts_cell_resel_ofs_cmd);
- install_element(BTS_NODE, &cfg_bts_temp_ofs_cmd);
- install_element(BTS_NODE, &cfg_bts_temp_ofs_inf_cmd);
- install_element(BTS_NODE, &cfg_bts_penalty_time_cmd);
- install_element(BTS_NODE, &cfg_bts_penalty_time_rsvd_cmd);
- install_element(BTS_NODE, &cfg_bts_gprs_mode_cmd);
- install_element(BTS_NODE, &cfg_bts_gprs_ns_timer_cmd);
- install_element(BTS_NODE, &cfg_bts_gprs_rac_cmd);
- install_element(BTS_NODE, &cfg_bts_gprs_bvci_cmd);
- install_element(BTS_NODE, &cfg_bts_gprs_cell_timer_cmd);
- install_element(BTS_NODE, &cfg_bts_gprs_nsei_cmd);
- install_element(BTS_NODE, &cfg_bts_gprs_nsvci_cmd);
- install_element(BTS_NODE, &cfg_bts_gprs_nsvc_lport_cmd);
- install_element(BTS_NODE, &cfg_bts_gprs_nsvc_rport_cmd);
- install_element(BTS_NODE, &cfg_bts_gprs_nsvc_rip_cmd);
- install_element(BTS_NODE, &cfg_bts_pag_free_cmd);
- install_element(BTS_NODE, &cfg_bts_si_mode_cmd);
- install_element(BTS_NODE, &cfg_bts_si_static_cmd);
- install_element(BTS_NODE, &cfg_bts_neigh_mode_cmd);
- install_element(BTS_NODE, &cfg_bts_neigh_cmd);
- install_element(BTS_NODE, &cfg_bts_si5_neigh_cmd);
-
- install_element(BTS_NODE, &cfg_trx_cmd);
- install_node(&trx_node, dummy_config_write);
- install_default(TRX_NODE);
- install_element(TRX_NODE, &ournode_exit_cmd);
- install_element(TRX_NODE, &ournode_end_cmd);
- install_element(TRX_NODE, &cfg_trx_arfcn_cmd);
- install_element(TRX_NODE, &cfg_description_cmd);
- install_element(TRX_NODE, &cfg_no_description_cmd);
- install_element(TRX_NODE, &cfg_trx_nominal_power_cmd);
- install_element(TRX_NODE, &cfg_trx_max_power_red_cmd);
- install_element(TRX_NODE, &cfg_trx_rsl_e1_cmd);
- install_element(TRX_NODE, &cfg_trx_rsl_e1_tei_cmd);
- install_element(TRX_NODE, &cfg_trx_rf_locked_cmd);
-
- install_element(TRX_NODE, &cfg_ts_cmd);
- install_node(&ts_node, dummy_config_write);
- install_default(TS_NODE);
- install_element(TS_NODE, &ournode_exit_cmd);
- install_element(TS_NODE, &ournode_end_cmd);
- install_element(TS_NODE, &cfg_ts_pchan_cmd);
- install_element(TS_NODE, &cfg_ts_hopping_cmd);
- install_element(TS_NODE, &cfg_ts_hsn_cmd);
- install_element(TS_NODE, &cfg_ts_maio_cmd);
- install_element(TS_NODE, &cfg_ts_arfcn_add_cmd);
- install_element(TS_NODE, &cfg_ts_arfcn_del_cmd);
- install_element(TS_NODE, &cfg_ts_e1_subslot_cmd);
-
- install_element(ENABLE_NODE, &drop_bts_cmd);
- install_element(ENABLE_NODE, &pdch_act_cmd);
-
- abis_nm_vty_init();
- abis_om2k_vty_init();
- e1inp_vty_init();
-
- bsc_vty_init_extra();
-
- return 0;
-}
diff --git a/openbsc/src/bsc/bts_ericsson_rbs2000.c b/openbsc/src/bsc/bts_ericsson_rbs2000.c
deleted file mode 100644
index def42b544..000000000
--- a/openbsc/src/bsc/bts_ericsson_rbs2000.c
+++ /dev/null
@@ -1,164 +0,0 @@
-/* Ericsson RBS-2xxx specific code */
-
-/* (C) 2011 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 Affero General Public License as published by
- * the Free Software Foundation; either version 3 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 Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-#include <sys/types.h>
-
-#include <osmocore/tlv.h>
-
-#include <openbsc/debug.h>
-#include <openbsc/gsm_data.h>
-#include <openbsc/abis_om2000.h>
-#include <openbsc/e1_input.h>
-#include <openbsc/signal.h>
-
-#include "../abis/input/lapd.h"
-
-static void bootstrap_om_bts(struct gsm_bts *bts)
-{
- LOGP(DNM, LOGL_NOTICE, "bootstrapping OML for BTS %u\n", bts->nr);
- abis_om2k_tx_start_req(bts, &om2k_mo_cf);
- /* FIXME */
-}
-
-static void bootstrap_om_trx(struct gsm_bts_trx *trx)
-{
- LOGP(DNM, LOGL_NOTICE, "bootstrapping OML for TRX %u/%u\n",
- trx->bts->nr, trx->nr);
- /* FIXME */
-}
-
-static int shutdown_om(struct gsm_bts *bts)
-{
- /* FIXME */
- return 0;
-}
-
-
-/* Tell LAPD to start start the SAP (send SABM requests) for all signalling
- * timeslots in this line */
-static void start_sabm_in_line(struct e1inp_line *line, int start)
-{
- struct e1inp_sign_link *link;
- int i;
-
- for (i = 0; i < ARRAY_SIZE(line->ts); i++) {
- struct e1inp_ts *ts = &line->ts[i];
-
- if (ts->type != E1INP_TS_TYPE_SIGN)
- continue;
-
- llist_for_each_entry(link, &ts->sign.sign_links, list) {
- if (start)
- lapd_sap_start(ts->driver.dahdi.lapd, link->tei, link->sapi);
- else
- lapd_sap_stop(ts->driver.dahdi.lapd, link->tei, link->sapi);
- }
- }
-}
-
-/* Callback function to be called every time we receive a signal from INPUT */
-static int gbl_sig_cb(unsigned int subsys, unsigned int signal,
- void *handler_data, void *signal_data)
-{
- struct gsm_bts *bts;
-
- if (subsys != SS_GLOBAL)
- return 0;
-
- switch (signal) {
- case S_GLOBAL_BTS_CLOSE_OM:
- bts = signal_data;
- if (bts->type == GSM_BTS_TYPE_RBS2000)
- shutdown_om(signal_data);
- break;
- }
-
- return 0;
-}
-
-/* Callback function to be called every time we receive a signal from INPUT */
-static int inp_sig_cb(unsigned int subsys, unsigned int signal,
- void *handler_data, void *signal_data)
-{
- struct input_signal_data *isd = signal_data;
-
- if (subsys != SS_INPUT)
- return 0;
-
- switch (signal) {
- case S_INP_TEI_UP:
- switch (isd->link_type) {
- case E1INP_SIGN_OML:
- if (isd->trx->bts->type != GSM_BTS_TYPE_RBS2000)
- break;
- if (isd->tei == isd->trx->bts->oml_tei)
- bootstrap_om_bts(isd->trx->bts);
- else
- bootstrap_om_trx(isd->trx);
- break;
- }
- break;
- case S_INP_LINE_INIT:
- /* Right now Ericsson RBS are only supported on DAHDI */
- if (strcasecmp(isd->line->driver->name, "DAHDI"))
- break;
- start_sabm_in_line(isd->line, 1);
- break;
- case S_INP_LINE_ALARM:
- if (strcasecmp(isd->line->driver->name, "DAHDI"))
- break;
- start_sabm_in_line(isd->line, 0);
- break;
- case S_INP_LINE_NOALARM:
- if (strcasecmp(isd->line->driver->name, "DAHDI"))
- break;
- start_sabm_in_line(isd->line, 1);
- break;
- }
-
- return 0;
-}
-
-static void config_write_bts(struct vty *vty, struct gsm_bts *bts)
-{
- abis_om2k_config_write_bts(vty, bts);
-}
-
-static struct gsm_bts_model model_rbs2k = {
- .type = GSM_BTS_TYPE_RBS2000,
- .name = "rbs2000",
- .oml_rcvmsg = &abis_om2k_rcvmsg,
- .config_write_bts = &config_write_bts,
-};
-
-int bts_model_rbs2k_init(void)
-{
- model_rbs2k.features.data = &model_rbs2k._features_data[0];
- model_rbs2k.features.data_len = sizeof(model_rbs2k._features_data);
-
- gsm_btsmodel_set_feature(&model_rbs2k, BTS_FEAT_HOPPING);
- gsm_btsmodel_set_feature(&model_rbs2k, BTS_FEAT_HSCSD);
-
- register_signal_handler(SS_INPUT, inp_sig_cb, NULL);
- register_signal_handler(SS_GLOBAL, gbl_sig_cb, NULL);
-
- return gsm_bts_model_register(&model_rbs2k);
-}
diff --git a/openbsc/src/bsc/bts_ipaccess_nanobts.c b/openbsc/src/bsc/bts_ipaccess_nanobts.c
deleted file mode 100644
index 25dc0c8a2..000000000
--- a/openbsc/src/bsc/bts_ipaccess_nanobts.c
+++ /dev/null
@@ -1,447 +0,0 @@
-/* ip.access nanoBTS specific code */
-
-/* (C) 2009-2010 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 Affero General Public License as published by
- * the Free Software Foundation; either version 3 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 Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-#include <sys/types.h>
-#include <arpa/inet.h>
-
-#include <osmocore/tlv.h>
-
-#include <openbsc/gsm_data.h>
-#include <openbsc/signal.h>
-#include <openbsc/abis_nm.h>
-
-static struct gsm_bts_model model_nanobts = {
- .type = GSM_BTS_TYPE_NANOBTS,
- .name = "nanobts",
- .oml_rcvmsg = &abis_nm_rcvmsg,
- .nm_att_tlvdef = {
- .def = {
- /* ip.access specifics */
- [NM_ATT_IPACC_DST_IP] = { TLV_TYPE_FIXED, 4 },
- [NM_ATT_IPACC_DST_IP_PORT] = { TLV_TYPE_FIXED, 2 },
- [NM_ATT_IPACC_STREAM_ID] = { TLV_TYPE_TV, },
- [NM_ATT_IPACC_SEC_OML_CFG] = { TLV_TYPE_FIXED, 6 },
- [NM_ATT_IPACC_IP_IF_CFG] = { TLV_TYPE_FIXED, 8 },
- [NM_ATT_IPACC_IP_GW_CFG] = { TLV_TYPE_FIXED, 12 },
- [NM_ATT_IPACC_IN_SERV_TIME] = { TLV_TYPE_FIXED, 4 },
- [NM_ATT_IPACC_LOCATION] = { TLV_TYPE_TL16V },
- [NM_ATT_IPACC_PAGING_CFG] = { TLV_TYPE_FIXED, 2 },
- [NM_ATT_IPACC_UNIT_ID] = { TLV_TYPE_TL16V },
- [NM_ATT_IPACC_UNIT_NAME] = { TLV_TYPE_TL16V },
- [NM_ATT_IPACC_SNMP_CFG] = { TLV_TYPE_TL16V },
- [NM_ATT_IPACC_PRIM_OML_CFG_LIST] = { TLV_TYPE_TL16V },
- [NM_ATT_IPACC_NV_FLAGS] = { TLV_TYPE_TL16V },
- [NM_ATT_IPACC_FREQ_CTRL] = { TLV_TYPE_FIXED, 2 },
- [NM_ATT_IPACC_PRIM_OML_FB_TOUT] = { TLV_TYPE_TL16V },
- [NM_ATT_IPACC_CUR_SW_CFG] = { TLV_TYPE_TL16V },
- [NM_ATT_IPACC_TIMING_BUS] = { TLV_TYPE_TL16V },
- [NM_ATT_IPACC_CGI] = { TLV_TYPE_TL16V },
- [NM_ATT_IPACC_RAC] = { TLV_TYPE_TL16V },
- [NM_ATT_IPACC_OBJ_VERSION] = { TLV_TYPE_TL16V },
- [NM_ATT_IPACC_GPRS_PAGING_CFG]= { TLV_TYPE_TL16V },
- [NM_ATT_IPACC_NSEI] = { TLV_TYPE_TL16V },
- [NM_ATT_IPACC_BVCI] = { TLV_TYPE_TL16V },
- [NM_ATT_IPACC_NSVCI] = { TLV_TYPE_TL16V },
- [NM_ATT_IPACC_NS_CFG] = { TLV_TYPE_TL16V },
- [NM_ATT_IPACC_BSSGP_CFG] = { TLV_TYPE_TL16V },
- [NM_ATT_IPACC_NS_LINK_CFG] = { TLV_TYPE_TL16V },
- [NM_ATT_IPACC_RLC_CFG] = { TLV_TYPE_TL16V },
- [NM_ATT_IPACC_ALM_THRESH_LIST]= { TLV_TYPE_TL16V },
- [NM_ATT_IPACC_MONIT_VAL_LIST] = { TLV_TYPE_TL16V },
- [NM_ATT_IPACC_TIB_CONTROL] = { TLV_TYPE_TL16V },
- [NM_ATT_IPACC_SUPP_FEATURES] = { TLV_TYPE_TL16V },
- [NM_ATT_IPACC_CODING_SCHEMES] = { TLV_TYPE_TL16V },
- [NM_ATT_IPACC_RLC_CFG_2] = { TLV_TYPE_TL16V },
- [NM_ATT_IPACC_HEARTB_TOUT] = { TLV_TYPE_TL16V },
- [NM_ATT_IPACC_UPTIME] = { TLV_TYPE_TL16V },
- [NM_ATT_IPACC_RLC_CFG_3] = { TLV_TYPE_TL16V },
- [NM_ATT_IPACC_SSL_CFG] = { TLV_TYPE_TL16V },
- [NM_ATT_IPACC_SEC_POSSIBLE] = { TLV_TYPE_TL16V },
- [NM_ATT_IPACC_IML_SSL_STATE] = { TLV_TYPE_TL16V },
- [NM_ATT_IPACC_REVOC_DATE] = { TLV_TYPE_TL16V },
- },
- },
-};
-
-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,
- NM_ATT_IPACC_CGI, 0, 7, 0x00, 0xf1, 0x10, 0x00, 0x01, 0x00, 0x00,
-};
-
-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_nse[] = {
- NM_ATT_IPACC_NSEI, 0, 2, 0x03, 0x9d, /* NSEI 925 */
- NM_ATT_IPACC_NS_CFG, 0, 7, 3, /* (un)blocking timer (Tns-block) */
- 3, /* (un)blocking retries */
- 3, /* reset timer (Tns-reset) */
- 3, /* reset retries */
- 30, /* test timer (Tns-test) */
- 3, /* alive timer (Tns-alive) */
- 10, /* alive retrires */
- NM_ATT_IPACC_BSSGP_CFG, 0, 11,
- 3, /* blockimg timer (T1) */
- 3, /* blocking retries */
- 3, /* unblocking retries */
- 3, /* reset timer */
- 3, /* reset retries */
- 10, /* suspend timer (T3) in 100ms */
- 3, /* suspend retries */
- 10, /* resume timer (T4) in 100ms */
- 3, /* resume retries */
- 10, /* capability update timer (T5) */
- 3, /* capability update retries */
-};
-
-static unsigned char nanobts_attr_cell[] = {
- NM_ATT_IPACC_RAC, 0, 1, 1, /* routing area code */
- NM_ATT_IPACC_GPRS_PAGING_CFG, 0, 2,
- 5, /* repeat time (50ms) */
- 3, /* repeat count */
- NM_ATT_IPACC_BVCI, 0, 2, 0x03, 0x9d, /* BVCI 925 */
- NM_ATT_IPACC_RLC_CFG, 0, 9,
- 20, /* T3142 */
- 5, /* T3169 */
- 5, /* T3191 */
- 200, /* T3193 */
- 5, /* T3195 */
- 10, /* N3101 */
- 4, /* N3103 */
- 8, /* N3105 */
- 15, /* RLC CV countdown */
- NM_ATT_IPACC_CODING_SCHEMES, 0, 2, 0x0f, 0x00, /* CS1..CS4 */
- NM_ATT_IPACC_RLC_CFG_2, 0, 5,
- 0x00, 250, /* T downlink TBF extension (0..500) */
- 0x00, 250, /* T uplink TBF extension (0..500) */
- 2, /* CS2 */
-#if 0
- /* EDGE model only, breaks older models.
- * Should inquire the BTS capabilities */
- NM_ATT_IPACC_RLC_CFG_3, 0, 1,
- 2, /* MCS2 */
-#endif
-};
-
-static unsigned char nanobts_attr_nsvc0[] = {
- NM_ATT_IPACC_NSVCI, 0, 2, 0x03, 0x9d, /* 925 */
- NM_ATT_IPACC_NS_LINK_CFG, 0, 8,
- 0x59, 0xd8, /* remote udp port (23000) */
- 192, 168, 100, 11, /* remote ip address */
- 0x59, 0xd8, /* local udp port (23000) */
-};
-
-static void patch_16(uint8_t *data, const uint16_t val)
-{
- memcpy(data, &val, sizeof(val));
-}
-
-static void patch_32(uint8_t *data, const uint32_t val)
-{
- memcpy(data, &val, sizeof(val));
-}
-
-/*
- * Patch the various SYSTEM INFORMATION tables to update
- * the LAI
- */
-static void patch_nm_tables(struct gsm_bts *bts)
-{
- u_int8_t arfcn_low = bts->c0->arfcn & 0xff;
- u_int8_t arfcn_high = (bts->c0->arfcn >> 8) & 0x0f;
-
- /* patch ARFCN into BTS Attributes */
- nanobts_attr_bts[42] &= 0xf0;
- nanobts_attr_bts[42] |= arfcn_high;
- nanobts_attr_bts[43] = arfcn_low;
-
- /* patch the RACH attributes */
- if (bts->rach_b_thresh != -1) {
- nanobts_attr_bts[33] = bts->rach_b_thresh & 0xff;
- }
-
- if (bts->rach_ldavg_slots != -1) {
- u_int8_t avg_high = bts->rach_ldavg_slots & 0xff;
- u_int8_t avg_low = (bts->rach_ldavg_slots >> 8) & 0x0f;
-
- nanobts_attr_bts[35] = avg_high;
- nanobts_attr_bts[36] = avg_low;
- }
-
- /* patch BSIC */
- nanobts_attr_bts[sizeof(nanobts_attr_bts)-11] = bts->bsic;
-
- /* patch CGI */
- abis_nm_ipaccess_cgi(nanobts_attr_bts+sizeof(nanobts_attr_bts)-7, bts);
-
- /* patch the power reduction */
- nanobts_attr_radio[1] = bts->c0->max_power_red / 2;
-
- /* patch NSEI */
- nanobts_attr_nse[3] = bts->gprs.nse.nsei >> 8;
- nanobts_attr_nse[4] = bts->gprs.nse.nsei & 0xff;
- memcpy(nanobts_attr_nse+8, bts->gprs.nse.timer,
- ARRAY_SIZE(bts->gprs.nse.timer));
- memcpy(nanobts_attr_nse+18, bts->gprs.cell.timer,
- ARRAY_SIZE(bts->gprs.cell.timer));
-
- /* patch NSVCI */
- nanobts_attr_nsvc0[3] = bts->gprs.nsvc[0].nsvci >> 8;
- nanobts_attr_nsvc0[4] = bts->gprs.nsvc[0].nsvci & 0xff;
-
- /* patch IP address as SGSN IP */
- patch_16(nanobts_attr_nsvc0 + 8,
- htons(bts->gprs.nsvc[0].remote_port));
- patch_32(nanobts_attr_nsvc0 + 10,
- htonl(bts->gprs.nsvc[0].remote_ip));
- patch_16(nanobts_attr_nsvc0 + 14,
- htons(bts->gprs.nsvc[0].local_port));
-
- /* patch BVCI */
- nanobts_attr_cell[12] = bts->gprs.cell.bvci >> 8;
- nanobts_attr_cell[13] = bts->gprs.cell.bvci & 0xff;
- /* patch RAC */
- nanobts_attr_cell[3] = bts->gprs.rac;
-
- if (bts->gprs.mode == BTS_GPRS_EGPRS) {
- /* patch EGPRS coding schemes MCS 1..9 */
- nanobts_attr_cell[29] = 0x8f;
- nanobts_attr_cell[30] = 0xff;
- }
-}
-
-
-/* Callback function to be called whenever we get a GSM 12.21 state change event */
-static int nm_statechg_event(int evt, struct nm_statechg_signal_data *nsd)
-{
- u_int8_t obj_class = nsd->obj_class;
- void *obj = nsd->obj;
- struct gsm_nm_state *new_state = nsd->new_state;
-
- struct gsm_bts *bts;
- struct gsm_bts_trx *trx;
- struct gsm_bts_trx_ts *ts;
- struct gsm_bts_gprs_nsvc *nsvc;
-
- /* This event-driven BTS setup is currently only required on nanoBTS */
-
- /* S_NM_STATECHG_ADM is called after we call chg_adm_state() and would create
- * endless loop */
- if (evt != S_NM_STATECHG_OPER)
- return 0;
-
- switch (obj_class) {
- case NM_OC_SITE_MANAGER:
- bts = container_of(obj, struct gsm_bts, site_mgr);
- if ((new_state->operational == NM_OPSTATE_ENABLED &&
- new_state->availability == NM_AVSTATE_OK) ||
- (new_state->operational == NM_OPSTATE_DISABLED &&
- new_state->availability == NM_AVSTATE_OFF_LINE))
- abis_nm_opstart(bts, obj_class, 0xff, 0xff, 0xff);
- break;
- case NM_OC_BTS:
- bts = obj;
- if (new_state->availability == NM_AVSTATE_DEPENDENCY) {
- patch_nm_tables(bts);
- abis_nm_set_bts_attr(bts, nanobts_attr_bts,
- sizeof(nanobts_attr_bts));
- abis_nm_chg_adm_state(bts, obj_class,
- bts->bts_nr, 0xff, 0xff,
- NM_STATE_UNLOCKED);
- abis_nm_opstart(bts, obj_class,
- bts->bts_nr, 0xff, 0xff);
- }
- break;
- case NM_OC_CHANNEL:
- ts = obj;
- trx = ts->trx;
- if (new_state->operational == NM_OPSTATE_DISABLED &&
- new_state->availability == NM_AVSTATE_DEPENDENCY) {
- patch_nm_tables(trx->bts);
- enum abis_nm_chan_comb ccomb =
- abis_nm_chcomb4pchan(ts->pchan);
- abis_nm_set_channel_attr(ts, ccomb);
- abis_nm_chg_adm_state(trx->bts, obj_class,
- trx->bts->bts_nr, trx->nr, ts->nr,
- NM_STATE_UNLOCKED);
- abis_nm_opstart(trx->bts, obj_class,
- trx->bts->bts_nr, trx->nr, ts->nr);
- }
- break;
- case NM_OC_RADIO_CARRIER:
- trx = obj;
- if (new_state->operational == NM_OPSTATE_DISABLED &&
- new_state->availability == NM_AVSTATE_OK)
- abis_nm_opstart(trx->bts, obj_class, trx->bts->bts_nr,
- trx->nr, 0xff);
- break;
- case NM_OC_GPRS_NSE:
- bts = container_of(obj, struct gsm_bts, gprs.nse);
- if (bts->gprs.mode == BTS_GPRS_NONE)
- break;
- if (new_state->availability == NM_AVSTATE_DEPENDENCY) {
- abis_nm_ipaccess_set_attr(bts, obj_class, bts->bts_nr,
- 0xff, 0xff, nanobts_attr_nse,
- sizeof(nanobts_attr_nse));
- abis_nm_opstart(bts, obj_class, bts->bts_nr,
- 0xff, 0xff);
- }
- break;
- case NM_OC_GPRS_CELL:
- bts = container_of(obj, struct gsm_bts, gprs.cell);
- if (bts->gprs.mode == BTS_GPRS_NONE)
- break;
- if (new_state->availability == NM_AVSTATE_DEPENDENCY) {
- abis_nm_ipaccess_set_attr(bts, obj_class, bts->bts_nr,
- 0, 0xff, nanobts_attr_cell,
- sizeof(nanobts_attr_cell));
- abis_nm_opstart(bts, obj_class, bts->bts_nr,
- 0, 0xff);
- abis_nm_chg_adm_state(bts, obj_class, bts->bts_nr,
- 0, 0xff, NM_STATE_UNLOCKED);
- abis_nm_chg_adm_state(bts, NM_OC_GPRS_NSE, bts->bts_nr,
- 0xff, 0xff, NM_STATE_UNLOCKED);
- }
- break;
- case NM_OC_GPRS_NSVC:
- nsvc = obj;
- bts = nsvc->bts;
- if (bts->gprs.mode == BTS_GPRS_NONE)
- break;
- /* We skip NSVC1 since we only use NSVC0 */
- if (nsvc->id == 1)
- break;
- if (new_state->availability == NM_AVSTATE_OFF_LINE) {
- abis_nm_ipaccess_set_attr(bts, obj_class, bts->bts_nr,
- nsvc->id, 0xff,
- nanobts_attr_nsvc0,
- sizeof(nanobts_attr_nsvc0));
- abis_nm_opstart(bts, obj_class, bts->bts_nr,
- nsvc->id, 0xff);
- abis_nm_chg_adm_state(bts, obj_class, bts->bts_nr,
- nsvc->id, 0xff,
- NM_STATE_UNLOCKED);
- }
- default:
- 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 *bts = mb->trx->bts;
- struct gsm_bts_trx *trx = gsm_bts_trx_num(bts, foh->obj_inst.trx_nr);
-
- if (!trx)
- return -EINVAL;
-
- if (trx->bts->type != GSM_BTS_TYPE_NANOBTS)
- return 0;
-
- switch (foh->obj_class) {
- case NM_OC_BASEB_TRANSC:
- abis_nm_chg_adm_state(trx->bts, foh->obj_class,
- trx->bts->bts_nr, trx->nr, 0xff,
- NM_STATE_UNLOCKED);
- abis_nm_opstart(trx->bts, foh->obj_class,
- trx->bts->bts_nr, trx->nr, 0xff);
- /* TRX software is active, tell it to initiate RSL Link */
- abis_nm_ipaccess_rsl_connect(trx, 0, 3003, trx->rsl_tei);
- break;
- case NM_OC_RADIO_CARRIER: {
- /*
- * Locking the radio carrier will make it go
- * offline again and we would come here. The
- * framework should determine that there was
- * no change and avoid recursion.
- *
- * This code is here to make sure that on start
- * a TRX remains locked.
- */
- int rc_state = trx->nm_state.administrative;
- /* Patch ARFCN into radio attribute */
- nanobts_attr_radio[5] &= 0xf0;
- nanobts_attr_radio[5] |= trx->arfcn >> 8;
- nanobts_attr_radio[6] = trx->arfcn & 0xff;
- abis_nm_set_radio_attr(trx, nanobts_attr_radio,
- sizeof(nanobts_attr_radio));
- abis_nm_chg_adm_state(trx->bts, foh->obj_class,
- trx->bts->bts_nr, trx->nr, 0xff,
- rc_state);
- abis_nm_opstart(trx->bts, foh->obj_class, trx->bts->bts_nr,
- trx->nr, 0xff);
- 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)
-{
- if (subsys != SS_NM)
- return 0;
-
- switch (signal) {
- case S_NM_SW_ACTIV_REP:
- return sw_activ_rep(signal_data);
- case S_NM_STATECHG_OPER:
- case S_NM_STATECHG_ADM:
- return nm_statechg_event(signal, signal_data);
- default:
- break;
- }
- return 0;
-}
-
-int bts_model_nanobts_init(void)
-{
- model_nanobts.features.data = &model_nanobts._features_data[0];
- model_nanobts.features.data_len = sizeof(model_nanobts._features_data);
-
- gsm_btsmodel_set_feature(&model_nanobts, BTS_FEAT_GPRS);
- gsm_btsmodel_set_feature(&model_nanobts, BTS_FEAT_EGPRS);
-
- register_signal_handler(SS_NM, nm_sig_cb, NULL);
-
- return gsm_bts_model_register(&model_nanobts);
-}
diff --git a/openbsc/src/bsc/bts_siemens_bs11.c b/openbsc/src/bsc/bts_siemens_bs11.c
deleted file mode 100644
index 5a5f88306..000000000
--- a/openbsc/src/bsc/bts_siemens_bs11.c
+++ /dev/null
@@ -1,591 +0,0 @@
-/* Siemens BS-11 specific code */
-
-/* (C) 2009-2010 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 Affero General Public License as published by
- * the Free Software Foundation; either version 3 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 Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-#include <sys/types.h>
-
-#include <osmocore/tlv.h>
-
-#include <openbsc/debug.h>
-#include <openbsc/gsm_data.h>
-#include <openbsc/abis_nm.h>
-#include <openbsc/e1_input.h>
-#include <openbsc/signal.h>
-
-static struct gsm_bts_model model_bs11 = {
- .type = GSM_BTS_TYPE_BS11,
- .name = "bs11",
- .oml_rcvmsg = &abis_nm_rcvmsg,
- .nm_att_tlvdef = {
- .def = {
- [NM_ATT_AVAIL_STATUS] = { TLV_TYPE_TLV },
- /* 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 },
- [0x95] = { TLV_TYPE_FIXED, 2 },
- },
- },
-};
-
-/* 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[] =
-{
- NM_MT_BS11_SET_ATTR, NM_OC_SITE_MANAGER, 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
-*/
-
-static unsigned char bs11_attr_bts[] =
-{
- 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[] =
-{
- NM_MT_BS11_SET_ATTR, NM_OC_BS11_HANDOVER, 0x00, 0xFF, 0xFF,
- 0xD0, 0x00, /* enableDelayPowerBudgetHO */
- 0x64, 0x00, /* enableDistanceHO */
- 0x67, 0x00, /* enableInternalInterCellHandover */
- 0x68, 0x00, /* enableInternalInterCellHandover */
- 0x6A, 0x00, /* enablePowerBudgetHO */
- 0x6C, 0x00, /* enableRXLEVHO */
- 0x6D, 0x00, /* enableRXQUALHO */
- 0x6F, 0x08, /* hoAveragingDistance */
- 0x70, 0x08, 0x01, /* hoAveragingLev */
- 0x71, 0x10, 0x10, 0x10,
- 0x72, 0x08, 0x02, /* hoAveragingQual */
- 0x73, 0x0A, /* hoLowerThresholdLevDL */
- 0x74, 0x05, /* hoLowerThresholdLevUL */
- 0x75, 0x06, /* hoLowerThresholdQualDL */
- 0x76, 0x06, /* hoLowerThresholdQualUL */
- 0x78, 0x14, /* hoThresholdLevDLintra */
- 0x79, 0x14, /* hoThresholdLevULintra */
- 0x7A, 0x14, /* hoThresholdMsRangeMax */
- 0x7D, 0x06, /* nCell */
- NM_ATT_BS11_TIMER_HO_REQUEST, 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[] =
-{
- NM_MT_BS11_SET_ATTR, 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, /* pcAveragingLev */
- 0x7F, 0x04, 0x02, /* pcAveragingQual */
- 0x80, 0x0F, /* pcLowerThresholdLevDL */
- 0x81, 0x0A, /* pcLowerThresholdLevUL */
- 0x82, 0x05, /* pcLowerThresholdQualDL */
- 0x83, 0x05, /* pcLowerThresholdQualUL */
- 0x84, 0x0C, /* pcRLFThreshold */
- 0x85, 0x14, /* pcUpperThresholdLevDL */
- 0x86, 0x0F, /* pcUpperThresholdLevUL */
- 0x87, 0x04, /* pcUpperThresholdQualDL */
- 0x88, 0x04, /* pcUpperThresholdQualUL */
- 0x89, 0x02, /* powerConfirm */
- 0x8A, 0x02, /* powerConfirmInterval */
- 0x8B, 0x02, /* powerIncrStepSize */
- 0x8C, 0x01, /* powerRedStepSize */
- 0x8D, 0x40, /* radioLinkTimeoutBs */
- 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
-*/
-
-static unsigned char bs11_attr_radio[] =
-{
- NM_ATT_ARFCN_LIST, 0x01, 0x00, HARDCODED_ARFCN /*0x01*/,
- NM_ATT_RF_MAXPOWR_R, 0x00,
- NM_ATT_BS11_RADIO_MEAS_GRAN, 0x01, 0x05,
- NM_ATT_BS11_RADIO_MEAS_REP, 0x01, 0x01,
- NM_ATT_BS11_EMRG_CFG_MEMBER, 0x01, 0x01,
- NM_ATT_BS11_TRX_AREA, 0x01, 0x00,
-};
-
-/*
- * Patch the various SYSTEM INFORMATION tables to update
- * the LAI
- */
-static void patch_nm_tables(struct gsm_bts *bts)
-{
- u_int8_t arfcn_low = bts->c0->arfcn & 0xff;
- u_int8_t arfcn_high = (bts->c0->arfcn >> 8) & 0x0f;
-
- /* patch ARFCN into BTS Attributes */
- bs11_attr_bts[69] &= 0xf0;
- bs11_attr_bts[69] |= arfcn_high;
- bs11_attr_bts[70] = arfcn_low;
-
- /* patch ARFCN into TRX Attributes */
- bs11_attr_radio[2] &= 0xf0;
- bs11_attr_radio[2] |= arfcn_high;
- bs11_attr_radio[3] = arfcn_low;
-
- /* patch the RACH attributes */
- if (bts->rach_b_thresh != -1)
- bs11_attr_bts[33] = bts->rach_b_thresh & 0xff;
-
- if (bts->rach_ldavg_slots != -1) {
- u_int8_t avg_high = bts->rach_ldavg_slots & 0xff;
- u_int8_t avg_low = (bts->rach_ldavg_slots >> 8) & 0x0f;
-
- bs11_attr_bts[35] = avg_high;
- bs11_attr_bts[36] = avg_low;
- }
-
- /* patch BSIC */
- bs11_attr_bts[1] = bts->bsic;
-
- /* patch the power reduction */
- bs11_attr_radio[5] = bts->c0->max_power_red / 2;
-}
-
-
-static void nm_reconfig_ts(struct gsm_bts_trx_ts *ts)
-{
- enum abis_nm_chan_comb ccomb = abis_nm_chcomb4pchan(ts->pchan);
- struct gsm_e1_subslot *e1l = &ts->e1_link;
-
- abis_nm_set_channel_attr(ts, ccomb);
-
- if (is_ipaccess_bts(ts->trx->bts))
- return;
-
- switch (ts->pchan) {
- case GSM_PCHAN_TCH_F:
- case GSM_PCHAN_TCH_H:
- abis_nm_conn_terr_traf(ts, e1l->e1_nr, e1l->e1_ts,
- e1l->e1_ts_ss);
- break;
- default:
- break;
- }
-}
-
-static void nm_reconfig_trx(struct gsm_bts_trx *trx)
-{
- struct gsm_e1_subslot *e1l = &trx->rsl_e1_link;
- int i;
-
- patch_nm_tables(trx->bts);
-
- switch (trx->bts->type) {
- case GSM_BTS_TYPE_BS11:
- /* FIXME: discover this by fetching an attribute */
-#if 0
- trx->nominal_power = 15; /* 15dBm == 30mW PA configuration */
-#else
- trx->nominal_power = 24; /* 24dBm == 250mW PA configuration */
-#endif
- abis_nm_conn_terr_sign(trx, e1l->e1_nr, e1l->e1_ts,
- e1l->e1_ts_ss);
- abis_nm_establish_tei(trx->bts, trx->nr, e1l->e1_nr,
- e1l->e1_ts, e1l->e1_ts_ss, trx->rsl_tei);
-
- /* Set Radio Attributes */
- if (trx == trx->bts->c0)
- abis_nm_set_radio_attr(trx, bs11_attr_radio,
- sizeof(bs11_attr_radio));
- else {
- u_int8_t trx1_attr_radio[sizeof(bs11_attr_radio)];
- u_int8_t arfcn_low = trx->arfcn & 0xff;
- u_int8_t arfcn_high = (trx->arfcn >> 8) & 0x0f;
- memcpy(trx1_attr_radio, bs11_attr_radio,
- sizeof(trx1_attr_radio));
-
- /* patch ARFCN into TRX Attributes */
- trx1_attr_radio[2] &= 0xf0;
- trx1_attr_radio[2] |= arfcn_high;
- trx1_attr_radio[3] = arfcn_low;
-
- abis_nm_set_radio_attr(trx, trx1_attr_radio,
- sizeof(trx1_attr_radio));
- }
- break;
- case GSM_BTS_TYPE_NANOBTS:
- switch (trx->bts->band) {
- case GSM_BAND_850:
- case GSM_BAND_900:
- trx->nominal_power = 20;
- break;
- case GSM_BAND_1800:
- case GSM_BAND_1900:
- trx->nominal_power = 23;
- break;
- default:
- LOGP(DNM, LOGL_ERROR, "Unsupported nanoBTS GSM band %s\n",
- gsm_band_name(trx->bts->band));
- break;
- }
- break;
- default:
- break;
- }
-
- for (i = 0; i < TRX_NR_TS; i++)
- nm_reconfig_ts(&trx->ts[i]);
-}
-
-static void nm_reconfig_bts(struct gsm_bts *bts)
-{
- struct gsm_bts_trx *trx;
-
- switch (bts->type) {
- case GSM_BTS_TYPE_BS11:
- patch_nm_tables(bts);
- abis_nm_raw_msg(bts, sizeof(msg_1), msg_1); /* set BTS SiteMgr attr*/
- abis_nm_set_bts_attr(bts, bs11_attr_bts, sizeof(bs11_attr_bts));
- 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 */
- break;
- default:
- break;
- }
-
- llist_for_each_entry(trx, &bts->trx_list, list)
- nm_reconfig_trx(trx);
-}
-
-
-static void bootstrap_om_bs11(struct gsm_bts *bts)
-{
- LOGP(DNM, LOGL_NOTICE, "bootstrapping OML for BTS %u\n", bts->nr);
-
- /* 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);
-
- /* reconfigure BTS with all TRX and all TS */
- nm_reconfig_bts(bts);
-
- /* 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 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;
-}
-
-/* Callback function to be called every time we receive a signal from INPUT */
-static int gbl_sig_cb(unsigned int subsys, unsigned int signal,
- void *handler_data, void *signal_data)
-{
- struct gsm_bts *bts;
-
- if (subsys != SS_GLOBAL)
- return 0;
-
- switch (signal) {
- case S_GLOBAL_BTS_CLOSE_OM:
- bts = signal_data;
- if (bts->type == GSM_BTS_TYPE_BS11)
- shutdown_om(signal_data);
- break;
- }
-
- return 0;
-}
-
-/* Callback function to be called every time we receive a signal from INPUT */
-static int inp_sig_cb(unsigned int subsys, unsigned int signal,
- void *handler_data, void *signal_data)
-{
- struct input_signal_data *isd = signal_data;
-
- if (subsys != SS_INPUT)
- return 0;
-
- switch (signal) {
- case S_INP_TEI_UP:
- switch (isd->link_type) {
- case E1INP_SIGN_OML:
- if (isd->trx->bts->type == GSM_BTS_TYPE_BS11)
- bootstrap_om_bs11(isd->trx->bts);
- break;
- }
- }
-
- return 0;
-}
-
-int bts_model_bs11_init(void)
-{
- model_bs11.features.data = &model_bs11._features_data[0];
- model_bs11.features.data_len = sizeof(model_bs11._features_data);
-
- gsm_btsmodel_set_feature(&model_bs11, BTS_FEAT_HOPPING);
- gsm_btsmodel_set_feature(&model_bs11, BTS_FEAT_HSCSD);
-
- register_signal_handler(SS_INPUT, inp_sig_cb, NULL);
- register_signal_handler(SS_GLOBAL, gbl_sig_cb, NULL);
-
- return gsm_bts_model_register(&model_bs11);
-}
diff --git a/openbsc/src/bsc/bts_unknown.c b/openbsc/src/bsc/bts_unknown.c
deleted file mode 100644
index f95459959..000000000
--- a/openbsc/src/bsc/bts_unknown.c
+++ /dev/null
@@ -1,41 +0,0 @@
-/* Generic BTS - VTY code tries to allocate this BTS before type is known */
-
-/* (C) 2010 by Daniel Willmann <daniel@totalueberwachung.de>
- *
- * All Rights Reserved
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation; either version 3 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 Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-#include <sys/types.h>
-
-#include <openbsc/gsm_data.h>
-#include <osmocore/tlv.h>
-#include <openbsc/abis_nm.h>
-
-static struct gsm_bts_model model_unknown = {
- .type = GSM_BTS_TYPE_UNKNOWN,
- .name = "unknown",
- .oml_rcvmsg = &abis_nm_rcvmsg,
- .nm_att_tlvdef = {
- .def = {
- },
- },
-};
-
-int bts_model_unknown_init(void)
-{
- return gsm_bts_model_register(&model_unknown);
-}
diff --git a/openbsc/src/bsc/chan_alloc.c b/openbsc/src/bsc/chan_alloc.c
deleted file mode 100644
index 167381b37..000000000
--- a/openbsc/src/bsc/chan_alloc.c
+++ /dev/null
@@ -1,507 +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 Affero General Public License as published by
- * the Free Software Foundation; either version 3 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 Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-
-#include <openbsc/gsm_subscriber.h>
-#include <openbsc/chan_alloc.h>
-#include <openbsc/abis_nm.h>
-#include <openbsc/abis_rsl.h>
-#include <openbsc/debug.h>
-#include <openbsc/signal.h>
-
-#include <osmocore/talloc.h>
-
-static int ts_is_usable(struct gsm_bts_trx_ts *ts)
-{
- /* FIXME: How does this behave for BS-11 ? */
- if (is_ipaccess_bts(ts->trx->bts)) {
- if (!nm_is_running(&ts->nm_state))
- return 0;
- }
-
- return 1;
-}
-
-int trx_is_usable(struct gsm_bts_trx *trx)
-{
- /* FIXME: How does this behave for BS-11 ? */
- if (is_ipaccess_bts(trx->bts)) {
- if (!nm_is_running(&trx->nm_state) ||
- !nm_is_running(&trx->bb_transc.nm_state))
- return 0;
- }
-
- return 1;
-}
-
-struct gsm_bts_trx_ts *ts_c0_alloc(struct gsm_bts *bts,
- enum gsm_phys_chan_config pchan)
-{
- struct gsm_bts_trx *trx = bts->c0;
- 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;
-}
-
-/* Allocate a physical channel (TS) */
-struct gsm_bts_trx_ts *ts_alloc(struct gsm_bts *bts,
- enum gsm_phys_chan_config pchan)
-{
- int j;
- struct gsm_bts_trx *trx;
-
- llist_for_each_entry(trx, &bts->trx_list, list) {
- int from, to;
-
- if (!trx_is_usable(trx))
- continue;
-
- /* the following constraints are pure policy,
- * no requirement to put this restriction in place */
- if (trx == bts->c0) {
- /* On the first TRX we run one CCCH and one SDCCH8 */
- switch (pchan) {
- case GSM_PCHAN_CCCH:
- case GSM_PCHAN_CCCH_SDCCH4:
- from = 0; to = 0;
- break;
- case GSM_PCHAN_TCH_F:
- case GSM_PCHAN_TCH_H:
- from = 1; to = 7;
- break;
- case GSM_PCHAN_SDCCH8_SACCH8C:
- default:
- return NULL;
- }
- } else {
- /* Every secondary TRX is configured for TCH/F
- * and TCH/H only */
- switch (pchan) {
- case GSM_PCHAN_SDCCH8_SACCH8C:
- from = 1; to = 1;
- case GSM_PCHAN_TCH_F:
- case GSM_PCHAN_TCH_H:
- from = 1; to = 7;
- break;
- default:
- return NULL;
- }
- }
-
- for (j = from; j <= to; j++) {
- struct gsm_bts_trx_ts *ts = &trx->ts[j];
-
- if (!ts_is_usable(ts))
- continue;
-
- if (ts->pchan == GSM_PCHAN_NONE) {
- ts->pchan = pchan;
- /* set channel attribute on OML */
- abis_nm_set_channel_attr(ts, abis_nm_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,
- /* FIXME: what about dynamic TCH_F_TCH_H ? */
- [GSM_PCHAN_TCH_F_PDCH] = 1,
-};
-
-static struct gsm_lchan *
-_lc_find_trx(struct gsm_bts_trx *trx, enum gsm_phys_chan_config pchan)
-{
- struct gsm_bts_trx_ts *ts;
- int j, ss;
-
- if (!trx_is_usable(trx))
- return NULL;
-
- for (j = 0; j < 8; j++) {
- ts = &trx->ts[j];
- if (!ts_is_usable(ts))
- continue;
- /* ip.access dynamic TCH/F + PDCH combination */
- if (ts->pchan == GSM_PCHAN_TCH_F_PDCH &&
- pchan == GSM_PCHAN_TCH_F) {
- /* we can only consider such a dynamic channel
- * if the PDCH is currently inactive */
- if (ts->flags & TS_F_PDCH_MODE)
- continue;
- } else 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 &&
- lc->state == LCHAN_S_NONE)
- return lc;
- }
- }
-
- return NULL;
-}
-
-static struct gsm_lchan *
-_lc_find_bts(struct gsm_bts *bts, enum gsm_phys_chan_config pchan)
-{
- struct gsm_bts_trx *trx;
- struct gsm_bts_trx_ts *ts;
- struct gsm_lchan *lc;
-
- if (bts->chan_alloc_reverse) {
- llist_for_each_entry_reverse(trx, &bts->trx_list, list) {
- lc = _lc_find_trx(trx, pchan);
- if (lc)
- return lc;
- }
- } else {
- llist_for_each_entry(trx, &bts->trx_list, list) {
- lc = _lc_find_trx(trx, pchan);
- if (lc)
- 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,
- int allow_bigger)
-{
- struct gsm_lchan *lchan = NULL;
- enum gsm_phys_chan_config first, second;
-
- switch (type) {
- case GSM_LCHAN_SDCCH:
- if (bts->chan_alloc_reverse) {
- first = GSM_PCHAN_SDCCH8_SACCH8C;
- second = GSM_PCHAN_CCCH_SDCCH4;
- } else {
- first = GSM_PCHAN_CCCH_SDCCH4;
- second = GSM_PCHAN_SDCCH8_SACCH8C;
- }
-
- lchan = _lc_find_bts(bts, first);
- if (lchan == NULL)
- lchan = _lc_find_bts(bts, second);
-
- /* allow to assign bigger channels */
- if (allow_bigger) {
- if (lchan == NULL) {
- lchan = _lc_find_bts(bts, GSM_PCHAN_TCH_H);
- type = GSM_LCHAN_TCH_H;
- }
-
- if (lchan == NULL) {
- lchan = _lc_find_bts(bts, GSM_PCHAN_TCH_F);
- type = GSM_LCHAN_TCH_F;
- }
- }
- break;
- case GSM_LCHAN_TCH_F:
- lchan = _lc_find_bts(bts, GSM_PCHAN_TCH_F);
- break;
- case GSM_LCHAN_TCH_H:
- lchan =_lc_find_bts(bts, GSM_PCHAN_TCH_H);
- /* If we don't have TCH/H available, fall-back to TCH/F */
- if (!lchan) {
- lchan = _lc_find_bts(bts, GSM_PCHAN_TCH_F);
- type = GSM_LCHAN_TCH_F;
- }
- break;
- default:
- LOGP(DRLL, LOGL_ERROR, "Unknown gsm_chan_t %u\n", type);
- }
-
- if (lchan) {
- lchan->type = type;
-
- /* clear sapis */
- memset(lchan->sapis, 0, ARRAY_SIZE(lchan->sapis));
-
- /* clear multi rate config */
- memset(&lchan->mr_conf, 0, sizeof(lchan->mr_conf));
- } else {
- struct challoc_signal_data sig;
- sig.bts = bts;
- sig.type = type;
- dispatch_signal(SS_CHALLOC, S_CHALLOC_ALLOC_FAIL, &sig);
- }
-
- return lchan;
-}
-
-/* Free a logical channel */
-void lchan_free(struct gsm_lchan *lchan)
-{
- struct challoc_signal_data sig;
- int i;
-
- sig.type = lchan->type;
- lchan->type = GSM_LCHAN_NONE;
-
-
- if (lchan->conn) {
- struct lchan_signal_data sig;
-
- /* We might kill an active channel... */
- sig.lchan = lchan;
- sig.mr = NULL;
- dispatch_signal(SS_LCHAN, S_LCHAN_UNEXPECTED_RELEASE, &sig);
- }
-
-
- /* stop the timer */
- bsc_del_timer(&lchan->T3101);
-
- /* clear cached measuement reports */
- lchan->meas_rep_idx = 0;
- for (i = 0; i < ARRAY_SIZE(lchan->meas_rep); i++) {
- lchan->meas_rep[i].flags = 0;
- lchan->meas_rep[i].nr = 0;
- }
- for (i = 0; i < ARRAY_SIZE(lchan->neigh_meas); i++)
- lchan->neigh_meas[i].arfcn = 0;
-
- if (lchan->rqd_ref) {
- talloc_free(lchan->rqd_ref);
- lchan->rqd_ref = NULL;
- lchan->rqd_ta = 0;
- }
-
- sig.lchan = lchan;
- sig.bts = lchan->ts->trx->bts;
- dispatch_signal(SS_CHALLOC, S_CHALLOC_FREED, &sig);
-
- if (lchan->conn) {
- LOGP(DRLL, LOGL_ERROR, "the subscriber connection should be gone.\n");
- lchan->conn = NULL;
- }
-
- lchan->sach_deact = 0;
- lchan->release_reason = 0;
-
- /* FIXME: ts_free() the timeslot, if we're the last logical
- * channel using it */
-}
-
-/*
- * There was an error with the TRX and we need to forget
- * any state so that a lchan can be allocated again after
- * the trx is fully usable.
- *
- * This should be called after lchan_free to force a channel
- * be available for allocation again. This means that this
- * method will stop the "delay after error"-timer and set the
- * state to LCHAN_S_NONE.
- */
-void lchan_reset(struct gsm_lchan *lchan)
-{
- bsc_del_timer(&lchan->T3101);
- bsc_del_timer(&lchan->T3111);
- bsc_del_timer(&lchan->error_timer);
-
- lchan->type = GSM_LCHAN_NONE;
- lchan->state = LCHAN_S_NONE;
-}
-
-/* release the next allocated SAPI or return 0 */
-static int _lchan_release_next_sapi(struct gsm_lchan *lchan)
-{
- int sapi;
-
- for (sapi = 1; sapi < ARRAY_SIZE(lchan->sapis); ++sapi) {
- u_int8_t link_id;
- if (lchan->sapis[sapi] == LCHAN_SAPI_UNUSED)
- continue;
-
- link_id = sapi;
- if (lchan->type == GSM_LCHAN_TCH_F || lchan->type == GSM_LCHAN_TCH_H)
- link_id |= 0x40;
- rsl_release_request(lchan, link_id, lchan->release_reason);
- return 0;
- }
-
- return 1;
-}
-
-/* Drive the release process of the lchan */
-static void _lchan_handle_release(struct gsm_lchan *lchan)
-{
- /* Ask for SAPI != 0 to be freed first and stop if we need to wait */
- if (_lchan_release_next_sapi(lchan) == 0)
- return;
-
- if (lchan->sach_deact) {
- gsm48_send_rr_release(lchan);
- return;
- }
-
- rsl_release_request(lchan, 0, lchan->release_reason);
- rsl_lchan_set_state(lchan, LCHAN_S_REL_REQ);
-}
-
-/* called from abis rsl */
-int rsl_lchan_rll_release(struct gsm_lchan *lchan, u_int8_t link_id)
-{
- if (lchan->state != LCHAN_S_REL_REQ)
- return -1;
-
- if ((link_id & 0x7) != 0)
- _lchan_handle_release(lchan);
- return 0;
-}
-
-/* Consider releasing the channel now */
-int lchan_release(struct gsm_lchan *lchan, int sach_deact, int reason)
-{
- DEBUGP(DRLL, "%s starting release sequence\n", gsm_lchan_name(lchan));
- rsl_lchan_set_state(lchan, LCHAN_S_REL_REQ);
-
- lchan->conn = NULL;
- lchan->release_reason = reason;
- lchan->sach_deact = sach_deact;
- _lchan_handle_release(lchan);
- return 1;
-}
-
-static struct gsm_lchan* lchan_find(struct gsm_bts *bts, struct gsm_subscriber *subscr) {
- struct gsm_bts_trx *trx;
- int ts_no, lchan_no;
-
- llist_for_each_entry(trx, &bts->trx_list, list) {
- for (ts_no = 0; ts_no < 8; ++ts_no) {
- for (lchan_no = 0; lchan_no < TS_MAX_LCHAN; ++lchan_no) {
- struct gsm_lchan *lchan =
- &trx->ts[ts_no].lchan[lchan_no];
- if (lchan->conn && subscr == lchan->conn->subscr)
- return lchan;
- }
- }
- }
-
- return NULL;
-}
-
-struct gsm_subscriber_connection *connection_for_subscr(struct gsm_subscriber *subscr)
-{
- struct gsm_bts *bts;
- struct gsm_network *net = subscr->net;
- struct gsm_lchan *lchan;
-
- llist_for_each_entry(bts, &net->bts_list, list) {
- lchan = lchan_find(bts, subscr);
- if (lchan)
- return lchan->conn;
- }
-
- return NULL;
-}
-
-void bts_chan_load(struct pchan_load *cl, const struct gsm_bts *bts)
-{
- struct gsm_bts_trx *trx;
-
- llist_for_each_entry(trx, &bts->trx_list, list) {
- int i;
-
- /* skip administratively deactivated tranxsceivers */
- if (!nm_is_running(&trx->nm_state) ||
- !nm_is_running(&trx->bb_transc.nm_state))
- continue;
-
- for (i = 0; i < ARRAY_SIZE(trx->ts); i++) {
- struct gsm_bts_trx_ts *ts = &trx->ts[i];
- struct load_counter *pl = &cl->pchan[ts->pchan];
- int j;
-
- /* skip administratively deactivated timeslots */
- if (!nm_is_running(&ts->nm_state))
- continue;
-
- for (j = 0; j < subslots_per_pchan[ts->pchan]; j++) {
- struct gsm_lchan *lchan = &ts->lchan[j];
-
- pl->total++;
-
- switch (lchan->state) {
- case LCHAN_S_NONE:
- break;
- default:
- pl->used++;
- break;
- }
- }
- }
- }
-}
-
-void network_chan_load(struct pchan_load *pl, struct gsm_network *net)
-{
- struct gsm_bts *bts;
-
- memset(pl, 0, sizeof(*pl));
-
- llist_for_each_entry(bts, &net->bts_list, list)
- bts_chan_load(pl, bts);
-}
-
diff --git a/openbsc/src/bsc/e1_config.c b/openbsc/src/bsc/e1_config.c
deleted file mode 100644
index 958839dcc..000000000
--- a/openbsc/src/bsc/e1_config.c
+++ /dev/null
@@ -1,296 +0,0 @@
-/* OpenBSC E1 Input code */
-
-/* (C) 2008-2010 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 Affero General Public License as published by
- * the Free Software Foundation; either version 3 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 Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-#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>
-#include <openbsc/ipaccess.h>
-#include <osmocore/talloc.h>
-#include <openbsc/debug.h>
-
-#define SAPI_L2ML 0
-#define SAPI_OML 62
-#define SAPI_RSL 0 /* 63 ? */
-
-/* The e1_reconfig_*() functions below tale the configuration present in the
- * bts/trx/ts data structures and ensure the E1 configuration reflects the
- * timeslot/subslot/TEI configuration */
-
-int e1_reconfig_ts(struct gsm_bts_trx_ts *ts)
-{
- struct gsm_e1_subslot *e1_link = &ts->e1_link;
- struct e1inp_line *line;
- struct e1inp_ts *e1_ts;
-
- DEBUGP(DMI, "e1_reconfig_ts(%u,%u,%u)\n", ts->trx->bts->nr, ts->trx->nr, ts->nr);
-
- if (!e1_link->e1_ts) {
- LOGP(DINP, LOGL_ERROR, "TS (%u/%u/%u) without E1 timeslot?\n",
- ts->nr, ts->trx->nr, ts->trx->bts->nr);
- return 0;
- }
-
- line = e1inp_line_get(e1_link->e1_nr);
- if (!line) {
- LOGP(DINP, LOGL_ERROR, "TS (%u/%u/%u) referring to "
- "non-existing E1 line %u\n", ts->nr, ts->trx->nr,
- ts->trx->bts->nr, e1_link->e1_nr);
- return -ENOMEM;
- }
-
- switch (ts->pchan) {
- case GSM_PCHAN_TCH_F:
- case GSM_PCHAN_TCH_H:
- e1_ts = &line->ts[e1_link->e1_ts-1];
- e1inp_ts_config(e1_ts, line, E1INP_TS_TYPE_TRAU);
- subch_demux_activate(&e1_ts->trau.demux, e1_link->e1_ts_ss);
- break;
- default:
- break;
- }
-
- return 0;
-}
-
-int e1_reconfig_trx(struct gsm_bts_trx *trx)
-{
- struct gsm_e1_subslot *e1_link = &trx->rsl_e1_link;
- struct e1inp_ts *sign_ts;
- struct e1inp_line *line;
- struct e1inp_sign_link *rsl_link;
- int i;
-
- if (!e1_link->e1_ts) {
- LOGP(DINP, LOGL_ERROR, "TRX (%u/%u) RSL link without "
- "timeslot?\n", trx->bts->nr, trx->nr);
- return -EINVAL;
- }
-
- /* RSL Link */
- line = e1inp_line_get(e1_link->e1_nr);
- if (!line) {
- LOGP(DINP, LOGL_ERROR, "TRX (%u/%u) RSL link referring "
- "to non-existing E1 line %u\n", trx->bts->nr,
- trx->nr, e1_link->e1_nr);
- return -ENOMEM;
- }
- sign_ts = &line->ts[e1_link->e1_ts-1];
- e1inp_ts_config(sign_ts, line, E1INP_TS_TYPE_SIGN);
- /* Ericsson RBS have a per-TRX OML link in parallel to RSL */
- if (trx->bts->type == GSM_BTS_TYPE_RBS2000) {
- struct e1inp_sign_link *oml_link;
- oml_link = e1inp_sign_link_create(sign_ts, E1INP_SIGN_OML, trx,
- trx->rsl_tei, SAPI_OML);
- if (!oml_link) {
- LOGP(DINP, LOGL_ERROR, "TRX (%u/%u) OML link creation "
- "failed\n", trx->bts->nr, trx->nr);
- return -ENOMEM;
- }
- if (trx->oml_link)
- e1inp_sign_link_destroy(trx->oml_link);
- trx->oml_link = oml_link;
- }
- rsl_link = e1inp_sign_link_create(sign_ts, E1INP_SIGN_RSL,
- trx, trx->rsl_tei, SAPI_RSL);
- if (!rsl_link) {
- LOGP(DINP, LOGL_ERROR, "TRX (%u/%u) RSL link creation "
- "failed\n", trx->bts->nr, trx->nr);
- return -ENOMEM;
- }
- if (trx->rsl_link)
- e1inp_sign_link_destroy(trx->rsl_link);
- trx->rsl_link = rsl_link;
-
- for (i = 0; i < TRX_NR_TS; i++)
- e1_reconfig_ts(&trx->ts[i]);
-
- return 0;
-}
-
-int e1_reconfig_bts(struct gsm_bts *bts)
-{
- struct gsm_e1_subslot *e1_link = &bts->oml_e1_link;
- struct e1inp_ts *sign_ts;
- struct e1inp_line *line;
- struct e1inp_sign_link *oml_link;
- struct gsm_bts_trx *trx;
-
- DEBUGP(DMI, "e1_reconfig_bts(%u)\n", bts->nr);
-
- if (!e1_link->e1_ts) {
- LOGP(DINP, LOGL_ERROR, "BTS %u OML link without timeslot?\n",
- bts->nr);
- return -EINVAL;
- }
-
- /* OML link */
- line = e1inp_line_get(e1_link->e1_nr);
- if (!line) {
- LOGP(DINP, LOGL_ERROR, "BTS %u OML link referring to "
- "non-existing E1 line %u\n", bts->nr, e1_link->e1_nr);
- return -ENOMEM;
- }
- sign_ts = &line->ts[e1_link->e1_ts-1];
- e1inp_ts_config(sign_ts, line, E1INP_TS_TYPE_SIGN);
- oml_link = e1inp_sign_link_create(sign_ts, E1INP_SIGN_OML,
- bts->c0, bts->oml_tei, SAPI_OML);
- if (!oml_link) {
- LOGP(DINP, LOGL_ERROR, "BTS %u OML link creation failed\n",
- bts->nr);
- return -ENOMEM;
- }
- if (bts->oml_link)
- e1inp_sign_link_destroy(bts->oml_link);
- bts->oml_link = oml_link;
-
- llist_for_each_entry(trx, &bts->trx_list, list)
- e1_reconfig_trx(trx);
-
- /* notify E1 input something has changed */
- return e1inp_line_update(line);
-}
-
-#if 0
-/* 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;
- struct gsm_bts_trx *trx = bts->c0;
- int base_ts;
-
- switch (bts->nr) {
- case 0:
- /* First BTS uses E1 TS 01,02,03,04,05 */
- base_ts = HARDCODED_BTS0_TS - 1;
- break;
- case 1:
- /* Second BTS uses E1 TS 06,07,08,09,10 */
- base_ts = HARDCODED_BTS1_TS - 1;
- break;
- case 2:
- /* Third BTS uses E1 TS 11,12,13,14,15 */
- base_ts = HARDCODED_BTS2_TS - 1;
- default:
- return -EINVAL;
- }
-
- line = talloc_zero(tall_bsc_ctx, struct e1inp_line);
- if (!line)
- return -ENOMEM;
-
- /* create E1 timeslots for signalling and TRAU frames */
- e1inp_ts_config(&line->ts[base_ts+1-1], line, E1INP_TS_TYPE_SIGN);
- e1inp_ts_config(&line->ts[base_ts+2-1], line, E1INP_TS_TYPE_TRAU);
- e1inp_ts_config(&line->ts[base_ts+3-1], line, E1INP_TS_TYPE_TRAU);
-
- /* create signalling links for TS1 */
- sign_ts = &line->ts[base_ts+1-1];
- oml_link = e1inp_sign_link_create(sign_ts, E1INP_SIGN_OML,
- trx, TEI_OML, SAPI_OML);
- rsl_link = e1inp_sign_link_create(sign_ts, E1INP_SIGN_RSL,
- trx, TEI_RSL, SAPI_RSL);
-
- /* create back-links from bts/trx */
- bts->oml_link = oml_link;
- trx->rsl_link = rsl_link;
-
- /* enable subchannel demuxer on TS2 */
- subch_demux_activate(&line->ts[base_ts+2-1].trau.demux, 1);
- subch_demux_activate(&line->ts[base_ts+2-1].trau.demux, 2);
- subch_demux_activate(&line->ts[base_ts+2-1].trau.demux, 3);
-
- /* enable subchannel demuxer on TS3 */
- subch_demux_activate(&line->ts[base_ts+3-1].trau.demux, 0);
- subch_demux_activate(&line->ts[base_ts+3-1].trau.demux, 1);
- subch_demux_activate(&line->ts[base_ts+3-1].trau.demux, 2);
- subch_demux_activate(&line->ts[base_ts+3-1].trau.demux, 3);
-
- trx = gsm_bts_trx_num(bts, 1);
- if (trx) {
- /* create E1 timeslots for TRAU frames of TRX1 */
- e1inp_ts_config(&line->ts[base_ts+4-1], line, E1INP_TS_TYPE_TRAU);
- e1inp_ts_config(&line->ts[base_ts+5-1], line, E1INP_TS_TYPE_TRAU);
-
- /* create RSL signalling link for TRX1 */
- sign_ts = &line->ts[base_ts+1-1];
- rsl_link = e1inp_sign_link_create(sign_ts, E1INP_SIGN_RSL,
- trx, TEI_RSL+1, SAPI_RSL);
- /* create back-links from trx */
- trx->rsl_link = rsl_link;
-
- /* enable subchannel demuxer on TS2 */
- subch_demux_activate(&line->ts[base_ts+4-1].trau.demux, 0);
- subch_demux_activate(&line->ts[base_ts+4-1].trau.demux, 1);
- subch_demux_activate(&line->ts[base_ts+4-1].trau.demux, 2);
- subch_demux_activate(&line->ts[base_ts+4-1].trau.demux, 3);
-
- /* enable subchannel demuxer on TS3 */
- subch_demux_activate(&line->ts[base_ts+5-1].trau.demux, 0);
- subch_demux_activate(&line->ts[base_ts+5-1].trau.demux, 1);
- subch_demux_activate(&line->ts[base_ts+5-1].trau.demux, 2);
- subch_demux_activate(&line->ts[base_ts+5-1].trau.demux, 3);
- }
-
- return mi_setup(cardnr, line, release_l2);
-}
-#endif
-
-/* 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 = talloc_zero(tall_bsc_ctx, struct e1inp_line);
- if (!line)
- return -ENOMEM;
-
- /* 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, 0xff, 0);
- 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/openbsc/src/bsc/gsm_04_08_utils.c b/openbsc/src/bsc/gsm_04_08_utils.c
deleted file mode 100644
index 6d12cc08e..000000000
--- a/openbsc/src/bsc/gsm_04_08_utils.c
+++ /dev/null
@@ -1,655 +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
- * utility functions
- */
-
-/* (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 Affero General Public License as published by
- * the Free Software Foundation; either version 3 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 Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- */
-#include <stdio.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <netinet/in.h>
-
-#include <osmocore/msgb.h>
-#include <osmocore/gsm48.h>
-
-#include <openbsc/abis_rsl.h>
-#include <openbsc/debug.h>
-#include <openbsc/gsm_04_08.h>
-#include <openbsc/transaction.h>
-#include <openbsc/paging.h>
-#include <openbsc/signal.h>
-
-/* should ip.access BTS use direct RTP streams between each other (1),
- * or should OpenBSC always act as RTP relay/proxy in between (0) ? */
-int ipacc_rtp_direct = 1;
-
-static int gsm48_sendmsg(struct msgb *msg)
-{
- if (msg->lchan)
- msg->trx = msg->lchan->ts->trx;
-
- msg->l3h = msg->data;
- return rsl_data_request(msg, 0);
-}
-
-/* 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_TCH_F },
- { 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_NECI1 },
- { 0x20, 0xf0, CHREQ_T_PAG_R_TCH_F },
- { 0x30, 0xf0, CHREQ_T_PAG_R_TCH_FH },
- { 0x67, 0xff, CHREQ_T_LMU },
- { 0x60, 0xf9, CHREQ_T_RESERVED_SDCCH },
- { 0x61, 0xfb, CHREQ_T_RESERVED_SDCCH },
- { 0x63, 0xff, CHREQ_T_RESERVED_SDCCH },
- { 0x7f, 0xff, CHREQ_T_RESERVED_IGNORE },
-};
-
-/* 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_NECI0 },
- { 0x20, 0xf0, CHREQ_T_PAG_R_TCH_F },
- { 0x30, 0xf0, CHREQ_T_PAG_R_TCH_FH },
- { 0x67, 0xff, CHREQ_T_LMU },
- { 0x60, 0xf9, CHREQ_T_RESERVED_SDCCH },
- { 0x61, 0xfb, CHREQ_T_RESERVED_SDCCH },
- { 0x63, 0xff, CHREQ_T_RESERVED_SDCCH },
- { 0x7f, 0xff, CHREQ_T_RESERVED_IGNORE },
-};
-
-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_NECI1] = GSM_LCHAN_SDCCH,
- [CHREQ_T_PAG_R_ANY_NECI0] = GSM_LCHAN_SDCCH,
- [CHREQ_T_PAG_R_TCH_F] = GSM_LCHAN_TCH_F,
- [CHREQ_T_PAG_R_TCH_FH] = GSM_LCHAN_TCH_F,
- [CHREQ_T_LMU] = GSM_LCHAN_SDCCH,
- [CHREQ_T_RESERVED_SDCCH] = GSM_LCHAN_SDCCH,
- [CHREQ_T_RESERVED_IGNORE] = GSM_LCHAN_UNKNOWN,
-};
-
-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_CALL,
- [CHREQ_T_DATA_CALL_TCH_H] = GSM_CHREQ_REASON_OTHER,
- [CHREQ_T_LOCATION_UPD] = GSM_CHREQ_REASON_LOCATION_UPD,
- [CHREQ_T_PAG_R_ANY_NECI1] = GSM_CHREQ_REASON_PAG,
- [CHREQ_T_PAG_R_ANY_NECI0] = GSM_CHREQ_REASON_PAG,
- [CHREQ_T_PAG_R_TCH_F] = GSM_CHREQ_REASON_PAG,
- [CHREQ_T_PAG_R_TCH_FH] = GSM_CHREQ_REASON_PAG,
- [CHREQ_T_LMU] = GSM_CHREQ_REASON_OTHER,
- [CHREQ_T_RESERVED_SDCCH] = GSM_CHREQ_REASON_OTHER,
- [CHREQ_T_RESERVED_IGNORE] = GSM_CHREQ_REASON_OTHER,
-};
-
-/* verify that the two tables match */
-static_assert(sizeof(ctype_by_chreq) ==
- sizeof(((struct gsm_network *) NULL)->ctype_by_chreq), assert_size);
-
-/*
- * Update channel types for request based on policy. E.g. in the
- * case of a TCH/H network/bsc use TCH/H for the emergency calls,
- * for early assignment assign a SDCCH and some other options.
- */
-void gsm_net_update_ctype(struct gsm_network *network)
-{
- /* copy over the data */
- memcpy(network->ctype_by_chreq, ctype_by_chreq, sizeof(ctype_by_chreq));
-
- /*
- * Use TCH/H for emergency calls when this cell allows TCH/H. Maybe it
- * is better to iterate over the BTS/TRX and check if no TCH/F is available
- * and then set it to TCH/H.
- */
- if (network->neci)
- network->ctype_by_chreq[CHREQ_T_EMERG_CALL] = GSM_LCHAN_TCH_H;
-
- if (network->pag_any_tch) {
- if (network->neci) {
- network->ctype_by_chreq[CHREQ_T_PAG_R_ANY_NECI0] = GSM_LCHAN_TCH_H;
- network->ctype_by_chreq[CHREQ_T_PAG_R_ANY_NECI1] = GSM_LCHAN_TCH_H;
- } else {
- network->ctype_by_chreq[CHREQ_T_PAG_R_ANY_NECI0] = GSM_LCHAN_TCH_F;
- network->ctype_by_chreq[CHREQ_T_PAG_R_ANY_NECI1] = GSM_LCHAN_TCH_F;
- }
- }
-}
-
-enum gsm_chan_t get_ctype_by_chreq(struct gsm_network *network, u_int8_t ra)
-{
- int i;
- int length;
- const struct chreq *chreq;
-
- if (network->neci) {
- chreq = chreq_type_neci1;
- length = ARRAY_SIZE(chreq_type_neci1);
- } else {
- chreq = chreq_type_neci0;
- length = ARRAY_SIZE(chreq_type_neci0);
- }
-
-
- for (i = 0; i < length; i++) {
- const struct chreq *chr = &chreq[i];
- if ((ra & chr->mask) == chr->val)
- return network->ctype_by_chreq[chr->type];
- }
- LOGP(DRR, LOGL_ERROR, "Unknown CHANNEL REQUEST RQD 0x%02x\n", ra);
- return GSM_LCHAN_SDCCH;
-}
-
-enum gsm_chreq_reason_t get_reason_by_chreq(u_int8_t ra, int neci)
-{
- int i;
- int length;
- const struct chreq *chreq;
-
- if (neci) {
- chreq = chreq_type_neci1;
- length = ARRAY_SIZE(chreq_type_neci1);
- } else {
- chreq = chreq_type_neci0;
- length = ARRAY_SIZE(chreq_type_neci0);
- }
-
- for (i = 0; i < length; i++) {
- const struct chreq *chr = &chreq[i];
- if ((ra & chr->mask) == chr->val)
- return reason_by_chreq[chr->type];
- }
- LOGP(DRR, LOGL_ERROR, "Unknown CHANNEL REQUEST REASON 0x%02x\n", ra);
- return GSM_CHREQ_REASON_OTHER;
-}
-
-/* 7.1.7 and 9.1.7: RR 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);
-
- /* Send actual release request to MS */
- gsm48_sendmsg(msg);
- /* FIXME: Start Timer T3109 */
-
- /* Deactivate the SACCH on the BTS side */
- return rsl_deact_sacch(lchan);
-}
-
-int send_siemens_mrpci(struct gsm_lchan *lchan,
- u_int8_t *classmark2_lv)
-{
- struct rsl_mrpci mrpci;
-
- if (classmark2_lv[0] < 2)
- return -EINVAL;
-
- mrpci.power_class = classmark2_lv[1] & 0x7;
- mrpci.vgcs_capable = classmark2_lv[2] & (1 << 1);
- mrpci.vbs_capable = classmark2_lv[2] & (1 <<2);
- mrpci.gsm_phase = (classmark2_lv[1]) >> 5 & 0x3;
-
- return rsl_siemens_mrpci(lchan, &mrpci);
-}
-
-int gsm48_extract_mi(uint8_t *classmark2_lv, int length, char *mi_string, uint8_t *mi_type)
-{
- /* Check the size for the classmark */
- if (length < 1 + *classmark2_lv)
- return -1;
-
- u_int8_t *mi_lv = classmark2_lv + *classmark2_lv + 1;
- if (length < 2 + *classmark2_lv + mi_lv[0])
- return -2;
-
- *mi_type = mi_lv[1] & GSM_MI_TYPE_MASK;
- return gsm48_mi_to_string(mi_string, GSM48_MI_SIZE, mi_lv+1, *mi_lv);
-}
-
-int gsm48_paging_extract_mi(struct gsm48_pag_resp *resp, int length,
- char *mi_string, u_int8_t *mi_type)
-{
- static const uint32_t classmark_offset =
- offsetof(struct gsm48_pag_resp, classmark2);
- u_int8_t *classmark2_lv = (uint8_t *) &resp->classmark2;
- return gsm48_extract_mi(classmark2_lv, length - classmark_offset,
- mi_string, mi_type);
-}
-
-int gsm48_handle_paging_resp(struct gsm_subscriber_connection *conn,
- struct msgb *msg, struct gsm_subscriber *subscr)
-{
- struct gsm_bts *bts = msg->lchan->ts->trx->bts;
- struct gsm48_hdr *gh = msgb_l3(msg);
- u_int8_t *classmark2_lv = gh->data + 1;
-
- if (is_siemens_bts(bts))
- send_siemens_mrpci(msg->lchan, classmark2_lv);
-
- if (!conn->subscr) {
- conn->subscr = subscr;
- } else if (conn->subscr != subscr) {
- LOGP(DRR, LOGL_ERROR, "<- 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 = conn->subscr;
- }
-
- counter_inc(bts->network->stats.paging.completed);
-
- /* Stop paging on the bts we received the paging response */
- paging_request_stop(conn->bts, subscr, conn, msg);
- return 0;
-}
-
-/* Chapter 9.1.9: Ciphering Mode Command */
-int gsm48_send_rr_ciph_mode(struct gsm_lchan *lchan, int want_imeisv)
-{
- struct msgb *msg = gsm48_msgb_alloc();
- struct gsm48_hdr *gh;
- u_int8_t ciph_mod_set;
-
- msg->lchan = lchan;
-
- DEBUGP(DRR, "TX CIPHERING MODE CMD\n");
-
- if (lchan->encr.alg_id <= RSL_ENC_ALG_A5(0))
- ciph_mod_set = 0;
- else
- ciph_mod_set = (lchan->encr.alg_id-2)<<1 | 1;
-
- gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh) + 1);
- gh->proto_discr = GSM48_PDISC_RR;
- gh->msg_type = GSM48_MT_RR_CIPH_M_CMD;
- gh->data[0] = (want_imeisv & 0x1) << 4 | (ciph_mod_set & 0xf);
-
- return rsl_encryption_cmd(msg);
-}
-
-static void gsm48_cell_desc(struct gsm48_cell_desc *cd,
- const struct gsm_bts *bts)
-{
- cd->ncc = (bts->bsic >> 3 & 0x7);
- cd->bcc = (bts->bsic & 0x7);
- cd->arfcn_hi = bts->c0->arfcn >> 8;
- cd->arfcn_lo = bts->c0->arfcn & 0xff;
-}
-
-void gsm48_lchan2chan_desc(struct gsm48_chan_desc *cd,
- const struct gsm_lchan *lchan)
-{
- u_int16_t arfcn = lchan->ts->trx->arfcn & 0x3ff;
-
- cd->chan_nr = lchan2chan_nr(lchan);
- if (!lchan->ts->hopping.enabled) {
- cd->h0.tsc = lchan->ts->trx->bts->tsc;
- cd->h0.h = 0;
- cd->h0.arfcn_high = arfcn >> 8;
- cd->h0.arfcn_low = arfcn & 0xff;
- } else {
- cd->h1.tsc = lchan->ts->trx->bts->tsc;
- cd->h1.h = 1;
- cd->h1.maio_high = lchan->ts->hopping.maio >> 2;
- cd->h1.maio_low = lchan->ts->hopping.maio & 0x03;
- cd->h1.hsn = lchan->ts->hopping.hsn;
- }
-}
-
-#define GSM48_HOCMD_CCHDESC_LEN 16
-
-/* Chapter 9.1.15: Handover Command */
-int gsm48_send_ho_cmd(struct gsm_lchan *old_lchan, struct gsm_lchan *new_lchan,
- u_int8_t power_command, u_int8_t ho_ref)
-{
- struct msgb *msg = gsm48_msgb_alloc();
- struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
- struct gsm48_ho_cmd *ho =
- (struct gsm48_ho_cmd *) msgb_put(msg, sizeof(*ho));
-
- msg->lchan = old_lchan;
- gh->proto_discr = GSM48_PDISC_RR;
- gh->msg_type = GSM48_MT_RR_HANDO_CMD;
-
- /* mandatory bits */
- gsm48_cell_desc(&ho->cell_desc, new_lchan->ts->trx->bts);
- gsm48_lchan2chan_desc(&ho->chan_desc, new_lchan);
- ho->ho_ref = ho_ref;
- ho->power_command = power_command;
-
- if (new_lchan->ts->hopping.enabled) {
- struct gsm_bts *bts = new_lchan->ts->trx->bts;
- struct gsm48_system_information_type_1 *si1;
- uint8_t *cur;
-
- si1 = GSM_BTS_SI(bts, SYSINFO_TYPE_1);
- /* Copy the Cell Chan Desc (ARFCNS in this cell) */
- msgb_put_u8(msg, GSM48_IE_CELL_CH_DESC);
- cur = msgb_put(msg, GSM48_HOCMD_CCHDESC_LEN);
- memcpy(cur, si1->cell_channel_description,
- GSM48_HOCMD_CCHDESC_LEN);
- /* Copy the Mobile Allocation */
- msgb_tlv_put(msg, GSM48_IE_MA_BEFORE,
- new_lchan->ts->hopping.ma_len,
- new_lchan->ts->hopping.ma_data);
- }
- /* FIXME: optional bits for type of synchronization? */
-
- return gsm48_sendmsg(msg);
-}
-
-/* Chapter 9.1.2: Assignment Command */
-int gsm48_send_rr_ass_cmd(struct gsm_lchan *dest_lchan, struct gsm_lchan *lchan, u_int8_t power_command)
-{
- struct msgb *msg = gsm48_msgb_alloc();
- struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
- struct gsm48_ass_cmd *ass =
- (struct gsm48_ass_cmd *) msgb_put(msg, sizeof(*ass));
-
- DEBUGP(DRR, "-> ASSIGNMENT COMMAND tch_mode=0x%02x\n", lchan->tch_mode);
-
- msg->lchan = dest_lchan;
- gh->proto_discr = GSM48_PDISC_RR;
- gh->msg_type = GSM48_MT_RR_ASS_CMD;
-
- /*
- * fill the channel information element, this code
- * should probably be shared with rsl_rx_chan_rqd(),
- * gsm48_tx_chan_mode_modify. But beware that 10.5.2.5
- * 10.5.2.5.a have slightly different semantic for
- * the chan_desc. But as long as multi-slot configurations
- * are not used we seem to be fine.
- */
- gsm48_lchan2chan_desc(&ass->chan_desc, lchan);
- ass->power_command = power_command;
-
- /* optional: cell channel description */
-
- msgb_tv_put(msg, GSM48_IE_CHANMODE_1, lchan->tch_mode);
-
- /* mobile allocation in case of hopping */
- if (lchan->ts->hopping.enabled) {
- msgb_tlv_put(msg, GSM48_IE_MA_BEFORE, lchan->ts->hopping.ma_len,
- lchan->ts->hopping.ma_data);
- }
-
- /* in case of multi rate we need to attach a config */
- if (lchan->tch_mode == GSM48_CMODE_SPEECH_AMR) {
- if (lchan->mr_conf.ver == 0) {
- LOGP(DRR, LOGL_ERROR, "BUG: Using multirate codec "
- "without multirate config.\n");
- } else {
- u_int8_t *data = msgb_put(msg, 4);
- data[0] = GSM48_IE_MUL_RATE_CFG;
- data[1] = 0x2;
- memcpy(&data[2], &lchan->mr_conf, 2);
- }
- }
-
- return gsm48_sendmsg(msg);
-}
-
-/* 9.1.5 Channel mode modify: Modify the mode on the MS side */
-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));
-
- 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() */
- gsm48_lchan2chan_desc(&cmm->chan_desc, lchan);
- cmm->mode = mode;
-
- /* in case of multi rate we need to attach a config */
- if (lchan->tch_mode == GSM48_CMODE_SPEECH_AMR) {
- if (lchan->mr_conf.ver == 0) {
- LOGP(DRR, LOGL_ERROR, "BUG: Using multirate codec "
- "without multirate config.\n");
- } else {
- u_int8_t *data = msgb_put(msg, 4);
- data[0] = GSM48_IE_MUL_RATE_CFG;
- data[1] = 0x2;
- memcpy(&data[2], &lchan->mr_conf, 2);
- }
- }
-
- return gsm48_sendmsg(msg);
-}
-
-int gsm48_lchan_modify(struct gsm_lchan *lchan, u_int8_t lchan_mode)
-{
- int rc;
-
- rc = gsm48_tx_chan_mode_modify(lchan, lchan_mode);
- if (rc < 0)
- return rc;
-
- return rc;
-}
-
-int gsm48_rx_rr_modif_ack(struct msgb *msg)
-{
- int rc;
- struct gsm48_hdr *gh = msgb_l3(msg);
- struct gsm48_chan_mode_modify *mod =
- (struct gsm48_chan_mode_modify *) gh->data;
-
- DEBUGP(DRR, "CHANNEL MODE MODIFY ACK\n");
-
- if (mod->mode != msg->lchan->tch_mode) {
- LOGP(DRR, LOGL_ERROR, "CHANNEL MODE change failed. Wanted: %d Got: %d\n",
- msg->lchan->tch_mode, mod->mode);
- return -1;
- }
-
- /* update the channel type */
- switch (mod->mode) {
- case GSM48_CMODE_SIGN:
- msg->lchan->rsl_cmode = RSL_CMOD_SPD_SIGN;
- break;
- case GSM48_CMODE_SPEECH_V1:
- case GSM48_CMODE_SPEECH_EFR:
- case GSM48_CMODE_SPEECH_AMR:
- msg->lchan->rsl_cmode = RSL_CMOD_SPD_SPEECH;
- break;
- case GSM48_CMODE_DATA_14k5:
- case GSM48_CMODE_DATA_12k0:
- case GSM48_CMODE_DATA_6k0:
- case GSM48_CMODE_DATA_3k6:
- msg->lchan->rsl_cmode = RSL_CMOD_SPD_DATA;
- break;
- }
-
- /* We've successfully modified the MS side of the channel,
- * now go on to modify the BTS side of the channel */
- rc = rsl_chan_mode_modify_req(msg->lchan);
-
- /* FIXME: we not only need to do this after mode modify, but
- * also after channel activation */
- if (is_ipaccess_bts(msg->lchan->ts->trx->bts) && mod->mode != GSM48_CMODE_SIGN)
- rsl_ipacc_crcx(msg->lchan);
- return rc;
-}
-
-int gsm48_parse_meas_rep(struct gsm_meas_rep *rep, struct msgb *msg)
-{
- struct gsm48_hdr *gh = msgb_l3(msg);
- u_int8_t *data = gh->data;
- struct gsm_bts *bts = msg->lchan->ts->trx->bts;
- struct bitvec *nbv = &bts->si_common.neigh_list;
- struct gsm_meas_rep_cell *mrc;
-
- if (gh->msg_type != GSM48_MT_RR_MEAS_REP)
- return -EINVAL;
-
- if (data[0] & 0x80)
- rep->flags |= MEAS_REP_F_BA1;
- if (data[0] & 0x40)
- rep->flags |= MEAS_REP_F_UL_DTX;
- if ((data[1] & 0x40) == 0x00)
- rep->flags |= MEAS_REP_F_DL_VALID;
-
- rep->dl.full.rx_lev = data[0] & 0x3f;
- rep->dl.sub.rx_lev = data[1] & 0x3f;
- rep->dl.full.rx_qual = (data[3] >> 4) & 0x7;
- rep->dl.sub.rx_qual = (data[3] >> 1) & 0x7;
-
- rep->num_cell = ((data[3] >> 6) & 0x3) | ((data[2] & 0x01) << 2);
- if (rep->num_cell < 1 || rep->num_cell > 6)
- return 0;
-
- /* an encoding nightmare in perfection */
- mrc = &rep->cell[0];
- mrc->rxlev = data[3] & 0x3f;
- mrc->neigh_idx = data[4] >> 3;
- mrc->arfcn = bitvec_get_nth_set_bit(nbv, mrc->neigh_idx + 1);
- mrc->bsic = ((data[4] & 0x07) << 3) | (data[5] >> 5);
- if (rep->num_cell < 2)
- return 0;
-
- mrc = &rep->cell[1];
- mrc->rxlev = ((data[5] & 0x1f) << 1) | (data[6] >> 7);
- mrc->neigh_idx = (data[6] >> 2) & 0x1f;
- mrc->arfcn = bitvec_get_nth_set_bit(nbv, mrc->neigh_idx + 1);
- mrc->bsic = ((data[6] & 0x03) << 4) | (data[7] >> 4);
- if (rep->num_cell < 3)
- return 0;
-
- mrc = &rep->cell[2];
- mrc->rxlev = ((data[7] & 0x0f) << 2) | (data[8] >> 6);
- mrc->neigh_idx = (data[8] >> 1) & 0x1f;
- mrc->arfcn = bitvec_get_nth_set_bit(nbv, mrc->neigh_idx + 1);
- mrc->bsic = ((data[8] & 0x01) << 5) | (data[9] >> 3);
- if (rep->num_cell < 4)
- return 0;
-
- mrc = &rep->cell[3];
- mrc->rxlev = ((data[9] & 0x07) << 3) | (data[10] >> 5);
- mrc->neigh_idx = data[10] & 0x1f;
- mrc->arfcn = bitvec_get_nth_set_bit(nbv, mrc->neigh_idx + 1);
- mrc->bsic = data[11] >> 2;
- if (rep->num_cell < 5)
- return 0;
-
- mrc = &rep->cell[4];
- mrc->rxlev = ((data[11] & 0x03) << 4) | (data[12] >> 4);
- mrc->neigh_idx = ((data[12] & 0xf) << 1) | (data[13] >> 7);
- mrc->arfcn = bitvec_get_nth_set_bit(nbv, mrc->neigh_idx + 1);
- mrc->bsic = (data[13] >> 1) & 0x3f;
- if (rep->num_cell < 6)
- return 0;
-
- mrc = &rep->cell[5];
- mrc->rxlev = ((data[13] & 0x01) << 5) | (data[14] >> 3);
- mrc->neigh_idx = ((data[14] & 0x07) << 2) | (data[15] >> 6);
- mrc->arfcn = bitvec_get_nth_set_bit(nbv, mrc->neigh_idx + 1);
- mrc->bsic = data[15] & 0x3f;
-
- return 0;
-}
-
-struct msgb *gsm48_create_mm_serv_rej(enum gsm48_reject_value value)
-{
- struct msgb *msg;
- struct gsm48_hdr *gh;
-
- msg = gsm48_msgb_alloc();
- if (!msg)
- return NULL;
-
- gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh) + 1);
- gh->proto_discr = GSM48_PDISC_MM;
- gh->msg_type = GSM48_MT_MM_CM_SERV_REJ;
- gh->data[0] = value;
-
- return msg;
-}
-
-struct msgb *gsm48_create_loc_upd_rej(uint8_t cause)
-{
- struct gsm48_hdr *gh;
- struct msgb *msg;
-
- msg = gsm48_msgb_alloc();
- if (!msg)
- return NULL;
-
- 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;
- return msg;
-}
diff --git a/openbsc/src/bsc/gsm_subscriber_base.c b/openbsc/src/bsc/gsm_subscriber_base.c
deleted file mode 100644
index caf84e7bb..000000000
--- a/openbsc/src/bsc/gsm_subscriber_base.c
+++ /dev/null
@@ -1,149 +0,0 @@
-/* The concept of a subscriber as seen by the BSC */
-
-/* (C) 2008 by Harald Welte <laforge@gnumonks.org>
- * (C) 2009-2010 by Holger Hans Peter Freyther <zecke@selfish.org>
- * (C) 2010 by On-Waves
- *
- * All Rights Reserved
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation; either version 3 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 Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-#include <unistd.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <assert.h>
-
-#include <osmocore/talloc.h>
-#include <openbsc/gsm_subscriber.h>
-#include <openbsc/debug.h>
-
-LLIST_HEAD(active_subscribers);
-void *tall_subscr_ctx;
-
-/* for the gsm_subscriber.c */
-struct llist_head *subscr_bsc_active_subscriber(void)
-{
- return &active_subscribers;
-}
-
-
-char *subscr_name(struct gsm_subscriber *subscr)
-{
- if (strlen(subscr->name))
- return subscr->name;
-
- return subscr->imsi;
-}
-
-struct gsm_subscriber *subscr_alloc(void)
-{
- struct gsm_subscriber *s;
-
- s = talloc_zero(tall_subscr_ctx, struct gsm_subscriber);
- if (!s)
- return NULL;
-
- llist_add_tail(&s->entry, &active_subscribers);
- s->use_count = 1;
- s->tmsi = GSM_RESERVED_TMSI;
-
- INIT_LLIST_HEAD(&s->requests);
-
- return s;
-}
-
-static void subscr_free(struct gsm_subscriber *subscr)
-{
- llist_del(&subscr->entry);
- talloc_free(subscr);
-}
-
-struct gsm_subscriber *subscr_get(struct gsm_subscriber *subscr)
-{
- subscr->use_count++;
- DEBUGP(DREF, "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(DREF, "subscr %s usage decreased usage to: %d\n",
- subscr->extension, subscr->use_count);
- if (subscr->use_count <= 0 && !subscr->net->keep_subscr)
- subscr_free(subscr);
- return NULL;
-}
-
-struct gsm_subscriber *subscr_get_or_create(struct gsm_network *net,
- const char *imsi)
-{
- struct gsm_subscriber *subscr;
-
- llist_for_each_entry(subscr, subscr_bsc_active_subscriber(), entry) {
- if (strcmp(subscr->imsi, imsi) == 0 && subscr->net == net)
- return subscr_get(subscr);
- }
-
- subscr = subscr_alloc();
- if (!subscr)
- return NULL;
-
- strcpy(subscr->imsi, imsi);
- subscr->net = net;
- return subscr;
-}
-
-struct gsm_subscriber *subscr_active_by_tmsi(struct gsm_network *net, uint32_t tmsi)
-{
- struct gsm_subscriber *subscr;
-
- llist_for_each_entry(subscr, subscr_bsc_active_subscriber(), entry) {
- if (subscr->tmsi == tmsi && subscr->net == net)
- return subscr_get(subscr);
- }
-
- return NULL;
-}
-
-struct gsm_subscriber *subscr_active_by_imsi(struct gsm_network *net, const char *imsi)
-{
- struct gsm_subscriber *subscr;
-
- llist_for_each_entry(subscr, subscr_bsc_active_subscriber(), entry) {
- if (strcmp(subscr->imsi, imsi) == 0 && subscr->net == net)
- return subscr_get(subscr);
- }
-
- return NULL;
-}
-
-int subscr_purge_inactive(struct gsm_network *net)
-{
- struct gsm_subscriber *subscr, *tmp;
- int purged = 0;
-
- llist_for_each_entry_safe(subscr, tmp, subscr_bsc_active_subscriber(), entry) {
- if (subscr->net == net && subscr->use_count <= 0) {
- subscr_free(subscr);
- purged += 1;
- }
- }
-
- return purged;
-}
diff --git a/openbsc/src/bsc/handover_decision.c b/openbsc/src/bsc/handover_decision.c
deleted file mode 100644
index d3f843afb..000000000
--- a/openbsc/src/bsc/handover_decision.c
+++ /dev/null
@@ -1,297 +0,0 @@
-/* Handover Decision making for Inter-BTS (Intra-BSC) Handover. This
- * only implements the handover algorithm/decision, but not execution
- * of it */
-
-/* (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 Affero General Public License as published by
- * the Free Software Foundation; either version 3 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 Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-#include <stdlib.h>
-#include <errno.h>
-
-#include <osmocore/msgb.h>
-#include <openbsc/debug.h>
-#include <openbsc/gsm_data.h>
-#include <openbsc/meas_rep.h>
-#include <openbsc/signal.h>
-#include <osmocore/talloc.h>
-#include <openbsc/handover.h>
-#include <osmocore/gsm_utils.h>
-
-/* issue handover to a cell identified by ARFCN and BSIC */
-static int handover_to_arfcn_bsic(struct gsm_lchan *lchan,
- u_int16_t arfcn, u_int8_t bsic)
-{
- struct gsm_bts *new_bts;
-
- /* resolve the gsm_bts structure for the best neighbor */
- new_bts = gsm_bts_neighbor(lchan->ts->trx->bts, arfcn, bsic);
- if (!new_bts) {
- LOGP(DHO, LOGL_NOTICE, "unable to determine neighbor BTS "
- "for ARFCN %u BSIC %u ?!?\n", arfcn, bsic);
- return -EINVAL;
- }
-
- /* and actually try to handover to that cell */
- return bsc_handover_start(lchan, new_bts);
-}
-
-/* did we get a RXLEV for a given cell in the given report? */
-static int rxlev_for_cell_in_rep(struct gsm_meas_rep *mr,
- u_int16_t arfcn, u_int8_t bsic)
-{
- int i;
-
- for (i = 0; i < mr->num_cell; i++) {
- struct gsm_meas_rep_cell *mrc = &mr->cell[i];
-
- /* search for matching report */
- if (!(mrc->arfcn == arfcn && mrc->bsic == bsic))
- continue;
-
- mrc->flags |= MRC_F_PROCESSED;
- return mrc->rxlev;
- }
- return -ENODEV;
-}
-
-/* obtain averaged rxlev for given neighbor */
-static int neigh_meas_avg(struct neigh_meas_proc *nmp, int window)
-{
- unsigned int i, idx;
- int avg = 0;
-
- idx = calc_initial_idx(ARRAY_SIZE(nmp->rxlev),
- nmp->rxlev_cnt % ARRAY_SIZE(nmp->rxlev),
- window);
-
- for (i = 0; i < window; i++) {
- int j = (idx+i) % ARRAY_SIZE(nmp->rxlev);
-
- avg += nmp->rxlev[j];
- }
-
- return avg / window;
-}
-
-/* find empty or evict bad neighbor */
-static struct neigh_meas_proc *find_evict_neigh(struct gsm_lchan *lchan)
-{
- int j, worst = 999999;
- struct neigh_meas_proc *nmp_worst;
-
- /* first try to find an empty/unused slot */
- for (j = 0; j < ARRAY_SIZE(lchan->neigh_meas); j++) {
- struct neigh_meas_proc *nmp = &lchan->neigh_meas[j];
- if (!nmp->arfcn)
- return nmp;
- }
-
- /* no empty slot found. evict worst neighbor from list */
- for (j = 0; j < ARRAY_SIZE(lchan->neigh_meas); j++) {
- struct neigh_meas_proc *nmp = &lchan->neigh_meas[j];
- int avg = neigh_meas_avg(nmp, MAX_WIN_NEIGH_AVG);
- if (avg < worst) {
- worst = avg;
- nmp_worst = nmp;
- }
- }
-
- return nmp_worst;
-}
-
-/* process neighbor cell measurement reports */
-static void process_meas_neigh(struct gsm_meas_rep *mr)
-{
- int i, j, idx;
-
- /* for each reported cell, try to update global state */
- for (j = 0; j < ARRAY_SIZE(mr->lchan->neigh_meas); j++) {
- struct neigh_meas_proc *nmp = &mr->lchan->neigh_meas[j];
- unsigned int idx;
- int rxlev;
-
- /* skip unused entries */
- if (!nmp->arfcn)
- continue;
-
- rxlev = rxlev_for_cell_in_rep(mr, nmp->arfcn, nmp->bsic);
- idx = nmp->rxlev_cnt % ARRAY_SIZE(nmp->rxlev);
- if (rxlev >= 0) {
- nmp->rxlev[idx] = rxlev;
- nmp->last_seen_nr = mr->nr;
- } else
- nmp->rxlev[idx] = 0;
- nmp->rxlev_cnt++;
- }
-
- /* iterate over list of reported cells, check if we did not
- * process all of them */
- for (i = 0; i < mr->num_cell; i++) {
- struct gsm_meas_rep_cell *mrc = &mr->cell[i];
- struct neigh_meas_proc *nmp;
-
- if (mrc->flags & MRC_F_PROCESSED)
- continue;
-
- nmp = find_evict_neigh(mr->lchan);
-
- nmp->arfcn = mrc->arfcn;
- nmp->bsic = mrc->bsic;
-
- idx = nmp->rxlev_cnt % ARRAY_SIZE(nmp->rxlev);
- nmp->rxlev[idx] = mrc->rxlev;
- nmp->rxlev_cnt++;
- nmp->last_seen_nr = mr->nr;
-
- mrc->flags |= MRC_F_PROCESSED;
- }
-}
-
-/* attempt to do a handover */
-static int attempt_handover(struct gsm_meas_rep *mr)
-{
- struct gsm_network *net = mr->lchan->ts->trx->bts->network;
- struct neigh_meas_proc *best_cell = NULL;
- unsigned int best_better_db = 0;
- int i, rc;
-
- /* find the best cell in this report that is at least RXLEV_HYST
- * better than the current serving cell */
-
- for (i = 0; i < ARRAY_SIZE(mr->lchan->neigh_meas); i++) {
- struct neigh_meas_proc *nmp = &mr->lchan->neigh_meas[i];
- int avg, better;
-
- /* skip empty slots */
- if (nmp->arfcn == 0)
- continue;
-
- /* caculate average rxlev for this cell over the window */
- avg = neigh_meas_avg(nmp, net->handover.win_rxlev_avg_neigh);
-
- /* check if hysteresis is fulfilled */
- if (avg < mr->dl.full.rx_lev + net->handover.pwr_hysteresis)
- continue;
-
- better = avg - mr->dl.full.rx_lev;
- if (better > best_better_db) {
- best_cell = nmp;
- best_better_db = better;
- }
- }
-
- if (!best_cell)
- return 0;
-
- LOGP(DHO, LOGL_INFO, "%s: Cell on ARFCN %u is better: ",
- gsm_ts_name(mr->lchan->ts), best_cell->arfcn);
- if (!net->handover.active) {
- LOGPC(DHO, LOGL_INFO, "Skipping, Handover disabled\n");
- return 0;
- }
-
- rc = handover_to_arfcn_bsic(mr->lchan, best_cell->arfcn, best_cell->bsic);
- switch (rc) {
- case 0:
- LOGPC(DHO, LOGL_INFO, "Starting handover\n");
- break;
- case -ENOSPC:
- LOGPC(DHO, LOGL_INFO, "No channel available\n");
- break;
- case -EBUSY:
- LOGPC(DHO, LOGL_INFO, "Handover already active\n");
- break;
- default:
- LOGPC(DHO, LOGL_ERROR, "Unknown error\n");
- }
- return rc;
-}
-
-/* process an already parsed measurement report and decide if we want to
- * attempt a handover */
-static int process_meas_rep(struct gsm_meas_rep *mr)
-{
- struct gsm_network *net = mr->lchan->ts->trx->bts->network;
- int av_rxlev;
-
- /* we currently only do handover for TCH channels */
- switch (mr->lchan->type) {
- case GSM_LCHAN_TCH_F:
- case GSM_LCHAN_TCH_H:
- break;
- default:
- return 0;
- }
-
- /* parse actual neighbor cell info */
- if (mr->num_cell > 0 && mr->num_cell < 7)
- process_meas_neigh(mr);
-
- av_rxlev = get_meas_rep_avg(mr->lchan, MEAS_REP_DL_RXLEV_FULL,
- net->handover.win_rxlev_avg);
-
- /* Interference HO */
- if (rxlev2dbm(av_rxlev) > -85 &&
- meas_rep_n_out_of_m_be(mr->lchan, MEAS_REP_DL_RXQUAL_FULL,
- 3, 4, 5))
- return attempt_handover(mr);
-
- /* Bad Quality */
- if (meas_rep_n_out_of_m_be(mr->lchan, MEAS_REP_DL_RXQUAL_FULL,
- 3, 4, 5))
- return attempt_handover(mr);
-
- /* Low Level */
- if (rxlev2dbm(av_rxlev) <= -110)
- return attempt_handover(mr);
-
- /* Distance */
- if (mr->ms_l1.ta > net->handover.max_distance)
- return attempt_handover(mr);
-
- /* Power Budget AKA Better Cell */
- if ((mr->nr % net->handover.pwr_interval) == 0)
- return attempt_handover(mr);
-
- return 0;
-
-}
-
-static int ho_dec_sig_cb(unsigned int subsys, unsigned int signal,
- void *handler_data, void *signal_data)
-{
- struct lchan_signal_data *lchan_data;
-
- if (subsys != SS_LCHAN)
- return 0;
-
- lchan_data = signal_data;
- switch (signal) {
- case S_LCHAN_MEAS_REP:
- process_meas_rep(lchan_data->mr);
- break;
- }
-
- return 0;
-}
-
-void on_dso_load_ho_dec(void)
-{
- register_signal_handler(SS_LCHAN, ho_dec_sig_cb, NULL);
-}
diff --git a/openbsc/src/bsc/handover_logic.c b/openbsc/src/bsc/handover_logic.c
deleted file mode 100644
index c2e3f8c72..000000000
--- a/openbsc/src/bsc/handover_logic.c
+++ /dev/null
@@ -1,393 +0,0 @@
-/* Handover Logic for Inter-BTS (Intra-BSC) Handover. This does not
- * actually implement the handover algorithm/decision, but executes a
- * handover decision */
-
-/* (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 Affero General Public License as published by
- * the Free Software Foundation; either version 3 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 Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-#include <time.h>
-#include <netinet/in.h>
-
-#include <osmocore/msgb.h>
-#include <openbsc/debug.h>
-#include <openbsc/gsm_data.h>
-#include <osmocore/gsm_utils.h>
-#include <openbsc/gsm_subscriber.h>
-#include <openbsc/gsm_04_08.h>
-#include <openbsc/abis_rsl.h>
-#include <openbsc/chan_alloc.h>
-#include <openbsc/signal.h>
-#include <osmocore/talloc.h>
-#include <openbsc/transaction.h>
-#include <openbsc/rtp_proxy.h>
-
-struct bsc_handover {
- struct llist_head list;
-
- struct gsm_lchan *old_lchan;
- struct gsm_lchan *new_lchan;
-
- struct timer_list T3103;
-
- u_int8_t ho_ref;
-};
-
-static LLIST_HEAD(bsc_handovers);
-
-static struct bsc_handover *bsc_ho_by_new_lchan(struct gsm_lchan *new_lchan)
-{
- struct bsc_handover *ho;
-
- llist_for_each_entry(ho, &bsc_handovers, list) {
- if (ho->new_lchan == new_lchan)
- return ho;
- }
-
- return NULL;
-}
-
-static struct bsc_handover *bsc_ho_by_old_lchan(struct gsm_lchan *old_lchan)
-{
- struct bsc_handover *ho;
-
- llist_for_each_entry(ho, &bsc_handovers, list) {
- if (ho->old_lchan == old_lchan)
- return ho;
- }
-
- return NULL;
-}
-
-/* Hand over the specified logical channel to the specified new BTS.
- * This is the main entry point for the actual handover algorithm,
- * after it has decided it wants to initiate HO to a specific BTS */
-int bsc_handover_start(struct gsm_lchan *old_lchan, struct gsm_bts *bts)
-{
- struct gsm_lchan *new_lchan;
- struct bsc_handover *ho;
- static u_int8_t ho_ref;
- int rc;
-
- /* don't attempt multiple handovers for the same lchan at
- * the same time */
- if (bsc_ho_by_old_lchan(old_lchan))
- return -EBUSY;
-
- DEBUGP(DHO, "(old_lchan on BTS %u, new BTS %u)\n",
- old_lchan->ts->trx->bts->nr, bts->nr);
-
- counter_inc(bts->network->stats.handover.attempted);
-
- if (!old_lchan->conn) {
- LOGP(DHO, LOGL_ERROR, "Old lchan lacks connection data.\n");
- return -ENOSPC;
- }
-
- new_lchan = lchan_alloc(bts, old_lchan->type, 0);
- if (!new_lchan) {
- LOGP(DHO, LOGL_NOTICE, "No free channel\n");
- counter_inc(bts->network->stats.handover.no_channel);
- return -ENOSPC;
- }
-
- ho = talloc_zero(tall_bsc_ctx, struct bsc_handover);
- if (!ho) {
- LOGP(DHO, LOGL_FATAL, "Out of Memory\n");
- lchan_free(new_lchan);
- return -ENOMEM;
- }
- ho->old_lchan = old_lchan;
- ho->new_lchan = new_lchan;
- ho->ho_ref = ho_ref++;
-
- /* copy some parameters from old lchan */
- memcpy(&new_lchan->encr, &old_lchan->encr, sizeof(new_lchan->encr));
- new_lchan->ms_power = old_lchan->ms_power;
- new_lchan->bs_power = old_lchan->bs_power;
- new_lchan->rsl_cmode = old_lchan->rsl_cmode;
- new_lchan->tch_mode = old_lchan->tch_mode;
-
- new_lchan->conn = old_lchan->conn;
- new_lchan->conn->ho_lchan = new_lchan;
-
- /* FIXME: do we have a better idea of the timing advance? */
- rc = rsl_chan_activate_lchan(new_lchan, RSL_ACT_INTER_ASYNC, 0,
- ho->ho_ref);
- if (rc < 0) {
- LOGP(DHO, LOGL_ERROR, "could not activate channel\n");
- new_lchan->conn->ho_lchan = NULL;
- new_lchan->conn = NULL;
- talloc_free(ho);
- lchan_free(new_lchan);
- return rc;
- }
-
- rsl_lchan_set_state(new_lchan, LCHAN_S_ACT_REQ);
- llist_add(&ho->list, &bsc_handovers);
- /* we continue in the SS_LCHAN handler / ho_chan_activ_ack */
-
- return 0;
-}
-
-void bsc_clear_handover(struct gsm_subscriber_connection *conn, int free_lchan)
-{
- struct bsc_handover *ho;
-
- ho = bsc_ho_by_new_lchan(conn->ho_lchan);
-
-
- if (!ho && conn->ho_lchan)
- LOGP(DHO, LOGL_ERROR, "BUG: We lost some state.\n");
-
- if (!ho) {
- LOGP(DHO, LOGL_ERROR, "unable to find HO record\n");
- return;
- }
-
- conn->ho_lchan->conn = NULL;
- conn->ho_lchan = NULL;
-
- if (free_lchan)
- lchan_release(ho->new_lchan, 0, 1);
-
- bsc_del_timer(&ho->T3103);
- llist_del(&ho->list);
- talloc_free(ho);
-}
-
-/* T3103 expired: Handover has failed without HO COMPLETE or HO FAIL */
-static void ho_T3103_cb(void *_ho)
-{
- struct bsc_handover *ho = _ho;
- struct gsm_network *net = ho->new_lchan->ts->trx->bts->network;
-
- DEBUGP(DHO, "HO T3103 expired\n");
- counter_inc(net->stats.handover.timeout);
-
- ho->new_lchan->conn->ho_lchan = NULL;
- ho->new_lchan->conn = NULL;
- lchan_release(ho->new_lchan, 0, 1);
- llist_del(&ho->list);
- talloc_free(ho);
-}
-
-/* RSL has acknowledged activation of the new lchan */
-static int ho_chan_activ_ack(struct gsm_lchan *new_lchan)
-{
- struct bsc_handover *ho;
- int rc;
-
- /* we need to check if this channel activation is related to
- * a handover at all (and if, which particular handover) */
- ho = bsc_ho_by_new_lchan(new_lchan);
- if (!ho)
- return -ENODEV;
-
- DEBUGP(DHO, "handover activate ack, send HO Command\n");
-
- /* we can now send the 04.08 HANDOVER COMMAND to the MS
- * using the old lchan */
-
- rc = gsm48_send_ho_cmd(ho->old_lchan, new_lchan, 0, ho->ho_ref);
-
- /* start T3103. We can continue either with T3103 expiration,
- * 04.08 HANDOVER COMPLETE or 04.08 HANDOVER FAIL */
- ho->T3103.cb = ho_T3103_cb;
- ho->T3103.data = ho;
- bsc_schedule_timer(&ho->T3103, 10, 0);
-
- /* create a RTP connection */
- if (is_ipaccess_bts(new_lchan->ts->trx->bts))
- rsl_ipacc_crcx(new_lchan);
-
- return 0;
-}
-
-/* RSL has not acknowledged activation of the new lchan */
-static int ho_chan_activ_nack(struct gsm_lchan *new_lchan)
-{
- struct bsc_handover *ho;
-
- ho = bsc_ho_by_new_lchan(new_lchan);
- if (!ho) {
- LOGP(DHO, LOGL_ERROR, "unable to find HO record\n");
- return -ENODEV;
- }
-
- new_lchan->conn->ho_lchan = NULL;
- new_lchan->conn = NULL;
- llist_del(&ho->list);
- talloc_free(ho);
-
- /* FIXME: maybe we should try to allocate a new LCHAN here? */
-
- return 0;
-}
-
-/* GSM 04.08 HANDOVER COMPLETE has been received on new channel */
-static int ho_gsm48_ho_compl(struct gsm_lchan *new_lchan)
-{
- struct gsm_network *net;
- struct bsc_handover *ho;
-
- ho = bsc_ho_by_new_lchan(new_lchan);
- if (!ho) {
- LOGP(DHO, LOGL_ERROR, "unable to find HO record\n");
- return -ENODEV;
- }
-
- net = new_lchan->ts->trx->bts->network;
- LOGP(DHO, LOGL_INFO, "Subscriber %s HO from BTS %u->%u on ARFCN "
- "%u->%u\n", subscr_name(ho->old_lchan->conn->subscr),
- ho->old_lchan->ts->trx->bts->nr, new_lchan->ts->trx->bts->nr,
- ho->old_lchan->ts->trx->arfcn, new_lchan->ts->trx->arfcn);
-
- counter_inc(net->stats.handover.completed);
-
- bsc_del_timer(&ho->T3103);
-
- /* Replace the ho lchan with the primary one */
- if (ho->old_lchan != new_lchan->conn->lchan)
- LOGP(DHO, LOGL_ERROR, "Primary lchan changed during handover.\n");
-
- if (new_lchan != new_lchan->conn->ho_lchan)
- LOGP(DHO, LOGL_ERROR, "Handover channel changed during this handover.\n");
-
- new_lchan->conn->ho_lchan = NULL;
- new_lchan->conn->lchan = new_lchan;
- ho->old_lchan->conn = NULL;
-
- rsl_lchan_set_state(ho->old_lchan, LCHAN_S_INACTIVE);
- lchan_release(ho->old_lchan, 0, 1);
-
- /* do something to re-route the actual speech frames ! */
-
- llist_del(&ho->list);
- talloc_free(ho);
-
- return 0;
-}
-
-/* GSM 04.08 HANDOVER FAIL has been received */
-static int ho_gsm48_ho_fail(struct gsm_lchan *old_lchan)
-{
- struct gsm_network *net = old_lchan->ts->trx->bts->network;
- struct bsc_handover *ho;
-
- ho = bsc_ho_by_old_lchan(old_lchan);
- if (!ho) {
- LOGP(DHO, LOGL_ERROR, "unable to find HO record\n");
- return -ENODEV;
- }
-
- counter_inc(net->stats.handover.failed);
-
- bsc_del_timer(&ho->T3103);
- llist_del(&ho->list);
-
- /* release the channel and forget about it */
- ho->new_lchan->conn->ho_lchan = NULL;
- ho->new_lchan->conn = NULL;
- lchan_release(ho->new_lchan, 0, 1);
-
- talloc_free(ho);
-
- return 0;
-}
-
-/* GSM 08.58 HANDOVER DETECT has been received */
-static int ho_rsl_detect(struct gsm_lchan *new_lchan)
-{
- struct bsc_handover *ho;
-
- ho = bsc_ho_by_new_lchan(new_lchan);
- if (!ho) {
- LOGP(DHO, LOGL_ERROR, "unable to find HO record\n");
- return -ENODEV;
- }
-
- /* FIXME: do we actually want to do something here ? */
-
- return 0;
-}
-
-static int ho_ipac_crcx_ack(struct gsm_lchan *new_lchan)
-{
- struct bsc_handover *ho;
- struct ho_signal_data sig_ho;
-
- ho = bsc_ho_by_new_lchan(new_lchan);
- if (!ho) {
- /* it is perfectly normal, we have CRCX even in non-HO cases */
- return 0;
- }
-
- sig_ho.old_lchan = ho->old_lchan;
- sig_ho.new_lchan = new_lchan;
- dispatch_signal(SS_HO, S_HANDOVER_ACK, &sig_ho);
- return 0;
-}
-
-static int ho_logic_sig_cb(unsigned int subsys, unsigned int signal,
- void *handler_data, void *signal_data)
-{
- struct lchan_signal_data *lchan_data;
- struct gsm_lchan *lchan;
-
- lchan_data = signal_data;
- switch (subsys) {
- case SS_LCHAN:
- lchan = lchan_data->lchan;
- switch (signal) {
- case S_LCHAN_ACTIVATE_ACK:
- return ho_chan_activ_ack(lchan);
- case S_LCHAN_ACTIVATE_NACK:
- return ho_chan_activ_nack(lchan);
- case S_LCHAN_HANDOVER_DETECT:
- return ho_rsl_detect(lchan);
- case S_LCHAN_HANDOVER_COMPL:
- return ho_gsm48_ho_compl(lchan);
- case S_LCHAN_HANDOVER_FAIL:
- return ho_gsm48_ho_fail(lchan);
- }
- break;
- case SS_ABISIP:
- lchan = signal_data;
- switch (signal) {
- case S_ABISIP_CRCX_ACK:
- return ho_ipac_crcx_ack(lchan);
- break;
- }
- break;
- default:
- break;
- }
-
- return 0;
-}
-
-static __attribute__((constructor)) void on_dso_load_ho_logic(void)
-{
- register_signal_handler(SS_LCHAN, ho_logic_sig_cb, NULL);
- register_signal_handler(SS_ABISIP, ho_logic_sig_cb, NULL);
-}
diff --git a/openbsc/src/bsc/meas_proc.c b/openbsc/src/bsc/meas_proc.c
deleted file mode 100644
index ade1f2e0c..000000000
--- a/openbsc/src/bsc/meas_proc.c
+++ /dev/null
@@ -1,84 +0,0 @@
-/* Measurement Processing */
-
-/* (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 Affero General Public License as published by
- * the Free Software Foundation; either version 3 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 Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-#include <stdlib.h>
-#include <errno.h>
-
-#include <osmocore/talloc.h>
-#include <osmocore/msgb.h>
-#include <openbsc/debug.h>
-#include <openbsc/gsm_data.h>
-#include <openbsc/meas_rep.h>
-#include <openbsc/signal.h>
-
-/* process an already parsed measurement report */
-static int process_meas_rep(struct gsm_meas_rep *mr)
-{
- struct gsm_meas_rep_cell *mr_cell = NULL;
- unsigned int best_better_db;
- int i;
-
- /* FIXME: implement actual averaging over multiple measurement
- * reports */
-
- /* find the best cell in this report that is at least RXLEV_HYST
- * better than the current serving cell */
- for (i = 0; i < mr->num_cell; i++) {
- unsigned int better;
- if (mr->cell[i].rxlev < mr->dl.full.rx_lev + RXLEV_HYST)
- continue;
-
- better = mr->cell[i].rxlev - mr->dl.full.rx_lev;
- if (better > best_better_db) {
- mr_cell = &mr->cell[i];
- best_better_db = better;
- }
- }
-
- if (mr_cell)
- return handover_to_arfcn_bsic(mr->lchan, mr_cell->arfcn,
- mr_cell->bsic);
- return 0;
-}
-
-static int meas_proc_sig_cb(unsigned int subsys, unsigned int signal,
- void *handler_data, void *signal_data)
-{
- struct gsm_lchan *lchan;
- struct gsm_meas_rep *mr;
-
- if (subsys != SS_LCHAN)
- return 0;
-
- switch (signal) {
- case S_LCHAN_MEAS_REP:
- mr = signal_data;
- process_meas_rep(mr);
- break;
- }
-
- return 0;
-}
-
-static __attribute__((constructor)) void on_dso_load_meas(void)
-{
- register_signal_handler(SS_LCHAN, meas_proc_sig_cb, NULL);
-}
diff --git a/openbsc/src/bsc/meas_rep.c b/openbsc/src/bsc/meas_rep.c
deleted file mode 100644
index 788a9baed..000000000
--- a/openbsc/src/bsc/meas_rep.c
+++ /dev/null
@@ -1,116 +0,0 @@
-/* Measurement Report Processing */
-
-/* (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 Affero General Public License as published by
- * the Free Software Foundation; either version 3 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 Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-#include <sys/types.h>
-
-#include <openbsc/gsm_data.h>
-#include <openbsc/meas_rep.h>
-
-static int get_field(const struct gsm_meas_rep *rep,
- enum meas_rep_field field)
-{
- switch (field) {
- case MEAS_REP_DL_RXLEV_FULL:
- return rep->dl.full.rx_lev;
- case MEAS_REP_DL_RXLEV_SUB:
- return rep->dl.sub.rx_lev;
- case MEAS_REP_DL_RXQUAL_FULL:
- return rep->dl.full.rx_qual;
- case MEAS_REP_DL_RXQUAL_SUB:
- return rep->dl.sub.rx_qual;
- case MEAS_REP_UL_RXLEV_FULL:
- return rep->ul.full.rx_lev;
- case MEAS_REP_UL_RXLEV_SUB:
- return rep->ul.sub.rx_lev;
- case MEAS_REP_UL_RXQUAL_FULL:
- return rep->ul.full.rx_qual;
- case MEAS_REP_UL_RXQUAL_SUB:
- return rep->ul.sub.rx_qual;
- }
-
- return 0;
-}
-
-
-unsigned int calc_initial_idx(unsigned int array_size,
- unsigned int meas_rep_idx,
- unsigned int num_values)
-{
- int offs, idx;
-
- /* from which element do we need to start if we're interested
- * in an average of 'num' elements */
- offs = meas_rep_idx - num_values;
-
- if (offs < 0)
- idx = array_size + offs;
- else
- idx = offs;
-
- return idx;
-}
-
-/* obtain an average over the last 'num' fields in the meas reps */
-int get_meas_rep_avg(const struct gsm_lchan *lchan,
- enum meas_rep_field field, unsigned int num)
-{
- unsigned int i, idx;
- int avg = 0;
-
- if (num < 1)
- return 0;
-
- idx = calc_initial_idx(ARRAY_SIZE(lchan->meas_rep),
- lchan->meas_rep_idx, num);
-
- for (i = 0; i < num; i++) {
- int j = (idx+i) % ARRAY_SIZE(lchan->meas_rep);
-
- avg += get_field(&lchan->meas_rep[j], field);
- }
-
- return avg / num;
-}
-
-/* Check if N out of M last values for FIELD are >= bd */
-int meas_rep_n_out_of_m_be(const struct gsm_lchan *lchan,
- enum meas_rep_field field,
- unsigned int n, unsigned int m, int be)
-{
- unsigned int i, idx;
- int count = 0;
-
- idx = calc_initial_idx(ARRAY_SIZE(lchan->meas_rep),
- lchan->meas_rep_idx, m);
-
- for (i = 0; i < m; i++) {
- int j = (idx + i) % ARRAY_SIZE(lchan->meas_rep);
- int val = get_field(&lchan->meas_rep[j], field);
-
- if (val >= be)
- count++;
-
- if (count >= n)
- return 1;
- }
-
- return 0;
-}
diff --git a/openbsc/src/bsc/paging.c b/openbsc/src/bsc/paging.c
deleted file mode 100644
index 650254575..000000000
--- a/openbsc/src/bsc/paging.c
+++ /dev/null
@@ -1,395 +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 Affero General Public License as published by
- * the Free Software Foundation; either version 3 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 Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-/*
- * 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 <osmocore/talloc.h>
-#include <openbsc/debug.h>
-#include <openbsc/signal.h>
-#include <openbsc/abis_rsl.h>
-#include <openbsc/gsm_data.h>
-#include <openbsc/chan_alloc.h>
-#include <openbsc/bsc_api.h>
-
-void *tall_paging_ctx;
-
-#define PAGING_TIMER 0, 500000
-
-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->si_common.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)
-{
- bsc_del_timer(&to_be_deleted->T3113);
- llist_del(&to_be_deleted->entry);
- subscr_put(to_be_deleted->subscr);
- talloc_free(to_be_deleted);
-}
-
-static void page_ms(struct gsm_paging_request *request)
-{
- u_int8_t mi[128];
- unsigned int mi_len;
- unsigned int page_group;
-
- LOGP(DPAG, LOGL_INFO, "Going to send paging commands: imsi: '%s' tmsi: '0x%x'\n",
- request->subscr->imsi, request->subscr->tmsi);
-
- if (request->subscr->tmsi == GSM_RESERVED_TMSI)
- mi_len = gsm48_generate_mid_from_imsi(mi, request->subscr->imsi);
- else
- mi_len = gsm48_generate_mid_from_tmsi(mi, request->subscr->tmsi);
-
- page_group = calculate_group(request->bts, request->subscr);
- gsm0808_page(request->bts, page_group, mi_len, mi, request->chan_type);
-}
-
-static void paging_schedule_if_needed(struct gsm_bts_paging_state *paging_bts)
-{
- if (llist_empty(&paging_bts->pending_requests))
- return;
-
- if (!bsc_timer_pending(&paging_bts->work_timer))
- bsc_schedule_timer(&paging_bts->work_timer, PAGING_TIMER);
-}
-
-
-static void paging_handle_pending_requests(struct gsm_bts_paging_state *paging_bts);
-static void paging_give_credit(void *data)
-{
- struct gsm_bts_paging_state *paging_bts = data;
-
- LOGP(DPAG, LOGL_NOTICE, "No slots available on bts nr %d\n", paging_bts->bts->nr);
- paging_bts->available_slots = 20;
- paging_handle_pending_requests(paging_bts);
-}
-
-static int can_send_pag_req(struct gsm_bts *bts, int rsl_type)
-{
- struct pchan_load pl;
- int count;
-
- memset(&pl, 0, sizeof(pl));
- bts_chan_load(&pl, bts);
-
- switch (rsl_type) {
- case RSL_CHANNEED_TCH_F:
- case RSL_CHANNEED_TCH_ForH:
- goto count_tch;
- break;
- case RSL_CHANNEED_SDCCH:
- goto count_sdcch;
- break;
- case RSL_CHANNEED_ANY:
- default:
- if (bts->network->pag_any_tch)
- goto count_tch;
- else
- goto count_sdcch;
- break;
- }
-
- return 0;
-
- /* could available SDCCH */
-count_sdcch:
- count = 0;
- count += pl.pchan[GSM_PCHAN_SDCCH8_SACCH8C].total
- - pl.pchan[GSM_PCHAN_SDCCH8_SACCH8C].used;
- count += pl.pchan[GSM_PCHAN_CCCH_SDCCH4].total
- - pl.pchan[GSM_PCHAN_CCCH_SDCCH4].used;
- return bts->paging.free_chans_need > count;
-
-count_tch:
- count = 0;
- count += pl.pchan[GSM_PCHAN_TCH_F].total
- - pl.pchan[GSM_PCHAN_TCH_F].used;
- if (bts->network->neci)
- count += pl.pchan[GSM_PCHAN_TCH_H].total
- - pl.pchan[GSM_PCHAN_TCH_H].used;
- return bts->paging.free_chans_need > count;
-}
-
-/*
- * 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 *request = NULL;
-
- /*
- * Determine if the pending_requests list is empty and
- * return then.
- */
- if (llist_empty(&paging_bts->pending_requests)) {
- /* since the list is empty, no need to reschedule the timer */
- return;
- }
-
- /*
- * In case the BTS does not provide us with load indication and we
- * ran out of slots, call an autofill routine. It might be that the
- * BTS did not like our paging messages and then we have counted down
- * to zero and we do not get any messages.
- */
- if (paging_bts->available_slots == 0) {
- paging_bts->credit_timer.cb = paging_give_credit;
- paging_bts->credit_timer.data = paging_bts;
- bsc_schedule_timer(&paging_bts->credit_timer, 5, 0);
- return;
- }
-
- request = llist_entry(paging_bts->pending_requests.next,
- struct gsm_paging_request, entry);
-
- /* we need to determine the number of free channels */
- if (paging_bts->free_chans_need != -1) {
- if (can_send_pag_req(request->bts, request->chan_type) != 0)
- goto skip_paging;
- }
-
- /* handle the paging request now */
- page_ms(request);
- paging_bts->available_slots--;
- request->attempts++;
-
- /* take the current and add it to the back */
- llist_del(&request->entry);
- llist_add_tail(&request->entry, &paging_bts->pending_requests);
-
-skip_paging:
- bsc_schedule_timer(&paging_bts->work_timer, PAGING_TIMER);
-}
-
-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 = 20;
-}
-
-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;
- void *cbfn_param;
- gsm_cbfn *cbfn;
- int msg;
-
- LOGP(DPAG, LOGL_INFO, "T3113 expired for request %p (%s)\n",
- req, req->subscr->imsi);
-
- /* must be destroyed before calling cbfn, to prevent double free */
- counter_inc(req->bts->network->stats.paging.expired);
- cbfn_param = req->cbfn_param;
- cbfn = req->cbfn;
-
- /* did we ever manage to page the subscriber */
- msg = req->attempts > 0 ? GSM_PAGING_EXPIRED : GSM_PAGING_BUSY;
-
- /* destroy it now. Do not access req afterwards */
- paging_remove_request(&req->bts->paging, req);
-
- if (cbfn)
- cbfn(GSM_HOOK_RR_PAGING, msg, NULL, NULL,
- cbfn_param);
-}
-
-static int _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)) {
- LOGP(DPAG, LOGL_INFO, "Paging request already pending for %s\n", subscr->imsi);
- return -EEXIST;
- }
-
- LOGP(DPAG, LOGL_DEBUG, "Start paging of subscriber %llu on bts %d.\n",
- subscr->id, bts->nr);
- req = talloc_zero(tall_paging_ctx, struct gsm_paging_request);
- 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, bts->network->T3113, 0);
- llist_add_tail(&req->entry, &bts_entry->pending_requests);
- paging_schedule_if_needed(bts_entry);
-
- return 0;
-}
-
-int paging_request(struct gsm_network *network, struct gsm_subscriber *subscr,
- int type, gsm_cbfn *cbfn, void *data)
-{
- struct gsm_bts *bts = NULL;
- int num_pages = 0;
-
- counter_inc(network->stats.paging.attempted);
-
- /* start paging subscriber on all BTS within Location Area */
- do {
- int rc;
-
- bts = gsm_bts_by_lac(network, subscr->lac, bts);
- if (!bts)
- break;
-
- /* skip all currently inactive TRX */
- if (!trx_is_usable(bts->c0))
- continue;
-
- num_pages++;
-
- /* Trigger paging, pass any error to caller */
- rc = _paging_request(bts, subscr, type, cbfn, data);
- if (rc < 0)
- return rc;
- } while (1);
-
- if (num_pages == 0)
- counter_inc(network->stats.paging.detached);
-
- return num_pages;
-}
-
-
-/* we consciously ignore the type of the request here */
-static void _paging_request_stop(struct gsm_bts *bts, struct gsm_subscriber *subscr,
- struct gsm_subscriber_connection *conn,
- struct msgb *msg)
-{
- 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 (conn && req->cbfn) {
- LOGP(DPAG, LOGL_DEBUG, "Stop paging on bts %d, calling cbfn.\n", bts->nr);
- req->cbfn(GSM_HOOK_RR_PAGING, GSM_PAGING_SUCCEEDED,
- msg, conn, req->cbfn_param);
- } else
- LOGP(DPAG, LOGL_DEBUG, "Stop paging on bts %d silently.\n", bts->nr);
- paging_remove_request(&bts->paging, req);
- break;
- }
- }
-}
-
-/* Stop paging on all other bts' */
-void paging_request_stop(struct gsm_bts *_bts, struct gsm_subscriber *subscr,
- struct gsm_subscriber_connection *conn,
- struct msgb *msg)
-{
- struct gsm_bts *bts = NULL;
-
- if (_bts)
- _paging_request_stop(_bts, subscr, conn, msg);
-
- do {
- /*
- * FIXME: Don't use the lac of the subscriber...
- * as it might have magically changed the lac.. use the
- * location area of the _bts as reconfiguration of the
- * network is probably happening less often.
- */
- bts = gsm_bts_by_lac(subscr->net, subscr->lac, bts);
- if (!bts)
- break;
-
- /* Stop paging */
- if (bts != _bts)
- _paging_request_stop(bts, subscr, NULL, NULL);
- } while (1);
-}
-
-void paging_update_buffer_space(struct gsm_bts *bts, u_int16_t free_slots)
-{
- bsc_del_timer(&bts->paging.credit_timer);
- bts->paging.available_slots = free_slots;
- paging_schedule_if_needed(&bts->paging);
-}
diff --git a/openbsc/src/bsc/rest_octets.c b/openbsc/src/bsc/rest_octets.c
deleted file mode 100644
index 084f14498..000000000
--- a/openbsc/src/bsc/rest_octets.c
+++ /dev/null
@@ -1,432 +0,0 @@
-/* GSM Mobile Radio Interface Layer 3 messages on the A-bis interface,
- * rest octet handling according to
- * 3GPP TS 04.08 version 7.21.0 Release 1998 / ETSI TS 100 940 V7.21.0 */
-
-/* (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 Affero General Public License as published by
- * the Free Software Foundation; either version 3 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 Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-#include <string.h>
-#include <stdlib.h>
-#include <errno.h>
-
-#include <openbsc/gsm_data.h>
-#include <osmocore/bitvec.h>
-#include <openbsc/rest_octets.h>
-
-/* generate SI1 rest octets */
-int rest_octets_si1(u_int8_t *data, u_int8_t *nch_pos)
-{
- struct bitvec bv;
-
- memset(&bv, 0, sizeof(bv));
- bv.data = data;
- bv.data_len = 1;
-
- if (nch_pos) {
- bitvec_set_bit(&bv, H);
- bitvec_set_uint(&bv, *nch_pos, 5);
- } else
- bitvec_set_bit(&bv, L);
-
- bitvec_spare_padding(&bv, 7);
- return bv.data_len;
-}
-
-/* Append selection parameters to bitvec */
-static void append_selection_params(struct bitvec *bv,
- const struct gsm48_si_selection_params *sp)
-{
- if (sp->present) {
- bitvec_set_bit(bv, H);
- bitvec_set_bit(bv, sp->cbq);
- bitvec_set_uint(bv, sp->cell_resel_off, 6);
- bitvec_set_uint(bv, sp->temp_offs, 3);
- bitvec_set_uint(bv, sp->penalty_time, 5);
- } else
- bitvec_set_bit(bv, L);
-}
-
-/* Append power offset to bitvec */
-static void append_power_offset(struct bitvec *bv,
- const struct gsm48_si_power_offset *po)
-{
- if (po->present) {
- bitvec_set_bit(bv, H);
- bitvec_set_uint(bv, po->power_offset, 2);
- } else
- bitvec_set_bit(bv, L);
-}
-
-/* Append GPRS indicator to bitvec */
-static void append_gprs_ind(struct bitvec *bv,
- const struct gsm48_si3_gprs_ind *gi)
-{
- if (gi->present) {
- bitvec_set_bit(bv, H);
- bitvec_set_uint(bv, gi->ra_colour, 3);
- /* 0 == SI13 in BCCH Norm, 1 == SI13 sent on BCCH Ext */
- bitvec_set_bit(bv, gi->si13_position);
- } else
- bitvec_set_bit(bv, L);
-}
-
-
-/* Generate SI3 Rest Octests (Chapter 10.5.2.34 / Table 10.4.72) */
-int rest_octets_si3(u_int8_t *data, const struct gsm48_si_ro_info *si3)
-{
- struct bitvec bv;
-
- memset(&bv, 0, sizeof(bv));
- bv.data = data;
- bv.data_len = 4;
-
- /* Optional Selection Parameters */
- append_selection_params(&bv, &si3->selection_params);
-
- /* Optional Power Offset */
- append_power_offset(&bv, &si3->power_offset);
-
- /* Do we have a SI2ter on the BCCH? */
- if (si3->si2ter_indicator)
- bitvec_set_bit(&bv, H);
- else
- bitvec_set_bit(&bv, L);
-
- /* Early Classmark Sending Control */
- if (si3->early_cm_ctrl)
- bitvec_set_bit(&bv, H);
- else
- bitvec_set_bit(&bv, L);
-
- /* Do we have a SI Type 9 on the BCCH? */
- if (si3->scheduling.present) {
- bitvec_set_bit(&bv, H);
- bitvec_set_uint(&bv, si3->scheduling.where, 3);
- } else
- bitvec_set_bit(&bv, L);
-
- /* GPRS Indicator */
- append_gprs_ind(&bv, &si3->gprs_ind);
-
- bitvec_spare_padding(&bv, (bv.data_len*8)-1);
- return bv.data_len;
-}
-
-static int append_lsa_params(struct bitvec *bv,
- const struct gsm48_lsa_params *lsa_params)
-{
- /* FIXME */
- return -1;
-}
-
-/* Generate SI4 Rest Octets (Chapter 10.5.2.35) */
-int rest_octets_si4(u_int8_t *data, const struct gsm48_si_ro_info *si4)
-{
- struct bitvec bv;
-
- memset(&bv, 0, sizeof(bv));
- bv.data = data;
- bv.data_len = 10; /* FIXME: up to ? */
-
- /* SI4 Rest Octets O */
- append_selection_params(&bv, &si4->selection_params);
- append_power_offset(&bv, &si4->power_offset);
- append_gprs_ind(&bv, &si4->gprs_ind);
-
- if (0 /* FIXME */) {
- /* H and SI4 Rest Octets S */
- bitvec_set_bit(&bv, H);
-
- /* LSA Parameters */
- if (si4->lsa_params.present) {
- bitvec_set_bit(&bv, H);
- append_lsa_params(&bv, &si4->lsa_params);
- } else
- bitvec_set_bit(&bv, L);
-
- /* Cell Identity */
- if (1) {
- bitvec_set_bit(&bv, H);
- bitvec_set_uint(&bv, si4->cell_id, 16);
- } else
- bitvec_set_bit(&bv, L);
-
- /* LSA ID Information */
- if (0) {
- bitvec_set_bit(&bv, H);
- /* FIXME */
- } else
- bitvec_set_bit(&bv, L);
- } else {
- /* L and break indicator */
- bitvec_set_bit(&bv, L);
- bitvec_set_bit(&bv, si4->break_ind ? H : L);
- }
-
- return bv.data_len;
-}
-
-/* GPRS Mobile Allocation as per TS 04.60 Chapter 12.10a:
- < GPRS Mobile Allocation IE > ::=
- < HSN : bit (6) >
- { 0 | 1 < RFL number list : < RFL number list struct > > }
- { 0 < MA_LENGTH : bit (6) >
- < MA_BITMAP: bit (val(MA_LENGTH) + 1) >
- | 1 { 0 | 1 <ARFCN index list : < ARFCN index list struct > > } } ;
-
- < RFL number list struct > :: =
- < RFL_NUMBER : bit (4) >
- { 0 | 1 < RFL number list struct > } ;
- < ARFCN index list struct > ::=
- < ARFCN_INDEX : bit(6) >
- { 0 | 1 < ARFCN index list struct > } ;
- */
-static int append_gprs_mobile_alloc(struct bitvec *bv)
-{
- /* Hopping Sequence Number */
- bitvec_set_uint(bv, 0, 6);
-
- if (0) {
- /* We want to use a RFL number list */
- bitvec_set_bit(bv, 1);
- /* FIXME: RFL number list */
- } else
- bitvec_set_bit(bv, 0);
-
- if (0) {
- /* We want to use a MA_BITMAP */
- bitvec_set_bit(bv, 0);
- /* FIXME: MA_LENGTH, MA_BITMAP, ... */
- } else {
- bitvec_set_bit(bv, 1);
- if (0) {
- /* We want to provide an ARFCN index list */
- bitvec_set_bit(bv, 1);
- /* FIXME */
- } else
- bitvec_set_bit(bv, 0);
- }
- return 0;
-}
-
-static int encode_t3192(unsigned int t3192)
-{
- if (t3192 == 0)
- return 3;
- else if (t3192 <= 80)
- return 4;
- else if (t3192 <= 120)
- return 5;
- else if (t3192 <= 160)
- return 6;
- else if (t3192 <= 200)
- return 7;
- else if (t3192 <= 500)
- return 0;
- else if (t3192 <= 1000)
- return 1;
- else if (t3192 <= 1500)
- return 2;
- else
- return -EINVAL;
-}
-
-static int encode_drx_timer(unsigned int drx)
-{
- if (drx == 0)
- return 0;
- else if (drx == 1)
- return 1;
- else if (drx == 2)
- return 2;
- else if (drx <= 4)
- return 3;
- else if (drx <= 8)
- return 4;
- else if (drx <= 16)
- return 5;
- else if (drx <= 32)
- return 6;
- else if (drx <= 64)
- return 7;
- else
- return -EINVAL;
-}
-
-/* GPRS Cell Options as per TS 04.60 Chapter 12.24
- < GPRS Cell Options IE > ::=
- < NMO : bit(2) >
- < T3168 : bit(3) >
- < T3192 : bit(3) >
- < DRX_TIMER_MAX: bit(3) >
- < ACCESS_BURST_TYPE: bit >
- < CONTROL_ACK_TYPE : bit >
- < BS_CV_MAX: bit(4) >
- { 0 | 1 < PAN_DEC : bit(3) >
- < PAN_INC : bit(3) >
- < PAN_MAX : bit(3) >
- { 0 | 1 < Extension Length : bit(6) >
- < bit (val(Extension Length) + 1
- & { < Extension Information > ! { bit ** = <no string> } } ;
- < Extension Information > ::=
- { 0 | 1 < EGPRS_PACKET_CHANNEL_REQUEST : bit >
- < BEP_PERIOD : bit(4) > }
- < PFC_FEATURE_MODE : bit >
- < DTM_SUPPORT : bit >
- <BSS_PAGING_COORDINATION: bit >
- <spare bit > ** ;
- */
-static int append_gprs_cell_opt(struct bitvec *bv,
- const struct gprs_cell_options *gco)
-{
- int t3192, drx_timer_max;
-
- t3192 = encode_t3192(gco->t3192);
- if (t3192 < 0)
- return t3192;
-
- drx_timer_max = encode_drx_timer(gco->drx_timer_max);
- if (drx_timer_max < 0)
- return drx_timer_max;
-
- bitvec_set_uint(bv, gco->nmo, 2);
- bitvec_set_uint(bv, gco->t3168 / 500, 3);
- bitvec_set_uint(bv, t3192, 3);
- bitvec_set_uint(bv, drx_timer_max, 3);
- /* ACCESS_BURST_TYPE: Hard-code 8bit */
- bitvec_set_bit(bv, 0);
- /* CONTROL_ACK_TYPE: Hard-code to RLC/MAC control block */
- bitvec_set_bit(bv, 1);
- bitvec_set_uint(bv, gco->bs_cv_max, 4);
-
- if (0) {
- /* hard-code no PAN_{DEC,INC,MAX} */
- bitvec_set_bit(bv, 0);
- } else {
- /* copied from ip.access BSC protocol trace */
- bitvec_set_bit(bv, 1);
- bitvec_set_uint(bv, 1, 3); /* DEC */
- bitvec_set_uint(bv, 1, 3); /* INC */
- bitvec_set_uint(bv, 15, 3); /* MAX */
- }
-
- if (!gco->ext_info_present) {
- /* no extension information */
- bitvec_set_bit(bv, 0);
- } else {
- /* extension information */
- bitvec_set_bit(bv, 1);
- if (!gco->ext_info.egprs_supported) {
- /* 6bit length of extension */
- bitvec_set_uint(bv, (1 + 3)-1, 6);
- /* EGPRS supported in the cell */
- bitvec_set_bit(bv, 0);
- } else {
- /* 6bit length of extension */
- bitvec_set_uint(bv, (1 + 5 + 3)-1, 6);
- /* EGPRS supported in the cell */
- bitvec_set_bit(bv, 1);
- /* 1bit EGPRS PACKET CHANNEL REQUEST */
- bitvec_set_bit(bv, gco->ext_info.use_egprs_p_ch_req);
- /* 4bit BEP PERIOD */
- bitvec_set_uint(bv, gco->ext_info.bep_period, 4);
- }
- bitvec_set_bit(bv, gco->ext_info.pfc_supported);
- bitvec_set_bit(bv, gco->ext_info.dtm_supported);
- bitvec_set_bit(bv, gco->ext_info.bss_paging_coordination);
- }
-
- return 0;
-}
-
-static void append_gprs_pwr_ctrl_pars(struct bitvec *bv,
- const struct gprs_power_ctrl_pars *pcp)
-{
- bitvec_set_uint(bv, pcp->alpha, 4);
- bitvec_set_uint(bv, pcp->t_avg_w, 5);
- bitvec_set_uint(bv, pcp->t_avg_t, 5);
- bitvec_set_uint(bv, pcp->pc_meas_chan, 1);
- bitvec_set_uint(bv, pcp->n_avg_i, 4);
-}
-
-/* Generate SI13 Rest Octests (04.08 Chapter 10.5.2.37b) */
-int rest_octets_si13(u_int8_t *data, const struct gsm48_si13_info *si13)
-{
- struct bitvec bv;
-
- memset(&bv, 0, sizeof(bv));
- bv.data = data;
- bv.data_len = 20;
-
- if (0) {
- /* No rest octets */
- bitvec_set_bit(&bv, L);
- } else {
- bitvec_set_bit(&bv, H);
- bitvec_set_uint(&bv, si13->bcch_change_mark, 3);
- bitvec_set_uint(&bv, si13->si_change_field, 4);
- if (1) {
- bitvec_set_bit(&bv, 0);
- } else {
- bitvec_set_bit(&bv, 1);
- bitvec_set_uint(&bv, si13->bcch_change_mark, 2);
- append_gprs_mobile_alloc(&bv);
- }
- if (!si13->pbcch_present) {
- /* PBCCH not present in cell */
- bitvec_set_bit(&bv, 0);
- bitvec_set_uint(&bv, si13->no_pbcch.rac, 8);
- bitvec_set_bit(&bv, si13->no_pbcch.spgc_ccch_sup);
- bitvec_set_uint(&bv, si13->no_pbcch.prio_acc_thr, 3);
- bitvec_set_uint(&bv, si13->no_pbcch.net_ctrl_ord, 2);
- append_gprs_cell_opt(&bv, &si13->cell_opts);
- append_gprs_pwr_ctrl_pars(&bv, &si13->pwr_ctrl_pars);
- } else {
- /* PBCCH present in cell */
- bitvec_set_bit(&bv, 1);
- bitvec_set_uint(&bv, si13->pbcch.psi1_rep_per, 4);
- /* PBCCH Descripiton */
- bitvec_set_uint(&bv, si13->pbcch.pb, 4);
- bitvec_set_uint(&bv, si13->pbcch.tsc, 3);
- bitvec_set_uint(&bv, si13->pbcch.tn, 3);
- switch (si13->pbcch.carrier_type) {
- case PBCCH_BCCH:
- bitvec_set_bit(&bv, 0);
- bitvec_set_bit(&bv, 0);
- break;
- case PBCCH_ARFCN:
- bitvec_set_bit(&bv, 0);
- bitvec_set_bit(&bv, 1);
- bitvec_set_uint(&bv, si13->pbcch.arfcn, 10);
- break;
- case PBCCH_MAIO:
- bitvec_set_bit(&bv, 1);
- bitvec_set_uint(&bv, si13->pbcch.maio, 6);
- break;
- }
- }
- /* 3GPP TS 44.018 Release 6 / 10.5.2.37b */
- bitvec_set_bit(&bv, H); /* added Release 99 */
- /* claim our SGSN is compatible with Release 99, as EDGE and EGPRS
- * was only added in this Release */
- bitvec_set_bit(&bv, 1);
- }
- bitvec_spare_padding(&bv, (bv.data_len*8)-1);
- return bv.data_len;
-}
diff --git a/openbsc/src/bsc/system_information.c b/openbsc/src/bsc/system_information.c
deleted file mode 100644
index 8a99c565e..000000000
--- a/openbsc/src/bsc/system_information.c
+++ /dev/null
@@ -1,606 +0,0 @@
-/* GSM 04.08 System Information (SI) encoding and decoding
- * 3GPP TS 04.08 version 7.21.0 Release 1998 / ETSI TS 100 940 V7.21.0 */
-
-/* (C) 2008-2010 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 Affero General Public License as published by
- * the Free Software Foundation; either version 3 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 Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-#include <errno.h>
-#include <string.h>
-#include <stdio.h>
-#include <sys/types.h>
-#include <netinet/in.h>
-
-#include <openbsc/gsm_04_08.h>
-#include <openbsc/gsm_data.h>
-#include <openbsc/abis_rsl.h>
-#include <openbsc/rest_octets.h>
-#include <osmocore/bitvec.h>
-#include <osmocore/utils.h>
-#include <openbsc/debug.h>
-
-#define GSM48_CELL_CHAN_DESC_SIZE 16
-#define GSM_MACBLOCK_PADDING 0x2b
-
-/* verify the sizes of the system information type structs */
-
-/* rest octets are not part of the struct */
-static_assert(sizeof(struct gsm48_system_information_type_header) == 3, _si_header_size);
-static_assert(sizeof(struct gsm48_rach_control) == 3, _si_rach_control);
-static_assert(sizeof(struct gsm48_system_information_type_1) == 22, _si1_size);
-static_assert(sizeof(struct gsm48_system_information_type_2) == 23, _si2_size);
-static_assert(sizeof(struct gsm48_system_information_type_3) == 19, _si3_size);
-static_assert(sizeof(struct gsm48_system_information_type_4) == 13, _si4_size);
-
-/* bs11 forgot the l2 len, 0-6 rest octets */
-static_assert(sizeof(struct gsm48_system_information_type_5) == 18, _si5_size);
-static_assert(sizeof(struct gsm48_system_information_type_6) == 11, _si6_size);
-
-static_assert(sizeof(struct gsm48_system_information_type_13) == 3, _si13_size);
-
-/* Frequency Lists as per TS 04.08 10.5.2.13 */
-
-/* 10.5.2.13.2: Bit map 0 format */
-static int freq_list_bm0_set_arfcn(u_int8_t *chan_list, unsigned int arfcn)
-{
- unsigned int byte, bit;
-
- if (arfcn > 124 || arfcn < 1) {
- LOGP(DRR, LOGL_ERROR, "Bitmap 0 only supports ARFCN 1...124\n");
- return -EINVAL;
- }
-
- /* the bitmask is from 1..124, not from 0..123 */
- arfcn--;
-
- byte = arfcn / 8;
- bit = arfcn % 8;
-
- chan_list[GSM48_CELL_CHAN_DESC_SIZE-1-byte] |= (1 << bit);
-
- return 0;
-}
-
-/* 10.5.2.13.7: Variable bit map format */
-static int freq_list_bmrel_set_arfcn(u_int8_t *chan_list, unsigned int arfcn)
-{
- unsigned int byte, bit;
- unsigned int min_arfcn;
- unsigned int bitno;
-
- min_arfcn = (chan_list[0] & 1) << 9;
- min_arfcn |= chan_list[1] << 1;
- min_arfcn |= (chan_list[2] >> 7) & 1;
-
- /* The lower end of our bitmaks is always implicitly included */
- if (arfcn == min_arfcn)
- return 0;
-
- if (arfcn < min_arfcn) {
- LOGP(DRR, LOGL_ERROR, "arfcn(%u) < min(%u)\n", arfcn, min_arfcn);
- return -EINVAL;
- }
- if (arfcn > min_arfcn + 111) {
- LOGP(DRR, LOGL_ERROR, "arfcn(%u) > min(%u) + 111\n", arfcn, min_arfcn);
- return -EINVAL;
- }
-
- bitno = (arfcn - min_arfcn);
- byte = bitno / 8;
- bit = bitno % 8;
-
- chan_list[2 + byte] |= 1 << (7 - bit);
-
- return 0;
-}
-
-/* generate a cell channel list as per Section 10.5.2.1b of 04.08 */
-static int bitvec2freq_list(u_int8_t *chan_list, struct bitvec *bv,
- const struct gsm_bts *bts)
-{
- int i, rc, min = 1024, max = -1;
-
- memset(chan_list, 0, 16);
-
- /* GSM900-only handsets only support 'bit map 0 format' */
- if (bts->band == GSM_BAND_900) {
- chan_list[0] = 0;
-
- for (i = 0; i < bv->data_len*8; i++) {
- if (bitvec_get_bit_pos(bv, i)) {
- rc = freq_list_bm0_set_arfcn(chan_list, i);
- if (rc < 0)
- return rc;
- }
- }
- return 0;
- }
-
- /* We currently only support the 'Variable bitmap format' */
- chan_list[0] = 0x8e;
-
- for (i = 0; i < bv->data_len*8; i++) {
- if (bitvec_get_bit_pos(bv, i)) {
- if (i < min)
- min = i;
- if (i > max)
- max = i;
- }
- }
-
- if (max == -1) {
- /* Empty set, use 'bit map 0 format' */
- chan_list[0] = 0;
- return 0;
- }
-
- if ((max - min) > 111) {
- LOGP(DRR, LOGL_ERROR, "min_arfcn=%u, max_arfcn=%u, "
- "distance > 111\n", min, max);
- return -EINVAL;
- }
-
- chan_list[0] |= (min >> 9) & 1;
- chan_list[1] = (min >> 1);
- chan_list[2] = (min & 1) << 7;
-
- for (i = 0; i < bv->data_len*8; i++) {
- if (bitvec_get_bit_pos(bv, i)) {
- rc = freq_list_bmrel_set_arfcn(chan_list, i);
- if (rc < 0)
- return rc;
- }
- }
-
- return 0;
-}
-
-/* generate a cell channel list as per Section 10.5.2.1b of 04.08 */
-static int generate_cell_chan_list(u_int8_t *chan_list, struct gsm_bts *bts)
-{
- struct gsm_bts_trx *trx;
- struct bitvec *bv = &bts->si_common.cell_alloc;
-
- /* Zero-initialize the bit-vector */
- memset(bv->data, 0, bv->data_len);
-
- /* first we generate a bitvec of all TRX ARFCN's in our BTS */
- llist_for_each_entry(trx, &bts->trx_list, list) {
- unsigned int i, j;
- /* Always add the TRX's ARFCN */
- bitvec_set_bit_pos(bv, trx->arfcn, 1);
- for (i = 0; i < ARRAY_SIZE(trx->ts); i++) {
- struct gsm_bts_trx_ts *ts = &trx->ts[i];
- /* Add any ARFCNs present in hopping channels */
- for (j = 0; j < 1024; j++) {
- if (bitvec_get_bit_pos(&ts->hopping.arfcns, j))
- bitvec_set_bit_pos(bv, j, 1);
- }
- }
- }
-
- /* then we generate a GSM 04.08 frequency list from the bitvec */
- return bitvec2freq_list(chan_list, bv, bts);
-}
-
-/* generate a cell channel list as per Section 10.5.2.1b of 04.08 */
-static int generate_bcch_chan_list(u_int8_t *chan_list, struct gsm_bts *bts, int si5)
-{
- struct gsm_bts *cur_bts;
- struct bitvec *bv;
-
- if (si5 && bts->neigh_list_manual_mode == NL_MODE_MANUAL_SI5SEP)
- bv = &bts->si_common.si5_neigh_list;
- else
- bv = &bts->si_common.neigh_list;
-
- /* Generate list of neighbor cells if we are in automatic mode */
- if (bts->neigh_list_manual_mode == NL_MODE_AUTOMATIC) {
- /* Zero-initialize the bit-vector */
- memset(bv->data, 0, bv->data_len);
-
- /* first we generate a bitvec of the BCCH ARFCN's in our BSC */
- llist_for_each_entry(cur_bts, &bts->network->bts_list, list) {
- if (cur_bts == bts)
- continue;
- bitvec_set_bit_pos(bv, cur_bts->c0->arfcn, 1);
- }
- }
-
- /* then we generate a GSM 04.08 frequency list from the bitvec */
- return bitvec2freq_list(chan_list, bv, bts);
-}
-
-static int generate_si1(u_int8_t *output, struct gsm_bts *bts)
-{
- int rc;
- struct gsm48_system_information_type_1 *si1 =
- (struct gsm48_system_information_type_1 *) output;
-
- memset(si1, GSM_MACBLOCK_PADDING, GSM_MACBLOCK_LEN);
-
- si1->header.l2_plen = (21 << 2) | 1;
- si1->header.rr_protocol_discriminator = GSM48_PDISC_RR;
- si1->header.skip_indicator = 0;
- si1->header.system_information = GSM48_MT_RR_SYSINFO_1;
-
- rc = generate_cell_chan_list(si1->cell_channel_description, bts);
- if (rc < 0)
- return rc;
-
- si1->rach_control = bts->si_common.rach_control;
-
- /* SI1 Rest Octets (10.5.2.32), contains NCH position */
- rc = rest_octets_si1(si1->rest_octets, NULL);
-
- return sizeof(*si1) + rc;
-}
-
-static int generate_si2(u_int8_t *output, struct gsm_bts *bts)
-{
- int rc;
- struct gsm48_system_information_type_2 *si2 =
- (struct gsm48_system_information_type_2 *) output;
-
- memset(si2, GSM_MACBLOCK_PADDING, GSM_MACBLOCK_LEN);
-
- si2->header.l2_plen = (22 << 2) | 1;
- si2->header.rr_protocol_discriminator = GSM48_PDISC_RR;
- si2->header.skip_indicator = 0;
- si2->header.system_information = GSM48_MT_RR_SYSINFO_2;
-
- rc = generate_bcch_chan_list(si2->bcch_frequency_list, bts, 0);
- if (rc < 0)
- return rc;
-
- si2->ncc_permitted = bts->si_common.ncc_permitted;
- si2->rach_control = bts->si_common.rach_control;
-
- return sizeof(*si2);
-}
-
-static struct gsm48_si_ro_info si_info = {
- .selection_params = {
- .present = 0,
- },
- .power_offset = {
- .present = 0,
- },
- .si2ter_indicator = 0,
- .early_cm_ctrl = 1,
- .scheduling = {
- .present = 0,
- },
- .gprs_ind = {
- .si13_position = 0,
- .ra_colour = 0,
- .present = 1,
- },
- .lsa_params = {
- .present = 0,
- },
- .cell_id = 0, /* FIXME: doesn't the bts have this? */
- .break_ind = 0,
-};
-
-static int generate_si3(u_int8_t *output, struct gsm_bts *bts)
-{
- int rc;
- struct gsm48_system_information_type_3 *si3 =
- (struct gsm48_system_information_type_3 *) output;
-
- memset(si3, GSM_MACBLOCK_PADDING, GSM_MACBLOCK_LEN);
-
- si3->header.l2_plen = (18 << 2) | 1;
- si3->header.rr_protocol_discriminator = GSM48_PDISC_RR;
- si3->header.skip_indicator = 0;
- si3->header.system_information = GSM48_MT_RR_SYSINFO_3;
-
- si3->cell_identity = htons(bts->cell_identity);
- gsm48_generate_lai(&si3->lai, bts->network->country_code,
- bts->network->network_code,
- bts->location_area_code);
- si3->control_channel_desc = bts->si_common.chan_desc;
- si3->cell_options = bts->si_common.cell_options;
- si3->cell_sel_par = bts->si_common.cell_sel_par;
- si3->rach_control = bts->si_common.rach_control;
-
- /* SI3 Rest Octets (10.5.2.34), containing
- CBQ, CELL_RESELECT_OFFSET, TEMPORARY_OFFSET, PENALTY_TIME
- Power Offset, 2ter Indicator, Early Classmark Sending,
- Scheduling if and WHERE, GPRS Indicator, SI13 position */
- rc = rest_octets_si3(si3->rest_octets, &si_info);
-
- return sizeof(*si3) + rc;
-}
-
-static int generate_si4(u_int8_t *output, struct gsm_bts *bts)
-{
- int rc;
- struct gsm48_system_information_type_4 *si4 =
- (struct gsm48_system_information_type_4 *) output;
-
- /* length of all IEs present except SI4 rest octets and l2_plen */
- int l2_plen = sizeof(*si4) - 1;
-
- memset(si4, GSM_MACBLOCK_PADDING, GSM_MACBLOCK_LEN);
-
- si4->header.rr_protocol_discriminator = GSM48_PDISC_RR;
- si4->header.skip_indicator = 0;
- si4->header.system_information = GSM48_MT_RR_SYSINFO_4;
-
- gsm48_generate_lai(&si4->lai, bts->network->country_code,
- bts->network->network_code,
- bts->location_area_code);
- si4->cell_sel_par = bts->si_common.cell_sel_par;
- si4->rach_control = bts->si_common.rach_control;
-
- /* Optional: CBCH Channel Description + CBCH Mobile Allocation */
-
- si4->header.l2_plen = (l2_plen << 2) | 1;
-
- /* SI4 Rest Octets (10.5.2.35), containing
- Optional Power offset, GPRS Indicator,
- Cell Identity, LSA ID, Selection Parameter */
- rc = rest_octets_si4(si4->data, &si_info);
-
- return sizeof(*si4) + rc;
-}
-
-static int generate_si5(u_int8_t *output, struct gsm_bts *bts)
-{
- struct gsm48_system_information_type_5 *si5;
- int rc, l2_plen = 18;
-
- memset(output, GSM_MACBLOCK_PADDING, GSM_MACBLOCK_LEN);
-
- /* ip.access nanoBTS needs l2_plen!! */
- if (is_ipaccess_bts(bts)) {
- *output++ = (l2_plen << 2) | 1;
- l2_plen++;
- }
-
- si5 = (struct gsm48_system_information_type_5 *) output;
-
- /* l2 pseudo length, not part of msg: 18 */
- si5->rr_protocol_discriminator = GSM48_PDISC_RR;
- si5->skip_indicator = 0;
- si5->system_information = GSM48_MT_RR_SYSINFO_5;
- rc = generate_bcch_chan_list(si5->bcch_frequency_list, bts, 1);
- if (rc < 0)
- return rc;
-
- /* 04.08 9.1.37: L2 Pseudo Length of 18 */
- return l2_plen;
-}
-
-static int generate_si6(u_int8_t *output, struct gsm_bts *bts)
-{
- struct gsm48_system_information_type_6 *si6;
- int l2_plen = 11;
-
- memset(output, GSM_MACBLOCK_PADDING, GSM_MACBLOCK_LEN);
-
- /* ip.access nanoBTS needs l2_plen!! */
- if (is_ipaccess_bts(bts)) {
- *output++ = (l2_plen << 2) | 1;
- l2_plen++;
- }
-
- si6 = (struct gsm48_system_information_type_6 *) output;
-
- /* l2 pseudo length, not part of msg: 11 */
- si6->rr_protocol_discriminator = GSM48_PDISC_RR;
- si6->skip_indicator = 0;
- si6->system_information = GSM48_MT_RR_SYSINFO_6;
- si6->cell_identity = htons(bts->cell_identity);
- gsm48_generate_lai(&si6->lai, bts->network->country_code,
- bts->network->network_code,
- bts->location_area_code);
- si6->cell_options = bts->si_common.cell_options;
- si6->ncc_permitted = bts->si_common.ncc_permitted;
-
- /* SI6 Rest Octets: 10.5.2.35a: PCH / NCH info, VBS/VGCS options */
-
- return l2_plen;
-}
-
-static struct gsm48_si13_info si13_default = {
- .cell_opts = {
- .nmo = GPRS_NMO_II,
- .t3168 = 2000,
- .t3192 = 200,
- .drx_timer_max = 3,
- .bs_cv_max = 15,
- .ext_info_present = 1,
- .ext_info = {
- /* The values below are just guesses ! */
- .egprs_supported = 0,
- .use_egprs_p_ch_req = 1,
- .bep_period = 5,
- .pfc_supported = 0,
- .dtm_supported = 0,
- .bss_paging_coordination = 0,
- },
- },
- .pwr_ctrl_pars = {
- .alpha = 10, /* a = 1.0 */
- .t_avg_w = 16,
- .t_avg_t = 16,
- .pc_meas_chan = 0, /* downling measured on CCCH */
- .n_avg_i = 8,
- },
- .bcch_change_mark = 1,
- .si_change_field = 0,
- .pbcch_present = 0,
- {
- .no_pbcch = {
- .rac = 0, /* needs to be patched */
- .spgc_ccch_sup = 0,
- .net_ctrl_ord = 0,
- .prio_acc_thr = 6,
- },
- },
-};
-
-static int generate_si13(u_int8_t *output, struct gsm_bts *bts)
-{
- struct gsm48_system_information_type_13 *si13 =
- (struct gsm48_system_information_type_13 *) output;
- int ret;
-
- memset(si13, GSM_MACBLOCK_PADDING, GSM_MACBLOCK_LEN);
-
- si13->header.rr_protocol_discriminator = GSM48_PDISC_RR;
- si13->header.skip_indicator = 0;
- si13->header.system_information = GSM48_MT_RR_SYSINFO_13;
-
- si13_default.no_pbcch.rac = bts->gprs.rac;
-
- ret = rest_octets_si13(si13->rest_octets, &si13_default);
- if (ret < 0)
- return ret;
-
- /* length is coded in bit 2 an up */
- si13->header.l2_plen = 0x01;
-
- return sizeof (*si13) + ret;
-}
-
-static const uint8_t sitype2rsl[_MAX_SYSINFO_TYPE] = {
- [SYSINFO_TYPE_1] = RSL_SYSTEM_INFO_1,
- [SYSINFO_TYPE_2] = RSL_SYSTEM_INFO_2,
- [SYSINFO_TYPE_3] = RSL_SYSTEM_INFO_3,
- [SYSINFO_TYPE_4] = RSL_SYSTEM_INFO_4,
- [SYSINFO_TYPE_5] = RSL_SYSTEM_INFO_5,
- [SYSINFO_TYPE_6] = RSL_SYSTEM_INFO_6,
- [SYSINFO_TYPE_7] = RSL_SYSTEM_INFO_7,
- [SYSINFO_TYPE_8] = RSL_SYSTEM_INFO_8,
- [SYSINFO_TYPE_9] = RSL_SYSTEM_INFO_9,
- [SYSINFO_TYPE_10] = RSL_SYSTEM_INFO_10,
- [SYSINFO_TYPE_13] = RSL_SYSTEM_INFO_13,
- [SYSINFO_TYPE_16] = RSL_SYSTEM_INFO_16,
- [SYSINFO_TYPE_17] = RSL_SYSTEM_INFO_17,
- [SYSINFO_TYPE_18] = RSL_SYSTEM_INFO_18,
- [SYSINFO_TYPE_19] = RSL_SYSTEM_INFO_19,
- [SYSINFO_TYPE_20] = RSL_SYSTEM_INFO_20,
- [SYSINFO_TYPE_2bis] = RSL_SYSTEM_INFO_2bis,
- [SYSINFO_TYPE_2ter] = RSL_SYSTEM_INFO_2ter,
- [SYSINFO_TYPE_2quater] = RSL_SYSTEM_INFO_2quater,
- [SYSINFO_TYPE_5bis] = RSL_SYSTEM_INFO_5bis,
- [SYSINFO_TYPE_5ter] = RSL_SYSTEM_INFO_5ter,
-};
-
-static const uint8_t rsl2sitype[0xff] = {
- [RSL_SYSTEM_INFO_1] = SYSINFO_TYPE_1,
- [RSL_SYSTEM_INFO_2] = SYSINFO_TYPE_2,
- [RSL_SYSTEM_INFO_3] = SYSINFO_TYPE_3,
- [RSL_SYSTEM_INFO_4] = SYSINFO_TYPE_4,
- [RSL_SYSTEM_INFO_5] = SYSINFO_TYPE_5,
- [RSL_SYSTEM_INFO_6] = SYSINFO_TYPE_6,
- [RSL_SYSTEM_INFO_7] = SYSINFO_TYPE_7,
- [RSL_SYSTEM_INFO_8] = SYSINFO_TYPE_8,
- [RSL_SYSTEM_INFO_9] = SYSINFO_TYPE_9,
- [RSL_SYSTEM_INFO_10] = SYSINFO_TYPE_10,
- [RSL_SYSTEM_INFO_13] = SYSINFO_TYPE_13,
- [RSL_SYSTEM_INFO_16] = SYSINFO_TYPE_16,
- [RSL_SYSTEM_INFO_17] = SYSINFO_TYPE_17,
- [RSL_SYSTEM_INFO_18] = SYSINFO_TYPE_18,
- [RSL_SYSTEM_INFO_19] = SYSINFO_TYPE_19,
- [RSL_SYSTEM_INFO_20] = SYSINFO_TYPE_20,
- [RSL_SYSTEM_INFO_2bis] = SYSINFO_TYPE_2bis,
- [RSL_SYSTEM_INFO_2ter] = SYSINFO_TYPE_2ter,
- [RSL_SYSTEM_INFO_2quater] = SYSINFO_TYPE_2quater,
- [RSL_SYSTEM_INFO_5bis] = SYSINFO_TYPE_5bis,
- [RSL_SYSTEM_INFO_5ter] = SYSINFO_TYPE_5ter,
-};
-
-typedef int (*gen_si_fn_t)(uint8_t *output, struct gsm_bts *bts);
-
-static const gen_si_fn_t gen_si_fn[_MAX_SYSINFO_TYPE] = {
- [SYSINFO_TYPE_1] = &generate_si1,
- [SYSINFO_TYPE_2] = &generate_si2,
- [SYSINFO_TYPE_3] = &generate_si3,
- [SYSINFO_TYPE_4] = &generate_si4,
- [SYSINFO_TYPE_5] = &generate_si5,
- [SYSINFO_TYPE_6] = &generate_si6,
- [SYSINFO_TYPE_13] = &generate_si13,
-};
-
-const struct value_string osmo_sitype_strs[_MAX_SYSINFO_TYPE] = {
- { SYSINFO_TYPE_1, "1" },
- { SYSINFO_TYPE_2, "2" },
- { SYSINFO_TYPE_3, "3" },
- { SYSINFO_TYPE_4, "4" },
- { SYSINFO_TYPE_5, "5" },
- { SYSINFO_TYPE_6, "6" },
- { SYSINFO_TYPE_7, "7" },
- { SYSINFO_TYPE_8, "8" },
- { SYSINFO_TYPE_9, "9" },
- { SYSINFO_TYPE_10, "10" },
- { SYSINFO_TYPE_13, "13" },
- { SYSINFO_TYPE_16, "16" },
- { SYSINFO_TYPE_17, "17" },
- { SYSINFO_TYPE_18, "18" },
- { SYSINFO_TYPE_19, "19" },
- { SYSINFO_TYPE_20, "20" },
- { SYSINFO_TYPE_2bis, "2bis" },
- { SYSINFO_TYPE_2ter, "2ter" },
- { SYSINFO_TYPE_2quater, "2quater" },
- { SYSINFO_TYPE_5bis, "5bis" },
- { SYSINFO_TYPE_5ter, "5ter" },
- { 0, NULL }
-};
-
-uint8_t gsm_sitype2rsl(enum osmo_sysinfo_type si_type)
-{
- return sitype2rsl[si_type];
-}
-
-const char *gsm_sitype_name(enum osmo_sysinfo_type si_type)
-{
- return get_value_string(osmo_sitype_strs, si_type);
-}
-
-int gsm_generate_si(struct gsm_bts *bts, enum osmo_sysinfo_type si_type)
-{
- gen_si_fn_t gen_si;
-
- switch (bts->gprs.mode) {
- case BTS_GPRS_EGPRS:
- si13_default.cell_opts.ext_info_present = 1;
- si13_default.cell_opts.ext_info.egprs_supported = 1;
- /* fallthrough */
- case BTS_GPRS_GPRS:
- si_info.gprs_ind.present = 1;
- break;
- case BTS_GPRS_NONE:
- si_info.gprs_ind.present = 0;
- break;
- }
-
- memcpy(&si_info.selection_params,
- &bts->si_common.cell_ro_sel_par,
- sizeof(struct gsm48_si_selection_params));
-
- gen_si = gen_si_fn[si_type];
- if (!gen_si)
- return -EINVAL;
-
- return gen_si(bts->si_buf[si_type], bts);
-}
diff --git a/openbsc/src/bsc/transaction.c b/openbsc/src/bsc/transaction.c
deleted file mode 100644
index 9b4af1aac..000000000
--- a/openbsc/src/bsc/transaction.c
+++ /dev/null
@@ -1,152 +0,0 @@
-/* GSM 04.07 Transaction handling */
-
-/* (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 Affero General Public License as published by
- * the Free Software Foundation; either version 3 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 Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-#include <openbsc/transaction.h>
-#include <openbsc/gsm_data.h>
-#include <openbsc/mncc.h>
-#include <openbsc/debug.h>
-#include <osmocore/talloc.h>
-#include <openbsc/gsm_subscriber.h>
-#include <openbsc/gsm_04_08.h>
-#include <openbsc/mncc.h>
-#include <openbsc/paging.h>
-#include <openbsc/osmo_msc.h>
-
-void *tall_trans_ctx;
-
-void _gsm48_cc_trans_free(struct gsm_trans *trans);
-
-struct gsm_trans *trans_find_by_id(struct gsm_subscriber *subscr,
- u_int8_t proto, u_int8_t trans_id)
-{
- struct gsm_trans *trans;
- struct gsm_network *net = subscr->net;
-
- llist_for_each_entry(trans, &net->trans_list, entry) {
- if (trans->subscr == subscr &&
- trans->protocol == proto &&
- trans->transaction_id == trans_id)
- return trans;
- }
- return NULL;
-}
-
-struct gsm_trans *trans_find_by_callref(struct gsm_network *net,
- u_int32_t callref)
-{
- struct gsm_trans *trans;
-
- llist_for_each_entry(trans, &net->trans_list, entry) {
- if (trans->callref == callref)
- return trans;
- }
- return NULL;
-}
-
-struct gsm_trans *trans_alloc(struct gsm_subscriber *subscr,
- u_int8_t protocol, u_int8_t trans_id,
- u_int32_t callref)
-{
- struct gsm_trans *trans;
-
- DEBUGP(DCC, "subscr=%p, subscr->net=%p\n", subscr, subscr->net);
-
- trans = talloc_zero(tall_trans_ctx, struct gsm_trans);
- if (!trans)
- return NULL;
-
- trans->subscr = subscr;
- subscr_get(trans->subscr);
-
- trans->protocol = protocol;
- trans->transaction_id = trans_id;
- trans->callref = callref;
-
- llist_add_tail(&trans->entry, &subscr->net->trans_list);
-
- return trans;
-}
-
-void trans_free(struct gsm_trans *trans)
-{
- switch (trans->protocol) {
- case GSM48_PDISC_CC:
- _gsm48_cc_trans_free(trans);
- break;
- case GSM48_PDISC_SMS:
- _gsm411_sms_trans_free(trans);
- break;
- }
-
- /* FIXME: implement a sane way to stop this. */
- if (!trans->conn && trans->paging_request) {
- LOGP(DNM, LOGL_ERROR,
- "Transaction freed while paging for sub: %llu\n",
- trans->subscr->id);
- trans->paging_request = NULL;
- }
-
- if (trans->subscr)
- subscr_put(trans->subscr);
-
- llist_del(&trans->entry);
-
- if (trans->conn)
- msc_release_connection(trans->conn);
-
-
- talloc_free(trans);
-}
-
-/* allocate an unused transaction ID for the given subscriber
- * in the given protocol using the ti_flag specified */
-int trans_assign_trans_id(struct gsm_subscriber *subscr,
- u_int8_t protocol, u_int8_t ti_flag)
-{
- struct gsm_network *net = subscr->net;
- struct gsm_trans *trans;
- unsigned int used_tid_bitmask = 0;
- int i, j, h;
-
- if (ti_flag)
- ti_flag = 0x8;
-
- /* generate bitmask of already-used TIDs for this (subscr,proto) */
- llist_for_each_entry(trans, &net->trans_list, entry) {
- if (trans->subscr != subscr ||
- trans->protocol != protocol ||
- trans->transaction_id == 0xff)
- continue;
- used_tid_bitmask |= (1 << trans->transaction_id);
- }
-
- /* find a new one, trying to go in a 'circular' pattern */
- for (h = 6; h > 0; h--)
- if (used_tid_bitmask & (1 << (h | ti_flag)))
- break;
- for (i = 0; i < 7; i++) {
- j = ((h + i) % 7) | ti_flag;
- if ((used_tid_bitmask & (1 << j)) == 0)
- return j;
- }
-
- return -1;
-}
-