From 825607672215b7a12ea6e201a89cd5209f6d657f Mon Sep 17 00:00:00 2001
From: Pablo Neira Ayuso <pablo@gnumonks.org>
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(+)

(limited to 'src')

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 <laforge@gnumonks.org>
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)
---
 src/Makefile.am   |   4 +-
 src/gsmtap_util.c | 192 ++++++++++++++++++++++++++++++------------------------
 src/socket.c      | 143 ++++++++++++++++++++++++++++++++++++++++
 3 files changed, 251 insertions(+), 88 deletions(-)
 create mode 100644 src/socket.c

(limited to 'src')

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 <laforge@gnumonks.org>
+ * (C) 2010-2011 by Harald Welte <laforge@gnumonks.org>
  *
  * All Rights Reserved
  *
@@ -22,18 +22,19 @@
 
 #include "../config.h"
 
-#ifdef HAVE_SYS_SELECT_H
-
 #include <osmocom/core/gsmtap_util.h>
 #include <osmocom/core/logging.h>
 #include <osmocom/core/gsmtap.h>
 #include <osmocom/core/msgb.h>
+#include <osmocom/core/talloc.h>
 #include <osmocom/core/select.h>
+#include <osmocom/core/socket.h>
 #include <osmocom/gsm/protocol/gsm_04_08.h>
 #include <osmocom/gsm/rsl.h>
 
 #include <arpa/inet.h>
 #include <sys/socket.h>
+#include <sys/types.h>
 #include <netinet/in.h>
 
 #include <stdio.h>
@@ -42,10 +43,6 @@
 #include <string.h>
 #include <errno.h>
 
-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(&gti->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 = &gti->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(&gti->wq, 64);
+		gti->wq.write_cb = &gsmtap_wq_w_cb;
+
+		osmo_fd_register(&gti->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 <osmocom/core/logging.h>
+#include <osmocom/core/select.h>
+#include <osmocom/core/socket.h>
+
+#include <arpa/inet.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdint.h>
+#include <string.h>
+#include <errno.h>
+#include <netdb.h>
+#include <ifaddrs.h>
+
+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 <laforge@gnumonks.org>
Date: Sun, 22 May 2011 12:25:57 +0200
Subject: GSMTAP/socket code: Check for sys/socket.h and conditionally compile

---
 src/gsmtap_util.c | 14 ++++++++------
 src/socket.c      |  6 +++++-
 2 files changed, 13 insertions(+), 7 deletions(-)

(limited to 'src')

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 <osmocom/gsm/protocol/gsm_04_08.h>
 #include <osmocom/gsm/rsl.h>
 
-#include <arpa/inet.h>
-#include <sys/socket.h>
 #include <sys/types.h>
-#include <netinet/in.h>
+
+#include <arpa/inet.h>
 
 #include <stdio.h>
 #include <unistd.h>
@@ -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 <sys/socket.h>
+#include <netinet/in.h>
+
 /* 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 <osmocom/core/logging.h>
 #include <osmocom/core/select.h>
 #include <osmocom/core/socket.h>
@@ -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 <laforge@gnumonks.org>
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(-)

(limited to 'src')

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 = "<unnamed>";
 
-	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 <laforge@gnumonks.org>
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(+)

(limited to 'src')

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(&gti->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 <laforge@gnumonks.org>
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(-)

(limited to 'src')

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 <laforge@gnumonks.org>
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.
---
 src/socket.c | 35 ++++++++++++++++++++++++++++++++++-
 1 file changed, 34 insertions(+), 1 deletion(-)

(limited to 'src')

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 f7a1bcce0cea50650517e305d59e674475f913d0 Mon Sep 17 00:00:00 2001
From: Harald Welte <laforge@gnumonks.org>
Date: Sun, 22 May 2011 22:45:16 +0200
Subject: abis_nm: import definitions and common code on A-bis OML from OpenBSC

---
 src/gsm/Makefile.am |   2 +-
 src/gsm/abis_nm.c   | 406 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 407 insertions(+), 1 deletion(-)
 create mode 100644 src/gsm/abis_nm.c

(limited to 'src')

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 <laforge@gnumonks.org>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU 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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <stdint.h>
+#include <osmocom/core/utils.h>
+#include <osmocom/core/logging.h>
+#include <osmocom/gsm/tlv.h>
+#include <osmocom/gsm/protocol/gsm_12_21.h>
+#include <osmocom/gsm/abis_nm.h>
+
+/* 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