aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am2
-rw-r--r--src/gtp-genl.c149
-rw-r--r--src/gtp.c42
-rw-r--r--src/internal.h26
-rw-r--r--src/libgtpnl.map9
5 files changed, 187 insertions, 41 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index a87c5cc..4d6910e 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -2,7 +2,7 @@ include $(top_srcdir)/Make_global.am
# This is _NOT_ the library release version, it's an API version.
# Please read Chapter 6 "Library interface versions" of the libtool documentation before making any modification
-LIBVERSION=1:1:1
+LIBVERSION=1:2:1
lib_LTLIBRARIES = libgtpnl.la
diff --git a/src/gtp-genl.c b/src/gtp-genl.c
index f12f872..33a78d8 100644
--- a/src/gtp-genl.c
+++ b/src/gtp-genl.c
@@ -44,20 +44,55 @@
static void gtp_build_payload(struct nlmsghdr *nlh, struct gtp_tunnel *t)
{
- mnl_attr_put_u32(nlh, GTPA_VERSION, t->gtp_version);
- if (t->ifns >= 0)
+ if (t->flags & GTP_TUN_FAMILY)
+ mnl_attr_put_u8(nlh, GTPA_FAMILY, t->ms_addr.family);
+ if (t->flags & GTP_TUN_VERSION)
+ mnl_attr_put_u32(nlh, GTPA_VERSION, t->gtp_version);
+ if (t->flags & GTP_TUN_IFNS)
mnl_attr_put_u32(nlh, GTPA_NET_NS_FD, t->ifns);
- mnl_attr_put_u32(nlh, GTPA_LINK, t->ifidx);
- if (t->sgsn_addr.s_addr)
- mnl_attr_put_u32(nlh, GTPA_PEER_ADDRESS, t->sgsn_addr.s_addr);
- if (t->ms_addr.s_addr)
- mnl_attr_put_u32(nlh, GTPA_MS_ADDRESS, t->ms_addr.s_addr);
- if (t->gtp_version == GTP_V0) {
- mnl_attr_put_u64(nlh, GTPA_TID, t->u.v0.tid);
- mnl_attr_put_u16(nlh, GTPA_FLOW, t->u.v0.flowid);
- } else if (t->gtp_version == GTP_V1) {
- mnl_attr_put_u32(nlh, GTPA_I_TEI, t->u.v1.i_tei);
- mnl_attr_put_u32(nlh, GTPA_O_TEI, t->u.v1.o_tei);
+ if (t->flags & GTP_TUN_IFIDX)
+ mnl_attr_put_u32(nlh, GTPA_LINK, t->ifidx);
+
+ if (t->flags & GTP_TUN_MS_ADDR) {
+ switch (t->ms_addr.family) {
+ case AF_INET:
+ mnl_attr_put_u32(nlh, GTPA_MS_ADDRESS, t->ms_addr.ip4.s_addr);
+ break;
+ case AF_INET6:
+ mnl_attr_put(nlh, GTPA_MS_ADDR6, sizeof(t->ms_addr.ip6), &t->ms_addr.ip6);
+ break;
+ default:
+ /* No addr is set when deleting a tunnel */
+ break;
+ }
+ }
+
+ if (t->flags & GTP_TUN_SGSN_ADDR) {
+ switch (t->sgsn_addr.family) {
+ case AF_INET:
+ mnl_attr_put_u32(nlh, GTPA_PEER_ADDRESS, t->sgsn_addr.ip4.s_addr);
+ break;
+ case AF_INET6:
+ mnl_attr_put(nlh, GTPA_PEER_ADDR6, sizeof(t->sgsn_addr.ip6), &t->sgsn_addr.ip6);
+ break;
+ default:
+ /* No addr is set when deleting a tunnel */
+ break;
+ }
+ }
+
+ if (t->flags & GTP_TUN_VERSION) {
+ if (t->gtp_version == GTP_V0) {
+ if (t->flags & GTP_TUN_V0_TID)
+ mnl_attr_put_u64(nlh, GTPA_TID, t->u.v0.tid);
+ if (t->flags & GTP_TUN_V0_FLOWID)
+ mnl_attr_put_u16(nlh, GTPA_FLOW, t->u.v0.flowid);
+ } else if (t->gtp_version == GTP_V1) {
+ if (t->flags & GTP_TUN_V1_I_TEI)
+ mnl_attr_put_u32(nlh, GTPA_I_TEI, t->u.v1.i_tei);
+ if (t->flags & GTP_TUN_V1_O_TEI)
+ mnl_attr_put_u32(nlh, GTPA_O_TEI, t->u.v1.o_tei);
+ }
}
}
@@ -77,8 +112,10 @@ int gtp_add_tunnel(int genl_id, struct mnl_socket *nl, struct gtp_tunnel *t)
GTP_CMD_NEWPDP);
gtp_build_payload(nlh, t);
- if (genl_socket_talk(nl, nlh, seq, NULL, NULL) < 0)
+ if (genl_socket_talk(nl, nlh, seq, NULL, NULL) < 0) {
perror("genl_socket_talk");
+ return -1;
+ }
return 0;
}
@@ -94,14 +131,17 @@ int gtp_del_tunnel(int genl_id, struct mnl_socket *nl, struct gtp_tunnel *t)
GTP_CMD_DELPDP);
gtp_build_payload(nlh, t);
- if (genl_socket_talk(nl, nlh, seq, NULL, NULL) < 0)
+ if (genl_socket_talk(nl, nlh, seq, NULL, NULL) < 0) {
perror("genl_socket_talk");
+ return -1;
+ }
return 0;
}
EXPORT_SYMBOL(gtp_del_tunnel);
struct gtp_pdp {
+ uint32_t ifidx;
uint32_t version;
union {
struct {
@@ -112,8 +152,8 @@ struct gtp_pdp {
uint32_t o_tei;
} v1;
} u;
- struct in_addr sgsn_addr;
- struct in_addr ms_addr;
+ struct gtp_addr sgsn_addr;
+ struct gtp_addr ms_addr;
};
static int genl_gtp_validate_cb(const struct nlattr *attr, void *data)
@@ -125,6 +165,12 @@ static int genl_gtp_validate_cb(const struct nlattr *attr, void *data)
return MNL_CB_OK;
switch(type) {
+ case GTPA_FAMILY:
+ if (mnl_attr_validate(attr, MNL_TYPE_U8) < 0) {
+ perror("mnl_attr_validate");
+ return MNL_CB_ERROR;
+ }
+ break;
case GTPA_TID:
if (mnl_attr_validate(attr, MNL_TYPE_U64) < 0) {
perror("mnl_attr_validate");
@@ -136,11 +182,20 @@ static int genl_gtp_validate_cb(const struct nlattr *attr, void *data)
case GTPA_PEER_ADDRESS:
case GTPA_MS_ADDRESS:
case GTPA_VERSION:
+ case GTPA_LINK:
if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0) {
perror("mnl_attr_validate");
return MNL_CB_ERROR;
}
break;
+ case GTPA_PEER_ADDR6:
+ case GTPA_MS_ADDR6:
+ if (mnl_attr_validate2(attr, MNL_TYPE_BINARY,
+ sizeof(struct in6_addr)) < 0) {
+ perror("mnl_attr_validate");
+ return MNL_CB_ERROR;
+ }
+ break;
default:
break;
}
@@ -151,39 +206,65 @@ static int genl_gtp_validate_cb(const struct nlattr *attr, void *data)
static int genl_gtp_attr_cb(const struct nlmsghdr *nlh, void *data)
{
struct nlattr *tb[GTPA_MAX + 1] = {};
- char buf[INET_ADDRSTRLEN];
+ char buf[INET6_ADDRSTRLEN];
struct gtp_pdp pdp = {};
struct genlmsghdr *genl;
mnl_attr_parse(nlh, sizeof(*genl), genl_gtp_validate_cb, tb);
+
+ if (tb[GTPA_LINK])
+ pdp.ifidx = mnl_attr_get_u32(tb[GTPA_LINK]);
if (tb[GTPA_TID])
pdp.u.v0.tid = mnl_attr_get_u64(tb[GTPA_TID]);
if (tb[GTPA_I_TEI])
pdp.u.v1.i_tei = mnl_attr_get_u32(tb[GTPA_I_TEI]);
if (tb[GTPA_O_TEI])
pdp.u.v1.o_tei = mnl_attr_get_u32(tb[GTPA_O_TEI]);
+
if (tb[GTPA_PEER_ADDRESS]) {
- pdp.sgsn_addr.s_addr =
- mnl_attr_get_u32(tb[GTPA_PEER_ADDRESS]);
+ pdp.sgsn_addr.family = AF_INET;
+ pdp.sgsn_addr.ip4.s_addr = mnl_attr_get_u32(tb[GTPA_PEER_ADDRESS]);
+ } else if (tb[GTPA_PEER_ADDR6]) {
+ pdp.sgsn_addr.family = AF_INET6;
+ memcpy(&pdp.sgsn_addr.ip6, mnl_attr_get_payload(tb[GTPA_PEER_ADDR6]),
+ sizeof(struct in6_addr));
+ } else {
+ fprintf(stderr, "sgsn_addr: no IPv4 nor IPv6 set\n");
+ return MNL_CB_ERROR;
}
+
if (tb[GTPA_MS_ADDRESS]) {
- pdp.ms_addr.s_addr = mnl_attr_get_u32(tb[GTPA_MS_ADDRESS]);
+ pdp.ms_addr.family = AF_INET;
+ pdp.ms_addr.ip4.s_addr = mnl_attr_get_u32(tb[GTPA_MS_ADDRESS]);
+ } else if (tb[GTPA_MS_ADDR6]) {
+ pdp.ms_addr.family = AF_INET6;
+ memcpy(&pdp.ms_addr.ip6, mnl_attr_get_payload(tb[GTPA_MS_ADDR6]), sizeof(struct in6_addr));
+ } else {
+ fprintf(stderr, "ms_addr: no IPv4 nor IPv6 set\n");
+ return MNL_CB_ERROR;
}
- if (tb[GTPA_VERSION]) {
- pdp.version = mnl_attr_get_u32(tb[GTPA_VERSION]);
+
+ if (tb[GTPA_FAMILY] && mnl_attr_get_u32(tb[GTPA_FAMILY]) != pdp.ms_addr.family) {
+ fprintf(stderr, "ms_addr family does not match GTPA_FAMILY\n");
+ return MNL_CB_ERROR;
}
+ printf("%s ", if_indextoname(pdp.ifidx, buf));
+
+ if (tb[GTPA_VERSION])
+ pdp.version = mnl_attr_get_u32(tb[GTPA_VERSION]);
+
printf("version %u ", pdp.version);
- if (pdp.version == GTP_V0) {
- inet_ntop(AF_INET, &pdp.ms_addr, buf, sizeof(buf));
- printf("tid %"PRIu64" ms_addr %s ",
- pdp.u.v0.tid, buf);
- } else if (pdp.version == GTP_V1) {
- inet_ntop(AF_INET, &pdp.ms_addr, buf, sizeof(buf));
- printf("tei %u/%u ms_addr %s ", pdp.u.v1.i_tei,
- pdp.u.v1.o_tei, buf);
- }
- inet_ntop(AF_INET, &pdp.sgsn_addr, buf, sizeof(buf));
+
+ if (pdp.version == GTP_V0)
+ printf("tid %"PRIu64" ", pdp.u.v0.tid);
+ else if (pdp.version == GTP_V1)
+ printf("tei %u/%u ", pdp.u.v1.i_tei, pdp.u.v1.o_tei);
+
+ inet_ntop(pdp.ms_addr.family, &pdp.ms_addr.ip4, buf, sizeof(buf));
+ printf("ms_addr %s ", buf);
+
+ inet_ntop(pdp.sgsn_addr.family, &pdp.sgsn_addr.ip4, buf, sizeof(buf));
printf("sgsn_addr %s\n", buf);
return MNL_CB_OK;
@@ -200,7 +281,7 @@ int gtp_list_tunnel(int genl_id, struct mnl_socket *nl)
if (genl_socket_talk(nl, nlh, seq, genl_gtp_attr_cb, NULL) < 0) {
perror("genl_socket_talk");
- return 0;
+ return -1;
}
return 0;
diff --git a/src/gtp.c b/src/gtp.c
index e65b0b6..af216f7 100644
--- a/src/gtp.c
+++ b/src/gtp.c
@@ -49,54 +49,88 @@ EXPORT_SYMBOL(gtp_tunnel_free);
void gtp_tunnel_set_ifns(struct gtp_tunnel *t, int ifns)
{
t->ifns = ifns;
+ t->flags |= GTP_TUN_IFNS;
}
EXPORT_SYMBOL(gtp_tunnel_set_ifns);
void gtp_tunnel_set_ifidx(struct gtp_tunnel *t, uint32_t ifidx)
{
t->ifidx = ifidx;
+ t->flags |= GTP_TUN_IFIDX;
}
EXPORT_SYMBOL(gtp_tunnel_set_ifidx);
+void gtp_tunnel_set_family(struct gtp_tunnel *t, uint16_t family)
+{
+ t->ms_addr.family = family;
+ t->flags |= GTP_TUN_FAMILY;
+}
+EXPORT_SYMBOL(gtp_tunnel_set_family);
+
void gtp_tunnel_set_ms_ip4(struct gtp_tunnel *t, struct in_addr *ms_addr)
{
- t->ms_addr = *ms_addr;
+ t->ms_addr.family = AF_INET;
+ t->ms_addr.ip4 = *ms_addr;
+ t->flags |= GTP_TUN_FAMILY | GTP_TUN_MS_ADDR;
}
EXPORT_SYMBOL(gtp_tunnel_set_ms_ip4);
void gtp_tunnel_set_sgsn_ip4(struct gtp_tunnel *t, struct in_addr *sgsn_addr)
{
- t->sgsn_addr = *sgsn_addr;
+ t->sgsn_addr.family = AF_INET;
+ t->sgsn_addr.ip4 = *sgsn_addr;
+ t->flags |= GTP_TUN_SGSN_ADDR;
}
EXPORT_SYMBOL(gtp_tunnel_set_sgsn_ip4);
+void gtp_tunnel_set_ms_ip6(struct gtp_tunnel *t, const struct in6_addr *ms_addr)
+{
+ t->ms_addr.family = AF_INET6;
+ t->ms_addr.ip6 = *ms_addr;
+ t->flags |= GTP_TUN_FAMILY | GTP_TUN_MS_ADDR;
+}
+EXPORT_SYMBOL(gtp_tunnel_set_ms_ip6);
+
+void gtp_tunnel_set_sgsn_ip6(struct gtp_tunnel *t, const struct in6_addr *sgsn_addr)
+{
+ t->sgsn_addr.family = AF_INET6;
+ t->sgsn_addr.ip6 = *sgsn_addr;
+ t->flags |= GTP_TUN_SGSN_ADDR;
+}
+EXPORT_SYMBOL(gtp_tunnel_set_sgsn_ip6);
+
void gtp_tunnel_set_version(struct gtp_tunnel *t, uint32_t version)
{
t->gtp_version = version;
+ t->flags |= GTP_TUN_VERSION;
}
EXPORT_SYMBOL(gtp_tunnel_set_version);
void gtp_tunnel_set_tid(struct gtp_tunnel *t, uint64_t tid)
{
t->u.v0.tid = tid;
+ t->flags |= GTP_TUN_V0_TID;
}
EXPORT_SYMBOL(gtp_tunnel_set_tid);
void gtp_tunnel_set_flowid(struct gtp_tunnel *t, uint16_t flowid)
{
t->u.v0.flowid = flowid;
+ t->flags |= GTP_TUN_V0_FLOWID;
}
EXPORT_SYMBOL(gtp_tunnel_set_flowid);
void gtp_tunnel_set_i_tei(struct gtp_tunnel *t, uint32_t i_tei)
{
t->u.v1.i_tei = i_tei;
+ t->flags |= GTP_TUN_V1_I_TEI;
}
EXPORT_SYMBOL(gtp_tunnel_set_i_tei);
void gtp_tunnel_set_o_tei(struct gtp_tunnel *t, uint32_t o_tei)
{
t->u.v1.o_tei = o_tei;
+ t->flags |= GTP_TUN_V1_O_TEI;
}
EXPORT_SYMBOL(gtp_tunnel_set_o_tei);
@@ -114,13 +148,13 @@ EXPORT_SYMBOL(gtp_tunnel_get_ifidx);
const struct in_addr *gtp_tunnel_get_ms_ip4(struct gtp_tunnel *t)
{
- return &t->ms_addr;
+ return &t->ms_addr.ip4;
}
EXPORT_SYMBOL(gtp_tunnel_get_ms_ip4);
const struct in_addr *gtp_tunnel_get_sgsn_ip4(struct gtp_tunnel *t)
{
- return &t->sgsn_addr;
+ return &t->sgsn_addr.ip4;
}
EXPORT_SYMBOL(gtp_tunnel_get_sgsn_ip4);
diff --git a/src/internal.h b/src/internal.h
index 1754e3b..1433621 100644
--- a/src/internal.h
+++ b/src/internal.h
@@ -12,11 +12,32 @@
#include <stdint.h>
#include <netinet/in.h>
+struct gtp_addr {
+ sa_family_t family;
+ union {
+ struct in_addr ip4;
+ struct in6_addr ip6;
+ };
+};
+
+enum {
+ GTP_TUN_IFNS = (1 << 0),
+ GTP_TUN_IFIDX = (1 << 1),
+ GTP_TUN_FAMILY = (1 << 2),
+ GTP_TUN_MS_ADDR = (1 << 3),
+ GTP_TUN_SGSN_ADDR = (1 << 4),
+ GTP_TUN_VERSION = (1 << 5),
+ GTP_TUN_V0_TID = (1 << 6),
+ GTP_TUN_V0_FLOWID = (1 << 7),
+ GTP_TUN_V1_I_TEI = (1 << 8),
+ GTP_TUN_V1_O_TEI = (1 << 9),
+};
+
struct gtp_tunnel {
int ifns;
uint32_t ifidx;
- struct in_addr ms_addr;
- struct in_addr sgsn_addr;
+ struct gtp_addr ms_addr;
+ struct gtp_addr sgsn_addr;
int gtp_version;
union {
struct {
@@ -28,6 +49,7 @@ struct gtp_tunnel {
uint32_t o_tei;
} v1;
} u;
+ uint32_t flags;
};
#endif
diff --git a/src/libgtpnl.map b/src/libgtpnl.map
index 804f8b3..41b7dd7 100644
--- a/src/libgtpnl.map
+++ b/src/libgtpnl.map
@@ -38,3 +38,12 @@ global:
local: *;
};
+
+LIBGTPNL_1.1 {
+ gtp_tunnel_set_ms_ip6;
+ gtp_tunnel_set_sgsn_ip6;
+} LIBGTPNL_1.0;
+
+LIBGTPNL_1.2 {
+ gtp_tunnel_set_family;
+} LIBGTPNL_1.1;