diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/Makefile.am | 37 | ||||
-rw-r--r-- | lib/gtp-kernel.c | 111 | ||||
-rw-r--r-- | lib/icmpv6.h | 14 | ||||
-rw-r--r-- | lib/in46_addr.c | 7 | ||||
-rw-r--r-- | lib/in46_addr.h | 2 | ||||
-rw-r--r-- | lib/tun.c | 9 | ||||
-rw-r--r-- | lib/tun.h | 3 |
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); @@ -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) @@ -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 */ |