aboutsummaryrefslogtreecommitdiffstats
path: root/openbsc/src
diff options
context:
space:
mode:
authorMax <msuraev@sysmocom.de>2018-11-25 19:25:30 +0100
committerHarald Welte <laforge@gnumonks.org>2018-12-06 09:56:35 +0000
commit07bcda7554a981cb23af9eb4ea9f5e23573580c6 (patch)
tree79d54fe40542d28784e3d1888c587aa6ed0a04f2 /openbsc/src
parentd0415ec1172b396153a28a10156fd3bc095eec69 (diff)
Remove ipaccess utils
There's increasing gap in functionality between ipaccess utils from this repo and from osmo-bsc due to ongoing development in new repository. To avoid potential user confusion let's drop them similar to the way SGSN was removed earlier. Change-Id: I9c04f9b469e60802461a2a6e421d3ba27e6dafa1
Diffstat (limited to 'openbsc/src')
-rw-r--r--openbsc/src/Makefile.am1
-rw-r--r--openbsc/src/ipaccess/Makefile.am66
-rw-r--r--openbsc/src/ipaccess/abisip-find.c216
-rw-r--r--openbsc/src/ipaccess/ipaccess-config.c1019
-rw-r--r--openbsc/src/ipaccess/ipaccess-firmware.c135
-rw-r--r--openbsc/src/ipaccess/ipaccess-proxy.c1226
-rw-r--r--openbsc/src/ipaccess/network_listen.c257
7 files changed, 0 insertions, 2920 deletions
diff --git a/openbsc/src/Makefile.am b/openbsc/src/Makefile.am
index e579ea0fc..86d6f8f83 100644
--- a/openbsc/src/Makefile.am
+++ b/openbsc/src/Makefile.am
@@ -42,7 +42,6 @@ SUBDIRS += \
osmo-nitb \
osmo-bsc_mgcp \
utils \
- ipaccess \
$(NULL)
# Conditional Programs
diff --git a/openbsc/src/ipaccess/Makefile.am b/openbsc/src/ipaccess/Makefile.am
deleted file mode 100644
index 4dfe24738..000000000
--- a/openbsc/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/openbsc/src/ipaccess/abisip-find.c b/openbsc/src/ipaccess/abisip-find.c
deleted file mode 100644
index 21d9f2290..000000000
--- a/openbsc/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/openbsc/src/ipaccess/ipaccess-config.c b/openbsc/src/ipaccess/ipaccess-config.c
deleted file mode 100644
index 6822c06a6..000000000
--- a/openbsc/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/openbsc/src/ipaccess/ipaccess-firmware.c b/openbsc/src/ipaccess/ipaccess-firmware.c
deleted file mode 100644
index 5f55bb526..000000000
--- a/openbsc/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/openbsc/src/ipaccess/ipaccess-proxy.c b/openbsc/src/ipaccess/ipaccess-proxy.c
deleted file mode 100644
index d3674426c..000000000
--- a/openbsc/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/openbsc/src/ipaccess/network_listen.c b/openbsc/src/ipaccess/network_listen.c
deleted file mode 100644
index 43d82a97a..000000000
--- a/openbsc/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: %s, LAC %d CI %d BSIC %u\n",
- binfo.arfcn, binfo.rx_lev, binfo.rx_qual,
- osmo_plmn_name(&binfo.cgi.lai.plmn),
- binfo.cgi.lai.lac, binfo.cgi.cell_identity, 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);
-}