aboutsummaryrefslogtreecommitdiffstats
path: root/src/gsmtap_util.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/gsmtap_util.c')
-rw-r--r--src/gsmtap_util.c192
1 files changed, 106 insertions, 86 deletions
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 */