From 07bcda7554a981cb23af9eb4ea9f5e23573580c6 Mon Sep 17 00:00:00 2001 From: Max Date: Sun, 25 Nov 2018 19:25:30 +0100 Subject: 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 --- debian/control | 9 - debian/osmocom-ipaccess-utils.install | 3 - debian/rules | 1 - openbsc/README | 1 - openbsc/configure.ac | 1 - openbsc/src/Makefile.am | 1 - openbsc/src/ipaccess/Makefile.am | 66 -- openbsc/src/ipaccess/abisip-find.c | 216 ------ openbsc/src/ipaccess/ipaccess-config.c | 1019 ------------------------- openbsc/src/ipaccess/ipaccess-firmware.c | 135 ---- openbsc/src/ipaccess/ipaccess-proxy.c | 1226 ------------------------------ openbsc/src/ipaccess/network_listen.c | 257 ------- 12 files changed, 2935 deletions(-) delete mode 100644 debian/osmocom-ipaccess-utils.install delete mode 100644 openbsc/src/ipaccess/Makefile.am delete mode 100644 openbsc/src/ipaccess/abisip-find.c delete mode 100644 openbsc/src/ipaccess/ipaccess-config.c delete mode 100644 openbsc/src/ipaccess/ipaccess-firmware.c delete mode 100644 openbsc/src/ipaccess/ipaccess-proxy.c delete mode 100644 openbsc/src/ipaccess/network_listen.c diff --git a/debian/control b/debian/control index 0e9bb0cb4..a841acfe8 100644 --- a/debian/control +++ b/debian/control @@ -42,15 +42,6 @@ Description: GSM Network-in-a-Box, implements BSC, MSC, SMSC, HLR, VLR components bundled together. When using osmocom-nitb, there is no need for a Mobile Switching Center (MSC) which is needed when using osmocom-bsc-sccplite. -Package: osmocom-ipaccess-utils -Architecture: any -Depends: ${shlibs:Depends}, - ${misc:Depends} -Description: Command line utilities for ip.access nanoBTS - This package contains utilities that are specific for nanoBTS when being used - together with OpenBSC. It contains mainly three tools: ipaccess-find, - ipaccess-config and ipaccess-proxy. - Package: osmocom-bs11-utils Architecture: any Depends: ${shlibs:Depends}, diff --git a/debian/osmocom-ipaccess-utils.install b/debian/osmocom-ipaccess-utils.install deleted file mode 100644 index de13c1896..000000000 --- a/debian/osmocom-ipaccess-utils.install +++ /dev/null @@ -1,3 +0,0 @@ -/usr/bin/ipaccess-config -/usr/bin/abisip-find -/usr/bin/ipaccess-proxy diff --git a/debian/rules b/debian/rules index dc609f941..0ea9b23d9 100755 --- a/debian/rules +++ b/debian/rules @@ -19,7 +19,6 @@ override_dh_autoreconf: override_dh_strip: dh_strip -posmocom-bsc-sccplite --dbg-package=osmocom-bsc-sccplite-dbg dh_strip -posmocom-nitb --dbg-package=osmocom-nitb-dbg - dh_strip -posmocom-ipaccess-utils --dbg-package=osmocom-ipaccess-utils-dbg dh_strip -posmocom-bs11-utils --dbg-package=osmocom-bs11-utils-dbg dh_strip -posmocom-bsc-nat --dbg-package=osmocom-bsc-nat-dbg diff --git a/openbsc/README b/openbsc/README index d01b2cf9a..bffdd8123 100644 --- a/openbsc/README +++ b/openbsc/README @@ -14,7 +14,6 @@ implementing protocol stacks and functional elements, including * Osmo-GbProxy - a Proxy to aggregate many Gb links as one Gb link to the SGSN * OsmoBSCNAT - a gateway aggregating many A links as one A link to the MSC * OsmoGTPHUB - a hub aggregating many GTP links (between SGSN and GGSN) - * ipaccess-utils - some tools to discover + configure ip.access nanoBTS * bs11_config - a tool to configure the Siemens BS-11 microBTS Various interfaces towards the BTS are supported, among which are: diff --git a/openbsc/configure.ac b/openbsc/configure.ac index 75dd5d33f..64285e051 100644 --- a/openbsc/configure.ac +++ b/openbsc/configure.ac @@ -259,7 +259,6 @@ AC_OUTPUT( src/osmo-bsc/Makefile src/osmo-bsc_nat/Makefile src/osmo-bsc_mgcp/Makefile - src/ipaccess/Makefile src/utils/Makefile tests/Makefile tests/atlocal 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 - * 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 . - * - */ - -#include -#include -#include -#include -#include -#include - - -#include -#include -#include -#include -#include - -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 - * (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 . - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -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 - * 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 . - * - */ - -#include -#include -#include - -#include -#include -#include -#include - -#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 - * (C) 2010 by On-Waves - * (C) 2010 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 . - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define _GNU_SOURCE -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* 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 - * - * 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 . - * - */ - -#include -#include -#include -#include -#include -#include - -#include - -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#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); -} -- cgit v1.2.3