aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/Makefile.am37
-rw-r--r--lib/gtp-kernel.c111
-rw-r--r--lib/icmpv6.h14
-rw-r--r--lib/in46_addr.c7
-rw-r--r--lib/in46_addr.h2
-rw-r--r--lib/tun.c9
-rw-r--r--lib/tun.h3
7 files changed, 131 insertions, 52 deletions
diff --git a/lib/Makefile.am b/lib/Makefile.am
index 5bd9443..bef8962 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -1,10 +1,41 @@
noinst_LIBRARIES = libmisc.a
-noinst_HEADERS = gnugetopt.h ippool.h lookup.h syserr.h tun.h in46_addr.h netdev.h gtp-kernel.h netns.h util.h icmpv6.h checksum.h
+noinst_HEADERS = \
+ checksum.h \
+ gnugetopt.h \
+ gtp-kernel.h \
+ icmpv6.h \
+ in46_addr.h \
+ ippool.h \
+ lookup.h \
+ netdev.h \
+ netns.h \
+ syserr.h \
+ tun.h \
+ util.h \
+ $(NULL)
-AM_CFLAGS = -O2 -fno-builtin -Wall -DSBINDIR='"$(sbindir)"' -ggdb $(LIBOSMOCORE_CFLAGS)
+AM_CFLAGS = \
+ -fno-builtin \
+ -Wall \
+ -DSBINDIR='"$(sbindir)"' \
+ $(LIBOSMOCORE_CFLAGS) \
+ $(NULL)
-libmisc_a_SOURCES = getopt1.c getopt.c ippool.c lookup.c tun.c debug.c in46_addr.c netdev.c netns.c util.c icmpv6.c checksum.c
+libmisc_a_SOURCES = \
+ checksum.c \
+ debug.c \
+ getopt.c \
+ getopt1.c \
+ icmpv6.c \
+ in46_addr.c \
+ ippool.c \
+ lookup.c \
+ netdev.c \
+ netns.c \
+ tun.c \
+ util.c \
+ $(NULL)
if ENABLE_GTP_KERNEL
AM_CFLAGS += -DGTP_KERNEL $(LIBGTPNL_CFLAGS)
diff --git a/lib/gtp-kernel.c b/lib/gtp-kernel.c
index f6df408..6a14d78 100644
--- a/lib/gtp-kernel.c
+++ b/lib/gtp-kernel.c
@@ -18,7 +18,6 @@
#include <libgtpnl/gtp.h>
#include <libgtpnl/gtpnl.h>
-#include <libmnl/libmnl.h>
#include <errno.h>
@@ -31,10 +30,6 @@
#include "../gtp/pdp.h"
#include "../gtp/gtp.h"
-#include <libgtpnl/gtp.h>
-#include <libgtpnl/gtpnl.h>
-#include <libmnl/libmnl.h>
-
#include "gtp-kernel.h"
static void pdp_debug(const char *prefix, const char *devname, struct pdp_t *pdp)
@@ -109,61 +104,97 @@ void gtp_kernel_stop(const char *devname)
int gtp_kernel_tunnel_add(struct pdp_t *pdp, const char *devname)
{
- struct in_addr ms, sgsn;
+ int ms_addr_count;
+ struct in46_addr ms[2];
+ struct in46_addr sgsn;
struct gtp_tunnel *t;
- int ret;
+ int ret = 0;
pdp_debug(__func__, devname, pdp);
- t = gtp_tunnel_alloc();
- if (t == NULL)
+ in46a_from_gsna(&pdp->gsnrc, &sgsn);
+
+ ms_addr_count = in46a_from_eua(&pdp->eua, ms);
+ if (ms_addr_count < 0)
return -1;
- memcpy(&ms, &pdp->eua.v[2], sizeof(struct in_addr));
- memcpy(&sgsn, &pdp->gsnrc.v[0], sizeof(struct in_addr));
-
- gtp_tunnel_set_ifidx(t, if_nametoindex(devname));
- gtp_tunnel_set_version(t, pdp->version);
- gtp_tunnel_set_ms_ip4(t, &ms);
- gtp_tunnel_set_sgsn_ip4(t, &sgsn);
- if (pdp->version == 0) {
- gtp_tunnel_set_tid(t, pdp_gettid(pdp->imsi, pdp->nsapi));
- gtp_tunnel_set_flowid(t, pdp->flru);
- } else {
- gtp_tunnel_set_i_tei(t, pdp->teid_own);
- /* use the TEI advertised by SGSN when sending packets
- * towards the SGSN */
- gtp_tunnel_set_o_tei(t, pdp->teid_gn);
+ for (int i = 0; i < ms_addr_count; i++) {
+ t = gtp_tunnel_alloc();
+ if (t == NULL)
+ return -1;
+
+ gtp_tunnel_set_ifidx(t, if_nametoindex(devname));
+ gtp_tunnel_set_version(t, pdp->version);
+
+ if (in46a_to_af(&ms[i]) == AF_INET)
+ gtp_tunnel_set_ms_ip4(t, &ms[i].v4);
+ else {
+ /* In IPv6, EUA doesn't contain the actual IP
+ * addr/prefix. Set higher bits to 0 to get the 64 bit
+ * netmask. */
+ memset(((void *)&ms[i].v6) + 8, 0, 8);
+ gtp_tunnel_set_ms_ip6(t, &ms[i].v6);
+ }
+
+ if (in46a_to_af(&sgsn) == AF_INET)
+ gtp_tunnel_set_sgsn_ip4(t, &sgsn.v4);
+ else
+ gtp_tunnel_set_sgsn_ip6(t, &sgsn.v6);
+
+ if (pdp->version == 0) {
+ gtp_tunnel_set_tid(t, pdp_gettid(pdp->imsi, pdp->nsapi));
+ gtp_tunnel_set_flowid(t, pdp->flru);
+ } else {
+ gtp_tunnel_set_i_tei(t, pdp->teid_own);
+ /* use the TEI advertised by SGSN when sending packets
+ * towards the SGSN */
+ gtp_tunnel_set_o_tei(t, pdp->teid_gn);
+ }
+
+ ret = gtp_add_tunnel(gtp_nl.genl_id, gtp_nl.nl, t);
+ gtp_tunnel_free(t);
+
+ if (ret != 0)
+ break;
}
- ret = gtp_add_tunnel(gtp_nl.genl_id, gtp_nl.nl, t);
- gtp_tunnel_free(t);
-
return ret;
}
int gtp_kernel_tunnel_del(struct pdp_t *pdp, const char *devname)
{
+ int ms_addr_count;
+ struct in46_addr ms[2];
struct gtp_tunnel *t;
- int ret;
+ int ret = 0;
pdp_debug(__func__, devname, pdp);
- t = gtp_tunnel_alloc();
- if (t == NULL)
+ ms_addr_count = in46a_from_eua(&pdp->eua, ms);
+ if (ms_addr_count < 0)
return -1;
- gtp_tunnel_set_ifidx(t, if_nametoindex(devname));
- gtp_tunnel_set_version(t, pdp->version);
- if (pdp->version == 0) {
- gtp_tunnel_set_tid(t, pdp_gettid(pdp->imsi, pdp->nsapi));
- gtp_tunnel_set_flowid(t, pdp->flru);
- } else {
- gtp_tunnel_set_i_tei(t, pdp->teid_own);
+ for (int i = 0; i < ms_addr_count; i++) {
+ t = gtp_tunnel_alloc();
+ if (t == NULL)
+ return -1;
+
+ gtp_tunnel_set_ifidx(t, if_nametoindex(devname));
+ gtp_tunnel_set_family(t, in46a_to_af(&ms[i]));
+ gtp_tunnel_set_version(t, pdp->version);
+ if (pdp->version == 0) {
+ gtp_tunnel_set_tid(t, pdp_gettid(pdp->imsi, pdp->nsapi));
+ gtp_tunnel_set_flowid(t, pdp->flru);
+ } else {
+ gtp_tunnel_set_i_tei(t, pdp->teid_own);
+ }
+
+ ret = gtp_del_tunnel(gtp_nl.genl_id, gtp_nl.nl, t);
+ gtp_tunnel_free(t);
+
+ if (ret != 0)
+ break;
}
- ret = gtp_del_tunnel(gtp_nl.genl_id, gtp_nl.nl, t);
- gtp_tunnel_free(t);
-
return ret;
}
diff --git a/lib/icmpv6.h b/lib/icmpv6.h
index 4b4dc37..ee5ef29 100644
--- a/lib/icmpv6.h
+++ b/lib/icmpv6.h
@@ -44,10 +44,9 @@ struct icmpv6_radv_hdr {
uint8_t res:6,
m:1,
o:1;
-#else
- uint8_t m:1,
- o:1,
- res:6;
+#elif OSMO_IS_BIG_ENDIAN
+/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianness.py) */
+ uint8_t o:1, m:1, res:6;
#endif
uint16_t router_lifetime;
uint32_t reachable_time;
@@ -72,10 +71,9 @@ struct icmpv6_opt_prefix {
uint8_t res:6,
a:1,
l:1;
-#else
- uint8_t l:1,
- a:1,
- res:6;
+#elif OSMO_IS_BIG_ENDIAN
+/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianness.py) */
+ uint8_t l:1, a:1, res:6;
#endif
uint32_t valid_lifetime;
uint32_t preferred_lifetime;
diff --git a/lib/in46_addr.c b/lib/in46_addr.c
index 2562c71..648fe7e 100644
--- a/lib/in46_addr.c
+++ b/lib/in46_addr.c
@@ -375,3 +375,10 @@ default_to_dyn_v4:
dst->v4.s_addr = 0;
return 1;
}
+
+void in46a_from_gsna(const struct ul16_t *in, struct in46_addr *dst)
+{
+ dst->len = in->l;
+ OSMO_ASSERT(in->l <= sizeof(dst->v6));
+ memcpy(&dst->v6, in->v, in->l);
+}
diff --git a/lib/in46_addr.h b/lib/in46_addr.h
index 153df00..5589f94 100644
--- a/lib/in46_addr.h
+++ b/lib/in46_addr.h
@@ -39,3 +39,5 @@ static inline bool in46a_is_v6(const struct in46_addr *addr) {
static inline bool in46a_is_v4(const struct in46_addr *addr) {
return addr->len == sizeof(struct in_addr);
}
+
+void in46a_from_gsna(const struct ul16_t *in, struct in46_addr *dst);
diff --git a/lib/tun.c b/lib/tun.c
index c771b92..cb66fef 100644
--- a/lib/tun.c
+++ b/lib/tun.c
@@ -318,7 +318,14 @@ int tun_decaps(struct tun_t *this)
int tun_encaps(struct tun_t *tun, void *pack, unsigned len)
{
- return write(tun->fd, pack, 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)
diff --git a/lib/tun.h b/lib/tun.h
index 07ca04a..36a4f7e 100644
--- a/lib/tun.h
+++ b/lib/tun.h
@@ -59,4 +59,7 @@ 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 */