pespin has uploaded this change for review.

View Change

layer23: Introduce tun.{c,h}

This module provides several operations on tun devices (interfaces).
These functionalitites will be used by the "modem" app to set up tunnels for each APN in a
follow-up patch.

The code is basically an import from osmo-ggsn.git
97f60e3dca581797007524e0006ca9fafad59713 src/lib/tun.{c,h}, with
small modifications to make use of osmo_sockaddr instead of
osmo-ggsn.git specific in46_addr.

Related: OS#5503
Change-Id: Id8611b720ada17a3c602872fe095bb91eeb17bcd
---
M src/host/layer23/include/osmocom/bb/common/Makefile.am
M src/host/layer23/include/osmocom/bb/common/apn.h
A src/host/layer23/include/osmocom/bb/common/tun.h
M src/host/layer23/src/common/Makefile.am
M src/host/layer23/src/common/apn.c
A src/host/layer23/src/common/tun.c
6 files changed, 555 insertions(+), 2 deletions(-)

git pull ssh://gerrit.osmocom.org:29418/osmocom-bb refs/changes/94/30994/1
diff --git a/src/host/layer23/include/osmocom/bb/common/Makefile.am b/src/host/layer23/include/osmocom/bb/common/Makefile.am
index 12be730..67dc21c 100644
--- a/src/host/layer23/include/osmocom/bb/common/Makefile.am
+++ b/src/host/layer23/include/osmocom/bb/common/Makefile.am
@@ -18,5 +18,6 @@
sim.h \
subscriber.h \
support.h \
+ tun.h \
vty.h \
$(NULL)
diff --git a/src/host/layer23/include/osmocom/bb/common/apn.h b/src/host/layer23/include/osmocom/bb/common/apn.h
index 18dc16f..7a6215b 100644
--- a/src/host/layer23/include/osmocom/bb/common/apn.h
+++ b/src/host/layer23/include/osmocom/bb/common/apn.h
@@ -21,6 +21,7 @@
#include <osmocom/core/select.h>

struct osmocom_ms;
+struct tun_t;

#define APN_TYPE_IPv4 0x01 /* v4-only */
#define APN_TYPE_IPv6 0x02 /* v6-only */
@@ -54,7 +55,7 @@

/* corresponding tun device */
struct {
- //struct tun_t *tun;
+ struct tun_t *tun;
struct osmo_fd fd;
} tun;

@@ -66,3 +67,6 @@
void apn_free(struct osmobb_apn *apn);
int apn_start(struct osmobb_apn *apn);
int apn_stop(struct osmobb_apn *apn);
+
+#define LOGPAPN(level, apn, fmt, args...) \
+ LOGP(DTUN, level, "APN(%s): " fmt, (apn)->cfg.name, ## args)
diff --git a/src/host/layer23/include/osmocom/bb/common/tun.h b/src/host/layer23/include/osmocom/bb/common/tun.h
new file mode 100644
index 0000000..703d1bd
--- /dev/null
+++ b/src/host/layer23/include/osmocom/bb/common/tun.h
@@ -0,0 +1,64 @@
+/*
+ * TUN interface functions.
+ * Copyright (C) 2002, 2003 Mondru AB.
+ * Copyright (C) 2017-2018 by Harald Welte <laforge@gnumonks.org>
+ * Copyright (C) 2023 by sysmocom - s.m.f.c. GmbH <info@sysmocom.de>
+ *
+ * The contents of this file may be used under the terms of the GNU
+ * General Public License Version 2, provided that the above copyright
+ * notice and this permission notice is included in all copies or
+ * substantial portions of the software.
+ *
+ */
+
+#ifndef _TUN_H
+#define _TUN_H
+
+#include <stdbool.h>
+#include <net/if.h>
+
+#include <osmocom/core/socket.h>
+#include <osmocom/bb/common/netdev.h>
+
+#define PACKET_MAX 8196 /* Maximum packet size we receive */
+#define TUN_SCRIPTSIZE 256
+#define TUN_ADDRSIZE 128
+
+/* ***********************************************************
+ * Information storage for each tun instance
+ *************************************************************/
+
+struct tun_t {
+ int fd; /* File descriptor to tun interface */
+ struct osmo_sockaddr addr;
+ struct osmo_sockaddr dstaddr;
+ struct in_addr netmask;
+ int addrs; /* Number of allocated IP addresses */
+ int routes; /* One if we allocated an automatic route */
+ char devname[IFNAMSIZ]; /* Name of the tun device */
+ int (*cb_ind) (struct tun_t * tun, void *pack, unsigned len);
+ /* to be used by callers/users (to attach their own private state) */
+ void *priv;
+};
+
+extern int tun_new(struct tun_t **tun, const char *dev_name, bool use_kernel, int fd0, int fd1u);
+extern int tun_free(struct tun_t *tun);
+extern int tun_decaps(struct tun_t *this);
+extern int tun_encaps(struct tun_t *tun, void *pack, unsigned len);
+
+extern int tun_addaddr(struct tun_t *this, struct osmo_sockaddr *addr,
+ struct osmo_sockaddr *dstaddr, size_t prefixlen);
+
+extern int tun_set_cb_ind(struct tun_t *this,
+ int (*cb_ind) (struct tun_t * tun, void *pack,
+ unsigned len));
+
+extern int tun_runscript(struct tun_t *tun, char *script);
+
+int tun_ip_local_get(const struct tun_t *tun, struct in46_prefix *prefix_list,
+ size_t prefix_size, int flags);
+
+#define LOGTUN(level, tun, fmt, args...) \
+ LOGP(DTUN, level, "TUN(%s): " fmt, (tun)->devname, ## args)
+
+#endif /* !_TUN_H */
diff --git a/src/host/layer23/src/common/Makefile.am b/src/host/layer23/src/common/Makefile.am
index 3a6ba37..cc6f3f5 100644
--- a/src/host/layer23/src/common/Makefile.am
+++ b/src/host/layer23/src/common/Makefile.am
@@ -30,6 +30,7 @@
subscriber.c \
support.c \
sysinfo.c \
+ tun.c \
utils.c \
vty.c \
$(NULL)
diff --git a/src/host/layer23/src/common/apn.c b/src/host/layer23/src/common/apn.c
index bd0eb25..f21892e 100644
--- a/src/host/layer23/src/common/apn.c
+++ b/src/host/layer23/src/common/apn.c
@@ -18,12 +18,14 @@
#include <stdint.h>
#include <errno.h>
#include <string.h>
-#include <arpa/inet.h>
+#include <netinet/ip.h>
+#include <netinet/ip6.h>

#include <talloc.h>

#include <osmocom/bb/common/logging.h>
#include <osmocom/bb/common/apn.h>
+#include <osmocom/bb/common/tun.h>
#include <osmocom/bb/common/ms.h>

struct osmobb_apn *apn_alloc(struct osmocom_ms *ms, const char *name)
@@ -49,12 +51,98 @@
talloc_free(apn);
}

+/* Local network-originated IP packet, needs to be sent via SNDCP/LLC (GPRS) towards GSM network */
+static int cb_tun_ind(struct tun_t *tun, void *pack, unsigned len)
+{
+ struct osmobb_apn *apn = tun->priv;
+ struct osmo_sockaddr dst;
+ struct iphdr *iph = (struct iphdr *)pack;
+ struct ip6_hdr *ip6h = (struct ip6_hdr *)pack;
+ uint8_t pref_offset;
+
+ switch (iph->version) {
+ case 4:
+ if (len < sizeof(*iph) || len < 4*iph->ihl)
+ return -1;
+ dst.u.sin.sin_family = AF_INET;
+ dst.u.sin.sin_addr.s_addr = iph->daddr;
+ break;
+ case 6:
+ /* Due to the fact that 3GPP requires an allocation of a
+ * /64 prefix to each MS, we must instruct
+ * ippool_getip() below to match only the leading /64
+ * prefix, i.e. the first 8 bytes of the address. If the ll addr
+ * is used, then the match should be done on the trailing 64
+ * bits. */
+ pref_offset = IN6_IS_ADDR_LINKLOCAL(&ip6h->ip6_dst) ? 8 : 0;
+ memcpy(&dst.u.sin6.sin6_addr, ((uint8_t*)&ip6h->ip6_dst) + pref_offset, 8);
+ break;
+ default:
+ LOGTUN(LOGL_NOTICE, tun, "non-IPv%u packet received\n", iph->version);
+ return -1;
+ }
+
+ LOGPAPN(LOGL_DEBUG, apn, "system wants to transmit IPv%u pkt to %s (%u bytes)\n",
+ iph->version == 4 ? '4' : '6', osmo_sockaddr_to_str(&dst), len);
+
+ /* TODO: prepare & transmit SNDCP UNITDATA.req */
+
+ return 0;
+}
+
+/* callback for tun device osmocom select loop integration */
+static int apn_tun_fd_cb(struct osmo_fd *fd, unsigned int what)
+{
+ struct osmobb_apn *apn = fd->data;
+
+ OSMO_ASSERT(what & OSMO_FD_READ);
+
+ return tun_decaps(apn->tun.tun);
+}
+
int apn_start(struct osmobb_apn *apn)
{
+ if (apn->started)
+ return 0;
+
+ LOGPAPN(LOGL_INFO, apn, "Opening TUN device %s\n", apn->cfg.dev_name);
+ if (tun_new(&apn->tun.tun, apn->cfg.dev_name, false, -1, -1)) {
+ LOGPAPN(LOGL_ERROR, apn, "Failed to configure tun device\n");
+ return -1;
+ }
+ LOGPAPN(LOGL_INFO, apn, "Opened TUN device %s\n", apn->tun.tun->devname);
+
+ /* Register with libosmcoore */
+ osmo_fd_setup(&apn->tun.fd, apn->tun.tun->fd, OSMO_FD_READ, apn_tun_fd_cb, apn, 0);
+ osmo_fd_register(&apn->tun.fd);
+
+ /* Set TUN library callback */
+ tun_set_cb_ind(apn->tun.tun, cb_tun_ind);
+
+ /* set back-pointer from TUN device to APN */
+ apn->tun.tun->priv = apn;
+
+ /* TODO: set IP addresses on the tun device once we receive them from GGSN. See
+ osmo-ggsn.git's apn_start() */
+
+ LOGPAPN(LOGL_NOTICE, apn, "Successfully started\n");
+ apn->started = true;
return 0;
}

int apn_stop(struct osmobb_apn *apn)
{
+ LOGPAPN(LOGL_NOTICE, apn, "Stopping\n");
+
+ /* shutdown whatever old state might be left */
+ if (apn->tun.tun) {
+ /* release tun device */
+ LOGPAPN(LOGL_INFO, apn, "Closing TUN device %s\n", apn->tun.tun->devname);
+ osmo_fd_unregister(&apn->tun.fd);
+ tun_free(apn->tun.tun);
+ apn->tun.tun = NULL;
+ }
+
+ apn->started = false;
return 0;
}
\ No newline at end of file
diff --git a/src/host/layer23/src/common/tun.c b/src/host/layer23/src/common/tun.c
new file mode 100644
index 0000000..98d1927
--- /dev/null
+++ b/src/host/layer23/src/common/tun.c
@@ -0,0 +1,395 @@
+/*
+ * TUN interface functions.
+ * Copyright (C) 2002, 2003, 2004 Mondru AB.
+ * Copyright (C) 2017-2018 by Harald Welte <laforge@gnumonks.org>
+ * Copyright (C) 2023 by sysmocom - s.m.f.c. GmbH <info@sysmocom.de>
+ *
+ * The contents of this file may be used under the terms of the GNU
+ * General Public License Version 2, provided that the above copyright
+ * notice and this permission notice is included in all copies or
+ * substantial portions of the software.
+ *
+ */
+
+/*
+ * tun.c: Contains all TUN functionality. Is able to handle multiple
+ * tunnels in the same program. Each tunnel is identified by the struct,
+ * which is passed to functions.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/time.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <errno.h>
+#include <net/route.h>
+#include <net/if.h>
+
+#if defined(__linux__)
+#include <linux/if_tun.h>
+
+#elif defined (__FreeBSD__)
+#include <net/if_tun.h>
+#include <net/if_var.h>
+#include <netinet/in_var.h>
+
+#elif defined (__APPLE__)
+#include <net/if.h>
+
+#else
+#error "Unknown platform!"
+#endif
+
+#include <osmocom/core/logging.h>
+#include <osmocom/core/socket.h>
+#include <osmocom/bb/common/logging.h>
+#include <osmocom/bb/common/tun.h>
+
+#define SYS_ERR(sub, pri, en, fmt, args...) \
+ if (en) { \
+ logp2(sub, pri, __FILE__, __LINE__, 0, \
+ "errno=%d/%s " fmt "\n", en, strerror(en), \
+ ##args); \
+ } else { \
+ logp2(sub, pri, __FILE__, __LINE__, 0, \
+ fmt "\n", ##args); \
+ }
+
+/* FIXME: import gtp-kernel.{c,h} from osmo-ggsn.git. */
+static int gtp_kernel_create(int dest_ns, const char *devname, int fd0, int fd1u)
+{
+ return -ENOTSUP;
+}
+static void gtp_kernel_stop(const char *devname)
+{
+ (void)devname;
+}
+
+static int tun_setaddr4(struct tun_t *this, struct in_addr *addr,
+ struct in_addr *dstaddr, struct in_addr *netmask)
+{
+ int rc;
+ rc = netdev_setaddr4(this->devname, addr, dstaddr, netmask);
+ if (rc < 0)
+ return rc;
+
+ if (addr) {
+ this->addr.u.sin.sin_family = AF_INET;
+ this->addr.u.sin.sin_addr.s_addr = addr->s_addr;
+ }
+ if (dstaddr) {
+ this->dstaddr.u.sin.sin_family = AF_INET;
+ this->dstaddr.u.sin.sin_addr.s_addr = dstaddr->s_addr;
+ }
+ if (netmask)
+ this->netmask.s_addr = netmask->s_addr;
+ this->addrs++;
+#if defined(__FreeBSD__) || defined (__APPLE__)
+ this->routes = 1;
+#endif
+
+ return rc;
+}
+
+static int tun_setaddr6(struct tun_t *this, struct in6_addr *addr, struct in6_addr *dstaddr,
+ size_t prefixlen)
+{
+ int rc;
+ rc = netdev_setaddr6(this->devname, addr, dstaddr, prefixlen);
+ if (rc < 0)
+ return rc;
+ if (dstaddr) {
+ this->dstaddr.u.sin6.sin6_family = AF_INET6;
+ memcpy(&this->dstaddr.u.sin6.sin6_addr, dstaddr, sizeof(*dstaddr));
+ }
+ this->addrs++;
+#if defined(__FreeBSD__) || defined (__APPLE__)
+ this->routes = 1;
+#endif
+
+ return rc;
+}
+
+static int tun_addaddr4(struct tun_t *this, struct in_addr *addr,
+ struct in_addr *dstaddr, struct in_addr *netmask)
+{
+ int rc;
+
+ /* TODO: Is this needed on FreeBSD? */
+ if (!this->addrs) /* Use ioctl for first addr to make ping work */
+ return tun_setaddr4(this, addr, dstaddr, netmask); /* TODO dstaddr */
+
+ rc = netdev_addaddr4(this->devname, addr, dstaddr, netmask);
+ if (rc < 0)
+ return rc;
+
+ this->addrs++;
+
+ return rc;
+}
+
+static int tun_addaddr6(struct tun_t *this,
+ struct in6_addr *addr,
+ struct in6_addr *dstaddr, int prefixlen)
+{
+ int rc;
+
+ if (!this->addrs) /* Use ioctl for first addr to make ping work */
+ return tun_setaddr6(this, addr, dstaddr, prefixlen);
+
+ rc = netdev_addaddr6(this->devname, addr, dstaddr, prefixlen);
+ if (rc < 0)
+ return rc;
+
+ this->addrs++;
+
+ return rc;
+}
+
+int tun_addaddr(struct tun_t *this, struct osmo_sockaddr *addr, struct osmo_sockaddr *dstaddr, size_t prefixlen)
+{
+ struct in_addr netmask;
+ switch (addr->u.sa.sa_family) {
+ case AF_INET:
+ netmask.s_addr = htonl(0xffffffff << (32 - prefixlen));
+ return tun_addaddr4(this, &addr->u.sin.sin_addr, dstaddr ? &dstaddr->u.sin.sin_addr : NULL, &netmask);
+ case AF_INET6:
+ return tun_addaddr6(this, &addr->u.sin6.sin6_addr, dstaddr ? &dstaddr->u.sin6.sin6_addr : NULL, prefixlen);
+ default:
+ return -1;
+ }
+}
+
+int tun_new(struct tun_t **tun, const char *dev_name, bool use_kernel, int fd0, int fd1u)
+{
+
+#if defined(__linux__)
+ struct ifreq ifr;
+
+#elif defined(__FreeBSD__) || defined (__APPLE__)
+ char devname[IFNAMSIZ + 5]; /* "/dev/" + ifname */
+ int devnum;
+ struct ifaliasreq areq;
+ int fd;
+#endif
+
+ if (!(*tun = calloc(1, sizeof(struct tun_t)))) {
+ SYS_ERR(DTUN, LOGL_ERROR, errno, "calloc() failed");
+ return EOF;
+ }
+
+ (*tun)->cb_ind = NULL;
+ (*tun)->addrs = 0;
+ (*tun)->routes = 0;
+
+#if defined(__linux__)
+ if (!use_kernel) {
+ /* Open the actual tun device */
+ if (((*tun)->fd = open("/dev/net/tun", O_RDWR)) < 0) {
+ SYS_ERR(DTUN, LOGL_ERROR, errno, "open() failed");
+ goto err_free;
+ }
+
+ /* Set device flags. For some weird reason this is also the method
+ used to obtain the network interface name */
+ memset(&ifr, 0, sizeof(ifr));
+ if (dev_name)
+ strcpy(ifr.ifr_name, dev_name);
+ ifr.ifr_flags = IFF_TUN | IFF_NO_PI; /* Tun device, no packet info */
+ if (ioctl((*tun)->fd, TUNSETIFF, (void *)&ifr) < 0) {
+ SYS_ERR(DTUN, LOGL_ERROR, errno, "ioctl() failed");
+ goto err_close;
+ }
+
+ strncpy((*tun)->devname, ifr.ifr_name, IFNAMSIZ);
+ (*tun)->devname[IFNAMSIZ - 1] = 0;
+
+ /* Disable checksums */
+ if (ioctl((*tun)->fd, TUNSETNOCSUM, 1) < 0) {
+ SYS_ERR(DTUN, LOGL_NOTICE, errno, "could not disable checksum on %s", (*tun)->devname);
+ }
+ return 0;
+ } else {
+ strncpy((*tun)->devname, dev_name, IFNAMSIZ);
+ (*tun)->devname[IFNAMSIZ - 1] = 0;
+ (*tun)->fd = -1;
+
+ if (gtp_kernel_create(-1, dev_name, fd0, fd1u) < 0) {
+ LOGP(DTUN, LOGL_ERROR, "cannot create GTP tunnel device: %s\n",
+ strerror(errno));
+ return -1;
+ }
+ LOGP(DTUN, LOGL_NOTICE, "GTP kernel configured\n");
+ return 0;
+ }
+
+#elif defined(__FreeBSD__) || defined (__APPLE__)
+
+ if (use_kernel) {
+ LOGP(DTUN, LOGL_ERROR, "No kernel GTP-U support in FreeBSD!\n");
+ return -1;
+ }
+
+ /* Find suitable device */
+ for (devnum = 0; devnum < 255; devnum++) { /* TODO 255 */
+ snprintf(devname, sizeof(devname), "/dev/tun%d", devnum);
+ if (((*tun)->fd = open(devname, O_RDWR)) >= 0)
+ break;
+ if (errno != EBUSY)
+ break;
+ }
+ if ((*tun)->fd < 0) {
+ SYS_ERR(DTUN, LOGL_ERROR, errno,
+ "Can't find tunnel device");
+ goto err_free;
+ }
+
+ snprintf((*tun)->devname, sizeof((*tun)->devname), "tun%d", devnum);
+ (*tun)->devname[sizeof((*tun)->devname)-1] = 0;
+
+ /* The tun device we found might have "old" IP addresses allocated */
+ /* We need to delete those. This problem is not present on Linux */
+
+ memset(&areq, 0, sizeof(areq));
+
+ /* Set up interface name */
+ strncpy(areq.ifra_name, (*tun)->devname, IFNAMSIZ);
+ areq.ifra_name[IFNAMSIZ - 1] = 0; /* Make sure to terminate */
+
+ /* Create a channel to the NET kernel. */
+ if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+ SYS_ERR(DTUN, LOGL_ERROR, errno, "socket() failed");
+ goto err_close;
+ }
+
+ /* Delete any IP addresses until SIOCDIFADDR fails */
+ while (ioctl(fd, SIOCDIFADDR, (void *)&areq) != -1) ;
+
+ close(fd);
+ return 0;
+#endif
+
+err_close:
+ close((*tun)->fd);
+err_free:
+ free(*tun);
+ *tun = NULL;
+ return -1;
+}
+
+int tun_free(struct tun_t *tun)
+{
+
+ if (tun->routes) {
+ netdev_delroute4(&tun->dstaddr.u.sin.sin_addr, &tun->addr.u.sin.sin_addr, &tun->netmask);
+ }
+
+ if (tun->fd >= 0) {
+ if (close(tun->fd)) {
+ SYS_ERR(DTUN, LOGL_ERROR, errno, "close() failed");
+ }
+ }
+
+ gtp_kernel_stop(tun->devname);
+
+ /* TODO: For solaris we need to unlink streams */
+
+ free(tun);
+ return 0;
+}
+
+int tun_set_cb_ind(struct tun_t *this,
+ int (*cb_ind) (struct tun_t * tun, void *pack, unsigned len))
+{
+ this->cb_ind = cb_ind;
+ return 0;
+}
+
+int tun_decaps(struct tun_t *this)
+{
+ unsigned char buffer[PACKET_MAX];
+ int status;
+
+ if ((status = read(this->fd, buffer, sizeof(buffer))) <= 0) {
+ SYS_ERR(DTUN, LOGL_ERROR, errno, "read() failed");
+ return -1;
+ }
+
+ if (this->cb_ind)
+ return this->cb_ind(this, buffer, status);
+
+ return 0;
+}
+
+int tun_encaps(struct tun_t *tun, void *pack, unsigned len)
+{
+ int rc;
+ rc = write(tun->fd, pack, len);
+ if (rc < 0) {
+ SYS_ERR(DTUN, LOGL_ERROR, errno, "TUN(%s): write() failed", tun->devname);
+ } else if (rc < len) {
+ LOGTUN(LOGL_ERROR, tun, "short write() %d < %u\n", rc, len);
+ }
+ return rc;
+}
+
+int tun_runscript(struct tun_t *tun, char *script)
+{
+
+ char buf[TUN_SCRIPTSIZE];
+ char snet[TUN_ADDRSIZE];
+ char smask[TUN_ADDRSIZE];
+ int rc;
+
+ snet[0] = '\0';
+ smask[0] = '\0';
+
+ /* system("ipup /dev/tun0 192.168.0.10 255.255.255.0"); */
+ snprintf(buf, sizeof(buf), "%s %s %s %s",
+ script, tun->devname,
+ osmo_sockaddr_ntop(&tun->addr.u.sa, snet),
+ inet_ntop(AF_INET, &tun->netmask, smask, sizeof(smask)));
+ buf[sizeof(buf) - 1] = 0;
+ rc = system(buf);
+ if (rc == -1) {
+ SYS_ERR(DTUN, LOGL_ERROR, errno,
+ "Error executing command %s", buf);
+ return -1;
+ }
+ return 0;
+}
+
+/*! Obtain the local address of the tun device.
+ * \param[in] tun Target device owning the IP
+ * \param[out] prefix_list List of prefix structures to fill with each IPv4/6 and prefix length found.
+ * \param[in] prefix_size Amount of elements allowed to be fill in the prefix_list array.
+ * \param[in] flags Specify which kind of IP to look for: IP_TYPE_IPv4, IP_TYPE_IPv6_LINK, IP_TYPE_IPv6_NONLINK
+ * \returns The number of ips found following the criteria specified by flags, -1 on error.
+ *
+ * This function will fill prefix_list with up to prefix_size IPs following the
+ * criteria specified by flags parameter. It returns the number of IPs matching
+ * the criteria. As a result, the number returned can be bigger than
+ * prefix_size. It can be used with prefix_size=0 to get an estimate of the size
+ * needed for prefix_list.
+ */
+int tun_ip_local_get(const struct tun_t *tun, struct in46_prefix *prefix_list, size_t prefix_size, int flags)
+{
+ return netdev_ip_local_get(tun->devname, prefix_list, prefix_size, flags);
+}

To view, visit change 30994. To unsubscribe, or for help writing mail filters, visit settings.

Gerrit-Project: osmocom-bb
Gerrit-Branch: master
Gerrit-Change-Id: Id8611b720ada17a3c602872fe095bb91eeb17bcd
Gerrit-Change-Number: 30994
Gerrit-PatchSet: 1
Gerrit-Owner: pespin <pespin@sysmocom.de>
Gerrit-MessageType: newchange