From 825607672215b7a12ea6e201a89cd5209f6d657f Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Thu, 19 May 2011 08:55:32 +0200 Subject: logging: fix corrupted output Harald reported a problem in the logging: http://lists.osmocom.org/pipermail/openbsc/2011-May/002896.html Reverting 81e9636454294ae10ef9bc8bf149dd0248afce76 seems to fix the problem. However, that workaround looks ugly. Holger gives us another clue on what was wrong: http://lists.osmocom.org/pipermail/openbsc/2011-May/002905.html While digging in the manpage, I found this: "The functions vprintf(), vfprintf(), vsprintf(), vsnprintf() are equivalent to the functions printf(), fprintf(), sprintf(), snprintf(), respectively, except that they are called with a va_list instead of a variable number of arguments. These functions do not call the va_end macro. Consequently, the value of ap is undefined after the call. The application should call va_end(ap) itself afterwards." --- src/logging.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/logging.c b/src/logging.c index 0911010a..3c9dc03f 100644 --- a/src/logging.c +++ b/src/logging.c @@ -198,6 +198,7 @@ static void _logp(unsigned int subsys, int level, char *file, int line, llist_for_each_entry(tar, &osmo_log_target_list, entry) { struct log_category *category; int output = 0; + va_list bp; category = &tar->categories[subsys]; /* subsystem is not supposed to be logged */ @@ -224,7 +225,12 @@ static void _logp(unsigned int subsys, int level, char *file, int line, if (!output) continue; + /* According to the manpage, vsnprintf leaves the value of ap + * in undefined state. Since _output uses vsnprintf and it may + * be called several times, we have to pass a copy of ap. */ + va_copy(bp, ap); _output(tar, subsys, level, file, line, cont, format, ap); + va_end(bp); } } -- cgit v1.2.3 From 33cb71ac91fb870702dbb71595dba4a554001e3c Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sat, 21 May 2011 18:54:32 +0200 Subject: gsmtap: rework GSMTAP API to be more future-proof * use write_queue where applicable * provide functions that work on raw FD and those with osmo_fd * add support for multiple gsmtap instances (no global variables) --- include/osmocom/core/Makefile.am | 2 +- include/osmocom/core/gsmtap_util.h | 46 +++++++-- include/osmocom/core/socket.h | 16 ++++ src/Makefile.am | 4 +- src/gsmtap_util.c | 192 ++++++++++++++++++++----------------- src/socket.c | 143 +++++++++++++++++++++++++++ 6 files changed, 305 insertions(+), 98 deletions(-) create mode 100644 include/osmocom/core/socket.h create mode 100644 src/socket.c diff --git a/include/osmocom/core/Makefile.am b/include/osmocom/core/Makefile.am index 36988733..3c30362c 100644 --- a/include/osmocom/core/Makefile.am +++ b/include/osmocom/core/Makefile.am @@ -1,5 +1,5 @@ osmocore_HEADERS = signal.h linuxlist.h timer.h select.h msgb.h bits.h \ - bitvec.h statistics.h utils.h \ + bitvec.h statistics.h utils.h socket.h \ gsmtap.h write_queue.h \ logging.h rate_ctr.h gsmtap_util.h \ plugin.h crc16.h panic.h process.h msgfile.h \ diff --git a/include/osmocom/core/gsmtap_util.h b/include/osmocom/core/gsmtap_util.h index 785f5e58..f553c17a 100644 --- a/include/osmocom/core/gsmtap_util.h +++ b/include/osmocom/core/gsmtap_util.h @@ -2,24 +2,52 @@ #define _GSMTAP_UTIL_H #include +#include +#include /* convert RSL channel number to GSMTAP channel type */ uint8_t chantype_rsl2gsmtap(uint8_t rsl_chantype, uint8_t rsl_link_id); -/* receive a message from L1/L2 and put it in GSMTAP */ +/* generate msgb from data + metadata */ struct msgb *gsmtap_makemsg(uint16_t arfcn, uint8_t ts, uint8_t chan_type, uint8_t ss, uint32_t fn, int8_t signal_dbm, uint8_t snr, const uint8_t *data, unsigned int len); -/* receive a message from L1/L2 and put it in GSMTAP */ -int gsmtap_sendmsg(uint16_t arfcn, uint8_t ts, uint8_t chan_type, uint8_t ss, - uint32_t fn, int8_t signal_dbm, uint8_t snr, - const uint8_t *data, unsigned int len); +/* one gsmtap instance */ +struct gsmtap_inst { + int ofd_wq_mode; + struct osmo_wqueue wq; + struct osmo_fd sink_ofd; +}; -int gsmtap_init(uint32_t dst_ip); +static inline int gsmtap_inst_fd(struct gsmtap_inst *gti) +{ + return gti->wq.bfd.fd; +} -/* Create a local 'gsmtap sink' avoiding the UDP packets being rejected - * with ICMP reject messages */ -int gsmtap_sink_init(uint32_t bind_ip); +/* Open a GSMTAP source (sending) socket, conncet it to host/port and + * return resulting fd */ +int gsmtap_source_init_fd(const char *host, uint16_t port); + +/* Add a local sink to an existing GSMTAP source and return fd */ +int gsmtap_source_add_sink_fd(int gsmtap_fd); + +/* Open GSMTAP source (sending) socket, connect it to host/port, + * allocate 'struct gsmtap_inst' and optionally osmo_fd/osmo_wqueue + * registration */ +struct gsmtap_inst *gsmtap_source_init(const char *host, uint16_t port, + int ofd_wq_mode); + +/* Add a local sink to an existing GSMTAP source instance */ +int gsmtap_source_add_sink(struct gsmtap_inst *gti); + +/* Send a msgb through a GSMTAP source */ +int gsmtap_sendmsg(struct gsmtap_inst *gti, struct msgb *msg); + +/* generate a message and send it via GSMTAP */ +int gsmtap_send(struct gsmtap_inst *gti, uint16_t arfcn, uint8_t ts, + uint8_t chan_type, uint8_t ss, uint32_t fn, + int8_t signal_dbm, uint8_t snr, const uint8_t *data, + unsigned int len); #endif /* _GSMTAP_UTIL_H */ diff --git a/include/osmocom/core/socket.h b/include/osmocom/core/socket.h new file mode 100644 index 00000000..3ede524b --- /dev/null +++ b/include/osmocom/core/socket.h @@ -0,0 +1,16 @@ +#ifndef _OSMOCORE_SOCKET_H +#define _OSMOCORE_SOCKET_H + +#include +#include + +int osmo_sock_init(uint16_t family, uint16_t type, uint8_t proto, + const char *host, uint16_t port, int connect0_bind1); + +int osmo_sock_init_sa(struct sockaddr *ss, uint16_t type, + uint8_t proto, int connect0_bind1); + +/* determine if the given address is a local address */ +int osmo_sockaddr_is_local(struct sockaddr *addr, socklen_t addrlen); + +#endif /* _OSMOCORE_SOCKET_H */ diff --git a/src/Makefile.am b/src/Makefile.am index e58bc286..1ae3cff8 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -2,7 +2,7 @@ SUBDIRS=. vty codec gsm # This is _NOT_ the library release version, it's an API version. # Please read Chapter 6 "Library interface versions" of the libtool documentation before making any modification -LIBVERSION=1:0:1 +LIBVERSION=2:0:0 INCLUDES = $(all_includes) -I$(top_srcdir)/include AM_CFLAGS = -fPIC -Wall @@ -11,7 +11,7 @@ lib_LTLIBRARIES = libosmocore.la libosmocore_la_SOURCES = timer.c select.c signal.c msgb.c bits.c \ bitvec.c statistics.c \ - write_queue.c utils.c \ + write_queue.c utils.c socket.c \ logging.c logging_syslog.c rate_ctr.c \ gsmtap_util.c crc16.c panic.c backtrace.c \ process.c conv.c application.c diff --git a/src/gsmtap_util.c b/src/gsmtap_util.c index e0bc848c..15426358 100644 --- a/src/gsmtap_util.c +++ b/src/gsmtap_util.c @@ -1,6 +1,6 @@ -/* GSMTAP output for Osmocom Layer2 (will only work on the host PC) */ +/* GSMTAP support code in libmsomcore */ /* - * (C) 2010 by Harald Welte + * (C) 2010-2011 by Harald Welte * * All Rights Reserved * @@ -22,18 +22,19 @@ #include "../config.h" -#ifdef HAVE_SYS_SELECT_H - #include #include #include #include +#include #include +#include #include #include #include #include +#include #include #include @@ -42,10 +43,6 @@ #include #include -static struct osmo_fd gsmtap_bfd = { .fd = -1 }; -static struct osmo_fd gsmtap_sink_bfd = { .fd = -1 }; -static LLIST_HEAD(gsmtap_txqueue); - uint8_t chantype_rsl2gsmtap(uint8_t rsl_chantype, uint8_t link_id) { uint8_t ret = GSMTAP_CHANNEL_UNKNOWN; @@ -114,44 +111,82 @@ struct msgb *gsmtap_makemsg(uint16_t arfcn, uint8_t ts, uint8_t chan_type, return msg; } +/* Open a GSMTAP source (sending) socket, conncet it to host/port and + * return resulting fd */ +int gsmtap_source_init_fd(const char *host, uint16_t port) +{ + if (port == 0) + port = GSMTAP_UDP_PORT; + if (host == NULL) + host = "localhost"; + + return osmo_sock_init(AF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP, host, port, 0); +} + +int gsmtap_source_add_sink_fd(int gsmtap_fd) +{ + struct sockaddr_storage ss; + socklen_t ss_len = sizeof(ss); + int rc; + + rc = getpeername(gsmtap_fd, (struct sockaddr *)&ss, &ss_len); + if (rc < 0) + return rc; + + if (osmo_sockaddr_is_local((struct sockaddr *)&ss, ss_len) == 1) { + rc = osmo_sock_init_sa((struct sockaddr *)&ss, SOCK_DGRAM, IPPROTO_UDP, 1); + if (rc >= 0) + return rc; + } + + return -ENODEV; +} + +#ifdef HAVE_SYS_SELECT_H + +int gsmtap_sendmsg(struct gsmtap_inst *gti, struct msgb *msg) +{ + if (gti->ofd_wq_mode) + return osmo_wqueue_enqueue(>i->wq, msg); + else { + /* try immediate send and return error if any */ + int rc; + + rc = write(gsmtap_inst_fd(gti), msg->data, msg->len); + if (rc <= 0) { + return rc; + } else if (rc >= msg->len) { + msgb_free(msg); + return 0; + } else { + /* short write */ + return -EIO; + } + } +} + /* receive a message from L1/L2 and put it in GSMTAP */ -int gsmtap_sendmsg(uint16_t arfcn, uint8_t ts, uint8_t chan_type, uint8_t ss, - uint32_t fn, int8_t signal_dbm, uint8_t snr, - const uint8_t *data, unsigned int len) +int gsmtap_send(struct gsmtap_inst *gti, uint16_t arfcn, uint8_t ts, + uint8_t chan_type, uint8_t ss, uint32_t fn, + int8_t signal_dbm, uint8_t snr, const uint8_t *data, + unsigned int len) { struct msgb *msg; - /* gsmtap was never initialized, so don't try to send anything */ - if (gsmtap_bfd.fd == -1) - return 0; - msg = gsmtap_makemsg(arfcn, ts, chan_type, ss, fn, signal_dbm, snr, data, len); if (!msg) return -ENOMEM; - msgb_enqueue(&gsmtap_txqueue, msg); - gsmtap_bfd.when |= BSC_FD_WRITE; - - return 0; + return gsmtap_sendmsg(gti, msg); } /* Callback from select layer if we can write to the socket */ -static int gsmtap_fd_cb(struct osmo_fd *fd, unsigned int flags) +static int gsmtap_wq_w_cb(struct osmo_fd *ofd, struct msgb *msg) { - struct msgb *msg; int rc; - if (!(flags & BSC_FD_WRITE)) - return 0; - - msg = msgb_dequeue(&gsmtap_txqueue); - if (!msg) { - /* no more messages in the queue, disable READ cb */ - gsmtap_bfd.when = 0; - return 0; - } - rc = write(gsmtap_bfd.fd, msg->data, msg->len); + rc = write(ofd->fd, msg->data, msg->len); if (rc < 0) { perror("writing msgb to gsmtap fd"); msgb_free(msg); @@ -167,37 +202,6 @@ static int gsmtap_fd_cb(struct osmo_fd *fd, unsigned int flags) return 0; } -int gsmtap_init(uint32_t dst_ip) -{ - int rc; - struct sockaddr_in sin; - - sin.sin_family = AF_INET; - sin.sin_port = htons(GSMTAP_UDP_PORT); - sin.sin_addr.s_addr = htonl(dst_ip); - - /* create socket */ - rc = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); - if (rc < 0) { - perror("creating UDP socket"); - return rc; - } - gsmtap_bfd.fd = rc; - rc = connect(rc, (struct sockaddr *)&sin, sizeof(sin)); - if (rc < 0) { - perror("connecting UDP socket"); - close(gsmtap_bfd.fd); - gsmtap_bfd.fd = -1; - return rc; - } - - gsmtap_bfd.when = BSC_FD_WRITE; - gsmtap_bfd.cb = gsmtap_fd_cb; - gsmtap_bfd.data = NULL; - - return osmo_fd_register(&gsmtap_bfd); -} - /* Callback from select layer if we can read from the sink socket */ static int gsmtap_sink_fd_cb(struct osmo_fd *fd, unsigned int flags) { @@ -217,37 +221,53 @@ static int gsmtap_sink_fd_cb(struct osmo_fd *fd, unsigned int flags) return 0; } -/* Create a local 'gsmtap sink' avoiding the UDP packets being rejected - * with ICMP reject messages */ -int gsmtap_sink_init(uint32_t bind_ip) +/* Add a local sink to an existing GSMTAP source instance */ +int gsmtap_source_add_sink(struct gsmtap_inst *gti) { - int rc; - struct sockaddr_in sin; + int fd; - sin.sin_family = AF_INET; - sin.sin_port = htons(GSMTAP_UDP_PORT); - sin.sin_addr.s_addr = htonl(bind_ip); + fd = gsmtap_source_add_sink_fd(gsmtap_inst_fd(gti)); + if (fd < 0) + return fd; - rc = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); - if (rc < 0) { - perror("creating UDP socket"); - return rc; - } - gsmtap_sink_bfd.fd = rc; - rc = bind(rc, (struct sockaddr *)&sin, sizeof(sin)); - if (rc < 0) { - perror("binding UDP socket"); - close(gsmtap_sink_bfd.fd); - gsmtap_sink_bfd.fd = -1; - return rc; + if (gti->ofd_wq_mode) { + struct osmo_fd *sink_ofd; + + sink_ofd = >i->sink_ofd; + sink_ofd->fd = fd; + sink_ofd->when = BSC_FD_READ; + sink_ofd->cb = gsmtap_sink_fd_cb; + + osmo_fd_register(sink_ofd); } - gsmtap_sink_bfd.when = BSC_FD_READ; - gsmtap_sink_bfd.cb = gsmtap_sink_fd_cb; - gsmtap_sink_bfd.data = NULL; + return fd; +} - return osmo_fd_register(&gsmtap_sink_bfd); +/* like gsmtap_init2() but integrated with libosmocore select.c */ +struct gsmtap_inst *gsmtap_source_init(const char *host, uint16_t port, + int ofd_wq_mode) +{ + struct gsmtap_inst *gti; + int fd; + + fd = gsmtap_source_init_fd(host, port); + if (fd < 0) + return NULL; + + gti = talloc_zero(NULL, struct gsmtap_inst); + gti->ofd_wq_mode = ofd_wq_mode; + gti->wq.bfd.fd = fd; + gti->sink_ofd.fd = -1; + + if (ofd_wq_mode) { + osmo_wqueue_init(>i->wq, 64); + gti->wq.write_cb = &gsmtap_wq_w_cb; + + osmo_fd_register(>i->wq.bfd); + } + return gti; } #endif /* HAVE_SYS_SELECT_H */ diff --git a/src/socket.c b/src/socket.c new file mode 100644 index 00000000..bd4914fd --- /dev/null +++ b/src/socket.c @@ -0,0 +1,143 @@ +#include "../config.h" + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +int osmo_sock_init(uint16_t family, uint16_t type, uint8_t proto, + const char *host, uint16_t port, int connect0_bind1) +{ + struct addrinfo hints, *result, *rp; + int sfd, rc; + char portbuf[16]; + + sprintf(portbuf, "%u", port); + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_family = family; + hints.ai_socktype = type; + hints.ai_flags = 0; + hints.ai_protocol = proto; + + rc = getaddrinfo(host, portbuf, &hints, &result); + if (rc != 0) { + perror("getaddrinfo returned NULL"); + return -EINVAL; + } + + for (rp = result; rp != NULL; rp = rp->ai_next) { + sfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); + if (sfd == -1) + continue; + if (connect0_bind1 == 0) { + if (connect(sfd, rp->ai_addr, rp->ai_addrlen) != -1) + break; + } else { + if (bind(sfd, rp->ai_addr, rp->ai_addrlen) != -1) + break; + } + close(sfd); + } + freeaddrinfo(result); + + if (rp == NULL) { + perror("unable to connect/bind socket"); + return -ENODEV; + } + return sfd; +} + +int osmo_sock_init_sa(struct sockaddr *ss, uint16_t type, + uint8_t proto, int connect0_bind1) +{ + char host[NI_MAXHOST]; + uint16_t port; + struct sockaddr_in *sin; + struct sockaddr_in6 *sin6; + int s, sa_len; + + /* determine port and host from ss */ + switch (ss->sa_family) { + case AF_INET: + sin = (struct sockaddr_in *) ss; + sa_len = sizeof(struct sockaddr_in); + port = ntohs(sin->sin_port); + break; + case AF_INET6: + sin6 = (struct sockaddr_in6 *) ss; + sa_len = sizeof(struct sockaddr_in6); + port = ntohs(sin6->sin6_port); + break; + default: + return -EINVAL; + } + fprintf(stderr, "==> PORT = %u\n", port); + + s = getnameinfo(ss, sa_len, host, NI_MAXHOST, + NULL, 0, NI_NUMERICHOST); + if (s != 0) { + perror("getnameinfo failed"); + return s; + } + + return osmo_sock_init(ss->sa_family, type, proto, host, + port, connect0_bind1); +} + +static int sockaddr_equal(const struct sockaddr *a, + const struct sockaddr *b, socklen_t len) +{ + struct sockaddr_in *sin_a, *sin_b; + struct sockaddr_in6 *sin6_a, *sin6_b; + + if (a->sa_family != b->sa_family) + return 0; + + switch (a->sa_family) { + case AF_INET: + sin_a = (struct sockaddr_in *)a; + sin_b = (struct sockaddr_in *)b; + if (!memcmp(&sin_a->sin_addr, &sin_b->sin_addr, + sizeof(struct in_addr))) + return 1; + break; + case AF_INET6: + sin6_a = (struct sockaddr_in6 *)a; + sin6_b = (struct sockaddr_in6 *)b; + if (!memcmp(&sin6_a->sin6_addr, &sin6_b->sin6_addr, + sizeof(struct in6_addr))) + return 1; + break; + } + return 0; +} + +/* determine if the given address is a local address */ +int osmo_sockaddr_is_local(struct sockaddr *addr, socklen_t addrlen) +{ + struct ifaddrs *ifaddr, *ifa; + + if (getifaddrs(&ifaddr) == -1) { + perror("getifaddrs"); + return -EIO; + } + + for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) { + if (sockaddr_equal(ifa->ifa_addr, addr, addrlen)) + return 1; + } + + return 0; +} -- cgit v1.2.3 From e476442cf0e84c65565ace545f5b73602b5f0ffc Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sun, 22 May 2011 12:25:57 +0200 Subject: GSMTAP/socket code: Check for sys/socket.h and conditionally compile --- configure.in | 2 +- include/osmocom/core/socket.h | 5 +++-- src/gsmtap_util.c | 14 ++++++++------ src/socket.c | 6 +++++- 4 files changed, 17 insertions(+), 10 deletions(-) diff --git a/configure.in b/configure.in index ead18f07..2e22bb24 100644 --- a/configure.in +++ b/configure.in @@ -18,7 +18,7 @@ AC_CONFIG_MACRO_DIR([m4]) dnl checks for header files AC_HEADER_STDC -AC_CHECK_HEADERS(execinfo.h sys/select.h syslog.h ctype.h) +AC_CHECK_HEADERS(execinfo.h sys/select.h sys/socket.h syslog.h ctype.h) # The following test is taken from WebKit's webkit.m4 saved_CFLAGS="$CFLAGS" diff --git a/include/osmocom/core/socket.h b/include/osmocom/core/socket.h index 3ede524b..a3baa9d5 100644 --- a/include/osmocom/core/socket.h +++ b/include/osmocom/core/socket.h @@ -2,7 +2,8 @@ #define _OSMOCORE_SOCKET_H #include -#include + +struct sockaddr; int osmo_sock_init(uint16_t family, uint16_t type, uint8_t proto, const char *host, uint16_t port, int connect0_bind1); @@ -11,6 +12,6 @@ int osmo_sock_init_sa(struct sockaddr *ss, uint16_t type, uint8_t proto, int connect0_bind1); /* determine if the given address is a local address */ -int osmo_sockaddr_is_local(struct sockaddr *addr, socklen_t addrlen); +int osmo_sockaddr_is_local(struct sockaddr *addr, unsigned int addrlen); #endif /* _OSMOCORE_SOCKET_H */ diff --git a/src/gsmtap_util.c b/src/gsmtap_util.c index 15426358..5c68b6a0 100644 --- a/src/gsmtap_util.c +++ b/src/gsmtap_util.c @@ -32,10 +32,9 @@ #include #include -#include -#include #include -#include + +#include #include #include @@ -111,6 +110,11 @@ struct msgb *gsmtap_makemsg(uint16_t arfcn, uint8_t ts, uint8_t chan_type, return msg; } +#ifdef HAVE_SYS_SOCKET_H + +#include +#include + /* Open a GSMTAP source (sending) socket, conncet it to host/port and * return resulting fd */ int gsmtap_source_init_fd(const char *host, uint16_t port) @@ -142,8 +146,6 @@ int gsmtap_source_add_sink_fd(int gsmtap_fd) return -ENODEV; } -#ifdef HAVE_SYS_SELECT_H - int gsmtap_sendmsg(struct gsmtap_inst *gti, struct msgb *msg) { if (gti->ofd_wq_mode) @@ -270,4 +272,4 @@ struct gsmtap_inst *gsmtap_source_init(const char *host, uint16_t port, return gti; } -#endif /* HAVE_SYS_SELECT_H */ +#endif /* HAVE_SYS_SOCKET_H */ diff --git a/src/socket.c b/src/socket.c index bd4914fd..e053c24d 100644 --- a/src/socket.c +++ b/src/socket.c @@ -1,5 +1,7 @@ #include "../config.h" +#ifdef HAVE_SYS_SOCKET_H + #include #include #include @@ -97,7 +99,7 @@ int osmo_sock_init_sa(struct sockaddr *ss, uint16_t type, } static int sockaddr_equal(const struct sockaddr *a, - const struct sockaddr *b, socklen_t len) + const struct sockaddr *b, unsigned int len) { struct sockaddr_in *sin_a, *sin_b; struct sockaddr_in6 *sin6_a, *sin6_b; @@ -141,3 +143,5 @@ int osmo_sockaddr_is_local(struct sockaddr *addr, socklen_t addrlen) return 0; } + +#endif /* HAVE_SYS_SOCKET_H */ -- cgit v1.2.3 From b62b04bbf320dca6d81a95e9b0dea0251ad4a665 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sun, 22 May 2011 19:15:07 +0200 Subject: vty: print actual application name rather than always OpenBSC on connect --- src/vty/telnet_interface.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/vty/telnet_interface.c b/src/vty/telnet_interface.c index 78459944..c08a256a 100644 --- a/src/vty/telnet_interface.c +++ b/src/vty/telnet_interface.c @@ -95,10 +95,16 @@ extern struct host host; static void print_welcome(int fd) { int ret; - static char *msg = - "Welcome to the OpenBSC Control interface\r\n"; + static const char *msg1 = "Welcome to the "; + static const char *msg2 = " control interface\r\n"; + char *app_name = ""; - ret = write(fd, msg, strlen(msg)); + if (host.app_info->name) + app_name = host.app_info->name; + + ret = write(fd, msg1, strlen(msg1)); + ret = write(fd, app_name, strlen(app_name)); + ret = write(fd, msg2, strlen(msg2)); if (host.app_info->copyright) ret = write(fd, host.app_info->copyright, strlen(host.app_info->copyright)); -- cgit v1.2.3 From 13692a6bd3df90d80cdbc4fd6852c69c6a99ea9b Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sun, 22 May 2011 20:06:11 +0200 Subject: gsmtap: deal with apps that call gsmtap_send*() with NULL gsmtap_inst --- src/gsmtap_util.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/gsmtap_util.c b/src/gsmtap_util.c index 5c68b6a0..3d20bfc2 100644 --- a/src/gsmtap_util.c +++ b/src/gsmtap_util.c @@ -148,6 +148,9 @@ int gsmtap_source_add_sink_fd(int gsmtap_fd) int gsmtap_sendmsg(struct gsmtap_inst *gti, struct msgb *msg) { + if (!gti) + return -ENODEV; + if (gti->ofd_wq_mode) return osmo_wqueue_enqueue(>i->wq, msg); else { @@ -175,6 +178,9 @@ int gsmtap_send(struct gsmtap_inst *gti, uint16_t arfcn, uint8_t ts, { struct msgb *msg; + if (!gti) + return -ENODEV; + msg = gsmtap_makemsg(arfcn, ts, chan_type, ss, fn, signal_dbm, snr, data, len); if (!msg) -- cgit v1.2.3 From 8265939c5e32843990dd14e5d2918f773e285468 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sun, 22 May 2011 20:30:18 +0200 Subject: remove debug printf from socket.c --- src/socket.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/socket.c b/src/socket.c index e053c24d..2414b1ff 100644 --- a/src/socket.c +++ b/src/socket.c @@ -85,7 +85,6 @@ int osmo_sock_init_sa(struct sockaddr *ss, uint16_t type, default: return -EINVAL; } - fprintf(stderr, "==> PORT = %u\n", port); s = getnameinfo(ss, sa_len, host, NI_MAXHOST, NULL, 0, NI_NUMERICHOST); -- cgit v1.2.3 From 68b1574257fdbf4b06d225c116cfa6a2a6929965 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sun, 22 May 2011 21:47:29 +0200 Subject: socket: use listen() and SO_REUSEADDR, new osmo_sock_init_ofd() function osmo_sock_init_ofd() is a wrapper around osmo_sock_init() which will take care of initializing and registering a 'struct osmo_fd' for the newly-created socket. --- include/osmocom/core/socket.h | 3 +++ src/socket.c | 35 ++++++++++++++++++++++++++++++++++- 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/include/osmocom/core/socket.h b/include/osmocom/core/socket.h index a3baa9d5..b2601c76 100644 --- a/include/osmocom/core/socket.h +++ b/include/osmocom/core/socket.h @@ -8,6 +8,9 @@ struct sockaddr; int osmo_sock_init(uint16_t family, uint16_t type, uint8_t proto, const char *host, uint16_t port, int connect0_bind1); +int osmo_sock_init_ofd(struct osmo_fd *ofd, int family, int type, int proto, + const char *host, uint16_t port, int connect0_bind1); + int osmo_sock_init_sa(struct sockaddr *ss, uint16_t type, uint8_t proto, int connect0_bind1); diff --git a/src/socket.c b/src/socket.c index 2414b1ff..66907c8c 100644 --- a/src/socket.c +++ b/src/socket.c @@ -23,7 +23,7 @@ int osmo_sock_init(uint16_t family, uint16_t type, uint8_t proto, const char *host, uint16_t port, int connect0_bind1) { struct addrinfo hints, *result, *rp; - int sfd, rc; + int sfd, rc, on = 1; char portbuf[16]; sprintf(portbuf, "%u", port); @@ -58,6 +58,39 @@ int osmo_sock_init(uint16_t family, uint16_t type, uint8_t proto, perror("unable to connect/bind socket"); return -ENODEV; } + + setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); + + /* Make sure to call 'listen' on a bound, connection-oriented sock */ + if (connect0_bind1 == 1) { + switch (type) { + case SOCK_STREAM: + case SOCK_SEQPACKET: + listen(sfd, 10); + break; + } + } + return sfd; +} + +int osmo_sock_init_ofd(struct osmo_fd *ofd, int family, int type, int proto, + const char *host, uint16_t port, int connect0_bind1) +{ + int sfd, rc; + + sfd = osmo_sock_init(family, type, proto, host, port, connect0_bind1); + if (sfd < 0) + return sfd; + + ofd->fd = sfd; + ofd->when = BSC_FD_READ; + + rc = osmo_fd_register(ofd); + if (rc < 0) { + close(sfd); + return rc; + } + return sfd; } -- cgit v1.2.3 From 4185fa5d9b6bf712499b8e65bac4077dd1aa34fa Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sun, 22 May 2011 21:57:15 +0200 Subject: libosmogsm: add ipaccess related header file --- include/osmocom/gsm/protocol/Makefile.am | 2 +- include/osmocom/gsm/protocol/ipaccess.h | 93 ++++++++++++++++++++++++++++++++ 2 files changed, 94 insertions(+), 1 deletion(-) create mode 100644 include/osmocom/gsm/protocol/ipaccess.h diff --git a/include/osmocom/gsm/protocol/Makefile.am b/include/osmocom/gsm/protocol/Makefile.am index 8483f10a..7f6de639 100644 --- a/include/osmocom/gsm/protocol/Makefile.am +++ b/include/osmocom/gsm/protocol/Makefile.am @@ -1,6 +1,6 @@ osmogsm_proto_HEADERS = gsm_03_41.h \ gsm_04_08.h gsm_04_11.h gsm_04_12.h gsm_04_80.h \ gsm_08_08.h gsm_08_58.h \ - gsm_12_21.h + gsm_12_21.h ipaccess.h osmogsm_protodir = $(includedir)/osmocom/gsm/protocol diff --git a/include/osmocom/gsm/protocol/ipaccess.h b/include/osmocom/gsm/protocol/ipaccess.h new file mode 100644 index 00000000..27925725 --- /dev/null +++ b/include/osmocom/gsm/protocol/ipaccess.h @@ -0,0 +1,93 @@ +#ifndef _OSMO_PROTO_IPACCESS_H +#define _OSMO_PROTO_IPACCESS_H + +#include + +#define IPA_TCP_PORT_OML 3002 +#define IPA_TCP_PORT_RSL 3003 + +struct ipaccess_head { + uint16_t len; /* network byte order */ + uint8_t proto; + uint8_t data[0]; +} __attribute__ ((packed)); + +struct ipaccess_head_ext { + uint8_t proto; + uint8_t data[0]; +} __attribute__ ((packed)); + +enum ipaccess_proto { + IPAC_PROTO_RSL = 0x00, + IPAC_PROTO_IPACCESS = 0xfe, + IPAC_PROTO_SCCP = 0xfd, + IPAC_PROTO_OML = 0xff, + + + /* OpenBSC extensions */ + IPAC_PROTO_OSMO = 0xee, + IPAC_PROTO_MGCP_OLD = 0xfc, +}; + +enum ipaccess_proto_ext { + IPAC_PROTO_EXT_CTRL = 0x00, + IPAC_PROTO_EXT_MGCP = 0x01, + IPAC_PROTO_EXT_LAC = 0x02, +}; + +enum ipaccess_msgtype { + IPAC_MSGT_PING = 0x00, + IPAC_MSGT_PONG = 0x01, + IPAC_MSGT_ID_GET = 0x04, + IPAC_MSGT_ID_RESP = 0x05, + IPAC_MSGT_ID_ACK = 0x06, + + /* OpenBSC extension */ + IPAC_MSGT_SCCP_OLD = 0xff, +}; + +enum ipaccess_id_tags { + IPAC_IDTAG_SERNR = 0x00, + IPAC_IDTAG_UNITNAME = 0x01, + IPAC_IDTAG_LOCATION1 = 0x02, + IPAC_IDTAG_LOCATION2 = 0x03, + IPAC_IDTAG_EQUIPVERS = 0x04, + IPAC_IDTAG_SWVERSION = 0x05, + IPAC_IDTAG_IPADDR = 0x06, + IPAC_IDTAG_MACADDR = 0x07, + IPAC_IDTAG_UNIT = 0x08, +}; + +/* + * Firmware specific header + */ +struct sdp_firmware { + char magic[4]; + char more_magic[2]; + uint16_t more_more_magic; + uint32_t header_length; + uint32_t file_length; + char sw_part[20]; + char text1[64]; + char time[12]; + char date[14]; + char text2[10]; + char version[20]; + uint16_t table_offset; + /* stuff i don't know */ +} __attribute__((packed)); + +struct sdp_header_entry { + uint16_t something1; + char text1[64]; + char time[12]; + char date[14]; + char text2[10]; + char version[20]; + uint32_t length; + uint32_t addr1; + uint32_t addr2; + uint32_t start; +} __attribute__((packed)); + +#endif /* _OSMO_PROTO_IPACCESS_H */ -- cgit v1.2.3 From f7a1bcce0cea50650517e305d59e674475f913d0 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sun, 22 May 2011 22:45:16 +0200 Subject: abis_nm: import definitions and common code on A-bis OML from OpenBSC --- include/osmocom/gsm/Makefile.am | 2 +- include/osmocom/gsm/abis_nm.h | 24 +++ src/gsm/Makefile.am | 2 +- src/gsm/abis_nm.c | 406 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 432 insertions(+), 2 deletions(-) create mode 100644 include/osmocom/gsm/abis_nm.h create mode 100644 src/gsm/abis_nm.c diff --git a/include/osmocom/gsm/Makefile.am b/include/osmocom/gsm/Makefile.am index a39d2d04..c3670ec7 100644 --- a/include/osmocom/gsm/Makefile.am +++ b/include/osmocom/gsm/Makefile.am @@ -1,5 +1,5 @@ osmogsm_HEADERS = a5.h comp128.h gsm0808.h gsm48_ie.h mncc.h rxlev_stat.h \ - gsm0480.h gsm48.h gsm_utils.h rsl.h tlv.h + gsm0480.h gsm48.h gsm_utils.h rsl.h tlv.h abis_nm.h SUBDIRS = protocol diff --git a/include/osmocom/gsm/abis_nm.h b/include/osmocom/gsm/abis_nm.h new file mode 100644 index 00000000..04e4575d --- /dev/null +++ b/include/osmocom/gsm/abis_nm.h @@ -0,0 +1,24 @@ +#ifndef _OSMO_GSM_ABIS_NM_H +#define _OSMO_GSM_ABIS_NM_H + +#include +#include + +const enum abis_nm_msgtype abis_nm_reports[4]; +const enum abis_nm_msgtype abis_nm_no_ack_nack[3]; +const enum abis_nm_msgtype abis_nm_sw_load_msgs[9]; +const enum abis_nm_msgtype abis_nm_nacks[33]; + +const char *abis_nm_nack_cause_name(uint8_t cause); +const char *abis_nm_nack_name(uint8_t nack); +const char *abis_nm_event_type_name(uint8_t cause); +const char *abis_nm_severity_name(uint8_t cause); +const struct tlv_definition abis_nm_att_tlvdef; +const char *abis_nm_obj_class_name(uint8_t oc); +const char *abis_nm_opstate_name(uint8_t os); +const char *abis_nm_avail_name(uint8_t avail); +const char *abis_nm_test_name(uint8_t test); +const char *abis_nm_adm_name(uint8_t adm); +void abis_nm_debugp_foh(int ss, struct abis_om_fom_hdr *foh); + +#endif /* _OSMO_GSM_ABIS_NM_H */ diff --git a/src/gsm/Makefile.am b/src/gsm/Makefile.am index fb4a8cb2..94f137e2 100644 --- a/src/gsm/Makefile.am +++ b/src/gsm/Makefile.am @@ -9,6 +9,6 @@ lib_LTLIBRARIES = libosmogsm.la libosmogsm_la_SOURCES = a5.c rxlev_stat.c tlv_parser.c comp128.c gsm_utils.c \ rsl.c gsm48.c gsm48_ie.c gsm0808.c \ - gprs_cipher_core.c gsm0480.c + gprs_cipher_core.c gsm0480.c abis_nm.c libosmogsm_la_LDFLAGS = -version-info $(LIBVERSION) libosmogsm_la_LIBADD = $(top_builddir)/src/libosmocore.la diff --git a/src/gsm/abis_nm.c b/src/gsm/abis_nm.c new file mode 100644 index 00000000..acea4ed5 --- /dev/null +++ b/src/gsm/abis_nm.c @@ -0,0 +1,406 @@ +/* GSM Network Management (OML) messages on the A-bis interface + * 3GPP TS 12.21 version 8.0.0 Release 1999 / ETSI TS 100 623 V8.0.0 */ + +/* (C) 2008-2011 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 General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +#include +#include +#include +#include +#include +#include + +/* unidirectional messages from BTS to BSC */ +const enum abis_nm_msgtype abis_nm_reports[4] = { + NM_MT_SW_ACTIVATED_REP, + NM_MT_TEST_REP, + NM_MT_STATECHG_EVENT_REP, + NM_MT_FAILURE_EVENT_REP, +}; + +/* messages without ACK/NACK */ +const enum abis_nm_msgtype abis_nm_no_ack_nack[3] = { + NM_MT_MEAS_RES_REQ, + NM_MT_STOP_MEAS, + NM_MT_START_MEAS, +}; + +/* Messages related to software load */ +const enum abis_nm_msgtype abis_nm_sw_load_msgs[9] = { + NM_MT_LOAD_INIT_ACK, + NM_MT_LOAD_INIT_NACK, + NM_MT_LOAD_SEG_ACK, + NM_MT_LOAD_ABORT, + NM_MT_LOAD_END_ACK, + NM_MT_LOAD_END_NACK, + //NM_MT_SW_ACT_REQ, + NM_MT_ACTIVATE_SW_ACK, + NM_MT_ACTIVATE_SW_NACK, + NM_MT_SW_ACTIVATED_REP, +}; + +const enum abis_nm_msgtype abis_nm_nacks[33] = { + NM_MT_LOAD_INIT_NACK, + NM_MT_LOAD_END_NACK, + NM_MT_SW_ACT_REQ_NACK, + NM_MT_ACTIVATE_SW_NACK, + NM_MT_ESTABLISH_TEI_NACK, + NM_MT_CONN_TERR_SIGN_NACK, + NM_MT_DISC_TERR_SIGN_NACK, + NM_MT_CONN_TERR_TRAF_NACK, + NM_MT_DISC_TERR_TRAF_NACK, + NM_MT_CONN_MDROP_LINK_NACK, + NM_MT_DISC_MDROP_LINK_NACK, + NM_MT_SET_BTS_ATTR_NACK, + NM_MT_SET_RADIO_ATTR_NACK, + NM_MT_SET_CHAN_ATTR_NACK, + NM_MT_PERF_TEST_NACK, + NM_MT_SEND_TEST_REP_NACK, + NM_MT_STOP_TEST_NACK, + NM_MT_STOP_EVENT_REP_NACK, + NM_MT_REST_EVENT_REP_NACK, + NM_MT_CHG_ADM_STATE_NACK, + NM_MT_CHG_ADM_STATE_REQ_NACK, + NM_MT_REP_OUTST_ALARMS_NACK, + NM_MT_CHANGEOVER_NACK, + NM_MT_OPSTART_NACK, + NM_MT_REINIT_NACK, + NM_MT_SET_SITE_OUT_NACK, + NM_MT_CHG_HW_CONF_NACK, + NM_MT_GET_ATTR_NACK, + NM_MT_SET_ALARM_THRES_NACK, + NM_MT_BS11_BEGIN_DB_TX_NACK, + NM_MT_BS11_END_DB_TX_NACK, + NM_MT_BS11_CREATE_OBJ_NACK, + NM_MT_BS11_DELETE_OBJ_NACK, +}; + +static const struct value_string nack_names[] = { + { NM_MT_LOAD_INIT_NACK, "SOFTWARE LOAD INIT" }, + { NM_MT_LOAD_END_NACK, "SOFTWARE LOAD END" }, + { NM_MT_SW_ACT_REQ_NACK, "SOFTWARE ACTIVATE REQUEST" }, + { NM_MT_ACTIVATE_SW_NACK, "ACTIVATE SOFTWARE" }, + { NM_MT_ESTABLISH_TEI_NACK, "ESTABLISH TEI" }, + { NM_MT_CONN_TERR_SIGN_NACK, "CONNECT TERRESTRIAL SIGNALLING" }, + { NM_MT_DISC_TERR_SIGN_NACK, "DISCONNECT TERRESTRIAL SIGNALLING" }, + { NM_MT_CONN_TERR_TRAF_NACK, "CONNECT TERRESTRIAL TRAFFIC" }, + { NM_MT_DISC_TERR_TRAF_NACK, "DISCONNECT TERRESTRIAL TRAFFIC" }, + { NM_MT_CONN_MDROP_LINK_NACK, "CONNECT MULTI-DROP LINK" }, + { NM_MT_DISC_MDROP_LINK_NACK, "DISCONNECT MULTI-DROP LINK" }, + { NM_MT_SET_BTS_ATTR_NACK, "SET BTS ATTRIBUTE" }, + { NM_MT_SET_RADIO_ATTR_NACK, "SET RADIO ATTRIBUTE" }, + { NM_MT_SET_CHAN_ATTR_NACK, "SET CHANNEL ATTRIBUTE" }, + { NM_MT_PERF_TEST_NACK, "PERFORM TEST" }, + { NM_MT_SEND_TEST_REP_NACK, "SEND TEST REPORT" }, + { NM_MT_STOP_TEST_NACK, "STOP TEST" }, + { NM_MT_STOP_EVENT_REP_NACK, "STOP EVENT REPORT" }, + { NM_MT_REST_EVENT_REP_NACK, "RESET EVENT REPORT" }, + { NM_MT_CHG_ADM_STATE_NACK, "CHANGE ADMINISTRATIVE STATE" }, + { NM_MT_CHG_ADM_STATE_REQ_NACK, + "CHANGE ADMINISTRATIVE STATE REQUEST" }, + { NM_MT_REP_OUTST_ALARMS_NACK, "REPORT OUTSTANDING ALARMS" }, + { NM_MT_CHANGEOVER_NACK, "CHANGEOVER" }, + { NM_MT_OPSTART_NACK, "OPSTART" }, + { NM_MT_REINIT_NACK, "REINIT" }, + { NM_MT_SET_SITE_OUT_NACK, "SET SITE OUTPUT" }, + { NM_MT_CHG_HW_CONF_NACK, "CHANGE HARDWARE CONFIGURATION" }, + { NM_MT_GET_ATTR_NACK, "GET ATTRIBUTE" }, + { NM_MT_SET_ALARM_THRES_NACK, "SET ALARM THRESHOLD" }, + { NM_MT_BS11_BEGIN_DB_TX_NACK, "BS11 BEGIN DATABASE TRANSMISSION" }, + { NM_MT_BS11_END_DB_TX_NACK, "BS11 END DATABASE TRANSMISSION" }, + { NM_MT_BS11_CREATE_OBJ_NACK, "BS11 CREATE OBJECT" }, + { NM_MT_BS11_DELETE_OBJ_NACK, "BS11 DELETE OBJECT" }, + { 0, NULL } +}; + +const char *abis_nm_nack_name(uint8_t nack) +{ + return get_value_string(nack_names, nack); +} + +/* Chapter 9.4.36 */ +static const struct value_string nack_cause_names[] = { + /* General Nack Causes */ + { NM_NACK_INCORR_STRUCT, "Incorrect message structure" }, + { NM_NACK_MSGTYPE_INVAL, "Invalid message type value" }, + { NM_NACK_OBJCLASS_INVAL, "Invalid Object class value" }, + { NM_NACK_OBJCLASS_NOTSUPP, "Object class not supported" }, + { NM_NACK_BTSNR_UNKN, "BTS no. unknown" }, + { NM_NACK_TRXNR_UNKN, "Baseband Transceiver no. unknown" }, + { NM_NACK_OBJINST_UNKN, "Object Instance unknown" }, + { NM_NACK_ATTRID_INVAL, "Invalid attribute identifier value" }, + { NM_NACK_ATTRID_NOTSUPP, "Attribute identifier not supported" }, + { NM_NACK_PARAM_RANGE, "Parameter value outside permitted range" }, + { NM_NACK_ATTRLIST_INCONSISTENT,"Inconsistency in attribute list" }, + { NM_NACK_SPEC_IMPL_NOTSUPP, "Specified implementation not supported" }, + { NM_NACK_CANT_PERFORM, "Message cannot be performed" }, + /* Specific Nack Causes */ + { NM_NACK_RES_NOTIMPL, "Resource not implemented" }, + { NM_NACK_RES_NOTAVAIL, "Resource not available" }, + { NM_NACK_FREQ_NOTAVAIL, "Frequency not available" }, + { NM_NACK_TEST_NOTSUPP, "Test not supported" }, + { NM_NACK_CAPACITY_RESTR, "Capacity restrictions" }, + { NM_NACK_PHYSCFG_NOTPERFORM, "Physical configuration cannot be performed" }, + { NM_NACK_TEST_NOTINIT, "Test not initiated" }, + { NM_NACK_PHYSCFG_NOTRESTORE, "Physical configuration cannot be restored" }, + { NM_NACK_TEST_NOSUCH, "No such test" }, + { NM_NACK_TEST_NOSTOP, "Test cannot be stopped" }, + { NM_NACK_MSGINCONSIST_PHYSCFG, "Message inconsistent with physical configuration" }, + { NM_NACK_FILE_INCOMPLETE, "Complete file notreceived" }, + { NM_NACK_FILE_NOTAVAIL, "File not available at destination" }, + { NM_NACK_FILE_NOTACTIVATE, "File cannot be activate" }, + { NM_NACK_REQ_NOT_GRANT, "Request not granted" }, + { NM_NACK_WAIT, "Wait" }, + { NM_NACK_NOTH_REPORT_EXIST, "Nothing reportable existing" }, + { NM_NACK_MEAS_NOTSUPP, "Measurement not supported" }, + { NM_NACK_MEAS_NOTSTART, "Measurement not started" }, + { 0, NULL } +}; + +const char *abis_nm_nack_cause_name(uint8_t cause) +{ + return get_value_string(nack_cause_names, cause); +} + +/* Chapter 9.4.16: Event Type */ +static const struct value_string event_type_names[] = { + { NM_EVT_COMM_FAIL, "communication failure" }, + { NM_EVT_QOS_FAIL, "quality of service failure" }, + { NM_EVT_PROC_FAIL, "processing failure" }, + { NM_EVT_EQUIP_FAIL, "equipment failure" }, + { NM_EVT_ENV_FAIL, "environment failure" }, + { 0, NULL } +}; + +const char *abis_nm_event_type_name(uint8_t cause) +{ + return get_value_string(event_type_names, cause); +} + +/* Chapter 9.4.63: Perceived Severity */ +static const struct value_string severity_names[] = { + { NM_SEVER_CEASED, "failure ceased" }, + { NM_SEVER_CRITICAL, "critical failure" }, + { NM_SEVER_MAJOR, "major failure" }, + { NM_SEVER_MINOR, "minor failure" }, + { NM_SEVER_WARNING, "warning level failure" }, + { NM_SEVER_INDETERMINATE, "indeterminate failure" }, + { 0, NULL } +}; + +const char *abis_nm_severity_name(uint8_t cause) +{ + return get_value_string(severity_names, cause); +} + +/* Attributes that the BSC can set, not only get, according to Section 9.4 */ +const enum abis_nm_attr abis_nm_att_settable[] = { + NM_ATT_ADD_INFO, + NM_ATT_ADD_TEXT, + NM_ATT_DEST, + NM_ATT_EVENT_TYPE, + NM_ATT_FILE_DATA, + NM_ATT_GET_ARI, + NM_ATT_HW_CONF_CHG, + NM_ATT_LIST_REQ_ATTR, + NM_ATT_MDROP_LINK, + NM_ATT_MDROP_NEXT, + NM_ATT_NACK_CAUSES, + NM_ATT_OUTST_ALARM, + NM_ATT_PHYS_CONF, + NM_ATT_PROB_CAUSE, + NM_ATT_RAD_SUBC, + NM_ATT_SOURCE, + NM_ATT_SPEC_PROB, + NM_ATT_START_TIME, + NM_ATT_TEST_DUR, + NM_ATT_TEST_NO, + NM_ATT_TEST_REPORT, + NM_ATT_WINDOW_SIZE, + NM_ATT_SEVERITY, + NM_ATT_MEAS_RES, + NM_ATT_MEAS_TYPE, +}; + +const struct tlv_definition abis_nm_att_tlvdef = { + .def = { + [NM_ATT_ABIS_CHANNEL] = { TLV_TYPE_FIXED, 3 }, + [NM_ATT_ADD_INFO] = { TLV_TYPE_TL16V }, + [NM_ATT_ADD_TEXT] = { TLV_TYPE_TL16V }, + [NM_ATT_ADM_STATE] = { TLV_TYPE_TV }, + [NM_ATT_ARFCN_LIST]= { TLV_TYPE_TL16V }, + [NM_ATT_AUTON_REPORT] = { TLV_TYPE_TV }, + [NM_ATT_AVAIL_STATUS] = { TLV_TYPE_TL16V }, + [NM_ATT_BCCH_ARFCN] = { TLV_TYPE_FIXED, 2 }, + [NM_ATT_BSIC] = { TLV_TYPE_TV }, + [NM_ATT_BTS_AIR_TIMER] = { TLV_TYPE_TV }, + [NM_ATT_CCCH_L_I_P] = { TLV_TYPE_TV }, + [NM_ATT_CCCH_L_T] = { TLV_TYPE_TV }, + [NM_ATT_CHAN_COMB] = { TLV_TYPE_TV }, + [NM_ATT_CONN_FAIL_CRIT] = { TLV_TYPE_TL16V }, + [NM_ATT_DEST] = { TLV_TYPE_TL16V }, + [NM_ATT_EVENT_TYPE] = { TLV_TYPE_TV }, + [NM_ATT_FILE_DATA] = { TLV_TYPE_TL16V }, + [NM_ATT_FILE_ID] = { TLV_TYPE_TL16V }, + [NM_ATT_FILE_VERSION] = { TLV_TYPE_TL16V }, + [NM_ATT_GSM_TIME] = { TLV_TYPE_FIXED, 2 }, + [NM_ATT_HSN] = { TLV_TYPE_TV }, + [NM_ATT_HW_CONFIG] = { TLV_TYPE_TL16V }, + [NM_ATT_HW_DESC] = { TLV_TYPE_TL16V }, + [NM_ATT_INTAVE_PARAM] = { TLV_TYPE_TV }, + [NM_ATT_INTERF_BOUND] = { TLV_TYPE_FIXED, 6 }, + [NM_ATT_LIST_REQ_ATTR] = { TLV_TYPE_TL16V }, + [NM_ATT_MAIO] = { TLV_TYPE_TV }, + [NM_ATT_MANUF_STATE] = { TLV_TYPE_TV }, + [NM_ATT_MANUF_THRESH] = { TLV_TYPE_TL16V }, + [NM_ATT_MANUF_ID] = { TLV_TYPE_TL16V }, + [NM_ATT_MAX_TA] = { TLV_TYPE_TV }, + [NM_ATT_MDROP_LINK] = { TLV_TYPE_FIXED, 2 }, + [NM_ATT_MDROP_NEXT] = { TLV_TYPE_FIXED, 2 }, + [NM_ATT_NACK_CAUSES] = { TLV_TYPE_TV }, + [NM_ATT_NY1] = { TLV_TYPE_TV }, + [NM_ATT_OPER_STATE] = { TLV_TYPE_TV }, + [NM_ATT_OVERL_PERIOD] = { TLV_TYPE_TL16V }, + [NM_ATT_PHYS_CONF] = { TLV_TYPE_TL16V }, + [NM_ATT_POWER_CLASS] = { TLV_TYPE_TV }, + [NM_ATT_POWER_THRESH] = { TLV_TYPE_FIXED, 3 }, + [NM_ATT_PROB_CAUSE] = { TLV_TYPE_FIXED, 3 }, + [NM_ATT_RACH_B_THRESH] = { TLV_TYPE_TV }, + [NM_ATT_LDAVG_SLOTS] = { TLV_TYPE_FIXED, 2 }, + [NM_ATT_RAD_SUBC] = { TLV_TYPE_TV }, + [NM_ATT_RF_MAXPOWR_R] = { TLV_TYPE_TV }, + [NM_ATT_SITE_INPUTS] = { TLV_TYPE_TL16V }, + [NM_ATT_SITE_OUTPUTS] = { TLV_TYPE_TL16V }, + [NM_ATT_SOURCE] = { TLV_TYPE_TL16V }, + [NM_ATT_SPEC_PROB] = { TLV_TYPE_TV }, + [NM_ATT_START_TIME] = { TLV_TYPE_FIXED, 2 }, + [NM_ATT_T200] = { TLV_TYPE_FIXED, 7 }, + [NM_ATT_TEI] = { TLV_TYPE_TV }, + [NM_ATT_TEST_DUR] = { TLV_TYPE_FIXED, 2 }, + [NM_ATT_TEST_NO] = { TLV_TYPE_TV }, + [NM_ATT_TEST_REPORT] = { TLV_TYPE_TL16V }, + [NM_ATT_VSWR_THRESH] = { TLV_TYPE_FIXED, 2 }, + [NM_ATT_WINDOW_SIZE] = { TLV_TYPE_TV }, + [NM_ATT_TSC] = { TLV_TYPE_TV }, + [NM_ATT_SW_CONFIG] = { TLV_TYPE_TL16V }, + [NM_ATT_SEVERITY] = { TLV_TYPE_TV }, + [NM_ATT_GET_ARI] = { TLV_TYPE_TL16V }, + [NM_ATT_HW_CONF_CHG] = { TLV_TYPE_TL16V }, + [NM_ATT_OUTST_ALARM] = { TLV_TYPE_TV }, + [NM_ATT_MEAS_RES] = { TLV_TYPE_TL16V }, + }, +}; + +static const struct value_string abis_nm_obj_class_names[] = { + { NM_OC_SITE_MANAGER, "SITE-MANAGER" }, + { NM_OC_BTS, "BTS" }, + { NM_OC_RADIO_CARRIER, "RADIO-CARRIER" }, + { NM_OC_BASEB_TRANSC, "BASEBAND-TRANSCEIVER" }, + { NM_OC_CHANNEL, "CHANNEL" }, + { NM_OC_BS11_ADJC, "ADJC" }, + { NM_OC_BS11_HANDOVER, "HANDOVER" }, + { NM_OC_BS11_PWR_CTRL, "POWER-CONTROL" }, + { NM_OC_BS11_BTSE, "BTSE" }, + { NM_OC_BS11_RACK, "RACK" }, + { NM_OC_BS11_TEST, "TEST" }, + { NM_OC_BS11_ENVABTSE, "ENVABTSE" }, + { NM_OC_BS11_BPORT, "BPORT" }, + { NM_OC_GPRS_NSE, "GPRS-NSE" }, + { NM_OC_GPRS_CELL, "GPRS-CELL" }, + { NM_OC_GPRS_NSVC, "GPRS-NSVC" }, + { NM_OC_BS11, "SIEMENSHW" }, + { 0, NULL } +}; + +const char *abis_nm_obj_class_name(uint8_t oc) +{ + return get_value_string(abis_nm_obj_class_names, oc); +} + +const char *abis_nm_opstate_name(uint8_t os) +{ + switch (os) { + case NM_OPSTATE_DISABLED: + return "Disabled"; + case NM_OPSTATE_ENABLED: + return "Enabled"; + case NM_OPSTATE_NULL: + return "NULL"; + default: + return "RFU"; + } +} + +/* Chapter 9.4.7 */ +static const struct value_string avail_names[] = { + { 0, "In test" }, + { 1, "Failed" }, + { 2, "Power off" }, + { 3, "Off line" }, + /* Not used */ + { 5, "Dependency" }, + { 6, "Degraded" }, + { 7, "Not installed" }, + { 0xff, "OK" }, + { 0, NULL } +}; + +const char *abis_nm_avail_name(uint8_t avail) +{ + return get_value_string(avail_names, avail); +} + +static struct value_string test_names[] = { + /* FIXME: standard test names */ + { NM_IPACC_TESTNO_CHAN_USAGE, "Channel Usage" }, + { NM_IPACC_TESTNO_BCCH_CHAN_USAGE, "BCCH Channel Usage" }, + { NM_IPACC_TESTNO_FREQ_SYNC, "Frequency Synchronization" }, + { NM_IPACC_TESTNO_BCCH_INFO, "BCCH Info" }, + { NM_IPACC_TESTNO_TX_BEACON, "Transmit Beacon" }, + { NM_IPACC_TESTNO_SYSINFO_MONITOR, "System Info Monitor" }, + { NM_IPACC_TESTNO_BCCCH_MONITOR, "BCCH Monitor" }, + { 0, NULL } +}; + +const char *abis_nm_test_name(uint8_t test) +{ + return get_value_string(test_names, test); +} + +static const struct value_string abis_nm_adm_state_names[] = { + { NM_STATE_LOCKED, "Locked" }, + { NM_STATE_UNLOCKED, "Unlocked" }, + { NM_STATE_SHUTDOWN, "Shutdown" }, + { NM_STATE_NULL, "NULL" }, + { 0, NULL } +}; + +const char *abis_nm_adm_name(uint8_t adm) +{ + return get_value_string(abis_nm_adm_state_names, adm); +} + +void abis_nm_debugp_foh(int ss, struct abis_om_fom_hdr *foh) +{ + DEBUGP(ss, "OC=%s(%02x) INST=(%02x,%02x,%02x) ", + abis_nm_obj_class_name(foh->obj_class), foh->obj_class, + foh->obj_inst.bts_nr, foh->obj_inst.trx_nr, + foh->obj_inst.ts_nr); +} -- cgit v1.2.3