diff options
author | Oliver Smith <osmith@sysmocom.de> | 2024-02-20 14:01:51 +0100 |
---|---|---|
committer | Oliver Smith <osmith@sysmocom.de> | 2024-02-21 16:22:21 +0100 |
commit | 0917ce4e2271c0d71dfb8c86eb2d99821a374781 (patch) | |
tree | 644afd95667e509d41a5cce1012787719bf45e6e | |
parent | 2a0d37cb1db9d66301628db124aba8c0d496769f (diff) |
kernel-gtp: support IPv6 on outer layer
-rw-r--r-- | ggsn/ggsn.c | 8 | ||||
-rw-r--r-- | gtp/gsn.c | 61 | ||||
-rw-r--r-- | gtp/gsn.h | 8 | ||||
-rw-r--r-- | gtp/gtp.c | 4 | ||||
-rw-r--r-- | lib/in46_addr.c | 8 | ||||
-rw-r--r-- | lib/in46_addr.h | 1 | ||||
-rw-r--r-- | sgsnemu/sgsnemu.c | 9 | ||||
-rw-r--r-- | tests/gtp/Makefile.am | 2 |
8 files changed, 61 insertions, 40 deletions
diff --git a/ggsn/ggsn.c b/ggsn/ggsn.c index 918d565..cec043d 100644 --- a/ggsn/ggsn.c +++ b/ggsn/ggsn.c @@ -822,7 +822,7 @@ int ggsn_start(struct ggsn_ctx *ggsn) LOGPGGSN(LOGL_INFO, ggsn, "Starting GGSN\n"); /* Start libgtp listener */ - if (gtp_new(&ggsn->gsn, ggsn->cfg.state_dir, &ggsn->cfg.listen_addr.v4, GTP_MODE_GGSN)) { + if (gtp_new(&ggsn->gsn, ggsn->cfg.state_dir, &ggsn->cfg.listen_addr, GTP_MODE_GGSN)) { LOGPGGSN(LOGL_ERROR, ggsn, "Failed to create GTP: %s\n", strerror(errno)); return -1; } @@ -830,11 +830,9 @@ int ggsn_start(struct ggsn_ctx *ggsn) /* patch in different addresses to use (in case we're behind NAT, the listen * address is different from what we advertise externally) */ - if (ggsn->cfg.gtpc_addr.v4.s_addr) - ggsn->gsn->gsnc = ggsn->cfg.gtpc_addr.v4; + ggsn->gsn->gsnc = ggsn->cfg.gtpc_addr; - if (ggsn->cfg.gtpu_addr.v4.s_addr) - ggsn->gsn->gsnu = ggsn->cfg.gtpu_addr.v4; + ggsn->gsn->gsnu = ggsn->cfg.gtpu_addr; /* Register File Descriptors */ osmo_fd_setup(&ggsn->gtp_fd0, ggsn->gsn->fd0, OSMO_FD_READ, ggsn_gtp_fd_cb, ggsn, 0); @@ -64,11 +64,6 @@ /* Error reporting functions */ -#define LOGP_WITH_ADDR(ss, level, addr, fmt, args...) \ - LOGP(ss, level, "addr(%s:%d) " fmt, \ - inet_ntoa((addr).sin_addr), htons((addr).sin_port), \ - ##args); - static const struct rate_ctr_desc gsn_ctr_description[] = { [GSN_CTR_ERR_SOCKET] = { "err:socket", "Socket error" }, [GSN_CTR_ERR_READFROM] = { "err:readfrom", "readfrom() errors" }, @@ -423,46 +418,62 @@ free_filename: talloc_free(filename); } -static int create_and_bind_socket(const char *name, struct gsn_t *gsn, int *fd, int domain, - const struct in_addr *listen, int port) +static int create_and_bind_socket(const char *name, struct gsn_t *gsn, int *fd, const struct in46_addr *listen, + int port) { - struct sockaddr_in addr; + int family = in46a_to_af(listen); int type = SOCK_DGRAM; int protocol = 0; + struct sockaddr addr = {0}; + struct sockaddr_in *addr4 = (struct sockaddr_in *)&addr; + struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)&addr; - *fd = socket(domain, type, protocol); + *fd = socket(family, type, protocol); if (*fd < 0) { rate_ctr_inc2(gsn->ctrg, GSN_CTR_ERR_SOCKET); LOGP(DLGTP, LOGL_ERROR, "%s socket(domain=%d, type=%d, protocol=%d) failed: Error = %s\n", - name, domain, type, protocol, strerror(errno)); + name, family, type, protocol, strerror(errno)); return -errno; } - memset(&addr, 0, sizeof(addr)); - addr.sin_family = domain; - addr.sin_addr = *listen; - addr.sin_port = htons(port); + switch (family) { + case AF_INET: + addr4->sin_family = AF_INET; + addr4->sin_addr = listen->v4; + addr4->sin_port = htons(port); +#if defined(__FreeBSD__) || defined(__APPLE__) + addr4->sin_len = sizeof(struct addr); +#endif + break; + case AF_INET6: + addr6->sin6_family = AF_INET6; + addr6->sin6_addr = listen->v6; + addr6->sin6_port = htons(port); #if defined(__FreeBSD__) || defined(__APPLE__) - addr.sin_len = sizeof(addr); + addr6->sin6_len = sizeof(struct addr); #endif + break; + default: + OSMO_ASSERT(false); + break; + } - if (bind(*fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) { + if (bind(*fd, &addr, sizeof(addr)) < 0) { rate_ctr_inc2(gsn->ctrg, GSN_CTR_ERR_SOCKET); - LOGP_WITH_ADDR(DLGTP, LOGL_ERROR, addr, - "%s bind(fd=%d) failed: Error = %s\n", - name, *fd, strerror(errno)); + LOGP(DLGTP, LOGL_ERROR, + "%s bind(fd=%d, addr=(%s:%d)) failed: Error = %s\n", + name, *fd, in46a_ntoa(listen), port, strerror(errno)); return -errno; } return 0; } -int gtp_new(struct gsn_t **gsn, char *statedir, struct in_addr *listen, - int mode) +int gtp_new(struct gsn_t **gsn, char *statedir, struct in46_addr *listen, int mode) { - LOGP(DLGTP, LOGL_NOTICE, "GTP: gtp_newgsn() started at %s\n", inet_ntoa(*listen)); + LOGP(DLGTP, LOGL_NOTICE, "GTP: gtp_newgsn() started at %s\n", in46a_ntoa(listen)); *gsn = calloc(sizeof(struct gsn_t), 1); /* TODO */ @@ -511,15 +522,15 @@ int gtp_new(struct gsn_t **gsn, char *statedir, struct in_addr *listen, (*gsn)->fd1u = -1; /* Create GTP version 0 socket */ - if (create_and_bind_socket("GTPv0", *gsn, &(*gsn)->fd0, AF_INET, listen, GTP0_PORT) < 0) + if (create_and_bind_socket("GTPv0", *gsn, &(*gsn)->fd0, listen, GTP0_PORT) < 0) goto error; /* Create GTP version 1 control plane socket */ - if (create_and_bind_socket("GTPv1 control plane", *gsn, &(*gsn)->fd1c, AF_INET, listen, GTP1C_PORT) < 0) + if (create_and_bind_socket("GTPv1 control plane", *gsn, &(*gsn)->fd1c, listen, GTP1C_PORT) < 0) goto error; /* Create GTP version 1 user plane socket */ - if (create_and_bind_socket("GTPv1 user plane", *gsn, &(*gsn)->fd1u, AF_INET, listen, GTP1U_PORT) < 0) + if (create_and_bind_socket("GTPv1 user plane", *gsn, &(*gsn)->fd1u, listen, GTP1U_PORT) < 0) goto error; /* Start internal queue timer */ @@ -18,6 +18,7 @@ #include <osmocom/core/tdef.h> #include <osmocom/core/rate_ctr.h> +#include "../lib/in46_addr.h" #include "pdp.h" #define GTP_MODE_GGSN 1 @@ -77,8 +78,8 @@ struct gsn_t { int fd1c; /* GTP1 control plane file descriptor */ int fd1u; /* GTP0 user plane file descriptor */ int mode; /* Mode of operation: GGSN or SGSN */ - struct in_addr gsnc; /* IP address of this gsn for signalling */ - struct in_addr gsnu; /* IP address of this gsn for user traffic */ + struct in46_addr gsnc; /* IP address of this gsn for signalling */ + struct in46_addr gsnu; /* IP address of this gsn for user traffic */ /* Parameters related to signalling messages */ uint16_t seq_next; /* Next sequence number to use */ @@ -117,8 +118,7 @@ struct gsn_t { /* External API functions */ -extern int gtp_new(struct gsn_t **gsn, char *statedir, struct in_addr *listen, - int mode); +extern int gtp_new(struct gsn_t **gsn, char *statedir, struct in46_addr *listen, int mode); extern int gtp_free(struct gsn_t *gsn); @@ -1297,8 +1297,8 @@ int gtp_create_pdp_ind(struct gsn_t *gsn, int version, } /* Initialize our own IP addresses */ - in_addr2gsna(&pdp->gsnlc, &gsn->gsnc); - in_addr2gsna(&pdp->gsnlu, &gsn->gsnu); + in46a_to_gsna(&pdp->gsnlc, &gsn->gsnc); + in46a_to_gsna(&pdp->gsnlu, &gsn->gsnu); if (!gtp_pdp_getimsi(gsn, &pdp_old, pdp->imsi, pdp->nsapi)) { /* Found old pdp with same tid. Now the voodoo begins! */ diff --git a/lib/in46_addr.c b/lib/in46_addr.c index 648fe7e..d7c194f 100644 --- a/lib/in46_addr.c +++ b/lib/in46_addr.c @@ -376,6 +376,14 @@ default_to_dyn_v4: return 1; } +void in46a_to_gsna(struct ul16_t *gsna, const struct in46_addr *src) +{ + memset(gsna, 0, sizeof(struct ul16_t)); + gsna->l = src->len; + OSMO_ASSERT(gsna->l <= sizeof(gsna->v)); + memcpy(gsna->v, &src->v6, gsna->l); +} + void in46a_from_gsna(const struct ul16_t *in, struct in46_addr *dst) { dst->len = in->l; diff --git a/lib/in46_addr.h b/lib/in46_addr.h index 5589f94..59f58fc 100644 --- a/lib/in46_addr.h +++ b/lib/in46_addr.h @@ -40,4 +40,5 @@ static inline bool in46a_is_v4(const struct in46_addr *addr) { return addr->len == sizeof(struct in_addr); } +void in46a_to_gsna(struct ul16_t *gsna, const struct in46_addr *src); void in46a_from_gsna(const struct ul16_t *in, struct in46_addr *dst); diff --git a/sgsnemu/sgsnemu.c b/sgsnemu/sgsnemu.c index 7893f4f..f5ed671 100644 --- a/sgsnemu/sgsnemu.c +++ b/sgsnemu/sgsnemu.c @@ -59,6 +59,7 @@ #include "../lib/syserr.h" #include "../lib/netns.h" #include "../lib/icmpv6.h" +#include "../lib/in46_addr.h" #include "../gtp/pdp.h" #include "../gtp/gtp.h" #include "cmdline.h" @@ -117,7 +118,7 @@ struct { int pingsize; int pingcount; int pingquiet; - struct in_addr listen; + struct in46_addr listen; struct in_addr remote; struct in_addr dns; int contexts; /* Number of contexts to create */ @@ -459,10 +460,10 @@ static int process_options(int argc, char **argv) args_info.listen_arg); return -1; } else { - memcpy(&options.listen.s_addr, host->h_addr, - host->h_length); + options.listen.len = host->h_length; + memcpy(&options.listen.v6, host->h_addr, host->h_length); printf("Local IP address is: %s (%s)\n", - args_info.listen_arg, inet_ntoa(options.listen)); + args_info.listen_arg, in46a_ntoa(&options.listen)); } } else { SYS_ERR(DSGSN, LOGL_ERROR, 0, diff --git a/tests/gtp/Makefile.am b/tests/gtp/Makefile.am index ef69260..4d4d2e3 100644 --- a/tests/gtp/Makefile.am +++ b/tests/gtp/Makefile.am @@ -22,11 +22,13 @@ queue_test_SOURCES = \ gtpie_test_LDADD = \ $(top_builddir)/lib/debug.o \ $(top_builddir)/gtp/libgtp.la \ + $(top_builddir)/lib/libmisc.a \ $(LIBOSMOCORE_LIBS) \ $(NULL) queue_test_LDADD = \ $(top_builddir)/lib/debug.o \ $(top_builddir)/gtp/libgtp.la \ + $(top_builddir)/lib/libmisc.a \ $(LIBOSMOCORE_LIBS) \ $(NULL) |