gtp-link: allow to specify listener address
gtp-link add <device> <family> [--sgsn] [<address>]
Allow to specify listener address, if not specified use ANY_ADDRESS.
Change-Id: I7a9b64393fd68d58c2c158c0e85c0470be007f63
diff --git a/tools/gtp-link.c b/tools/gtp-link.c
index 325a45f..0881f15 100644
--- a/tools/gtp-link.c
+++ b/tools/gtp-link.c
@@ -39,6 +39,7 @@
#include <linux/if_link.h>
#include <libgtpnl/gtpnl.h>
+#include <errno.h>
struct gtp_server_sock {
int family;
@@ -55,20 +56,26 @@
struct sockaddr_in6 in6;
} fd2;
} sockaddr;
+ union {
+ struct in_addr v4;
+ struct in6_addr v6;
+ } addr;
};
-static void setup_sockaddr_in(struct sockaddr_in *sockaddr, uint16_t port)
+static void setup_sockaddr_in(struct sockaddr_in *sockaddr, struct in_addr *in,
+ uint16_t port)
{
sockaddr->sin_family = AF_INET;
sockaddr->sin_port = htons(port);
- sockaddr->sin_addr.s_addr = INADDR_ANY;
+ sockaddr->sin_addr = *in;
}
-static void setup_sockaddr_in6(struct sockaddr_in6 *sockaddr, uint16_t port)
+static void setup_sockaddr_in6(struct sockaddr_in6 *sockaddr, struct in6_addr *in6,
+ uint16_t port)
{
sockaddr->sin6_family = AF_INET6;
sockaddr->sin6_port = htons(port);
- sockaddr->sin6_addr = in6addr_any;
+ sockaddr->sin6_addr = *in6;
}
static int setup_socket(struct gtp_server_sock *gtp_sock, int family)
@@ -80,8 +87,6 @@
if (fd1 < 0 || fd2 < 0)
return -1;
- memset(gtp_sock, 0, sizeof(*gtp_sock));
-
gtp_sock->family = family;
gtp_sock->fd1 = fd1;
gtp_sock->fd2 = fd2;
@@ -89,13 +94,17 @@
switch (family) {
case AF_INET:
gtp_sock->len = sizeof(struct sockaddr_in);
- setup_sockaddr_in(>p_sock->sockaddr.fd1.in, 3386);
- setup_sockaddr_in(>p_sock->sockaddr.fd2.in, 2152);
+ setup_sockaddr_in(>p_sock->sockaddr.fd1.in,
+ >p_sock->addr.v4, 3386);
+ setup_sockaddr_in(>p_sock->sockaddr.fd2.in,
+ >p_sock->addr.v4, 2152);
break;
case AF_INET6:
gtp_sock->len = sizeof(struct sockaddr_in6);
- setup_sockaddr_in6(>p_sock->sockaddr.fd1.in6, 3386);
- setup_sockaddr_in6(>p_sock->sockaddr.fd2.in6, 2152);
+ setup_sockaddr_in6(>p_sock->sockaddr.fd1.in6,
+ >p_sock->addr.v6, 3386);
+ setup_sockaddr_in6(>p_sock->sockaddr.fd2.in6,
+ >p_sock->addr.v6, 2152);
if (setsockopt(fd1, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof(one)) < 0)
perror("setsockopt IPV6_V6ONLY: ");
if (setsockopt(fd2, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof(one)) < 0)
@@ -111,9 +120,12 @@
char buf[MNL_SOCKET_BUFFER_SIZE];
struct gtp_server_sock gtp_sock;
int ret, sgsn_mode = 0, family;
+ const char *addr = NULL;
+
+ memset(>p_sock, 0, sizeof(gtp_sock));
if (argc < 3) {
- printf("Usage: %s add <device> <family> [--sgsn]\n", argv[0]);
+ printf("Usage: %s add <device> <family> [--sgsn] [<address>]\n", argv[0]);
printf(" %s del <device>\n", argv[0]);
exit(EXIT_FAILURE);
}
@@ -126,12 +138,23 @@
return 0;
} else if (!strcmp(argv[1], "add")) {
if (argc < 4) {
- printf("Usage: %s add <device> <family> [--sgsn]\n", argv[0]);
+ printf("Usage: %s add <device> <family> [--sgsn] [<address>]\n", argv[0]);
exit(EXIT_FAILURE);
}
- if (argc == 5 && !strcmp(argv[4], "--sgsn"))
- sgsn_mode = 1;
+ if (argc == 5) {
+ if (!strcmp(argv[4], "--sgsn"))
+ sgsn_mode = 1;
+ else
+ addr = argv[4];
+ }
+
+ if (argc == 6) {
+ if (!strcmp(argv[4], "--sgsn"))
+ sgsn_mode = 1;
+
+ addr = argv[5];
+ }
}
if (!strcmp(argv[3], "ip"))
@@ -144,6 +167,23 @@
exit(EXIT_FAILURE);
}
+ if (addr) {
+ if (!inet_pton(family, addr, >p_sock.addr)) {
+ fprintf(stderr, "invalid listener address: %s\n",
+ strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+ } else {
+ switch (family) {
+ case AF_INET:
+ gtp_sock.addr.v4.s_addr = INADDR_ANY;
+ break;
+ case AF_INET6:
+ gtp_sock.addr.v6 = in6addr_any;
+ break;
+ }
+ }
+
if (setup_socket(>p_sock, family) < 0) {
perror("socket");
exit(EXIT_FAILURE);