aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNeels Hofmeyr <nhofmeyr@sysmocom.de>2017-07-13 02:03:50 +0200
committerNeels Hofmeyr <nhofmeyr@sysmocom.de>2017-07-13 02:03:50 +0200
commitd9f55fa8f569f555a4ac93fbc4c25d31044cbcd4 (patch)
treec4b0dbeefde2d95bdc3695735b1c146ee64dfd61
parentb271e460490131f7d9c4873057b7ebe0826803b8 (diff)
remove files obviously unrelated to gprs
-rw-r--r--src/ipaccess/Makefile.am66
-rw-r--r--src/ipaccess/abisip-find.c216
-rw-r--r--src/ipaccess/ipaccess-config.c1019
-rw-r--r--src/ipaccess/ipaccess-firmware.c135
-rw-r--r--src/ipaccess/ipaccess-proxy.c1226
-rw-r--r--src/ipaccess/network_listen.c257
-rw-r--r--src/libbsc/Makefile.am57
-rw-r--r--src/libbsc/abis_nm.c2917
-rw-r--r--src/libbsc/abis_nm_ipaccess.c87
-rw-r--r--src/libbsc/abis_nm_vty.c191
-rw-r--r--src/libbsc/abis_om2000.c2776
-rw-r--r--src/libbsc/abis_om2000_vty.c609
-rw-r--r--src/libbsc/abis_rsl.c2939
-rw-r--r--src/libbsc/arfcn_range_encode.c330
-rw-r--r--src/libbsc/bsc_api.c896
-rw-r--r--src/libbsc/bsc_ctrl_commands.c459
-rw-r--r--src/libbsc/bsc_ctrl_lookup.c107
-rw-r--r--src/libbsc/bsc_dyn_ts.c77
-rw-r--r--src/libbsc/bsc_init.c556
-rw-r--r--src/libbsc/bsc_msc.c320
-rw-r--r--src/libbsc/bsc_rf_ctrl.c534
-rw-r--r--src/libbsc/bsc_rll.c139
-rw-r--r--src/libbsc/bsc_subscriber.c168
-rw-r--r--src/libbsc/bsc_vty.c4281
-rw-r--r--src/libbsc/bts_ericsson_rbs2000.c204
-rw-r--r--src/libbsc/bts_init.c30
-rw-r--r--src/libbsc/bts_ipaccess_nanobts.c520
-rw-r--r--src/libbsc/bts_ipaccess_nanobts_omlattr.c240
-rw-r--r--src/libbsc/bts_nokia_site.c1739
-rw-r--r--src/libbsc/bts_siemens_bs11.c602
-rw-r--r--src/libbsc/bts_sysmobts.c60
-rw-r--r--src/libbsc/bts_unknown.c40
-rw-r--r--src/libbsc/chan_alloc.c543
-rw-r--r--src/libbsc/e1_config.c297
-rw-r--r--src/libbsc/gsm_04_08_utils.c664
-rw-r--r--src/libbsc/gsm_04_80_utils.c40
-rw-r--r--src/libbsc/handover_decision.c325
-rw-r--r--src/libbsc/handover_logic.c379
-rw-r--r--src/libbsc/meas_proc.c84
-rw-r--r--src/libbsc/meas_rep.c115
-rw-r--r--src/libbsc/net_init.c69
-rw-r--r--src/libbsc/paging.c456
-rw-r--r--src/libbsc/pcu_sock.c742
-rw-r--r--src/libbsc/rest_octets.c860
-rw-r--r--src/libbsc/system_information.c1169
-rw-r--r--src/libcommon-cs/Makefile.am21
-rw-r--r--src/libcommon-cs/a_reset.c224
-rw-r--r--src/libcommon-cs/common_cs.c155
-rw-r--r--src/libcommon-cs/common_cs_vty.c373
-rw-r--r--src/libfilter/Makefile.am26
-rw-r--r--src/libfilter/bsc_msg_acc.c118
-rw-r--r--src/libfilter/bsc_msg_filter.c398
-rw-r--r--src/libfilter/bsc_msg_vty.c140
-rw-r--r--src/libmgcp/Makefile.am46
-rw-r--r--src/libmgcp/g711common.h187
-rw-r--r--src/libmgcp/mgcp_common.c54
-rw-r--r--src/libmgcp/mgcp_network.c1160
-rw-r--r--src/libmgcp/mgcp_osmux.c586
-rw-r--r--src/libmgcp/mgcp_protocol.c1595
-rw-r--r--src/libmgcp/mgcp_sdp.c305
-rw-r--r--src/libmgcp/mgcp_transcode.c612
-rw-r--r--src/libmgcp/mgcp_vty.c1543
-rw-r--r--src/libmgcp/mgcpgw_client.c616
-rw-r--r--src/libmgcp/mgcpgw_client_vty.c167
-rw-r--r--src/libmsc/Makefile.am67
-rw-r--r--src/libmsc/a_iface.c561
-rw-r--r--src/libmsc/a_iface_bssap.c702
-rw-r--r--src/libmsc/auth.c42
-rw-r--r--src/libmsc/ctrl_commands.c88
-rw-r--r--src/libmsc/db.c851
-rw-r--r--src/libmsc/gsm_04_08.c3899
-rw-r--r--src/libmsc/gsm_04_11.c1074
-rw-r--r--src/libmsc/gsm_04_80.c155
-rw-r--r--src/libmsc/gsm_subscriber.c190
-rw-r--r--src/libmsc/iucs.c189
-rw-r--r--src/libmsc/iucs_ranap.c106
-rw-r--r--src/libmsc/meas_feed.c168
-rw-r--r--src/libmsc/meas_feed.h12
-rw-r--r--src/libmsc/mncc.c107
-rw-r--r--src/libmsc/mncc_builtin.c433
-rw-r--r--src/libmsc/mncc_sock.c318
-rw-r--r--src/libmsc/msc_ifaces.c369
-rw-r--r--src/libmsc/msc_vty.c181
-rw-r--r--src/libmsc/osmo_msc.c327
-rw-r--r--src/libmsc/rrlp.c104
-rw-r--r--src/libmsc/silent_call.c161
-rw-r--r--src/libmsc/smpp_openbsc.c763
-rw-r--r--src/libmsc/smpp_smsc.c1030
-rw-r--r--src/libmsc/smpp_smsc.h166
-rw-r--r--src/libmsc/smpp_utils.c62
-rw-r--r--src/libmsc/smpp_vty.c612
-rw-r--r--src/libmsc/sms_queue.c578
-rw-r--r--src/libmsc/subscr_conn.c372
-rw-r--r--src/libmsc/token_auth.c167
-rw-r--r--src/libmsc/transaction.c214
-rw-r--r--src/libmsc/ussd.c103
-rw-r--r--src/libmsc/vty_interface_layer3.c1019
-rw-r--r--src/libtrau/Makefile.am31
-rw-r--r--src/libtrau/rtp_proxy.c764
-rw-r--r--src/libtrau/trau_mux.c547
-rw-r--r--src/libtrau/trau_upqueue.c27
-rw-r--r--src/libvlr/Makefile.am19
-rw-r--r--src/libvlr/vlr.c1112
-rw-r--r--src/libvlr/vlr_access_req_fsm.c789
-rw-r--r--src/libvlr/vlr_access_req_fsm.h17
-rw-r--r--src/libvlr/vlr_auth_fsm.c605
-rw-r--r--src/libvlr/vlr_auth_fsm.h52
-rw-r--r--src/libvlr/vlr_core.h21
-rw-r--r--src/libvlr/vlr_lu_fsm.c1436
-rw-r--r--src/libvlr/vlr_lu_fsm.h18
-rw-r--r--src/osmo-bsc/Makefile.am57
-rw-r--r--src/osmo-bsc/osmo_bsc_api.c569
-rw-r--r--src/osmo-bsc/osmo_bsc_audio.c135
-rw-r--r--src/osmo-bsc/osmo_bsc_bssap.c720
-rw-r--r--src/osmo-bsc/osmo_bsc_ctrl.c680
-rw-r--r--src/osmo-bsc/osmo_bsc_filter.c381
-rw-r--r--src/osmo-bsc/osmo_bsc_grace.c169
-rw-r--r--src/osmo-bsc/osmo_bsc_main.c305
-rw-r--r--src/osmo-bsc/osmo_bsc_msc.c600
-rw-r--r--src/osmo-bsc/osmo_bsc_reset.c190
-rw-r--r--src/osmo-bsc/osmo_bsc_sigtran.c465
-rw-r--r--src/osmo-bsc/osmo_bsc_vty.c1053
-rw-r--r--src/osmo-bsc_mgcp/Makefile.am36
-rw-r--r--src/osmo-bsc_mgcp/mgcp_main.c311
-rw-r--r--src/osmo-bsc_nat/Makefile.am59
-rw-r--r--src/osmo-bsc_nat/bsc_filter.c218
-rw-r--r--src/osmo-bsc_nat/bsc_mgcp_utils.c1152
-rw-r--r--src/osmo-bsc_nat/bsc_nat.c1736
-rw-r--r--src/osmo-bsc_nat/bsc_nat_ctrl.c524
-rw-r--r--src/osmo-bsc_nat/bsc_nat_filter.c119
-rw-r--r--src/osmo-bsc_nat/bsc_nat_rewrite.c714
-rw-r--r--src/osmo-bsc_nat/bsc_nat_rewrite_trie.c259
-rw-r--r--src/osmo-bsc_nat/bsc_nat_utils.c535
-rw-r--r--src/osmo-bsc_nat/bsc_nat_vty.c1336
-rw-r--r--src/osmo-bsc_nat/bsc_sccp.c247
-rw-r--r--src/osmo-bsc_nat/bsc_ussd.c453
-rw-r--r--src/osmo-msc/Makefile.am52
-rw-r--r--src/osmo-msc/msc_main.c528
-rw-r--r--src/utils/Makefile.am147
-rw-r--r--src/utils/bs11_config.c953
-rw-r--r--src/utils/isdnsync.c189
-rw-r--r--src/utils/meas_db.c330
-rw-r--r--src/utils/meas_db.h17
-rw-r--r--src/utils/meas_json.c190
-rw-r--r--src/utils/meas_pcap2db.c138
-rw-r--r--src/utils/meas_udp2db.c126
-rw-r--r--src/utils/meas_vis.c310
-rw-r--r--src/utils/smpp_mirror.c329
148 files changed, 0 insertions, 74826 deletions
diff --git a/src/ipaccess/Makefile.am b/src/ipaccess/Makefile.am
deleted file mode 100644
index 4dfe2473..00000000
--- a/src/ipaccess/Makefile.am
+++ /dev/null
@@ -1,66 +0,0 @@
-AM_CPPFLAGS = \
- $(all_includes) \
- -I$(top_srcdir)/include \
- -I$(top_builddir) \
- $(NULL)
-
-AM_CFLAGS = \
- -Wall \
- $(LIBOSMOCORE_CFLAGS) \
- $(LIBOSMOGSM_CFLAGS) \
- $(LIBOSMOABIS_CFLAGS) \
- $(COVERAGE_CFLAGS) \
- $(NULL)
-
-AM_LDFLAGS = \
- $(COVERAGE_LDFLAGS) \
- $(NULL)
-
-OSMO_LIBS = \
- $(LIBOSMOCORE_LIBS) \
- $(LIBOSMOGSM_LIBS) \
- $(LIBOSMOABIS_LIBS) \
- $(NULL)
-
-bin_PROGRAMS = \
- abisip-find \
- ipaccess-config \
- ipaccess-proxy \
- $(NULL)
-
-abisip_find_LDADD = \
- $(top_builddir)/src/libbsc/libbsc.a \
- $(top_builddir)/src/libtrau/libtrau.a \
- $(top_builddir)/src/libcommon/libcommon.a \
- $(OSMO_LIBS) \
- $(NULL)
-
-abisip_find_SOURCES = \
- abisip-find.c \
- $(NULL)
-
-ipaccess_config_SOURCES = \
- ipaccess-config.c \
- ipaccess-firmware.c \
- network_listen.c \
- $(NULL)
-
-# FIXME: resolve the bogus dependencies patched around here:
-ipaccess_config_LDADD = \
- $(top_builddir)/src/libbsc/libbsc.a \
- $(top_builddir)/src/libcommon-cs/libcommon-cs.a \
- $(top_builddir)/src/libtrau/libtrau.a \
- $(top_builddir)/src/libcommon/libcommon.a \
- $(OSMO_LIBS) \
- $(NULL)
-
-ipaccess_proxy_SOURCES = \
- ipaccess-proxy.c \
- $(NULL)
-
-ipaccess_proxy_LDADD = \
- $(top_builddir)/src/libbsc/libbsc.a \
- $(top_builddir)/src/libtrau/libtrau.a \
- $(top_builddir)/src/libcommon/libcommon.a \
- $(OSMO_LIBS) \
- $(NULL)
diff --git a/src/ipaccess/abisip-find.c b/src/ipaccess/abisip-find.c
deleted file mode 100644
index 21d9f229..00000000
--- a/src/ipaccess/abisip-find.c
+++ /dev/null
@@ -1,216 +0,0 @@
-/* ip.access nanoBTS configuration tool */
-
-/* (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 <unistd.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-
-
-#include <osmocom/core/select.h>
-#include <osmocom/core/timer.h>
-#include <osmocom/gsm/protocol/ipaccess.h>
-#include <osmocom/gsm/ipa.h>
-#include <openbsc/gsm_data.h>
-
-static int udp_sock(const char *ifname)
-{
- int fd, rc, bc = 1;
- struct sockaddr_in sa;
-
- fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
- if (fd < 0)
- return fd;
-
- if (ifname) {
-#ifdef __FreeBSD__
- rc = setsockopt(fd, SOL_SOCKET, IP_RECVIF, ifname,
- strlen(ifname));
-#else
- rc = setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, ifname,
- strlen(ifname));
-#endif
- if (rc < 0)
- goto err;
- }
-
- memset(&sa, 0, sizeof(sa));
- sa.sin_family = AF_INET;
- sa.sin_port = htons(3006);
- sa.sin_addr.s_addr = INADDR_ANY;
-
- rc = bind(fd, (struct sockaddr *)&sa, sizeof(sa));
- if (rc < 0)
- goto err;
-
- rc = setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &bc, sizeof(bc));
- if (rc < 0)
- goto err;
-
-#if 0
- /* we cannot bind, since the response packets don't come from
- * the broadcast address */
- sa.sin_family = AF_INET;
- sa.sin_port = htons(3006);
- inet_aton("255.255.255.255", &sa.sin_addr);
-
- rc = connect(fd, (struct sockaddr *)&sa, sizeof(sa));
- if (rc < 0)
- goto err;
-#endif
- return fd;
-
-err:
- close(fd);
- return rc;
-}
-
-const unsigned char find_pkt[] = { 0x00, 0x0b+8, IPAC_PROTO_IPACCESS, 0x00,
- IPAC_MSGT_ID_GET,
- 0x01, IPAC_IDTAG_MACADDR,
- 0x01, IPAC_IDTAG_IPADDR,
- 0x01, IPAC_IDTAG_UNIT,
- 0x01, IPAC_IDTAG_LOCATION1,
- 0x01, IPAC_IDTAG_LOCATION2,
- 0x01, IPAC_IDTAG_EQUIPVERS,
- 0x01, IPAC_IDTAG_SWVERSION,
- 0x01, IPAC_IDTAG_UNITNAME,
- 0x01, IPAC_IDTAG_SERNR,
- };
-
-
-static int bcast_find(int fd)
-{
- struct sockaddr_in sa;
-
- sa.sin_family = AF_INET;
- sa.sin_port = htons(3006);
- inet_aton("255.255.255.255", &sa.sin_addr);
-
- return sendto(fd, find_pkt, sizeof(find_pkt), 0, (struct sockaddr *) &sa, sizeof(sa));
-}
-
-static int parse_response(unsigned char *buf, int len)
-{
- uint8_t t_len;
- uint8_t t_tag;
- uint8_t *cur = buf;
-
- while (cur < buf + len) {
- t_len = *cur++;
- t_tag = *cur++;
-
- printf("%s='%s' ", ipa_ccm_idtag_name(t_tag), cur);
-
- cur += t_len;
- }
- printf("\n");
- return 0;
-}
-
-static int read_response(int fd)
-{
- unsigned char buf[255];
- struct sockaddr_in sa;
- int len;
- socklen_t sa_len = sizeof(sa);
-
- len = recvfrom(fd, buf, sizeof(buf), 0, (struct sockaddr *)&sa, &sa_len);
- if (len < 0)
- return len;
-
- /* 2 bytes length, 1 byte protocol */
- if (buf[2] != IPAC_PROTO_IPACCESS)
- return 0;
-
- if (buf[4] != IPAC_MSGT_ID_RESP)
- return 0;
-
- return parse_response(buf+6, len-6);
-}
-
-static int bfd_cb(struct osmo_fd *bfd, unsigned int flags)
-{
- if (flags & BSC_FD_READ)
- return read_response(bfd->fd);
- if (flags & BSC_FD_WRITE) {
- bfd->when &= ~BSC_FD_WRITE;
- return bcast_find(bfd->fd);
- }
- return 0;
-}
-
-static struct osmo_timer_list timer;
-
-static void timer_cb(void *_data)
-{
- struct osmo_fd *bfd = _data;
-
- bfd->when |= BSC_FD_WRITE;
-
- osmo_timer_schedule(&timer, 5, 0);
-}
-
-int main(int argc, char **argv)
-{
- struct osmo_fd bfd;
- char *ifname = NULL;
- int rc;
-
- printf("abisip-find (C) 2009 by Harald Welte\n");
- printf("This is FREE SOFTWARE with ABSOLUTELY NO WARRANTY\n\n");
-
- if (argc < 2) {
- fprintf(stdout, "you might need to specify the outgoing\n"
- " network interface, e.g. ``%s eth0''\n", argv[0]);
- } else {
- ifname = argv[1];
- }
-
- bfd.cb = bfd_cb;
- bfd.when = BSC_FD_READ | BSC_FD_WRITE;
- bfd.fd = udp_sock(ifname);
- if (bfd.fd < 0) {
- perror("Cannot create local socket for broadcast udp");
- exit(1);
- }
-
- rc = osmo_fd_register(&bfd);
- if (rc < 0) {
- fprintf(stderr, "Cannot register FD\n");
- exit(1);
- }
-
- osmo_timer_setup(&timer, timer_cb, &bfd);
- osmo_timer_schedule(&timer, 5, 0);
-
- printf("Trying to find ip.access BTS by broadcast UDP...\n");
-
- while (1) {
- rc = osmo_select_main(0);
- if (rc < 0)
- exit(3);
- }
-
- exit(0);
-}
-
diff --git a/src/ipaccess/ipaccess-config.c b/src/ipaccess/ipaccess-config.c
deleted file mode 100644
index 6822c06a..00000000
--- a/src/ipaccess/ipaccess-config.c
+++ /dev/null
@@ -1,1019 +0,0 @@
-/* ip.access nanoBTS configuration tool */
-
-/* (C) 2009-2010 by Harald Welte <laforge@gnumonks.org>
- * (C) 2009-2011 by Holger Hans Peter Freyther
- * (C) 2009-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 <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <getopt.h>
-#include <errno.h>
-#include <sys/fcntl.h>
-#include <sys/stat.h>
-
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-
-
-#include <osmocom/core/application.h>
-#include <osmocom/core/select.h>
-#include <osmocom/core/timer.h>
-#include <openbsc/ipaccess.h>
-#include <openbsc/common_bsc.h>
-#include <osmocom/abis/e1_input.h>
-#include <openbsc/abis_nm.h>
-#include <openbsc/signal.h>
-#include <openbsc/debug.h>
-#include <openbsc/network_listen.h>
-#include <osmocom/abis/ipaccess.h>
-#include <openbsc/gsm_data.h>
-#include <openbsc/abis_nm.h>
-#include <openbsc/signal.h>
-#include <openbsc/debug.h>
-#include <openbsc/network_listen.h>
-#include <osmocom/core/talloc.h>
-#include <osmocom/abis/abis.h>
-#include <osmocom/gsm/protocol/gsm_12_21.h>
-
-struct gsm_network *bsc_gsmnet;
-
-static int net_listen_testnr;
-static int restart;
-static char *prim_oml_ip;
-static char *bts_ip_addr, *bts_ip_mask, *bts_ip_gw;
-static char *unit_id;
-static uint16_t nv_flags;
-static uint16_t nv_mask;
-static char *software = NULL;
-static int sw_load_state = 0;
-static int oml_state = 0;
-static int dump_files = 0;
-static char *firmware_analysis = NULL;
-static int found_trx = 0;
-static int loop_tests = 0;
-
-static void *tall_ctx_config = NULL;
-static struct abis_nm_sw_desc *sw_load1 = NULL;
-static struct abis_nm_sw_desc *sw_load2 = NULL;
-
-/*
-static uint8_t prim_oml_attr[] = { 0x95, 0x00, 7, 0x88, 192, 168, 100, 11, 0x00, 0x00 };
-static uint8_t unit_id_attr[] = { 0x91, 0x00, 9, '2', '3', '4', '2', '/' , '0', '/', '0', 0x00 };
-*/
-
-extern int ipaccess_fd_cb(struct osmo_fd *bfd, unsigned int what);
-extern struct e1inp_line_ops ipaccess_e1inp_line_ops;
-
-/* Actively connect to a BTS. Currently used by ipaccess-config.c */
-static int ipaccess_connect(struct e1inp_line *line, struct sockaddr_in *sa)
-{
- struct e1inp_ts *e1i_ts = &line->ts[0];
- struct osmo_fd *bfd = &e1i_ts->driver.ipaccess.fd;
- int ret, on = 1;
-
- bfd->fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
- bfd->cb = ipaccess_fd_cb;
- bfd->when = BSC_FD_READ | BSC_FD_WRITE;
- bfd->data = line;
- bfd->priv_nr = E1INP_SIGN_OML;
-
- if (bfd->fd < 0) {
- LOGP(DLINP, LOGL_ERROR, "could not create TCP socket.\n");
- return -EIO;
- }
-
- ret = setsockopt(bfd->fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
- if (ret < 0) {
- LOGP(DLINP, LOGL_ERROR, "could not set socket option\n");
- close(bfd->fd);
- return -EIO;
- }
-
- ret = connect(bfd->fd, (struct sockaddr *) sa, sizeof(*sa));
- if (ret < 0) {
- LOGP(DLINP, LOGL_ERROR, "could not connect socket\n");
- close(bfd->fd);
- return ret;
- }
-
- ret = osmo_fd_register(bfd);
- if (ret < 0) {
- close(bfd->fd);
- return ret;
- }
- return ret;
- //return e1inp_line_register(line);
-}
-
-/* configure pseudo E1 line in ip.access style and connect to BTS */
-static 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;
-
- line->driver = e1inp_driver_find("ipa");
- if (!line->driver) {
- fprintf(stderr, "cannot `ipa' driver, giving up.\n");
- return -EINVAL;
- }
- line->ops = &ipaccess_e1inp_line_ops;
-
- /* create E1 timeslots for signalling and TRAU frames */
- e1inp_ts_config_sign(&line->ts[1-1], line);
- e1inp_ts_config_sign(&line->ts[2-1], line);
-
- /* 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);
-}
-
-/*
- * Callback function for NACK on the OML NM
- *
- * Currently we send the config requests but don't check the
- * result. The nanoBTS will send us a NACK when we did something the
- * BTS didn't like.
- */
-static int ipacc_msg_nack(uint8_t mt)
-{
- fprintf(stderr, "Failure to set attribute. This seems fatal\n");
- exit(-1);
- return 0;
-}
-
-static void check_restart_or_exit(struct gsm_bts_trx *trx)
-{
- if (restart) {
- abis_nm_ipaccess_restart(trx);
- } else {
- exit(0);
- }
-}
-
-static int ipacc_msg_ack(uint8_t mt, struct gsm_bts_trx *trx)
-{
- if (sw_load_state == 1) {
- fprintf(stderr, "The new software is activaed.\n");
- check_restart_or_exit(trx);
- } else if (oml_state == 1) {
- fprintf(stderr, "Set the NV Attributes.\n");
- check_restart_or_exit(trx);
- }
-
- return 0;
-}
-
-static const uint8_t phys_conf_min[] = { 0x02 };
-
-static uint16_t build_physconf(uint8_t *physconf_buf, const struct rxlev_stats *st)
-{
- uint16_t *whitelist = (uint16_t *) (physconf_buf + 4);
- int num_arfcn;
- unsigned int arfcnlist_size;
-
- /* Create whitelist from rxlevels */
- physconf_buf[0] = phys_conf_min[0];
- physconf_buf[1] = NM_IPAC_EIE_ARFCN_WHITE;
- num_arfcn = ipac_rxlevstat2whitelist(whitelist, st, 0, 100);
- arfcnlist_size = num_arfcn * 2;
- *((uint16_t *) (physconf_buf+2)) = htons(arfcnlist_size);
- DEBUGP(DNM, "physconf_buf (%s)\n", osmo_hexdump(physconf_buf, arfcnlist_size+4));
- return arfcnlist_size+4;
-}
-
-static int nwl_sig_cb(unsigned int subsys, unsigned int signal,
- void *handler_data, void *signal_data)
-{
- struct gsm_bts_trx *trx;
- uint8_t physconf_buf[2*NUM_ARFCNS+16];
- uint16_t physconf_len;
-
- switch (signal) {
- case S_IPAC_NWL_COMPLETE:
- trx = signal_data;
- DEBUGP(DNM, "received S_IPAC_NWL_COMPLETE signal\n");
- switch (trx->ipaccess.test_nr) {
- case NM_IPACC_TESTNO_CHAN_USAGE:
- /* Dump RxLev results */
- //rxlev_stat_dump(&trx->ipaccess.rxlev_stat);
- /* Create whitelist from results */
- physconf_len = build_physconf(physconf_buf,
- &trx->ipaccess.rxlev_stat);
- /* Start next test abbout BCCH channel usage */
- ipac_nwl_test_start(trx, NM_IPACC_TESTNO_BCCH_CHAN_USAGE,
- physconf_buf, physconf_len);
- break;
- case NM_IPACC_TESTNO_BCCH_CHAN_USAGE:
- /* Dump BCCH RxLev results */
- //rxlev_stat_dump(&trx->ipaccess.rxlev_stat);
- /* Create whitelist from results */
- physconf_len = build_physconf(physconf_buf,
- &trx->ipaccess.rxlev_stat);
- /* Start next test about BCCH info */
- ipac_nwl_test_start(trx, NM_IPACC_TESTNO_BCCH_INFO,
- physconf_buf, physconf_len);
- break;
- case NM_IPACC_TESTNO_BCCH_INFO:
- /* re-start full process with CHAN_USAGE */
- if (loop_tests) {
- DEBUGP(DNM, "starting next test cycle\n");
- ipac_nwl_test_start(trx, net_listen_testnr, phys_conf_min,
- sizeof(phys_conf_min));
- } else {
- exit(0);
- }
- break;
- }
- break;
- }
- return 0;
-}
-
-static int nm_state_event(int evt, uint8_t obj_class, void *obj,
- struct gsm_nm_state *old_state, struct gsm_nm_state *new_state,
- struct abis_om_obj_inst *obj_inst);
-
-static int nm_sig_cb(unsigned int subsys, unsigned int signal,
- void *handler_data, void *signal_data)
-{
- struct ipacc_ack_signal_data *ipacc_data;
- struct nm_statechg_signal_data *nsd;
-
- switch (signal) {
- case S_NM_IPACC_NACK:
- ipacc_data = signal_data;
- return ipacc_msg_nack(ipacc_data->msg_type);
- case S_NM_IPACC_ACK:
- ipacc_data = signal_data;
- return ipacc_msg_ack(ipacc_data->msg_type, ipacc_data->trx);
- case S_NM_IPACC_RESTART_ACK:
- printf("The BTS has acked the restart. Exiting.\n");
- exit(0);
- break;
- case S_NM_IPACC_RESTART_NACK:
- printf("The BTS has nacked the restart. Exiting.\n");
- exit(0);
- break;
- case S_NM_STATECHG_OPER:
- case S_NM_STATECHG_ADM:
- nsd = signal_data;
- nm_state_event(signal, nsd->obj_class, nsd->obj, nsd->old_state,
- nsd->new_state, nsd->obj_inst);
- break;
- default:
- break;
- }
-
- return 0;
-}
-
-/* callback function passed to the ABIS OML code */
-static int percent;
-static int percent_old;
-static int swload_cbfn(unsigned int hook, unsigned int event, struct msgb *_msg,
- void *data, void *param)
-{
- struct msgb *msg;
- struct gsm_bts_trx *trx;
-
- if (hook != GSM_HOOK_NM_SWLOAD)
- return 0;
-
- trx = (struct gsm_bts_trx *) data;
-
- switch (event) {
- case NM_MT_LOAD_INIT_ACK:
- fprintf(stdout, "Software Load Initiate ACK\n");
- break;
- case NM_MT_LOAD_INIT_NACK:
- fprintf(stderr, "ERROR: Software Load Initiate NACK\n");
- exit(5);
- break;
- case NM_MT_LOAD_END_ACK:
- fprintf(stderr, "LOAD END ACK...");
- /* now make it the default */
- sw_load_state = 1;
-
- msg = msgb_alloc(1024, "sw: nvattr");
- msg->l2h = msgb_put(msg, 3);
- msg->l3h = &msg->l2h[3];
-
- /* activate software */
- if (sw_load1)
- abis_nm_put_sw_desc(msg, sw_load1, true);
-
- if (sw_load2)
- abis_nm_put_sw_desc(msg, sw_load2, true);
-
- /* fill in the data */
- msg->l2h[0] = NM_ATT_IPACC_CUR_SW_CFG;
- msg->l2h[1] = msgb_l3len(msg) >> 8;
- msg->l2h[2] = msgb_l3len(msg) & 0xff;
- printf("Foo l2h: %p l3h: %p... length l2: %u l3: %u\n", msg->l2h, msg->l3h, msgb_l2len(msg), msgb_l3len(msg));
- abis_nm_ipaccess_set_nvattr(trx, msg->l2h, msgb_l2len(msg));
- msgb_free(msg);
- break;
- case NM_MT_LOAD_END_NACK:
- fprintf(stderr, "ERROR: Software Load End NACK\n");
- exit(3);
- break;
- case NM_MT_ACTIVATE_SW_NACK:
- fprintf(stderr, "ERROR: Activate Software NACK\n");
- exit(4);
- break;
- case NM_MT_ACTIVATE_SW_ACK:
- break;
- case NM_MT_LOAD_SEG_ACK:
- percent = abis_nm_software_load_status(trx->bts);
- if (percent > percent_old)
- printf("Software Download Progress: %d%%\n", percent);
- percent_old = percent;
- break;
- case NM_MT_LOAD_ABORT:
- fprintf(stderr, "ERROR: Load aborted by the BTS.\n");
- exit(6);
- break;
- }
- return 0;
-}
-
-static void nv_put_ip_if_cfg(struct msgb *nmsg, uint32_t ip, uint32_t mask)
-{
- msgb_put_u8(nmsg, NM_ATT_IPACC_IP_IF_CFG);
-
- msgb_put_u32(nmsg, ip);
- msgb_put_u32(nmsg, mask);
-}
-
-static void nv_put_gw_cfg(struct msgb *nmsg, uint32_t addr, uint32_t mask, uint32_t gw)
-{
- msgb_put_u8(nmsg, NM_ATT_IPACC_IP_GW_CFG);
- msgb_put_u32(nmsg, addr);
- msgb_put_u32(nmsg, mask);
- msgb_put_u32(nmsg, gw);
-}
-
-static void nv_put_unit_id(struct msgb *nmsg, const char *unit_id)
-{
- msgb_tl16v_put(nmsg, NM_ATT_IPACC_UNIT_ID, strlen(unit_id)+1,
- (const uint8_t *)unit_id);
-}
-
-static void nv_put_prim_oml(struct msgb *nmsg, uint32_t ip, uint16_t port)
-{
- int len;
-
- /* 0x88 + IP + port */
- len = 1 + sizeof(ip) + sizeof(port);
-
- msgb_put_u8(nmsg, NM_ATT_IPACC_PRIM_OML_CFG_LIST);
- msgb_put_u16(nmsg, len);
-
- msgb_put_u8(nmsg, 0x88);
-
- /* IP address */
- msgb_put_u32(nmsg, ip);
-
- /* port number */
- msgb_put_u16(nmsg, port);
-}
-
-static void nv_put_flags(struct msgb *nmsg, uint16_t nv_flags, uint16_t nv_mask)
-{
- msgb_put_u8(nmsg, NM_ATT_IPACC_NV_FLAGS);
- msgb_put_u16(nmsg, sizeof(nv_flags) + sizeof(nv_mask));
- msgb_put_u8(nmsg, nv_flags & 0xff);
- msgb_put_u8(nmsg, nv_mask & 0xff);
- msgb_put_u8(nmsg, nv_flags >> 8);
- msgb_put_u8(nmsg, nv_mask >> 8);
-}
-
-/* human-readable test names for the ip.access tests */
-static const struct value_string ipa_test_strs[] = {
- { 64, "ccch-usage" },
- { 65, "bcch-usage" },
- { 66, "freq-sync" },
- { 67, "rtp-usage" },
- { 68, "rtp-perf" },
- { 69, "gprs-ccch" },
- { 70, "pccch-usage" },
- { 71, "gprs-usage" },
- { 72, "esta-mf" },
- { 73, "uplink-mf" },
- { 74, "dolink-mf" },
- { 75, "tbf-details" },
- { 76, "tbf-usage" },
- { 77, "llc-data" },
- { 78, "pdch-usage" },
- { 79, "power-control" },
- { 80, "link-adaption" },
- { 81, "tch-usage" },
- { 82, "amr-mf" },
- { 83, "rtp-multiplex-perf" },
- { 84, "rtp-multiplex-usage" },
- { 85, "srtp-multiplex-usage" },
- { 86, "abis-traffic" },
- { 89, "gprs-multiplex-perf" },
- { 90, "gprs-multiplex-usage" },
- { 0, NULL },
-};
-
-/* human-readable names for the ip.access nanoBTS NVRAM Flags */
-static const struct value_string ipa_nvflag_strs[] = {
- { 0x0001, "static-ip" },
- { 0x0002, "static-gw" },
- { 0x0004, "no-dhcp-vsi" },
- { 0x0008, "dhcp-enabled" },
- { 0x0040, "led-disabled" },
- { 0x0100, "secondary-oml-enabled" },
- { 0x0200, "diag-enabled" },
- { 0x0400, "cli-enabled" },
- { 0x0800, "http-enabled" },
- { 0x1000, "post-enabled" },
- { 0x2000, "snmp-enabled" },
- { 0, NULL }
-};
-
-/* set the flags in flags/mask according to a string-identified flag and 'enable' */
-static int ipa_nvflag_set(uint16_t *flags, uint16_t *mask, const char *name, int en)
-{
- int rc;
- rc = get_string_value(ipa_nvflag_strs, name);
- if (rc < 0)
- return rc;
-
- *mask |= rc;
- if (en)
- *flags |= rc;
- else
- *flags &= ~rc;
-
- return 0;
-}
-
-static void bootstrap_om(struct gsm_bts_trx *trx)
-{
- struct msgb *nmsg = msgb_alloc(1024, "nested msgb");
- int need_to_set_attr = 0;
- int len;
-
- printf("OML link established using TRX %d\n", trx->nr);
-
- if (unit_id) {
- len = strlen(unit_id);
- if (len > nmsg->data_len-10)
- goto out_err;
- printf("setting Unit ID to '%s'\n", unit_id);
- nv_put_unit_id(nmsg, unit_id);
- need_to_set_attr = 1;
- }
- if (prim_oml_ip) {
- struct in_addr ia;
-
- if (!inet_aton(prim_oml_ip, &ia)) {
- fprintf(stderr, "invalid IP address: %s\n",
- prim_oml_ip);
- goto out_err;
- }
-
- printf("setting primary OML link IP to '%s'\n", inet_ntoa(ia));
- nv_put_prim_oml(nmsg, ntohl(ia.s_addr), 0);
- need_to_set_attr = 1;
- }
- if (nv_mask) {
- printf("setting NV Flags/Mask to 0x%04x/0x%04x\n",
- nv_flags, nv_mask);
- nv_put_flags(nmsg, nv_flags, nv_mask);
- need_to_set_attr = 1;
- }
- if (bts_ip_addr && bts_ip_mask) {
- struct in_addr ia_addr, ia_mask;
-
- if (!inet_aton(bts_ip_addr, &ia_addr)) {
- fprintf(stderr, "invalid IP address: %s\n",
- bts_ip_addr);
- goto out_err;
- }
-
- if (!inet_aton(bts_ip_mask, &ia_mask)) {
- fprintf(stderr, "invalid IP address: %s\n",
- bts_ip_mask);
- goto out_err;
- }
-
- printf("setting static IP Address/Mask\n");
- nv_put_ip_if_cfg(nmsg, ntohl(ia_addr.s_addr), ntohl(ia_mask.s_addr));
- need_to_set_attr = 1;
- }
- if (bts_ip_gw) {
- struct in_addr ia_gw;
-
- if (!inet_aton(bts_ip_gw, &ia_gw)) {
- fprintf(stderr, "invalid IP address: %s\n",
- bts_ip_gw);
- goto out_err;
- }
-
- printf("setting static IP Gateway\n");
- /* we only set the default gateway with zero addr/mask */
- nv_put_gw_cfg(nmsg, 0, 0, ntohl(ia_gw.s_addr));
- need_to_set_attr = 1;
- }
-
- if (need_to_set_attr) {
- abis_nm_ipaccess_set_nvattr(trx, nmsg->head, nmsg->len);
- oml_state = 1;
- }
-
- if (restart && !prim_oml_ip && !software) {
- printf("restarting BTS\n");
- abis_nm_ipaccess_restart(trx);
- }
-
-out_err:
- msgb_free(nmsg);
-}
-
-static int nm_state_event(int evt, uint8_t obj_class, void *obj,
- struct gsm_nm_state *old_state, struct gsm_nm_state *new_state,
- struct abis_om_obj_inst *obj_inst)
-{
- if (obj_class == NM_OC_BASEB_TRANSC) {
- if (!found_trx && obj_inst->trx_nr != 0xff) {
- struct gsm_bts_trx *trx = container_of(obj, struct gsm_bts_trx, bb_transc);
- bootstrap_om(trx);
- found_trx = 1;
- }
- } else if (evt == S_NM_STATECHG_OPER &&
- obj_class == NM_OC_RADIO_CARRIER &&
- new_state->availability == 3) {
- struct gsm_bts_trx *trx = obj;
-
- if (net_listen_testnr)
- ipac_nwl_test_start(trx, net_listen_testnr,
- phys_conf_min, sizeof(phys_conf_min));
- else if (software) {
- int rc;
- printf("Attempting software upload with '%s'\n", software);
- rc = abis_nm_software_load(trx->bts, trx->nr, software, 19, 0, swload_cbfn, trx);
- if (rc < 0) {
- fprintf(stderr, "Failed to start software load\n");
- exit(-3);
- }
- }
- }
- return 0;
-}
-
-static struct abis_nm_sw_desc *create_swload(struct sdp_header *header)
-{
- struct abis_nm_sw_desc *load;
-
- load = talloc_zero(tall_ctx_config, struct abis_nm_sw_desc);
-
- osmo_strlcpy((char *)load->file_id, header->firmware_info.sw_part,
- sizeof(load->file_id));
- load->file_id_len = strlen((char*)load->file_id) + 1;
-
- osmo_strlcpy((char *)load->file_version, header->firmware_info.version,
- sizeof(load->file_version));
- load->file_version_len = strlen((char*)load->file_version) + 1;
-
- return load;
-}
-
-static int find_sw_load_params(const char *filename)
-{
- struct stat stat;
- struct sdp_header *header;
- struct llist_head *entry;
- int fd;
- void *tall_firm_ctx = 0;
-
- entry = talloc_zero(tall_firm_ctx, struct llist_head);
- INIT_LLIST_HEAD(entry);
-
- fd = open(filename, O_RDONLY);
- if (!fd) {
- perror("nada");
- return -1;
- }
-
- /* verify the file */
- if (fstat(fd, &stat) == -1) {
- perror("Can not stat the file");
- close(fd);
- return -1;
- }
-
- ipaccess_analyze_file(fd, stat.st_size, 0, entry);
- if (close(fd) != 0) {
- perror("Close failed.\n");
- return -1;
- }
-
- /* try to find what we are looking for */
- llist_for_each_entry(header, entry, entry) {
- if (ntohs(header->firmware_info.more_more_magic) == 0x1000) {
- sw_load1 = create_swload(header);
- } else if (ntohs(header->firmware_info.more_more_magic) == 0x2001) {
- sw_load2 = create_swload(header);
- }
- }
-
- if (!sw_load1 || !sw_load2) {
- fprintf(stderr, "Did not find data.\n");
- talloc_free(tall_firm_ctx);
- return -1;
- }
-
- talloc_free(tall_firm_ctx);
- return 0;
-}
-
-static void dump_entry(struct sdp_header_item *sub_entry, int part, int fd)
-{
- int out_fd;
- int copied;
- char filename[4096];
- off_t target;
-
- if (!dump_files)
- return;
-
- if (sub_entry->header_entry.something1 == 0)
- return;
-
- snprintf(filename, sizeof(filename), "part.%d", part++);
- out_fd = open(filename, O_WRONLY | O_CREAT, 0660);
- if (out_fd < 0) {
- perror("Can not dump firmware");
- return;
- }
-
- target = sub_entry->absolute_offset + ntohl(sub_entry->header_entry.start) + 4;
- if (lseek(fd, target, SEEK_SET) != target) {
- perror("seek failed");
- close(out_fd);
- return;
- }
-
- for (copied = 0; copied < ntohl(sub_entry->header_entry.length); ++copied) {
- char c;
- if (read(fd, &c, sizeof(c)) != sizeof(c)) {
- perror("copy failed");
- break;
- }
-
- if (write(out_fd, &c, sizeof(c)) != sizeof(c)) {
- perror("write failed");
- break;
- }
- }
-
- close(out_fd);
-}
-
-static void analyze_firmware(const char *filename)
-{
- struct stat stat;
- struct sdp_header *header;
- struct sdp_header_item *sub_entry;
- struct llist_head *entry;
- int fd;
- void *tall_firm_ctx = 0;
- int part = 0;
-
- entry = talloc_zero(tall_firm_ctx, struct llist_head);
- INIT_LLIST_HEAD(entry);
-
- printf("Opening possible firmware '%s'\n", filename);
- fd = open(filename, O_RDONLY);
- if (!fd) {
- perror("nada");
- return;
- }
-
- /* verify the file */
- if (fstat(fd, &stat) == -1) {
- perror("Can not stat the file");
- close(fd);
- return;
- }
-
- ipaccess_analyze_file(fd, stat.st_size, 0, entry);
-
- llist_for_each_entry(header, entry, entry) {
- printf("Printing header information:\n");
- printf("more_more_magic: 0x%x\n", ntohs(header->firmware_info.more_more_magic));
- printf("header_length: %u\n", ntohl(header->firmware_info.header_length));
- printf("file_length: %u\n", ntohl(header->firmware_info.file_length));
- printf("sw_part: %.20s\n", header->firmware_info.sw_part);
- printf("text1: %.64s\n", header->firmware_info.text1);
- printf("time: %.12s\n", header->firmware_info.time);
- printf("date: %.14s\n", header->firmware_info.date);
- printf("text2: %.10s\n", header->firmware_info.text2);
- printf("version: %.20s\n", header->firmware_info.version);
- printf("subitems...\n");
-
- llist_for_each_entry(sub_entry, &header->header_list, entry) {
- printf("\tsomething1: %u\n", sub_entry->header_entry.something1);
- printf("\ttext1: %.64s\n", sub_entry->header_entry.text1);
- printf("\ttime: %.12s\n", sub_entry->header_entry.time);
- printf("\tdate: %.14s\n", sub_entry->header_entry.date);
- printf("\ttext2: %.10s\n", sub_entry->header_entry.text2);
- printf("\tversion: %.20s\n", sub_entry->header_entry.version);
- printf("\tlength: %u\n", ntohl(sub_entry->header_entry.length));
- printf("\taddr1: 0x%x\n", ntohl(sub_entry->header_entry.addr1));
- printf("\taddr2: 0x%x\n", ntohl(sub_entry->header_entry.addr2));
- printf("\tstart: 0x%x\n", ntohl(sub_entry->header_entry.start));
- printf("\tabs. offset: 0x%lx\n", sub_entry->absolute_offset);
- printf("\n\n");
-
- dump_entry(sub_entry, part++, fd);
- }
- printf("\n\n");
- }
-
- if (close(fd) != 0) {
- perror("Close failed.\n");
- return;
- }
-
- talloc_free(tall_firm_ctx);
-}
-
-static void print_usage(void)
-{
- printf("Usage: ipaccess-config IP_OF_BTS\n");
-}
-
-static void print_help(void)
-{
-#if 0
- printf("Commands for reading from the BTS:\n");
- printf(" -D --dump\t\t\tDump the BTS configuration\n");
- printf("\n");
-#endif
- printf("Commands for writing to the BTS:\n");
- printf(" -u --unit-id UNIT_ID\t\tSet the Unit ID of the BTS\n");
- printf(" -o --oml-ip IP\t\tSet primary OML IP (IP of your BSC)\n");
- printf(" -i --ip-address IP/MASK\tSet static IP address + netmask of BTS\n");
- printf(" -g --ip-gateway IP\t\tSet static IP gateway of BTS\n");
- printf(" -r --restart\t\t\tRestart the BTS (after other operations)\n");
- printf(" -n --nvram-flags FLAGS/MASK\tSet NVRAM attributes\n");
- printf(" -S --nvattr-set FLAG\tSet one additional NVRAM attribute\n");
- printf(" -U --nvattr-unset FLAG\tSet one additional NVRAM attribute\n");
- printf(" -l --listen TESTNR\t\tPerform specified test number\n");
- printf(" -L --Listen TEST_NAME\t\tPerform specified test\n");
- printf(" -s --stream-id ID\t\tSet the IPA Stream Identifier for OML\n");
- printf(" -d --software FIRMWARE\tDownload firmware into BTS\n");
- printf("\n");
- printf("Miscellaneous commands:\n");
- printf(" -h --help\t\t\tthis text\n");
- printf(" -H --HELP\t\t\tPrint parameter details.\n");
- printf(" -f --firmware FIRMWARE\tProvide firmware information\n");
- printf(" -w --write-firmware\t\tThis will dump the firmware parts to the filesystem. Use with -f.\n");
- printf(" -p --loop\t\t\tLoop the tests executed with the --listen command.\n");
-}
-
-static void print_value_string(const struct value_string *val, int size)
-{
- int i;
-
- for (i = 0; i < size - 1; ++i) {
- char sep = val[i + 1].str == NULL ? '.' : ',';
- printf("%s%c ", val[i].str, sep);
- }
- printf("\n");
-}
-
-static void print_options(void)
-{
-
- printf("Options for NVRAM (-S,-U):\n ");
- print_value_string(&ipa_nvflag_strs[0], ARRAY_SIZE(ipa_nvflag_strs));
-
- printf("Options for Tests (-L):\n ");
- print_value_string(&ipa_test_strs[0], ARRAY_SIZE(ipa_test_strs));
-}
-
-extern void bts_model_nanobts_init();
-
-int main(int argc, char **argv)
-{
- struct gsm_bts *bts;
- struct sockaddr_in sin;
- int rc, option_index = 0, stream_id = 0xff;
-
- tall_ctx_config = talloc_named_const(NULL, 0, "ipaccess-config");
- msgb_talloc_ctx_init(tall_ctx_config, 0);
-
- osmo_init_logging(&log_info);
- log_parse_category_mask(osmo_stderr_target, "DNM,0");
- bts_model_nanobts_init();
-
- printf("ipaccess-config (C) 2009-2010 by Harald Welte and others\n");
- printf("This is FREE SOFTWARE with ABSOLUTELY NO WARRANTY\n\n");
-
- while (1) {
- int c;
- unsigned long ul;
- char *slash;
- static struct option long_options[] = {
- { "unit-id", 1, 0, 'u' },
- { "oml-ip", 1, 0, 'o' },
- { "ip-address", 1, 0, 'i' },
- { "ip-gateway", 1, 0, 'g' },
- { "restart", 0, 0, 'r' },
- { "nvram-flags", 1, 0, 'n' },
- { "nvattr-set", 1, 0, 'S' },
- { "nvattr-unset", 1, 0, 'U' },
- { "help", 0, 0, 'h' },
- { "HELP", 0, 0, 'H' },
- { "listen", 1, 0, 'l' },
- { "Listen", 1, 0, 'L' },
- { "stream-id", 1, 0, 's' },
- { "software", 1, 0, 'd' },
- { "firmware", 1, 0, 'f' },
- { "write-firmware", 0, 0, 'w' },
- { "disable-color", 0, 0, 'c'},
- { "loop", 0, 0, 'p' },
- { 0, 0, 0, 0 },
- };
-
- c = getopt_long(argc, argv, "u:o:i:g:rn:S:U:l:L:hs:d:f:wcpH", long_options,
- &option_index);
-
- if (c == -1)
- break;
-
- switch (c) {
- case 'u':
- unit_id = optarg;
- break;
- case 'o':
- prim_oml_ip = optarg;
- break;
- case 'i':
- slash = strchr(optarg, '/');
- if (!slash)
- exit(2);
- bts_ip_addr = optarg;
- *slash = 0;
- bts_ip_mask = slash+1;
- break;
- case 'g':
- bts_ip_gw = optarg;
- break;
- case 'r':
- restart = 1;
- break;
- case 'n':
- slash = strchr(optarg, '/');
- if (!slash)
- exit(2);
- ul = strtoul(optarg, NULL, 16);
- nv_flags = ul & 0xffff;
- ul = strtoul(slash+1, NULL, 16);
- nv_mask = ul & 0xffff;
- break;
- case 'S':
- if (ipa_nvflag_set(&nv_flags, &nv_mask, optarg, 1) < 0)
- exit(2);
- break;
- case 'U':
- if (ipa_nvflag_set(&nv_flags, &nv_mask, optarg, 0) < 0)
- exit(2);
- break;
- case 'l':
- net_listen_testnr = atoi(optarg);
- break;
- case 'L':
- net_listen_testnr = get_string_value(ipa_test_strs,
- optarg);
- if (net_listen_testnr < 0) {
- fprintf(stderr,
- "The test '%s' is not known. Use -H to"
- " see available tests.\n", optarg);
- exit(2);
- }
- break;
- case 's':
- stream_id = atoi(optarg);
- break;
- case 'd':
- software = strdup(optarg);
- if (find_sw_load_params(optarg) != 0)
- exit(0);
- break;
- case 'f':
- firmware_analysis = optarg;
- break;
- case 'w':
- dump_files = 1;
- break;
- case 'c':
- log_set_use_color(osmo_stderr_target, 0);
- break;
- case 'p':
- loop_tests = 1;
- break;
- case 'h':
- print_usage();
- print_help();
- exit(0);
- case 'H':
- print_options();
- exit(0);
- }
- };
-
- if (firmware_analysis)
- analyze_firmware(firmware_analysis);
-
- if (optind >= argc) {
- /* only warn if we have not done anything else */
- if (!firmware_analysis)
- fprintf(stderr, "you have to specify the IP address of the BTS. Use --help for more information\n");
- exit(2);
- }
- libosmo_abis_init(tall_ctx_config);
-
- bsc_gsmnet = bsc_network_init(tall_bsc_ctx, 1, 1, NULL);
- if (!bsc_gsmnet)
- exit(1);
-
- bts = gsm_bts_alloc_register(bsc_gsmnet, GSM_BTS_TYPE_NANOBTS,
- HARDCODED_BSIC);
- /* ip.access supports up to 4 chained TRX */
- gsm_bts_trx_alloc(bts);
- gsm_bts_trx_alloc(bts);
- gsm_bts_trx_alloc(bts);
- bts->oml_tei = stream_id;
-
- osmo_signal_register_handler(SS_NM, nm_sig_cb, NULL);
- osmo_signal_register_handler(SS_IPAC_NWL, nwl_sig_cb, NULL);
-
- ipac_nwl_init();
-
- printf("Trying to connect to ip.access BTS ...\n");
-
- memset(&sin, 0, sizeof(sin));
- sin.sin_family = AF_INET;
- inet_aton(argv[optind], &sin.sin_addr);
- rc = ia_config_connect(bts, &sin);
- if (rc < 0) {
- perror("Error connecting to the BTS");
- exit(1);
- }
-
- bts->oml_link->ts->sign.delay = 10;
- bts->c0->rsl_link->ts->sign.delay = 10;
- while (1) {
- rc = osmo_select_main(0);
- if (rc < 0)
- exit(3);
- }
-
- exit(0);
-}
-
diff --git a/src/ipaccess/ipaccess-firmware.c b/src/ipaccess/ipaccess-firmware.c
deleted file mode 100644
index 5f55bb52..00000000
--- a/src/ipaccess/ipaccess-firmware.c
+++ /dev/null
@@ -1,135 +0,0 @@
-/* Routines for parsing an ipacces SDP firmware file */
-
-/* (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/debug.h>
-#include <openbsc/ipaccess.h>
-#include <osmocom/core/talloc.h>
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#define PART_LENGTH 138
-
-osmo_static_assert(sizeof(struct sdp_header_entry) == 138, right_entry);
-osmo_static_assert(sizeof(struct sdp_firmware) == 158, _right_header_length);
-
-/* more magic, the second "int" in the header */
-static char more_magic[] = { 0x10, 0x02 };
-
-int ipaccess_analyze_file(int fd, const unsigned int st_size, const unsigned int base_offset, struct llist_head *list)
-{
- struct sdp_firmware *firmware_header = 0;
- struct sdp_header *header;
- char buf[4096];
- int rc, i;
- uint16_t table_size;
- uint16_t table_offset;
- off_t table_start;
-
-
- rc = read(fd, buf, sizeof(*firmware_header));
- if (rc < 0) {
- perror("Can not read header start.");
- return -1;
- }
-
- firmware_header = (struct sdp_firmware *) &buf[0];
- if (strncmp(firmware_header->magic, " SDP", 4) != 0) {
- fprintf(stderr, "Wrong magic.\n");
- return -1;
- }
-
- if (memcmp(firmware_header->more_magic, more_magic, 2) != 0) {
- fprintf(stderr, "Wrong more magic. Got: 0x%x 0x%x vs. 0x%x 0x%x\n",
- firmware_header->more_magic[0] & 0xff, firmware_header->more_magic[1] & 0xff,
- more_magic[0], more_magic[1]);
- return -1;
- }
-
-
- if (ntohl(firmware_header->file_length) != st_size) {
- fprintf(stderr, "The filesize and the header do not match.\n");
- return -1;
- }
-
- /* add the firmware */
- header = talloc_zero(list, struct sdp_header);
- header->firmware_info = *firmware_header;
- INIT_LLIST_HEAD(&header->header_list);
- llist_add(&header->entry, list);
-
- table_offset = ntohs(firmware_header->table_offset);
- table_start = lseek(fd, table_offset, SEEK_CUR);
- if (table_start == -1) {
- fprintf(stderr, "Failed to seek to the rel position: 0x%x\n", table_offset);
- return -1;
- }
-
- if (read(fd, &table_size, sizeof(table_size)) != sizeof(table_size)) {
- fprintf(stderr, "The table size could not be read.\n");
- return -1;
- }
-
- table_size = ntohs(table_size);
-
- if (table_size % PART_LENGTH != 0) {
- fprintf(stderr, "The part length seems to be wrong: 0x%x\n", table_size);
- return -1;
- }
-
- /* look into each firmware now */
- for (i = 0; i < table_size / PART_LENGTH; ++i) {
- struct sdp_header_entry entry;
- struct sdp_header_item *header_entry;
- unsigned int offset = table_start + 2;
- offset += i * 138;
-
- if (lseek(fd, offset, SEEK_SET) != offset) {
- fprintf(stderr, "Can not seek to the offset: %u.\n", offset);
- return -1;
- }
-
- rc = read(fd, &entry, sizeof(entry));
- if (rc != sizeof(entry)) {
- fprintf(stderr, "Can not read the header entry.\n");
- return -1;
- }
-
- header_entry = talloc_zero(header, struct sdp_header_item);
- header_entry->header_entry = entry;
- header_entry->absolute_offset = base_offset;
- llist_add(&header_entry->entry, &header->header_list);
-
- /* now we need to find the SDP file... */
- offset = ntohl(entry.start) + 4 + base_offset;
- if (lseek(fd, offset, SEEK_SET) != offset) {
- perror("can't seek to sdp");
- return -1;
- }
-
-
- ipaccess_analyze_file(fd, ntohl(entry.length), offset, list);
- }
-
- return 0;
-}
-
diff --git a/src/ipaccess/ipaccess-proxy.c b/src/ipaccess/ipaccess-proxy.c
deleted file mode 100644
index d3674426..00000000
--- a/src/ipaccess/ipaccess-proxy.c
+++ /dev/null
@@ -1,1226 +0,0 @@
-/* OpenBSC Abis/IP proxy ip.access nanoBTS */
-
-/* (C) 2009 by Harald Welte <laforge@gnumonks.org>
- * (C) 2010 by On-Waves
- * (C) 2010 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 <unistd.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <string.h>
-#include <signal.h>
-#include <time.h>
-#include <sys/fcntl.h>
-#include <sys/socket.h>
-#include <sys/ioctl.h>
-#include <arpa/inet.h>
-#include <netinet/in.h>
-
-#define _GNU_SOURCE
-#include <getopt.h>
-
-#include <openbsc/gsm_data.h>
-#include <osmocom/core/application.h>
-#include <osmocom/core/select.h>
-#include <osmocom/gsm/tlv.h>
-#include <osmocom/core/msgb.h>
-#include <osmocom/gsm/ipa.h>
-#include <osmocom/abis/ipa.h>
-#include <osmocom/abis/ipaccess.h>
-#include <openbsc/debug.h>
-#include <openbsc/ipaccess.h>
-#include <openbsc/socket.h>
-#include <osmocom/core/talloc.h>
-
-/* one instance of an ip.access protocol proxy */
-struct ipa_proxy {
- /* socket where we listen for incoming OML from BTS */
- struct osmo_fd oml_listen_fd;
- /* socket where we listen for incoming RSL from BTS */
- struct osmo_fd rsl_listen_fd;
- /* list of BTS's (struct ipa_bts_conn */
- struct llist_head bts_list;
- /* the BSC reconnect timer */
- struct osmo_timer_list reconn_timer;
- /* global GPRS NS data */
- struct in_addr gprs_addr;
- struct in_addr listen_addr;
-};
-
-/* global pointer to the proxy structure */
-static struct ipa_proxy *ipp;
-
-struct ipa_proxy_conn {
- struct osmo_fd fd;
- struct llist_head tx_queue;
- struct ipa_bts_conn *bts_conn;
-};
-#define MAX_TRX 4
-
-/* represents a particular BTS in our proxy */
-struct ipa_bts_conn {
- /* list of BTS's (ipa_proxy->bts_list) */
- struct llist_head list;
- /* back pointer to the proxy which we belong to */
- struct ipa_proxy *ipp;
- /* the unit ID as determined by CCM */
- struct {
- uint16_t site_id;
- uint16_t bts_id;
- } unit_id;
-
- /* incoming connections from BTS */
- struct ipa_proxy_conn *oml_conn;
- struct ipa_proxy_conn *rsl_conn[MAX_TRX];
-
- /* outgoing connections to BSC */
- struct ipa_proxy_conn *bsc_oml_conn;
- struct ipa_proxy_conn *bsc_rsl_conn[MAX_TRX];
-
- /* UDP sockets for BTS and BSC injection */
- struct osmo_fd udp_bts_fd;
- struct osmo_fd udp_bsc_fd;
-
- /* NS data */
- struct in_addr bts_addr;
- struct osmo_fd gprs_ns_fd;
- int gprs_local_port;
- uint16_t gprs_orig_port;
- uint32_t gprs_orig_ip;
-
- char *id_tags[256];
- uint8_t *id_resp;
- unsigned int id_resp_len;
-};
-
-enum ipp_fd_type {
- OML_FROM_BTS = 1,
- RSL_FROM_BTS = 2,
- OML_TO_BSC = 3,
- RSL_TO_BSC = 4,
- UDP_TO_BTS = 5,
- UDP_TO_BSC = 6,
-};
-
-/* some of the code against we link from OpenBSC needs this */
-void *tall_bsc_ctx;
-
-static char *listen_ipaddr;
-static char *bsc_ipaddr;
-static char *gprs_ns_ipaddr;
-
-static int gprs_ns_cb(struct osmo_fd *bfd, unsigned int what);
-
-#define PROXY_ALLOC_SIZE 1200
-
-static struct ipa_bts_conn *find_bts_by_unitid(struct ipa_proxy *ipp,
- uint16_t site_id,
- uint16_t bts_id)
-{
- struct ipa_bts_conn *ipbc;
-
- llist_for_each_entry(ipbc, &ipp->bts_list, list) {
- if (ipbc->unit_id.site_id == site_id &&
- ipbc->unit_id.bts_id == bts_id)
- return ipbc;
- }
-
- return NULL;
-}
-
-struct ipa_proxy_conn *alloc_conn(void)
-{
- struct ipa_proxy_conn *ipc;
-
- ipc = talloc_zero(tall_bsc_ctx, struct ipa_proxy_conn);
- if (!ipc)
- return NULL;
-
- INIT_LLIST_HEAD(&ipc->tx_queue);
-
- return ipc;
-}
-
-static int store_idtags(struct ipa_bts_conn *ipbc, struct tlv_parsed *tlvp)
-{
- unsigned int i, len;
-
- for (i = 0; i <= 0xff; i++) {
- if (!TLVP_PRESENT(tlvp, i))
- continue;
-
- len = TLVP_LEN(tlvp, i);
-#if 0
- if (!ipbc->id_tags[i])
- ipbc->id_tags[i] = talloc_size(tall_bsc_ctx, len);
- else
-#endif
- ipbc->id_tags[i] = talloc_realloc_size(ipbc,
- ipbc->id_tags[i], len);
- if (!ipbc->id_tags[i])
- return -ENOMEM;
-
- memset(ipbc->id_tags[i], 0, len);
- //memcpy(ipbc->id_tags[i], TLVP_VAL(tlvp, i), len);
- }
- return 0;
-}
-
-
-static struct ipa_proxy_conn *connect_bsc(struct sockaddr_in *sa, int priv_nr, void *data);
-
-#define logp_ipbc_uid(ss, lvl, ipbc, trx_id) _logp_ipbc_uid(ss, lvl, __FILE__, __LINE__, ipbc, trx_id)
-
-static void _logp_ipbc_uid(unsigned int ss, unsigned int lvl, char *file, int line,
- struct ipa_bts_conn *ipbc, uint8_t trx_id)
-{
- if (ipbc)
- logp2(ss, lvl, file, line, 0, "(%u/%u/%u) ", ipbc->unit_id.site_id,
- ipbc->unit_id.bts_id, trx_id);
- else
- logp2(ss, lvl, file, line, 0, "unknown ");
-}
-
-static int handle_udp_read(struct osmo_fd *bfd)
-{
- struct ipa_bts_conn *ipbc = bfd->data;
- struct ipa_proxy_conn *other_conn = NULL;
- struct msgb *msg = msgb_alloc(PROXY_ALLOC_SIZE, "Abis/IP UDP");
- struct ipaccess_head *hh;
- int ret;
-
- /* with UDP sockets, we cannot read partial packets but have to read
- * all of it in one go */
- hh = (struct ipaccess_head *) msg->data;
- ret = recv(bfd->fd, msg->data, msg->data_len, 0);
- if (ret < 0) {
- if (errno != EAGAIN)
- LOGP(DLINP, LOGL_ERROR, "recv error %s\n", strerror(errno));
- msgb_free(msg);
- return ret;
- }
- if (ret == 0) {
- DEBUGP(DLINP, "UDP peer disappeared, dead socket\n");
- osmo_fd_unregister(bfd);
- close(bfd->fd);
- bfd->fd = -1;
- msgb_free(msg);
- return -EIO;
- }
- if (ret < sizeof(*hh)) {
- DEBUGP(DLINP, "could not even read header!?!\n");
- msgb_free(msg);
- return -EIO;
- }
- msgb_put(msg, ret);
- msg->l2h = msg->data + sizeof(*hh);
- DEBUGP(DLMI, "UDP RX: %s\n", osmo_hexdump(msg->data, msg->len));
-
- if (hh->len != msg->len - sizeof(*hh)) {
- DEBUGP(DLINP, "length (%u/%u) disagrees with header(%u)\n",
- msg->len, msg->len - 3, hh->len);
- msgb_free(msg);
- return -EIO;
- }
-
- switch (bfd->priv_nr & 0xff) {
- case UDP_TO_BTS:
- /* injection towards BTS */
- switch (hh->proto) {
- case IPAC_PROTO_RSL:
- /* FIXME: what to do about TRX > 0 */
- other_conn = ipbc->rsl_conn[0];
- break;
- default:
- DEBUGP(DLINP, "Unknown protocol 0x%02x, sending to "
- "OML FD\n", hh->proto);
- /* fall through */
- case IPAC_PROTO_IPACCESS:
- case IPAC_PROTO_OML:
- other_conn = ipbc->oml_conn;
- break;
- }
- break;
- case UDP_TO_BSC:
- /* injection towards BSC */
- switch (hh->proto) {
- case IPAC_PROTO_RSL:
- /* FIXME: what to do about TRX > 0 */
- other_conn = ipbc->bsc_rsl_conn[0];
- break;
- default:
- DEBUGP(DLINP, "Unknown protocol 0x%02x, sending to "
- "OML FD\n", hh->proto);
- /* fall through */
- case IPAC_PROTO_IPACCESS:
- case IPAC_PROTO_OML:
- other_conn = ipbc->bsc_oml_conn;
- break;
- }
- break;
- default:
- DEBUGP(DLINP, "Unknown filedescriptor priv_nr=%04x\n", bfd->priv_nr);
- break;
- }
-
- if (other_conn) {
- /* enqueue the message for TX on the respective FD */
- msgb_enqueue(&other_conn->tx_queue, msg);
- other_conn->fd.when |= BSC_FD_WRITE;
- } else
- msgb_free(msg);
-
- return 0;
-}
-
-static int handle_udp_write(struct osmo_fd *bfd)
-{
- /* not implemented yet */
- bfd->when &= ~BSC_FD_WRITE;
-
- return -EIO;
-}
-
-/* callback from select.c in case one of the fd's can be read/written */
-static int udp_fd_cb(struct osmo_fd *bfd, unsigned int what)
-{
- int rc = 0;
-
- if (what & BSC_FD_READ)
- rc = handle_udp_read(bfd);
- if (what & BSC_FD_WRITE)
- rc = handle_udp_write(bfd);
-
- return rc;
-}
-
-
-static int ipbc_alloc_connect(struct ipa_proxy_conn *ipc, struct osmo_fd *bfd,
- uint16_t site_id, uint16_t bts_id,
- uint16_t trx_id, struct tlv_parsed *tlvp,
- struct msgb *msg)
-{
- struct ipa_bts_conn *ipbc;
- uint16_t udp_port;
- int ret = 0;
- struct sockaddr_in sin;
-
- memset(&sin, 0, sizeof(sin));
- sin.sin_family = AF_INET;
- inet_aton(bsc_ipaddr, &sin.sin_addr);
-
- DEBUGP(DLINP, "(%u/%u/%u) New BTS connection: ",
- site_id, bts_id, trx_id);
-
- /* OML needs to be established before RSL */
- if ((bfd->priv_nr & 0xff) != OML_FROM_BTS) {
- DEBUGPC(DLINP, "Not a OML connection ?!?\n");
- return -EIO;
- }
-
- /* allocate new BTS connection data structure */
- ipbc = talloc_zero(tall_bsc_ctx, struct ipa_bts_conn);
- if (!ipbc) {
- ret = -ENOMEM;
- goto err_out;
- }
-
- DEBUGPC(DLINP, "Created BTS Conn data structure\n");
- ipbc->ipp = ipp;
- ipbc->unit_id.site_id = site_id;
- ipbc->unit_id.bts_id = bts_id;
- ipbc->oml_conn = ipc;
- ipc->bts_conn = ipbc;
-
- /* store the content of the ID TAGS for later reference */
- store_idtags(ipbc, tlvp);
- ipbc->id_resp_len = msg->len;
- ipbc->id_resp = talloc_size(tall_bsc_ctx, ipbc->id_resp_len);
- memcpy(ipbc->id_resp, msg->data, ipbc->id_resp_len);
-
- /* Create OML TCP connection towards BSC */
- sin.sin_port = htons(IPA_TCP_PORT_OML);
- ipbc->bsc_oml_conn = connect_bsc(&sin, OML_TO_BSC, ipbc);
- if (!ipbc->bsc_oml_conn) {
- ret = -EIO;
- goto err_bsc_conn;
- }
-
- DEBUGP(DLINP, "(%u/%u/%u) OML Connected to BSC\n",
- site_id, bts_id, trx_id);
-
- /* Create UDP socket for BTS packet injection */
- udp_port = 10000 + (site_id % 1000)*100 + (bts_id % 100);
- ret = make_sock(&ipbc->udp_bts_fd, IPPROTO_UDP, INADDR_ANY, udp_port,
- UDP_TO_BTS, udp_fd_cb, ipbc);
- if (ret < 0)
- goto err_udp_bts;
- DEBUGP(DLINP, "(%u/%u/%u) Created UDP socket for injection "
- "towards BTS at port %u\n", site_id, bts_id, trx_id, udp_port);
-
- /* Create UDP socket for BSC packet injection */
- udp_port = 20000 + (site_id % 1000)*100 + (bts_id % 100);
- ret = make_sock(&ipbc->udp_bsc_fd, IPPROTO_UDP, INADDR_ANY, udp_port,
- UDP_TO_BSC, udp_fd_cb, ipbc);
- if (ret < 0)
- goto err_udp_bsc;
- DEBUGP(DLINP, "(%u/%u/%u) Created UDP socket for injection "
- "towards BSC at port %u\n", site_id, bts_id, trx_id, udp_port);
-
-
- /* GPRS NS related code */
- if (gprs_ns_ipaddr) {
- struct sockaddr_in sock;
- socklen_t len = sizeof(sock);
- struct in_addr addr;
- uint32_t ip;
-
- inet_aton(listen_ipaddr, &addr);
- ip = ntohl(addr.s_addr); /* make_sock() needs host byte order */
- ret = make_sock(&ipbc->gprs_ns_fd, IPPROTO_UDP, ip, 0, 0,
- gprs_ns_cb, ipbc);
- if (ret < 0) {
- LOGP(DLINP, LOGL_ERROR, "Creating the GPRS socket failed.\n");
- goto err_udp_bsc;
- }
-
- ret = getsockname(ipbc->gprs_ns_fd.fd, (struct sockaddr* ) &sock, &len);
- ipbc->gprs_local_port = ntohs(sock.sin_port);
- LOGP(DLINP, LOGL_NOTICE,
- "Created GPRS NS Socket. Listening on: %s:%d\n",
- inet_ntoa(sock.sin_addr), ipbc->gprs_local_port);
-
- ret = getpeername(bfd->fd, (struct sockaddr* ) &sock, &len);
- ipbc->bts_addr = sock.sin_addr;
- }
-
- llist_add(&ipbc->list, &ipp->bts_list);
-
- return 0;
-
-err_udp_bsc:
- osmo_fd_unregister(&ipbc->udp_bts_fd);
-err_udp_bts:
- osmo_fd_unregister(&ipbc->bsc_oml_conn->fd);
- close(ipbc->bsc_oml_conn->fd.fd);
- talloc_free(ipbc->bsc_oml_conn);
- ipbc->bsc_oml_conn = NULL;
-err_bsc_conn:
- talloc_free(ipbc->id_resp);
- talloc_free(ipbc);
-#if 0
- osmo_fd_unregister(bfd);
- close(bfd->fd);
- talloc_free(bfd);
-#endif
-err_out:
- return ret;
-}
-
-static int ipaccess_rcvmsg(struct ipa_proxy_conn *ipc, struct msgb *msg,
- struct osmo_fd *bfd)
-{
- struct tlv_parsed tlvp;
- uint8_t msg_type = *(msg->l2h);
- struct ipaccess_unit unit_data;
- struct ipa_bts_conn *ipbc;
- int ret = 0;
-
- switch (msg_type) {
- case IPAC_MSGT_PING:
- ret = ipa_ccm_send_pong(bfd->fd);
- break;
- case IPAC_MSGT_PONG:
- DEBUGP(DLMI, "PONG!\n");
- break;
- case IPAC_MSGT_ID_RESP:
- DEBUGP(DLMI, "ID_RESP ");
- /* parse tags, search for Unit ID */
- ipa_ccm_idtag_parse(&tlvp, (uint8_t *)msg->l2h + 2,
- msgb_l2len(msg)-2);
- DEBUGP(DLMI, "\n");
-
- if (!TLVP_PRESENT(&tlvp, IPAC_IDTAG_UNIT)) {
- LOGP(DLINP, LOGL_ERROR, "No Unit ID in ID RESPONSE !?!\n");
- return -EIO;
- }
-
- /* lookup BTS, create sign_link, ... */
- memset(&unit_data, 0, sizeof(unit_data));
- ipa_parse_unitid((char *)TLVP_VAL(&tlvp, IPAC_IDTAG_UNIT),
- &unit_data);
- ipbc = find_bts_by_unitid(ipp, unit_data.site_id, unit_data.bts_id);
- if (!ipbc) {
- /* We have not found an ipbc (per-bts proxy instance)
- * for this BTS yet. The first connection of a new BTS must
- * be a OML connection. We allocate the associated data structures,
- * and try to connect to the remote end */
-
- return ipbc_alloc_connect(ipc, bfd, unit_data.site_id,
- unit_data.bts_id,
- unit_data.trx_id, &tlvp, msg);
- /* if this fails, the caller will clean up bfd */
- } else {
- struct sockaddr_in sin;
- memset(&sin, 0, sizeof(sin));
- sin.sin_family = AF_INET;
- inet_aton(bsc_ipaddr, &sin.sin_addr);
-
- DEBUGP(DLINP, "Identified BTS %u/%u/%u\n",
- unit_data.site_id, unit_data.bts_id, unit_data.trx_id);
-
- if ((bfd->priv_nr & 0xff) != RSL_FROM_BTS) {
- LOGP(DLINP, LOGL_ERROR, "Second OML connection from "
- "same BTS ?!?\n");
- return 0;
- }
-
- if (unit_data.trx_id >= MAX_TRX) {
- LOGP(DLINP, LOGL_ERROR, "We don't support more "
- "than %u TRX\n", MAX_TRX);
- return -EINVAL;
- }
-
- ipc->bts_conn = ipbc;
- /* store TRX number in higher 8 bit of the bfd private number */
- bfd->priv_nr |= unit_data.trx_id << 8;
- ipbc->rsl_conn[unit_data.trx_id] = ipc;
-
- /* Create RSL TCP connection towards BSC */
- sin.sin_port = htons(IPA_TCP_PORT_RSL);
- ipbc->bsc_rsl_conn[unit_data.trx_id] =
- connect_bsc(&sin, RSL_TO_BSC | (unit_data.trx_id << 8), ipbc);
- if (!ipbc->bsc_oml_conn)
- return -EIO;
- DEBUGP(DLINP, "(%u/%u/%u) Connected RSL to BSC\n",
- unit_data.site_id, unit_data.bts_id, unit_data.trx_id);
- }
- break;
- case IPAC_MSGT_ID_GET:
- DEBUGP(DLMI, "ID_GET\n");
- if ((bfd->priv_nr & 0xff) != OML_TO_BSC &&
- (bfd->priv_nr & 0xff) != RSL_TO_BSC) {
- DEBUGP(DLINP, "IDentity REQuest from BTS ?!?\n");
- return -EIO;
- }
- ipbc = ipc->bts_conn;
- if (!ipbc) {
- DEBUGP(DLINP, "ID_GET from BSC before we have ID_RESP from BTS\n");
- return -EIO;
- }
- ret = write(bfd->fd, ipbc->id_resp, ipbc->id_resp_len);
- if (ret != ipbc->id_resp_len) {
- LOGP(DLINP, LOGL_ERROR, "Partial write: %d of %d\n",
- ret, ipbc->id_resp_len);
- return -EIO;
- }
- ret = 0;
- break;
- case IPAC_MSGT_ID_ACK:
- DEBUGP(DLMI, "ID_ACK? -> ACK!\n");
- ret = ipa_ccm_send_id_ack(bfd->fd);
- break;
- default:
- LOGP(DLMI, LOGL_ERROR, "Unhandled IPA type; %d\n", msg_type);
- return 1;
- break;
- }
- return ret;
-}
-
-struct msgb *ipaccess_proxy_read_msg(struct osmo_fd *bfd, int *error)
-{
- struct msgb *msg = msgb_alloc(PROXY_ALLOC_SIZE, "Abis/IP");
- struct ipaccess_head *hh;
- int len, ret = 0;
-
- if (!msg) {
- *error = -ENOMEM;
- return NULL;
- }
-
- /* first read our 3-byte header */
- hh = (struct ipaccess_head *) msg->data;
- ret = recv(bfd->fd, msg->data, 3, 0);
- if (ret < 0) {
- if (errno != EAGAIN)
- LOGP(DLINP, LOGL_ERROR, "recv error: %s\n", strerror(errno));
- msgb_free(msg);
- *error = ret;
- return NULL;
- } else if (ret == 0) {
- msgb_free(msg);
- *error = ret;
- return NULL;
- }
-
- msgb_put(msg, ret);
-
- /* then read te length as specified in header */
- msg->l2h = msg->data + sizeof(*hh);
- len = ntohs(hh->len);
- ret = recv(bfd->fd, msg->l2h, len, 0);
- if (ret < len) {
- LOGP(DLINP, LOGL_ERROR, "short read!\n");
- msgb_free(msg);
- *error = -EIO;
- return NULL;
- }
- msgb_put(msg, ret);
-
- return msg;
-}
-
-static struct ipa_proxy_conn *ipc_by_priv_nr(struct ipa_bts_conn *ipbc,
- unsigned int priv_nr)
-{
- struct ipa_proxy_conn *bsc_conn;
- unsigned int trx_id = priv_nr >> 8;
-
- switch (priv_nr & 0xff) {
- case OML_FROM_BTS: /* incoming OML data from BTS, forward to BSC OML */
- bsc_conn = ipbc->bsc_oml_conn;
- break;
- case RSL_FROM_BTS: /* incoming RSL data from BTS, forward to BSC RSL */
- bsc_conn = ipbc->bsc_rsl_conn[trx_id];
- break;
- case OML_TO_BSC: /* incoming OML data from BSC, forward to BTS OML */
- bsc_conn = ipbc->oml_conn;
- break;
- case RSL_TO_BSC: /* incoming RSL data from BSC, forward to BTS RSL */
- bsc_conn = ipbc->rsl_conn[trx_id];
- break;
- default:
- bsc_conn = NULL;
- break;
- }
- return bsc_conn;
-}
-
-static void reconn_tmr_cb(void *data)
-{
- struct ipa_proxy *ipp = data;
- struct ipa_bts_conn *ipbc;
- struct sockaddr_in sin;
- int i;
-
- DEBUGP(DLINP, "Running reconnect timer\n");
-
- memset(&sin, 0, sizeof(sin));
- sin.sin_family = AF_INET;
- inet_aton(bsc_ipaddr, &sin.sin_addr);
-
- llist_for_each_entry(ipbc, &ipp->bts_list, list) {
- /* if OML to BSC is dead, try to restore it */
- if (ipbc->oml_conn && !ipbc->bsc_oml_conn) {
- sin.sin_port = htons(IPA_TCP_PORT_OML);
- logp_ipbc_uid(DLINP, LOGL_NOTICE, ipbc, 0);
- LOGPC(DLINP, LOGL_NOTICE, "OML Trying to reconnect\n");
- ipbc->bsc_oml_conn = connect_bsc(&sin, OML_TO_BSC, ipbc);
- if (!ipbc->bsc_oml_conn)
- goto reschedule;
- logp_ipbc_uid(DLINP, LOGL_NOTICE, ipbc, 0);
- LOGPC(DLINP, LOGL_NOTICE, "OML Reconnected\n");
- }
- /* if we (still) don't have a OML connection, skip RSL */
- if (!ipbc->oml_conn || !ipbc->bsc_oml_conn)
- continue;
-
- for (i = 0; i < ARRAY_SIZE(ipbc->rsl_conn); i++) {
- unsigned int priv_nr;
- /* don't establish RSL links which we don't have */
- if (!ipbc->rsl_conn[i])
- continue;
- if (ipbc->bsc_rsl_conn[i])
- continue;
- priv_nr = ipbc->rsl_conn[i]->fd.priv_nr;
- priv_nr &= ~0xff;
- priv_nr |= RSL_TO_BSC;
- sin.sin_port = htons(IPA_TCP_PORT_RSL);
- logp_ipbc_uid(DLINP, LOGL_NOTICE, ipbc, priv_nr >> 8);
- LOGPC(DLINP, LOGL_NOTICE, "RSL Trying to reconnect\n");
- ipbc->bsc_rsl_conn[i] = connect_bsc(&sin, priv_nr, ipbc);
- if (!ipbc->bsc_rsl_conn[i])
- goto reschedule;
- logp_ipbc_uid(DLINP, LOGL_NOTICE, ipbc, priv_nr >> 8);
- LOGPC(DLINP, LOGL_NOTICE, "RSL Reconnected\n");
- }
- }
- return;
-
-reschedule:
- osmo_timer_schedule(&ipp->reconn_timer, 5, 0);
-}
-
-static void handle_dead_socket(struct osmo_fd *bfd)
-{
- struct ipa_proxy_conn *ipc = bfd->data; /* local conn */
- struct ipa_proxy_conn *bsc_conn; /* remote conn */
- struct ipa_bts_conn *ipbc = ipc->bts_conn;
- unsigned int trx_id = bfd->priv_nr >> 8;
- struct msgb *msg, *msg2;
-
- osmo_fd_unregister(bfd);
- close(bfd->fd);
- bfd->fd = -1;
-
- /* FIXME: clear tx_queue, remove all references, etc. */
- llist_for_each_entry_safe(msg, msg2, &ipc->tx_queue, list)
- msgb_free(msg);
-
- switch (bfd->priv_nr & 0xff) {
- case OML_FROM_BTS: /* incoming OML data from BTS, forward to BSC OML */
- /* The BTS started a connection with us but we got no
- * IPAC_MSGT_ID_RESP message yet, in that scenario we did not
- * allocate the ipa_bts_conn structure. */
- if (ipbc == NULL)
- break;
- ipbc->oml_conn = NULL;
- bsc_conn = ipbc->bsc_oml_conn;
- /* close the connection to the BSC */
- osmo_fd_unregister(&bsc_conn->fd);
- close(bsc_conn->fd.fd);
- llist_for_each_entry_safe(msg, msg2, &bsc_conn->tx_queue, list)
- msgb_free(msg);
- talloc_free(bsc_conn);
- ipbc->bsc_oml_conn = NULL;
- /* FIXME: do we need to delete the entire ipbc ? */
- break;
- case RSL_FROM_BTS: /* incoming RSL data from BTS, forward to BSC RSL */
- ipbc->rsl_conn[trx_id] = NULL;
- bsc_conn = ipbc->bsc_rsl_conn[trx_id];
- /* close the connection to the BSC */
- osmo_fd_unregister(&bsc_conn->fd);
- close(bsc_conn->fd.fd);
- llist_for_each_entry_safe(msg, msg2, &bsc_conn->tx_queue, list)
- msgb_free(msg);
- talloc_free(bsc_conn);
- ipbc->bsc_rsl_conn[trx_id] = NULL;
- break;
- case OML_TO_BSC: /* incoming OML data from BSC, forward to BTS OML */
- ipbc->bsc_oml_conn = NULL;
- bsc_conn = ipbc->oml_conn;
- /* start reconnect timer */
- osmo_timer_schedule(&ipp->reconn_timer, 5, 0);
- break;
- case RSL_TO_BSC: /* incoming RSL data from BSC, forward to BTS RSL */
- ipbc->bsc_rsl_conn[trx_id] = NULL;
- bsc_conn = ipbc->rsl_conn[trx_id];
- /* start reconnect timer */
- osmo_timer_schedule(&ipp->reconn_timer, 5, 0);
- break;
- default:
- bsc_conn = NULL;
- break;
- }
-
- talloc_free(ipc);
-}
-
-static void patch_gprs_msg(struct ipa_bts_conn *ipbc, int priv_nr, struct msgb *msg)
-{
- uint8_t *nsvci;
-
- if ((priv_nr & 0xff) != OML_FROM_BTS && (priv_nr & 0xff) != OML_TO_BSC)
- return;
-
- if (msgb_l2len(msg) != 39)
- return;
-
- /*
- * Check if this is a IPA Set Attribute or IPA Set Attribute ACK
- * and if the FOM Class is GPRS NSVC0 and then we will patch it.
- *
- * The patch assumes the message looks like the one from the trace
- * but we only match messages with a specific size anyway... So
- * this hack should work just fine.
- */
-
- if (msg->l2h[0] == 0x10 && msg->l2h[1] == 0x80 &&
- msg->l2h[2] == 0x00 && msg->l2h[3] == 0x15 &&
- msg->l2h[18] == 0xf5 && msg->l2h[19] == 0xf2) {
- nsvci = &msg->l2h[23];
- ipbc->gprs_orig_port = *(uint16_t *)(nsvci+8);
- ipbc->gprs_orig_ip = *(uint32_t *)(nsvci+10);
- *(uint16_t *)(nsvci+8) = htons(ipbc->gprs_local_port);
- *(uint32_t *)(nsvci+10) = ipbc->ipp->listen_addr.s_addr;
- } else if (msg->l2h[0] == 0x10 && msg->l2h[1] == 0x80 &&
- msg->l2h[2] == 0x00 && msg->l2h[3] == 0x15 &&
- msg->l2h[18] == 0xf6 && msg->l2h[19] == 0xf2) {
- nsvci = &msg->l2h[23];
- *(uint16_t *)(nsvci+8) = ipbc->gprs_orig_port;
- *(uint32_t *)(nsvci+10) = ipbc->gprs_orig_ip;
- }
-}
-
-static int handle_tcp_read(struct osmo_fd *bfd)
-{
- struct ipa_proxy_conn *ipc = bfd->data;
- struct ipa_bts_conn *ipbc = ipc->bts_conn;
- struct ipa_proxy_conn *bsc_conn;
- struct msgb *msg;
- struct ipaccess_head *hh;
- int ret = 0;
- char *btsbsc;
-
- if ((bfd->priv_nr & 0xff) <= 2)
- btsbsc = "BTS";
- else
- btsbsc = "BSC";
-
- msg = ipaccess_proxy_read_msg(bfd, &ret);
- if (!msg) {
- if (ret == 0) {
- logp_ipbc_uid(DLINP, LOGL_NOTICE, ipbc, bfd->priv_nr >> 8);
- LOGPC(DLINP, LOGL_NOTICE, "%s disappeared, "
- "dead socket\n", btsbsc);
- handle_dead_socket(bfd);
- }
- return ret;
- }
-
- msgb_put(msg, ret);
- logp_ipbc_uid(DLMI, LOGL_DEBUG, ipbc, bfd->priv_nr >> 8);
- DEBUGPC(DLMI, "RX<-%s: %s\n", btsbsc, osmo_hexdump(msg->data, msg->len));
-
- hh = (struct ipaccess_head *) msg->data;
- if (hh->proto == IPAC_PROTO_IPACCESS) {
- ret = ipaccess_rcvmsg(ipc, msg, bfd);
- if (ret < 0) {
- osmo_fd_unregister(bfd);
- close(bfd->fd);
- bfd->fd = -1;
- talloc_free(bfd);
- msgb_free(msg);
- return ret;
- } else if (ret == 0) {
- /* we do not forward parts of the CCM protocol
- * through the proxy but rather terminate it ourselves. */
- msgb_free(msg);
- return ret;
- }
- }
-
- if (!ipbc) {
- LOGP(DLINP, LOGL_ERROR,
- "received %s packet but no ipc->bts_conn?!?\n", btsbsc);
- msgb_free(msg);
- return -EIO;
- }
-
- bsc_conn = ipc_by_priv_nr(ipbc, bfd->priv_nr);
- if (bsc_conn) {
- if (gprs_ns_ipaddr)
- patch_gprs_msg(ipbc, bfd->priv_nr, msg);
- /* enqueue packet towards BSC */
- msgb_enqueue(&bsc_conn->tx_queue, msg);
- /* mark respective filedescriptor as 'we want to write' */
- bsc_conn->fd.when |= BSC_FD_WRITE;
- } else {
- logp_ipbc_uid(DLINP, LOGL_INFO, ipbc, bfd->priv_nr >> 8);
- LOGPC(DLINP, LOGL_INFO, "Dropping packet from %s, "
- "since remote connection is dead\n", btsbsc);
- msgb_free(msg);
- }
-
- return ret;
-}
-
-/* a TCP socket is ready to be written to */
-static int handle_tcp_write(struct osmo_fd *bfd)
-{
- struct ipa_proxy_conn *ipc = bfd->data;
- struct ipa_bts_conn *ipbc = ipc->bts_conn;
- struct llist_head *lh;
- struct msgb *msg;
- char *btsbsc;
- int ret;
-
- if ((bfd->priv_nr & 0xff) <= 2)
- btsbsc = "BTS";
- else
- btsbsc = "BSC";
-
-
- /* get the next msg for this timeslot */
- if (llist_empty(&ipc->tx_queue)) {
- bfd->when &= ~BSC_FD_WRITE;
- return 0;
- }
- lh = ipc->tx_queue.next;
- llist_del(lh);
- msg = llist_entry(lh, struct msgb, list);
-
- logp_ipbc_uid(DLMI, LOGL_DEBUG, ipbc, bfd->priv_nr >> 8);
- DEBUGPC(DLMI, "TX %04x: %s\n", bfd->priv_nr,
- osmo_hexdump(msg->data, msg->len));
-
- ret = send(bfd->fd, msg->data, msg->len, 0);
- msgb_free(msg);
-
- if (ret == 0) {
- logp_ipbc_uid(DLINP, LOGL_NOTICE, ipbc, bfd->priv_nr >> 8);
- LOGP(DLINP, LOGL_NOTICE, "%s disappeared, dead socket\n", btsbsc);
- handle_dead_socket(bfd);
- }
-
- return ret;
-}
-
-/* callback from select.c in case one of the fd's can be read/written */
-static int proxy_ipaccess_fd_cb(struct osmo_fd *bfd, unsigned int what)
-{
- int rc = 0;
-
- if (what & BSC_FD_READ) {
- rc = handle_tcp_read(bfd);
- if (rc < 0)
- return rc;
- }
- if (what & BSC_FD_WRITE)
- rc = handle_tcp_write(bfd);
-
- return rc;
-}
-
-/* callback of the listening filedescriptor */
-static int listen_fd_cb(struct osmo_fd *listen_bfd, unsigned int what)
-{
- int ret;
- struct ipa_proxy_conn *ipc;
- struct osmo_fd *bfd;
- struct sockaddr_in sa;
- socklen_t sa_len = sizeof(sa);
-
- if (!(what & BSC_FD_READ))
- return 0;
-
- ret = accept(listen_bfd->fd, (struct sockaddr *) &sa, &sa_len);
- if (ret < 0) {
- perror("accept");
- return ret;
- }
- DEBUGP(DLINP, "accept()ed new %s link from %s\n",
- (listen_bfd->priv_nr & 0xff) == OML_FROM_BTS ? "OML" : "RSL",
- inet_ntoa(sa.sin_addr));
-
- ipc = alloc_conn();
- if (!ipc) {
- close(ret);
- return -ENOMEM;
- }
-
- bfd = &ipc->fd;
- bfd->fd = ret;
- bfd->data = ipc;
- bfd->priv_nr = listen_bfd->priv_nr;
- bfd->cb = proxy_ipaccess_fd_cb;
- bfd->when = BSC_FD_READ;
- ret = osmo_fd_register(bfd);
- if (ret < 0) {
- LOGP(DLINP, LOGL_ERROR, "could not register FD\n");
- close(bfd->fd);
- talloc_free(ipc);
- return ret;
- }
-
- /* Request ID. FIXME: request LOCATION, HW/SW VErsion, Unit Name, Serno */
- ret = ipa_ccm_send_id_req(bfd->fd);
-
- return 0;
-}
-
-static void send_ns(int fd, const char *buf, int size, struct in_addr ip, int port)
-{
- int ret;
- struct sockaddr_in addr;
- socklen_t len = sizeof(addr);
- memset(&addr, 0, sizeof(addr));
-
- addr.sin_family = AF_INET;
- addr.sin_port = htons(port);
- addr.sin_addr = ip;
-
- ret = sendto(fd, buf, size, 0, (struct sockaddr *) &addr, len);
- if (ret < 0) {
- LOGP(DLINP, LOGL_ERROR, "Failed to forward GPRS message.\n");
- }
-}
-
-static int gprs_ns_cb(struct osmo_fd *bfd, unsigned int what)
-{
- struct ipa_bts_conn *bts;
- char buf[4096];
- int ret;
- struct sockaddr_in sock;
- socklen_t len = sizeof(sock);
-
- /* 1. get the data... */
- ret = recvfrom(bfd->fd, buf, sizeof(buf), 0, (struct sockaddr *) &sock, &len);
- if (ret < 0) {
- LOGP(DLINP, LOGL_ERROR, "Failed to recv GPRS NS msg: %s.\n", strerror(errno));
- return -1;
- }
-
- bts = bfd->data;
-
- /* 2. figure out where to send it to */
- if (memcmp(&sock.sin_addr, &ipp->gprs_addr, sizeof(sock.sin_addr)) == 0) {
- LOGP(DLINP, LOGL_DEBUG, "GPRS NS msg from network.\n");
- send_ns(bfd->fd, buf, ret, bts->bts_addr, 23000);
- } else if (memcmp(&sock.sin_addr, &bts->bts_addr, sizeof(sock.sin_addr)) == 0) {
- LOGP(DLINP, LOGL_DEBUG, "GPRS NS msg from BTS.\n");
- send_ns(bfd->fd, buf, ret, ipp->gprs_addr, 23000);
- } else {
- LOGP(DLINP, LOGL_ERROR, "Unknown GPRS source: %s\n", inet_ntoa(sock.sin_addr));
- }
-
- return 0;
-}
-
-/* Actively connect to a BSC. */
-static struct ipa_proxy_conn *connect_bsc(struct sockaddr_in *sa, int priv_nr, void *data)
-{
- struct ipa_proxy_conn *ipc;
- struct osmo_fd *bfd;
- int ret, on = 1;
-
- ipc = alloc_conn();
- if (!ipc)
- return NULL;
-
- ipc->bts_conn = data;
-
- bfd = &ipc->fd;
- bfd->fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
- bfd->cb = ipaccess_fd_cb;
- bfd->when = BSC_FD_READ | BSC_FD_WRITE;
- bfd->data = ipc;
- bfd->priv_nr = priv_nr;
-
- if (bfd->fd < 0) {
- LOGP(DLINP, LOGL_ERROR, "Could not create socket: %s\n",
- strerror(errno));
- talloc_free(ipc);
- return NULL;
- }
-
- ret = setsockopt(bfd->fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
- if (ret < 0) {
- LOGP(DLINP, LOGL_ERROR, "Could not set socket option\n");
- close(bfd->fd);
- talloc_free(ipc);
- return NULL;
- }
-
- ret = connect(bfd->fd, (struct sockaddr *) sa, sizeof(*sa));
- if (ret < 0) {
- LOGP(DLINP, LOGL_ERROR, "Could not connect socket: %s\n",
- inet_ntoa(sa->sin_addr));
- close(bfd->fd);
- talloc_free(ipc);
- return NULL;
- }
-
- /* pre-fill tx_queue with identity request */
- ret = osmo_fd_register(bfd);
- if (ret < 0) {
- close(bfd->fd);
- talloc_free(ipc);
- return NULL;
- }
-
- return ipc;
-}
-
-static int ipaccess_proxy_setup(void)
-{
- int ret;
-
- ipp = talloc_zero(tall_bsc_ctx, struct ipa_proxy);
- if (!ipp)
- return -ENOMEM;
- INIT_LLIST_HEAD(&ipp->bts_list);
- osmo_timer_setup(&ipp->reconn_timer, reconn_tmr_cb, ipp);
-
- /* Listen for OML connections */
- ret = make_sock(&ipp->oml_listen_fd, IPPROTO_TCP, INADDR_ANY,
- IPA_TCP_PORT_OML, OML_FROM_BTS, listen_fd_cb, NULL);
- if (ret < 0)
- return ret;
-
- /* Listen for RSL connections */
- ret = make_sock(&ipp->rsl_listen_fd, IPPROTO_TCP, INADDR_ANY,
- IPA_TCP_PORT_RSL, RSL_FROM_BTS, listen_fd_cb, NULL);
-
- if (ret < 0)
- return ret;
-
- /* Connect the GPRS NS Socket */
- if (gprs_ns_ipaddr) {
- inet_aton(gprs_ns_ipaddr, &ipp->gprs_addr);
- inet_aton(listen_ipaddr, &ipp->listen_addr);
- }
-
- return ret;
-}
-
-static void signal_handler(int signal)
-{
- fprintf(stdout, "signal %u received\n", signal);
-
- switch (signal) {
- case SIGABRT:
- /* in case of abort, we want to obtain a talloc report
- * and then return to the caller, who will abort the process */
- case SIGUSR1:
- talloc_report_full(tall_bsc_ctx, stderr);
- break;
- default:
- break;
- }
-}
-
-static void print_help(void)
-{
- printf(" ipaccess-proxy is a proxy BTS.\n");
- printf(" -h --help. This help text.\n");
- printf(" -l --listen IP. The ip to listen to.\n");
- printf(" -b --bsc IP. The BSC IP address.\n");
- printf(" -g --gprs IP. Take GPRS NS from that IP.\n");
- printf("\n");
- printf(" -s --disable-color. Disable the color inside the logging message.\n");
- printf(" -e --log-level number. Set the global loglevel.\n");
- printf(" -T --timestamp. Prefix every log message with a timestamp.\n");
- printf(" -V --version. Print the version of OpenBSC.\n");
-}
-
-static void print_usage(void)
-{
- printf("Usage: ipaccess-proxy [options]\n");
-}
-
-enum {
- IPA_PROXY_OPT_LISTEN_NONE = 0,
- IPA_PROXY_OPT_LISTEN_IP = (1 << 0),
- IPA_PROXY_OPT_BSC_IP = (1 << 1),
-};
-
-static void handle_options(int argc, char** argv)
-{
- int options_mask = 0;
-
- /* disable explicit missing arguments error output from getopt_long */
- opterr = 0;
-
- while (1) {
- int option_index = 0, c;
- static struct option long_options[] = {
- {"help", 0, 0, 'h'},
- {"disable-color", 0, 0, 's'},
- {"timestamp", 0, 0, 'T'},
- {"log-level", 1, 0, 'e'},
- {"listen", 1, 0, 'l'},
- {"bsc", 1, 0, 'b'},
- {0, 0, 0, 0}
- };
-
- c = getopt_long(argc, argv, "hsTe:l:b:g:",
- long_options, &option_index);
- if (c == -1)
- break;
-
- switch (c) {
- case 'h':
- print_usage();
- print_help();
- exit(0);
- case 'l':
- listen_ipaddr = optarg;
- options_mask |= IPA_PROXY_OPT_LISTEN_IP;
- break;
- case 'b':
- bsc_ipaddr = optarg;
- options_mask |= IPA_PROXY_OPT_BSC_IP;
- break;
- case 'g':
- gprs_ns_ipaddr = optarg;
- break;
- case 's':
- log_set_use_color(osmo_stderr_target, 0);
- break;
- case 'T':
- log_set_print_timestamp(osmo_stderr_target, 1);
- break;
- case 'e':
- log_set_log_level(osmo_stderr_target, atoi(optarg));
- break;
- case '?':
- if (optopt) {
- printf("ERROR: missing mandatory argument "
- "for `%s' option\n", argv[optind-1]);
- } else {
- printf("ERROR: unknown option `%s'\n",
- argv[optind-1]);
- }
- print_usage();
- print_help();
- exit(EXIT_FAILURE);
- break;
- default:
- /* ignore */
- break;
- }
- }
- if ((options_mask & (IPA_PROXY_OPT_LISTEN_IP | IPA_PROXY_OPT_BSC_IP))
- != (IPA_PROXY_OPT_LISTEN_IP | IPA_PROXY_OPT_BSC_IP)) {
- printf("ERROR: You have to specify `--listen' and `--bsc' "
- "options at least.\n");
- print_usage();
- print_help();
- exit(EXIT_FAILURE);
- }
-}
-
-int main(int argc, char **argv)
-{
- int rc;
-
- tall_bsc_ctx = talloc_named_const(NULL, 1, "ipaccess-proxy");
- msgb_talloc_ctx_init(tall_bsc_ctx, 0);
-
- osmo_init_logging(&log_info);
- log_parse_category_mask(osmo_stderr_target, "DLINP:DLMI");
-
- handle_options(argc, argv);
-
- rc = ipaccess_proxy_setup();
- if (rc < 0)
- exit(1);
-
- signal(SIGUSR1, &signal_handler);
- signal(SIGABRT, &signal_handler);
- osmo_init_ignore_signals();
-
- while (1) {
- osmo_select_main(0);
- }
-}
diff --git a/src/ipaccess/network_listen.c b/src/ipaccess/network_listen.c
deleted file mode 100644
index 3b44ceb7..00000000
--- a/src/ipaccess/network_listen.c
+++ /dev/null
@@ -1,257 +0,0 @@
-/* ip.access nanoBTS network listen mode */
-
-/* (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 <unistd.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-#include <stdint.h>
-
-#include <arpa/inet.h>
-
-#include <osmocom/core/talloc.h>
-#include <osmocom/core/timer.h>
-#include <osmocom/gsm/rxlev_stat.h>
-#include <osmocom/gsm/gsm48_ie.h>
-
-#include <openbsc/gsm_data.h>
-#include <openbsc/abis_nm.h>
-#include <openbsc/signal.h>
-#include <openbsc/debug.h>
-#include <osmocom/abis/e1_input.h>
-
-#define WHITELIST_MAX_SIZE ((NUM_ARFCNS*2)+2+1)
-
-int ipac_rxlevstat2whitelist(uint16_t *buf, const struct rxlev_stats *st, uint8_t min_rxlev,
- uint16_t max_num_arfcns)
-{
- int i;
- unsigned int num_arfcn = 0;
-
- for (i = NUM_RXLEVS-1; i >= min_rxlev; i--) {
- int16_t arfcn = -1;
-
- while ((arfcn = rxlev_stat_get_next(st, i, arfcn)) >= 0) {
- *buf++ = htons(arfcn);
- num_arfcn++;
-
- }
-
- if (num_arfcn > max_num_arfcns)
- break;
- }
-
- return num_arfcn;
-}
-
-enum ipac_test_state {
- IPAC_TEST_S_IDLE,
- IPAC_TEST_S_RQD,
- IPAC_TEST_S_EXEC,
- IPAC_TEST_S_PARTIAL,
-};
-
-int ipac_nwl_test_start(struct gsm_bts_trx *trx, uint8_t testnr,
- const uint8_t *phys_conf, unsigned int phys_conf_len)
-{
- struct msgb *msg;
-
- if (trx->ipaccess.test_state != IPAC_TEST_S_IDLE) {
- fprintf(stderr, "Cannot start test in state %u\n", trx->ipaccess.test_state);
- return -EINVAL;
- }
-
- switch (testnr) {
- case NM_IPACC_TESTNO_CHAN_USAGE:
- case NM_IPACC_TESTNO_BCCH_CHAN_USAGE:
- rxlev_stat_reset(&trx->ipaccess.rxlev_stat);
- break;
- }
-
- msg = msgb_alloc_headroom(phys_conf_len+256, 128, "OML");
-
- if (phys_conf && phys_conf_len) {
- uint8_t *payload;
- /* first put the phys conf header */
- msgb_tv16_put(msg, NM_ATT_PHYS_CONF, phys_conf_len);
- payload = msgb_put(msg, phys_conf_len);
- memcpy(payload, phys_conf, phys_conf_len);
- }
-
- abis_nm_perform_test(trx->bts, NM_OC_RADIO_CARRIER, 0, trx->nr, 0xff,
- testnr, 1, msg);
- trx->ipaccess.test_nr = testnr;
-
- /* FIXME: start safety timer until when test is supposed to complete */
-
- return 0;
-}
-
-static uint16_t last_arfcn;
-static struct gsm_sysinfo_freq nwl_si_freq[1024];
-#define FREQ_TYPE_NCELL_2 0x04 /* sub channel of SI 2 */
-#define FREQ_TYPE_NCELL_2bis 0x08 /* sub channel of SI 2bis */
-#define FREQ_TYPE_NCELL_2ter 0x10 /* sub channel of SI 2ter */
-
-struct ipacc_ferr_elem {
- int16_t freq_err;
- uint8_t freq_qual;
- uint8_t arfcn;
-} __attribute__((packed));
-
-struct ipacc_cusage_elem {
- uint16_t arfcn:10,
- rxlev:6;
-} __attribute__ ((packed));
-
-static int test_rep(void *_msg)
-{
- struct msgb *msg = _msg;
- struct abis_om_fom_hdr *foh = msgb_l3(msg);
- uint16_t test_rep_len, ferr_list_len;
- struct ipacc_ferr_elem *ife;
- struct ipac_bcch_info binfo;
- struct e1inp_sign_link *sign_link = (struct e1inp_sign_link *)msg->dst;
- int i, rc;
-
- DEBUGP(DNM, "TEST REPORT: ");
-
- if (foh->data[0] != NM_ATT_TEST_NO ||
- foh->data[2] != NM_ATT_TEST_REPORT)
- return -EINVAL;
-
- DEBUGPC(DNM, "test_no=0x%02x ", foh->data[1]);
- /* data[2] == NM_ATT_TEST_REPORT */
- /* data[3..4]: test_rep_len */
- memcpy(&test_rep_len, &foh->data[3], sizeof(uint16_t));
- test_rep_len = ntohs(test_rep_len);
- /* data[5]: ip.access test result */
- DEBUGPC(DNM, "tst_res=%s\n", ipacc_testres_name(foh->data[5]));
-
- /* data[6]: ip.access nested IE. 3 == freq_err_list */
- switch (foh->data[6]) {
- case NM_IPAC_EIE_FREQ_ERR_LIST:
- /* data[7..8]: length of ferr_list */
- memcpy(&ferr_list_len, &foh->data[7], sizeof(uint16_t));
- ferr_list_len = ntohs(ferr_list_len);
-
- /* data[9...]: frequency error list elements */
- for (i = 0; i < ferr_list_len; i+= sizeof(*ife)) {
- ife = (struct ipacc_ferr_elem *) (foh->data + 9 + i);
- DEBUGP(DNM, "==> ARFCN %4u, Frequency Error %6hd\n",
- ife->arfcn, ntohs(ife->freq_err));
- }
- break;
- case NM_IPAC_EIE_CHAN_USE_LIST:
- /* data[7..8]: length of ferr_list */
- memcpy(&ferr_list_len, &foh->data[7], sizeof(uint16_t));
- ferr_list_len = ntohs(ferr_list_len);
-
- /* data[9...]: channel usage list elements */
- for (i = 0; i < ferr_list_len; i+= 2) {
- uint16_t *cu_ptr = (uint16_t *)(foh->data + 9 + i);
- uint16_t cu = ntohs(*cu_ptr);
- uint16_t arfcn = cu & 0x3ff;
- uint8_t rxlev = cu >> 10;
- DEBUGP(DNM, "==> ARFCN %4u, RxLev %2u\n", arfcn, rxlev);
- rxlev_stat_input(&sign_link->trx->ipaccess.rxlev_stat,
- arfcn, rxlev);
- }
- break;
- case NM_IPAC_EIE_BCCH_INFO_TYPE:
- break;
- case NM_IPAC_EIE_BCCH_INFO:
- rc = ipac_parse_bcch_info(&binfo, foh->data+6);
- if (rc < 0) {
- DEBUGP(DNM, "BCCH Info parsing failed\n");
- break;
- }
- DEBUGP(DNM, "==> ARFCN %u, RxLev %2u, RxQual %2u: %3d-%d, LAC %d CI %d BSIC %u\n",
- binfo.arfcn, binfo.rx_lev, binfo.rx_qual,
- binfo.cgi.mcc, binfo.cgi.mnc,
- binfo.cgi.lac, binfo.cgi.ci, binfo.bsic);
-
- if (binfo.arfcn != last_arfcn) {
- /* report is on a new arfcn, need to clear channel list */
- memset(nwl_si_freq, 0, sizeof(nwl_si_freq));
- last_arfcn = binfo.arfcn;
- }
- if (binfo.info_type & IPAC_BINF_NEIGH_BA_SI2) {
- DEBUGP(DNM, "BA SI2: %s\n", osmo_hexdump(binfo.ba_list_si2, sizeof(binfo.ba_list_si2)));
- gsm48_decode_freq_list(nwl_si_freq, binfo.ba_list_si2, sizeof(binfo.ba_list_si2),
- 0x8c, FREQ_TYPE_NCELL_2);
- }
- if (binfo.info_type & IPAC_BINF_NEIGH_BA_SI2bis) {
- DEBUGP(DNM, "BA SI2bis: %s\n", osmo_hexdump(binfo.ba_list_si2bis, sizeof(binfo.ba_list_si2bis)));
- gsm48_decode_freq_list(nwl_si_freq, binfo.ba_list_si2bis, sizeof(binfo.ba_list_si2bis),
- 0x8e, FREQ_TYPE_NCELL_2bis);
- }
- if (binfo.info_type & IPAC_BINF_NEIGH_BA_SI2ter) {
- DEBUGP(DNM, "BA SI2ter: %s\n", osmo_hexdump(binfo.ba_list_si2ter, sizeof(binfo.ba_list_si2ter)));
- gsm48_decode_freq_list(nwl_si_freq, binfo.ba_list_si2ter, sizeof(binfo.ba_list_si2ter),
- 0x8e, FREQ_TYPE_NCELL_2ter);
- }
- for (i = 0; i < ARRAY_SIZE(nwl_si_freq); i++) {
- if (nwl_si_freq[i].mask)
- DEBUGP(DNM, "Neighbor Cell on ARFCN %u\n", i);
- }
- break;
- default:
- break;
- }
-
- switch (foh->data[5]) {
- case NM_IPACC_TESTRES_SUCCESS:
- case NM_IPACC_TESTRES_STOPPED:
- case NM_IPACC_TESTRES_TIMEOUT:
- case NM_IPACC_TESTRES_NO_CHANS:
- sign_link->trx->ipaccess.test_state = IPAC_TEST_S_IDLE;
- /* Send signal to notify higher layers of test completion */
- DEBUGP(DNM, "dispatching S_IPAC_NWL_COMPLETE signal\n");
- osmo_signal_dispatch(SS_IPAC_NWL, S_IPAC_NWL_COMPLETE,
- sign_link->trx);
- break;
- case NM_IPACC_TESTRES_PARTIAL:
- sign_link->trx->ipaccess.test_state = IPAC_TEST_S_PARTIAL;
- break;
- }
-
- return 0;
-}
-
-static int nwl_sig_cb(unsigned int subsys, unsigned int signal,
- void *handler_data, void *signal_data)
-{
- switch (signal) {
- case S_NM_TEST_REP:
- return test_rep(signal_data);
- default:
- break;
- }
-
- return 0;
-}
-
-void ipac_nwl_init(void)
-{
- osmo_signal_register_handler(SS_NM, nwl_sig_cb, NULL);
-}
diff --git a/src/libbsc/Makefile.am b/src/libbsc/Makefile.am
deleted file mode 100644
index e78bde62..00000000
--- a/src/libbsc/Makefile.am
+++ /dev/null
@@ -1,57 +0,0 @@
-AM_CPPFLAGS = \
- $(all_includes) \
- -I$(top_srcdir)/include \
- -I$(top_builddir) \
- $(NULL)
-
-AM_CFLAGS = \
- -Wall \
- $(LIBOSMOCORE_CFLAGS) \
- $(LIBOSMOGSM_CFLAGS) \
- $(LIBOSMOVTY_CFLAGS) \
- $(LIBOSMOABIS_CFLAGS) \
- $(COVERAGE_CFLAGS) \
- $(NULL)
-
-noinst_LIBRARIES = \
- libbsc.a \
- $(NULL)
-
-libbsc_a_SOURCES = \
- abis_nm.c \
- abis_nm_vty.c \
- abis_om2000.c \
- abis_om2000_vty.c \
- abis_rsl.c \
- bsc_rll.c \
- bsc_subscriber.c \
- paging.c \
- bts_ericsson_rbs2000.c \
- bts_ipaccess_nanobts.c \
- bts_siemens_bs11.c \
- bts_nokia_site.c \
- bts_unknown.c \
- bts_sysmobts.c \
- chan_alloc.c \
- handover_decision.c \
- handover_logic.c \
- meas_rep.c \
- pcu_sock.c \
- rest_octets.c \
- system_information.c \
- e1_config.c \
- bsc_api.c \
- bsc_msc.c bsc_vty.c \
- gsm_04_08_utils.c \
- gsm_04_80_utils.c \
- bsc_init.c \
- bts_init.c \
- bsc_rf_ctrl.c \
- arfcn_range_encode.c \
- bsc_ctrl_commands.c \
- bsc_ctrl_lookup.c \
- net_init.c \
- bsc_dyn_ts.c \
- bts_ipaccess_nanobts_omlattr.c \
- $(NULL)
-
diff --git a/src/libbsc/abis_nm.c b/src/libbsc/abis_nm.c
deleted file mode 100644
index 019d0395..00000000
--- a/src/libbsc/abis_nm.c
+++ /dev/null
@@ -1,2917 +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/stat.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-
-#include <openbsc/gsm_data.h>
-#include <openbsc/debug.h>
-#include <osmocom/core/msgb.h>
-#include <osmocom/gsm/protocol/gsm_12_21.h>
-#include <osmocom/gsm/tlv.h>
-#include <osmocom/gsm/abis_nm.h>
-#include <osmocom/core/talloc.h>
-#include <osmocom/core/utils.h>
-#include <openbsc/abis_nm.h>
-#include <openbsc/misdn.h>
-#include <openbsc/signal.h>
-#include <osmocom/abis/e1_input.h>
-
-#define OM_ALLOC_SIZE 1024
-#define OM_HEADROOM_SIZE 128
-#define IPACC_SEGMENT_SIZE 245
-
-int abis_nm_tlv_parse(struct tlv_parsed *tp, struct gsm_bts *bts, const uint8_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, abis_nm_reports, ARRAY_SIZE(abis_nm_reports));
-}
-
-#define MT_ACK(x) (x+1)
-#define MT_NACK(x) (x+2)
-
-static void fill_om_hdr(struct abis_om_hdr *oh, uint8_t len)
-{
- oh->mdisc = ABIS_OM_MDISC_FOM;
- oh->placement = ABIS_OM_PLACEMENT_ONLY;
- oh->sequence = 0;
- oh->length = len;
-}
-
-static struct abis_om_fom_hdr *fill_om_fom_hdr(struct abis_om_hdr *oh, uint8_t len,
- uint8_t msg_type, uint8_t obj_class,
- uint8_t bts_nr, uint8_t trx_nr, uint8_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;
- return foh;
-}
-
-static struct msgb *nm_msgb_alloc(void)
-{
- return msgb_alloc_headroom(OM_ALLOC_SIZE, OM_HEADROOM_SIZE,
- "OML");
-}
-
-int _abis_nm_sendmsg(struct msgb *msg)
-{
- msg->l2h = msg->data;
-
- if (!msg->dst) {
- LOGP(DNM, LOGL_ERROR, "%s: msg->dst == NULL\n", __func__);
- return -EINVAL;
- }
-
- return abis_sendmsg(msg);
-}
-
-/* Send a OML NM Message from BSC to BTS */
-static int abis_nm_queue_msg(struct gsm_bts *bts, struct msgb *msg)
-{
- msg->dst = bts->oml_link;
-
- /* 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);
- } 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);
-
-int nm_is_running(struct gsm_nm_state *s) {
- return (s->operational == NM_OPSTATE_ENABLED) && (
- (s->availability == NM_AVSTATE_OK) ||
- (s->availability == 0xff)
- );
-}
-
-/* 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, uint8_t obj_class,
- struct abis_om_obj_inst *obj_inst, uint8_t adm_state)
-{
- struct gsm_nm_state *nm_state, new_state;
- struct nm_statechg_signal_data nsd;
-
- memset(&nsd, 0, sizeof(nsd));
-
- nsd.obj = gsm_objclass2obj(bts, obj_class, obj_inst);
- if (!nsd.obj)
- return -EINVAL;
- nm_state = gsm_objclass2nmstate(bts, obj_class, obj_inst);
- if (!nm_state)
- return -1;
-
- new_state = *nm_state;
- new_state.administrative = adm_state;
-
- nsd.bts = bts;
- nsd.obj_class = obj_class;
- nsd.old_state = nm_state;
- nsd.new_state = &new_state;
- nsd.obj_inst = obj_inst;
- osmo_signal_dispatch(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 e1inp_sign_link *sign_link = mb->dst;
- struct gsm_bts *bts = sign_link->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 = gsm_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 ",
- abis_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) ",
- abis_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 ",
- get_value_string(abis_nm_adm_state_names,
- 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 = gsm_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;
- nsd.bts = bts;
- osmo_signal_dispatch(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 inline void log_oml_fail_rep(const struct gsm_bts *bts, const char *type,
- const char *severity, const uint8_t *p_val,
- const char *text)
-{
- enum abis_nm_pcause_type pcause = p_val[0];
- enum abis_mm_event_causes cause = osmo_load16be(p_val + 1);
-
- LOGPC(DNM, LOGL_ERROR, "BTS %u: Failure Event Report: ", bts->nr);
- if (type)
- LOGPC(DNM, LOGL_ERROR, "Type=%s, ", type);
- if (severity)
- LOGPC(DNM, LOGL_ERROR, "Severity=%s, ", severity);
-
- LOGPC(DNM, LOGL_ERROR, "Probable cause=%s: ",
- get_value_string(abis_nm_pcause_type_names, pcause));
-
- if (pcause == NM_PCAUSE_T_MANUF)
- LOGPC(DNM, LOGL_ERROR, "%s, ",
- get_value_string(abis_mm_event_cause_names, cause));
- else
- LOGPC(DNM, LOGL_ERROR, "%02X %02X ", p_val[1], p_val[2]);
-
- if (text) {
- LOGPC(DNM, LOGL_ERROR, "Additional Text=%s. ", text);
- }
-
- LOGPC(DNM, LOGL_ERROR, "\n");
-}
-
-static inline void handle_manufact_report(struct gsm_bts *bts, const uint8_t *p_val, const char *type,
- const char *severity, const char *text)
-{
- enum abis_mm_event_causes cause = osmo_load16be(p_val + 1);
-
- switch (cause) {
- case OSMO_EVT_PCU_VERS:
- if (text) {
- LOGPC(DNM, LOGL_NOTICE, "BTS %u reported connected PCU version %s\n", bts->nr, text);
- osmo_strlcpy(bts->pcu_version, text, sizeof(bts->pcu_version));
- } else {
- LOGPC(DNM, LOGL_ERROR, "BTS %u reported PCU disconnection.\n", bts->nr);
- bts->pcu_version[0] = '\0';
- }
- break;
- default:
- log_oml_fail_rep(bts, type, severity, p_val, text);
- };
-}
-
-static int rx_fail_evt_rep(struct msgb *mb, struct gsm_bts *bts)
-{
- struct abis_om_hdr *oh = msgb_l2(mb);
- struct abis_om_fom_hdr *foh = msgb_l3(mb);
- struct e1inp_sign_link *sign_link = mb->dst;
- struct tlv_parsed tp;
- int rc = 0;
- const uint8_t *p_val = NULL;
- char *p_text = NULL;
- const char *e_type = NULL, *severity = NULL;
-
- abis_nm_tlv_parse(&tp, sign_link->trx->bts, foh->data,
- oh->length-sizeof(*foh));
-
- 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 (TLVP_PRESENT(&tp, NM_ATT_EVENT_TYPE))
- e_type = abis_nm_event_type_name(*TLVP_VAL(&tp,
- NM_ATT_EVENT_TYPE));
-
- if (TLVP_PRESENT(&tp, NM_ATT_SEVERITY))
- severity = abis_nm_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);
-
- switch (p_val[0]) {
- case NM_PCAUSE_T_MANUF:
- handle_manufact_report(bts, p_val, e_type, severity,
- p_text);
- break;
- default:
- log_oml_fail_rep(bts, e_type, severity, p_val, p_text);
- };
- } else {
- LOGPC(DNM, LOGL_ERROR, "BTS%u: Failure Event Report without "
- "Probable Cause?!\n", bts->nr);
- rc = -EINVAL;
- }
-
- if (p_text)
- talloc_free(p_text);
-
- return rc;
-}
-
-static int abis_nm_rcvmsg_report(struct msgb *mb, struct gsm_bts *bts)
-{
- struct abis_om_fom_hdr *foh = msgb_l3(mb);
- uint8_t mt = foh->msg_type;
-
- abis_nm_debugp_foh(DNM, 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");
- osmo_signal_dispatch(SS_NM, S_NM_SW_ACTIV_REP, mb);
- break;
- case NM_MT_FAILURE_EVENT_REP:
- rx_fail_evt_rep(mb, bts);
- osmo_signal_dispatch(SS_NM, S_NM_FAIL_REP, mb);
- break;
- case NM_MT_TEST_REP:
- DEBUGPC(DNM, "Test Report\n");
- osmo_signal_dispatch(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, uint8_t obj_class, uint8_t i0, uint8_t i1,
- uint8_t i2, const struct abis_nm_sw_desc *sw_desc)
-{
- struct abis_om_hdr *oh;
- struct msgb *msg = nm_msgb_alloc();
- uint16_t len = abis_nm_sw_desc_len(sw_desc, true);
-
- 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);
- abis_nm_put_sw_desc(msg, sw_desc, true);
-
- return abis_nm_sendmsg(bts, msg);
-}
-
-int abis_nm_select_newest_sw(const struct abis_nm_sw_desc *sw_descr,
- const size_t size)
-{
- int res = 0;
- int i;
-
- for (i = 1; i < size; ++i) {
- if (memcmp(sw_descr[res].file_version, sw_descr[i].file_version,
- OSMO_MIN(sw_descr[i].file_version_len,
- sw_descr[res].file_version_len)) < 0) {
- res = i;
- }
- }
-
- return res;
-}
-
-static inline bool handle_attr(const struct gsm_bts *bts, enum bts_attribute id, uint8_t *val, uint8_t len)
-{
- switch (id) {
- case BTS_TYPE_VARIANT:
- LOGP(DNM, LOGL_NOTICE, "BTS%u reported variant: %s\n", bts->nr, val);
- break;
- case BTS_SUB_MODEL:
- LOGP(DNM, LOGL_NOTICE, "BTS%u reported submodel: %s\n", bts->nr, val);
- break;
- default:
- return false;
- }
- return true;
-}
-
-/* Parse Attribute Response Info - return pointer to the actual content */
-static inline uint8_t *parse_attr_resp_info_unreported(uint8_t bts_nr, uint8_t *ari, uint16_t ari_len, uint16_t *out_len)
-{
- uint8_t num_unreported = ari[0], i;
-
- DEBUGP(DNM, "BTS%u Get Attributes Response Info: %u bytes total with %u unreported attributes\n",
- bts_nr, ari_len, num_unreported);
-
- /* +1 because we have to account for number of unreported attributes, prefixing the list: */
- for (i = 0; i < num_unreported; i++)
- LOGP(DNM, LOGL_ERROR, "BTS%u Attribute %s is unreported\n",
- bts_nr, get_value_string(abis_nm_att_names, ari[i + 1]));
-
- /* the data starts right after the list of unreported attributes + space for length of that list */
- *out_len = ari_len - (num_unreported + 2);
-
- return ari + num_unreported + 1; /* we have to account for 1st byte with number of unreported attributes */
-}
-
-/* Parse Attribute Response Info content for 3GPP TS 52.021 §9.4.30 Manufacturer Id */
-static inline uint8_t *parse_attr_resp_info_manuf_id(struct gsm_bts *bts, uint8_t *data, uint16_t *data_len)
-{
- struct tlv_parsed tp;
- uint16_t m_id_len = 0;
- uint8_t adjust = 0, i;
-
- abis_nm_tlv_parse(&tp, bts, data, *data_len);
- if (TLVP_PRES_LEN(&tp, NM_ATT_MANUF_ID, 2)) {
- m_id_len = TLVP_LEN(&tp, NM_ATT_MANUF_ID);
-
- /* log potential BTS feature vector overflow */
- if (m_id_len > sizeof(bts->_features_data))
- LOGP(DNM, LOGL_NOTICE, "BTS%u Get Attributes Response: feature vector is truncated to %u bytes\n",
- bts->nr, MAX_BTS_FEATURES/8);
-
- /* check that max. expected BTS attribute is above given feature vector length */
- if (m_id_len > OSMO_BYTES_FOR_BITS(_NUM_BTS_FEAT))
- LOGP(DNM, LOGL_NOTICE, "BTS%u Get Attributes Response: reported unexpectedly long (%u bytes) "
- "feature vector - most likely it was compiled against newer BSC headers. "
- "Consider upgrading your BSC to later version.\n",
- bts->nr, m_id_len);
-
- memcpy(bts->_features_data, TLVP_VAL(&tp, NM_ATT_MANUF_ID), sizeof(bts->_features_data));
- adjust = m_id_len + 3; /* adjust for parsed TL16V struct */
-
- for (i = 0; i < _NUM_BTS_FEAT; i++)
- if (gsm_bts_has_feature(bts, i) != gsm_btsmodel_has_feature(bts->model, i))
- LOGP(DNM, LOGL_NOTICE, "BTS%u feature '%s' reported via OML does not match statically "
- "set feature: %u != %u. Please fix.\n", bts->nr,
- get_value_string(gsm_bts_features_descs, i),
- gsm_bts_has_feature(bts, i), gsm_btsmodel_has_feature(bts->model, i));
- }
-
- *data_len -= adjust;
-
- return data + adjust;
-}
-
-/* Parse Attribute Response Info content for 3GPP TS 52.021 §9.4.28 Manufacturer Dependent State */
-static inline uint8_t *parse_attr_resp_info_manuf_state(const struct gsm_bts_trx *trx, uint8_t *data, uint16_t *data_len)
-{
- struct tlv_parsed tp;
- const uint8_t *power;
- uint8_t adjust = 0;
-
- if (!trx) /* this attribute does not make sense on BTS level, only on TRX level */
- return data;
-
- abis_nm_tlv_parse(&tp, trx->bts, data, *data_len);
- if (TLVP_PRES_LEN(&tp, NM_ATT_MANUF_STATE, 1)) {
- power = TLVP_VAL(&tp, NM_ATT_MANUF_STATE);
- LOGP(DNM, LOGL_NOTICE, "%s Get Attributes Response: nominal power is %u\n", gsm_trx_name(trx), *power);
- adjust = 2; /* adjust for parsed TV struct */
- }
-
- *data_len -= adjust;
-
- return data + adjust;
-}
-
-/* Handle 3GPP TS 52.021 §9.4.64 Get Attribute Response Info */
-static int abis_nm_rx_get_attr_resp(struct msgb *mb, const struct gsm_bts_trx *trx)
-{
- struct abis_om_hdr *oh = msgb_l2(mb);
- struct abis_om_fom_hdr *foh = msgb_l3(mb);
- struct e1inp_sign_link *sign_link = mb->dst;
- struct gsm_bts *bts = trx ? trx->bts : sign_link->trx->bts;
- struct tlv_parsed tp;
- uint8_t *data, i;
- uint16_t data_len;
- int rc;
- struct abis_nm_sw_desc sw_descr[MAX_BTS_ATTR];
-
- abis_nm_debugp_foh(DNM, foh);
-
- DEBUGPC(DNM, "Get Attributes Response for BTS%u\n", bts->nr);
-
- abis_nm_tlv_parse(&tp, bts, foh->data, oh->length-sizeof(*foh));
- if (!TLVP_PRES_LEN(&tp, NM_ATT_GET_ARI, 1)) {
- LOGP(DNM, LOGL_ERROR, "BTS%u: Get Attributes Response without Response Info?!\n", bts->nr);
- return -EINVAL;
- }
-
- data = parse_attr_resp_info_unreported(bts->nr, TLVP_VAL(&tp, NM_ATT_GET_ARI), TLVP_LEN(&tp, NM_ATT_GET_ARI),
- &data_len);
-
- data = parse_attr_resp_info_manuf_state(trx, data, &data_len);
- data = parse_attr_resp_info_manuf_id(bts, data, &data_len);
-
- /* after parsing manufacturer-specific attributes there's list of replies in form of sw-conf structure: */
- rc = abis_nm_get_sw_conf(data, data_len, &sw_descr[0], ARRAY_SIZE(sw_descr));
- if (rc > 0) {
- for (i = 0; i < rc; i++) {
- if (!handle_attr(bts, str2btsattr((const char *)sw_descr[i].file_id),
- sw_descr[i].file_version, sw_descr[i].file_version_len))
- LOGP(DNM, LOGL_NOTICE, "BTS%u: ARI reported sw[%d/%d]: %s is %s\n",
- bts->nr, i, rc, sw_descr[i].file_id, sw_descr[i].file_version);
- }
- } else
- LOGP(DNM, LOGL_ERROR, "BTS%u: failed to parse SW-Config part of Get Attribute Response Info: %s\n",
- bts->nr, strerror(-rc));
-
- return 0;
-}
-
-/* 3GPP TS 52.021 §6.2.5 */
-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 e1inp_sign_link *sign_link = mb->dst;
- struct tlv_parsed tp;
- const uint8_t *sw_config;
- int ret, sw_config_len, len;
- struct abis_nm_sw_desc sw_descr[MAX_BTS_ATTR];
-
- abis_nm_debugp_foh(DNM, foh);
-
- DEBUGPC(DNM, "SW Activate Request: ");
-
- DEBUGP(DNM, "Software Activate Request, ACKing and Activating\n");
-
- ret = abis_nm_sw_act_req_ack(sign_link->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));
- if (ret != 0) {
- LOGP(DNM, LOGL_ERROR,
- "Sending SW ActReq ACK failed: %d\n", ret);
- return ret;
- }
-
- abis_nm_tlv_parse(&tp, sign_link->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)) {
- LOGP(DNM, LOGL_ERROR,
- "SW config not found! Can't continue.\n");
- return -EINVAL;
- } else {
- DEBUGP(DNM, "Found SW config: %s\n", osmo_hexdump(sw_config, sw_config_len));
- }
-
- /* Parse up to two sw descriptions from the data */
- len = abis_nm_get_sw_conf(sw_config, sw_config_len, &sw_descr[0],
- ARRAY_SIZE(sw_descr));
- if (len <= 0) {
- LOGP(DNM, LOGL_ERROR, "Failed to parse SW Config.\n");
- return -EINVAL;
- }
-
- ret = abis_nm_select_newest_sw(&sw_descr[0], len);
- DEBUGP(DNM, "Selected sw description %d of %d\n", ret, len);
-
- return ipacc_sw_activate(sign_link->trx->bts, foh->obj_class,
- foh->obj_inst.bts_nr,
- foh->obj_inst.trx_nr,
- foh->obj_inst.ts_nr,
- &sw_descr[ret]);
-}
-
-/* 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 e1inp_sign_link *sign_link = mb->dst;
- struct tlv_parsed tp;
- uint8_t adm_state;
-
- abis_nm_tlv_parse(&tp, sign_link->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(sign_link->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 e1inp_sign_link *sign_link = mb->dst;
- struct tlv_parsed tp;
-
- DEBUGP(DNM, "LMT Event ");
- abis_nm_tlv_parse(&tp, sign_link->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) {
- uint8_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) {
- uint8_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;
-}
-
-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);
-
- 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);
- struct e1inp_sign_link *sign_link = mb->dst;
- uint8_t mt = foh->msg_type;
- /* sign_link might get deleted via osmo_signal_dispatch -> save bts */
- struct gsm_bts *bts = sign_link->trx->bts;
- int ret = 0;
-
- /* check for unsolicited message */
- if (is_report(mt))
- return abis_nm_rcvmsg_report(mb, bts);
-
- if (is_in_arr(mt, abis_nm_sw_load_msgs, ARRAY_SIZE(abis_nm_sw_load_msgs)))
- return abis_nm_rcvmsg_sw(mb);
-
- if (is_in_arr(mt, abis_nm_nacks, ARRAY_SIZE(abis_nm_nacks))) {
- struct nm_nack_signal_data nack_data;
- struct tlv_parsed tp;
-
- abis_nm_debugp_foh(DNM, foh);
-
- DEBUGPC(DNM, "%s NACK ", abis_nm_nack_name(mt));
-
- abis_nm_tlv_parse(&tp, bts, foh->data, oh->length-sizeof(*foh));
- if (TLVP_PRESENT(&tp, NM_ATT_NACK_CAUSES))
- DEBUGPC(DNM, "CAUSE=%s\n",
- abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
- else
- DEBUGPC(DNM, "\n");
-
- nack_data.msg = mb;
- nack_data.mt = mt;
- nack_data.bts = bts;
- osmo_signal_dispatch(SS_NM, S_NM_NACK, &nack_data);
- abis_nm_queue_send_next(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_OPSTART_ACK:
- abis_nm_debugp_foh(DNM, foh);
- DEBUGPC(DNM, "Opstart ACK\n");
- break;
- case NM_MT_SET_CHAN_ATTR_ACK:
- abis_nm_debugp_foh(DNM, foh);
- DEBUGPC(DNM, "Set Channel Attributes ACK\n");
- break;
- case NM_MT_SET_RADIO_ATTR_ACK:
- abis_nm_debugp_foh(DNM, foh);
- DEBUGPC(DNM, "Set Radio Carrier Attributes ACK\n");
- break;
- case NM_MT_CONN_MDROP_LINK_ACK:
- abis_nm_debugp_foh(DNM, foh);
- DEBUGPC(DNM, "CONN MDROP LINK ACK\n");
- break;
- case NM_MT_IPACC_RESTART_ACK:
- osmo_signal_dispatch(SS_NM, S_NM_IPACC_RESTART_ACK, NULL);
- break;
- case NM_MT_IPACC_RESTART_NACK:
- osmo_signal_dispatch(SS_NM, S_NM_IPACC_RESTART_NACK, NULL);
- break;
- case NM_MT_SET_BTS_ATTR_ACK:
- break;
- case NM_MT_GET_ATTR_RESP:
- ret = abis_nm_rx_get_attr_resp(mb, gsm_bts_trx_num(bts, (foh)->obj_inst.trx_nr));
- break;
- default:
- abis_nm_debugp_foh(DNM, foh);
- LOGPC(DNM, LOGL_ERROR, "Unhandled message %s\n",
- get_value_string(abis_nm_msgtype_names, mt));
- }
-
- abis_nm_queue_send_next(bts);
- return ret;
-}
-
-static int abis_nm_rx_ipacc(struct msgb *mb);
-
-static int abis_nm_rcvmsg_manuf(struct msgb *mb)
-{
- int rc;
- struct e1inp_sign_link *sign_link = mb->dst;
- int bts_type = sign_link->trx->bts->type;
-
- switch (bts_type) {
- case GSM_BTS_TYPE_NANOBTS:
- case GSM_BTS_TYPE_OSMOBTS:
- rc = abis_nm_rx_ipacc(mb);
- abis_nm_queue_send_next(sign_link->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) {
- rc = -EINVAL;
- goto err;
- }
- }
- if (oh->sequence != 0) {
- LOGP(DNM, LOGL_ERROR, "ABIS OML sequence 0x%x != 0x00\n",
- oh->sequence);
- rc = -EINVAL;
- goto err;
- }
-#if 0
- unsigned int l2_len = msg->tail - (uint8_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);
- rc = -EINVAL;
- break;
- }
-err:
- 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 */
- uint8_t obj_class;
- uint8_t obj_instance[3];
-
- uint8_t file_id[255];
- uint8_t file_id_len;
-
- uint8_t file_version[255];
- uint8_t file_version_len;
-
- uint8_t window_size;
- uint8_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();
- uint8_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);
-
- /* Did ftell fail? Then we are at the end for sure */
- if (pos < 0)
- return 1;
-
- if (!fgets(next_seg_buf, sizeof(next_seg_buf)-2, stream)) {
- int rc = fseek(stream, pos, SEEK_SET);
- if (rc < 0)
- return rc;
- 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;
- int 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, (uint8_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: {
- osmo_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 uint8_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();
- uint8_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();
- uint8_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);
- struct e1inp_sign_link *sign_link = mb->dst;
- 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(sign_link->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(sign_link->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(sign_link->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(sign_link->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(sign_link->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(sign_link->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(sign_link->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,
- uint8_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, uint8_t bts_port,
- uint8_t ts_nr, uint8_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, uint8_t trx_nr,
- uint8_t e1_port, uint8_t e1_timeslot, uint8_t e1_subslot,
- uint8_t tei)
-{
- struct abis_om_hdr *oh;
- struct abis_nm_channel *ch;
- uint8_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,
- uint8_t e1_port, uint8_t e1_timeslot, uint8_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,
- uint8_t e1_port, uint8_t e1_timeslot,
- uint8_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,
- uint8_t subchan)
-{
-}
-#endif
-
-/* 3GPP TS 52.021 § 8.11.1 */
-int abis_nm_get_attr(struct gsm_bts *bts, uint8_t obj_class, uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr,
- const uint8_t *attr, uint8_t attr_len)
-{
- struct abis_om_hdr *oh;
- struct msgb *msg = nm_msgb_alloc();
-
- DEBUGP(DNM, "Get 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_GET_ATTR, obj_class,
- bts_nr, trx_nr, ts_nr);
- msgb_tl16v_put(msg, NM_ATT_LIST_REQ_ATTR, attr_len, attr);
-
- return abis_nm_sendmsg(bts, msg);
-}
-
-/* Chapter 8.6.1 */
-int abis_nm_set_bts_attr(struct gsm_bts *bts, uint8_t *attr, int attr_len)
-{
- struct abis_om_hdr *oh;
- struct msgb *msg = nm_msgb_alloc();
- uint8_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, uint8_t *attr, int attr_len)
-{
- struct abis_om_hdr *oh;
- struct msgb *msg = nm_msgb_alloc();
- uint8_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);
-}
-
-int abis_nm_update_max_power_red(struct gsm_bts_trx *trx)
-{
- uint8_t attr[] = { NM_ATT_RF_MAXPOWR_R, trx->max_power_red / 2 };
- return abis_nm_set_radio_attr(trx, attr, ARRAY_SIZE(attr));
-}
-
-static int verify_chan_comb(struct gsm_bts_trx_ts *ts, uint8_t chan_comb,
- const char **reason)
-{
- int i;
-
- *reason = "Reason unknown";
-
- /* 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:
- case NM_CHANC_OSMO_TCHFull_TCHHalf_PDCH:
- /* not supported */
- *reason = "TCH/H is 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) {
- *reason = "Only one SDCCH/8 per TRX allowed.";
- return -EINVAL;
- }
- }
- /* not allowed for TS0 of BCCH-TRX */
- if (ts->trx == ts->trx->bts->c0 &&
- ts->nr == 0) {
- *reason = "SDCCH/8 must be on TS0.";
- 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)) {
- *reason = "SDCCH/8 and BCCH must be on the same TRX.";
- 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) {
- *reason = "Main BCCH must be on TS0.";
- return -EINVAL;
- }
- break;
- case NM_CHANC_BCCH:
- /* allowed only for TS 2/4/6 of C0 */
- if (ts->trx != ts->trx->bts->c0) {
- *reason = "BCCH must be on C0.";
- return -EINVAL;
- }
- if (ts->nr != 2 && ts->nr != 4 && ts->nr != 6) {
- *reason = "BCCH must be on TS 2/4/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:
- *reason = "TS0 of TRX0 must carry a BCCH.";
- return -EINVAL;
- }
- } else {
- switch (chan_comb) {
- case NM_CHANC_TCHFull:
- case NM_CHANC_TCHHalf:
- case NM_CHANC_IPAC_TCHFull_TCHHalf:
- return 0;
- default:
- *reason = "TS0 must carry a TCH/F or TCH/H.";
- 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;
- *reason = "TS0 must be the main BCCH for CBCH.";
- 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:
- case NM_CHANC_OSMO_TCHFull_TCHHalf_PDCH:
- return 0;
- default:
- *reason = "TS1 must carry a CBCH, SDCCH or TCH.";
- return -EINVAL;
- }
- } 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:
- *reason = "TS1 must carry a SDCCH or TCH.";
- 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:
- case NM_CHANC_OSMO_TCHFull_TCHHalf_PDCH:
- if (ts->trx->nr == 0)
- return 0;
- else {
- *reason = "PDCH must be on TRX0.";
- return -EINVAL;
- }
- }
- break;
- }
- *reason = "Unknown combination";
- return -EINVAL;
- case GSM_BTS_TYPE_OSMOBTS:
- /* no known restrictions */
- return 0;
- default:
- /* unknown BTS type */
- return 0;
- }
- return 0;
-}
-
-/* Chapter 8.6.3 */
-int abis_nm_set_channel_attr(struct gsm_bts_trx_ts *ts, uint8_t chan_comb)
-{
- struct gsm_bts *bts = ts->trx->bts;
- struct abis_om_hdr *oh;
- uint8_t zero = 0x00;
- struct msgb *msg = nm_msgb_alloc();
- uint8_t len = 2 + 2;
- const char *reason = NULL;
-
- 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, &reason) < 0) {
- msgb_free(msg);
- LOGP(DNM, LOGL_ERROR,
- "Invalid Channel Combination %d on %s. Reason: %s\n",
- chan_comb, gsm_ts_name(ts), reason);
- 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, gsm_ts_tsc(ts)); /* 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, uint8_t obj_class, uint8_t i1,
- uint8_t i2, uint8_t i3, int nack, uint8_t *attr, int att_len)
-{
- struct abis_om_hdr *oh;
- struct msgb *msg = nm_msgb_alloc();
- uint8_t msgtype = NM_MT_SW_ACT_REQ_ACK;
- uint8_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) {
- uint8_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, uint8_t *rawmsg)
-{
- struct msgb *msg = nm_msgb_alloc();
- struct abis_om_hdr *oh;
- uint8_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, uint8_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, uint8_t obj_class, uint8_t i0, uint8_t i1, uint8_t i2)
-{
- struct abis_om_hdr *oh;
- struct abis_om_fom_hdr *foh;
- struct msgb *msg = nm_msgb_alloc();
-
- oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
- foh = fill_om_fom_hdr(oh, 0, NM_MT_OPSTART, obj_class, i0, i1, i2);
-
- abis_nm_debugp_foh(DNM, foh);
- 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, uint8_t obj_class, uint8_t i0,
- uint8_t i1, uint8_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, uint8_t e1_port0, uint8_t ts0,
- uint8_t e1_port1, uint8_t ts1)
-{
- struct abis_om_hdr *oh;
- struct msgb *msg = nm_msgb_alloc();
- uint8_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, uint8_t obj_class,
- uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr,
- uint8_t test_nr, uint8_t auton_report, struct msgb *msg)
-{
- struct abis_om_hdr *oh;
-
- DEBUGP(DNM, "PEFORM TEST %s\n", abis_nm_test_name(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 {
- uint16_t year;
- uint8_t month;
- uint8_t day;
- uint8_t hour;
- uint8_t min;
- uint8_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, uint8_t idx,
- uint8_t attr_len, const uint8_t *attr)
-{
- struct abis_om_hdr *oh;
- struct msgb *msg = nm_msgb_alloc();
- uint8_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, uint8_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, uint8_t idx)
-{
- struct abis_om_hdr *oh;
- struct msgb *msg = nm_msgb_alloc();
- uint8_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, uint8_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, uint8_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 uint8_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, uint8_t e1_port,
- uint8_t e1_timeslot, uint8_t e1_subslot,
- uint8_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, uint8_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();
- uint8_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();
- uint8_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();
- uint8_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 uint8_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, uint8_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) {
- uint8_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), (uint8_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), (uint8_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 uint8_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;
- uint8_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;
- uint8_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];
- uint8_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 */
- osmo_strlcpy(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,
- uint8_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;
-
- osmo_strlcpy(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 uint8_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 uint8_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 uint8_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), (uint8_t *) &aet);
-
- return abis_nm_sendmsg(bts, msg);
-}
-
-int abis_nm_bs11_get_bport_line_cfg(struct gsm_bts *bts, uint8_t bport)
-{
- struct abis_om_hdr *oh;
- struct msgb *msg = nm_msgb_alloc();
- uint8_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, uint8_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;
- uint8_t idstrlen = oh->data[0];
- struct tlv_parsed tp;
- struct ipacc_ack_signal_data signal;
- struct e1inp_sign_link *sign_link = msg->dst;
-
- 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, sign_link->trx->bts, foh->data, oh->length-sizeof(*foh));
-
- abis_nm_debugp_foh(DNM, 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(*((uint16_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))
- LOGPC(DNM, LOGL_ERROR, " CAUSE=%s\n",
- abis_nm_nack_cause_name(*TLVP_VAL(&tp, NM_ATT_NACK_CAUSES)));
- else
- LOGPC(DNM, LOGL_ERROR, "\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",
- abis_nm_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",
- abis_nm_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",
- abis_nm_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(sign_link->trx->bts, foh->obj_inst.trx_nr);
- signal.msg_type = foh->msg_type;
- osmo_signal_dispatch(SS_NM, S_NM_IPACC_NACK, &signal);
- break;
- case NM_MT_IPACC_SET_NVATTR_ACK:
- signal.trx = gsm_bts_trx_by_nr(sign_link->trx->bts, foh->obj_inst.trx_nr);
- signal.msg_type = foh->msg_type;
- osmo_signal_dispatch(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, uint8_t msg_type,
- uint8_t obj_class, uint8_t bts_nr,
- uint8_t trx_nr, uint8_t ts_nr,
- uint8_t *attr, int attr_len)
-{
- struct msgb *msg = nm_msgb_alloc();
- struct abis_om_hdr *oh;
- struct abis_om_fom_hdr *foh;
- uint8_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, uint8_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,
- uint32_t ip, uint16_t port, uint8_t stream)
-{
- struct in_addr ia;
- uint8_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;
- *(uint32_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_direct(trx->bts, msg);
-}
-
-int abis_nm_ipaccess_set_attr(struct gsm_bts *bts, uint8_t obj_class,
- uint8_t bts_nr, uint8_t trx_nr, uint8_t ts_nr,
- uint8_t *attr, uint8_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(uint8_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);
- *((uint16_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->mo.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(uint8_t res)
-{
- return get_value_string(ipacc_testres_names, res);
-}
-
-void ipac_parse_cgi(struct cell_global_id *cid, const uint8_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(*((uint16_t *)&buf[3]));
- cid->ci = ntohs(*((uint16_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, uint8_t *buf)
-{
- uint8_t *cur = buf;
- uint16_t len __attribute__((unused));
-
- memset(binf, 0, sizeof(*binf));
-
- if (cur[0] != NM_IPAC_EIE_BCCH_INFO)
- return -EINVAL;
- cur++;
-
- len = ntohs(*(uint16_t *)cur);
- cur += 2;
-
- binf->info_type = ntohs(*(uint16_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(*(uint16_t *)cur);
- cur += 2;
-
- if (binf->info_type & IPAC_BINF_FRAME_OFFSET)
- binf->frame_offset = ntohs(*(uint16_t *)cur);
- cur += 2;
-
- if (binf->info_type & IPAC_BINF_FRAME_NR_OFFSET)
- binf->frame_nr_offset = ntohl(*(uint32_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/src/libbsc/abis_nm_ipaccess.c b/src/libbsc/abis_nm_ipaccess.c
deleted file mode 100644
index b8225383..00000000
--- a/src/libbsc/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, uint8_t ie,
- uint16_t *arfcns, int arfcn_count)
-{
- int i;
- uint8_t *u8;
- uint16_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/src/libbsc/abis_nm_vty.c b/src/libbsc/abis_nm_vty.c
deleted file mode 100644
index 6ec0a4a2..00000000
--- a/src/libbsc/abis_nm_vty.c
+++ /dev/null
@@ -1,191 +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 <osmocom/gsm/abis_nm.h>
-
-#include <openbsc/gsm_data.h>
-#include <osmocom/core/msgb.h>
-#include <osmocom/gsm/tlv.h>
-#include <osmocom/core/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 "Site Manager Object\n" \
- "BTS Object\n" \
- "Radio Carrier Object\n" \
- "Baseband Transceiver Object\n" \
- "Channel (Timeslot) Object\n" \
- "Adjacent Object (Siemens)\n" \
- "Handover Object (Siemens)\n" \
- "Power Control Object (Siemens)\n" \
- "BTSE Object (Siemens)\n" \
- "Rack Object (Siemens)\n" \
- "Test Object (Siemens)\n" \
- "ENVABTSE Object (Siemens)\n" \
- "BPORT Object (Siemens)\n" \
- "GPRS NSE Object (ip.access/osmo-bts)\n" \
- "GPRS Cell Object (ip.acecss/osmo-bts)\n" \
- "GPRS NSVC Object (ip.acecss/osmo-bts)\n" \
- "SIEMENSHW Object (Siemens)\n"
-
-
-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(gsmnet_from_vty(vty), 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(gsmnet_from_vty(vty), 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_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);
-
- vty_install_default(OML_NODE);
- install_element(OML_NODE, &oml_chg_adm_state_cmd);
- install_element(OML_NODE, &oml_opstart_cmd);
-
- return 0;
-}
diff --git a/src/libbsc/abis_om2000.c b/src/libbsc/abis_om2000.c
deleted file mode 100644
index 82a14b26..00000000
--- a/src/libbsc/abis_om2000.c
+++ /dev/null
@@ -1,2776 +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,2016 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 <osmocom/core/msgb.h>
-#include <osmocom/gsm/tlv.h>
-#include <osmocom/core/talloc.h>
-#include <osmocom/core/utils.h>
-#include <osmocom/core/fsm.h>
-
-#include <openbsc/gsm_data.h>
-#include <openbsc/debug.h>
-#include <openbsc/abis_nm.h>
-#include <openbsc/abis_rsl.h>
-#include <openbsc/abis_om2000.h>
-#include <openbsc/signal.h>
-#include <osmocom/abis/e1_input.h>
-
-/* FIXME: move to libosmocore */
-struct osmo_fsm_inst *osmo_fsm_inst_alloc_child_id(struct osmo_fsm *fsm,
- struct osmo_fsm_inst *parent,
- uint32_t parent_term_event,
- const char *id)
-{
- struct osmo_fsm_inst *fi;
-
- fi = osmo_fsm_inst_alloc(fsm, parent, NULL, parent->log_level,
- id ? id : parent->id);
- if (!fi) {
- /* indicate immediate termination to caller */
- osmo_fsm_inst_dispatch(parent, parent_term_event, NULL);
- return NULL;
- }
-
- LOGPFSM(fi, "is child of %s\n", osmo_fsm_inst_name(parent));
-
- fi->proc.parent = parent;
- fi->proc.parent_term_event = parent_term_event;
- llist_add(&fi->proc.child, &parent->proc.children);
-
- return fi;
-}
-
-
-#define OM_ALLOC_SIZE 1024
-#define OM_HEADROOM_SIZE 128
-
-#define OM2K_TIMEOUT 10
-#define TRX_FSM_TIMEOUT 60
-#define BTS_FSM_TIMEOUT 60
-
-/* 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_RX_CONF_REQ = 0x007c,
- OM2K_MSGT_RX_CONF_REQ_ACK = 0x007e,
- OM2K_MSGT_RX_CONF_REQ_REJ = 0x007f,
- OM2K_MSGT_RX_CONF_RES_ACK = 0x0080,
- OM2K_MSGT_RX_CONF_RES_NACK = 0x0081,
- OM2K_MSGT_RX_CONF_RES = 0x0082,
- 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_TF_CONF_REQ = 0x00a0,
- OM2K_MSGT_TF_CONF_REQ_ACK = 0x00a2,
- OM2K_MSGT_TF_CONF_REQ_REJ = 0x00a3,
- OM2K_MSGT_TF_CONF_RES_ACK = 0x00a4,
- OM2K_MSGT_TF_CONF_RES_NACK = 0x00a5,
- OM2K_MSGT_TF_CONF_RES = 0x00a6,
- OM2K_MSGT_TS_CONF_REQ = 0x00a8,
- OM2K_MSGT_TS_CONF_REQ_ACK = 0x00aa,
- OM2K_MSGT_TS_CONF_REQ_REJ = 0x00ab,
- OM2K_MSGT_TS_CONF_RES_ACK = 0x00ac,
- OM2K_MSGT_TS_CONF_RES_NACK = 0x00ad,
- OM2K_MSGT_TS_CONF_RES = 0x00ae,
- OM2K_MSGT_TX_CONF_REQ = 0x00b0,
- OM2K_MSGT_TX_CONF_REQ_ACK = 0x00b2,
- OM2K_MSGT_TX_CONF_REQ_REJ = 0x00b3,
- OM2K_MSGT_TX_CONF_RES_ACK = 0x00b4,
- OM2K_MSGT_TX_CONF_RES_NACK = 0x00b5,
- OM2K_MSGT_TX_CONF_RES = 0x00b6,
-
- OM2K_MSGT_CAPA_REQ = 0x00e8,
- OM2K_MSGT_CAPA_REQ_ACK = 0x00ea,
- OM2K_MSGT_CAPA_REQ_REJ = 0x00eb,
- OM2K_MSGT_CAPA_RES = 0x00ee,
- OM2K_MSGT_CAPA_RES_ACK = 0x00ec,
- OM2K_MSGT_CAPA_RES_NACK = 0x00ed,
-
- OM2K_MSGT_NEGOT_REQ_ACK = 0x0104,
- OM2K_MSGT_NEGOT_REQ_NACK = 0x0105,
- OM2K_MSGT_NEGOT_REQ = 0x0106,
-};
-
-enum abis_om2k_dei {
- OM2K_DEI_ACCORDANCE_IND = 0x00,
- OM2K_DEI_BCC = 0x06,
- OM2K_DEI_BS_AG_BKS_RES = 0x07,
- OM2K_DEI_BSIC = 0x09,
- OM2K_DEI_BA_PA_MFRMS = 0x0a,
- OM2K_DEI_CBCH_INDICATOR = 0x0b,
- OM2K_DEI_CCCH_OPTIONS = 0x0c,
- OM2K_DEI_CAL_TIME = 0x0d,
- OM2K_DEI_COMBINATION = 0x0f,
- OM2K_DEI_CON_CONN_LIST = 0x10,
- OM2K_DEI_DRX_DEV_MAX = 0x12,
- OM2K_DEI_END_LIST_NR = 0x13,
- OM2K_DEI_EXT_COND_MAP_1 = 0x14,
- OM2K_DEI_EXT_COND_MAP_2 = 0x15,
- OM2K_DEI_FILLING_MARKER = 0x1c,
- OM2K_DEI_FN_OFFSET = 0x1d,
- OM2K_DEI_FREQ_LIST = 0x1e,
- OM2K_DEI_FREQ_SPEC_RX = 0x1f,
- OM2K_DEI_FREQ_SPEC_TX = 0x20,
- OM2K_DEI_HSN = 0x21,
- OM2K_DEI_ICM_INDICATOR = 0x22,
- OM2K_DEI_INT_FAULT_MAP_1A = 0x23,
- OM2K_DEI_INT_FAULT_MAP_1B = 0x24,
- OM2K_DEI_INT_FAULT_MAP_2A = 0x25,
- OM2K_DEI_INT_FAULT_MAP_2A_EXT = 0x26,
- OM2K_DEI_IS_CONN_LIST = 0x27,
- OM2K_DEI_LIST_NR = 0x28,
- OM2K_DEI_LOCAL_ACCESS = 0x2a,
- OM2K_DEI_MAIO = 0x2b,
- OM2K_DEI_MO_STATE = 0x2c,
- OM2K_DEI_NY1 = 0x2d,
- OM2K_DEI_OP_INFO = 0x2e,
- OM2K_DEI_POWER = 0x2f,
- OM2K_DEI_REASON_CODE = 0x32,
- OM2K_DEI_RX_DIVERSITY = 0x33,
- OM2K_DEI_REPL_UNIT_MAP = 0x34,
- OM2K_DEI_RESULT_CODE = 0x35,
- OM2K_DEI_T3105 = 0x38,
- OM2K_DEI_TF_MODE = 0x3a,
- OM2K_DEI_TS_NR = 0x3c,
- OM2K_DEI_TSC = 0x3d,
- OM2K_DEI_BTS_VERSION = 0x40,
- OM2K_DEI_OML_IWD_VERSION = 0x41,
- OM2K_DEI_RSL_IWD_VERSION = 0x42,
- OM2K_DEI_OML_FUNC_MAP_1 = 0x43,
- OM2K_DEI_OML_FUNC_MAP_2 = 0x44,
- OM2K_DEI_RSL_FUNC_MAP_1 = 0x45,
- OM2K_DEI_RSL_FUNC_MAP_2 = 0x46,
- OM2K_DEI_EXT_RANGE = 0x47,
- OM2K_DEI_REQ_IND = 0x48,
- OM2K_DEI_REPL_UNIT_MAP_EXT = 0x50,
- OM2K_DEI_ICM_BOUND_PARAMS = 0x74,
- OM2K_DEI_LSC = 0x79,
- OM2K_DEI_LSC_FILT_TIME = 0x7a,
- OM2K_DEI_CALL_SUPV_TIME = 0x7b,
- OM2K_DEI_ICM_CHAN_RATE = 0x7e,
- OM2K_DEI_HW_INFO_SIG = 0x84,
- OM2K_DEI_TF_SYNC_SRC = 0x86,
- OM2K_DEI_TTA = 0x87,
- OM2K_DEI_CAPA_SIG = 0x8a,
- OM2K_DEI_NEGOT_REC1 = 0x90,
- OM2K_DEI_NEGOT_REC2 = 0x91,
- OM2K_DEI_ENCR_ALG = 0x92,
- OM2K_DEI_INTERF_REJ_COMB = 0x94,
- OM2K_DEI_FS_OFFSET = 0x98,
- OM2K_DEI_EXT_COND_MAP_2_EXT = 0x9c,
- OM2K_DEI_TSS_MO_STATE = 0x9d,
-};
-
-const struct tlv_definition om2k_att_tlvdef = {
- .def = {
- [OM2K_DEI_ACCORDANCE_IND] = { TLV_TYPE_TV },
- [OM2K_DEI_BCC] = { TLV_TYPE_TV },
- [OM2K_DEI_BS_AG_BKS_RES] = { TLV_TYPE_TV },
- [OM2K_DEI_BSIC] = { TLV_TYPE_TV },
- [OM2K_DEI_BA_PA_MFRMS] = { TLV_TYPE_TV },
- [OM2K_DEI_CBCH_INDICATOR] = { TLV_TYPE_TV },
- [OM2K_DEI_INT_FAULT_MAP_1A] = { TLV_TYPE_FIXED, 6 },
- [OM2K_DEI_INT_FAULT_MAP_1B] = { TLV_TYPE_FIXED, 6 },
- [OM2K_DEI_INT_FAULT_MAP_2A] = { TLV_TYPE_FIXED, 6 },
- [OM2K_DEI_INT_FAULT_MAP_2A_EXT]={ TLV_TYPE_FIXED, 6 },
- [OM2K_DEI_CCCH_OPTIONS] = { TLV_TYPE_TV },
- [OM2K_DEI_CAL_TIME] = { TLV_TYPE_FIXED, 6 },
- [OM2K_DEI_COMBINATION] = { TLV_TYPE_TV },
- [OM2K_DEI_CON_CONN_LIST] = { TLV_TYPE_TLV },
- [OM2K_DEI_DRX_DEV_MAX] = { TLV_TYPE_TV },
- [OM2K_DEI_END_LIST_NR] = { TLV_TYPE_TV },
- [OM2K_DEI_EXT_COND_MAP_1] = { TLV_TYPE_FIXED, 2 },
- [OM2K_DEI_EXT_COND_MAP_2] = { TLV_TYPE_FIXED, 2 },
- [OM2K_DEI_FILLING_MARKER] = { TLV_TYPE_TV },
- [OM2K_DEI_FN_OFFSET] = { TLV_TYPE_FIXED, 2 },
- [OM2K_DEI_FREQ_LIST] = { TLV_TYPE_TLV },
- [OM2K_DEI_FREQ_SPEC_RX] = { TLV_TYPE_FIXED, 2 },
- [OM2K_DEI_FREQ_SPEC_TX] = { TLV_TYPE_FIXED, 2 },
- [OM2K_DEI_HSN] = { TLV_TYPE_TV },
- [OM2K_DEI_ICM_INDICATOR] = { TLV_TYPE_TV },
- [OM2K_DEI_IS_CONN_LIST] = { TLV_TYPE_TLV },
- [OM2K_DEI_LIST_NR] = { TLV_TYPE_TV },
- [OM2K_DEI_LOCAL_ACCESS] = { TLV_TYPE_TV },
- [OM2K_DEI_MAIO] = { TLV_TYPE_TV },
- [OM2K_DEI_MO_STATE] = { TLV_TYPE_TV },
- [OM2K_DEI_NY1] = { TLV_TYPE_TV },
- [OM2K_DEI_OP_INFO] = { TLV_TYPE_TV },
- [OM2K_DEI_POWER] = { TLV_TYPE_TV },
- [OM2K_DEI_REASON_CODE] = { TLV_TYPE_TV },
- [OM2K_DEI_RX_DIVERSITY] = { TLV_TYPE_TV },
- [OM2K_DEI_RESULT_CODE] = { TLV_TYPE_TV },
- [OM2K_DEI_T3105] = { TLV_TYPE_TV },
- [OM2K_DEI_TF_MODE] = { TLV_TYPE_TV },
- [OM2K_DEI_TS_NR] = { TLV_TYPE_TV },
- [OM2K_DEI_TSC] = { TLV_TYPE_TV },
- [OM2K_DEI_BTS_VERSION] = { TLV_TYPE_FIXED, 12 },
- [OM2K_DEI_OML_IWD_VERSION] = { TLV_TYPE_FIXED, 6 },
- [OM2K_DEI_RSL_IWD_VERSION] = { TLV_TYPE_FIXED, 6 },
- [OM2K_DEI_OML_FUNC_MAP_1] = { TLV_TYPE_TLV },
- [OM2K_DEI_OML_FUNC_MAP_2] = { TLV_TYPE_TLV },
- [OM2K_DEI_RSL_FUNC_MAP_1] = { TLV_TYPE_TLV },
- [OM2K_DEI_RSL_FUNC_MAP_2] = { TLV_TYPE_TLV },
- [OM2K_DEI_EXT_RANGE] = { TLV_TYPE_TV },
- [OM2K_DEI_REQ_IND] = { TLV_TYPE_TV },
- [OM2K_DEI_REPL_UNIT_MAP] = { TLV_TYPE_FIXED, 6 },
- [OM2K_DEI_REPL_UNIT_MAP_EXT] = {TLV_TYPE_FIXED, 6},
- [OM2K_DEI_ICM_BOUND_PARAMS] = { TLV_TYPE_FIXED, 5 },
- [OM2K_DEI_LSC] = { TLV_TYPE_TV },
- [OM2K_DEI_LSC_FILT_TIME] = { TLV_TYPE_TV },
- [OM2K_DEI_CALL_SUPV_TIME] = { TLV_TYPE_TV },
- [OM2K_DEI_ICM_CHAN_RATE] = { TLV_TYPE_TV },
- [OM2K_DEI_HW_INFO_SIG] = { TLV_TYPE_FIXED, 2 },
- [OM2K_DEI_TF_SYNC_SRC] = { TLV_TYPE_TV },
- [OM2K_DEI_TTA] = { TLV_TYPE_TV },
- [OM2K_DEI_CAPA_SIG] = { TLV_TYPE_FIXED, 2 },
- [OM2K_DEI_NEGOT_REC1] = { TLV_TYPE_TLV },
- [OM2K_DEI_NEGOT_REC2] = { TLV_TYPE_TLV },
- [OM2K_DEI_ENCR_ALG] = { TLV_TYPE_TV },
- [OM2K_DEI_INTERF_REJ_COMB] = { TLV_TYPE_TV },
- [OM2K_DEI_FS_OFFSET] = { TLV_TYPE_FIXED, 5 },
- [OM2K_DEI_EXT_COND_MAP_2_EXT] = { TLV_TYPE_FIXED, 4 },
- [OM2K_DEI_TSS_MO_STATE] = { TLV_TYPE_FIXED, 4 },
- },
-};
-
-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 Reject" },
- { 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 }
-};
-
-const struct value_string om2k_result_strings[] = {
- { 0x02, "Wrong state or out of sequence" },
- { 0x03, "File error" },
- { 0x04, "Fault, unspecified" },
- { 0x05, "Tuning fault" },
- { 0x06, "Protocol error" },
- { 0x07, "MO not connected" },
- { 0x08, "Parameter error" },
- { 0x09, "Optional function not supported" },
- { 0x0a, "Local access state LOCALLY DISCONNECTED" },
- { 0, NULL }
-};
-
-const struct value_string om2k_accordance_strings[] = {
- { 0x00, "Data according to request" },
- { 0x01, "Data not according to request" },
- { 0x02, "Inconsistent MO data" },
- { 0x03, "Capability constraint violation" },
- { 0, NULL }
-};
-
-const struct value_string om2k_mostate_vals[] = {
- { 0x00, "RESET" },
- { 0x01, "STARTED" },
- { 0x02, "ENABLED" },
- { 0x03, "DISABLED" },
- { 0, NULL }
-};
-
-/* entire decoded OM2K message (header + parsed TLV) */
-struct om2k_decoded_msg {
- struct abis_om2k_hdr o2h;
- uint16_t msg_type;
- struct tlv_parsed tp;
-};
-
-/* resolve the OM2000 Managed Object by BTS + MO Address */
-static struct om2k_mo *
-get_om2k_mo(struct gsm_bts *bts, const struct abis_om2k_mo *abis_mo)
-{
- struct om2k_mo *mo = NULL;
- struct gsm_bts_trx *trx;
-
- switch (abis_mo->class) {
- case OM2K_MO_CLS_CF:
- mo = &bts->rbs2000.cf.om2k_mo;
- break;
- case OM2K_MO_CLS_CON:
- mo = &bts->rbs2000.con.om2k_mo;
- break;
- case OM2K_MO_CLS_IS:
- mo = &bts->rbs2000.is.om2k_mo;
- break;
- case OM2K_MO_CLS_TF:
- mo = &bts->rbs2000.tf.om2k_mo;
- break;
-
- case OM2K_MO_CLS_TRXC:
- trx = gsm_bts_trx_num(bts, abis_mo->inst);
- if (!trx)
- return NULL;
- mo = &trx->rbs2000.trxc.om2k_mo;
- break;
- case OM2K_MO_CLS_TX:
- trx = gsm_bts_trx_num(bts, abis_mo->inst);
- if (!trx)
- return NULL;
- mo = &trx->rbs2000.tx.om2k_mo;
- break;
- case OM2K_MO_CLS_RX:
- trx = gsm_bts_trx_num(bts, abis_mo->inst);
- if (!trx)
- return NULL;
- mo = &trx->rbs2000.rx.om2k_mo;
- break;
- case OM2K_MO_CLS_TS:
- trx = gsm_bts_trx_num(bts, abis_mo->assoc_so);
- if (!trx)
- return NULL;
- if (abis_mo->inst >= ARRAY_SIZE(trx->ts))
- return NULL;
- mo = &trx->ts[abis_mo->inst].rbs2000.om2k_mo;
- break;
- default:
- return NULL;
- };
-
- return mo;
-}
-
-static struct msgb *om2k_msgb_alloc(void)
-{
- return msgb_alloc_headroom(OM_ALLOC_SIZE, OM_HEADROOM_SIZE,
- "OM2000");
-}
-
-static int abis_om2k_tlv_parse(struct tlv_parsed *tp, const uint8_t *buf, int len)
-{
- return tlv_parse(tp, &om2k_att_tlvdef, buf, len, 0, 0);
-}
-
-static int abis_om2k_msg_tlv_parse(struct tlv_parsed *tp, struct abis_om2k_hdr *oh)
-{
- return abis_om2k_tlv_parse(tp, oh->data, oh->om.length - 6);
-}
-
-/* decode/parse the message */
-static int om2k_decode_msg(struct om2k_decoded_msg *odm, struct msgb *msg)
-{
- struct abis_om2k_hdr *o2h = msgb_l2(msg);
- odm->msg_type = ntohs(o2h->msg_type);
- odm->o2h = *o2h;
- return abis_om2k_msg_tlv_parse(&odm->tp, o2h);
-}
-
-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;
-}
-
-/* resolve the gsm_nm_state data structure for a given MO */
-static struct gsm_nm_state *
-mo2nm_state(struct gsm_bts *bts, const struct abis_om2k_mo *mo)
-{
- struct gsm_bts_trx *trx;
- struct gsm_nm_state *nm_state = NULL;
-
- switch (mo->class) {
- case OM2K_MO_CLS_TRXC:
- trx = gsm_bts_trx_num(bts, mo->inst);
- if (!trx)
- return NULL;
- nm_state = &trx->mo.nm_state;
- break;
- case OM2K_MO_CLS_TS:
- trx = gsm_bts_trx_num(bts, mo->assoc_so);
- if (!trx)
- return NULL;
- if (mo->inst >= ARRAY_SIZE(trx->ts))
- return NULL;
- nm_state = &trx->ts[mo->inst].mo.nm_state;
- break;
- case OM2K_MO_CLS_TF:
- nm_state = &bts->rbs2000.tf.mo.nm_state;
- break;
- case OM2K_MO_CLS_IS:
- nm_state = &bts->rbs2000.is.mo.nm_state;
- break;
- case OM2K_MO_CLS_CON:
- nm_state = &bts->rbs2000.con.mo.nm_state;
- break;
- case OM2K_MO_CLS_DP:
- nm_state = &bts->rbs2000.con.mo.nm_state;
- break;
- case OM2K_MO_CLS_CF:
- nm_state = &bts->mo.nm_state;
- break;
- case OM2K_MO_CLS_TX:
- trx = gsm_bts_trx_num(bts, mo->inst);
- if (!trx)
- return NULL;
- /* FIXME */
- break;
- case OM2K_MO_CLS_RX:
- trx = gsm_bts_trx_num(bts, mo->inst);
- if (!trx)
- return NULL;
- /* FIXME */
- break;
- }
-
- return nm_state;
-}
-
-static void *mo2obj(struct gsm_bts *bts, struct abis_om2k_mo *mo)
-{
- struct gsm_bts_trx *trx;
-
- switch (mo->class) {
- case OM2K_MO_CLS_TX:
- case OM2K_MO_CLS_RX:
- case OM2K_MO_CLS_TRXC:
- return gsm_bts_trx_num(bts, mo->inst);
- case OM2K_MO_CLS_TS:
- trx = gsm_bts_trx_num(bts, mo->assoc_so);
- if (!trx)
- return NULL;
- if (mo->inst >= ARRAY_SIZE(trx->ts))
- return NULL;
- return &trx->ts[mo->inst];
- case OM2K_MO_CLS_TF:
- case OM2K_MO_CLS_IS:
- case OM2K_MO_CLS_CON:
- case OM2K_MO_CLS_DP:
- case OM2K_MO_CLS_CF:
- return bts;
- }
-
- return NULL;
-}
-
-static void update_mo_state(struct gsm_bts *bts, struct abis_om2k_mo *mo,
- uint8_t mo_state)
-{
- struct gsm_nm_state *nm_state = mo2nm_state(bts, mo);
- struct gsm_nm_state new_state;
- struct nm_statechg_signal_data nsd;
-
- if (!nm_state)
- return;
-
- new_state = *nm_state;
- /* NOTICE: 12.21 Availability state values != OM2000 */
- new_state.availability = mo_state;
-
- memset(&nsd, 0, sizeof(nsd));
-
- nsd.bts = bts;
- nsd.obj = mo2obj(bts, mo);
- nsd.old_state = nm_state;
- nsd.new_state = &new_state;
- nsd.om2k_mo = mo;
-
- osmo_signal_dispatch(SS_NM, S_NM_STATECHG_ADM, &nsd);
-
- nm_state->availability = new_state.availability;
-}
-
-static void update_op_state(struct gsm_bts *bts, const struct abis_om2k_mo *mo,
- uint8_t op_state)
-{
- struct gsm_nm_state *nm_state = mo2nm_state(bts, mo);
- struct gsm_nm_state new_state;
-
- if (!nm_state)
- return;
-
- new_state = *nm_state;
- switch (op_state) {
- case 1:
- new_state.operational = NM_OPSTATE_ENABLED;
- break;
- case 0:
- new_state.operational = NM_OPSTATE_DISABLED;
- break;
- default:
- new_state.operational = NM_OPSTATE_NULL;
- break;
- }
-
- nm_state->operational = new_state.operational;
-}
-
-static int abis_om2k_sendmsg(struct gsm_bts *bts, struct msgb *msg)
-{
- struct abis_om2k_hdr *o2h;
- struct gsm_bts_trx *trx;
-
- msg->l2h = msg->data;
- o2h = (struct abis_om2k_hdr *) msg->l2h;
-
- /* Compute the length in the OML header */
- o2h->om.length = 6 + msgb_l2len(msg)-sizeof(*o2h);
-
- switch (o2h->mo.class) {
- case OM2K_MO_CLS_TRXC:
- case OM2K_MO_CLS_TX:
- case OM2K_MO_CLS_RX:
- /* Route through per-TRX OML Link to the appropriate TRX */
- trx = gsm_bts_trx_by_nr(bts, o2h->mo.inst);
- if (!trx) {
- LOGP(DNM, LOGL_ERROR, "MO=%s Tx Dropping msg to "
- "non-existing TRX\n", om2k_mo_name(&o2h->mo));
- return -ENODEV;
- }
- msg->dst = trx->oml_link;
- break;
- case OM2K_MO_CLS_TS:
- /* Route through per-TRX OML Link to the appropriate TRX */
- trx = gsm_bts_trx_by_nr(bts, o2h->mo.assoc_so);
- if (!trx) {
- LOGP(DNM, LOGL_ERROR, "MO=%s Tx Dropping msg to "
- "non-existing TRX\n", om2k_mo_name(&o2h->mo));
- return -ENODEV;
- }
- msg->dst = trx->oml_link;
- break;
- default:
- /* Route through the IXU/DXU OML Link */
- msg->dst = bts->oml_link;
- break;
- }
-
- return _abis_nm_sendmsg(msg);
-}
-
-static void fill_om2k_hdr(struct abis_om2k_hdr *o2h, const struct abis_om2k_mo *mo,
- uint16_t msg_type)
-{
- o2h->om.mdisc = ABIS_OM_MDISC_FOM;
- o2h->om.placement = ABIS_OM_PLACEMENT_ONLY;
- o2h->om.sequence = 0;
- /* We fill o2h->om.length later during om2k_sendmsg() */
- o2h->msg_type = htons(msg_type);
- memcpy(&o2h->mo, mo, sizeof(o2h->mo));
-}
-
-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, &bts->rbs2000.cf.om2k_mo.addr,
- OM2K_MSGT_CAL_TIME_RESP);
-
- 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);
-
- 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);
-
- 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));
-
- /* we update the state here... and send the signal at ACK */
- update_op_state(bts, mo, operational);
-
- return abis_om2k_sendmsg(bts, msg);
-}
-
-int abis_om2k_tx_cap_req(struct gsm_bts *bts, const struct abis_om2k_mo *mo)
-{
- return abis_om2k_tx_simple(bts, mo, OM2K_MSGT_CAPA_REQ);
-}
-
-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;
-}
-
-int abis_om2k_tx_is_conf_req(struct gsm_bts *bts)
-{
- struct msgb *msg = om2k_msgb_alloc();
- struct abis_om2k_hdr *o2k;
- struct is_conn_group *grp;
- unsigned int num_grps = 0, i = 0;
- struct om2k_is_conn_grp *cg;
-
- /* count number of groups in linked list */
- llist_for_each_entry(grp, &bts->rbs2000.is.conn_groups, list)
- num_grps++;
-
- if (!num_grps)
- return -EINVAL;
-
- /* allocate buffer for oml group array */
- cg = 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(&cg[i++], grp->icp1, grp->icp2, grp->ci);
-
- o2k = (struct abis_om2k_hdr *) msgb_put(msg, sizeof(*o2k));
- fill_om2k_hdr(o2k, &bts->rbs2000.is.om2k_mo.addr,
- OM2K_MSGT_IS_CONF_REQ);
-
- 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_grps * sizeof(*cg), (uint8_t *)cg);
-
- talloc_free(cg);
-
- DEBUGP(DNM, "Tx MO=%s %s\n",
- om2k_mo_name(&bts->rbs2000.is.om2k_mo.addr),
- get_value_string(om2k_msgcode_vals, OM2K_MSGT_IS_CONF_REQ));
-
- return abis_om2k_sendmsg(bts, msg);
-}
-
-int abis_om2k_tx_con_conf_req(struct gsm_bts *bts)
-{
- struct msgb *msg = om2k_msgb_alloc();
- struct abis_om2k_hdr *o2k;
- struct con_group *grp;
- unsigned int num_grps = 0;
-
- /* count number of groups in linked list */
- llist_for_each_entry(grp, &bts->rbs2000.con.conn_groups, list)
- num_grps++;
-
- if (!num_grps)
- return -EINVAL;
-
- /* first build the value part of the OM2K_DEI_CON_CONN_LIST DEI */
- msgb_put_u8(msg, num_grps);
- llist_for_each_entry(grp, &bts->rbs2000.con.conn_groups, list) {
- struct con_path *cp;
- unsigned int num_paths = 0;
- llist_for_each_entry(cp, &grp->paths, list)
- num_paths++;
- msgb_put_u8(msg, num_paths);
- llist_for_each_entry(cp, &grp->paths, list) {
- struct om2k_con_path *om2k_cp;
- om2k_cp = (struct om2k_con_path *) msgb_put(msg, sizeof(*om2k_cp));
- om2k_cp->ccp = htons(cp->ccp);
- om2k_cp->ci = cp->ci;
- om2k_cp->tag = cp->tag;
- om2k_cp->tei = cp->tei;
- }
- }
- msgb_push_u8(msg, msgb_length(msg));
- msgb_push_u8(msg, OM2K_DEI_CON_CONN_LIST);
-
- /* pre-pend the list number DEIs */
- msgb_tv_push(msg, OM2K_DEI_END_LIST_NR, 1);
- msgb_tv_push(msg, OM2K_DEI_LIST_NR, 1);
-
- /* pre-pend the OM2K header */
- o2k = (struct abis_om2k_hdr *) msgb_push(msg, sizeof(*o2k));
- fill_om2k_hdr(o2k, &bts->rbs2000.con.om2k_mo.addr,
- OM2K_MSGT_CON_CONF_REQ);
-
- DEBUGP(DNM, "Tx MO=%s %s\n",
- om2k_mo_name(&bts->rbs2000.con.om2k_mo.addr),
- get_value_string(om2k_msgcode_vals, OM2K_MSGT_CON_CONF_REQ));
-
- return abis_om2k_sendmsg(bts, msg);
-}
-
-static void om2k_trx_to_mo(struct abis_om2k_mo *mo,
- const struct gsm_bts_trx *trx,
- enum abis_om2k_mo_cls cls)
-{
- mo->class = cls;
- mo->bts = 0;
- mo->inst = trx->nr;
- mo->assoc_so = 255;
-}
-
-static void om2k_ts_to_mo(struct abis_om2k_mo *mo,
- const struct gsm_bts_trx_ts *ts)
-{
- mo->class = OM2K_MO_CLS_TS;
- mo->bts = 0;
- mo->inst = ts->nr;
- mo->assoc_so = ts->trx->nr;
-}
-
-/* Configure a Receiver MO */
-int abis_om2k_tx_rx_conf_req(struct gsm_bts_trx *trx)
-{
- struct msgb *msg = om2k_msgb_alloc();
- struct abis_om2k_hdr *o2k;
- struct abis_om2k_mo mo;
-
- om2k_trx_to_mo(&mo, trx, OM2K_MO_CLS_RX);
-
- o2k = (struct abis_om2k_hdr *) msgb_put(msg, sizeof(*o2k));
- fill_om2k_hdr(o2k, &mo, OM2K_MSGT_RX_CONF_REQ);
-
- msgb_tv16_put(msg, OM2K_DEI_FREQ_SPEC_RX, trx->arfcn);
- msgb_tv_put(msg, OM2K_DEI_RX_DIVERSITY, 0x02); /* A */
-
- return abis_om2k_sendmsg(trx->bts, msg);
-}
-
-/* Configure a Transmitter MO */
-int abis_om2k_tx_tx_conf_req(struct gsm_bts_trx *trx)
-{
- struct msgb *msg = om2k_msgb_alloc();
- struct abis_om2k_hdr *o2k;
- struct abis_om2k_mo mo;
-
- om2k_trx_to_mo(&mo, trx, OM2K_MO_CLS_TX);
-
- o2k = (struct abis_om2k_hdr *) msgb_put(msg, sizeof(*o2k));
- fill_om2k_hdr(o2k, &mo, OM2K_MSGT_TX_CONF_REQ);
-
- msgb_tv16_put(msg, OM2K_DEI_FREQ_SPEC_TX, trx->arfcn);
- msgb_tv_put(msg, OM2K_DEI_POWER, trx->nominal_power-trx->max_power_red);
- msgb_tv_put(msg, OM2K_DEI_FILLING_MARKER, 0); /* Filling enabled */
- msgb_tv_put(msg, OM2K_DEI_BCC, trx->bts->bsic & 0x7);
- /* Dedication Information is optional */
-
- return abis_om2k_sendmsg(trx->bts, msg);
-}
-
-enum abis_om2k_tf_mode {
- OM2K_TF_MODE_MASTER = 0x00,
- OM2K_TF_MODE_STANDALONE = 0x01,
- OM2K_TF_MODE_SLAVE = 0x02,
- OM2K_TF_MODE_UNDEFINED = 0xff,
-};
-
-static const uint8_t fs_offset_undef[5] = { 0xff, 0xff, 0xff, 0xff, 0xff };
-
-int abis_om2k_tx_tf_conf_req(struct gsm_bts *bts)
-{
- 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, &bts->rbs2000.tf.om2k_mo.addr,
- OM2K_MSGT_TF_CONF_REQ);
-
- msgb_tv_put(msg, OM2K_DEI_TF_MODE, OM2K_TF_MODE_STANDALONE);
- msgb_tv_put(msg, OM2K_DEI_TF_SYNC_SRC, 0x00);
- msgb_tv_fixed_put(msg, OM2K_DEI_FS_OFFSET,
- sizeof(fs_offset_undef), fs_offset_undef);
-
- DEBUGP(DNM, "Tx MO=%s %s\n",
- om2k_mo_name(&bts->rbs2000.tf.om2k_mo.addr),
- get_value_string(om2k_msgcode_vals, OM2K_MSGT_TF_CONF_REQ));
-
- return abis_om2k_sendmsg(bts, msg);
-}
-
-static uint8_t pchan2comb(enum gsm_phys_chan_config pchan)
-{
- switch (pchan) {
- case GSM_PCHAN_CCCH:
- return 4;
- case GSM_PCHAN_CCCH_SDCCH4:
- return 5;
- case GSM_PCHAN_SDCCH8_SACCH8C:
- return 3;
- case GSM_PCHAN_TCH_F:
- case GSM_PCHAN_TCH_H:
- case GSM_PCHAN_PDCH:
- case GSM_PCHAN_TCH_F_PDCH:
- case GSM_PCHAN_TCH_F_TCH_H_PDCH:
- return 8;
- default:
- return 0;
- }
-}
-
-static uint8_t ts2comb(struct gsm_bts_trx_ts *ts)
-{
- switch (ts->pchan) {
- case GSM_PCHAN_TCH_F_PDCH:
- LOGP(DNM, LOGL_ERROR, "%s pchan %s not intended for use"
- " with OM2000, use %s instead\n",
- gsm_ts_and_pchan_name(ts),
- gsm_pchan_name(GSM_PCHAN_TCH_F_PDCH),
- gsm_pchan_name(GSM_PCHAN_TCH_F_TCH_H_PDCH));
- /* If we allowed initialization of TCH/F_PDCH, it would fail
- * when we try to send the ip.access specific RSL PDCH Act
- * message for it. Rather fail completely right now: */
- return 0;
- case GSM_PCHAN_TCH_F_TCH_H_PDCH:
- return pchan2comb(GSM_PCHAN_TCH_F);
- default:
- return pchan2comb(ts->pchan);
- }
-}
-
-static int put_freq_list(uint8_t *buf, uint16_t arfcn)
-{
- buf[0] = 0x00; /* TX/RX address */
- buf[1] = (arfcn >> 8);
- buf[2] = (arfcn & 0xff);
-
- return 3;
-}
-
-/* Compute a frequency list in OM2000 fomrmat */
-static int om2k_gen_freq_list(uint8_t *list, struct gsm_bts_trx_ts *ts)
-{
- uint8_t *cur = list;
- int len;
-
- if (ts->hopping.enabled) {
- unsigned int i;
- for (i = 0; i < ts->hopping.arfcns.data_len*8; i++) {
- if (bitvec_get_bit_pos(&ts->hopping.arfcns, i))
- cur += put_freq_list(cur, i);
- }
- } else
- cur += put_freq_list(cur, ts->trx->arfcn);
-
- len = cur - list;
-
- return len;
-}
-
-const uint8_t icm_bound_params[] = { 0x02, 0x06, 0x0c, 0x16, 0x06 };
-
-int abis_om2k_tx_ts_conf_req(struct gsm_bts_trx_ts *ts)
-{
- struct msgb *msg = om2k_msgb_alloc();
- struct abis_om2k_hdr *o2k;
- struct abis_om2k_mo mo;
- uint8_t freq_list[64*3]; /* BA max size: 64 ARFCN */
- int freq_list_len;
-
- om2k_ts_to_mo(&mo, ts);
-
- memset(freq_list, 0, sizeof(freq_list));
- freq_list_len = om2k_gen_freq_list(freq_list, ts);
- if (freq_list_len < 0)
- return freq_list_len;
-
- o2k = (struct abis_om2k_hdr *) msgb_put(msg, sizeof(*o2k));
- fill_om2k_hdr(o2k, &mo, OM2K_MSGT_TS_CONF_REQ);
-
- msgb_tv_put(msg, OM2K_DEI_COMBINATION, ts2comb(ts));
- msgb_tv_put(msg, OM2K_DEI_TS_NR, ts->nr);
- msgb_tlv_put(msg, OM2K_DEI_FREQ_LIST, freq_list_len, freq_list);
- msgb_tv_put(msg, OM2K_DEI_HSN, ts->hopping.hsn);
- msgb_tv_put(msg, OM2K_DEI_MAIO, ts->hopping.maio);
- msgb_tv_put(msg, OM2K_DEI_BSIC, ts->trx->bts->bsic);
- msgb_tv_put(msg, OM2K_DEI_RX_DIVERSITY, 0x02); /* A */
- msgb_tv16_put(msg, OM2K_DEI_FN_OFFSET, 0);
- msgb_tv_put(msg, OM2K_DEI_EXT_RANGE, 0); /* Off */
- /* Optional: Interference Rejection Combining */
- msgb_tv_put(msg, OM2K_DEI_INTERF_REJ_COMB, 0x00);
- switch (ts->pchan) {
- case GSM_PCHAN_CCCH:
- msgb_tv_put(msg, OM2K_DEI_BA_PA_MFRMS, 0x06);
- msgb_tv_put(msg, OM2K_DEI_BS_AG_BKS_RES, 0x01);
- msgb_tv_put(msg, OM2K_DEI_DRX_DEV_MAX, 0x05);
- /* Repeat Paging/IMM.ASS: True, Allow Paging Type 3: Yes, Page for 5 seconds (default) */
- msgb_tv_put(msg, OM2K_DEI_CCCH_OPTIONS, 0x01);
- break;
- case GSM_PCHAN_CCCH_SDCCH4:
- msgb_tv_put(msg, OM2K_DEI_T3105, ts->trx->bts->network->T3105 / 10);
- msgb_tv_put(msg, OM2K_DEI_NY1, 35);
- msgb_tv_put(msg, OM2K_DEI_BA_PA_MFRMS, 0x06);
- msgb_tv_put(msg, OM2K_DEI_CBCH_INDICATOR, 0);
- msgb_tv_put(msg, OM2K_DEI_TSC, gsm_ts_tsc(ts));
- msgb_tv_put(msg, OM2K_DEI_BS_AG_BKS_RES, 0x01);
- msgb_tv_put(msg, OM2K_DEI_ICM_INDICATOR, 0);
- msgb_tv_put(msg, OM2K_DEI_DRX_DEV_MAX, 0x05);
- /* Repeat Paging/IMM.ASS: True, Allow Paging Type 3: Yes, Page for 5 seconds (default) */
- msgb_tv_put(msg, OM2K_DEI_CCCH_OPTIONS, 0x01);
- msgb_tv_fixed_put(msg, OM2K_DEI_ICM_BOUND_PARAMS,
- sizeof(icm_bound_params), icm_bound_params);
- break;
- case GSM_PCHAN_SDCCH8_SACCH8C:
- msgb_tv_put(msg, OM2K_DEI_T3105, ts->trx->bts->network->T3105 / 10);
- msgb_tv_put(msg, OM2K_DEI_NY1, 35);
- msgb_tv_put(msg, OM2K_DEI_CBCH_INDICATOR, 0);
- msgb_tv_put(msg, OM2K_DEI_TSC, gsm_ts_tsc(ts));
- /* Disable RF RESOURCE INDICATION on idle channels */
- msgb_tv_put(msg, OM2K_DEI_ICM_INDICATOR, 0);
- msgb_tv_fixed_put(msg, OM2K_DEI_ICM_BOUND_PARAMS,
- sizeof(icm_bound_params), icm_bound_params);
- break;
- default:
- msgb_tv_put(msg, OM2K_DEI_T3105, ts->trx->bts->network->T3105 / 10);
- msgb_tv_put(msg, OM2K_DEI_NY1, 35);
- msgb_tv_put(msg, OM2K_DEI_TSC, gsm_ts_tsc(ts));
- /* Disable RF RESOURCE INDICATION on idle channels */
- msgb_tv_put(msg, OM2K_DEI_ICM_INDICATOR, 0);
- msgb_tv_fixed_put(msg, OM2K_DEI_ICM_BOUND_PARAMS,
- sizeof(icm_bound_params), icm_bound_params);
- msgb_tv_put(msg, OM2K_DEI_TTA, 10); /* Timer for Time Alignment */
- if (ts->pchan == GSM_PCHAN_TCH_H)
- msgb_tv_put(msg, OM2K_DEI_ICM_CHAN_RATE, 1); /* TCH/H */
- else
- msgb_tv_put(msg, OM2K_DEI_ICM_CHAN_RATE, 0); /* TCH/F */
- msgb_tv_put(msg, OM2K_DEI_LSC, 1); /* enabled */
- msgb_tv_put(msg, OM2K_DEI_LSC_FILT_TIME, 10); /* units of 100ms */
- msgb_tv_put(msg, OM2K_DEI_CALL_SUPV_TIME, 8);
- msgb_tv_put(msg, OM2K_DEI_ENCR_ALG, 0x00);
- /* Not sure what those below mean */
- msgb_tv_put(msg, 0x9e, 0x00);
- msgb_tv_put(msg, 0x9f, 0x37);
- msgb_tv_put(msg, 0xa0, 0x01);
- break;
- }
-
- DEBUGP(DNM, "Tx MO=%s %s\n",
- om2k_mo_name(&mo),
- get_value_string(om2k_msgcode_vals, OM2K_MSGT_TS_CONF_REQ));
-
- return abis_om2k_sendmsg(ts->trx->bts, msg);
-}
-
-
-/***********************************************************************
- * OM2000 Managed Object (MO) FSM
- ***********************************************************************/
-
-#define S(x) (1 << (x))
-
-enum om2k_event_name {
- OM2K_MO_EVT_START,
- OM2K_MO_EVT_RX_CONN_COMPL,
- OM2K_MO_EVT_RX_RESET_COMPL,
- OM2K_MO_EVT_RX_START_REQ_ACCEPT,
- OM2K_MO_EVT_RX_START_RES,
- OM2K_MO_EVT_RX_CFG_REQ_ACCEPT,
- OM2K_MO_EVT_RX_CFG_RES,
- OM2K_MO_EVT_RX_ENA_REQ_ACCEPT,
- OM2K_MO_EVT_RX_ENA_RES,
- OM2K_MO_EVT_RX_OPINFO_ACC,
-};
-
-static const struct value_string om2k_event_names[] = {
- { OM2K_MO_EVT_START, "START" },
- { OM2K_MO_EVT_RX_CONN_COMPL, "RX-CONN-COMPL" },
- { OM2K_MO_EVT_RX_RESET_COMPL, "RX-RESET-COMPL" },
- { OM2K_MO_EVT_RX_START_REQ_ACCEPT, "RX-RESET-REQ-ACCEPT" },
- { OM2K_MO_EVT_RX_START_RES, "RX-START-RESULT" },
- { OM2K_MO_EVT_RX_CFG_REQ_ACCEPT, "RX-CFG-REQ-ACCEPT" },
- { OM2K_MO_EVT_RX_CFG_RES, "RX-CFG-RESULT" },
- { OM2K_MO_EVT_RX_ENA_REQ_ACCEPT, "RX-ENABLE-REQ-ACCEPT" },
- { OM2K_MO_EVT_RX_ENA_RES, "RX-ENABLE-RESULT" },
- { OM2K_MO_EVT_RX_OPINFO_ACC, "RX-OPINFO-ACCEPT" },
- { 0, NULL }
-};
-
-enum om2k_mo_fsm_state {
- OM2K_ST_INIT,
- OM2K_ST_WAIT_CONN_COMPL,
- OM2K_ST_WAIT_RES_COMPL,
- OM2K_ST_WAIT_START_ACCEPT,
- OM2K_ST_WAIT_START_RES,
- OM2K_ST_WAIT_CFG_ACCEPT,
- OM2K_ST_WAIT_CFG_RES,
- OM2K_ST_WAIT_ENABLE_ACCEPT,
- OM2K_ST_WAIT_ENABLE_RES,
- OM2K_ST_WAIT_OPINFO_ACCEPT,
- OM2K_ST_DONE,
- OM2K_ST_ERROR,
-};
-
-struct om2k_mo_fsm_priv {
- struct gsm_bts_trx *trx;
- struct om2k_mo *mo;
- uint8_t ts_nr;
-};
-
-static void om2k_mo_st_init(struct osmo_fsm_inst *fi, uint32_t event, void *data)
-{
- struct om2k_mo_fsm_priv *omfp = fi->priv;
-
- OSMO_ASSERT(event == OM2K_MO_EVT_START);
-
- switch (omfp->mo->addr.class) {
- case OM2K_MO_CLS_CF:
- /* no Connect required, is always connected */
- osmo_fsm_inst_state_chg(fi, OM2K_ST_WAIT_START_ACCEPT,
- OM2K_TIMEOUT, 0);
- abis_om2k_tx_start_req(omfp->trx->bts, &omfp->mo->addr);
- break;
- case OM2K_MO_CLS_TRXC:
- /* no Connect required, start with Reset */
- osmo_fsm_inst_state_chg(fi, OM2K_ST_WAIT_RES_COMPL,
- OM2K_TIMEOUT, 0);
- abis_om2k_tx_reset_cmd(omfp->trx->bts, &omfp->mo->addr);
- break;
- default:
- /* start with Connect */
- osmo_fsm_inst_state_chg(fi, OM2K_ST_WAIT_CONN_COMPL,
- OM2K_TIMEOUT, 0);
- abis_om2k_tx_connect_cmd(omfp->trx->bts, &omfp->mo->addr);
- break;
- }
-}
-
-static void om2k_mo_st_wait_conn_compl(struct osmo_fsm_inst *fi, uint32_t event, void *data)
-{
- struct om2k_mo_fsm_priv *omfp = fi->priv;
-
- switch (omfp->mo->addr.class) {
-#if 0
- case OM2K_MO_CLS_TF:
- /* skip the reset, hope that helps */
- osmo_fsm_inst_state_chg(fi, OM2K_ST_WAIT_START_ACCEPT,
- OM2K_TIMEOUT, 0);
- abis_om2k_tx_start_req(omfp->trx->bts, &omfp->mo->addr);
- break;
-#endif
- default:
- osmo_fsm_inst_state_chg(fi, OM2K_ST_WAIT_RES_COMPL,
- OM2K_TIMEOUT, 0);
- abis_om2k_tx_reset_cmd(omfp->trx->bts, &omfp->mo->addr);
- break;
- }
-}
-
-static void om2k_mo_st_wait_res_compl(struct osmo_fsm_inst *fi, uint32_t event, void *data)
-{
- struct om2k_mo_fsm_priv *omfp = fi->priv;
-
- osmo_fsm_inst_state_chg(fi, OM2K_ST_WAIT_START_ACCEPT,
- OM2K_TIMEOUT, 0);
- abis_om2k_tx_start_req(omfp->trx->bts, &omfp->mo->addr);
-}
-
-static void om2k_mo_st_wait_start_accept(struct osmo_fsm_inst *fi, uint32_t event, void *data)
-{
- struct om2k_decoded_msg *omd = data;
-
- switch (omd->msg_type) {
- case OM2K_MSGT_START_REQ_ACK:
- osmo_fsm_inst_state_chg(fi, OM2K_ST_WAIT_START_RES,
- OM2K_TIMEOUT, 0);
- break;
- case OM2K_MSGT_START_REQ_REJ:
- osmo_fsm_inst_state_chg(fi, OM2K_ST_ERROR, 0, 0);
- break;
- }
-}
-
-static void om2k_mo_st_wait_start_res(struct osmo_fsm_inst *fi, uint32_t event, void *data)
-{
- struct om2k_mo_fsm_priv *omfp = fi->priv;
- struct gsm_bts_trx_ts *ts;
-
- switch (omfp->mo->addr.class) {
- case OM2K_MO_CLS_CF:
- case OM2K_MO_CLS_TRXC:
- /* Transition directly to Operational Info */
- osmo_fsm_inst_state_chg(fi, OM2K_ST_WAIT_OPINFO_ACCEPT,
- OM2K_TIMEOUT, 0);
- abis_om2k_tx_op_info(omfp->trx->bts, &omfp->mo->addr, 1);
- return;
- case OM2K_MO_CLS_DP:
- /* Transition directoy to WAIT_ENABLE_ACCEPT */
- osmo_fsm_inst_state_chg(fi, OM2K_ST_WAIT_ENABLE_ACCEPT,
- OM2K_TIMEOUT, 0);
- abis_om2k_tx_enable_req(omfp->trx->bts, &omfp->mo->addr);
- return;
-#if 0
- case OM2K_MO_CLS_TF:
- /* skip the config, hope that helps speeding things up */
- osmo_fsm_inst_state_chg(fi, OM2K_ST_WAIT_ENABLE_ACCEPT,
- OM2K_TIMEOUT, 0);
- abis_om2k_tx_enable_req(omfp->trx->bts, &omfp->mo->addr);
- return;
-#endif
- }
-
- osmo_fsm_inst_state_chg(fi, OM2K_ST_WAIT_CFG_ACCEPT,
- OM2K_TIMEOUT, 0);
- switch (omfp->mo->addr.class) {
- case OM2K_MO_CLS_TF:
- abis_om2k_tx_tf_conf_req(omfp->trx->bts);
- break;
- case OM2K_MO_CLS_IS:
- abis_om2k_tx_is_conf_req(omfp->trx->bts);
- break;
- case OM2K_MO_CLS_CON:
- abis_om2k_tx_con_conf_req(omfp->trx->bts);
- break;
- case OM2K_MO_CLS_TX:
- abis_om2k_tx_tx_conf_req(omfp->trx);
- break;
- case OM2K_MO_CLS_RX:
- abis_om2k_tx_rx_conf_req(omfp->trx);
- break;
- case OM2K_MO_CLS_TS:
- ts = mo2obj(omfp->trx->bts, &omfp->mo->addr);
- abis_om2k_tx_ts_conf_req(ts);
- break;
- }
-}
-
-static void om2k_mo_st_wait_cfg_accept(struct osmo_fsm_inst *fi, uint32_t event, void *data)
-{
- struct om2k_mo_fsm_priv *omfp = fi->priv;
- uint32_t timeout = OM2K_TIMEOUT;
-
- if (omfp->mo->addr.class == OM2K_MO_CLS_TF)
- timeout = 600;
-
- osmo_fsm_inst_state_chg(fi, OM2K_ST_WAIT_CFG_RES, timeout, 0);
-}
-
-static void om2k_mo_st_wait_cfg_res(struct osmo_fsm_inst *fi, uint32_t event, void *data)
-{
- struct om2k_mo_fsm_priv *omfp = fi->priv;
- struct om2k_decoded_msg *omd = data;
- uint8_t accordance;
-
- if (!TLVP_PRESENT(&omd->tp, OM2K_DEI_ACCORDANCE_IND)) {
- osmo_fsm_inst_state_chg(fi, OM2K_ST_ERROR, 0, 0);
- return;
- }
- accordance = *TLVP_VAL(&omd->tp, OM2K_DEI_ACCORDANCE_IND);
-
- if (accordance != 0) {
- /* accordance not OK */
- osmo_fsm_inst_state_chg(fi, OM2K_ST_ERROR, 0, 0);
- return;
- }
-
- osmo_fsm_inst_state_chg(fi, OM2K_ST_WAIT_ENABLE_ACCEPT,
- OM2K_TIMEOUT, 0);
- abis_om2k_tx_enable_req(omfp->trx->bts, &omfp->mo->addr);
-}
-
-static void om2k_mo_st_wait_enable_accept(struct osmo_fsm_inst *fi, uint32_t event, void *data)
-{
- struct om2k_mo_fsm_priv *omfp = fi->priv;
- struct om2k_decoded_msg *omd = data;
-
- switch (omd->msg_type) {
- case OM2K_MSGT_ENABLE_REQ_REJ:
- osmo_fsm_inst_state_chg(fi, OM2K_ST_ERROR, 0, 0);
- break;
- case OM2K_MSGT_ENABLE_REQ_ACK:
- if (omfp->mo->addr.class == OM2K_MO_CLS_IS &&
- omfp->trx->bts->rbs2000.use_superchannel)
- e1inp_ericsson_set_altc(omfp->trx->bts->oml_link->ts->line, 1);
- osmo_fsm_inst_state_chg(fi, OM2K_ST_WAIT_ENABLE_RES,
- OM2K_TIMEOUT, 0);
- }
-}
-
-static void om2k_mo_st_wait_enable_res(struct osmo_fsm_inst *fi, uint32_t event, void *data)
-{
- struct om2k_mo_fsm_priv *omfp = fi->priv;
- //struct om2k_decoded_msg *omd = data;
- /* TODO: check if state is actually enabled now? */
-
- osmo_fsm_inst_state_chg(fi, OM2K_ST_WAIT_OPINFO_ACCEPT,
- OM2K_TIMEOUT, 0);
- abis_om2k_tx_op_info(omfp->trx->bts, &omfp->mo->addr, 1);
-}
-
-static void om2k_mo_st_wait_opinfo_accept(struct osmo_fsm_inst *fi, uint32_t event, void *data)
-{
- struct om2k_mo_fsm_priv *omfp = fi->priv;
-
- /* if we have just received opinfo accept for the timeslot,
- * start dynamic TCH switching procedures */
- if (omfp->mo->addr.class == OM2K_MO_CLS_TS) {
- struct gsm_bts_trx_ts *ts;
- ts = mo2obj(omfp->trx->bts, &omfp->mo->addr);
- dyn_ts_init(ts);
- }
- osmo_fsm_inst_state_chg(fi, OM2K_ST_DONE, 0, 0);
-}
-
-static void om2k_mo_s_done_onenter(struct osmo_fsm_inst *fi, uint32_t prev_state)
-{
- struct om2k_mo_fsm_priv *omfp = fi->priv;
- omfp->mo->fsm = NULL;
- osmo_fsm_inst_term(fi, OSMO_FSM_TERM_REGULAR, NULL);
-}
-
-static void om2k_mo_s_error_onenter(struct osmo_fsm_inst *fi, uint32_t prev_state)
-{
- struct om2k_mo_fsm_priv *omfp = fi->priv;
-
- omfp->mo->fsm = NULL;
- osmo_fsm_inst_term(fi, OSMO_FSM_TERM_ERROR, NULL);
-}
-
-static const struct osmo_fsm_state om2k_is_states[] = {
- [OM2K_ST_INIT] = {
- .name = "INIT",
- .in_event_mask = S(OM2K_MO_EVT_START),
- .out_state_mask = S(OM2K_ST_DONE) |
- S(OM2K_ST_ERROR) |
- S(OM2K_ST_WAIT_CONN_COMPL) |
- S(OM2K_ST_WAIT_START_ACCEPT) |
- S(OM2K_ST_WAIT_RES_COMPL),
- .action = om2k_mo_st_init,
- },
- [OM2K_ST_WAIT_CONN_COMPL] = {
- .name = "WAIT-CONN-COMPL",
- .in_event_mask = S(OM2K_MO_EVT_RX_CONN_COMPL),
- .out_state_mask = S(OM2K_ST_DONE) |
- S(OM2K_ST_ERROR) |
- S(OM2K_ST_WAIT_START_ACCEPT) |
- S(OM2K_ST_WAIT_RES_COMPL),
- .action = om2k_mo_st_wait_conn_compl,
- },
- [OM2K_ST_WAIT_RES_COMPL] = {
- .name = "WAIT-RES-COMPL",
- .in_event_mask = S(OM2K_MO_EVT_RX_RESET_COMPL),
- .out_state_mask = S(OM2K_ST_DONE) |
- S(OM2K_ST_ERROR) |
- S(OM2K_ST_WAIT_START_ACCEPT),
- .action = om2k_mo_st_wait_res_compl,
- },
- [OM2K_ST_WAIT_START_ACCEPT] = {
- .name = "WAIT-START-ACCEPT",
- .in_event_mask = S(OM2K_MO_EVT_RX_START_REQ_ACCEPT),
- .out_state_mask = S(OM2K_ST_DONE) |
- S(OM2K_ST_ERROR) |
- S(OM2K_ST_WAIT_START_RES),
- .action =om2k_mo_st_wait_start_accept,
- },
- [OM2K_ST_WAIT_START_RES] = {
- .name = "WAIT-START-RES",
- .in_event_mask = S(OM2K_MO_EVT_RX_START_RES),
- .out_state_mask = S(OM2K_ST_DONE) |
- S(OM2K_ST_ERROR) |
- S(OM2K_ST_WAIT_CFG_ACCEPT) |
- S(OM2K_ST_WAIT_OPINFO_ACCEPT),
- .action = om2k_mo_st_wait_start_res,
- },
- [OM2K_ST_WAIT_CFG_ACCEPT] = {
- .name = "WAIT-CFG-ACCEPT",
- .in_event_mask = S(OM2K_MO_EVT_RX_CFG_REQ_ACCEPT),
- .out_state_mask = S(OM2K_ST_DONE) |
- S(OM2K_ST_ERROR) |
- S(OM2K_ST_WAIT_CFG_RES),
- .action = om2k_mo_st_wait_cfg_accept,
- },
- [OM2K_ST_WAIT_CFG_RES] = {
- .name = "WAIT-CFG-RES",
- .in_event_mask = S(OM2K_MO_EVT_RX_CFG_RES),
- .out_state_mask = S(OM2K_ST_DONE) |
- S(OM2K_ST_ERROR) |
- S(OM2K_ST_WAIT_ENABLE_ACCEPT),
- .action = om2k_mo_st_wait_cfg_res,
- },
- [OM2K_ST_WAIT_ENABLE_ACCEPT] = {
- .name = "WAIT-ENABLE-ACCEPT",
- .in_event_mask = S(OM2K_MO_EVT_RX_ENA_REQ_ACCEPT),
- .out_state_mask = S(OM2K_ST_DONE) |
- S(OM2K_ST_ERROR) |
- S(OM2K_ST_WAIT_ENABLE_RES),
- .action = om2k_mo_st_wait_enable_accept,
- },
- [OM2K_ST_WAIT_ENABLE_RES] = {
- .name = "WAIT-ENABLE-RES",
- .in_event_mask = S(OM2K_MO_EVT_RX_ENA_RES),
- .out_state_mask = S(OM2K_ST_DONE) |
- S(OM2K_ST_ERROR) |
- S(OM2K_ST_WAIT_OPINFO_ACCEPT),
- .action = om2k_mo_st_wait_enable_res,
- },
- [OM2K_ST_WAIT_OPINFO_ACCEPT] = {
- .name = "WAIT-OPINFO-ACCEPT",
- .in_event_mask = S(OM2K_MO_EVT_RX_OPINFO_ACC),
- .out_state_mask = S(OM2K_ST_DONE) |
- S(OM2K_ST_ERROR),
- .action = om2k_mo_st_wait_opinfo_accept,
- },
- [OM2K_ST_DONE] = {
- .name = "DONE",
- .in_event_mask = 0,
- .out_state_mask = 0,
- .onenter = om2k_mo_s_done_onenter,
- },
- [OM2K_ST_ERROR] = {
- .name = "ERROR",
- .in_event_mask = 0,
- .out_state_mask = 0,
- .onenter = om2k_mo_s_error_onenter,
- },
-
-};
-
-static int om2k_mo_timer_cb(struct osmo_fsm_inst *fi)
-{
- osmo_fsm_inst_state_chg(fi, OM2K_ST_ERROR, 0, 0);
- return 0;
-}
-
-static struct osmo_fsm om2k_mo_fsm = {
- .name = "OM2000-MO",
- .states = om2k_is_states,
- .num_states = ARRAY_SIZE(om2k_is_states),
- .log_subsys = DNM,
- .event_names = om2k_event_names,
- .timer_cb = om2k_mo_timer_cb,
-};
-
-struct osmo_fsm_inst *om2k_mo_fsm_start(struct osmo_fsm_inst *parent,
- uint32_t term_event,
- struct gsm_bts_trx *trx, struct om2k_mo *mo)
-{
- struct osmo_fsm_inst *fi;
- struct om2k_mo_fsm_priv *omfp;
- char idbuf[64];
-
- snprintf(idbuf, sizeof(idbuf), "%s-%s", parent->id,
- om2k_mo_name(&mo->addr));
-
- fi = osmo_fsm_inst_alloc_child_id(&om2k_mo_fsm, parent,
- term_event, idbuf);
- if (!fi)
- return NULL;
-
- mo->fsm = fi;
- omfp = talloc_zero(fi, struct om2k_mo_fsm_priv);
- omfp->mo = mo;
- omfp->trx = trx;
- fi->priv = omfp;
-
- osmo_fsm_inst_dispatch(fi, OM2K_MO_EVT_START, NULL);
-
- return fi;
-}
-
-int om2k_mo_fsm_recvmsg(struct gsm_bts *bts, struct om2k_mo *mo,
- struct om2k_decoded_msg *odm)
-{
- switch (odm->msg_type) {
- case OM2K_MSGT_CONNECT_COMPL:
- case OM2K_MSGT_CONNECT_REJ:
- osmo_fsm_inst_dispatch(mo->fsm,
- OM2K_MO_EVT_RX_CONN_COMPL, odm);
- break;
-
- case OM2K_MSGT_RESET_COMPL:
- case OM2K_MSGT_RESET_REJ:
- osmo_fsm_inst_dispatch(mo->fsm,
- OM2K_MO_EVT_RX_RESET_COMPL, odm);
- break;
-
- case OM2K_MSGT_START_REQ_ACK:
- case OM2K_MSGT_START_REQ_REJ:
- osmo_fsm_inst_dispatch(mo->fsm,
- OM2K_MO_EVT_RX_START_REQ_ACCEPT, odm);
- break;
-
- case OM2K_MSGT_START_RES:
- osmo_fsm_inst_dispatch(mo->fsm,
- OM2K_MO_EVT_RX_START_RES, odm);
- break;
-
- case OM2K_MSGT_CON_CONF_REQ_ACK:
- case OM2K_MSGT_IS_CONF_REQ_ACK:
- case OM2K_MSGT_RX_CONF_REQ_ACK:
- case OM2K_MSGT_TF_CONF_REQ_ACK:
- case OM2K_MSGT_TS_CONF_REQ_ACK:
- case OM2K_MSGT_TX_CONF_REQ_ACK:
- osmo_fsm_inst_dispatch(mo->fsm,
- OM2K_MO_EVT_RX_CFG_REQ_ACCEPT, odm);
- break;
-
- case OM2K_MSGT_CON_CONF_RES:
- case OM2K_MSGT_IS_CONF_RES:
- case OM2K_MSGT_RX_CONF_RES:
- case OM2K_MSGT_TF_CONF_RES:
- case OM2K_MSGT_TS_CONF_RES:
- case OM2K_MSGT_TX_CONF_RES:
- osmo_fsm_inst_dispatch(mo->fsm,
- OM2K_MO_EVT_RX_CFG_RES, odm);
- break;
-
- case OM2K_MSGT_ENABLE_REQ_ACK:
- case OM2K_MSGT_ENABLE_REQ_REJ:
- osmo_fsm_inst_dispatch(mo->fsm,
- OM2K_MO_EVT_RX_ENA_REQ_ACCEPT, odm);
- break;
- case OM2K_MSGT_ENABLE_RES:
- osmo_fsm_inst_dispatch(mo->fsm,
- OM2K_MO_EVT_RX_ENA_RES, odm);
- break;
-
- case OM2K_MSGT_OP_INFO_ACK:
- case OM2K_MSGT_OP_INFO_REJ:
- osmo_fsm_inst_dispatch(mo->fsm,
- OM2K_MO_EVT_RX_OPINFO_ACC, odm);
- break;
- default:
- return -1;
- }
-
- return 0;
-}
-
-/***********************************************************************
- * OM2000 TRX Finite State Machine, initializes TRXC and all siblings
- ***********************************************************************/
-
-enum om2k_trx_event {
- OM2K_TRX_EVT_START,
- OM2K_TRX_EVT_TRXC_DONE,
- OM2K_TRX_EVT_TX_DONE,
- OM2K_TRX_EVT_RX_DONE,
- OM2K_TRX_EVT_TS_DONE,
- OM2K_TRX_EVT_STOP,
-};
-
-static struct value_string om2k_trx_events[] = {
- { OM2K_TRX_EVT_START, "START" },
- { OM2K_TRX_EVT_TRXC_DONE, "TRXC-DONE" },
- { OM2K_TRX_EVT_TX_DONE, "TX-DONE" },
- { OM2K_TRX_EVT_RX_DONE, "RX-DONE" },
- { OM2K_TRX_EVT_TS_DONE, "TS-DONE" },
- { OM2K_TRX_EVT_STOP, "STOP" },
- { 0, NULL }
-};
-
-enum om2k_trx_state {
- OM2K_TRX_S_INIT,
- OM2K_TRX_S_WAIT_TRXC,
- OM2K_TRX_S_WAIT_TX,
- OM2K_TRX_S_WAIT_RX,
- OM2K_TRX_S_WAIT_TS,
- OM2K_TRX_S_DONE,
- OM2K_TRX_S_ERROR
-};
-
-struct om2k_trx_fsm_priv {
- struct gsm_bts_trx *trx;
- uint8_t next_ts_nr;
-};
-
-static void om2k_trx_s_init(struct osmo_fsm_inst *fi, uint32_t event, void *data)
-{
- struct om2k_trx_fsm_priv *otfp = fi->priv;
-
- /* First initialize TRXC */
- osmo_fsm_inst_state_chg(fi, OM2K_TRX_S_WAIT_TRXC,
- TRX_FSM_TIMEOUT, 0);
- om2k_mo_fsm_start(fi, OM2K_TRX_EVT_TRXC_DONE, otfp->trx,
- &otfp->trx->rbs2000.trxc.om2k_mo);
-}
-
-static void om2k_trx_s_wait_trxc(struct osmo_fsm_inst *fi, uint32_t event, void *data)
-{
- struct om2k_trx_fsm_priv *otfp = fi->priv;
-
- /* Initialize TX after TRXC */
- osmo_fsm_inst_state_chg(fi, OM2K_TRX_S_WAIT_TX,
- TRX_FSM_TIMEOUT, 0);
- om2k_mo_fsm_start(fi, OM2K_TRX_EVT_TX_DONE, otfp->trx,
- &otfp->trx->rbs2000.tx.om2k_mo);
-}
-
-static void om2k_trx_s_wait_tx(struct osmo_fsm_inst *fi, uint32_t event, void *data)
-{
- struct om2k_trx_fsm_priv *otfp = fi->priv;
-
- /* Initialize RX after TX */
- osmo_fsm_inst_state_chg(fi, OM2K_TRX_S_WAIT_RX,
- TRX_FSM_TIMEOUT, 0);
- om2k_mo_fsm_start(fi, OM2K_TRX_EVT_RX_DONE, otfp->trx,
- &otfp->trx->rbs2000.rx.om2k_mo);
-}
-
-static void om2k_trx_s_wait_rx(struct osmo_fsm_inst *fi, uint32_t event, void *data)
-{
- struct om2k_trx_fsm_priv *otfp = fi->priv;
- struct gsm_bts_trx_ts *ts;
-
- /* Initialize Timeslots after TX */
- osmo_fsm_inst_state_chg(fi, OM2K_TRX_S_WAIT_TS,
- TRX_FSM_TIMEOUT, 0);
- otfp->next_ts_nr = 0;
- ts = &otfp->trx->ts[otfp->next_ts_nr++];
- om2k_mo_fsm_start(fi, OM2K_TRX_EVT_TS_DONE, otfp->trx,
- &ts->rbs2000.om2k_mo);
-}
-
-static void om2k_trx_s_wait_ts(struct osmo_fsm_inst *fi, uint32_t event, void *data)
-{
- struct om2k_trx_fsm_priv *otfp = fi->priv;
- struct gsm_bts_trx_ts *ts;
-
- if (otfp->next_ts_nr < 8) {
- /* iterate to the next timeslot */
- ts = &otfp->trx->ts[otfp->next_ts_nr++];
- om2k_mo_fsm_start(fi, OM2K_TRX_EVT_TS_DONE, otfp->trx,
- &ts->rbs2000.om2k_mo);
- } else {
- /* only after all 8 TS */
- osmo_fsm_inst_state_chg(fi, OM2K_TRX_S_DONE, 0, 0);
- }
-}
-
-static void om2k_trx_s_done_onenter(struct osmo_fsm_inst *fi, uint32_t prev_state)
-{
- struct om2k_trx_fsm_priv *otfp = fi->priv;
- gsm_bts_trx_set_system_infos(otfp->trx);
- osmo_fsm_inst_term(fi, OSMO_FSM_TERM_REGULAR, NULL);
-}
-
-static const struct osmo_fsm_state om2k_trx_states[] = {
- [OM2K_TRX_S_INIT] = {
- .in_event_mask = S(OM2K_TRX_EVT_START),
- .out_state_mask = S(OM2K_TRX_S_WAIT_TRXC),
- .name = "INIT",
- .action = om2k_trx_s_init,
- },
- [OM2K_TRX_S_WAIT_TRXC] = {
- .in_event_mask = S(OM2K_TRX_EVT_TRXC_DONE),
- .out_state_mask = S(OM2K_TRX_S_ERROR) |
- S(OM2K_TRX_S_WAIT_TX),
- .name = "WAIT-TRXC",
- .action = om2k_trx_s_wait_trxc,
- },
- [OM2K_TRX_S_WAIT_TX] = {
- .in_event_mask = S(OM2K_TRX_EVT_TX_DONE),
- .out_state_mask = S(OM2K_TRX_S_ERROR) |
- S(OM2K_TRX_S_WAIT_RX),
- .name = "WAIT-TX",
- .action = om2k_trx_s_wait_tx,
- },
- [OM2K_TRX_S_WAIT_RX] = {
- .in_event_mask = S(OM2K_TRX_EVT_RX_DONE),
- .out_state_mask = S(OM2K_TRX_S_ERROR) |
- S(OM2K_TRX_S_WAIT_TS),
- .name = "WAIT-RX",
- .action = om2k_trx_s_wait_rx,
- },
- [OM2K_TRX_S_WAIT_TS] = {
- .in_event_mask = S(OM2K_TRX_EVT_TS_DONE),
- .out_state_mask = S(OM2K_TRX_S_ERROR) |
- S(OM2K_TRX_S_DONE),
- .name = "WAIT-TS",
- .action = om2k_trx_s_wait_ts,
- },
- [OM2K_TRX_S_DONE] = {
- .name = "DONE",
- .onenter = om2k_trx_s_done_onenter,
- },
- [OM2K_TRX_S_ERROR] = {
- .name = "ERROR",
- },
-};
-
-static int om2k_trx_timer_cb(struct osmo_fsm_inst *fi)
-{
- osmo_fsm_inst_state_chg(fi, OM2K_TRX_S_ERROR, 0, 0);
- return 0;
-}
-
-static struct osmo_fsm om2k_trx_fsm = {
- .name = "OM2000-TRX",
- .states = om2k_trx_states,
- .num_states = ARRAY_SIZE(om2k_trx_states),
- .log_subsys = DNM,
- .event_names = om2k_trx_events,
- .timer_cb = om2k_trx_timer_cb,
-};
-
-struct osmo_fsm_inst *om2k_trx_fsm_start(struct osmo_fsm_inst *parent,
- struct gsm_bts_trx *trx,
- uint32_t term_event)
-{
- struct osmo_fsm_inst *fi;
- struct om2k_trx_fsm_priv *otfp;
- char idbuf[32];
-
- snprintf(idbuf, sizeof(idbuf), "%u/%u", trx->bts->nr, trx->nr);
-
- fi = osmo_fsm_inst_alloc_child_id(&om2k_trx_fsm, parent, term_event,
- idbuf);
- if (!fi)
- return NULL;
-
- otfp = talloc_zero(fi, struct om2k_trx_fsm_priv);
- otfp->trx = trx;
- fi->priv = otfp;
-
- osmo_fsm_inst_dispatch(fi, OM2K_TRX_EVT_START, NULL);
-
- return fi;
-}
-
-
-/***********************************************************************
- * OM2000 BTS Finite State Machine, initializes CF and all siblings
- ***********************************************************************/
-
-enum om2k_bts_event {
- OM2K_BTS_EVT_START,
- OM2K_BTS_EVT_CF_DONE,
- OM2K_BTS_EVT_IS_DONE,
- OM2K_BTS_EVT_CON_DONE,
- OM2K_BTS_EVT_TF_DONE,
- OM2K_BTS_EVT_TRX_DONE,
- OM2K_BTS_EVT_STOP,
-};
-
-static const struct value_string om2k_bts_events[] = {
- { OM2K_BTS_EVT_START, "START" },
- { OM2K_BTS_EVT_CF_DONE, "CF-DONE" },
- { OM2K_BTS_EVT_IS_DONE, "IS-DONE" },
- { OM2K_BTS_EVT_CON_DONE, "CON-DONE" },
- { OM2K_BTS_EVT_TF_DONE, "TF-DONE" },
- { OM2K_BTS_EVT_TRX_DONE, "TRX-DONE" },
- { OM2K_BTS_EVT_STOP, "STOP" },
- { 0, NULL }
-};
-
-enum om2k_bts_state {
- OM2K_BTS_S_INIT,
- OM2K_BTS_S_WAIT_CF,
- OM2K_BTS_S_WAIT_IS,
- OM2K_BTS_S_WAIT_CON,
- OM2K_BTS_S_WAIT_TF,
- OM2K_BTS_S_WAIT_TRX,
- OM2K_BTS_S_DONE,
- OM2K_BTS_S_ERROR,
-};
-
-struct om2k_bts_fsm_priv {
- struct gsm_bts *bts;
- uint8_t next_trx_nr;
-};
-
-static void om2k_bts_s_init(struct osmo_fsm_inst *fi, uint32_t event, void *data)
-{
- struct om2k_bts_fsm_priv *obfp = fi->priv;
- struct gsm_bts *bts = obfp->bts;
-
- OSMO_ASSERT(event == OM2K_BTS_EVT_START);
- osmo_fsm_inst_state_chg(fi, OM2K_BTS_S_WAIT_CF,
- BTS_FSM_TIMEOUT, 0);
- om2k_mo_fsm_start(fi, OM2K_BTS_EVT_CF_DONE, bts->c0,
- &bts->rbs2000.cf.om2k_mo);
-}
-
-static void om2k_bts_s_wait_cf(struct osmo_fsm_inst *fi, uint32_t event, void *data)
-{
- struct om2k_bts_fsm_priv *obfp = fi->priv;
- struct gsm_bts *bts = obfp->bts;
-
- OSMO_ASSERT(event == OM2K_BTS_EVT_CF_DONE);
- /* TF can take a long time to initialize, wait for 10min */
- osmo_fsm_inst_state_chg(fi, OM2K_BTS_S_WAIT_TF, 600, 0);
- om2k_mo_fsm_start(fi, OM2K_BTS_EVT_TF_DONE, bts->c0,
- &bts->rbs2000.tf.om2k_mo);
-}
-
-static void om2k_bts_s_wait_tf(struct osmo_fsm_inst *fi, uint32_t event, void *data)
-{
- struct om2k_bts_fsm_priv *obfp = fi->priv;
- struct gsm_bts *bts = obfp->bts;
-
- OSMO_ASSERT(event == OM2K_BTS_EVT_TF_DONE);
-
- osmo_fsm_inst_state_chg(fi, OM2K_BTS_S_WAIT_CON,
- BTS_FSM_TIMEOUT, 0);
- om2k_mo_fsm_start(fi, OM2K_BTS_EVT_CON_DONE, bts->c0,
- &bts->rbs2000.con.om2k_mo);
-}
-
-static void om2k_bts_s_wait_con(struct osmo_fsm_inst *fi, uint32_t event, void *data)
-{
- struct om2k_bts_fsm_priv *obfp = fi->priv;
- struct gsm_bts *bts = obfp->bts;
-
- OSMO_ASSERT(event == OM2K_BTS_EVT_CON_DONE);
-
- osmo_fsm_inst_state_chg(fi, OM2K_BTS_S_WAIT_IS,
- BTS_FSM_TIMEOUT, 0);
- om2k_mo_fsm_start(fi, OM2K_BTS_EVT_IS_DONE, bts->c0,
- &bts->rbs2000.is.om2k_mo);
-}
-
-static void om2k_bts_s_wait_is(struct osmo_fsm_inst *fi, uint32_t event, void *data)
-{
- struct om2k_bts_fsm_priv *obfp = fi->priv;
- struct gsm_bts_trx *trx;
-
- OSMO_ASSERT(event == OM2K_BTS_EVT_IS_DONE);
-
- osmo_fsm_inst_state_chg(fi, OM2K_BTS_S_WAIT_TRX,
- BTS_FSM_TIMEOUT, 0);
- obfp->next_trx_nr = 0;
- trx = gsm_bts_trx_num(obfp->bts, obfp->next_trx_nr++);
- om2k_trx_fsm_start(fi, trx, OM2K_BTS_EVT_TRX_DONE);
-}
-
-static void om2k_bts_s_wait_trx(struct osmo_fsm_inst *fi, uint32_t event, void *data)
-{
- struct om2k_bts_fsm_priv *obfp = fi->priv;
-
- OSMO_ASSERT(event == OM2K_BTS_EVT_TRX_DONE);
-
- if (obfp->next_trx_nr < obfp->bts->num_trx) {
- struct gsm_bts_trx *trx;
- trx = gsm_bts_trx_num(obfp->bts, obfp->next_trx_nr++);
- om2k_trx_fsm_start(fi, trx, OM2K_BTS_EVT_TRX_DONE);
- } else {
- osmo_fsm_inst_state_chg(fi, OM2K_BTS_S_DONE, 0, 0);
- }
-}
-
-static void om2k_bts_s_done_onenter(struct osmo_fsm_inst *fi, uint32_t prev_state)
-{
- osmo_fsm_inst_term(fi, OSMO_FSM_TERM_REGULAR, NULL);
-}
-
-static const struct osmo_fsm_state om2k_bts_states[] = {
- [OM2K_BTS_S_INIT] = {
- .in_event_mask = S(OM2K_BTS_EVT_START),
- .out_state_mask = S(OM2K_BTS_S_WAIT_CF),
- .name = "INIT",
- .action = om2k_bts_s_init,
- },
- [OM2K_BTS_S_WAIT_CF] = {
- .in_event_mask = S(OM2K_BTS_EVT_CF_DONE),
- .out_state_mask = S(OM2K_BTS_S_ERROR) |
- S(OM2K_BTS_S_WAIT_TF),
- .name = "WAIT-CF",
- .action = om2k_bts_s_wait_cf,
- },
- [OM2K_BTS_S_WAIT_TF] = {
- .in_event_mask = S(OM2K_BTS_EVT_TF_DONE),
- .out_state_mask = S(OM2K_BTS_S_ERROR) |
- S(OM2K_BTS_S_WAIT_CON),
- .name = "WAIT-TF",
- .action = om2k_bts_s_wait_tf,
- },
- [OM2K_BTS_S_WAIT_CON] = {
- .in_event_mask = S(OM2K_BTS_EVT_CON_DONE),
- .out_state_mask = S(OM2K_BTS_S_ERROR) |
- S(OM2K_BTS_S_WAIT_IS),
- .name = "WAIT-CON",
- .action = om2k_bts_s_wait_con,
- },
- [OM2K_BTS_S_WAIT_IS] = {
- .in_event_mask = S(OM2K_BTS_EVT_IS_DONE),
- .out_state_mask = S(OM2K_BTS_S_ERROR) |
- S(OM2K_BTS_S_WAIT_TRX),
- .name = "WAIT-IS",
- .action = om2k_bts_s_wait_is,
- },
- [OM2K_BTS_S_WAIT_TRX] = {
- .in_event_mask = S(OM2K_BTS_EVT_TRX_DONE),
- .out_state_mask = S(OM2K_BTS_S_ERROR) |
- S(OM2K_BTS_S_DONE),
- .name = "WAIT-TRX",
- .action = om2k_bts_s_wait_trx,
- },
- [OM2K_BTS_S_DONE] = {
- .name = "DONE",
- .onenter = om2k_bts_s_done_onenter,
- },
- [OM2K_BTS_S_ERROR] = {
- .name = "ERROR",
- },
-};
-
-static int om2k_bts_timer_cb(struct osmo_fsm_inst *fi)
-{
- osmo_fsm_inst_state_chg(fi, OM2K_BTS_S_ERROR, 0, 0);
- return 0;
-}
-
-static struct osmo_fsm om2k_bts_fsm = {
- .name = "OM2000-BTS",
- .states = om2k_bts_states,
- .num_states = ARRAY_SIZE(om2k_bts_states),
- .log_subsys = DNM,
- .event_names = om2k_bts_events,
- .timer_cb = om2k_bts_timer_cb,
-};
-
-struct osmo_fsm_inst *
-om2k_bts_fsm_start(struct gsm_bts *bts)
-{
- struct osmo_fsm_inst *fi;
- struct om2k_bts_fsm_priv *obfp;
- char idbuf[16];
-
- snprintf(idbuf, sizeof(idbuf), "%u", bts->nr);
-
- fi = osmo_fsm_inst_alloc(&om2k_bts_fsm, bts, NULL,
- LOGL_DEBUG, idbuf);
- if (!fi)
- return NULL;
- fi->priv = obfp = talloc_zero(fi, struct om2k_bts_fsm_priv);
- obfp->bts = bts;
-
- osmo_fsm_inst_dispatch(fi, OM2K_BTS_EVT_START, NULL);
-
- return fi;
-}
-
-
-/***********************************************************************
- * OM2000 Negotiation
- ***********************************************************************/
-
-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);
-
- 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 e1inp_sign_link *sign_link = (struct e1inp_sign_link *)msg->dst;
- 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(sign_link->trx->bts, &o2h->mo, out_buf, out_cur - out_buf);
-}
-
-
-/***********************************************************************
- * OM2000 Receive Message Handler
- ***********************************************************************/
-
-static int om2k_rx_nack(struct msgb *msg)
-{
- struct abis_om2k_hdr *o2h = msgb_l2(msg);
- uint16_t msg_type = ntohs(o2h->msg_type);
- struct tlv_parsed tp;
-
- LOGP(DNM, LOGL_ERROR, "Rx MO=%s %s", om2k_mo_name(&o2h->mo),
- get_value_string(om2k_msgcode_vals, msg_type));
-
- abis_om2k_msg_tlv_parse(&tp, o2h);
- if (TLVP_PRESENT(&tp, OM2K_DEI_REASON_CODE))
- LOGPC(DNM, LOGL_ERROR, ", Reason 0x%02x",
- *TLVP_VAL(&tp, OM2K_DEI_REASON_CODE));
-
- if (TLVP_PRESENT(&tp, OM2K_DEI_RESULT_CODE))
- LOGPC(DNM, LOGL_ERROR, ", Result %s",
- get_value_string(om2k_result_strings,
- *TLVP_VAL(&tp, OM2K_DEI_RESULT_CODE)));
- LOGPC(DNM, LOGL_ERROR, "\n");
-
- return 0;
-}
-
-static int process_mo_state(struct gsm_bts *bts, struct om2k_decoded_msg *odm)
-{
- uint8_t mo_state;
-
- if (!TLVP_PRESENT(&odm->tp, OM2K_DEI_MO_STATE))
- return -EIO;
- mo_state = *TLVP_VAL(&odm->tp, OM2K_DEI_MO_STATE);
-
- LOGP(DNM, LOGL_DEBUG, "Rx MO=%s %s, MO State: %s\n",
- om2k_mo_name(&odm->o2h.mo),
- get_value_string(om2k_msgcode_vals, odm->msg_type),
- get_value_string(om2k_mostate_vals, mo_state));
-
- /* Throw error message in case we see an enable rsponse that does
- * not yield an enabled mo-state */
- if (odm->msg_type == OM2K_MSGT_ENABLE_RES
- && mo_state != OM2K_MO_S_ENABLED) {
- LOGP(DNM, LOGL_ERROR,
- "Rx MO=%s %s Failed to enable MO State!\n",
- om2k_mo_name(&odm->o2h.mo),
- get_value_string(om2k_msgcode_vals, odm->msg_type));
- }
-
- update_mo_state(bts, &odm->o2h.mo, mo_state);
-
- return 0;
-}
-
-/* Display fault report bits (helper function of display_fault_maps()) */
-static bool display_fault_bits(const uint8_t *vect, uint16_t len,
- uint8_t dei, const struct abis_om2k_mo *mo)
-{
- uint16_t i;
- int k;
- bool faults_present = false;
- int first = 1;
- char string[255];
-
- /* Check if errors are present at all */
- for (i = 0; i < len; i++)
- if (vect[i])
- faults_present = true;
- if (!faults_present)
- return false;
-
- sprintf(string, "Fault Report: %s (",
- get_value_string(om2k_attr_vals, dei));
-
- for (i = 0; i < len; i++) {
- for (k = 0; k < 8; k++) {
- if ((vect[i] >> k) & 1) {
- if (!first)
- sprintf(string + strlen(string), ",");
- sprintf(string + strlen(string), "%d", k + i*8);
- first = 0;
- }
- }
- }
-
- sprintf(string + strlen(string), ")\n");
- DEBUGP(DNM, "Rx MO=%s %s", om2k_mo_name(mo), string);
-
- return true;
-}
-
-/* Display fault report maps */
-static void display_fault_maps(const uint8_t *src, unsigned int src_len,
- const struct abis_om2k_mo *mo)
-{
- uint8_t tag;
- uint16_t tag_len;
- const uint8_t *val;
- int src_pos = 0;
- int rc;
- int tlv_count = 0;
- uint16_t msg_code;
- bool faults_present = false;
-
- /* Chop off header */
- src+=4;
- src_len-=4;
-
- /* Check message type */
- msg_code = (*src & 0xff) << 8;
- src++;
- src_len--;
- msg_code |= (*src & 0xff);
- src++;
- src_len--;
- if (msg_code != OM2K_MSGT_FAULT_REP) {
- LOGP(DNM, LOGL_ERROR, "Rx MO=%s Fault report: invalid message code!\n",
- om2k_mo_name(mo));
- return;
- }
-
- /* Chop off mo-interface */
- src += 4;
- src_len -= 4;
-
- /* Iterate over each TLV element */
- while (1) {
-
- /* Bail if an the maximum number of TLV fields
- * have been parsed */
- if (tlv_count >= 11) {
- LOGP(DNM, LOGL_ERROR,
- "Rx MO=%s Fault Report: too many tlv elements!\n",
- om2k_mo_name(mo));
- return;
- }
-
- /* Parse TLV field */
- rc = tlv_parse_one(&tag, &tag_len, &val, &om2k_att_tlvdef,
- src + src_pos, src_len - src_pos);
- if (rc > 0)
- src_pos += rc;
- else {
- LOGP(DNM, LOGL_ERROR,
- "Rx MO=%s Fault Report: invalid tlv element!\n",
- om2k_mo_name(mo));
- return;
- }
-
- switch (tag) {
- case OM2K_DEI_INT_FAULT_MAP_1A:
- case OM2K_DEI_INT_FAULT_MAP_1B:
- case OM2K_DEI_INT_FAULT_MAP_2A:
- case OM2K_DEI_EXT_COND_MAP_1:
- case OM2K_DEI_EXT_COND_MAP_2:
- case OM2K_DEI_REPL_UNIT_MAP:
- case OM2K_DEI_INT_FAULT_MAP_2A_EXT:
- case OM2K_DEI_EXT_COND_MAP_2_EXT:
- case OM2K_DEI_REPL_UNIT_MAP_EXT:
- faults_present |= display_fault_bits(val, tag_len,
- tag, mo);
- break;
- }
-
- /* Stop when no further TLV elements can be expected */
- if (src_len - src_pos < 2)
- break;
-
- tlv_count++;
- }
-
- if (!faults_present) {
- DEBUGP(DNM, "Rx MO=%s Fault Report: All faults ceased!\n",
- om2k_mo_name(mo));
- }
-}
-
-int abis_om2k_rcvmsg(struct msgb *msg)
-{
- struct e1inp_sign_link *sign_link = (struct e1inp_sign_link *)msg->dst;
- struct gsm_bts *bts = sign_link->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);
- struct om2k_decoded_msg odm;
- struct om2k_mo *mo;
- 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),
- osmo_hexdump(msg->l2h, msgb_l2len(msg)));
-
- om2k_decode_msg(&odm, msg);
-
- process_mo_state(bts, &odm);
-
- switch (msg_type) {
- case OM2K_MSGT_CAL_TIME_REQ:
- rc = abis_om2k_cal_time_resp(bts);
- break;
- case OM2K_MSGT_FAULT_REP:
- display_fault_maps(msg->l2h, msgb_l2len(msg), &o2h->mo);
- 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:
- /* common processing here */
- rc = abis_om2k_tx_simple(bts, &o2h->mo, OM2K_MSGT_START_RES_ACK);
- /* below we dispatch into MO */
- 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_TX_CONF_RES:
- rc = abis_om2k_tx_simple(bts, &o2h->mo, OM2K_MSGT_TX_CONF_RES_ACK);
- break;
- case OM2K_MSGT_RX_CONF_RES:
- rc = abis_om2k_tx_simple(bts, &o2h->mo, OM2K_MSGT_RX_CONF_RES_ACK);
- break;
- case OM2K_MSGT_TS_CONF_RES:
- rc = abis_om2k_tx_simple(bts, &o2h->mo, OM2K_MSGT_TS_CONF_RES_ACK);
- break;
- case OM2K_MSGT_TF_CONF_RES:
- rc = abis_om2k_tx_simple(bts, &o2h->mo, OM2K_MSGT_TF_CONF_RES_ACK);
- 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_CAPA_RES:
- rc = abis_om2k_tx_simple(bts, &o2h->mo, OM2K_MSGT_CAPA_RES_ACK);
- break;
- /* ERrors */
- case OM2K_MSGT_START_REQ_REJ:
- case OM2K_MSGT_CONNECT_REJ:
- case OM2K_MSGT_OP_INFO_REJ:
- case OM2K_MSGT_DISCONNECT_REJ:
- case OM2K_MSGT_TEST_REQ_REJ:
- case OM2K_MSGT_CON_CONF_REQ_REJ:
- case OM2K_MSGT_IS_CONF_REQ_REJ:
- case OM2K_MSGT_TX_CONF_REQ_REJ:
- case OM2K_MSGT_RX_CONF_REQ_REJ:
- case OM2K_MSGT_TS_CONF_REQ_REJ:
- case OM2K_MSGT_TF_CONF_REQ_REJ:
- case OM2K_MSGT_ENABLE_REQ_REJ:
- case OM2K_MSGT_ALARM_STATUS_REQ_REJ:
- case OM2K_MSGT_DISABLE_REQ_REJ:
- rc = om2k_rx_nack(msg);
- break;
- }
-
- /* Resolve the MO for this message */
- mo = get_om2k_mo(bts, &o2h->mo);
- if (!mo) {
- LOGP(DNM, LOGL_ERROR, "Couldn't resolve MO for OM2K msg "
- "%s: %s\n", get_value_string(om2k_msgcode_vals, msg_type),
- msgb_hexdump(msg));
- return 0;
- }
- if (!mo->fsm) {
- LOGP(DNM, LOGL_ERROR, "MO object should not generate any message. fsm == NULL "
- "%s: %s\n", get_value_string(om2k_msgcode_vals, msg_type),
- msgb_hexdump(msg));
- return 0;
- }
-
- /* Dispatch message to that MO */
- om2k_mo_fsm_recvmsg(bts, mo, &odm);
-
- msgb_free(msg);
- return rc;
-}
-
-static void om2k_mo_init(struct om2k_mo *mo, uint8_t class,
- uint8_t bts_nr, uint8_t assoc_so, uint8_t inst)
-{
- mo->addr.class = class;
- mo->addr.bts = bts_nr;
- mo->addr.assoc_so = assoc_so;
- mo->addr.inst = inst;
-}
-
-/* initialize the OM2K_MO members of gsm_bts_trx and its timeslots */
-void abis_om2k_trx_init(struct gsm_bts_trx *trx)
-{
- struct gsm_bts *bts = trx->bts;
- unsigned int i;
-
- OSMO_ASSERT(bts->type == GSM_BTS_TYPE_RBS2000);
-
- om2k_mo_init(&trx->rbs2000.trxc.om2k_mo, OM2K_MO_CLS_TRXC,
- bts->nr, 255, trx->nr);
- om2k_mo_init(&trx->rbs2000.tx.om2k_mo, OM2K_MO_CLS_TX,
- bts->nr, 255, trx->nr);
- om2k_mo_init(&trx->rbs2000.rx.om2k_mo, OM2K_MO_CLS_RX,
- bts->nr, 255, trx->nr);
-
- for (i = 0; i < ARRAY_SIZE(trx->ts); i++) {
- om2k_mo_init(&trx->ts[i].rbs2000.om2k_mo, OM2K_MO_CLS_TS,
- bts->nr, trx->nr, i);
- }
-}
-
-/* initialize the OM2K_MO members of gsm_bts */
-void abis_om2k_bts_init(struct gsm_bts *bts)
-{
- OSMO_ASSERT(bts->type == GSM_BTS_TYPE_RBS2000);
-
- om2k_mo_init(&bts->rbs2000.cf.om2k_mo, OM2K_MO_CLS_CF,
- bts->nr, 0xFF, 0);
- om2k_mo_init(&bts->rbs2000.is.om2k_mo, OM2K_MO_CLS_IS,
- bts->nr, 0xFF, 0);
- om2k_mo_init(&bts->rbs2000.con.om2k_mo, OM2K_MO_CLS_CON,
- bts->nr, 0xFF, 0);
- om2k_mo_init(&bts->rbs2000.dp.om2k_mo, OM2K_MO_CLS_DP,
- bts->nr, 0xFF, 0);
- om2k_mo_init(&bts->rbs2000.tf.om2k_mo, OM2K_MO_CLS_TF,
- bts->nr, 0xFF, 0);
-}
-
-static __attribute__((constructor)) void abis_om2k_init(void)
-{
- osmo_fsm_register(&om2k_mo_fsm);
- osmo_fsm_register(&om2k_bts_fsm);
- osmo_fsm_register(&om2k_trx_fsm);
-}
diff --git a/src/libbsc/abis_om2000_vty.c b/src/libbsc/abis_om2000_vty.c
deleted file mode 100644
index a6bc4c78..00000000
--- a/src/libbsc/abis_om2000_vty.c
+++ /dev/null
@@ -1,609 +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 <osmocom/core/msgb.h>
-#include <osmocom/gsm/tlv.h>
-#include <osmocom/core/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,
-};
-
-static struct cmd_node om2k_con_group_node = {
- OM2K_CON_GROUP_NODE,
- "%s(om2k-con-group)# ",
- 1,
-};
-
-struct con_group;
-
-struct oml_node_state {
- struct gsm_bts *bts;
- struct abis_om2k_mo mo;
- struct con_group *cg;
-};
-
-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(gsmnet_from_vty(vty), 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(gsmnet_from_vty(vty), 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"
- "Set operational info to 0 or 1\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;
-}
-
-DEFUN(om2k_cap_req, om2k_cap_req_cmd,
- "capabilities-request",
- "Request MO capabilities\n")
-{
- struct oml_node_state *oms = vty->index;
-
- abis_om2k_tx_cap_req(oms->bts, &oms->mo);
- return CMD_SUCCESS;
-}
-
-static struct con_group *con_group_find_or_create(struct gsm_bts *bts, uint8_t cg)
-{
- struct con_group *ent;
-
- llist_for_each_entry(ent, &bts->rbs2000.con.conn_groups, list) {
- if (ent->cg == cg)
- return ent;
- }
-
- ent = talloc_zero(bts, struct con_group);
- ent->bts = bts;
- ent->cg = cg;
- INIT_LLIST_HEAD(&ent->paths);
- llist_add_tail(&ent->list, &bts->rbs2000.con.conn_groups);
-
- return ent;
-}
-
-static int con_group_del(struct gsm_bts *bts, uint8_t cg_id)
-{
- struct con_group *cg, *cg2;
-
- llist_for_each_entry_safe(cg, cg2, &bts->rbs2000.con.conn_groups, list) {
- if (cg->cg == cg_id) {
- llist_del(&cg->list);
- talloc_free(cg);
- return 0;
- };
- }
- return -ENOENT;
-}
-
-static void con_group_add_path(struct con_group *cg, uint16_t ccp,
- uint8_t ci, uint8_t tag, uint8_t tei)
-{
- struct con_path *cp = talloc_zero(cg, struct con_path);
-
- cp->ccp = ccp;
- cp->ci = ci;
- cp->tag = tag;
- cp->tei = tei;
- llist_add(&cp->list, &cg->paths);
-}
-
-static int con_group_del_path(struct con_group *cg, uint16_t ccp,
- uint8_t ci, uint8_t tag, uint8_t tei)
-{
- struct con_path *cp, *cp2;
- llist_for_each_entry_safe(cp, cp2, &cg->paths, list) {
- if (cp->ccp == ccp && cp->ci == ci && cp->tag == tag &&
- cp->tei == tei) {
- llist_del(&cp->list);
- talloc_free(cp);
- return 0;
- }
- }
- return -ENOENT;
-}
-
-DEFUN(cfg_om2k_con_group, cfg_om2k_con_group_cmd,
- "con-connection-group <1-31>",
- "Configure a CON (Concentrator) Connection Group\n"
- "CON Connection Group Number\n")
-{
- struct gsm_bts *bts = vty->index;
- struct con_group *cg;
- uint8_t cgid = atoi(argv[0]);
-
- if (bts->type != GSM_BTS_TYPE_RBS2000) {
- vty_out(vty, "%% CON MO only exists in RBS2000%s",
- VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- cg = con_group_find_or_create(bts, cgid);
- if (!cg) {
- vty_out(vty, "%% Cannot create CON Group%s",
- VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- vty->node = OM2K_CON_GROUP_NODE;
- vty->index = cg;
-
- return CMD_SUCCESS;
-}
-
-DEFUN(del_om2k_con_group, del_om2k_con_group_cmd,
- "del-connection-group <1-31>",
- "Delete a CON (Concentrator) Connection Group\n"
- "CON Connection Group Number\n")
-{
- struct gsm_bts *bts = vty->index;
- int rc;
- uint8_t cgid = atoi(argv[0]);
-
- if (bts->type != GSM_BTS_TYPE_RBS2000) {
- vty_out(vty, "%% CON MO only exists in RBS2000%s",
- VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- rc = con_group_del(bts, cgid);
- if (rc != 0) {
- vty_out(vty, "%% Cannot delete CON Group%s",
- VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- return CMD_SUCCESS;
-}
-
-#define CON_PATH_HELP "CON Path (In/Out)\n" \
- "Add CON Path to Concentration Group\n" \
- "Delete CON Path from Concentration Group\n" \
- "CON Conection Point\n" \
- "Contiguity Index\n" \
-
-DEFUN(cfg_om2k_con_path_dec, cfg_om2k_con_path_dec_cmd,
- "con-path (add|del) <0-2047> <0-255> deconcentrated <0-63>",
- CON_PATH_HELP "De-concentrated in/outlet\n" "TEI Value\n")
-{
- struct con_group *cg = vty->index;
- uint16_t ccp = atoi(argv[1]);
- uint8_t ci = atoi(argv[2]);
- uint8_t tei = atoi(argv[3]);
-
- if (!strcmp(argv[0], "add"))
- con_group_add_path(cg, ccp, ci, 0, tei);
- else {
- if (con_group_del_path(cg, ccp, ci, 0, tei) < 0) {
- vty_out(vty, "%% No matching CON Path%s",
- VTY_NEWLINE);
- return CMD_WARNING;
- }
- }
-
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_om2k_con_path_conc, cfg_om2k_con_path_conc_cmd,
- "con-path (add|del) <0-2047> <0-255> concentrated <1-16>",
- CON_PATH_HELP "Concentrated in/outlet\n" "Tag Number\n")
-{
- struct con_group *cg = vty->index;
- uint16_t ccp = atoi(argv[1]);
- uint8_t ci = atoi(argv[2]);
- uint8_t tag = atoi(argv[3]);
-
- if (!strcmp(argv[0], "add"))
- con_group_add_path(cg, ccp, ci, tag, 0xff);
- else {
- if (con_group_del_path(cg, ccp, ci, tag, 0xff) < 0) {
- vty_out(vty, "%% No matching CON list entry%s",
- VTY_NEWLINE);
- return CMD_WARNING;
- }
- }
-
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_bts_alt_mode, cfg_bts_alt_mode_cmd,
- "abis-lower-transport (single-timeslot|super-channel)",
- "Configure thee Abis Lower Transport\n"
- "Single Timeslot (classic Abis)\n"
- "SuperChannel (Packet Abis)\n")
-{
- struct gsm_bts *bts = vty->index;
- struct con_group *cg;
-
- if (bts->type != GSM_BTS_TYPE_RBS2000) {
- vty_out(vty, "%% Command only works for RBS2000%s",
- VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- if (!strcmp(argv[0], "super-channel"))
- bts->rbs2000.use_superchannel = 1;
- else
- bts->rbs2000.use_superchannel = 0;
-
- return CMD_SUCCESS;
-}
-
-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 Connection 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 (bts->type != GSM_BTS_TYPE_RBS2000) {
- vty_out(vty, "%% IS MO only exists in RBS2000%s",
- VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- 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_conf_req, om2k_conf_req_cmd,
- "configuration-request",
- "Send the configuration request for current MO\n")
-{
- struct oml_node_state *oms = vty->index;
- struct gsm_bts *bts = oms->bts;
- struct gsm_bts_trx *trx = NULL;
- struct gsm_bts_trx_ts *ts = NULL;
-
- switch (oms->mo.class) {
- case OM2K_MO_CLS_IS:
- abis_om2k_tx_is_conf_req(bts);
- break;
- case OM2K_MO_CLS_TS:
- trx = gsm_bts_trx_by_nr(bts, oms->mo.assoc_so);
- if (!trx) {
- vty_out(vty, "%% BTS %u has no TRX %u%s", bts->nr,
- oms->mo.assoc_so, VTY_NEWLINE);
- return CMD_WARNING;
- }
- if (oms->mo.inst >= ARRAY_SIZE(trx->ts)) {
- vty_out(vty, "%% Timeslot %u out of range%s",
- oms->mo.inst, VTY_NEWLINE);
- return CMD_WARNING;
- }
- ts = &trx->ts[oms->mo.inst];
- abis_om2k_tx_ts_conf_req(ts);
- break;
- case OM2K_MO_CLS_RX:
- case OM2K_MO_CLS_TX:
- case OM2K_MO_CLS_TRXC:
- trx = gsm_bts_trx_by_nr(bts, oms->mo.inst);
- if (!trx) {
- vty_out(vty, "%% BTS %u has no TRX %u%s", bts->nr,
- oms->mo.inst, VTY_NEWLINE);
- return CMD_WARNING;
- }
- switch (oms->mo.class) {
- case OM2K_MO_CLS_RX:
- abis_om2k_tx_rx_conf_req(trx);
- break;
- case OM2K_MO_CLS_TX:
- abis_om2k_tx_tx_conf_req(trx);
- break;
- default:
- break;
- }
- break;
- case OM2K_MO_CLS_TF:
- abis_om2k_tx_tf_conf_req(bts);
- break;
- default:
- vty_out(vty, "%% Don't know how to configure MO%s",
- VTY_NEWLINE);
- }
-
- return CMD_SUCCESS;
-}
-
-static void dump_con_group(struct vty *vty, struct con_group *cg)
-{
- struct con_path *cp;
-
- llist_for_each_entry(cp, &cg->paths, list) {
- vty_out(vty, " con-path add %u %u ", cp->ccp, cp->ci);
- if (cp->tei == 0xff) {
- vty_out(vty, "concentrated %u%s", cp->tag,
- VTY_NEWLINE);
- } else {
- vty_out(vty, "deconcentrated %u%s", cp->tei,
- VTY_NEWLINE);
- }
- }
-}
-
-void abis_om2k_config_write_bts(struct vty *vty, struct gsm_bts *bts)
-{
- struct is_conn_group *igrp;
- struct con_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-group %u%s", cgrp->cg,
- VTY_NEWLINE);
- dump_con_group(vty, cgrp);
- }
- if (bts->rbs2000.use_superchannel)
- vty_out(vty, " abis-lower-transport super-channel%s",
- 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);
-
- vty_install_default(OM2K_NODE);
- 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_cap_req_cmd);
- install_element(OM2K_NODE, &om2k_conf_req_cmd);
-
- install_node(&om2k_con_group_node, dummy_config_write);
- vty_install_default(OM2K_CON_GROUP_NODE);
- install_element(OM2K_CON_GROUP_NODE, &cfg_om2k_con_path_dec_cmd);
- install_element(OM2K_CON_GROUP_NODE, &cfg_om2k_con_path_conc_cmd);
-
- install_element(BTS_NODE, &cfg_bts_is_conn_list_cmd);
- install_element(BTS_NODE, &cfg_bts_alt_mode_cmd);
- install_element(BTS_NODE, &cfg_om2k_con_group_cmd);
- install_element(BTS_NODE, &del_om2k_con_group_cmd);
-
- return 0;
-}
diff --git a/src/libbsc/abis_rsl.c b/src/libbsc/abis_rsl.c
deleted file mode 100644
index 1b575884..00000000
--- a/src/libbsc/abis_rsl.c
+++ /dev/null
@@ -1,2939 +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>
- * (C) 2012 by Holger Hans Peter Freyther
- *
- * All Rights Reserved
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU 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 <arpa/inet.h>
-
-#include <openbsc/gsm_data.h>
-#include <openbsc/gsm_04_08.h>
-#include <osmocom/gsm/gsm_utils.h>
-#include <openbsc/abis_rsl.h>
-#include <openbsc/chan_alloc.h>
-#include <openbsc/bsc_rll.h>
-#include <openbsc/debug.h>
-#include <osmocom/gsm/tlv.h>
-#include <osmocom/gsm/protocol/gsm_04_08.h>
-#include <osmocom/gsm/protocol/gsm_08_58.h>
-#include <openbsc/paging.h>
-#include <openbsc/signal.h>
-#include <openbsc/meas_rep.h>
-#include <openbsc/rtp_proxy.h>
-#include <openbsc/gsm_subscriber.h>
-#include <osmocom/abis/e1_input.h>
-#include <osmocom/gsm/rsl.h>
-#include <osmocom/core/talloc.h>
-#include <openbsc/pcu_if.h>
-
-#define RSL_ALLOC_SIZE 1024
-#define RSL_ALLOC_HEADROOM 128
-
-enum sacch_deact {
- SACCH_NONE,
- SACCH_DEACTIVATE,
-};
-
-static int rsl_send_imm_assignment(struct gsm_lchan *lchan);
-static void error_timeout_cb(void *data);
-static int dyn_ts_switchover_continue(struct gsm_bts_trx_ts *ts);
-static int dyn_ts_switchover_failed(struct gsm_bts_trx_ts *ts, int rc);
-static void dyn_ts_switchover_complete(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;
- osmo_signal_dispatch(SS_LCHAN, sig_no, &sig);
-}
-
-static void do_lchan_free(struct gsm_lchan *lchan)
-{
- /* We start the error timer to make the channel available again */
- if (lchan->state == LCHAN_S_REL_ERR) {
- osmo_timer_setup(&lchan->error_timer, error_timeout_cb, lchan);
- osmo_timer_schedule(&lchan->error_timer,
- lchan->ts->trx->bts->network->T3111 + 2, 0);
- } else {
- rsl_lchan_set_state(lchan, LCHAN_S_NONE);
- }
- lchan_free(lchan);
-}
-
-static void count_codecs(struct gsm_bts *bts, struct gsm_lchan *lchan)
-{
- OSMO_ASSERT(bts);
-
- if (lchan->type == GSM_LCHAN_TCH_H) {
- switch (lchan->tch_mode) {
- case GSM48_CMODE_SPEECH_AMR:
- rate_ctr_inc(&bts->network->bsc_ctrs->ctr[BSC_CTR_CODEC_AMR_H]);
- break;
- case GSM48_CMODE_SPEECH_V1:
- rate_ctr_inc(&bts->network->bsc_ctrs->ctr[BSC_CTR_CODEC_V1_HR]);
- break;
- default:
- break;
- }
- } else if (lchan->type == GSM_LCHAN_TCH_F) {
- switch (lchan->tch_mode) {
- case GSM48_CMODE_SPEECH_AMR:
- rate_ctr_inc(&bts->network->bsc_ctrs->ctr[BSC_CTR_CODEC_AMR_F]);
- break;
- case GSM48_CMODE_SPEECH_V1:
- rate_ctr_inc(&bts->network->bsc_ctrs->ctr[BSC_CTR_CODEC_V1_FR]);
- break;
- case GSM48_CMODE_SPEECH_EFR:
- rate_ctr_inc(&bts->network->bsc_ctrs->ctr[BSC_CTR_CODEC_EFR]);
- break;
- default:
- break;
- }
- }
-}
-
-static uint8_t mdisc_by_msgtype(uint8_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,
- uint8_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;
-}
-
-/* call rsl_lchan_lookup and set the log context */
-static struct gsm_lchan *lchan_lookup(struct gsm_bts_trx *trx, uint8_t chan_nr,
- const char *log_name)
-{
- int rc;
- struct gsm_lchan *lchan = rsl_lchan_lookup(trx, chan_nr, &rc);
-
- if (!lchan) {
- LOGP(DRSL, LOGL_ERROR, "%sunknown chan_nr=0x%02x\n",
- log_name, chan_nr);
- return NULL;
- }
-
- if (rc < 0)
- LOGP(DRSL, LOGL_ERROR, "%s %smismatching chan_nr=0x%02x\n",
- gsm_ts_and_pchan_name(lchan->ts), log_name, chan_nr);
-
- if (lchan->conn)
- log_set_context(LOG_CTX_VLR_SUBSCR, lchan->conn->vsub);
-
- return lchan;
-}
-
-/* As per TS 03.03 Section 2.2, the IMSI has 'not more than 15 digits' */
-uint64_t str_to_imsi(const char *imsi_str)
-{
- uint64_t ret;
-
- ret = strtoull(imsi_str, NULL, 10);
-
- return ret;
-}
-
-static struct msgb *rsl_msgb_alloc(void)
-{
- return msgb_alloc_headroom(RSL_ALLOC_SIZE, RSL_ALLOC_HEADROOM,
- "RSL");
-}
-
-static void pad_macblock(uint8_t *out, const uint8_t *in, int len)
-{
- memcpy(out, in, len);
-
- if (len < GSM_MACBLOCK_LEN)
- memset(out+len, 0x2b, GSM_MACBLOCK_LEN - len);
-}
-
-/* Chapter 9.3.7: Encryption Information */
-static int build_encr_info(uint8_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 uint8_t *cause_v, uint8_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]);
-}
-
-static void lchan_act_tmr_cb(void *data)
-{
- struct gsm_lchan *lchan = data;
-
- rsl_lchan_mark_broken(lchan, "activation timeout");
- lchan_free(lchan);
-}
-
-static void lchan_deact_tmr_cb(void *data)
-{
- struct gsm_lchan *lchan = data;
-
- rsl_lchan_mark_broken(lchan, "de-activation timeout");
- lchan_free(lchan);
-}
-
-
-/* Send a BCCH_INFO message as per Chapter 8.5.1 */
-int rsl_bcch_info(const struct gsm_bts_trx *trx, enum osmo_sysinfo_type si_type, const uint8_t *data, int len)
-{
- struct abis_rsl_dchan_hdr *dh;
- const struct gsm_bts *bts = trx->bts;
- struct msgb *msg = rsl_msgb_alloc();
- uint8_t type = osmo_sitype2rsl(si_type);
-
- if (bts->c0 != trx)
- LOGP(DRR, LOGL_ERROR, "Attempting to set BCCH SI%s on wrong BTS%u/TRX%u\n",
- get_value_string(osmo_sitype_strs, si_type), bts->nr, trx->nr);
-
- 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;
-
- if (trx->bts->type == GSM_BTS_TYPE_RBS2000
- && type == RSL_SYSTEM_INFO_13) {
- /* Ericsson proprietary encoding of SI13 */
- msgb_tv_put(msg, RSL_IE_SYSINFO_TYPE, RSL_ERIC_SYSTEM_INFO_13);
- msgb_tlv_put(msg, RSL_IE_FULL_BCCH_INFO, len, data);
- msgb_tv_put(msg, RSL_IE_ERIC_BCCH_MAPPING, 0x00);
- } else {
- /* Normal encoding */
- msgb_tv_put(msg, RSL_IE_SYSINFO_TYPE, type);
- msgb_tlv_put(msg, RSL_IE_FULL_BCCH_INFO, len, data);
- }
-
- msg->dst = trx->rsl_link;
-
- return abis_rsl_sendmsg(msg);
-}
-
-int rsl_sacch_filling(struct gsm_bts_trx *trx, uint8_t type,
- const uint8_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->dst = trx->rsl_link;
-
- return abis_rsl_sendmsg(msg);
-}
-
-int rsl_sacch_info_modify(struct gsm_lchan *lchan, uint8_t type,
- const uint8_t *data, int len)
-{
- struct abis_rsl_dchan_hdr *dh;
- struct msgb *msg = rsl_msgb_alloc();
- uint8_t chan_nr = gsm_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->dst = lchan->ts->trx->rsl_link;
-
- 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;
- uint8_t chan_nr = gsm_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->dst = lchan->ts->trx->rsl_link;
-
- 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;
- uint8_t chan_nr = gsm_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->dst = lchan->ts->trx->rsl_link;
-
- 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 ? */
- cm->dtx_dtu = 0;
- if (lchan->ts->trx->bts->dtxu != GSM48_DTX_SHALL_NOT_BE_USED)
- cm->dtx_dtu |= RSL_CMOD_DTXu;
- if (lchan->ts->trx->bts->dtxd)
- cm->dtx_dtu |= RSL_CMOD_DTXd;
-
- /* 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:
- LOGP(DRSL, LOGL_ERROR,
- "unsupported activation lchan->type %u %s\n",
- lchan->type, gsm_lchant_name(lchan->type));
- 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:
- case GSM48_CMODE_DATA_12k0:
- case GSM48_CMODE_DATA_6k0:
- switch (lchan->csd_mode) {
- case LCHAN_CSD_M_NT:
- /* non-transparent CSD with RLP */
- switch (lchan->tch_mode) {
- 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:
- LOGP(DRSL, LOGL_ERROR,
- "unsupported lchan->tch_mode %u\n",
- lchan->tch_mode);
- return -EINVAL;
- }
- break;
- /* transparent data services below */
- case LCHAN_CSD_M_T_1200_75:
- cm->chan_rate = RSL_CMOD_CSD_T_1200_75;
- break;
- case LCHAN_CSD_M_T_600:
- cm->chan_rate = RSL_CMOD_CSD_T_600;
- break;
- case LCHAN_CSD_M_T_1200:
- cm->chan_rate = RSL_CMOD_CSD_T_1200;
- break;
- case LCHAN_CSD_M_T_2400:
- cm->chan_rate = RSL_CMOD_CSD_T_2400;
- break;
- case LCHAN_CSD_M_T_9600:
- cm->chan_rate = RSL_CMOD_CSD_T_9600;
- break;
- case LCHAN_CSD_M_T_14400:
- cm->chan_rate = RSL_CMOD_CSD_T_14400;
- break;
- case LCHAN_CSD_M_T_29000:
- cm->chan_rate = RSL_CMOD_CSD_T_29000;
- break;
- case LCHAN_CSD_M_T_32000:
- cm->chan_rate = RSL_CMOD_CSD_T_32000;
- break;
- default:
- LOGP(DRSL, LOGL_ERROR,
- "unsupported lchan->csd_mode %u\n",
- lchan->csd_mode);
- return -EINVAL;
- }
- break;
- default:
- LOGP(DRSL, LOGL_ERROR,
- "unsupported lchan->tch_mode %u\n",
- lchan->tch_mode);
- return -EINVAL;
- }
-
- return 0;
-}
-
-static void mr_config_for_bts(struct gsm_lchan *lchan, struct msgb *msg)
-{
- if (lchan->tch_mode == GSM48_CMODE_SPEECH_AMR)
- msgb_tlv_put(msg, RSL_IE_MR_CONFIG, lchan->mr_bts_lv[0],
- lchan->mr_bts_lv + 1);
-}
-
-static enum gsm_phys_chan_config pchan_for_lchant(enum gsm_chan_t type)
-{
- switch (type) {
- case GSM_LCHAN_TCH_F:
- return GSM_PCHAN_TCH_F;
- case GSM_LCHAN_TCH_H:
- return GSM_PCHAN_TCH_H;
- case GSM_LCHAN_NONE:
- case GSM_LCHAN_PDTCH:
- /* TODO: so far lchan->type is NONE in PDCH mode. PDTCH is only
- * used in osmo-bts. Maybe set PDTCH and drop the NONE case
- * here. */
- return GSM_PCHAN_PDCH;
- default:
- return GSM_PCHAN_UNKNOWN;
- }
-}
-
-/*! Tx simplified channel activation message for non-standard PDCH type. */
-static int rsl_chan_activate_lchan_as_pdch(struct gsm_lchan *lchan)
-{
- struct msgb *msg;
- struct abis_rsl_dchan_hdr *dh;
-
- /* This might be called after release of the second lchan of a TCH/H,
- * but PDCH activation must always happen on the first lchan. Make sure
- * the calling code passes the correct lchan. */
- OSMO_ASSERT(lchan == lchan->ts->lchan);
-
- rsl_lchan_set_state(lchan, LCHAN_S_ACT_REQ);
-
- 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 = gsm_lchan_as_pchan2chan_nr(lchan, GSM_PCHAN_PDCH);
-
- msgb_tv_put(msg, RSL_IE_ACT_TYPE, RSL_ACT_OSMO_PDCH);
-
- if (lchan->ts->trx->bts->type == GSM_BTS_TYPE_RBS2000 &&
- lchan->ts->trx->bts->rbs2000.use_superchannel) {
- const uint8_t eric_pgsl_tmr[] = { 30, 1 };
- msgb_tv_fixed_put(msg, RSL_IE_ERIC_PGSL_TIMERS,
- sizeof(eric_pgsl_tmr), eric_pgsl_tmr);
- }
-
- msg->dst = lchan->ts->trx->rsl_link;
-
- return abis_rsl_sendmsg(msg);
-}
-
-/* Chapter 8.4.1 */
-int rsl_chan_activate_lchan(struct gsm_lchan *lchan, uint8_t act_type,
- uint8_t ho_ref)
-{
- struct abis_rsl_dchan_hdr *dh;
- struct msgb *msg;
- int rc;
- uint8_t *len;
- uint8_t ta;
-
- struct rsl_ie_chan_mode cm;
- struct gsm48_chan_desc cd;
-
- /* If a TCH_F/PDCH TS is in PDCH mode, deactivate PDCH first. */
- if (lchan->ts->pchan == GSM_PCHAN_TCH_F_PDCH
- && (lchan->ts->flags & TS_F_PDCH_ACTIVE)) {
- /* store activation type and handover reference */
- lchan->dyn.act_type = act_type;
- lchan->dyn.ho_ref = ho_ref;
- return rsl_ipacc_pdch_activate(lchan->ts, 0);
- }
-
- /*
- * If necessary, release PDCH on dynamic TS. Note that sending a
- * release here is only necessary when in PDCH mode; for TCH types, an
- * RSL RF Chan Release is initiated by the BTS when a voice call ends,
- * so when we reach this, it will already be released. If a dyn TS is
- * in PDCH mode, it is still active and we need to initiate a release
- * from the BSC side here.
- *
- * If pchan_is != pchan_want, the PDCH has already been taken down and
- * the switchover now needs to enable the TCH lchan.
- *
- * To switch a dyn TS between TCH/H and TCH/F, it is sufficient to send
- * a chan activ with the new lchan type, because it will already be
- * released.
- */
- if (lchan->ts->pchan == GSM_PCHAN_TCH_F_TCH_H_PDCH
- && lchan->ts->dyn.pchan_is == GSM_PCHAN_PDCH
- && lchan->ts->dyn.pchan_is == lchan->ts->dyn.pchan_want) {
- enum gsm_phys_chan_config pchan_want;
- pchan_want = pchan_for_lchant(lchan->type);
- if (lchan->ts->dyn.pchan_is != pchan_want) {
- /*
- * Make sure to record on lchan[0] so that we'll find
- * it after the PDCH release.
- */
- struct gsm_lchan *lchan0 = lchan->ts->lchan;
- lchan0->dyn.act_type = act_type,
- lchan0->dyn.ho_ref = ho_ref;
- lchan0->dyn.rqd_ref = lchan->rqd_ref;
- lchan0->dyn.rqd_ta = lchan->rqd_ta;
- lchan->rqd_ref = NULL;
- lchan->rqd_ta = 0;
- DEBUGP(DRSL, "%s saved rqd_ref=%p ta=%u\n",
- gsm_lchan_name(lchan0), lchan0->rqd_ref,
- lchan0->rqd_ta);
- return dyn_ts_switchover_start(lchan->ts, pchan_want);
- }
- }
-
- DEBUGP(DRSL, "%s Tx RSL Channel Activate with act_type=%s\n",
- gsm_ts_and_pchan_name(lchan->ts),
- rsl_act_type_name(act_type));
-
- if (act_type == RSL_ACT_OSMO_PDCH) {
- if (lchan->ts->pchan != GSM_PCHAN_TCH_F_TCH_H_PDCH) {
- LOGP(DRSL, LOGL_ERROR,
- "%s PDCH channel activation only allowed on %s\n",
- gsm_ts_and_pchan_name(lchan->ts),
- gsm_pchan_name(GSM_PCHAN_TCH_F_TCH_H_PDCH));
- return -EINVAL;
- }
- return rsl_chan_activate_lchan_as_pdch(lchan);
- }
-
- if (lchan->ts->pchan == GSM_PCHAN_TCH_F_TCH_H_PDCH
- && lchan->ts->dyn.pchan_want == GSM_PCHAN_PDCH) {
- LOGP(DRSL, LOGL_ERROR,
- "%s Expected PDCH activation kind\n",
- gsm_ts_and_pchan_name(lchan->ts));
- return -EINVAL;
- }
-
- rc = channel_mode_from_lchan(&cm, lchan);
- if (rc < 0) {
- LOGP(DRSL, LOGL_ERROR,
- "%s Cannot find channel mode from lchan type\n",
- gsm_ts_and_pchan_name(lchan->ts));
- return rc;
- }
-
- rsl_lchan_set_state(lchan, LCHAN_S_ACT_REQ);
-
- ta = lchan->rqd_ta;
-
- /* BS11 requires TA shifted by 2 bits */
- if (lchan->ts->trx->bts->type == GSM_BTS_TYPE_BS11)
- ta <<= 2;
-
- 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);
-
- if (lchan->ts->pchan == GSM_PCHAN_TCH_F_TCH_H_PDCH)
- dh->chan_nr = gsm_lchan_as_pchan2chan_nr(
- lchan, lchan->ts->dyn.pchan_want);
- else
- dh->chan_nr = gsm_lchan2chan_nr(lchan);
-
- msgb_tv_put(msg, RSL_IE_ACT_TYPE, act_type);
- msgb_tlv_put(msg, RSL_IE_CHAN_MODE, sizeof(cm),
- (uint8_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_tv_fixed_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)) {
- uint8_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);
- mr_config_for_bts(lchan, msg);
-
- msg->dst = lchan->ts->trx->rsl_link;
-
- 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;
-
- uint8_t chan_nr = gsm_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),
- (uint8_t *) &cm);
-
- if (lchan->encr.alg_id > RSL_ENC_ALG_A5(0)) {
- uint8_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);
- }
-
- mr_config_for_bts(lchan, msg);
-
- msg->dst = lchan->ts->trx->rsl_link;
-
- 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;
- uint8_t chan_nr = gsm_lchan2chan_nr(lchan);
- uint8_t encr_info[MAX_A5_KEY_LEN+2];
- uint8_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->dst = lchan->ts->trx->rsl_link;
-
- 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 = gsm_lchan2chan_nr(lchan);
-
- msg->lchan = lchan;
- msg->dst = lchan->ts->trx->rsl_link;
-
- DEBUGP(DRSL, "%s DEACTivate SACCH CMD\n", gsm_lchan_name(lchan));
-
- return abis_rsl_sendmsg(msg);
-}
-
-static bool dyn_ts_should_switch_to_pdch(struct gsm_bts_trx_ts *ts)
-{
- int ss;
-
- if (ts->pchan != GSM_PCHAN_TCH_F_TCH_H_PDCH)
- return false;
-
- if (ts->trx->bts->gprs.mode == BTS_GPRS_NONE)
- return false;
-
- /* Already in PDCH mode? */
- if (ts->dyn.pchan_is == GSM_PCHAN_PDCH)
- return false;
-
- /* See if all lchans are released. */
- for (ss = 0; ss < ts_subslots(ts); ss++) {
- struct gsm_lchan *lc = &ts->lchan[ss];
- if (lc->state != LCHAN_S_NONE) {
- DEBUGP(DRSL, "%s lchan %u still in use"
- " (type=%s,state=%s)\n",
- gsm_ts_and_pchan_name(ts), lc->nr,
- gsm_lchant_name(lc->type),
- gsm_lchans_name(lc->state));
- /* An lchan is still used. */
- return false;
- }
- }
-
- /* All channels are released, go to PDCH mode. */
- DEBUGP(DRSL, "%s back to PDCH\n",
- gsm_ts_and_pchan_name(ts));
- return true;
-}
-
-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_INFO, "%s is back in operation.\n", gsm_lchan_name(lchan));
- rsl_lchan_set_state(lchan, LCHAN_S_NONE);
-
- /* Put PDCH channel back into PDCH mode, if GPRS is enabled */
- if (lchan->ts->pchan == GSM_PCHAN_TCH_F_PDCH
- && lchan->ts->trx->bts->gprs.mode != BTS_GPRS_NONE)
- rsl_ipacc_pdch_activate(lchan->ts, 1);
-
- if (dyn_ts_should_switch_to_pdch(lchan->ts))
- dyn_ts_switchover_start(lchan->ts, GSM_PCHAN_PDCH);
-}
-
-static int rsl_rx_rf_chan_rel_ack(struct gsm_lchan *lchan);
-
-/* 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,
- enum sacch_deact deact_sacch)
-{
- struct abis_rsl_dchan_hdr *dh;
- struct msgb *msg;
- int rc;
-
- /* Stop timers that should lead to a channel release */
- osmo_timer_del(&lchan->T3109);
-
- 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 = gsm_lchan2chan_nr(lchan);
-
- msg->lchan = lchan;
- msg->dst = lchan->ts->trx->rsl_link;
-
- if (error)
- DEBUGP(DRSL, "%s RF Channel Release due to error: %d\n",
- gsm_lchan_name(lchan), error);
- else
- DEBUGP(DRSL, "%s RF Channel Release\n", gsm_lchan_name(lchan));
-
- if (error) {
- /*
- * FIXME: GSM 04.08 gives us two options for the abnormal
- * chanel release. This can be either like in the non-existent
- * sub-lcuase 3.5.1 or for the main signalling link deactivate
- * the SACCH, start timer T3109 and consider the channel as
- * released.
- *
- * This code is doing the later for all raido links and not
- * only the main link. Right now all SAPIs are released on the
- * local end, the SACCH will be de-activated and right now the
- * T3111 will be started. First T3109 should be started and then
- * the T3111.
- *
- * TODO: Move this out of the function.
- */
-
- /*
- * sacch de-activate and "local end release"
- */
- if (deact_sacch == SACCH_DEACTIVATE)
- rsl_deact_sacch(lchan);
- rsl_release_sapis_from(lchan, 0, RSL_REL_LOCAL_END);
-
- /*
- * TODO: start T3109 now.
- */
- rsl_lchan_set_state(lchan, LCHAN_S_REL_ERR);
- }
-
- /* Start another timer or assume the BTS sends a ACK/NACK? */
- osmo_timer_setup(&lchan->act_timer, lchan_deact_tmr_cb, lchan);
- osmo_timer_schedule(&lchan->act_timer, 4, 0);
-
- rc = abis_rsl_sendmsg(msg);
-
- /* BTS will respond by RF CHAN REL ACK */
- return rc;
-}
-
-/*
- * Special handling for channel releases in the error case.
- */
-static int rsl_rf_chan_release_err(struct gsm_lchan *lchan)
-{
- enum sacch_deact sacch_deact;
- if (lchan->state != LCHAN_S_ACTIVE)
- return 0;
- switch (ts_pchan(lchan->ts)) {
- case GSM_PCHAN_TCH_F:
- case GSM_PCHAN_TCH_H:
- case GSM_PCHAN_CCCH_SDCCH4:
- case GSM_PCHAN_CCCH_SDCCH4_CBCH:
- case GSM_PCHAN_SDCCH8_SACCH8C:
- case GSM_PCHAN_SDCCH8_SACCH8C_CBCH:
- sacch_deact = SACCH_DEACTIVATE;
- break;
- default:
- sacch_deact = SACCH_NONE;
- break;
- }
- return rsl_rf_chan_release(lchan, 1, sacch_deact);
-}
-
-static int rsl_rx_rf_chan_rel_ack(struct gsm_lchan *lchan)
-{
- struct gsm_bts_trx_ts *ts = lchan->ts;
-
- DEBUGP(DRSL, "%s RF CHANNEL RELEASE ACK\n", gsm_lchan_name(lchan));
-
- /* Stop all pending timers */
- osmo_timer_del(&lchan->act_timer);
- osmo_timer_del(&lchan->T3111);
-
- /*
- * The BTS didn't respond within the timeout to our channel
- * release request and we have marked the channel as broken.
- * Now we do receive an ACK and let's be conservative. If it
- * is a sysmoBTS we know that only one RF Channel Release ACK
- * will be sent. So let's "repair" the channel.
- */
- if (lchan->state == LCHAN_S_BROKEN) {
- int do_free = is_sysmobts_v2(ts->trx->bts);
- LOGP(DRSL, LOGL_NOTICE,
- "%s CHAN REL ACK for broken channel. %s.\n",
- gsm_lchan_name(lchan),
- do_free ? "Releasing it" : "Keeping it broken");
- if (do_free)
- do_lchan_free(lchan);
- if (dyn_ts_should_switch_to_pdch(lchan->ts))
- dyn_ts_switchover_start(lchan->ts, GSM_PCHAN_PDCH);
- return 0;
- }
-
- 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));
-
- do_lchan_free(lchan);
-
- /*
- * Check Osmocom RSL CHAN ACT style dynamic TCH/F_TCH/H_PDCH TS for pending
- * transitions in these cases:
- *
- * a) after PDCH was released due to switchover request, activate TCH.
- * BSC initiated this switchover, so dyn.pchan_is != pchan_want and
- * lchan->type has been set to the desired GSM_LCHAN_*.
- *
- * b) Voice call ended and a TCH is released. If the TS is now unused,
- * switch to PDCH. Here still dyn.pchan_is == dyn.pchan_want because
- * we're only just notified and may decide to switch to PDCH now.
- */
- if (ts->pchan == GSM_PCHAN_TCH_F_TCH_H_PDCH) {
- DEBUGP(DRSL, "%s Rx RSL Channel Release ack for lchan %u\n",
- gsm_ts_and_pchan_name(ts), lchan->nr);
-
- /* (a) */
- if (ts->dyn.pchan_is != ts->dyn.pchan_want)
- return dyn_ts_switchover_continue(ts);
-
- /* (b) */
- if (dyn_ts_should_switch_to_pdch(ts))
- return dyn_ts_switchover_start(ts, GSM_PCHAN_PDCH);
- }
-
- /*
- * Put a dynamic TCH/F_PDCH channel back to PDCH mode iff it was
- * released successfully. If in error, the PDCH ACT will follow after
- * T3111 in error_timeout_cb().
- *
- * Any state other than LCHAN_S_REL_ERR became LCHAN_S_NONE after above
- * do_lchan_free(). Assert this, because that's what ensures a PDCH ACT
- * on a TCH/F_PDCH TS in all cases.
- *
- * If GPRS is disabled, always skip the PDCH ACT.
- */
- OSMO_ASSERT(lchan->state == LCHAN_S_NONE
- || lchan->state == LCHAN_S_REL_ERR);
- if (ts->trx->bts->gprs.mode == BTS_GPRS_NONE)
- return 0;
- if (ts->pchan == GSM_PCHAN_TCH_F_PDCH
- && lchan->state == LCHAN_S_NONE)
- return rsl_ipacc_pdch_activate(ts, 1);
- return 0;
-}
-
-int rsl_paging_cmd(struct gsm_bts *bts, uint8_t paging_group, uint8_t len,
- uint8_t *ms_ident, uint8_t chan_needed, bool is_gprs)
-{
- 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);
-
- /* Ericsson wants to have this IE in case a paging message
- * relates to packet paging */
- if (bts->type == GSM_BTS_TYPE_RBS2000 && is_gprs)
- msgb_tv_put(msg, RSL_IE_ERIC_PACKET_PAG_IND, 0);
-
- msg->dst = bts->c0->rsl_link;
-
- return abis_rsl_sendmsg(msg);
-}
-
-int imsi_str2bcd(uint8_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 */
-struct msgb *rsl_imm_assign_cmd_common(struct gsm_bts *bts, uint8_t len, uint8_t *val)
-{
- struct msgb *msg = rsl_msgb_alloc();
- struct abis_rsl_dchan_hdr *dh;
- uint8_t buf[GSM_MACBLOCK_LEN];
-
- 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, GSM_MACBLOCK_LEN,
- buf);
- break;
- }
-
- msg->dst = bts->c0->rsl_link;
- return msg;
-}
-
-/* Chapter 8.5.6 */
-int rsl_imm_assign_cmd(struct gsm_bts *bts, uint8_t len, uint8_t *val)
-{
- struct msgb *msg = rsl_imm_assign_cmd_common(bts, len, val);
- if (!msg)
- return 1;
- return abis_rsl_sendmsg(msg);
-}
-
-/* Chapter 8.5.6 */
-int rsl_ericsson_imm_assign_cmd(struct gsm_bts *bts, uint32_t tlli, uint8_t len, uint8_t *val)
-{
- struct msgb *msg = rsl_imm_assign_cmd_common(bts, len, val);
- if (!msg)
- return 1;
-
- /* ericsson can handle a reference at the end of the message which is used in
- * the confirm message. The confirm message is only sent if the trailer is present */
- msgb_put_u8(msg, RSL_IE_ERIC_MOBILE_ID);
- msgb_put_u32(msg, tlli);
-
- 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 = gsm_lchan2chan_nr(lchan);
- msgb_tv_put(msg, RSL_IE_SIEMENS_MRPCI, *(uint8_t *)mrpci);
-
- DEBUGP(DRSL, "%s TX Siemens MRPCI 0x%02x\n",
- gsm_lchan_name(lchan), *(uint8_t *)mrpci);
-
- msg->dst = lchan->ts->trx->rsl_link;
-
- 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, uint8_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, gsm_lchan2chan_nr(msg->lchan),
- link_id, 1);
-
- msg->dst = msg->lchan->ts->trx->rsl_link;
-
- 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, uint8_t link_id)
-{
- struct msgb *msg;
-
- msg = rsl_rll_simple(RSL_MT_EST_REQ, gsm_lchan2chan_nr(lchan),
- link_id, 0);
- msg->dst = lchan->ts->trx->rsl_link;
-
- DEBUGP(DRLL, "%s RSL RLL ESTABLISH REQ (link_id=0x%02x)\n",
- gsm_lchan_name(lchan), link_id);
-
- return abis_rsl_sendmsg(msg);
-}
-
-static void rsl_handle_release(struct gsm_lchan *lchan);
-
-/* Special work handler to handle missing RSL_MT_REL_CONF message from
- * Nokia InSite BTS */
-static void lchan_rel_work_cb(void *data)
-{
- struct gsm_lchan *lchan = data;
- int sapi;
-
- for (sapi = 0; sapi < ARRAY_SIZE(lchan->sapis); ++sapi) {
- if (lchan->sapis[sapi] == LCHAN_SAPI_REL)
- lchan->sapis[sapi] = LCHAN_SAPI_UNUSED;
- }
- rsl_handle_release(lchan);
-}
-
-/* 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, uint8_t link_id,
- enum rsl_rel_mode release_mode)
-{
-
- struct msgb *msg;
-
- msg = rsl_rll_simple(RSL_MT_REL_REQ, gsm_lchan2chan_nr(lchan),
- link_id, 0);
- /* 0 is normal release, 1 is local end */
- msgb_tv_put(msg, RSL_IE_RELEASE_MODE, release_mode);
-
- /* FIXME: start some timer in case we don't receive a REL ACK ? */
-
- msg->dst = lchan->ts->trx->rsl_link;
-
- DEBUGP(DRLL, "%s RSL RLL RELEASE REQ (link_id=0x%02x, reason=%u)\n",
- gsm_lchan_name(lchan), link_id, release_mode);
-
- abis_rsl_sendmsg(msg);
-
- /* Do not wait for Nokia BTS to send the confirm. */
- if (is_nokia_bts(lchan->ts->trx->bts)
- && lchan->ts->trx->bts->nokia.no_loc_rel_cnf
- && release_mode == RSL_REL_LOCAL_END) {
- DEBUGP(DRLL, "Scheduling release, becasuse Nokia InSite BTS does not send a RELease CONFirm.\n");
- lchan->sapis[link_id & 0x7] = LCHAN_SAPI_REL;
- osmo_timer_setup(&lchan->rel_work, lchan_rel_work_cb, lchan);
- osmo_timer_schedule(&lchan->rel_work, 0, 0);
- }
-
- return 0;
-}
-
-int rsl_lchan_mark_broken(struct gsm_lchan *lchan, const char *reason)
-{
- LOGP(DRSL, LOGL_ERROR, "%s %s lchan broken: %s\n",
- gsm_lchan_name(lchan), gsm_lchant_name(lchan->type), reason);
- rsl_lchan_set_state(lchan, LCHAN_S_BROKEN);
- lchan->broken_reason = reason;
- return 0;
-}
-
-int rsl_lchan_set_state(struct gsm_lchan *lchan, int state)
-{
- DEBUGP(DRSL, "%s state %s -> %s\n",
- gsm_lchan_name(lchan), gsm_lchans_name(lchan->state),
- gsm_lchans_name(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);
- struct gsm_lchan *lchan = msg->lchan;
- struct gsm_bts_trx_ts *ts = lchan->ts;
-
- /* 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;
-
- osmo_timer_del(&lchan->act_timer);
-
- if (lchan->state == LCHAN_S_BROKEN) {
- int do_release = is_sysmobts_v2(ts->trx->bts);
- LOGP(DRSL, LOGL_NOTICE, "%s CHAN ACT ACK for broken channel. %s\n",
- gsm_lchan_name(lchan),
- do_release ? "Releasing it" : "Keeping it broken");
- if (do_release) {
- talloc_free(lchan->rqd_ref);
- lchan->rqd_ref = NULL;
- lchan->rqd_ta = 0;
- rsl_lchan_set_state(msg->lchan, LCHAN_S_ACTIVE);
- if (ts->pchan == GSM_PCHAN_TCH_F_TCH_H_PDCH) {
- /*
- * lchan_act_tmr_cb() already called
- * lchan_free() and cleared the lchan->type, so
- * calling dyn_ts_switchover_complete() here
- * would not have the desired effect of
- * mimicking an activated lchan that we can
- * release. Instead hack the dyn ts state to
- * make sure that rsl_rx_rf_chan_rel_ack() will
- * switch back to PDCH, i.e. have pchan_is ==
- * pchan_want, both != GSM_PCHAN_PDCH:
- */
- ts->dyn.pchan_is = GSM_PCHAN_NONE;
- ts->dyn.pchan_want = GSM_PCHAN_NONE;
- }
- rsl_rf_chan_release(msg->lchan, 0, SACCH_NONE);
- }
- return 0;
- }
-
- if (lchan->state != LCHAN_S_ACT_REQ)
- LOGP(DRSL, LOGL_NOTICE, "%s CHAN ACT ACK, but state %s\n",
- gsm_lchan_name(lchan),
- gsm_lchans_name(lchan->state));
- rsl_lchan_set_state(lchan, LCHAN_S_ACTIVE);
-
- if (ts->pchan == GSM_PCHAN_TCH_F_TCH_H_PDCH)
- dyn_ts_switchover_complete(lchan);
-
- if (lchan->rqd_ref) {
- rsl_send_imm_assignment(lchan);
- talloc_free(lchan->rqd_ref);
- lchan->rqd_ref = NULL;
- lchan->rqd_ta = 0;
- }
-
- send_lchan_signal(S_LCHAN_ACTIVATE_ACK, lchan, NULL);
-
- /* Update bts attributes inside the PCU */
- if (ts->pchan == GSM_PCHAN_TCH_F_TCH_H_PDCH ||
- ts->pchan == GSM_PCHAN_TCH_F_PDCH ||
- ts->pchan == GSM_PCHAN_PDCH)
- pcu_info_update(ts->trx->bts);
-
- 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;
-
- osmo_timer_del(&msg->lchan->act_timer);
-
- if (msg->lchan->state == LCHAN_S_BROKEN) {
- LOGP(DRSL, LOGL_ERROR,
- "%s CHANNEL ACTIVATE NACK for broken channel.\n",
- gsm_lchan_name(msg->lchan));
- return -1;
- }
-
- 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 uint8_t *cause = TLVP_VAL(&tp, RSL_IE_CAUSE);
- print_rsl_cause(LOGL_ERROR, cause,
- TLVP_LEN(&tp, RSL_IE_CAUSE));
- msg->lchan->error_cause = *cause;
- if (*cause != RSL_ERR_RCH_ALR_ACTV_ALLOC) {
- rsl_lchan_mark_broken(msg->lchan, "NACK on activation");
- } else
- rsl_rf_chan_release(msg->lchan, 1, SACCH_DEACTIVATE);
-
- } else {
- rsl_lchan_mark_broken(msg->lchan, "NACK on activation no IE");
- }
-
- LOGPC(DRSL, LOGL_ERROR, "\n");
-
- send_lchan_signal(S_LCHAN_ACTIVATE_NACK, msg->lchan, NULL);
- 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;
-
- LOGP(DRSL, LOGL_NOTICE, "%s CONNECTION FAIL: RELEASING state %s ",
- gsm_lchan_name(msg->lchan),
- gsm_lchans_name(msg->lchan->state));
-
- 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");
- rate_ctr_inc(&msg->lchan->ts->trx->bts->network->bsc_ctrs->ctr[BSC_CTR_CHAN_RF_FAIL]);
- return rsl_rf_chan_release_err(msg->lchan);
-}
-
-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_lchan *lchan, struct gsm_meas_rep *mr)
-{
- int i;
- const char *name = "";
-
- if (lchan && lchan->conn) {
- if (lchan->conn->bsub)
- name = bsc_subscr_name(lchan->conn->bsub);
- else
- name = lchan->name;
- }
-
- DEBUGP(DMEAS, "[%s] MEASUREMENT RESULT NR=%d ", name, 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 struct gsm_meas_rep *lchan_next_meas_rep(struct gsm_lchan *lchan)
-{
- struct gsm_meas_rep *meas_rep;
-
- meas_rep = &lchan->meas_rep[lchan->meas_rep_idx];
- memset(meas_rep, 0, sizeof(*meas_rep));
- meas_rep->lchan = lchan;
- lchan->meas_rep_idx = (lchan->meas_rep_idx + 1)
- % ARRAY_SIZE(lchan->meas_rep);
-
- return meas_rep;
-}
-
-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);
- uint8_t len;
- const uint8_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)) {
- /* According to 3GPP TS 48.058 § MS Timing Offset = Timing Offset field - 63 */
- mr->ms_timing_offset = *TLVP_VAL(&tp, RSL_IE_MS_TIMING_OFFSET) - 63;
- mr->flags |= MEAS_REP_F_MS_TO;
- }
-
- if (TLVP_PRESENT(&tp, RSL_IE_L1_INFO)) {
- struct e1inp_sign_link *sign_link = msg->dst;
-
- val = TLVP_VAL(&tp, RSL_IE_L1_INFO);
- mr->flags |= MEAS_REP_F_MS_L1;
- mr->ms_l1.pwr = ms_pwr_dbm(sign_link->trx->bts->band, val[0] >> 3);
- if (val[0] & 0x04)
- mr->flags |= MEAS_REP_F_FPC;
- mr->ms_l1.ta = val[1];
- /* BS11 and Nokia reports TA shifted by 2 bits */
- if (msg->lchan->ts->trx->bts->type == GSM_BTS_TYPE_BS11
- || msg->lchan->ts->trx->bts->type == GSM_BTS_TYPE_NOKIA_SITE)
- mr->ms_l1.ta >>= 2;
- }
- if (TLVP_PRESENT(&tp, RSL_IE_L3_INFO)) {
- msg->l3h = (uint8_t *) TLVP_VAL(&tp, RSL_IE_L3_INFO);
- rc = gsm48_parse_meas_rep(mr, msg);
- if (rc < 0)
- return rc;
- }
-
- print_meas_rep(msg->lchan, 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 bool lchan_may_change_pdch(struct gsm_lchan *lchan, bool pdch_act)
-{
- struct gsm_bts_trx_ts *ts;
-
- OSMO_ASSERT(lchan);
-
- ts = lchan->ts;
- OSMO_ASSERT(ts);
- OSMO_ASSERT(ts->trx);
- OSMO_ASSERT(ts->trx->bts);
-
- if (lchan->ts->pchan != GSM_PCHAN_TCH_F_PDCH) {
- LOGP(DRSL, LOGL_ERROR, "%s pchan=%s Rx PDCH %s ACK"
- " for channel that is no TCH/F_PDCH\n",
- gsm_lchan_name(lchan),
- gsm_pchan_name(ts->pchan),
- pdch_act? "ACT" : "DEACT");
- return false;
- }
-
- if (lchan->state != LCHAN_S_NONE) {
- LOGP(DRSL, LOGL_ERROR, "%s pchan=%s Rx PDCH %s ACK"
- " in unexpected state: %s\n",
- gsm_lchan_name(lchan),
- gsm_pchan_name(ts->pchan),
- pdch_act? "ACT" : "DEACT",
- gsm_lchans_name(lchan->state));
- return false;
- }
- return true;
-}
-
-static int rsl_rx_pdch_act_ack(struct msgb *msg)
-{
- if (!lchan_may_change_pdch(msg->lchan, true))
- return -EINVAL;
-
- msg->lchan->ts->flags |= TS_F_PDCH_ACTIVE;
- msg->lchan->ts->flags &= ~TS_F_PDCH_ACT_PENDING;
-
- return 0;
-}
-
-static int rsl_rx_pdch_deact_ack(struct msgb *msg)
-{
- if (!lchan_may_change_pdch(msg->lchan, false))
- return -EINVAL;
-
- msg->lchan->ts->flags &= ~TS_F_PDCH_ACTIVE;
- msg->lchan->ts->flags &= ~TS_F_PDCH_DEACT_PENDING;
-
- rsl_chan_activate_lchan(msg->lchan, msg->lchan->dyn.act_type,
- msg->lchan->dyn.ho_ref);
-
- 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;
- struct e1inp_sign_link *sign_link = msg->dst;
-
- msg->lchan = lchan_lookup(sign_link->trx, rslh->chan_nr,
- "Abis RSL rx DCHAN: ");
- if (!msg->lchan)
- return -1;
- 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);
- count_codecs(sign_link->trx->bts, msg->lchan);
- 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:
- count_codecs(sign_link->trx->bts, msg->lchan);
- 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:
- DEBUGP(DRSL, "%s IPAC PDCH ACT ACK\n", ts_name);
- rc = rsl_rx_pdch_act_ack(msg);
- 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);
- rc = rsl_rx_pdch_deact_ack(msg);
- 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;
- struct e1inp_sign_link *sign_link = msg->dst;
-
- LOGP(DRSL, LOGL_ERROR, "%s ERROR REPORT ", gsm_trx_name(sign_link->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);
- struct e1inp_sign_link *sign_link = msg->dst;
- 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(sign_link->trx));
- break;
- case RSL_MT_OVERLOAD:
- /* indicate CCCH / ACCH / processor overload */
- LOGP(DRSL, LOGL_ERROR, "%s CCCH/ACCH/CPU Overload\n",
- gsm_trx_name(sign_link->trx));
- break;
- case 0x42: /* Nokia specific: SI End ACK */
- LOGP(DRSL, LOGL_INFO, "Nokia SI End ACK\n");
- break;
- case 0x43: /* Nokia specific: SI End NACK */
- LOGP(DRSL, LOGL_INFO, "Nokia SI End NACK\n");
- break;
- default:
- LOGP(DRSL, LOGL_NOTICE, "%s Unknown Abis RSL TRX message "
- "type 0x%02x\n", gsm_trx_name(sign_link->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;
- LOGP(DRSL, LOGL_NOTICE,
- "%s T3101 expired: no response to IMMEDIATE ASSIGN\n",
- gsm_lchan_name(lchan));
- rsl_rf_chan_release(lchan, 1, SACCH_DEACTIVATE);
-}
-
-/* If T3111 expires, we will send the RF Channel Request */
-static void t3111_expired(void *data)
-{
- struct gsm_lchan *lchan = data;
- LOGP(DRSL, LOGL_NOTICE,
- "%s T3111 expired: releasing RF Channel\n",
- gsm_lchan_name(lchan));
- rsl_rf_chan_release(lchan, 0, SACCH_NONE);
-}
-
-/* If T3109 expires the MS has not send a UA/UM do the error release */
-static void t3109_expired(void *data)
-{
- struct gsm_lchan *lchan = data;
-
- LOGP(DRSL, LOGL_ERROR,
- "%s SACCH deactivation timeout.\n", gsm_lchan_name(lchan));
- rsl_rf_chan_release(lchan, 1, SACCH_NONE);
-}
-
-/* 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_REJ;
- 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;
-
- /* we need to subtract 1 byte from sizeof(*iar) since ia includes the l2_plen field */
- iar->l2_plen = GSM48_LEN2PLEN((sizeof(*iar)-1));
-
- return rsl_imm_assign_cmd(bts, sizeof(*iar), (uint8_t *) iar);
-}
-
-/* Handle packet channel rach requests */
-static int rsl_rx_pchan_rqd(struct msgb *msg, struct gsm_bts *bts)
-{
- struct gsm48_req_ref *rqd_ref;
- struct abis_rsl_dchan_hdr *rqd_hdr = msgb_l2(msg);
- rqd_ref = (struct gsm48_req_ref *) &rqd_hdr->data[1];
- uint8_t ra = rqd_ref->ra;
- uint8_t t1, t2, t3;
- uint32_t fn;
- uint8_t rqd_ta;
- uint8_t is_11bit;
-
- /* Process rach request and forward contained information to PCU */
- if (ra == 0x7F) {
- is_11bit = 1;
-
- /* FIXME: Also handle 11 bit rach requests */
- LOGP(DRSL, LOGL_ERROR, "BTS %d eleven bit access burst not supported yet!\n",bts->nr);
- return -EINVAL;
- } else {
- is_11bit = 0;
- t1 = rqd_ref->t1;
- t2 = rqd_ref->t2;
- t3 = rqd_ref->t3_low | (rqd_ref->t3_high << 3);
- fn = (51 * ((t3-t2) % 26) + t3 + 51 * 26 * t1);
-
- rqd_ta = rqd_hdr->data[sizeof(struct gsm48_req_ref)+2];
- }
-
- return pcu_tx_rach_ind(bts, rqd_ta, ra, fn, is_11bit,
- GSM_L1_BURST_TYPE_ACCESS_0);
-}
-
-/* MS has requested a channel on the RACH */
-static int rsl_rx_chan_rqd(struct msgb *msg)
-{
- struct e1inp_sign_link *sign_link = msg->dst;
- struct gsm_bts *bts = sign_link->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;
- uint8_t rqd_ta;
- int is_lu;
-
- uint16_t arfcn;
- uint8_t 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 request cause code */
- chreq_reason = get_reason_by_chreq(rqd_ref->ra, bts->network->neci);
- LOGP(DRSL, LOGL_NOTICE, "BTS %d CHAN RQD: reason: %s (ra=0x%02x, neci=0x%02x, chreq_reason=0x%02x)\n",
- msg->lchan->ts->trx->bts->nr,
- get_value_string(gsm_chreq_descs, chreq_reason),
- rqd_ref->ra, bts->network->neci, chreq_reason);
-
- /* Handle PDCH related rach requests (in case of BSC-co-located-PCU */
- if (chreq_reason == GSM_CHREQ_REASON_PDCH)
- return rsl_rx_pchan_rqd(msg, bts);
-
- /* determine channel type (SDCCH/TCH_F/TCH_H) based on
- * request reference RA */
- lctype = get_ctype_by_chreq(bts->network, rqd_ref->ra);
-
- rate_ctr_inc(&bts->network->bsc_ctrs->ctr[BSC_CTR_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);
- rate_ctr_inc(&bts->network->bsc_ctrs->ctr[BSC_CTR_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 0;
- }
-
- /*
- * Expecting lchan state to be NONE, except for dyn TS in PDCH mode.
- * Those are expected to be ACTIVE: the PDCH release will be sent from
- * rsl_chan_activate_lchan() below.
- */
- if (lchan->state != LCHAN_S_NONE
- && !(lchan->ts->pchan == GSM_PCHAN_TCH_F_TCH_H_PDCH
- && lchan->ts->dyn.pchan_is == GSM_PCHAN_PDCH
- && lchan->state == LCHAN_S_ACTIVE))
- LOGP(DRSL, LOGL_NOTICE, "%s lchan_alloc() returned channel "
- "in state %s\n", gsm_lchan_name(lchan),
- gsm_lchans_name(lchan->state));
-
- /* 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;
-
- 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;
-
- /* Start another timer or assume the BTS sends a ACK/NACK? */
- osmo_timer_setup(&lchan->act_timer, lchan_act_tmr_cb, lchan);
- osmo_timer_schedule(&lchan->act_timer, 4, 0);
-
- DEBUGP(DRSL, "%s Activating ARFCN(%u) SS(%u) lctype %s "
- "r=%s ra=0x%02x ta=%d\n", gsm_lchan_name(lchan), arfcn, subch,
- gsm_lchant_name(lchan->type), gsm_chreq_name(chreq_reason),
- rqd_ref->ra, rqd_ta);
-
- rsl_chan_activate_lchan(lchan, RSL_ACT_INTRA_IMM_ASS, 0);
-
- return 0;
-}
-
-static int rsl_send_imm_assignment(struct gsm_lchan *lchan)
-{
- struct gsm_bts *bts = lchan->ts->trx->bts;
- uint8_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 */
- osmo_timer_setup(&lchan->T3101, t3101_expired, lchan);
- osmo_timer_schedule(&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, (uint8_t *) ia);
-}
-
-/* current load on the CCCH */
-static int rsl_rx_ccch_load(struct msgb *msg)
-{
- struct e1inp_sign_link *sign_link = msg->dst;
- struct abis_rsl_dchan_hdr *rslh = msgb_l2(msg);
- struct ccch_signal_data sd;
-
- sd.bts = sign_link->trx->bts;
- sd.rach_slot_count = -1;
- sd.rach_busy_count = -1;
- sd.rach_access_count = -1;
-
- switch (rslh->data[0]) {
- case RSL_IE_PAGING_LOAD:
- sd.pg_buf_space = rslh->data[1] << 8 | rslh->data[2];
- if (is_ipaccess_bts(sign_link->trx->bts) && sd.pg_buf_space == 0xffff) {
- /* paging load below configured threshold, use 50 as default */
- sd.pg_buf_space = 50;
- }
- paging_update_buffer_space(sign_link->trx->bts, sd.pg_buf_space);
- osmo_signal_dispatch(SS_CCCH, S_CCCH_PAGING_LOAD, &sd);
- break;
- case RSL_IE_RACH_LOAD:
- if (msg->data_len >= 7) {
- sd.rach_slot_count = rslh->data[2] << 8 | rslh->data[3];
- sd.rach_busy_count = rslh->data[4] << 8 | rslh->data[5];
- sd.rach_access_count = rslh->data[6] << 8 | rslh->data[7];
- osmo_signal_dispatch(SS_CCCH, S_CCCH_RACH_LOAD, &sd);
- }
- break;
- default:
- break;
- }
-
- return 0;
-}
-
-static int abis_rsl_rx_cchan(struct msgb *msg)
-{
- struct e1inp_sign_link *sign_link = msg->dst;
- struct abis_rsl_dchan_hdr *rslh = msgb_l2(msg);
- int rc = 0;
- uint32_t tlli;
-
- msg->lchan = lchan_lookup(sign_link->trx, rslh->chan_nr,
- "Abis RSL rx CCHAN: ");
-
- 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;
- case 0x10: /* Ericsson specific: Immediate Assign Sent */
- /* FIXME: Replace the messy message parsing below
- * with proper TV parser */
- LOGP(DRSL, LOGL_INFO, "IMM.ass sent\n");
- if(msg->len < 9)
- LOGP(DRSL, LOGL_ERROR, "short IMM.ass sent message!\n");
- else if(msg->data[4] != 0xf1)
- LOGP(DRSL, LOGL_ERROR, "unsupported IMM.ass message format! (please fix)\n");
- else {
- msgb_pull(msg, 5); /* drop previous data to use msg_pull_u32 */
- tlli = msgb_pull_u32(msg);
- pcu_tx_imm_ass_sent(sign_link->trx->bts, tlli);
- }
- 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 tlv_parsed tp;
- struct abis_rsl_rll_hdr *rllh = msgb_l2(msg);
- uint8_t rlm_cause;
-
- rsl_tlv_parse(&tp, rllh->data, msgb_l2len(msg) - sizeof(*rllh));
- if (!TLVP_PRESENT(&tp, RSL_IE_RLM_CAUSE)) {
- LOGP(DRLL, LOGL_ERROR,
- "%s ERROR INDICATION without mandantory cause.\n",
- gsm_lchan_name(msg->lchan));
- return -1;
- }
-
- rlm_cause = *TLVP_VAL(&tp, RSL_IE_RLM_CAUSE);
- LOGP(DRLL, LOGL_ERROR, "%s ERROR INDICATION cause=%s in state=%s\n",
- gsm_lchan_name(msg->lchan),
- rsl_rlm_cause_name(rlm_cause),
- gsm_lchans_name(msg->lchan->state));
-
- rll_indication(msg->lchan, rllh->link_id, BSC_RLLR_IND_ERR_IND);
-
- if (rlm_cause == RLL_CAUSE_T200_EXPIRED) {
- rate_ctr_inc(&msg->lchan->ts->trx->bts->network->bsc_ctrs->ctr[BSC_CTR_CHAN_RLL_ERR]);
- return rsl_rf_chan_release_err(msg->lchan);
- }
-
- return 0;
-}
-
-static void rsl_handle_release(struct gsm_lchan *lchan)
-{
- int sapi;
- struct gsm_bts *bts;
-
- /*
- * Maybe only one link/SAPI was releasd or the error handling
- * was activated. Just return now and let the other code handle
- * it.
- */
- 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;
- }
-
-
- /* Stop T3109 and wait for T3111 before re-using the channel */
- osmo_timer_del(&lchan->T3109);
- osmo_timer_setup(&lchan->T3111, t3111_expired, lchan);
- bts = lchan->ts->trx->bts;
- osmo_timer_schedule(&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 e1inp_sign_link *sign_link = msg->dst;
- struct abis_rsl_rll_hdr *rllh = msgb_l2(msg);
- int rc = 0;
- char *ts_name;
- uint8_t sapi = rllh->link_id & 7;
-
- msg->lchan = lchan_lookup(sign_link->trx, rllh->chan_nr,
- "Abis RSL rx RLL: ");
- 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;
- osmo_timer_del(&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);
- 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);
- break;
- case RSL_MT_ERROR_IND:
- DEBUGPC(DRLL, "ERROR INDICATION\n");
- rc = rsl_rx_rll_err_ind(msg);
- break;
- case RSL_MT_UNIT_DATA_IND:
- DEBUGPC(DRLL, "UNIT DATA INDICATION\n");
- LOGP(DRLL, LOGL_NOTICE, "unimplemented Abis RLL message "
- "type 0x%02x\n", rllh->c.msg_type);
- break;
- default:
- DEBUGPC(DRLL, "UNKNOWN\n");
- LOGP(DRLL, LOGL_NOTICE, "unknown Abis RLL message "
- "type 0x%02x\n", rllh->c.msg_type);
- }
- return rc;
-}
-
-static uint8_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;
- }
- break;
- case GSM48_CMODE_SPEECH_EFR:
- switch (lchan->type) {
- case GSM_LCHAN_TCH_F:
- return 0x01;
- /* there's no half-rate EFR */
- default:
- break;
- }
- 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;
- }
- 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 uint8_t ipa_rtp_pt_for_lchan(struct gsm_lchan *lchan)
-{
- 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;
- }
- 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;
- }
- break;
- case GSM48_CMODE_SPEECH_AMR:
- switch (lchan->type) {
- case GSM_LCHAN_TCH_F:
- case GSM_LCHAN_TCH_H:
- return RTP_PT_AMR;
- default:
- break;
- }
- 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;
- uint16_t port, conn_id;
-
- if (TLVP_PRESENT(tv, RSL_IE_IPAC_LOCAL_IP)) {
- ip.s_addr = tlvp_val32_unal(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 = tlvp_val16_unal(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 = tlvp_val16_unal(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 = tlvp_val32_unal(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 = tlvp_val16_unal(tv, RSL_IE_IPAC_REMOTE_PORT);
- port = ntohs(port);
- DEBUGPC(DRSL, "REMOTE_PORT=%u ", port);
- lchan->abis_ip.connect_port = port;
- }
-
- DEBUGPC(DRSL, "\n");
-}
-
-/*! \brief Issue IPA RSL CRCX to configure RTP on BTS side
- * \param[in] lchan Logical Channel for which we issue CRCX
- */
-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 = gsm_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->dst = lchan->ts->trx->rsl_link;
-
- return abis_rsl_sendmsg(msg);
-}
-
-/*! \brief Issue IPA RSL MDCX to configure MGW-side of RTP
- * \param[in] lchan Logical Channel for which we issue MDCX
- * \param[in] ip Remote (MGW) IP address for RTP
- * \param[in] port Remote (MGW) UDP port number for RTP
- * \param[in] rtp_payload2 Contents of RTP PAYLOAD 2 IE
- */
-int rsl_ipacc_mdcx(struct gsm_lchan *lchan, uint32_t ip, uint16_t port,
- uint8_t rtp_payload2)
-{
- struct msgb *msg = rsl_msgb_alloc();
- struct abis_rsl_dchan_hdr *dh;
- uint32_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 = gsm_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 = (uint32_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->dst = lchan->ts->trx->rsl_link;
-
- 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;
- uint8_t msg_type;
-
- if (ts->flags & TS_F_PDCH_PENDING_MASK) {
- LOGP(DRSL, LOGL_ERROR,
- "%s PDCH %s requested, but a PDCH%s%s is still pending\n",
- gsm_ts_name(ts),
- act ? "ACT" : "DEACT",
- ts->flags & TS_F_PDCH_ACT_PENDING? " ACT" : "",
- ts->flags & TS_F_PDCH_DEACT_PENDING? " DEACT" : "");
- return -EINVAL;
- }
-
- if (act){
- /* Callers should heed the GPRS mode. */
- OSMO_ASSERT(ts->trx->bts->gprs.mode != BTS_GPRS_NONE);
- msg_type = RSL_MT_IPAC_PDCH_ACT;
- ts->flags |= TS_F_PDCH_ACT_PENDING;
- } else {
- msg_type = RSL_MT_IPAC_PDCH_DEACT;
- ts->flags |= TS_F_PDCH_DEACT_PENDING;
- }
- /* TODO add timeout to cancel PDCH DE/ACT */
-
- 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 = gsm_pchan2chan_nr(GSM_PCHAN_PDCH, ts->nr, 0);
-
- DEBUGP(DRSL, "%s IPAC PDCH %sACT\n", gsm_ts_name(ts),
- act ? "" : "DE");
-
- msg->dst = ts->trx->rsl_link;
-
- 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);
-
- osmo_signal_dispatch(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);
- osmo_signal_dispatch(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));
-
- osmo_signal_dispatch(SS_ABISIP, S_ABISIP_DLCX_IND, msg->lchan);
-
- return 0;
-}
-
-static int abis_rsl_rx_ipacc(struct msgb *msg)
-{
- struct e1inp_sign_link *sign_link = msg->dst;
- struct abis_rsl_rll_hdr *rllh = msgb_l2(msg);
- char *ts_name;
- int rc = 0;
-
- msg->lchan = lchan_lookup(sign_link->trx, rllh->chan_nr,
- "Abis RSL rx IPACC: ");
- 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;
- }
-
- return rc;
-}
-
-int dyn_ts_switchover_start(struct gsm_bts_trx_ts *ts,
- enum gsm_phys_chan_config to_pchan)
-{
- int ss;
- int rc = -EIO;
-
- OSMO_ASSERT(ts->pchan == GSM_PCHAN_TCH_F_TCH_H_PDCH);
- DEBUGP(DRSL, "%s starting switchover to %s\n",
- gsm_ts_and_pchan_name(ts), gsm_pchan_name(to_pchan));
-
- if (ts->dyn.pchan_is != ts->dyn.pchan_want) {
- LOGP(DRSL, LOGL_ERROR,
- "%s: Attempt to switch dynamic channel to %s,"
- " but is already in switchover.\n",
- gsm_ts_and_pchan_name(ts),
- gsm_pchan_name(to_pchan));
- return ts->dyn.pchan_want == to_pchan? 0 : -EAGAIN;
- }
-
- if (ts->dyn.pchan_is == to_pchan) {
- LOGP(DRSL, LOGL_INFO,
- "%s %s Already is in %s mode, cannot switchover.\n",
- gsm_ts_name(ts), gsm_pchan_name(ts->pchan),
- gsm_pchan_name(to_pchan));
- return -EINVAL;
- }
-
- /* Paranoia: let's make sure all is indeed released. */
- for (ss = 0; ss < ts_subslots(ts); ss++) {
- struct gsm_lchan *lc = &ts->lchan[ss];
- if (lc->state != LCHAN_S_NONE) {
- LOGP(DRSL, LOGL_ERROR,
- "%s Attempt to switch dynamic channel to %s,"
- " but is not fully released.\n",
- gsm_ts_and_pchan_name(ts),
- gsm_pchan_name(to_pchan));
- return -EAGAIN;
- }
- }
-
- /* Record that we're busy switching. */
- ts->dyn.pchan_want = to_pchan;
-
- /*
- * To switch from PDCH, we need to initiate the release from the BSC
- * side. dyn_ts_switchover_continue() will be called from
- * rsl_rx_rf_chan_rel_ack(). PDCH is always on lchan[0].
- */
- if (ts->dyn.pchan_is == GSM_PCHAN_PDCH) {
- rsl_lchan_set_state(ts->lchan, LCHAN_S_REL_REQ);
- rc = rsl_rf_chan_release(ts->lchan, 0, SACCH_NONE);
- if (rc) {
- LOGP(DRSL, LOGL_ERROR,
- "%s RSL RF Chan Release failed\n",
- gsm_ts_and_pchan_name(ts));
- return dyn_ts_switchover_failed(ts, rc);
- }
- return 0;
- }
-
- /*
- * To switch from TCH/F and TCH/H pchans, this has been called from
- * rsl_rx_rf_chan_rel_ack(), i.e. release is complete. Go ahead and
- * activate as new type. This will always be PDCH.
- */
- return dyn_ts_switchover_continue(ts);
-}
-
-static int dyn_ts_switchover_continue(struct gsm_bts_trx_ts *ts)
-{
- int rc;
- uint8_t act_type;
- uint8_t ho_ref;
- int ss;
- struct gsm_lchan *lchan;
-
- OSMO_ASSERT(ts->pchan == GSM_PCHAN_TCH_F_TCH_H_PDCH);
- DEBUGP(DRSL, "%s switchover: release complete,"
- " activating new pchan type\n",
- gsm_ts_and_pchan_name(ts));
-
- if (ts->dyn.pchan_is == ts->dyn.pchan_want) {
- LOGP(DRSL, LOGL_ERROR,
- "%s Requested to switchover dynamic channel to the"
- " same type it is already in.\n",
- gsm_ts_and_pchan_name(ts));
- return 0;
- }
-
- for (ss = 0; ss < ts_subslots(ts); ss++) {
- lchan = &ts->lchan[ss];
- if (lchan->rqd_ref) {
- LOGP(DRSL, LOGL_ERROR,
- "%s During dyn TS switchover, expecting no"
- " Request Reference to be pending. Discarding!\n",
- gsm_lchan_name(lchan));
- talloc_free(lchan->rqd_ref);
- lchan->rqd_ref = NULL;
- }
- }
-
- /*
- * When switching pchan modes, all lchans are unused. So always
- * activate whatever wants to be activated on the first lchan. (We
- * wouldn't remember to use lchan[1] across e.g. a PDCH deact anyway)
- */
- lchan = ts->lchan;
-
- /*
- * For TCH/x, the lchan->type has been set in lchan_alloc(), but it may
- * have been lost during channel release due to dynamic switchover.
- *
- * For PDCH, the lchan->type will actually remain NONE.
- * TODO: set GSM_LCHAN_PDTCH?
- */
- switch (ts->dyn.pchan_want) {
- case GSM_PCHAN_TCH_F:
- lchan->type = GSM_LCHAN_TCH_F;
- break;
- case GSM_PCHAN_TCH_H:
- lchan->type = GSM_LCHAN_TCH_H;
- break;
- case GSM_PCHAN_PDCH:
- lchan->type = GSM_LCHAN_NONE;
- break;
- default:
- LOGP(DRSL, LOGL_ERROR,
- "%s Invalid target pchan for dynamic TS\n",
- gsm_ts_and_pchan_name(ts));
- }
-
- act_type = (ts->dyn.pchan_want == GSM_PCHAN_PDCH)
- ? RSL_ACT_OSMO_PDCH
- : lchan->dyn.act_type;
- ho_ref = (ts->dyn.pchan_want == GSM_PCHAN_PDCH)
- ? 0
- : lchan->dyn.ho_ref;
-
- /* Fetch the rqd_ref back from before switchover started. */
- lchan->rqd_ref = lchan->dyn.rqd_ref;
- lchan->rqd_ta = lchan->dyn.rqd_ta;
- lchan->dyn.rqd_ref = NULL;
- lchan->dyn.rqd_ta = 0;
-
- /* During switchover, we have received a release ack, which means that
- * the act_timer has been stopped. Start the timer again so we mark
- * this channel broken if the activation ack comes too late. */
- osmo_timer_setup(&lchan->act_timer, lchan_act_tmr_cb, lchan);
- osmo_timer_schedule(&lchan->act_timer, 4, 0);
-
- rc = rsl_chan_activate_lchan(lchan, act_type, ho_ref);
- if (rc) {
- LOGP(DRSL, LOGL_ERROR,
- "%s RSL Chan Activate failed\n",
- gsm_ts_and_pchan_name(ts));
- return dyn_ts_switchover_failed(ts, rc);
- }
- return 0;
-}
-
-static int dyn_ts_switchover_failed(struct gsm_bts_trx_ts *ts, int rc)
-{
- ts->dyn.pchan_want = ts->dyn.pchan_is;
- LOGP(DRSL, LOGL_ERROR, "%s Error %d during dynamic channel switchover."
- " Going back to previous pchan.\n", gsm_ts_and_pchan_name(ts),
- rc);
- return rc;
-}
-
-static void dyn_ts_switchover_complete(struct gsm_lchan *lchan)
-{
- enum gsm_phys_chan_config pchan_act;
- enum gsm_phys_chan_config pchan_was;
- struct gsm_bts_trx_ts *ts = lchan->ts;
-
- OSMO_ASSERT(ts->pchan == GSM_PCHAN_TCH_F_TCH_H_PDCH);
-
- pchan_act = pchan_for_lchant(lchan->type);
- /*
- * Paranoia: do the types match?
- * In case of errors: we've received an act ack already, so what to do
- * about it? Logging the error should suffice for now.
- */
- if (pchan_act != ts->dyn.pchan_want)
- LOGP(DRSL, LOGL_ERROR,
- "%s Requested transition does not match lchan type %s\n",
- gsm_ts_and_pchan_name(ts),
- gsm_lchant_name(lchan->type));
-
- pchan_was = ts->dyn.pchan_is;
- ts->dyn.pchan_is = ts->dyn.pchan_want = pchan_act;
-
- if (pchan_was != ts->dyn.pchan_is)
- LOGP(DRSL, LOGL_INFO, "%s switchover from %s complete.\n",
- gsm_ts_and_pchan_name(ts), gsm_pchan_name(pchan_was));
-}
-
-/* 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));
- msgb_free(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);
- rc = -EINVAL;
- }
- msgb_free(msg);
- return rc;
-}
-
-int rsl_sms_cb_command(struct gsm_bts *bts, uint8_t chan_number,
- struct rsl_ie_cb_cmd_type 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->c.msg_discr = ABIS_RSL_MDISC_COM_CHAN;
- dh->chan_nr = chan_number; /* TODO: check the chan config */
-
- msgb_tv_put(cb_cmd, RSL_IE_CB_CMD_TYPE, *(uint8_t*)&cb_command);
- msgb_tlv_put(cb_cmd, RSL_IE_SMSCB_MSG, len, data);
-
- cb_cmd->dst = bts->c0->rsl_link;
-
- return abis_rsl_sendmsg(cb_cmd);
-}
-
-int rsl_nokia_si_begin(struct gsm_bts_trx *trx)
-{
- 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 = 0x40; /* Nokia SI Begin */
-
- msg->dst = trx->rsl_link;
-
- return abis_rsl_sendmsg(msg);
-}
-
-int rsl_nokia_si_end(struct gsm_bts_trx *trx)
-{
- 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 = 0x41; /* Nokia SI End */
-
- msgb_tv_put(msg, 0xFD, 0x00); /* Nokia Pagemode Info, No paging reorganisation required */
-
- msg->dst = trx->rsl_link;
-
- return abis_rsl_sendmsg(msg);
-}
-
-int rsl_bs_power_control(struct gsm_bts_trx *trx, uint8_t channel, uint8_t reduction)
-{
- 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_DED_CHAN;
- ch->msg_type = RSL_MT_BS_POWER_CONTROL;
-
- msgb_tv_put(msg, RSL_IE_CHAN_NR, channel);
- msgb_tv_put(msg, RSL_IE_BS_POWER, reduction); /* reduction in 2dB steps */
-
- msg->dst = trx->rsl_link;
-
- return abis_rsl_sendmsg(msg);
-}
-
-/**
- * Release all allocated SAPIs starting from @param start and
- * release them with the given release mode. Once the release
- * confirmation arrives it will be attempted to release the
- * the RF channel.
- */
-int rsl_release_sapis_from(struct gsm_lchan *lchan, int start,
- enum rsl_rel_mode release_mode)
-{
- int no_sapi = 1;
- int sapi;
-
- for (sapi = start; sapi < ARRAY_SIZE(lchan->sapis); ++sapi) {
- uint8_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, release_mode);
- no_sapi = 0;
- }
-
- return no_sapi;
-}
-
-int rsl_start_t3109(struct gsm_lchan *lchan)
-{
- struct gsm_bts *bts = lchan->ts->trx->bts;
-
- /* Disabled, mostly legacy code */
- if (bts->network->T3109 == 0)
- return -1;
-
- osmo_timer_setup(&lchan->T3109, t3109_expired, lchan);
- osmo_timer_schedule(&lchan->T3109, bts->network->T3109, 0);
- return 0;
-}
-
-/**
- * \brief directly RF Channel Release the lchan
- *
- * When no SAPI was allocated, directly release the logical channel. This
- * should only be called from chan_alloc.c on channel release handling. In
- * case no SAPI was established the RF Channel can be directly released,
- */
-int rsl_direct_rf_release(struct gsm_lchan *lchan)
-{
- int i;
- for (i = 0; i < ARRAY_SIZE(lchan->sapis); ++i) {
- if (lchan->sapis[i] != LCHAN_SAPI_UNUSED) {
- LOGP(DRSL, LOGL_ERROR, "%s SAPI(%d) still allocated.\n",
- gsm_lchan_name(lchan), i);
- return -1;
- }
- }
-
- /* Now release it */
- return rsl_rf_chan_release(lchan, 0, SACCH_NONE);
-}
diff --git a/src/libbsc/arfcn_range_encode.c b/src/libbsc/arfcn_range_encode.c
deleted file mode 100644
index 9ca48407..00000000
--- a/src/libbsc/arfcn_range_encode.c
+++ /dev/null
@@ -1,330 +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) 2012 Holger Hans Peter Freyther
- * (C) 2012 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/arfcn_range_encode.h>
-#include <openbsc/debug.h>
-
-#include <osmocom/gsm/protocol/gsm_04_08.h>
-
-#include <osmocom/core/utils.h>
-
-#include <errno.h>
-
-static inline int greatest_power_of_2_lesser_or_equal_to(int index)
-{
- int power_of_2 = 1;
-
- do {
- power_of_2 *= 2;
- } while (power_of_2 <= index);
-
- /* now go back one step */
- return power_of_2 / 2;
-}
-
-static inline int mod(int data, int range)
-{
- int res = data % range;
- while (res < 0)
- res += range;
- return res;
-}
-
-/**
- * Determine at which index to split the ARFCNs to create an
- * equally size partition for the given range. Return -1 if
- * no such partition exists.
- */
-int range_enc_find_index(enum gsm48_range range, const int *freqs, const int size)
-{
- int i, j, n;
-
- const int RANGE_DELTA = (range - 1) / 2;
-
- for (i = 0; i < size; ++i) {
- n = 0;
- for (j = 0; j < size; ++j) {
- if (mod(freqs[j] - freqs[i], range) <= RANGE_DELTA)
- n += 1;
- }
-
- if (n - 1 == (size - 1) / 2)
- return i;
- }
-
- return -1;
-}
-
-/**
- * Range encode the ARFCN list.
- * \param range The range to use.
- * \param arfcns The list of ARFCNs
- * \param size The size of the list of ARFCNs
- * \param out Place to store the W(i) output.
- */
-int range_enc_arfcns(enum gsm48_range range,
- const int *arfcns, int size, int *out,
- const int index)
-{
- int split_at;
- int i;
-
- /*
- * The below is a GNU extension and we can remove it when
- * we move to a quicksort like in-situ swap with the pivot.
- */
- int arfcns_left[size / 2];
- int arfcns_right[size / 2];
- int l_size;
- int r_size;
- int l_origin;
- int r_origin;
-
-
- /* Test the two recursion anchors and stop processing */
- if (size == 0)
- return 0;
-
- if (size == 1) {
- out[index] = 1 + arfcns[0];
- return 0;
- }
-
- /* Now do the processing */
- split_at = range_enc_find_index(range, arfcns, size);
- if (split_at < 0)
- return -EINVAL;
-
- /* we now know where to split */
- out[index] = 1 + arfcns[split_at];
-
- /* calculate the work that needs to be done for the leafs */
- l_origin = mod(arfcns[split_at] + ((range - 1) / 2) + 1, range);
- r_origin = mod(arfcns[split_at] + 1, range);
- for (i = 0, l_size = 0, r_size = 0; i < size; ++i) {
- if (mod(arfcns[i] - l_origin, range) < range / 2)
- arfcns_left[l_size++] = mod(arfcns[i] - l_origin, range);
- if (mod(arfcns[i] - r_origin, range) < range / 2)
- arfcns_right[r_size++] = mod(arfcns[i] - r_origin, range);
- }
-
- /*
- * Now recurse and we need to make this iterative... but as the
- * tree is balanced the stack will not be too deep.
- */
- if (l_size)
- range_enc_arfcns(range / 2, arfcns_left, l_size,
- out, index + greatest_power_of_2_lesser_or_equal_to(index + 1));
- if (r_size)
- range_enc_arfcns((range - 1) / 2, arfcns_right, r_size,
- out, index + (2 * greatest_power_of_2_lesser_or_equal_to(index + 1)));
- return 0;
-}
-
-/*
- * The easiest is to use f0 == arfcns[0]. This means that under certain
- * circumstances we can encode less ARFCNs than possible with an optimal f0.
- *
- * TODO: Solve the optimisation problem and pick f0 so that the max distance
- * is the smallest. Taking into account the modulo operation. I think picking
- * size/2 will be the optimal arfcn.
- */
-/**
- * This implements the range determination as described in GSM 04.08 J4. The
- * result will be a base frequency f0 and the range to use. Note that for range
- * 1024 encoding f0 always refers to ARFCN 0 even if it is not an element of
- * the arfcns list.
- *
- * \param[in] arfcns The input frequencies, they must be sorted, lowest number first
- * \param[in] size The length of the array
- * \param[out] f0 The selected F0 base frequency. It might not be inside the list
- */
-int range_enc_determine_range(const int *arfcns, const int size, int *f0)
-{
- int max = 0;
-
- /*
- * Go for the easiest. And pick arfcns[0] == f0.
- */
- max = arfcns[size - 1] - arfcns[0];
- *f0 = arfcns[0];
-
- if (max < 128 && size <= 29)
- return ARFCN_RANGE_128;
- if (max < 256 && size <= 22)
- return ARFCN_RANGE_256;
- if (max < 512 && size <= 18)
- return ARFCN_RANGE_512;
- if (max < 1024 && size <= 17) {
- *f0 = 0;
- return ARFCN_RANGE_1024;
- }
-
- return ARFCN_RANGE_INVALID;
-}
-
-static void write_orig_arfcn(uint8_t *chan_list, int f0)
-{
- chan_list[0] |= (f0 >> 9) & 1;
- chan_list[1] = (f0 >> 1);
- chan_list[2] = (f0 & 1) << 7;
-}
-
-static void write_all_wn(uint8_t *chan_list, int bit_offs,
- int *w, int w_size, int w1_len)
-{
- int octet_offs = 0; /* offset into chan_list */
- int wk_len = w1_len; /* encoding size in bits of w[k] */
- int k; /* 1 based */
- int level = 0; /* tree level, top level = 0 */
- int lvl_left = 1; /* nodes per tree level */
-
- /* W(2^i) to W(2^(i+1)-1) are on w1_len-i bits when present */
-
- for (k = 1; k <= w_size; k++) {
- int wk_left = wk_len;
- DEBUGP(DRR,
- "k=%d, wk_len=%d, offs=%d:%d, level=%d, "
- "lvl_left=%d\n",
- k, wk_len, octet_offs, bit_offs, level, lvl_left);
-
- while (wk_left > 0) {
- int cur_bits = 8 - bit_offs;
- int cur_mask;
- int wk_slice;
-
- if (cur_bits > wk_left)
- cur_bits = wk_left;
-
- cur_mask = ((1 << cur_bits) - 1);
-
- DEBUGP(DRR,
- " wk_left=%d, cur_bits=%d, offs=%d:%d\n",
- wk_left, cur_bits, octet_offs, bit_offs);
-
- /* advance */
- wk_left -= cur_bits;
- bit_offs += cur_bits;
-
- /* right aligned wk data for current out octet */
- wk_slice = (w[k-1] >> wk_left) & cur_mask;
-
- /* cur_bits now contains the number of bits
- * that are to be copied from wk to the chan_list.
- * wk_left is set to the number of bits that must
- * not yet be copied.
- * bit_offs points after the bit area that is going to
- * be overwritten:
- *
- * wk_left
- * |
- * v
- * wk: WWWWWWWWWWW
- * |||||<-- wk_slice, cur_bits=5
- * --WWWWW-
- * ^
- * |
- * bit_offs
- */
-
- DEBUGP(DRR,
- " wk=%02x, slice=%02x/%02x, cl=%02x\n",
- w[k-1], wk_slice, cur_mask, wk_slice << (8 - bit_offs));
-
- chan_list[octet_offs] &= ~(cur_mask << (8 - bit_offs));
- chan_list[octet_offs] |= wk_slice << (8 - bit_offs);
-
- /* adjust output */
- if (bit_offs == 8) {
- bit_offs = 0;
- octet_offs += 1;
- }
- }
-
- /* adjust bit sizes */
- lvl_left -= 1;
- if (!lvl_left) {
- /* completed tree level, advance to next */
- level += 1;
- lvl_left = 1 << level;
- wk_len -= 1;
- }
- }
-}
-
-int range_enc_range128(uint8_t *chan_list, int f0, int *w)
-{
- chan_list[0] = 0x8C;
- write_orig_arfcn(chan_list, f0);
-
- write_all_wn(&chan_list[2], 1, w, 28, 7);
- return 0;
-}
-
-int range_enc_range256(uint8_t *chan_list, int f0, int *w)
-{
- chan_list[0] = 0x8A;
- write_orig_arfcn(chan_list, f0);
-
- write_all_wn(&chan_list[2], 1, w, 21, 8);
- return 0;
-}
-
-int range_enc_range512(uint8_t *chan_list, int f0, int *w)
-{
- chan_list[0] = 0x88;
- write_orig_arfcn(chan_list, f0);
-
- write_all_wn(&chan_list[2], 1, w, 17, 9);
- return 0;
-}
-
-int range_enc_range1024(uint8_t *chan_list, int f0, int f0_included, int *w)
-{
- chan_list[0] = 0x80 | (f0_included << 2);
-
- write_all_wn(&chan_list[0], 6, w, 16, 10);
- return 0;
-}
-
-int range_enc_filter_arfcns(int *arfcns,
- const int size, const int f0, int *f0_included)
-{
- int i, j = 0;
- *f0_included = 0;
-
- for (i = 0; i < size; ++i) {
- /*
- * Appendix J.4 says the following:
- * All frequencies except F(0), minus F(0) + 1.
- * I assume we need to exclude it here.
- */
- if (arfcns[i] == f0) {
- *f0_included = 1;
- continue;
- }
-
- arfcns[j++] = mod(arfcns[i] - (f0 + 1), 1024);
- }
-
- return j;
-}
diff --git a/src/libbsc/bsc_api.c b/src/libbsc/bsc_api.c
deleted file mode 100644
index 947644eb..00000000
--- a/src/libbsc/bsc_api.c
+++ /dev/null
@@ -1,896 +0,0 @@
-/* GSM 08.08 like API for OpenBSC. The bridge from MSC to BSC */
-
-/* (C) 2010-2011 by Holger Hans Peter Freyther
- * (C) 2010-2011 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 <openbsc/trau_mux.h>
-#include <openbsc/vlr.h>
-
-#include <osmocom/gsm/protocol/gsm_08_08.h>
-#include <osmocom/gsm/gsm48.h>
-
-#include <osmocom/core/talloc.h>
-
-#define GSM0808_T10_VALUE 6, 0
-
-
-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 uint8_t lchan_to_chosen_channel(struct gsm_lchan *lchan)
-{
- uint8_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:
- default:
- LOGP(DMSC, LOGL_ERROR, "Unknown lchan type: %p\n", lchan);
- break;
- }
-
- return channel_mode << 4 | channel;
-}
-
-static uint8_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, "Assignment T10 timeout on %p\n", conn);
-
- /*
- * normal release on the secondary channel but only if the
- * secondary_channel has not been released by the handle_chan_nack.
- */
- if (conn->secondary_lchan)
- lchan_release(conn->secondary_lchan, 0, RSL_REL_LOCAL_END);
- conn->secondary_lchan = NULL;
-
- /* inform them about the failure */
- api = conn->network->bsc_api;
- api->assign_fail(conn, GSM0808_CAUSE_NO_RADIO_RESOURCE_AVAILABLE, NULL);
-}
-
-/*! \brief Determine and apply AMR multi-rate configuration to lchan
- * Determine which AMR multi-rate configuration to use and apply it to
- * the lchan (so it can be communicated to BTS and MS during channel
- * activation.
- * \param[in] conn subscriber connection (used to resolve bsc_api)
- * \param[out] lchan logical channel to which to apply mr config
- * \param[in] full_rate whether to use full-rate (1) or half-rate (0) config
- */
-static void handle_mr_config(struct gsm_subscriber_connection *conn,
- struct gsm_lchan *lchan, int full_rate)
-{
- struct bsc_api *api;
- api = conn->network->bsc_api;
- struct amr_multirate_conf *mr;
- struct gsm48_multi_rate_conf *mr_conf;
-
- /* BSC api override for this method, used in OsmoBSC mode with
- * bsc_mr_config() to use MSC-specific/specified configuration */
- if (api->mr_config)
- return api->mr_config(conn, lchan, full_rate);
-
- /* NITB case: use the BTS-specic multi-rate configuration from
- * the vty/configuration file */
- if (full_rate)
- mr = &lchan->ts->trx->bts->mr_full;
- else
- mr = &lchan->ts->trx->bts->mr_half;
-
- mr_conf = (struct gsm48_multi_rate_conf *) mr->gsm48_ie;
- mr_conf->ver = 1;
-
- /* default, if no AMR codec defined */
- if (!mr->gsm48_ie[1]) {
- mr_conf->icmi = 1;
- mr_conf->m5_90 = 1;
- }
- /* store encoded MR config IE lchan for both MS (uplink) and BTS
- * (downlink) directions */
- gsm48_multirate_config(lchan->mr_ms_lv, mr, mr->ms_mode);
- gsm48_multirate_config(lchan->mr_bts_lv, mr, mr->bts_mode);
-}
-
-/*
- * 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;
- new_lchan->rqd_ta = conn->lchan->rqd_ta;
-
- /* 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)
- handle_mr_config(conn, new_lchan, full_rate);
-
- if (rsl_chan_activate_lchan(new_lchan, 0x1, 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 *bsc_subscr_con_allocate(struct gsm_lchan *lchan)
-{
- struct gsm_subscriber_connection *conn;
- struct gsm_network *net = lchan->ts->trx->bts->network;
-
- conn = talloc_zero(net, struct gsm_subscriber_connection);
- if (!conn)
- return NULL;
-
- conn->network = net;
- conn->lchan = lchan;
- conn->bts = lchan->ts->trx->bts;
- conn->via_ran = RAN_GERAN_A;
- lchan->conn = conn;
- llist_add_tail(&conn->entry, &net->subscr_conns);
- return conn;
-}
-
-void bsc_subscr_con_free(struct gsm_subscriber_connection *conn)
-{
- if (!conn)
- return;
-
- if (conn->network->bsc_api->conn_cleanup)
- conn->network->bsc_api->conn_cleanup(conn);
-
- if (conn->vsub) {
- LOGP(DNM, LOGL_ERROR, "conn->vsub should have been cleared.\n");
- conn->vsub = 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;
-}
-
-/*! \brief process incoming 08.08 DTAP from MSC (send via BTS to MS) */
-int gsm0808_submit_dtap(struct gsm_subscriber_connection *conn,
- struct msgb *msg, int link_id, int allow_sacch)
-{
- 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->dst = msg->lchan->ts->trx->rsl_link;
-
- /* If we are on a TCH and need to submit a SMS (on SAPI=3) we need to use the SACH */
- if (allow_sacch && sapi != 0) {
- if (conn->lchan->type == GSM_LCHAN_TCH_F || conn->lchan->type == GSM_LCHAN_TCH_H)
- link_id |= 0x40;
- }
-
- msg->l3h = msg->data;
- /* is requested SAPI already up? */
- if (conn->lchan->sapis[sapi] == LCHAN_SAPI_UNUSED) {
- /* Establish L2 for additional SAPI */
- 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 {
- /* Directly forward via RLL/RSL to BTS */
- return rsl_data_request(msg, link_id);
- }
-}
-
-/*
- * \brief Check if the given channel is compatible with the mode/fullrate
- */
-static int chan_compat_with_mode(struct gsm_lchan *lchan, int chan_mode, int full_rate)
-{
- switch (chan_mode) {
- case GSM48_CMODE_SIGN:
- /* signalling is always possible */
- return 1;
- case GSM48_CMODE_SPEECH_V1:
- case GSM48_CMODE_SPEECH_AMR:
- case GSM48_CMODE_DATA_3k6:
- case GSM48_CMODE_DATA_6k0:
- /* these services can all run on TCH/H, but we may have
- * an explicit override by the 'full_rate' argument */
- switch (lchan->type) {
- case GSM_LCHAN_TCH_F:
- return 1;
- case GSM_LCHAN_TCH_H:
- if (full_rate)
- return 0;
- else
- return 1;
- break;
- default:
- return 0;
- }
- break;
- case GSM48_CMODE_DATA_12k0:
- case GSM48_CMODE_DATA_14k5:
- case GSM48_CMODE_SPEECH_EFR:
- /* these services all explicitly require a TCH/F */
- if (lchan->type == GSM_LCHAN_TCH_F)
- return 1;
- else
- return 0;
- break;
- }
-
- return 0;
-}
-
-/**
- * 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 only. In case the current channel does not allow
- * the selected mode a new one will be allocated.
- *
- * TODO: Add multirate configuration, make it work for more than audio.
- */
-int gsm0808_assign_req(struct gsm_subscriber_connection *conn, int chan_mode, int full_rate)
-{
- struct bsc_api *api;
- api = conn->network->bsc_api;
-
- if (!chan_compat_with_mode(conn->lchan, chan_mode, full_rate)) {
- if (handle_new_assignment(conn, chan_mode, full_rate) != 0)
- goto error;
- } else {
- if (chan_mode == GSM48_CMODE_SPEECH_AMR)
- handle_mr_config(conn, conn->lchan, full_rate);
-
- LOGP(DMSC, LOGL_NOTICE,
- "Sending %s ChanModify for speech: %s on channel %s\n",
- gsm_lchan_name(conn->lchan),
- get_value_string(gsm48_chan_mode_names, chan_mode),
- get_value_string(gsm_chan_t_names, conn->lchan->type));
- gsm48_lchan_modify(conn->lchan, chan_mode);
- }
-
- /* we will now start the timer to complete the assignment */
- osmo_timer_setup(&conn->T10, assignment_t10_timeout, conn);
- osmo_timer_schedule(&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, false);
-}
-
-static void handle_ass_compl(struct gsm_subscriber_connection *conn,
- struct msgb *msg)
-{
- struct gsm48_hdr *gh;
- struct bsc_api *api = conn->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: %zu\n",
- msgb_l3len(msg) - sizeof(*gh));
- return;
- }
-
- /* switch TRAU muxer for E1 based BTS from one channel to another */
- if (is_e1_bts(conn->bts))
- switch_trau_mux(conn->lchan, conn->secondary_lchan);
-
- /* swap channels */
- osmo_timer_del(&conn->T10);
-
- lchan_release(conn->lchan, 0, RSL_REL_LOCAL_END);
- 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->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 */
- osmo_timer_del(&conn->T10);
- lchan_release(conn->secondary_lchan, 0, RSL_REL_LOCAL_END);
- conn->secondary_lchan = NULL;
-
- gh = msgb_l3(msg);
- if (msgb_l3len(msg) - sizeof(*gh) != 1) {
- LOGP(DMSC, LOGL_ERROR, "assignment failure unhandled: %zu\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 handle_classmark_chg(struct gsm_subscriber_connection *conn,
- struct msgb *msg)
-{
- struct bsc_api *api = msg->lchan->ts->trx->bts->network->bsc_api;
- struct gsm48_hdr *gh = msgb_l3(msg);
- unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
- uint8_t cm2_len, cm3_len = 0;
- uint8_t *cm2, *cm3 = NULL;
-
- DEBUGP(DRR, "CLASSMARK CHANGE ");
-
- /* classmark 2 */
- cm2_len = gh->data[0];
- cm2 = &gh->data[1];
- DEBUGPC(DRR, "CM2(len=%u) ", cm2_len);
-
- if (payload_len > cm2_len + 1) {
- /* we must have a classmark3 */
- if (gh->data[cm2_len+1] != 0x20) {
- DEBUGPC(DRR, "ERR CM3 TAG\n");
- return;
- }
- if (cm2_len > 3) {
- DEBUGPC(DRR, "CM2 too long!\n");
- return;
- }
-
- cm3_len = gh->data[cm2_len+2];
- cm3 = &gh->data[cm2_len+3];
- if (cm3_len > 14) {
- DEBUGPC(DRR, "CM3 len %u too long!\n", cm3_len);
- return;
- }
- DEBUGPC(DRR, "CM3(len=%u)\n", cm3_len);
- }
- api->classmark_chg(conn, cm2, cm2_len, cm3, cm3_len);
-}
-
-/* Chapter 9.1.16 Handover complete */
-static void handle_rr_ho_compl(struct msgb *msg)
-{
- struct lchan_signal_data sig;
- struct gsm48_hdr *gh = msgb_l3(msg);
-
- DEBUGP(DRR, "HANDOVER COMPLETE cause = %s\n",
- rr_cause_name(gh->data[0]));
-
- sig.lchan = msg->lchan;
- sig.mr = NULL;
- osmo_signal_dispatch(SS_LCHAN, S_LCHAN_HANDOVER_COMPL, &sig);
- /* FIXME: release old channel */
-}
-
-/* Chapter 9.1.17 Handover Failure */
-static void handle_rr_ho_fail(struct msgb *msg)
-{
- struct lchan_signal_data sig;
- struct gsm48_hdr *gh = msgb_l3(msg);
-
- DEBUGP(DRR, "HANDOVER FAILED cause = %s\n",
- rr_cause_name(gh->data[0]));
-
- sig.lchan = msg->lchan;
- sig.mr = NULL;
- osmo_signal_dispatch(SS_LCHAN, S_LCHAN_HANDOVER_FAIL, &sig);
- /* FIXME: release allocated new channel */
-}
-
-
-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;
- uint8_t msg_type;
- 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 = gsm48_hdr_pdisc(gh);
- msg_type = gsm48_hdr_msg_type(gh);
-
- /* the idea is to handle all RR messages here, and only hand
- * MM/CC/SMS-CP/LCS up to the MSC. Some messages like PAGING
- * RESPONSE or CM SERVICE REQUEST will not be covered here, as
- * they are only possible in the first L3 message of each L2
- * channel, i.e. 'conn' will not exist and gsm0408_rcvmsg()
- * will call api->compl_l3() for it */
- switch (pdisc) {
- case GSM48_PDISC_RR:
- switch (msg_type) {
- case GSM48_MT_RR_GPRS_SUSP_REQ:
- DEBUGP(DRR, "%s\n",
- gsm48_rr_msg_name(GSM48_MT_RR_GPRS_SUSP_REQ));
- break;
- case GSM48_MT_RR_STATUS:
- LOGP(DRR, LOGL_NOTICE, "%s (cause: %s)\n",
- gsm48_rr_msg_name(GSM48_MT_RR_GPRS_SUSP_REQ),
- rr_cause_name(gh->data[0]));
- break;
- case GSM48_MT_RR_MEAS_REP:
- /* This shouldn't actually end up here, as RSL treats
- * L3 Info of 08.58 MEASUREMENT REPORT different by calling
- * directly into gsm48_parse_meas_rep */
- LOGP(DMEAS, LOGL_ERROR, "DIRECT GSM48 MEASUREMENT REPORT ?!? ");
- break;
- case GSM48_MT_RR_HANDO_COMPL:
- handle_rr_ho_compl(msg);
- break;
- case GSM48_MT_RR_HANDO_FAIL:
- handle_rr_ho_fail(msg);
- break;
- case GSM48_MT_RR_CIPH_M_COMPL:
- if (api->cipher_mode_compl)
- 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:
- osmo_timer_del(&conn->T10);
- rc = gsm48_rx_rr_modif_ack(msg);
- if (rc < 0) {
- api->assign_fail(conn,
- GSM0808_CAUSE_NO_RADIO_RESOURCE_AVAILABLE,
- NULL);
- } else if (rc >= 0) {
- api->assign_compl(conn, 0,
- lchan_to_chosen_channel(conn->lchan),
- conn->lchan->encr.alg_id,
- chan_mode_to_speech(conn->lchan));
- }
- break;
- case GSM48_MT_RR_CLSM_CHG:
- handle_classmark_chg(conn, msg);
- break;
- case GSM48_MT_RR_APP_INFO:
- /* Passing RR APP INFO to MSC, not quite
- * according to spec */
- if (api->dtap)
- api->dtap(conn, link_id, msg);
- break;
- default:
- /* Normally, a MSC should never receive RR
- * messages, but we'd rather forward what we
- * don't know than drop it... */
- LOGP(DRR, LOGL_NOTICE,
- "BSC: Passing %s 04.08 RR message to MSC\n",
- gsm48_rr_msg_name(msg_type));
- if (api->dtap)
- api->dtap(conn, link_id, msg);
- }
- break;
- default:
- if (api->dtap)
- api->dtap(conn, link_id, msg);
- break;
- }
-}
-
-/*! \brief RSL has received a DATA INDICATION with L3 from MS */
-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) {
- /* if we already have a connection, forward via DTAP to
- * MSC */
- dispatch_dtap(lchan->conn, link_id, msg);
- } else {
- /* allocate a new connection */
- rc = BSC_API_CONN_POL_REJECT;
- lchan->conn = bsc_subscr_con_allocate(msg->lchan);
- if (!lchan->conn) {
- lchan_release(lchan, 1, RSL_REL_NORMAL);
- return -1;
- }
-
- /* fwd via bsc_api to send COMPLETE L3 INFO to MSC */
- rc = api->compl_l3(lchan->conn, msg, 0);
-
- if (rc != BSC_API_CONN_POL_ACCEPT) {
- lchan->conn->lchan = NULL;
- bsc_subscr_con_free(lchan->conn);
- lchan_release(lchan, 1, RSL_REL_NORMAL);
- }
- }
-
- return 0;
-}
-
-/*! \brief We received a GSM 08.08 CIPHER MODE from the MSC */
-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, RSL_REL_LOCAL_END);
-
- if (conn->lchan)
- lchan_release(conn->lchan, 1, RSL_REL_NORMAL);
-
- conn->lchan = NULL;
- conn->secondary_lchan = NULL;
- conn->ho_lchan = NULL;
- conn->bts = NULL;
-
- osmo_timer_del(&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->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) {
- osmo_timer_del(&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)
- bsc_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, lchan->ms_power);
-}
-
-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)
-{
- osmo_signal_register_handler(SS_LCHAN, bsc_handle_lchan_signal, NULL);
-}
-
diff --git a/src/libbsc/bsc_ctrl_commands.c b/src/libbsc/bsc_ctrl_commands.c
deleted file mode 100644
index 641fe2bf..00000000
--- a/src/libbsc/bsc_ctrl_commands.c
+++ /dev/null
@@ -1,459 +0,0 @@
-/*
- * (C) 2013-2015 by Holger Hans Peter Freyther
- * (C) 2013-2015 by sysmocom s.f.m.c. GmbH
- *
- * 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 <time.h>
-
-#include <osmocom/ctrl/control_cmd.h>
-#include <openbsc/ipaccess.h>
-#include <openbsc/gsm_data.h>
-#include <openbsc/abis_nm.h>
-#include <openbsc/debug.h>
-#include <openbsc/chan_alloc.h>
-#include <openbsc/osmo_bsc_rf.h>
-#include <openbsc/bsc_msc_data.h>
-
-#define CTRL_CMD_VTY_STRING(cmdname, cmdstr, dtype, element) \
- CTRL_HELPER_GET_STRING(cmdname, dtype, element) \
- CTRL_HELPER_SET_STRING(cmdname, dtype, element) \
-static struct ctrl_cmd_element cmd_##cmdname = { \
- .name = cmdstr, \
- .get = get_##cmdname, \
- .set = set_##cmdname, \
- .verify = verify_vty_description_string, \
-}
-
-/**
- * Check that there are no newlines or comments or other things
- * that could make the VTY configuration unparsable.
- */
-static int verify_vty_description_string(struct ctrl_cmd *cmd,
- const char *value, void *data)
-{
- int i;
- const size_t len = strlen(value);
-
- for (i = 0; i < len; ++i) {
- switch(value[i]) {
- case '#':
- case '\n':
- case '\r':
- cmd->reply = "String includes illegal character";
- return -1;
- default:
- break;
- }
- }
-
- return 0;
-}
-
-CTRL_CMD_DEFINE_RANGE(net_mnc, "mnc", struct gsm_network, network_code, 0, 999);
-CTRL_CMD_DEFINE_RANGE(net_mcc, "mcc", struct gsm_network, country_code, 1, 999);
-CTRL_CMD_VTY_STRING(net_short_name, "short-name", struct gsm_network, name_short);
-CTRL_CMD_VTY_STRING(net_long_name, "long-name", struct gsm_network, name_long);
-
-static int set_net_apply_config(struct ctrl_cmd *cmd, void *data)
-{
- struct gsm_network *net = cmd->node;
- struct gsm_bts *bts;
-
- llist_for_each_entry(bts, &net->bts_list, list) {
- if (!is_ipaccess_bts(bts))
- continue;
-
- /*
- * The ip.access nanoBTS seems to be unrelaible on BSSGP
- * so let's us just reboot it. For the sysmoBTS we can just
- * restart the process as all state is gone.
- */
- if (!is_sysmobts_v2(bts) && strcmp(cmd->value, "restart") == 0) {
- struct gsm_bts_trx *trx;
- llist_for_each_entry_reverse(trx, &bts->trx_list, list)
- abis_nm_ipaccess_restart(trx);
- } else
- ipaccess_drop_oml(bts);
- }
-
- cmd->reply = "Tried to drop the BTS";
- return CTRL_CMD_REPLY;
-}
-
-CTRL_CMD_DEFINE_WO_NOVRF(net_apply_config, "apply-configuration");
-
-static int verify_net_mcc_mnc_apply(struct ctrl_cmd *cmd, const char *value, void *d)
-{
- char *tmp, *saveptr, *mcc, *mnc;
-
- tmp = talloc_strdup(cmd, value);
- if (!tmp)
- return 1;
-
- mcc = strtok_r(tmp, ",", &saveptr);
- mnc = strtok_r(NULL, ",", &saveptr);
- talloc_free(tmp);
-
- if (!mcc || !mnc)
- return 1;
- return 0;
-}
-
-static int set_net_mcc_mnc_apply(struct ctrl_cmd *cmd, void *data)
-{
- struct gsm_network *net = cmd->node;
- char *tmp, *saveptr, *mcc_str, *mnc_str;
- int mcc, mnc;
-
- tmp = talloc_strdup(cmd, cmd->value);
- if (!tmp)
- goto oom;
-
-
- mcc_str = strtok_r(tmp, ",", &saveptr);
- mnc_str = strtok_r(NULL, ",", &saveptr);
-
- mcc = atoi(mcc_str);
- mnc = atoi(mnc_str);
-
- talloc_free(tmp);
-
- if (net->network_code == mnc && net->country_code == mcc) {
- cmd->reply = "Nothing changed";
- return CTRL_CMD_REPLY;
- }
-
- net->network_code = mnc;
- net->country_code = mcc;
-
- return set_net_apply_config(cmd, data);
-
-oom:
- cmd->reply = "OOM";
- return CTRL_CMD_ERROR;
-}
-CTRL_CMD_DEFINE_WO(net_mcc_mnc_apply, "mcc-mnc-apply");
-
-/* BTS related commands below */
-CTRL_CMD_DEFINE_RANGE(bts_lac, "location-area-code", struct gsm_bts, location_area_code, 0, 65535);
-CTRL_CMD_DEFINE_RANGE(bts_ci, "cell-identity", struct gsm_bts, cell_identity, 0, 65535);
-
-static int set_bts_apply_config(struct ctrl_cmd *cmd, void *data)
-{
- struct gsm_bts *bts = cmd->node;
-
- if (!is_ipaccess_bts(bts)) {
- cmd->reply = "BTS is not IP based";
- return CTRL_CMD_ERROR;
- }
-
- ipaccess_drop_oml(bts);
- cmd->reply = "Tried to drop the BTS";
- return CTRL_CMD_REPLY;
-}
-
-CTRL_CMD_DEFINE_WO_NOVRF(bts_apply_config, "apply-configuration");
-
-static int set_bts_si(struct ctrl_cmd *cmd, void *data)
-{
- struct gsm_bts *bts = cmd->node;
- int rc;
-
- rc = gsm_bts_set_system_infos(bts);
- if (rc != 0) {
- cmd->reply = "Failed to generate SI";
- return CTRL_CMD_ERROR;
- }
-
- cmd->reply = "Generated new System Information";
- return CTRL_CMD_REPLY;
-}
-CTRL_CMD_DEFINE_WO_NOVRF(bts_si, "send-new-system-informations");
-
-static int get_bts_chan_load(struct ctrl_cmd *cmd, void *data)
-{
- int i;
- struct pchan_load pl;
- struct gsm_bts *bts;
- const char *space = "";
-
- bts = cmd->node;
- memset(&pl, 0, sizeof(pl));
- bts_chan_load(&pl, bts);
-
- cmd->reply = talloc_strdup(cmd, "");
-
- for (i = 0; i < ARRAY_SIZE(pl.pchan); ++i) {
- const struct load_counter *lc = &pl.pchan[i];
-
- /* These can never have user load */
- if (i == GSM_PCHAN_NONE)
- continue;
- if (i == GSM_PCHAN_CCCH)
- continue;
- if (i == GSM_PCHAN_PDCH)
- continue;
- if (i == GSM_PCHAN_UNKNOWN)
- continue;
-
- cmd->reply = talloc_asprintf_append(cmd->reply,
- "%s%s,%u,%u",
- space, gsm_pchan_name(i), lc->used, lc->total);
- if (!cmd->reply)
- goto error;
- space = " ";
- }
-
- return CTRL_CMD_REPLY;
-
-error:
- cmd->reply = "Memory allocation failure";
- return CTRL_CMD_ERROR;
-}
-
-CTRL_CMD_DEFINE_RO(bts_chan_load, "channel-load");
-
-static int get_bts_oml_conn(struct ctrl_cmd *cmd, void *data)
-{
- struct gsm_bts *bts = cmd->node;
-
- cmd->reply = bts->oml_link ? "connected" : "disconnected";
- return CTRL_CMD_REPLY;
-}
-
-CTRL_CMD_DEFINE_RO(bts_oml_conn, "oml-connection-state");
-
-static int verify_bts_gprs_mode(struct ctrl_cmd *cmd, const char *value, void *_data)
-{
- int valid;
- enum bts_gprs_mode mode;
- struct gsm_bts *bts = cmd->node;
-
- mode = bts_gprs_mode_parse(value, &valid);
- if (!valid) {
- cmd->reply = "Mode is not known";
- return 1;
- }
-
- if (!bts_gprs_mode_is_compat(bts, mode)) {
- cmd->reply = "bts does not support this mode";
- return 1;
- }
-
- return 0;
-}
-
-static int get_bts_gprs_mode(struct ctrl_cmd *cmd, void *data)
-{
- struct gsm_bts *bts = cmd->node;
-
- cmd->reply = talloc_strdup(cmd, bts_gprs_mode_name(bts->gprs.mode));
- return CTRL_CMD_REPLY;
-}
-
-static int set_bts_gprs_mode(struct ctrl_cmd *cmd, void *data)
-{
- struct gsm_bts *bts = cmd->node;
-
- bts->gprs.mode = bts_gprs_mode_parse(cmd->value, NULL);
- return get_bts_gprs_mode(cmd, data);
-}
-
-CTRL_CMD_DEFINE(bts_gprs_mode, "gprs-mode");
-
-static int get_bts_rf_state(struct ctrl_cmd *cmd, void *data)
-{
- const char *oper, *admin, *policy;
- struct gsm_bts *bts = cmd->node;
-
- if (!bts) {
- cmd->reply = "bts not found.";
- return CTRL_CMD_ERROR;
- }
-
- oper = osmo_bsc_rf_get_opstate_name(osmo_bsc_rf_get_opstate_by_bts(bts));
- admin = osmo_bsc_rf_get_adminstate_name(osmo_bsc_rf_get_adminstate_by_bts(bts));
- policy = osmo_bsc_rf_get_policy_name(osmo_bsc_rf_get_policy_by_bts(bts));
-
- cmd->reply = talloc_asprintf(cmd, "%s,%s,%s", oper, admin, policy);
- if (!cmd->reply) {
- cmd->reply = "OOM.";
- return CTRL_CMD_ERROR;
- }
-
- return CTRL_CMD_REPLY;
-}
-CTRL_CMD_DEFINE_RO(bts_rf_state, "rf_state");
-
-static int get_net_rf_lock(struct ctrl_cmd *cmd, void *data)
-{
- struct gsm_network *net = cmd->node;
- struct gsm_bts *bts;
- const char *policy_name;
-
- policy_name = osmo_bsc_rf_get_policy_name(net->bsc_data->rf_ctrl->policy);
-
- llist_for_each_entry(bts, &net->bts_list, list) {
- struct gsm_bts_trx *trx;
-
- /* Exclude the BTS from the global lock */
- if (bts->excl_from_rf_lock)
- continue;
-
- llist_for_each_entry(trx, &bts->trx_list, list) {
- if (trx->mo.nm_state.availability == NM_AVSTATE_OK &&
- trx->mo.nm_state.operational != NM_OPSTATE_DISABLED) {
- cmd->reply = talloc_asprintf(cmd,
- "state=on,policy=%s,bts=%u,trx=%u",
- policy_name, bts->nr, trx->nr);
- return CTRL_CMD_REPLY;
- }
- }
- }
-
- cmd->reply = talloc_asprintf(cmd, "state=off,policy=%s",
- policy_name);
- return CTRL_CMD_REPLY;
-}
-
-#define TIME_FORMAT_RFC2822 "%a, %d %b %Y %T %z"
-
-static int set_net_rf_lock(struct ctrl_cmd *cmd, void *data)
-{
- int locked = atoi(cmd->value);
- struct gsm_network *net = cmd->node;
- time_t now = time(NULL);
- char now_buf[64];
- struct osmo_bsc_rf *rf;
-
- if (!net) {
- cmd->reply = "net not found.";
- return CTRL_CMD_ERROR;
- }
-
- rf = net->bsc_data->rf_ctrl;
-
- if (!rf) {
- cmd->reply = "RF Ctrl is not enabled in the BSC Configuration";
- return CTRL_CMD_ERROR;
- }
-
- talloc_free(rf->last_rf_lock_ctrl_command);
- strftime(now_buf, sizeof(now_buf), TIME_FORMAT_RFC2822, gmtime(&now));
- rf->last_rf_lock_ctrl_command =
- talloc_asprintf(rf, "rf_locked %u (%s)", locked, now_buf);
-
- osmo_bsc_rf_schedule_lock(rf, locked == 1 ? '0' : '1');
-
- cmd->reply = talloc_asprintf(cmd, "%u", locked);
- if (!cmd->reply) {
- cmd->reply = "OOM.";
- return CTRL_CMD_ERROR;
- }
-
- return CTRL_CMD_REPLY;
-}
-
-static int verify_net_rf_lock(struct ctrl_cmd *cmd, const char *value, void *data)
-{
- int locked = atoi(cmd->value);
-
- if ((locked != 0) && (locked != 1))
- return 1;
-
- return 0;
-}
-CTRL_CMD_DEFINE(net_rf_lock, "rf_locked");
-
-static int get_net_bts_num(struct ctrl_cmd *cmd, void *data)
-{
- struct gsm_network *net = cmd->node;
-
- cmd->reply = talloc_asprintf(cmd, "%u", net->num_bts);
- return CTRL_CMD_REPLY;
-}
-CTRL_CMD_DEFINE_RO(net_bts_num, "number-of-bts");
-
-/* TRX related commands below here */
-CTRL_HELPER_GET_INT(trx_max_power, struct gsm_bts_trx, max_power_red);
-static int verify_trx_max_power(struct ctrl_cmd *cmd, const char *value, void *_data)
-{
- int tmp = atoi(value);
-
- if (tmp < 0 || tmp > 22) {
- cmd->reply = "Value must be between 0 and 22";
- return -1;
- }
-
- if (tmp & 1) {
- cmd->reply = "Value must be even";
- return -1;
- }
-
- return 0;
-}
-CTRL_CMD_DEFINE_RANGE(trx_arfcn, "arfcn", struct gsm_bts_trx, arfcn, 0, 1023);
-
-static int set_trx_max_power(struct ctrl_cmd *cmd, void *_data)
-{
- struct gsm_bts_trx *trx = cmd->node;
- int old_power;
-
- /* remember the old value, set the new one */
- old_power = trx->max_power_red;
- trx->max_power_red = atoi(cmd->value);
-
- /* Maybe update the value */
- if (old_power != trx->max_power_red) {
- LOGP(DCTRL, LOGL_NOTICE,
- "%s updating max_pwr_red(%d)\n",
- gsm_trx_name(trx), trx->max_power_red);
- abis_nm_update_max_power_red(trx);
- }
-
- return get_trx_max_power(cmd, _data);
-}
-CTRL_CMD_DEFINE(trx_max_power, "max-power-reduction");
-
-int bsc_base_ctrl_cmds_install(void)
-{
- int rc = 0;
- rc |= ctrl_cmd_install(CTRL_NODE_ROOT, &cmd_net_mnc);
- rc |= ctrl_cmd_install(CTRL_NODE_ROOT, &cmd_net_mcc);
- rc |= ctrl_cmd_install(CTRL_NODE_ROOT, &cmd_net_short_name);
- rc |= ctrl_cmd_install(CTRL_NODE_ROOT, &cmd_net_long_name);
- rc |= ctrl_cmd_install(CTRL_NODE_ROOT, &cmd_net_apply_config);
- rc |= ctrl_cmd_install(CTRL_NODE_ROOT, &cmd_net_mcc_mnc_apply);
- rc |= ctrl_cmd_install(CTRL_NODE_ROOT, &cmd_net_rf_lock);
- rc |= ctrl_cmd_install(CTRL_NODE_ROOT, &cmd_net_bts_num);
-
- rc |= ctrl_cmd_install(CTRL_NODE_BTS, &cmd_bts_lac);
- rc |= ctrl_cmd_install(CTRL_NODE_BTS, &cmd_bts_ci);
- rc |= ctrl_cmd_install(CTRL_NODE_BTS, &cmd_bts_apply_config);
- rc |= ctrl_cmd_install(CTRL_NODE_BTS, &cmd_bts_si);
- rc |= ctrl_cmd_install(CTRL_NODE_BTS, &cmd_bts_chan_load);
- rc |= ctrl_cmd_install(CTRL_NODE_BTS, &cmd_bts_oml_conn);
- rc |= ctrl_cmd_install(CTRL_NODE_BTS, &cmd_bts_gprs_mode);
- rc |= ctrl_cmd_install(CTRL_NODE_BTS, &cmd_bts_rf_state);
-
- rc |= ctrl_cmd_install(CTRL_NODE_TRX, &cmd_trx_max_power);
- rc |= ctrl_cmd_install(CTRL_NODE_TRX, &cmd_trx_arfcn);
-
- return rc;
-}
diff --git a/src/libbsc/bsc_ctrl_lookup.c b/src/libbsc/bsc_ctrl_lookup.c
deleted file mode 100644
index a8a8cf52..00000000
--- a/src/libbsc/bsc_ctrl_lookup.c
+++ /dev/null
@@ -1,107 +0,0 @@
-/* SNMP-like status interface. Look-up of BTS/TRX
- *
- * (C) 2010-2011 by Daniel Willmann <daniel@totalueberwachung.de>
- * (C) 2010-2011 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 General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- */
-
-#include <errno.h>
-
-#include <osmocom/vty/command.h>
-#include <osmocom/ctrl/control_if.h>
-#include <openbsc/debug.h>
-#include <openbsc/gsm_data.h>
-
-extern vector ctrl_node_vec;
-
-/*! \brief control interface lookup function for bsc/bts gsm_data
- * \param[in] data Private data passed to controlif_setup()
- * \param[in] vline Vector of the line holding the command string
- * \param[out] node_type type (CTRL_NODE_) that was determined
- * \param[out] node_data private dta of node that was determined
- * \param i Current index into vline, up to which it is parsed
- */
-static int bsc_ctrl_node_lookup(void *data, vector vline, int *node_type,
- void **node_data, int *i)
-{
- struct gsm_network *net = data;
- struct gsm_bts *bts = NULL;
- struct gsm_bts_trx *trx = NULL;
- struct gsm_bts_trx_ts *ts = NULL;
- char *token = vector_slot(vline, *i);
- long num;
-
- /* TODO: We need to make sure that the following chars are digits
- * and/or use strtol to check if number conversion was successful
- * Right now something like net.bts_stats will not work */
- if (!strcmp(token, "bts")) {
- if (*node_type != CTRL_NODE_ROOT || !net)
- goto err_missing;
- (*i)++;
- if (!ctrl_parse_get_num(vline, *i, &num))
- goto err_index;
-
- bts = gsm_bts_num(net, num);
- if (!bts)
- goto err_missing;
- *node_data = bts;
- *node_type = CTRL_NODE_BTS;
- } else if (!strcmp(token, "trx")) {
- if (*node_type != CTRL_NODE_BTS || !*node_data)
- goto err_missing;
- bts = *node_data;
- (*i)++;
- if (!ctrl_parse_get_num(vline, *i, &num))
- goto err_index;
-
- trx = gsm_bts_trx_num(bts, num);
- if (!trx)
- goto err_missing;
- *node_data = trx;
- *node_type = CTRL_NODE_TRX;
- } else if (!strcmp(token, "ts")) {
- if (*node_type != CTRL_NODE_TRX || !*node_data)
- goto err_missing;
- trx = *node_data;
- (*i)++;
- if (!ctrl_parse_get_num(vline, *i, &num))
- goto err_index;
-
- if ((num >= 0) && (num < TRX_NR_TS))
- ts = &trx->ts[num];
- if (!ts)
- goto err_missing;
- *node_data = ts;
- *node_type = CTRL_NODE_TS;
- } else
- return 0;
-
- return 1;
-err_missing:
- return -ENODEV;
-err_index:
- return -ERANGE;
-}
-
-struct ctrl_handle *bsc_controlif_setup(struct gsm_network *net,
- const char *bind_addr, uint16_t port)
-{
- return ctrl_interface_setup_dynip(net, bind_addr, port,
- bsc_ctrl_node_lookup);
-}
diff --git a/src/libbsc/bsc_dyn_ts.c b/src/libbsc/bsc_dyn_ts.c
deleted file mode 100644
index e5422fc5..00000000
--- a/src/libbsc/bsc_dyn_ts.c
+++ /dev/null
@@ -1,77 +0,0 @@
-/* Dynamic PDCH initialisation implementation shared across NM and RSL */
-
-/* (C) 2016 by sysmocom s.f.m.c. GmbH <info@sysmocom.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 <osmocom/core/logging.h>
-#include <openbsc/debug.h>
-#include <openbsc/gsm_data.h>
-#include <openbsc/abis_rsl.h>
-
-void tchf_pdch_ts_init(struct gsm_bts_trx_ts *ts)
-{
- int rc;
-
- if (ts->trx->bts->gprs.mode == BTS_GPRS_NONE) {
- LOGP(DRSL, LOGL_NOTICE, "%s: GPRS mode is 'none':"
- " not activating PDCH.\n",
- gsm_ts_and_pchan_name(ts));
- return;
- }
-
- LOGP(DRSL, LOGL_DEBUG, "%s: trying to PDCH ACT\n",
- gsm_ts_and_pchan_name(ts));
-
- rc = rsl_ipacc_pdch_activate(ts, 1);
- if (rc != 0)
- LOGP(DRSL, LOGL_ERROR, "%s %s: PDCH ACT failed\n",
- gsm_ts_name(ts), gsm_pchan_name(ts->pchan));
-}
-
-void tchf_tchh_pdch_ts_init(struct gsm_bts_trx_ts *ts)
-{
- if (ts->trx->bts->gprs.mode == BTS_GPRS_NONE) {
- LOGP(DRSL, LOGL_NOTICE, "%s: GPRS mode is 'none':"
- " not activating PDCH.\n",
- gsm_ts_and_pchan_name(ts));
- return;
- }
-
- dyn_ts_switchover_start(ts, GSM_PCHAN_PDCH);
-}
-
-void dyn_ts_init(struct gsm_bts_trx_ts *ts)
-{
- /* Clear all TCH/F_PDCH flags */
- ts->flags &= ~(TS_F_PDCH_PENDING_MASK | TS_F_PDCH_ACTIVE);
-
- /* Clear TCH/F_TCH/H_PDCH state */
- ts->dyn.pchan_is = ts->dyn.pchan_want = GSM_PCHAN_NONE;
- ts->dyn.pending_chan_activ = NULL;
-
- switch (ts->pchan) {
- case GSM_PCHAN_TCH_F_PDCH:
- tchf_pdch_ts_init(ts);
- break;
- case GSM_PCHAN_TCH_F_TCH_H_PDCH:
- tchf_tchh_pdch_ts_init(ts);
- break;
- default:
- break;
- }
-}
diff --git a/src/libbsc/bsc_init.c b/src/libbsc/bsc_init.c
deleted file mode 100644
index 64dcd157..00000000
--- a/src/libbsc/bsc_init.c
+++ /dev/null
@@ -1,556 +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 <osmocom/gsm/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 <osmocom/vty/ports.h>
-#include <openbsc/system_information.h>
-#include <openbsc/paging.h>
-#include <openbsc/signal.h>
-#include <openbsc/chan_alloc.h>
-#include <osmocom/core/talloc.h>
-#include <openbsc/ipaccess.h>
-#include <osmocom/gsm/sysinfo.h>
-#include <openbsc/e1_config.h>
-#include <openbsc/common_bsc.h>
-#include <openbsc/pcu_if.h>
-#include <openbsc/osmo_msc.h>
-#include <limits.h>
-
-/* global pointer to the gsm network data structure */
-extern struct gsm_network *bsc_gsmnet;
-
-/* Callback function for NACK on the OML NM */
-static int oml_msg_nack(struct nm_nack_signal_data *nack)
-{
- if (nack->mt == NM_MT_GET_ATTR_NACK) {
- LOGP(DNM, LOGL_ERROR, "BTS%u does not support Get Attributes "
- "OML message.\n", nack->bts->nr);
- return 0;
- }
-
- if (nack->mt == NM_MT_SET_BTS_ATTR_NACK)
- LOGP(DNM, LOGL_ERROR, "Failed to set BTS attributes. That is fatal. "
- "Was the bts type and frequency properly specified?\n");
- else
- LOGP(DNM, LOGL_ERROR, "Got %s NACK going to drop the OML links.\n",
- abis_nm_nack_name(nack->mt));
-
- if (!nack->bts) {
- LOGP(DNM, LOGL_ERROR, "Unknown bts. Can not drop it.\n");
- return 0;
- }
-
- if (is_ipaccess_bts(nack->bts))
- ipaccess_drop_oml(nack->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);
- osmo_signal_dispatch(SS_L_GLOBAL, S_GLOBAL_BTS_CLOSE_OM, bts);
- }
-
- return 0;
-}
-
-static int rsl_si(struct gsm_bts_trx *trx, enum osmo_sysinfo_type i, int si_len)
-{
- struct gsm_bts *bts = trx->bts;
- int rc, j;
-
- DEBUGP(DRR, "SI%s: %s\n", get_value_string(osmo_sitype_strs, i),
- osmo_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, osmo_sitype2rsl(i),
- GSM_BTS_SI(bts, i), si_len);
- break;
- case SYSINFO_TYPE_2quater:
- for (j = 0; j <= bts->si2q_count; j++)
- rc = rsl_bcch_info(trx, i, (const uint8_t *)GSM_BTS_SI2Q(bts, j), GSM_MACBLOCK_LEN);
- break;
- default:
- rc = rsl_bcch_info(trx, i, GSM_BTS_SI(bts, i), si_len);
- break;
- }
-
- return rc;
-}
-
-/* set all system information types for a TRX */
-int gsm_bts_trx_set_system_infos(struct gsm_bts_trx *trx)
-{
- int i, rc;
- struct gsm_bts *bts = trx->bts;
- uint8_t gen_si[_MAX_SYSINFO_TYPE], n_si = 0, n;
- int si_len[_MAX_SYSINFO_TYPE];
-
- 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;
-
- /* Zero, forget the state of the SIs */
- bts->si_valid = 0;
-
- /* First, we determine which of the SI messages we actually need */
-
- if (trx == bts->c0) {
- /* 1...4 are always present on a C0 TRX */
- gen_si[n_si++] = SYSINFO_TYPE_1;
- gen_si[n_si++] = SYSINFO_TYPE_2;
- gen_si[n_si++] = SYSINFO_TYPE_2bis;
- gen_si[n_si++] = SYSINFO_TYPE_2ter;
- gen_si[n_si++] = SYSINFO_TYPE_2quater;
- gen_si[n_si++] = SYSINFO_TYPE_3;
- gen_si[n_si++] = SYSINFO_TYPE_4;
-
- /* 13 is always present on a C0 TRX of a GPRS BTS */
- if (bts->gprs.mode != BTS_GPRS_NONE)
- gen_si[n_si++] = SYSINFO_TYPE_13;
- }
-
- /* 5 and 6 are always present on every TRX */
- gen_si[n_si++] = SYSINFO_TYPE_5;
- gen_si[n_si++] = SYSINFO_TYPE_5bis;
- gen_si[n_si++] = SYSINFO_TYPE_5ter;
- gen_si[n_si++] = SYSINFO_TYPE_6;
-
- /* Second, we generate the selected SI via RSL */
-
- for (n = 0; n < n_si; n++) {
- i = gen_si[n];
- /* Only generate SI if this SI is not in "static" (user-defined) mode */
- if (!(bts->si_mode_static & (1 << i))) {
- /* Set SI as being valid. gsm_generate_si() might unset
- * it, if SI is not required. */
- bts->si_valid |= (1 << i);
- rc = gsm_generate_si(bts, i);
- if (rc < 0)
- goto err_out;
- si_len[i] = rc;
- } else {
- if (i == SYSINFO_TYPE_5 || i == SYSINFO_TYPE_5bis
- || i == SYSINFO_TYPE_5ter)
- si_len[i] = 18;
- else if (i == SYSINFO_TYPE_6)
- si_len[i] = 11;
- else
- si_len[i] = 23;
- }
- }
-
- /* Third, we send the selected SI via RSL */
-
- for (n = 0; n < n_si; n++) {
- i = gen_si[n];
- if (!GSM_BTS_HAS_SI(bts, i))
- continue;
- rc = rsl_si(trx, i, si_len[i]);
- if (rc < 0)
- return rc;
- }
-
- /* Make sure the PCU is aware (in case anything GPRS related has
- * changed in SI */
- pcu_info_update(bts);
-
- return 0;
-err_out:
- LOGP(DRR, LOGL_ERROR, "Cannot generate SI%s for BTS %u: error <%s>, "
- "most likely a problem with neighbor cell list generation\n",
- get_value_string(osmo_sitype_strs, i), bts->nr, strerror(-rc));
- return rc;
-}
-
-/* set all system information types for a BTS */
-int gsm_bts_set_system_infos(struct gsm_bts *bts)
-{
- struct gsm_bts_trx *trx;
-
- /* Generate a new ID */
- bts->bcch_change_mark += 1;
- bts->bcch_change_mark %= 0x7;
-
- llist_for_each_entry(trx, &bts->trx_list, list) {
- int rc;
-
- rc = gsm_bts_trx_set_system_infos(trx);
- if (rc != 0)
- return rc;
- }
-
- return 0;
-}
-
-/* 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 = 0; 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 = 0; 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\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);
-
- if (trx->bts->type == GSM_BTS_TYPE_NOKIA_SITE) {
- rsl_nokia_si_begin(trx);
- }
-
- gsm_bts_trx_set_system_infos(trx);
-
- if (trx->bts->type == GSM_BTS_TYPE_NOKIA_SITE) {
- /* channel unspecific, power reduction in 2 dB steps */
- rsl_bs_power_control(trx, 0xFF, trx->max_power_red / 2);
- rsl_nokia_si_end(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;
- /* N. B: we rely on attribute order when parsing response in abis_nm_rx_get_attr_resp() */
- const uint8_t bts_attr[] = { NM_ATT_MANUF_ID, NM_ATT_SW_CONFIG, };
- const uint8_t trx_attr[] = { NM_ATT_MANUF_STATE, NM_ATT_SW_CONFIG, };
-
- /* we should not request more attributes than we're ready to handle */
- OSMO_ASSERT(sizeof(bts_attr) < MAX_BTS_ATTR);
- OSMO_ASSERT(sizeof(trx_attr) < MAX_BTS_ATTR);
-
- if (subsys != SS_L_INPUT)
- return -EINVAL;
-
- LOGP(DLMI, LOGL_DEBUG, "%s(): Input signal '%s' received\n", __func__,
- get_value_string(e1inp_signal_names, signal));
- switch (signal) {
- case S_L_INP_TEI_UP:
- if (isd->link_type == E1INP_SIGN_OML) {
- /* TODO: this is required for the Nokia BTS, hopping is configured
- during OML, other MA is not set. */
- struct gsm_bts_trx *cur_trx;
- /* was static in system_information.c */
- extern int generate_cell_chan_list(uint8_t *chan_list, struct gsm_bts *bts);
- uint8_t ca[20];
- /* has to be called before generate_ma_for_ts to
- set bts->si_common.cell_alloc */
- generate_cell_chan_list(ca, trx->bts);
-
- /* Request generic BTS-level attributes */
- abis_nm_get_attr(trx->bts, NM_OC_BTS, trx->bts->nr, trx->nr, 0xFF, bts_attr, sizeof(bts_attr));
-
- llist_for_each_entry(cur_trx, &trx->bts->trx_list, list) {
- int i;
- /* Request TRX-level attributes */
- abis_nm_get_attr(cur_trx->bts, NM_OC_BASEB_TRANSC, cur_trx->bts->nr, cur_trx->nr, 0xFF,
- trx_attr, sizeof(trx_attr));
- for (i = 0; i < ARRAY_SIZE(cur_trx->ts); i++)
- generate_ma_for_ts(&cur_trx->ts[i]);
- }
- }
- if (isd->link_type == E1INP_SIGN_RSL)
- bootstrap_rsl(trx);
- break;
- case S_L_INP_TEI_DN:
- LOGP(DLMI, LOGL_ERROR, "Lost some E1 TEI link: %d %p\n", isd->link_type, trx);
-
- if (isd->link_type == E1INP_SIGN_OML)
- rate_ctr_inc(&trx->bts->network->bsc_ctrs->ctr[BSC_CTR_BTS_OML_FAIL]);
- else if (isd->link_type == E1INP_SIGN_RSL)
- rate_ctr_inc(&trx->bts->network->bsc_ctrs->ctr[BSC_CTR_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]);
- }
- }
-
- gsm_bts_mo_reset(trx->bts);
-
- abis_nm_clear_queue(trx->bts);
- break;
- default:
- break;
- }
-
- return 0;
-}
-
-static int bootstrap_bts(struct gsm_bts *bts)
-{
- int i, n;
-
- if (!bts->model)
- return -EFAULT;
-
- if (bts->model->start && !bts->model->started) {
- int ret = bts->model->start(bts->network);
- if (ret < 0)
- return ret;
-
- bts->model->started = true;
- }
-
- /* 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 > 124 && bts->c0->arfcn < 955) ||
- bts->c0->arfcn > 1023) {
- LOGP(DNM, LOGL_ERROR, "GSM900 channel must be between 0-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 is set from vty/config */
-
- /* 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;
-
- /* Indicate R99 MSC in SI3 */
- bts->si_common.chan_desc.mscr = 1;
-
- switch (n) {
- case 0:
- bts->si_common.chan_desc.ccch_conf = RSL_BCCH_CCCH_CONF_1_C;
- /* Limit reserved block to 2 on combined channel according to
- 3GPP TS 44.018 Table 10.5.2.11.1 */
- if (bts->si_common.chan_desc.bs_ag_blks_res > 2) {
- LOGP(DNM, LOGL_NOTICE, "CCCH is combined with SDCCHs, "
- "reducing BS-AG-BLKS-RES value %d -> 2\n",
- bts->si_common.chan_desc.bs_ag_blks_res);
- bts->si_common.chan_desc.bs_ag_blks_res = 2;
- }
- 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;
- }
-
- bts->si_common.cell_options.pwrc = 0; /* PWRC not set */
-
- bts->si_common.cell_sel_par.acs = 0;
-
- bts->si_common.ncc_permitted = 0xff;
-
- /* Initialize the BTS state */
- gsm_bts_mo_reset(bts);
-
- return 0;
-}
-
-int bsc_network_alloc(mncc_recv_cb_t mncc_recv)
-{
- /* initialize our data structures */
- bsc_gsmnet = bsc_network_init(tall_bsc_ctx, 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");
-
- return 0;
-}
-
-int bsc_network_configure(const char *config_file)
-{
- struct gsm_bts *bts;
- int rc;
-
- rc = vty_read_config_file(config_file, NULL);
- if (rc < 0) {
- LOGP(DNM, LOGL_FATAL, "Failed to parse the config file: '%s'\n", config_file);
- return rc;
- }
-
- /* start telnet after reading config for vty_get_bind_addr() */
- rc = telnet_init_dynif(tall_bsc_ctx, bsc_gsmnet, vty_get_bind_addr(),
- OSMO_VTY_PORT_NITB_BSC);
- if (rc < 0)
- return rc;
-
- osmo_signal_register_handler(SS_NM, nm_sig_cb, NULL);
- osmo_signal_register_handler(SS_L_INPUT, inp_sig_cb, NULL);
-
- llist_for_each_entry(bts, &bsc_gsmnet->bts_list, list) {
- rc = bootstrap_bts(bts);
- if (rc < 0) {
- LOGP(DNM, LOGL_FATAL, "Error bootstrapping BTS\n");
- return rc;
- }
- rc = e1_reconfig_bts(bts);
- if (rc < 0) {
- LOGP(DNM, LOGL_FATAL, "Error enabling E1 input driver\n");
- return rc;
- }
- }
-
- return 0;
-}
diff --git a/src/libbsc/bsc_msc.c b/src/libbsc/bsc_msc.c
deleted file mode 100644
index 82a572db..00000000
--- a/src/libbsc/bsc_msc.c
+++ /dev/null
@@ -1,320 +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 <osmocom/abis/ipaccess.h>
-
-#include <osmocom/core/write_queue.h>
-#include <osmocom/core/talloc.h>
-
-#include <osmocom/gsm/tlv.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 osmo_fd *fd;
-
- fd = &con->write_queue.bfd;
-
- if (con->pending_msg) {
- LOGP(DMSC, LOGL_ERROR,
- "MSC(%s) dropping incomplete message.\n", con->name);
- msgb_free(con->pending_msg);
- con->pending_msg = NULL;
- }
-
- close(fd->fd);
- fd->fd = -1;
- fd->cb = osmo_wqueue_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(%s) Connection timeout.\n", con->name);
- bsc_msc_lost(con);
-}
-
-/* called in the case of a non blocking connect */
-static int msc_connection_connect(struct osmo_fd *fd, unsigned int what)
-{
- int rc;
- int val;
- struct bsc_msc_connection *con;
- struct osmo_wqueue *queue;
-
- socklen_t len = sizeof(val);
-
- queue = container_of(fd, struct osmo_wqueue, bfd);
- con = container_of(queue, struct bsc_msc_connection, write_queue);
-
- if ((what & BSC_FD_WRITE) == 0) {
- LOGP(DMSC, LOGL_ERROR,
- "MSC(%s) Callback but not writable.\n", con->name);
- return -1;
- }
-
- /* From here on we will either be connected or reconnect */
- osmo_timer_del(&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(%s) socket failed.\n", con->name);
- goto error;
- }
- if (val != 0) {
- LOGP(DMSC, LOGL_ERROR,
- "Not connected to the MSC(%s): %d\n",
- con->name, val);
- goto error;
- }
-
-
- /* go to full operation */
- fd->cb = osmo_wqueue_bfd_cb;
- fd->when = BSC_FD_READ | BSC_FD_EXCEPT;
-
- con->is_connected = 1;
- LOGP(DMSC, LOGL_NOTICE,
- "(Re)Connected to the MSC(%s).\n", con->name);
- if (con->connected)
- con->connected(con);
- return 0;
-
-error:
- osmo_fd_unregister(fd);
- connection_loss(con);
- return -1;
-}
-static void setnonblocking(struct osmo_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_msc_dest *dest;
- struct osmo_fd *fd;
- struct sockaddr_in sin;
- int on = 1, ret;
-
- if (llist_empty(con->dests)) {
- LOGP(DMSC, LOGL_ERROR,
- "No MSC(%s) connections configured.\n",
- con->name);
- connection_loss(con);
- return -1;
- }
-
- /* TODO: Why are we not using the libosmocore soecket
- * abstraction, or libosmo-netif? */
-
- /* move to the next connection */
- dest = (struct bsc_msc_dest *) con->dests->next;
- llist_del(&dest->list);
- llist_add_tail(&dest->list, con->dests);
-
- LOGP(DMSC, LOGL_NOTICE,
- "Attempting to connect MSC(%s) at %s:%d\n",
- con->name, dest->ip, dest->port);
-
- con->is_connected = 0;
-
- msgb_free(con->pending_msg);
- con->pending_msg = NULL;
-
- 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,
- &dest->dscp, sizeof(dest->dscp));
- if (ret != 0)
- LOGP(DMSC, LOGL_ERROR,
- "Failed to set DSCP to %d on MSC(%s). %s\n",
- dest->dscp, con->name, strerror(errno));
-
- memset(&sin, 0, sizeof(sin));
- sin.sin_family = AF_INET;
- sin.sin_port = htons(dest->port);
- inet_aton(dest->ip, &sin.sin_addr);
-
- ret = setsockopt(fd->fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
- if (ret != 0)
- LOGP(DMSC, LOGL_ERROR,
- "Failed to set SO_REUSEADDR socket option\n");
- ret = connect(fd->fd, (struct sockaddr *) &sin, sizeof(sin));
-
- if (ret == -1 && errno == EINPROGRESS) {
- LOGP(DMSC, LOGL_ERROR,
- "MSC(%s) Connection in progress\n", con->name);
- fd->when = BSC_FD_WRITE;
- fd->cb = msc_connection_connect;
- osmo_timer_setup(&con->timeout_timer, msc_con_timeout, con);
- osmo_timer_schedule(&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 = osmo_wqueue_bfd_cb;
- con->is_connected = 1;
- if (con->connected)
- con->connected(con);
- }
-
- ret = osmo_fd_register(fd);
- if (ret < 0) {
- perror("Registering the fd failed");
- close(fd->fd);
- return ret;
- }
-
- return ret;
-}
-
-struct bsc_msc_connection *bsc_msc_create(void *ctx, struct llist_head *dests)
-{
- 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->dests = dests;
- con->write_queue.bfd.fd = -1;
- con->name = "";
- osmo_wqueue_init(&con->write_queue, 100);
- return con;
-}
-
-void bsc_msc_lost(struct bsc_msc_connection *con)
-{
- osmo_wqueue_clear(&con->write_queue);
- osmo_timer_del(&con->timeout_timer);
- osmo_timer_del(&con->reconnect_timer);
-
- if (con->write_queue.bfd.fd >= 0)
- osmo_fd_unregister(&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(%s).\n", con->name);
- bsc_msc_connect(con);
-}
-
-void bsc_msc_schedule_connect(struct bsc_msc_connection *con)
-{
- LOGP(DMSC, LOGL_NOTICE,
- "Attempting to reconnect to the MSC(%s)\n", con->name);
- osmo_timer_setup(&con->reconnect_timer, reconnect_msc, con);
- osmo_timer_schedule(&con->reconnect_timer, 5, 0);
-}
-
-struct msgb *bsc_msc_id_get_resp(int fixed, const char *token, const uint8_t *res, int len)
-{
- 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;
- }
-
- /*
- * The situation is bizarre. The encoding doesn't follow the
- * TLV structure. It is more like a LV and old versions had
- * it wrong but we want new versions to old servers so we
- * introduce the quirk here.
- */
- msg->l2h = msgb_v_put(msg, IPAC_MSGT_ID_RESP);
- if (fixed) {
- msgb_put_u8(msg, 0);
- msgb_put_u8(msg, strlen(token) + 2);
- msgb_tv_fixed_put(msg, IPAC_IDTAG_UNITNAME, strlen(token) + 1, (uint8_t *) token);
- if (len > 0) {
- msgb_put_u8(msg, 0);
- msgb_put_u8(msg, len + 1);
- msgb_tv_fixed_put(msg, 0x24, len, res);
- }
- } else {
- msgb_l16tv_put(msg, strlen(token) + 1,
- IPAC_IDTAG_UNITNAME, (uint8_t *) token);
- }
-
- return msg;
-}
diff --git a/src/libbsc/bsc_rf_ctrl.c b/src/libbsc/bsc_rf_ctrl.c
deleted file mode 100644
index b7b6fc81..00000000
--- a/src/libbsc/bsc_rf_ctrl.c
+++ /dev/null
@@ -1,534 +0,0 @@
-/* RF Ctl handling socket */
-
-/* (C) 2010 by Harald Welte <laforge@gnumonks.org>
- * (C) 2010-2014 by Holger Hans Peter Freyther <zecke@selfish.org>
- * (C) 2010-2014 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/osmo_bsc_rf.h>
-#include <openbsc/debug.h>
-#include <openbsc/gsm_data.h>
-#include <openbsc/signal.h>
-#include <openbsc/bsc_msc_data.h>
-#include <openbsc/ipaccess.h>
-
-#include <osmocom/core/talloc.h>
-#include <osmocom/core/utils.h>
-#include <osmocom/gsm/protocol/gsm_12_21.h>
-
-#include <sys/socket.h>
-#include <sys/un.h>
-
-#include <errno.h>
-#include <unistd.h>
-
-#define RF_CMD_QUERY '?'
-#define RF_CMD_OFF '0'
-#define RF_CMD_ON '1'
-#define RF_CMD_D_OFF 'd'
-#define RF_CMD_ON_G 'g'
-
-static const struct value_string opstate_names[] = {
- { OSMO_BSC_RF_OPSTATE_INOPERATIONAL, "inoperational" },
- { OSMO_BSC_RF_OPSTATE_OPERATIONAL, "operational" },
- { 0, NULL }
-};
-
-static const struct value_string adminstate_names[] = {
- { OSMO_BSC_RF_ADMINSTATE_UNLOCKED, "unlocked" },
- { OSMO_BSC_RF_ADMINSTATE_LOCKED, "locked" },
- { 0, NULL }
-};
-
-static const struct value_string policy_names[] = {
- { OSMO_BSC_RF_POLICY_OFF, "off" },
- { OSMO_BSC_RF_POLICY_ON, "on" },
- { OSMO_BSC_RF_POLICY_GRACE, "grace" },
- { OSMO_BSC_RF_POLICY_UNKNOWN, "unknown" },
- { 0, NULL }
-};
-
-const char *osmo_bsc_rf_get_opstate_name(enum osmo_bsc_rf_opstate opstate)
-{
- return get_value_string(opstate_names, opstate);
-}
-
-const char *osmo_bsc_rf_get_adminstate_name(enum osmo_bsc_rf_adminstate adminstate)
-{
- return get_value_string(adminstate_names, adminstate);
-}
-
-const char *osmo_bsc_rf_get_policy_name(enum osmo_bsc_rf_policy policy)
-{
- return get_value_string(policy_names, policy);
-}
-
-enum osmo_bsc_rf_opstate osmo_bsc_rf_get_opstate_by_bts(struct gsm_bts *bts)
-{
- struct gsm_bts_trx *trx;
-
- llist_for_each_entry(trx, &bts->trx_list, list) {
- if (trx->mo.nm_state.operational == NM_OPSTATE_ENABLED)
- return OSMO_BSC_RF_OPSTATE_OPERATIONAL;
- }
-
- /* No trx were active, so this bts is disabled */
- return OSMO_BSC_RF_OPSTATE_INOPERATIONAL;
-}
-
-enum osmo_bsc_rf_adminstate osmo_bsc_rf_get_adminstate_by_bts(struct gsm_bts *bts)
-{
- struct gsm_bts_trx *trx;
-
- llist_for_each_entry(trx, &bts->trx_list, list) {
- if (trx->mo.nm_state.administrative == NM_STATE_UNLOCKED)
- return OSMO_BSC_RF_ADMINSTATE_UNLOCKED;
- }
-
- /* All trx administrative states were locked */
- return OSMO_BSC_RF_ADMINSTATE_LOCKED;
-}
-
-enum osmo_bsc_rf_policy osmo_bsc_rf_get_policy_by_bts(struct gsm_bts *bts)
-{
- struct osmo_bsc_data *bsc_data = bts->network->bsc_data;
-
- if (!bsc_data)
- return OSMO_BSC_RF_POLICY_UNKNOWN;
-
- switch (bsc_data->rf_ctrl->policy) {
- case S_RF_ON:
- return OSMO_BSC_RF_POLICY_ON;
- case S_RF_OFF:
- return OSMO_BSC_RF_POLICY_OFF;
- case S_RF_GRACE:
- return OSMO_BSC_RF_POLICY_GRACE;
- default:
- return OSMO_BSC_RF_POLICY_UNKNOWN;
- }
-}
-
-static int lock_each_trx(struct gsm_network *net, int lock)
-{
- struct gsm_bts *bts;
-
- llist_for_each_entry(bts, &net->bts_list, list) {
- struct gsm_bts_trx *trx;
-
- /* Exclude the BTS from the global lock */
- if (bts->excl_from_rf_lock) {
- LOGP(DLINP, LOGL_DEBUG,
- "Excluding BTS(%d) from trx lock.\n", bts->nr);
- continue;
- }
-
- llist_for_each_entry(trx, &bts->trx_list, list) {
- gsm_trx_lock_rf(trx, lock);
- }
- }
-
- return 0;
-}
-
-static void send_resp(struct osmo_bsc_rf_conn *conn, char send)
-{
- struct msgb *msg;
-
- msg = msgb_alloc(10, "RF Query");
- if (!msg) {
- LOGP(DLINP, LOGL_ERROR, "Failed to allocate response msg.\n");
- return;
- }
-
- msg->l2h = msgb_put(msg, 1);
- msg->l2h[0] = send;
-
- if (osmo_wqueue_enqueue(&conn->queue, msg) != 0) {
- LOGP(DLINP, LOGL_ERROR, "Failed to enqueue the answer.\n");
- msgb_free(msg);
- return;
- }
-
- return;
-}
-
-
-/*
- * Send a
- * 'g' when we are in grace mode
- * '1' when one TRX is online,
- * '0' otherwise
- */
-static void handle_query(struct osmo_bsc_rf_conn *conn)
-{
- struct gsm_bts *bts;
- char send = RF_CMD_OFF;
-
- if (conn->rf->policy == S_RF_GRACE)
- return send_resp(conn, RF_CMD_ON_G);
-
- llist_for_each_entry(bts, &conn->rf->gsm_network->bts_list, list) {
- struct gsm_bts_trx *trx;
-
- /* Exclude the BTS from the global lock */
- if (bts->excl_from_rf_lock) {
- LOGP(DLINP, LOGL_DEBUG,
- "Excluding BTS(%d) from query.\n", bts->nr);
- continue;
- }
- llist_for_each_entry(trx, &bts->trx_list, list) {
- if (trx->mo.nm_state.availability == NM_AVSTATE_OK &&
- trx->mo.nm_state.operational != NM_OPSTATE_DISABLED) {
- send = RF_CMD_ON;
- break;
- }
- }
- }
-
- send_resp(conn, send);
-}
-
-static void rf_check_cb(void *_data)
-{
- struct gsm_bts *bts;
- struct osmo_bsc_rf *rf = _data;
-
- llist_for_each_entry(bts, &rf->gsm_network->bts_list, list) {
- struct gsm_bts_trx *trx;
-
- /* don't bother to check a booting or missing BTS */
- if (!bts->oml_link || !is_ipaccess_bts(bts))
- continue;
-
- /* Exclude the BTS from the global lock */
- if (bts->excl_from_rf_lock) {
- LOGP(DLINP, LOGL_DEBUG,
- "Excluding BTS(%d) from query.\n", bts->nr);
- continue;
- }
-
- llist_for_each_entry(trx, &bts->trx_list, list) {
- if (trx->mo.nm_state.availability != NM_AVSTATE_OK ||
- trx->mo.nm_state.operational != NM_OPSTATE_ENABLED ||
- trx->mo.nm_state.administrative != NM_STATE_UNLOCKED) {
- LOGP(DNM, LOGL_ERROR, "RF activation failed. Starting again.\n");
- ipaccess_drop_oml(bts);
- break;
- }
- }
- }
-}
-
-static void send_signal(struct osmo_bsc_rf *rf, int val)
-{
- struct rf_signal_data sig;
- sig.net = rf->gsm_network;
-
- rf->policy = val;
- osmo_signal_dispatch(SS_RF, val, &sig);
-}
-
-static int switch_rf_off(struct osmo_bsc_rf *rf)
-{
- lock_each_trx(rf->gsm_network, 1);
- send_signal(rf, S_RF_OFF);
-
- return 0;
-}
-
-static void grace_timeout(void *_data)
-{
- struct osmo_bsc_rf *rf = (struct osmo_bsc_rf *) _data;
-
- LOGP(DLINP, LOGL_NOTICE, "Grace timeout. Going to disable all BTS/TRX.\n");
- switch_rf_off(rf);
-}
-
-static int enter_grace(struct osmo_bsc_rf *rf)
-{
- if (osmo_timer_pending(&rf->grace_timeout)) {
- LOGP(DLINP, LOGL_NOTICE, "RF Grace timer is pending. Not restarting.\n");
- return 0;
- }
-
- osmo_timer_setup(&rf->grace_timeout, grace_timeout, rf);
- osmo_timer_schedule(&rf->grace_timeout, rf->gsm_network->bsc_data->mid_call_timeout, 0);
- LOGP(DLINP, LOGL_NOTICE, "Going to switch RF off in %d seconds.\n",
- rf->gsm_network->bsc_data->mid_call_timeout);
-
- send_signal(rf, S_RF_GRACE);
- return 0;
-}
-
-static void rf_delay_cmd_cb(void *data)
-{
- struct osmo_bsc_rf *rf = data;
-
- switch (rf->last_request) {
- case RF_CMD_D_OFF:
- rf->last_state_command = "RF Direct Off";
- osmo_timer_del(&rf->rf_check);
- osmo_timer_del(&rf->grace_timeout);
- switch_rf_off(rf);
- break;
- case RF_CMD_ON:
- rf->last_state_command = "RF Direct On";
- osmo_timer_del(&rf->grace_timeout);
- lock_each_trx(rf->gsm_network, 0);
- send_signal(rf, S_RF_ON);
- osmo_timer_schedule(&rf->rf_check, 3, 0);
- break;
- case RF_CMD_OFF:
- rf->last_state_command = "RF Scheduled Off";
- osmo_timer_del(&rf->rf_check);
- enter_grace(rf);
- break;
- }
-}
-
-static int rf_read_cmd(struct osmo_fd *fd)
-{
- struct osmo_bsc_rf_conn *conn = fd->data;
- char buf[1];
- int rc;
-
- rc = read(fd->fd, buf, sizeof(buf));
- if (rc != sizeof(buf)) {
- LOGP(DLINP, LOGL_ERROR, "Short read %d/%s\n", errno, strerror(errno));
- osmo_fd_unregister(fd);
- close(fd->fd);
- osmo_wqueue_clear(&conn->queue);
- talloc_free(conn);
- return -1;
- }
-
- switch (buf[0]) {
- case RF_CMD_QUERY:
- handle_query(conn);
- break;
- case RF_CMD_D_OFF:
- case RF_CMD_ON:
- case RF_CMD_OFF:
- osmo_bsc_rf_schedule_lock(conn->rf, buf[0]);
- break;
- default:
- conn->rf->last_state_command = "Unknown command";
- LOGP(DLINP, LOGL_ERROR, "Unknown command %d\n", buf[0]);
- break;
- }
-
- return 0;
-}
-
-static int rf_write_cmd(struct osmo_fd *fd, struct msgb *msg)
-{
- int rc;
-
- rc = write(fd->fd, msg->data, msg->len);
- if (rc != msg->len) {
- LOGP(DLINP, LOGL_ERROR, "Short write %d/%s\n", errno, strerror(errno));
- return -1;
- }
-
- return 0;
-}
-
-static int rf_ctrl_accept(struct osmo_fd *bfd, unsigned int what)
-{
- struct osmo_bsc_rf_conn *conn;
- struct osmo_bsc_rf *rf = bfd->data;
- struct sockaddr_un addr;
- socklen_t len = sizeof(addr);
- int fd;
-
- fd = accept(bfd->fd, (struct sockaddr *) &addr, &len);
- if (fd < 0) {
- LOGP(DLINP, LOGL_ERROR, "Failed to accept. errno: %d/%s\n",
- errno, strerror(errno));
- return -1;
- }
-
- conn = talloc_zero(rf, struct osmo_bsc_rf_conn);
- if (!conn) {
- LOGP(DLINP, LOGL_ERROR, "Failed to allocate mem.\n");
- close(fd);
- return -1;
- }
-
- osmo_wqueue_init(&conn->queue, 10);
- conn->queue.bfd.data = conn;
- conn->queue.bfd.fd = fd;
- conn->queue.bfd.when = BSC_FD_READ | BSC_FD_WRITE;
- conn->queue.read_cb = rf_read_cmd;
- conn->queue.write_cb = rf_write_cmd;
- conn->rf = rf;
-
- if (osmo_fd_register(&conn->queue.bfd) != 0) {
- close(fd);
- talloc_free(conn);
- return -1;
- }
-
- return 0;
-}
-
-static void rf_auto_off_cb(void *_timer)
-{
- struct osmo_bsc_rf *rf = _timer;
-
- LOGP(DLINP, LOGL_NOTICE,
- "Going to switch off RF due lack of a MSC connection.\n");
- osmo_bsc_rf_schedule_lock(rf, RF_CMD_D_OFF);
-}
-
-static int msc_signal_handler(unsigned int subsys, unsigned int signal,
- void *handler_data, void *signal_data)
-{
- struct gsm_network *net;
- struct msc_signal_data *msc;
- struct osmo_bsc_rf *rf;
-
- /* check if we want to handle this signal */
- if (subsys != SS_MSC)
- return 0;
-
- net = handler_data;
- msc = signal_data;
-
- /* check if we have the needed information */
- if (!net->bsc_data)
- return 0;
- if (msc->data->type != MSC_CON_TYPE_NORMAL)
- return 0;
-
- rf = net->bsc_data->rf_ctrl;
- switch (signal) {
- case S_MSC_LOST:
- if (net->bsc_data->auto_off_timeout < 0)
- return 0;
- if (osmo_timer_pending(&rf->auto_off_timer))
- return 0;
- osmo_timer_schedule(&rf->auto_off_timer,
- net->bsc_data->auto_off_timeout, 0);
- break;
- case S_MSC_CONNECTED:
- osmo_timer_del(&rf->auto_off_timer);
- break;
- }
-
- return 0;
-}
-
-static int rf_create_socket(struct osmo_bsc_rf *rf, const char *path)
-{
- unsigned int namelen;
- struct sockaddr_un local;
- struct osmo_fd *bfd;
- int rc;
-
- bfd = &rf->listen;
- bfd->fd = socket(AF_UNIX, SOCK_STREAM, 0);
- if (bfd->fd < 0) {
- LOGP(DLINP, LOGL_ERROR, "Can not create socket. %d/%s\n",
- errno, strerror(errno));
- return -1;
- }
-
- local.sun_family = AF_UNIX;
- osmo_strlcpy(local.sun_path, path, sizeof(local.sun_path));
- unlink(local.sun_path);
-
- /* we use the same magic that X11 uses in Xtranssock.c for
- * calculating the proper length of the sockaddr */
-#if defined(BSD44SOCKETS) || defined(__UNIXWARE__)
- local.sun_len = strlen(local.sun_path);
-#endif
-#if defined(BSD44SOCKETS) || defined(SUN_LEN)
- namelen = SUN_LEN(&local);
-#else
- namelen = strlen(local.sun_path) +
- offsetof(struct sockaddr_un, sun_path);
-#endif
-
- rc = bind(bfd->fd, (struct sockaddr *) &local, namelen);
- if (rc != 0) {
- LOGP(DLINP, LOGL_ERROR, "Failed to bind '%s' errno: %d/%s\n",
- local.sun_path, errno, strerror(errno));
- close(bfd->fd);
- return -1;
- }
-
- if (listen(bfd->fd, 0) != 0) {
- LOGP(DLINP, LOGL_ERROR, "Failed to listen: %d/%s\n", errno, strerror(errno));
- close(bfd->fd);
- return -1;
- }
-
- bfd->when = BSC_FD_READ;
- bfd->cb = rf_ctrl_accept;
- bfd->data = rf;
-
- if (osmo_fd_register(bfd) != 0) {
- LOGP(DLINP, LOGL_ERROR, "Failed to register bfd.\n");
- close(bfd->fd);
- return -1;
- }
-
- return 0;
-}
-
-struct osmo_bsc_rf *osmo_bsc_rf_create(const char *path, struct gsm_network *net)
-{
- struct osmo_bsc_rf *rf;
-
- rf = talloc_zero(NULL, struct osmo_bsc_rf);
- if (!rf) {
- LOGP(DLINP, LOGL_ERROR, "Failed to create osmo_bsc_rf.\n");
- return NULL;
- }
-
- if (path && rf_create_socket(rf, path) != 0) {
- talloc_free(rf);
- return NULL;
- }
-
- rf->gsm_network = net;
- rf->policy = S_RF_ON;
- rf->last_state_command = "";
- rf->last_rf_lock_ctrl_command = talloc_strdup(rf, "");
-
- /* check the rf state */
- osmo_timer_setup(&rf->rf_check, rf_check_cb, rf);
-
- /* delay cmd handling */
- osmo_timer_setup(&rf->delay_cmd, rf_delay_cmd_cb, rf);
-
- osmo_timer_setup(&rf->auto_off_timer, rf_auto_off_cb, rf);
-
- /* listen to RF signals */
- osmo_signal_register_handler(SS_MSC, msc_signal_handler, net);
-
- return rf;
-}
-
-void osmo_bsc_rf_schedule_lock(struct osmo_bsc_rf *rf, char cmd)
-{
- rf->last_request = cmd;
- if (!osmo_timer_pending(&rf->delay_cmd))
- osmo_timer_schedule(&rf->delay_cmd, 1, 0);
-}
diff --git a/src/libbsc/bsc_rll.c b/src/libbsc/bsc_rll.c
deleted file mode 100644
index bb488da1..00000000
--- a/src/libbsc/bsc_rll.c
+++ /dev/null
@@ -1,139 +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 <osmocom/core/talloc.h>
-#include <osmocom/core/timer.h>
-#include <osmocom/core/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 osmo_timer_list timer;
-
- struct gsm_lchan *lchan;
- uint8_t link_id;
-
- void (*cb)(struct gsm_lchan *lchan, uint8_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, uint8_t sapi,
- void (*cb)(struct gsm_lchan *, uint8_t, void *,
- enum bsc_rllr_ind),
- void *data)
-{
- struct bsc_rll_req *rllr = talloc_zero(tall_bsc_ctx, struct bsc_rll_req);
- uint8_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);
-
- osmo_timer_setup(&rllr->timer, timer_cb, rllr);
- osmo_timer_schedule(&rllr->timer, 7, 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, uint8_t link_id, uint8_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)) {
- osmo_timer_del(&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) {
- osmo_timer_del(&rllr->timer);
- complete_rllr(rllr, BSC_RLLR_IND_ERR_IND);
- }
- }
-
- return 0;
-}
-
-static __attribute__((constructor)) void on_dso_load_rll(void)
-{
- osmo_signal_register_handler(SS_CHALLOC, rll_lchan_signal, NULL);
-}
diff --git a/src/libbsc/bsc_subscriber.c b/src/libbsc/bsc_subscriber.c
deleted file mode 100644
index 73e61e80..00000000
--- a/src/libbsc/bsc_subscriber.c
+++ /dev/null
@@ -1,168 +0,0 @@
-/* GSM subscriber details for use in BSC land */
-
-/*
- * (C) 2016 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
- *
- * Author: Neels Hofmeyr <nhofmeyr@sysmocom.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 <talloc.h>
-#include <string.h>
-#include <limits.h>
-
-#include <osmocom/gsm/gsm48.h>
-#include <osmocom/core/logging.h>
-
-#include <openbsc/bsc_subscriber.h>
-#include <openbsc/debug.h>
-
-static struct bsc_subscr *bsc_subscr_alloc(struct llist_head *list)
-{
- struct bsc_subscr *bsub;
-
- bsub = talloc_zero(list, struct bsc_subscr);
- if (!bsub)
- return NULL;
-
- llist_add_tail(&bsub->entry, list);
- bsub->use_count = 1;
-
- return bsub;
-}
-
-struct bsc_subscr *bsc_subscr_find_by_imsi(struct llist_head *list,
- const char *imsi)
-{
- struct bsc_subscr *bsub;
-
- if (!imsi || !*imsi)
- return NULL;
-
- llist_for_each_entry(bsub, list, entry) {
- if (!strcmp(bsub->imsi, imsi))
- return bsc_subscr_get(bsub);
- }
- return NULL;
-}
-
-struct bsc_subscr *bsc_subscr_find_by_tmsi(struct llist_head *list,
- uint32_t tmsi)
-{
- struct bsc_subscr *bsub;
-
- if (tmsi == GSM_RESERVED_TMSI)
- return NULL;
-
- llist_for_each_entry(bsub, list, entry) {
- if (bsub->tmsi == tmsi)
- return bsc_subscr_get(bsub);
- }
- return NULL;
-}
-
-void bsc_subscr_set_imsi(struct bsc_subscr *bsub, const char *imsi)
-{
- if (!bsub)
- return;
- osmo_strlcpy(bsub->imsi, imsi, sizeof(bsub->imsi));
-}
-
-struct bsc_subscr *bsc_subscr_find_or_create_by_imsi(struct llist_head *list,
- const char *imsi)
-{
- struct bsc_subscr *bsub;
- bsub = bsc_subscr_find_by_imsi(list, imsi);
- if (bsub)
- return bsub;
- bsub = bsc_subscr_alloc(list);
- bsc_subscr_set_imsi(bsub, imsi);
- return bsub;
-}
-
-struct bsc_subscr *bsc_subscr_find_or_create_by_tmsi(struct llist_head *list,
- uint32_t tmsi)
-{
- struct bsc_subscr *bsub;
- bsub = bsc_subscr_find_by_tmsi(list, tmsi);
- if (bsub)
- return bsub;
- bsub = bsc_subscr_alloc(list);
- bsub->tmsi = tmsi;
- return bsub;
-}
-
-const char *bsc_subscr_name(struct bsc_subscr *bsub)
-{
- static char buf[32];
- if (!bsub)
- return "unknown";
- if (bsub->imsi[0])
- snprintf(buf, sizeof(buf), "IMSI:%s", bsub->imsi);
- else
- snprintf(buf, sizeof(buf), "TMSI:0x%08x", bsub->tmsi);
- return buf;
-}
-
-static void bsc_subscr_free(struct bsc_subscr *bsub)
-{
- llist_del(&bsub->entry);
- talloc_free(bsub);
-}
-
-struct bsc_subscr *_bsc_subscr_get(struct bsc_subscr *bsub,
- const char *file, int line)
-{
- OSMO_ASSERT(bsub->use_count < INT_MAX);
- bsub->use_count++;
- LOGPSRC(DREF, LOGL_DEBUG, file, line,
- "BSC subscr %s usage increases to: %d\n",
- bsc_subscr_name(bsub), bsub->use_count);
- return bsub;
-}
-
-struct bsc_subscr *_bsc_subscr_put(struct bsc_subscr *bsub,
- const char *file, int line)
-{
- bsub->use_count--;
- LOGPSRC(DREF, bsub->use_count >= 0? LOGL_DEBUG : LOGL_ERROR,
- file, line,
- "BSC subscr %s usage decreases to: %d\n",
- bsc_subscr_name(bsub), bsub->use_count);
- if (bsub->use_count <= 0)
- bsc_subscr_free(bsub);
- return NULL;
-}
-
-void log_set_filter_bsc_subscr(struct log_target *target,
- struct bsc_subscr *bsc_subscr)
-{
- struct bsc_subscr **fsub = (void*)&target->filter_data[LOG_FLT_BSC_SUBSCR];
-
- /* free the old data */
- if (*fsub) {
- bsc_subscr_put(*fsub);
- *fsub = NULL;
- }
-
- if (bsc_subscr) {
- target->filter_map |= (1 << LOG_FLT_BSC_SUBSCR);
- *fsub = bsc_subscr_get(bsc_subscr);
- } else
- target->filter_map &= ~(1 << LOG_FLT_BSC_SUBSCR);
-}
diff --git a/src/libbsc/bsc_vty.c b/src/libbsc/bsc_vty.c
deleted file mode 100644
index 554b5529..00000000
--- a/src/libbsc/bsc_vty.c
+++ /dev/null
@@ -1,4281 +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 <stdbool.h>
-#include <unistd.h>
-
-#include <osmocom/vty/command.h>
-#include <osmocom/vty/buffer.h>
-#include <osmocom/vty/vty.h>
-#include <osmocom/vty/logging.h>
-#include <osmocom/vty/stats.h>
-#include <osmocom/vty/telnet_interface.h>
-#include <osmocom/vty/misc.h>
-#include <osmocom/gsm/protocol/gsm_04_08.h>
-#include <osmocom/gsm/gsm0502.h>
-
-#include <arpa/inet.h>
-
-#include <osmocom/core/linuxlist.h>
-#include <openbsc/gsm_data.h>
-#include <osmocom/abis/e1_input.h>
-#include <openbsc/abis_nm.h>
-#include <openbsc/abis_om2000.h>
-#include <osmocom/core/utils.h>
-#include <osmocom/gsm/gsm_utils.h>
-#include <osmocom/gsm/abis_nm.h>
-#include <openbsc/chan_alloc.h>
-#include <openbsc/meas_rep.h>
-#include <openbsc/db.h>
-#include <openbsc/vty.h>
-#include <osmocom/gprs/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/bsc_msc_data.h>
-#include <openbsc/osmo_bsc_rf.h>
-#include <openbsc/pcu_if.h>
-#include <openbsc/common_cs.h>
-#include <openbsc/vlr.h>
-
-#include <inttypes.h>
-
-#include "../../bscconfig.h"
-
-
-#define LCHAN_NR_STR "Logical Channel Number\n"
-
-
-/* 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 }
-};
-
-const struct value_string bts_loc_fix_names[] = {
- { BTS_LOC_FIX_INVALID, "invalid" },
- { BTS_LOC_FIX_2D, "fix2d" },
- { BTS_LOC_FIX_3D, "fix3d" },
- { 0, NULL }
-};
-
-struct cmd_node bts_node = {
- BTS_NODE,
- "%s(config-net-bts)# ",
- 1,
-};
-
-struct cmd_node trx_node = {
- TRX_NODE,
- "%s(config-net-bts-trx)# ",
- 1,
-};
-
-struct cmd_node ts_node = {
- TS_NODE,
- "%s(config-net-bts-trx-ts)# ",
- 1,
-};
-
-static int dummy_config_write(struct vty *v)
-{
- return CMD_SUCCESS;
-}
-
-static void net_dump_nmstate(struct vty *vty, struct gsm_nm_state *nms)
-{
- vty_out(vty,"Oper '%s', Admin '%s', Avail '%s'%s",
- abis_nm_opstate_name(nms->operational),
- get_value_string(abis_nm_adm_state_names, nms->administrative),
- abis_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",
- gsm_auth_policy_name(net->auth_policy));
- if (net->authorized_reg_str)
- vty_out(vty, ", authorized regexp: %s", net->authorized_reg_str);
- vty_out(vty, "%s", VTY_NEWLINE);
- vty_out(vty, " Auto create subscriber: %s%s",
- net->auto_create_subscr ? "yes" : "no", VTY_NEWLINE);
- vty_out(vty, " Auto assign extension: %s%s",
- net->auto_assign_exten ? "yes" : "no", 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->bsc_data)
- vty_out(vty, " Last RF Command: %s%s",
- net->bsc_data->rf_ctrl->last_state_command,
- VTY_NEWLINE);
- if (net->bsc_data)
- vty_out(vty, " Last RF Lock Command: %s%s",
- net->bsc_data->rf_ctrl->last_rf_lock_ctrl_command,
- VTY_NEWLINE);
-}
-
-DEFUN(bsc_show_net, bsc_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 (NCC=%u, BCC=%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->bsic >> 3, bts->bsic & 7,
- bts->num_trx, VTY_NEWLINE);
- vty_out(vty, "Description: %s%s",
- bts->description ? bts->description : "(null)", VTY_NEWLINE);
- if (strnlen(bts->pcu_version, MAX_VERSION_LENGTH))
- vty_out(vty, "PCU version %s connected%s", bts->pcu_version,
- 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);
- if (bts->dtxu != GSM48_DTX_SHALL_NOT_BE_USED)
- vty_out(vty, "Uplink DTX: %s%s",
- (bts->dtxu != GSM48_DTX_SHALL_BE_USED) ?
- "enabled" : "forced", VTY_NEWLINE);
- else
- vty_out(vty, "Uplink DTX: not enabled%s", VTY_NEWLINE);
- vty_out(vty, "Downlink DTX: %senabled%s", bts->dtxd ? "" : "not ",
- VTY_NEWLINE);
- vty_out(vty, "Channel Description Attachment: %s%s",
- (bts->si_common.chan_desc.att) ? "yes" : "no", VTY_NEWLINE);
- vty_out(vty, "Channel Description BS-PA-MFRMS: %u%s",
- bts->si_common.chan_desc.bs_pa_mfrms + 2, VTY_NEWLINE);
- vty_out(vty, "Channel Description BS-AG_BLKS-RES: %u%s",
- bts->si_common.chan_desc.bs_ag_blks_res, VTY_NEWLINE);
- vty_out(vty, "System Information present: 0x%08x, static: 0x%08x%s",
- bts->si_valid, bts->si_mode_static, VTY_NEWLINE);
- vty_out(vty, "Early Classmark Sending: %s%s",
- bts->early_classmark_allowed ? "allowed" : "forbidden",
- VTY_NEWLINE);
- if (bts->pcu_sock_path)
- vty_out(vty, "PCU Socket Path: %s%s", bts->pcu_sock_path, 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);
- else if (bts->type == GSM_BTS_TYPE_NOKIA_SITE)
- vty_out(vty, " Skip Reset: %d%s",
- bts->nokia.skip_reset, VTY_NEWLINE);
- vty_out(vty, " NM State: ");
- net_dump_nmstate(vty, &bts->mo.nm_state);
- vty_out(vty, " Site Mgr NM State: ");
- net_dump_nmstate(vty, &bts->site_mgr.mo.nm_state);
- vty_out(vty, " GPRS NSE: ");
- net_dump_nmstate(vty, &bts->gprs.nse.mo.nm_state);
- vty_out(vty, " GPRS CELL: ");
- net_dump_nmstate(vty, &bts->gprs.cell.mo.nm_state);
- vty_out(vty, " GPRS NSVC0: ");
- net_dump_nmstate(vty, &bts->gprs.nsvc[0].mo.nm_state);
- vty_out(vty, " GPRS NSVC1: ");
- net_dump_nmstate(vty, &bts->gprs.nsvc[1].mo.nm_state);
- vty_out(vty, " Paging: %u pending requests, %u free slots%s",
- paging_pending_requests_nr(bts),
- 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 [<0-255>]",
- 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->tsc != -1)
- vty_out(vty, " training_sequence_code %u%s", ts->tsc, 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->mo.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 11bit_rach_support_for_egprs %u%s",
- bts->gprs.supports_egprs_11bit_rach, VTY_NEWLINE);
-
- vty_out(vty, " gprs routing area %u%s", bts->gprs.rac,
- VTY_NEWLINE);
- vty_out(vty, " gprs network-control-order nc%u%s",
- bts->gprs.net_ctrl_ord, VTY_NEWLINE);
- if (!bts->gprs.ctrl_ack_type_use_block)
- vty_out(vty, " gprs control-ack-type-rach%s", 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);
- }
-}
-
-/* Write the model data if there is one */
-static void config_write_bts_model(struct vty *vty, struct gsm_bts *bts)
-{
- struct gsm_bts_trx *trx;
-
- if (!bts->model)
- return;
-
- 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 void write_amr_modes(struct vty *vty, const char *prefix,
- const char *name, struct amr_mode *modes, int num)
-{
- int i;
-
- vty_out(vty, " %s threshold %s", prefix, name);
- for (i = 0; i < num - 1; i++)
- vty_out(vty, " %d", modes[i].threshold);
- vty_out(vty, "%s", VTY_NEWLINE);
- vty_out(vty, " %s hysteresis %s", prefix, name);
- for (i = 0; i < num - 1; i++)
- vty_out(vty, " %d", modes[i].hysteresis);
- vty_out(vty, "%s", VTY_NEWLINE);
-}
-
-static void config_write_bts_amr(struct vty *vty, struct gsm_bts *bts,
- struct amr_multirate_conf *mr, int full)
-{
- struct gsm48_multi_rate_conf *mr_conf;
- const char *prefix = (full) ? "amr tch-f" : "amr tch-h";
- int i, num;
-
- if (!(mr->gsm48_ie[1]))
- return;
-
- mr_conf = (struct gsm48_multi_rate_conf *) mr->gsm48_ie;
-
- num = 0;
- vty_out(vty, " %s modes", prefix);
- for (i = 0; i < ((full) ? 8 : 6); i++) {
- if ((mr->gsm48_ie[1] & (1 << i))) {
- vty_out(vty, " %d", i);
- num++;
- }
- }
- vty_out(vty, "%s", VTY_NEWLINE);
- if (num > 4)
- num = 4;
- if (num > 1) {
- write_amr_modes(vty, prefix, "ms", mr->ms_mode, num);
- write_amr_modes(vty, prefix, "bts", mr->bts_mode, num);
- }
- vty_out(vty, " %s start-mode ", prefix);
- if (mr_conf->icmi) {
- num = 0;
- for (i = 0; i < ((full) ? 8 : 6) && num < 4; i++) {
- if ((mr->gsm48_ie[1] & (1 << i)))
- num++;
- if (mr_conf->smod == num - 1) {
- vty_out(vty, "%d%s", num, VTY_NEWLINE);
- break;
- }
- }
- } else
- vty_out(vty, "auto%s", VTY_NEWLINE);
-}
-
-static void config_write_bts_single(struct vty *vty, struct gsm_bts *bts)
-{
- int i;
- uint8_t tmp;
-
- 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);
- if (bts->dtxu != GSM48_DTX_SHALL_NOT_BE_USED)
- vty_out(vty, " dtx uplink%s%s",
- (bts->dtxu != GSM48_DTX_SHALL_BE_USED) ? "" : " force",
- VTY_NEWLINE);
- if (bts->dtxd)
- vty_out(vty, " dtx downlink%s", 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 (gsm_bts_get_radio_link_timeout(bts) < 0)
- vty_out(vty, " radio-link-timeout infinite%s", VTY_NEWLINE);
- else
- vty_out(vty, " radio-link-timeout %d%s",
- gsm_bts_get_radio_link_timeout(bts), 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);
-
- vty_out(vty, " channel-descrption attach %u%s",
- bts->si_common.chan_desc.att, VTY_NEWLINE);
- vty_out(vty, " channel-descrption bs-pa-mfrms %u%s",
- bts->si_common.chan_desc.bs_pa_mfrms + 2, VTY_NEWLINE);
- vty_out(vty, " channel-descrption bs-ag-blks-res %u%s",
- bts->si_common.chan_desc.bs_ag_blks_res, 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);
- if ((bts->si_common.rach_control.t3) != 0)
- for (i = 0; i < 8; i++)
- if (bts->si_common.rach_control.t3 & (0x1 << i))
- vty_out(vty, " rach access-control-class %d barred%s", i, VTY_NEWLINE);
- if ((bts->si_common.rach_control.t2 & 0xfb) != 0)
- for (i = 0; i < 8; i++)
- if ((i != 2) && (bts->si_common.rach_control.t2 & (0x1 << i)))
- vty_out(vty, " rach access-control-class %d barred%s", i+8, 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),
- osmo_hexdump_nospc(GSM_BTS_SI(bts, i), GSM_MACBLOCK_LEN),
- VTY_NEWLINE);
- }
- }
- vty_out(vty, " early-classmark-sending %s%s",
- bts->early_classmark_allowed ? "allowed" : "forbidden", VTY_NEWLINE);
- switch (bts->type) {
- case GSM_BTS_TYPE_NANOBTS:
- case GSM_BTS_TYPE_OSMOBTS:
- vty_out(vty, " ip.access unit_id %u %u%s",
- bts->ip_access.site_id, bts->ip_access.bts_id, VTY_NEWLINE);
- if (bts->ip_access.rsl_ip) {
- struct in_addr ia;
- ia.s_addr = htonl(bts->ip_access.rsl_ip);
- vty_out(vty, " ip.access rsl-ip %s%s", inet_ntoa(ia),
- VTY_NEWLINE);
- }
- vty_out(vty, " oml ip.access stream_id %u line %u%s",
- bts->oml_tei, bts->oml_e1_link.e1_nr, VTY_NEWLINE);
- break;
- case GSM_BTS_TYPE_NOKIA_SITE:
- vty_out(vty, " nokia_site skip-reset %d%s", bts->nokia.skip_reset, VTY_NEWLINE);
- vty_out(vty, " nokia_site no-local-rel-conf %d%s",
- bts->nokia.no_loc_rel_cnf, VTY_NEWLINE);
- vty_out(vty, " nokia_site bts-reset-timer %d%s", bts->nokia.bts_reset_timer_cnf, VTY_NEWLINE);
- /* fall through: Nokia requires "oml e1" parameters also */
- default:
- config_write_e1_link(vty, &bts->oml_e1_link, " oml ");
- vty_out(vty, " oml e1 tei %u%s", bts->oml_tei, VTY_NEWLINE);
- break;
- }
-
- /* 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);
- }
- }
-
- for (i = 0; i < MAX_EARFCN_LIST; i++) {
- struct osmo_earfcn_si2q *e = &bts->si_common.si2quater_neigh_list;
- if (e->arfcn[i] != OSMO_EARFCN_INVALID) {
- vty_out(vty, " si2quater neighbor-list add earfcn %u "
- "thresh-hi %u", e->arfcn[i], e->thresh_hi);
-
- vty_out(vty, " thresh-lo %u",
- e->thresh_lo_valid ? e->thresh_lo : 32);
-
- vty_out(vty, " prio %u",
- e->prio_valid ? e->prio : 8);
-
- vty_out(vty, " qrxlv %u",
- e->qrxlm_valid ? e->qrxlm : 32);
-
- tmp = e->meas_bw[i];
- vty_out(vty, " meas %u",
- (tmp != OSMO_EARFCN_MEAS_INVALID) ? tmp : 8);
-
- vty_out(vty, "%s", VTY_NEWLINE);
- }
- }
-
- for (i = 0; i < bts->si_common.uarfcn_length; i++) {
- vty_out(vty, " si2quater neighbor-list add uarfcn %u %u %u%s",
- bts->si_common.data.uarfcn_list[i],
- bts->si_common.data.scramble_list[i] & ~(1 << 9),
- (bts->si_common.data.scramble_list[i] >> 9) & 1,
- VTY_NEWLINE);
- }
-
- vty_out(vty, " codec-support fr");
- if (bts->codec.hr)
- vty_out(vty, " hr");
- if (bts->codec.efr)
- vty_out(vty, " efr");
- if (bts->codec.amr)
- vty_out(vty, " amr");
- vty_out(vty, "%s", VTY_NEWLINE);
-
- config_write_bts_amr(vty, bts, &bts->mr_full, 1);
- config_write_bts_amr(vty, bts, &bts->mr_half, 0);
-
- config_write_bts_gprs(vty, bts);
-
- if (bts->excl_from_rf_lock)
- vty_out(vty, " rf-lock-exclude%s", VTY_NEWLINE);
-
- vty_out(vty, " %sforce-combined-si%s",
- bts->force_combined_si ? "" : "no ", VTY_NEWLINE);
-
- for (i = 0; i < ARRAY_SIZE(bts->depends_on); ++i) {
- int j;
-
- if (bts->depends_on[i] == 0)
- continue;
-
- for (j = 0; j < sizeof(bts->depends_on[i]) * 8; ++j) {
- int bts_nr;
-
- if ((bts->depends_on[i] & (1<<j)) == 0)
- continue;
-
- bts_nr = (i * sizeof(bts->depends_on[i]) * 8) + j;
- vty_out(vty, " depends-on-bts %d%s", bts_nr, VTY_NEWLINE);
- }
- }
- if (bts->pcu_sock_path)
- vty_out(vty, " pcu-socket %s%s", bts->pcu_sock_path, VTY_NEWLINE);
-
- config_write_bts_model(vty, bts);
-}
-
-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);
- if (gsmnet->authorized_reg_str)
- vty_out(vty, " authorized-regexp %s%s", gsmnet->authorized_reg_str, 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, " authentication %s%s",
- gsmnet->authentication_required ? "required" : "optional",
- 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, " dyn_ts_allow_tch_f %d%s",
- gsmnet->dyn_ts_allow_tch_f ? 1 : 0, VTY_NEWLINE);
- /*
- TODO: add in libvlr?
- vty_out(vty, " subscriber-keep-in-ram %d%s",
- gsmnet->subscr_group->keep_subscr, VTY_NEWLINE);
- */
- if (gsmnet->tz.override != 0) {
- if (gsmnet->tz.dst)
- vty_out(vty, " timezone %d %d %d%s",
- gsmnet->tz.hr, gsmnet->tz.mn, gsmnet->tz.dst,
- VTY_NEWLINE);
- else
- vty_out(vty, " timezone %d %d%s",
- gsmnet->tz.hr, gsmnet->tz.mn, VTY_NEWLINE);
- }
- if (gsmnet->t3212 == 0)
- vty_out(vty, " no periodic location update%s", VTY_NEWLINE);
- else
- vty_out(vty, " periodic location update %u%s",
- gsmnet->t3212 * 6, 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->mo.nm_state);
- vty_out(vty, " Baseband Transceiver NM State: ");
- net_dump_nmstate(vty, &trx->bb_transc.mo.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 [<0-255>] [<0-255>]",
- 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, TSC %u",
- ts->trx->bts->nr, ts->trx->nr, ts->nr,
- gsm_pchan_name(ts->pchan), gsm_ts_tsc(ts));
- if (ts->pchan == GSM_PCHAN_TCH_F_PDCH)
- vty_out(vty, " (%s mode)",
- ts->flags & TS_F_PDCH_ACTIVE ? "PDCH" : "TCH/F");
- vty_out(vty, "%s", VTY_NEWLINE);
- vty_out(vty, " NM State: ");
- net_dump_nmstate(vty, &ts->mo.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 [<0-255>] [<0-255>] [<0-7>]",
- 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 vlr_subscr *vsub)
-{
- OSMO_ASSERT(vsub);
- if (strlen(vsub->name))
- vty_out(vty, " Name: '%s'%s", vsub->name, VTY_NEWLINE);
- if (strlen(vsub->msisdn))
- vty_out(vty, " Extension: %s%s", vsub->msisdn,
- VTY_NEWLINE);
- if (strlen(vsub->imsi))
- vty_out(vty, " IMSI: %s%s", vsub->imsi, VTY_NEWLINE);
- if (vsub->tmsi != GSM_RESERVED_TMSI)
- vty_out(vty, " TMSI: %08X%s", vsub->tmsi,
- VTY_NEWLINE);
- if (vsub->tmsi_new != GSM_RESERVED_TMSI)
- vty_out(vty, " new TMSI: %08X%s", vsub->tmsi_new,
- VTY_NEWLINE);
-
- vty_out(vty, " Use count: %u%s", vsub->use_count, VTY_NEWLINE);
-}
-
-static void bsc_subscr_dump_vty(struct vty *vty, struct bsc_subscr *bsub)
-{
- if (strlen(bsub->imsi))
- vty_out(vty, " IMSI: %s%s", bsub->imsi, VTY_NEWLINE);
- if (bsub->tmsi != GSM_RESERVED_TMSI)
- vty_out(vty, " TMSI: 0x%08x%s", bsub->tmsi,
- VTY_NEWLINE);
- vty_out(vty, " Use count: %d%s", bsub->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: %d%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");
-}
-
-/* FIXME: move this to libosmogsm */
-static const struct value_string gsm48_cmode_names[] = {
- { GSM48_CMODE_SIGN, "signalling" },
- { GSM48_CMODE_SPEECH_V1, "FR or HR" },
- { GSM48_CMODE_SPEECH_EFR, "EFR" },
- { GSM48_CMODE_SPEECH_AMR, "AMR" },
- { GSM48_CMODE_DATA_14k5, "CSD(14k5)" },
- { GSM48_CMODE_DATA_12k0, "CSD(12k0)" },
- { GSM48_CMODE_DATA_6k0, "CSD(6k0)" },
- { GSM48_CMODE_DATA_3k6, "CSD(3k6)" },
- { 0, NULL }
-};
-
-/* call vty_out() to print a string like " as TCH/H" for dynamic timeslots.
- * Don't do anything if the ts is not dynamic. */
-static void vty_out_dyn_ts_status(struct vty *vty, struct gsm_bts_trx_ts *ts)
-{
- switch (ts->pchan) {
- case GSM_PCHAN_TCH_F_TCH_H_PDCH:
- if (ts->dyn.pchan_is == ts->dyn.pchan_want)
- vty_out(vty, " as %s",
- gsm_pchan_name(ts->dyn.pchan_is));
- else
- vty_out(vty, " switching %s -> %s",
- gsm_pchan_name(ts->dyn.pchan_is),
- gsm_pchan_name(ts->dyn.pchan_want));
- break;
- case GSM_PCHAN_TCH_F_PDCH:
- if ((ts->flags & TS_F_PDCH_PENDING_MASK) == 0)
- vty_out(vty, " as %s",
- (ts->flags & TS_F_PDCH_ACTIVE)? "PDCH"
- : "TCH/F");
- else
- vty_out(vty, " switching %s -> %s",
- (ts->flags & TS_F_PDCH_ACTIVE)? "PDCH"
- : "TCH/F",
- (ts->flags & TS_F_PDCH_ACT_PENDING)? "PDCH"
- : "TCH/F");
- break;
- default:
- /* no dyn ts */
- break;
- }
-}
-
-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);
- /* show dyn TS details, if applicable */
- switch (lchan->ts->pchan) {
- case GSM_PCHAN_TCH_F_TCH_H_PDCH:
- vty_out(vty, " Osmocom Dyn TS:");
- vty_out_dyn_ts_status(vty, lchan->ts);
- vty_out(vty, VTY_NEWLINE);
- break;
- case GSM_PCHAN_TCH_F_PDCH:
- vty_out(vty, " IPACC Dyn PDCH TS:");
- vty_out_dyn_ts_status(vty, lchan->ts);
- vty_out(vty, VTY_NEWLINE);
- break;
- default:
- /* no dyn ts */
- break;
- }
- vty_out(vty, " Connection: %u, State: %s%s%s%s",
- lchan->conn ? 1: 0,
- gsm_lchans_name(lchan->state),
- lchan->state == LCHAN_S_BROKEN ? " Error reason: " : "",
- lchan->state == LCHAN_S_BROKEN ? lchan->broken_reason : "",
- 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);
- vty_out(vty, " Channel Mode / Codec: %s%s",
- get_value_string(gsm48_cmode_names, lchan->tch_mode),
- VTY_NEWLINE);
- if (lchan->conn && lchan->conn->vsub) {
- vty_out(vty, " Subscriber:%s", VTY_NEWLINE);
- subscr_dump_vty(vty, lchan->conn->vsub);
- } 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 %s",
- lchan->ts->trx->bts->nr, lchan->ts->trx->nr, lchan->ts->nr,
- gsm_pchan_name(lchan->ts->pchan));
- vty_out_dyn_ts_status(vty, lchan->ts);
- vty_out(vty, ", Lchan %u, Type %s, State %s - "
- "L1 MS Power: %u dBm RXL-FULL-dl: %4d dBm RXL-FULL-ul: %4d dBm%s",
- lchan->nr,
- gsm_lchant_name(lchan->type), gsm_lchans_name(lchan->state),
- mr->ms_l1.pwr,
- rxlev2dbm(mr->dl.full.rx_lev),
- rxlev2dbm(mr->ul.full.rx_lev),
- VTY_NEWLINE);
-}
-
-
-static int dump_lchan_trx_ts(struct gsm_bts_trx_ts *ts, struct vty *vty,
- void (*dump_cb)(struct vty *, struct gsm_lchan *))
-{
- int lchan_nr;
- for (lchan_nr = 0; lchan_nr < TS_MAX_LCHAN; lchan_nr++) {
- struct gsm_lchan *lchan = &ts->lchan[lchan_nr];
- if ((lchan->type == GSM_LCHAN_NONE) && (lchan->state == LCHAN_S_NONE))
- continue;
- dump_cb(vty, lchan);
- }
-
- return CMD_SUCCESS;
-}
-
-static int dump_lchan_trx(struct gsm_bts_trx *trx, struct vty *vty,
- void (*dump_cb)(struct vty *, struct gsm_lchan *))
-{
- int ts_nr;
-
- for (ts_nr = 0; ts_nr < TRX_NR_TS; ts_nr++) {
- struct gsm_bts_trx_ts *ts = &trx->ts[ts_nr];
- dump_lchan_trx_ts(ts, vty, dump_cb);
- }
-
- return CMD_SUCCESS;
-}
-
-static int dump_lchan_bts(struct gsm_bts *bts, struct vty *vty,
- void (*dump_cb)(struct vty *, struct gsm_lchan *))
-{
- int trx_nr;
-
- for (trx_nr = 0; trx_nr < bts->num_trx; trx_nr++) {
- struct gsm_bts_trx *trx = gsm_bts_trx_num(bts, trx_nr);
- dump_lchan_trx(trx, vty, dump_cb);
- }
-
- return CMD_SUCCESS;
-}
-
-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 == 1)
- return dump_lchan_bts(bts, vty, dump_cb);
- }
- 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 == 2)
- return dump_lchan_trx(trx, vty, dump_cb);
- }
- 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 == 3)
- return dump_lchan_trx_ts(ts, vty, dump_cb);
- }
- 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);
- dump_lchan_bts(bts, vty, dump_cb);
- }
-
- return CMD_SUCCESS;
-}
-
-
-DEFUN(show_lchan,
- show_lchan_cmd,
- "show lchan [<0-255>] [<0-255>] [<0-7>] [lchan_nr]",
- SHOW_STR "Display information about a logical channel\n"
- "BTS Number\n" "TRX Number\n" "Timeslot Number\n"
- LCHAN_NR_STR)
-
-{
- return lchan_summary(vty, argc, argv, lchan_dump_full_vty);
-}
-
-DEFUN(show_lchan_summary,
- show_lchan_summary_cmd,
- "show lchan summary [<0-255>] [<0-255>] [<0-7>] [lchan_nr]",
- SHOW_STR "Display information about a logical channel\n"
- "Short summary\n"
- "BTS Number\n" "TRX Number\n" "Timeslot Number\n"
- LCHAN_NR_STR)
-{
- return lchan_summary(vty, argc, argv, lchan_dump_short_vty);
-}
-
-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);
- bsc_subscr_dump_vty(vty, pag->bsub);
-}
-
-static void bts_paging_dump_vty(struct vty *vty, struct gsm_bts *bts)
-{
- struct gsm_paging_request *pag;
-
- if (!bts->paging.bts)
- return;
-
- llist_for_each_entry(pag, &bts->paging.pending_requests, entry)
- paging_dump_vty(vty, pag);
-}
-
-DEFUN(show_paging,
- show_paging_cmd,
- "show paging [<0-255>]",
- 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;
-}
-
-DEFUN(show_paging_group,
- show_paging_group_cmd,
- "show paging-group <0-255> IMSI",
- SHOW_STR "Display the paging group\n"
- "BTS Number\n" "IMSI\n")
-{
- struct gsm_network *net = gsmnet_from_vty(vty);
- struct gsm_bts *bts;
- unsigned int page_group;
- int 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 (!bts) {
- vty_out(vty, "%% can't find BTS %s%s", argv[0], VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- page_group = gsm0502_calc_paging_group(&bts->si_common.chan_desc,
- str_to_imsi(argv[1]));
- vty_out(vty, "%%Paging group for IMSI %" PRIu64 " on BTS #%d is %u%s",
- str_to_imsi(argv[1]), bts->nr,
- page_group, VTY_NEWLINE);
- 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;
-}
-
-#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"
-#define HO_AVG_COUNT_STR "Amount to use for Averaging\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\n"
- HO_AVG_COUNT_STR)
-{
- 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\n"
- HO_AVG_COUNT_STR)
-{
- 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 "Neighbor\n"
- "How many RxQual measurements are used for averaging\n"
- HO_AVG_COUNT_STR)
-{
- 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)\n"
- "Interval\n" "Number\n")
-{
- 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\n"
- "Hysteresis\n" "Number\n")
-{
- 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\n"
- "Distance\n" "Number\n")
-{
- 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\n"
- "Any Channel\n" "Use\n" "TCH\n"
- "Do not use TCH for Paging Request Any\n"
- "Do use TCH for Paging Request Any\n")
-{
- 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 "Timer Value in seconds\n") \
-{ \
- 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.\n")
-DECLARE_TIMER(3103, "Set the timeout value for HANDOVER.\n")
-DECLARE_TIMER(3105, "Set the timer for repetition of PHYSICAL INFORMATION.\n")
-DECLARE_TIMER(3107, "Currently not used.\n")
-DECLARE_TIMER(3109, "Set the RSL SACCH deactivation timeout.\n")
-DECLARE_TIMER(3111, "Set the RSL timeout to wait before releasing the RF Channel.\n")
-DECLARE_TIMER(3113, "Set the time to try paging a subscriber.\n")
-DECLARE_TIMER(3115, "Currently not used.\n")
-DECLARE_TIMER(3117, "Currently not used.\n")
-DECLARE_TIMER(3119, "Currently not used.\n")
-DECLARE_TIMER(3122, "Waiting time (seconds) after IMM ASS REJECT\n")
-DECLARE_TIMER(3141, "Currently not used.\n")
-
-DEFUN_DEPRECATED(cfg_net_dtx,
- cfg_net_dtx_cmd,
- "dtx-used (0|1)",
- ".HIDDEN\n""Obsolete\n""Obsolete\n")
-{
- vty_out(vty, "%% 'dtx-used' is now deprecated: use dtx * "
- "configuration options of BTS instead%s", VTY_NEWLINE);
- return CMD_SUCCESS;
-}
-
-/* per-BTS configuration */
-DEFUN(cfg_bts,
- cfg_bts_cmd,
- "bts <0-255>",
- "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_register(gsmnet, GSM_BTS_TYPE_UNKNOWN,
- 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", /* dynamically created */
- "Set the BTS type\n" "Type\n")
-{
- struct gsm_bts *bts = vty->index;
- int rc;
-
- rc = gsm_set_bts_type(bts, str2btstype(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" "Frequency band\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_dtxu, cfg_bts_dtxu_cmd, "dtx uplink [force]",
- "Configure discontinuous transmission\n"
- "Enable Uplink DTX for this BTS\n"
- "MS 'shall' use DTXu instead of 'may' use (might not be supported by "
- "older phones).\n")
-{
- struct gsm_bts *bts = vty->index;
-
- bts->dtxu = (argc > 0) ? GSM48_DTX_SHALL_BE_USED : GSM48_DTX_MAY_BE_USED;
- if (!is_ipaccess_bts(bts))
- vty_out(vty, "%% DTX enabled on non-IP BTS: this configuration "
- "neither supported nor tested!%s", VTY_NEWLINE);
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_bts_no_dtxu, cfg_bts_no_dtxu_cmd, "no dtx uplink",
- NO_STR
- "Configure discontinuous transmission\n"
- "Disable Uplink DTX for this BTS\n")
-{
- struct gsm_bts *bts = vty->index;
-
- bts->dtxu = GSM48_DTX_SHALL_NOT_BE_USED;
-
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_bts_dtxd, cfg_bts_dtxd_cmd, "dtx downlink",
- "Configure discontinuous transmission\n"
- "Enable Downlink DTX for this BTS\n")
-{
- struct gsm_bts *bts = vty->index;
-
- bts->dtxd = true;
- if (!is_ipaccess_bts(bts))
- vty_out(vty, "%% DTX enabled on non-IP BTS: this configuration "
- "neither supported nor tested!%s", VTY_NEWLINE);
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_bts_no_dtxd, cfg_bts_no_dtxd_cmd, "no dtx downlink",
- NO_STR
- "Configure discontinuous transmission\n"
- "Disable Downlink DTX for this BTS\n")
-{
- struct gsm_bts *bts = vty->index;
-
- bts->dtxd = false;
-
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_bts_ci,
- cfg_bts_ci_cmd,
- "cell_identity <0-65535>",
- "Set the Cell identity of this BTS\n" "Cell Identity\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" "LAC\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;
-}
-
-
-/* compatibility wrapper for old config files */
-DEFUN_HIDDEN(cfg_bts_tsc,
- cfg_bts_tsc_cmd,
- "training_sequence_code <0-7>",
- "Set the Training Sequence Code (TSC) of this BTS\n" "TSC\n")
-{
- 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"
- "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>",
- "Abis/IP specific options\n"
- "Set the IPA BTS Unit ID\n"
- "Unit ID (Site)\n"
- "Unit ID (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;
-}
-
-DEFUN(cfg_bts_rsl_ip,
- cfg_bts_rsl_ip_cmd,
- "ip.access rsl-ip A.B.C.D",
- "Abis/IP specific options\n"
- "Set the IPA RSL IP Address of the BSC\n"
- "Destination IP address for RSL connection\n")
-{
- struct gsm_bts *bts = vty->index;
- struct in_addr ia;
-
- if (!is_ipaccess_bts(bts)) {
- vty_out(vty, "%% BTS is not of ip.access type%s", VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- inet_aton(argv[0], &ia);
- bts->ip_access.rsl_ip = ntohl(ia.s_addr);
-
- return CMD_SUCCESS;
-}
-
-#define NOKIA_STR "Nokia *Site related commands\n"
-
-DEFUN(cfg_bts_nokia_site_skip_reset,
- cfg_bts_nokia_site_skip_reset_cmd,
- "nokia_site skip-reset (0|1)",
- NOKIA_STR
- "Skip the reset step during bootstrap process of this BTS\n"
- "Do NOT skip the reset\n" "Skip the reset\n")
-{
- struct gsm_bts *bts = vty->index;
-
- if (bts->type != GSM_BTS_TYPE_NOKIA_SITE) {
- vty_out(vty, "%% BTS is not of Nokia *Site type%s", VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- bts->nokia.skip_reset = atoi(argv[0]);
-
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_bts_nokia_site_no_loc_rel_cnf,
- cfg_bts_nokia_site_no_loc_rel_cnf_cmd,
- "nokia_site no-local-rel-conf (0|1)",
- NOKIA_STR
- "Do not wait for RELease CONFirm message when releasing channel locally\n"
- "Wait for RELease CONFirm\n" "Do not wait for RELease CONFirm\n")
-{
- struct gsm_bts *bts = vty->index;
-
- if (!is_nokia_bts(bts)) {
- vty_out(vty, "%% BTS is not of Nokia *Site type%s",
- VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- bts->nokia.no_loc_rel_cnf = atoi(argv[0]);
-
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_bts_nokia_site_bts_reset_timer_cnf,
- cfg_bts_nokia_site_bts_reset_timer_cnf_cmd,
- "nokia_site bts-reset-timer <15-100>",
- NOKIA_STR
- "The amount of time (in sec.) between BTS_RESET is sent,\n"
- "and the BTS is being bootstrapped.\n")
-{
- struct gsm_bts *bts = vty->index;
-
- if (!is_nokia_bts(bts)) {
- vty_out(vty, "%% BTS is not of Nokia *Site type%s",
- VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- bts->nokia.bts_reset_timer_cnf = atoi(argv[0]);
-
- return CMD_SUCCESS;
-}
-#define OML_STR "Organization & Maintenance Link\n"
-#define IPA_STR "A-bis/IP Specific Options\n"
-
-DEFUN(cfg_bts_stream_id,
- cfg_bts_stream_id_cmd,
- "oml ip.access stream_id <0-255> line E1_LINE",
- OML_STR IPA_STR
- "Set the ip.access Stream ID of the OML link of this BTS\n"
- "Stream Identifier\n" "Virtual E1 Line Number\n" "Virtual E1 Line Number\n")
-{
- struct gsm_bts *bts = vty->index;
- int stream_id = atoi(argv[0]), linenr = 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->oml_tei = stream_id;
- /* This is used by e1inp_bind_ops callback for each BTS model. */
- bts->oml_e1_link.e1_nr = linenr;
-
- return CMD_SUCCESS;
-}
-
-#define OML_E1_STR OML_STR "OML E1/T1 Configuration\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/T1 line number to be used for OML\n"
- "E1/T1 line number to be used for OML\n"
- "E1/T1 timeslot to be used for OML\n"
- "E1/T1 timeslot to be used for OML\n"
- "E1/T1 sub-slot to be used for OML\n"
- "Use E1/T1 sub-slot 0\n"
- "Use E1/T1 sub-slot 1\n"
- "Use E1/T1 sub-slot 2\n"
- "Use E1/T1 sub-slot 3\n"
- "Use full E1 slot 3\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\n"
- "TEI Number\n")
-{
- 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\n"
- "Set the raw tx integer value in RACH Control parameters IE\n"
- "Raw tx integer value in RACH Control parameters IE\n")
-{
- 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\n"
- "Set the maximum number of RACH burst transmissions\n"
- "Maximum number of 1 RACH burst transmissions\n"
- "Maximum number of 2 RACH burst transmissions\n"
- "Maximum number of 4 RACH burst transmissions\n"
- "Maximum number of 7 RACH burst transmissions\n")
-{
- struct gsm_bts *bts = vty->index;
- bts->si_common.rach_control.max_trans = rach_max_trans_val2raw(atoi(argv[0]));
- return CMD_SUCCESS;
-}
-
-#define CD_STR "Channel Description\n"
-
-DEFUN(cfg_bts_chan_desc_att,
- cfg_bts_chan_desc_att_cmd,
- "channel-descrption attach (0|1)",
- CD_STR
- "Set if attachment is required\n"
- "Attachment is NOT required\n"
- "Attachment is required (standard)\n")
-{
- struct gsm_bts *bts = vty->index;
- bts->si_common.chan_desc.att = atoi(argv[0]);
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_bts_chan_desc_bs_pa_mfrms,
- cfg_bts_chan_desc_bs_pa_mfrms_cmd,
- "channel-descrption bs-pa-mfrms <2-9>",
- CD_STR
- "Set number of multiframe periods for paging groups\n"
- "Number of multiframe periods for paging groups\n")
-{
- struct gsm_bts *bts = vty->index;
- int bs_pa_mfrms = atoi(argv[0]);
-
- bts->si_common.chan_desc.bs_pa_mfrms = bs_pa_mfrms - 2;
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_bts_chan_desc_bs_ag_blks_res,
- cfg_bts_chan_desc_bs_ag_blks_res_cmd,
- "channel-descrption bs-ag-blks-res <0-7>",
- CD_STR
- "Set number of blocks reserved for access grant\n"
- "Number of blocks reserved for access grant\n")
-{
- struct gsm_bts *bts = vty->index;
- int bs_ag_blks_res = atoi(argv[0]);
-
- bts->si_common.chan_desc.bs_ag_blks_res = bs_ag_blks_res;
- 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\n"
- "Set the NM Busy Threshold\n"
- "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\n"
- "Set the NM Loadaverage Slots value\n"
- "NM Loadaverage Slots value\n")
-{
- 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?\n"
- "Should this cell be barred from access?\n"
- "Cell should NOT be barred\n"
- "Cell should be barred\n")
-
-{
- 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)",
- RACH_STR
- "Should this cell allow emergency calls?\n"
- "Should this cell allow emergency calls?\n"
- "Should this cell allow emergency calls?\n"
- "Do NOT allow emergency calls\n"
- "Allow emergency calls\n")
-{
- 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_rach_ac_class, cfg_bts_rach_ac_class_cmd,
- "rach access-control-class (0|1|2|3|4|5|6|7|8|9|11|12|13|14|15) (barred|allowed)",
- RACH_STR
- "Set access control class\n"
- "Access control class 0\n"
- "Access control class 1\n"
- "Access control class 2\n"
- "Access control class 3\n"
- "Access control class 4\n"
- "Access control class 5\n"
- "Access control class 6\n"
- "Access control class 7\n"
- "Access control class 8\n"
- "Access control class 9\n"
- "Access control class 11 for PLMN use\n"
- "Access control class 12 for security services\n"
- "Access control class 13 for public utilities (e.g. water/gas suppliers)\n"
- "Access control class 14 for emergency services\n"
- "Access control class 15 for PLMN staff\n"
- "barred to use access control class\n"
- "allowed to use access control class\n")
-{
- struct gsm_bts *bts = vty->index;
-
- uint8_t control_class;
- uint8_t allowed = 0;
-
- if (strcmp(argv[1], "allowed") == 0)
- allowed = 1;
-
- control_class = atoi(argv[0]);
- if (control_class < 8)
- if (allowed)
- bts->si_common.rach_control.t3 &= ~(0x1 << control_class);
- else
- bts->si_common.rach_control.t3 |= (0x1 << control_class);
- else
- if (allowed)
- bts->si_common.rach_control.t2 &= ~(0x1 << (control_class - 8));
- else
- bts->si_common.rach_control.t2 |= (0x1 << (control_class - 8));
-
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_bts_ms_max_power, cfg_bts_ms_max_power_cmd,
- "ms max power <0-40>",
- "MS Options\n"
- "Maximum transmit power of the MS\n"
- "Maximum transmit power of the MS\n"
- "Maximum transmit power of the MS in dBm")
-{
- struct gsm_bts *bts = vty->index;
-
- bts->ms_max_power = atoi(argv[0]);
-
- return CMD_SUCCESS;
-}
-
-#define CELL_STR "Cell Parameters\n"
-
-DEFUN(cfg_bts_cell_resel_hyst, cfg_bts_cell_resel_hyst_cmd,
- "cell reselection hysteresis <0-14>",
- CELL_STR "Cell re-selection parameters\n"
- "Cell Re-Selection Hysteresis in dB\n"
- "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\n"
- "Minimum RxLev needed for cell access\n"
- "Minimum RxLev needed for cell access\n"
- "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_STR "Cell Bar Qualify\n" "Cell Bar Qualify\n"
- "Set CBQ to 0\n" "Set CBQ to 1\n")
-{
- 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_STR "Cell Re-Selection Parameters\n"
- "Cell Re-Selection Offset (CRO) in dB\n"
- "Cell Re-Selection Offset (CRO) in dB\n"
- )
-{
- 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\n"
- "Cell selection temporary negative offset\n"
- "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",
- "Cell selection temporary negative offset\n"
- "Cell selection temporary negative offset\n"
- "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\n"
- "Cell selection penalty time\n"
- "Cell selection penalty time in seconds (by 20s increments)\n")
-{
- 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",
- "Cell selection penalty time\n"
- "Cell selection penalty time\n"
- "Set cell selection penalty time to reserved value 31, "
- "(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_radio_link_timeout, cfg_bts_radio_link_timeout_cmd,
- "radio-link-timeout <4-64>",
- "Radio link timeout criterion (BTS side)\n"
- "Radio link timeout value (lost SACCH block)\n")
-{
- struct gsm_bts *bts = vty->index;
-
- gsm_bts_set_radio_link_timeout(bts, atoi(argv[0]));
-
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_bts_radio_link_timeout_inf, cfg_bts_radio_link_timeout_inf_cmd,
- "radio-link-timeout infinite",
- "Radio link timeout criterion (BTS side)\n"
- "Infinite Radio link timeout value (use only for BTS RF testing)\n")
-{
- struct gsm_bts *bts = vty->index;
-
- if (bts->type != GSM_BTS_TYPE_OSMOBTS) {
- vty_out(vty, "%% infinite radio link timeout not supported by this BTS%s", VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- vty_out(vty, "%% INFINITE RADIO LINK TIMEOUT, USE ONLY FOR BTS RF TESTING%s", VTY_NEWLINE);
- gsm_bts_set_radio_link_timeout(bts, -1);
-
- 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\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\n"
- "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\n"
- "GPRS NS Local UDP Port\n"
- "GPRS NS Local UDP Port\n"
- "GPRS NS Local UDP Port Number\n")
-{
- 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\n"
- "GPRS NS Remote UDP Port\n"
- "GPRS NS Remote UDP Port\n"
- "GPRS NS Remote UDP Port Number\n")
-{
- 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\n"
- "GPRS NS Remote IP Address\n"
- "GPRS NS Remote IP Address\n")
-{
- 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 <-1-1024>",
- "Paging options\n"
- "Only page when having a certain amount of free slots\n"
- "amount of required free paging slots. -1 to disable\n")
-{
- 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\n"
- "GPRS Routing Area Code\n"
- "GPRS Routing Area Code\n")
-{
- 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_ctrl_ack, cfg_bts_gprs_ctrl_ack_cmd,
- "gprs control-ack-type-rach", GPRS_TEXT
- "Set GPRS Control Ack Type for PACKET CONTROL ACKNOWLEDGMENT message to "
- "four access bursts format instead of default RLC/MAC control block\n")
-{
- 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.ctrl_ack_type_use_block = false;
-
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_no_bts_gprs_ctrl_ack, cfg_no_bts_gprs_ctrl_ack_cmd,
- "no gprs control-ack-type-rach", NO_STR GPRS_TEXT
- "Set GPRS Control Ack Type for PACKET CONTROL ACKNOWLEDGMENT message to "
- "four access bursts format instead of default RLC/MAC control block\n")
-{
- 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.ctrl_ack_type_use_block = true;
-
- return CMD_SUCCESS;
-}
-
-DEFUN(cfg_bts_gprs_net_ctrl_ord, cfg_bts_gprs_net_ctrl_ord_cmd,
- "gprs network-control-order (nc0|nc1|nc2)",
- GPRS_TEXT
- "GPRS Network Control Order\n"
- "MS controlled cell re-selection, no measurement reporting\n"
- "MS controlled cell re-selection, MS sends measurement reports\n"
- "Network controlled cell re-selection, MS sends measurement reports\n")
-{
- 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.net_ctrl_ord = atoi(argv[0] + 2);
-
- 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], NULL);
-
- if (!bts_gprs_mode_is_compat(bts, mode)) {
- 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;
-}
-
-DEFUN(cfg_bts_gprs_11bit_rach_support_for_egprs,
- cfg_bts_gprs_11bit_rach_support_for_egprs_cmd,
- "gprs 11bit_rach_support_for_egprs (0|1)",
- GPRS_TEXT "11 bit RACH options\n"
- "Disable 11 bit RACH for EGPRS\n"
- "Enable 11 bit RACH for EGPRS")
-{
- struct gsm_bts *bts = vty->index;
-
- bts->gprs.supports_egprs_11bit_rach = atoi(argv[0]);
-
- if (bts->gprs.supports_egprs_11bit_rach > 1) {
- vty_out(vty, "Error in RACH type%s", VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- if ((bts->gprs.mode == BTS_GPRS_NONE) &&
- (bts->gprs.supports_egprs_11bit_rach == 1)) {
- vty_out(vty, "Error:gprs mode is none and 11bit rach is"
- " enabled%s", VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- 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(GSM_BTS_SI(bts, type), 0x2b, GSM_MACBLOCK_LEN);
-
- /* Parse the user-specified SI in hex format, [partially] overwriting padding */
- rc = osmo_hexparse(argv[1], GSM_BTS_SI(bts, type), GSM_MACBLOCK_LEN);
- if (rc < 0 || rc > GSM_MACBLOCK_LEN) {
- 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_early_cm, cfg_bts_early_cm_cmd,
- "early-classmark-sending (allowed|forbidden)",
- "Early Classmark Sending\n"
- "Early Classmark Sending is allowed\n"
- "Early Classmark Sending is forbidden\n")
-{
- struct gsm_bts *bts = vty->index;
-
- if (!strcmp(argv[0], "allowed"))
- bts->early_classmark_allowed = true;
- else
- bts->early_classmark_allowed = false;
-
- 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 */