kernel-gtp: support IPv6 on outer layer
Related: OS#1953, OS#6096 Change-Id: I257fff1dcd9d030a7f9ea936b2693a3f13208230
This commit is contained in:
parent
2a0d37cb1d
commit
0917ce4e22
|
@ -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);
|
||||
|
|
61
gtp/gsn.c
61
gtp/gsn.c
|
@ -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__)
|
||||
addr.sin_len = sizeof(addr);
|
||||
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__)
|
||||
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! */
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue