diff --git a/tools/gtp-link.c b/tools/gtp-link.c index 325a45f..fcce052 100644 --- a/tools/gtp-link.c +++ b/tools/gtp-link.c @@ -39,6 +39,7 @@ #include #include +#include struct gtp_server_sock { int family; @@ -55,20 +56,26 @@ struct gtp_server_sock { 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 @@ static int setup_socket(struct gtp_server_sock *gtp_sock, int family) 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 @@ static int setup_socket(struct gtp_server_sock *gtp_sock, int family) 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 @@ int main(int argc, char *argv[]) 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 [--sgsn]\n", argv[0]); + printf("Usage: %s add [--sgsn]
\n", argv[0]); printf(" %s del \n", argv[0]); exit(EXIT_FAILURE); } @@ -126,12 +138,23 @@ int main(int argc, char *argv[]) return 0; } else if (!strcmp(argv[1], "add")) { if (argc < 4) { - printf("Usage: %s add [--sgsn]\n", argv[0]); + printf("Usage: %s add [--sgsn]
\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 @@ int main(int argc, char *argv[]) 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);