39 |
39 |
#include <linux/if_link.h>
|
40 |
40 |
|
41 |
41 |
#include <libgtpnl/gtpnl.h>
|
|
42 |
#include <errno.h>
|
42 |
43 |
|
43 |
44 |
struct gtp_server_sock {
|
44 |
45 |
int family;
|
... | ... | |
55 |
56 |
struct sockaddr_in6 in6;
|
56 |
57 |
} fd2;
|
57 |
58 |
} sockaddr;
|
|
59 |
union {
|
|
60 |
struct in_addr v4;
|
|
61 |
struct in6_addr v6;
|
|
62 |
} addr;
|
58 |
63 |
};
|
59 |
64 |
|
60 |
|
static void setup_sockaddr_in(struct sockaddr_in *sockaddr, uint16_t port)
|
|
65 |
static void setup_sockaddr_in(struct sockaddr_in *sockaddr, struct in_addr *in,
|
|
66 |
uint16_t port)
|
61 |
67 |
{
|
62 |
68 |
sockaddr->sin_family = AF_INET;
|
63 |
69 |
sockaddr->sin_port = htons(port);
|
64 |
|
sockaddr->sin_addr.s_addr = INADDR_ANY;
|
|
70 |
sockaddr->sin_addr = *in;
|
65 |
71 |
}
|
66 |
72 |
|
67 |
|
static void setup_sockaddr_in6(struct sockaddr_in6 *sockaddr, uint16_t port)
|
|
73 |
static void setup_sockaddr_in6(struct sockaddr_in6 *sockaddr, struct in6_addr *in6,
|
|
74 |
uint16_t port)
|
68 |
75 |
{
|
69 |
76 |
sockaddr->sin6_family = AF_INET6;
|
70 |
77 |
sockaddr->sin6_port = htons(port);
|
71 |
|
sockaddr->sin6_addr = in6addr_any;
|
|
78 |
sockaddr->sin6_addr = *in6;
|
72 |
79 |
}
|
73 |
80 |
|
74 |
81 |
static int setup_socket(struct gtp_server_sock *gtp_sock, int family)
|
... | ... | |
80 |
87 |
if (fd1 < 0 || fd2 < 0)
|
81 |
88 |
return -1;
|
82 |
89 |
|
83 |
|
memset(gtp_sock, 0, sizeof(*gtp_sock));
|
84 |
|
|
85 |
90 |
gtp_sock->family = family;
|
86 |
91 |
gtp_sock->fd1 = fd1;
|
87 |
92 |
gtp_sock->fd2 = fd2;
|
... | ... | |
89 |
94 |
switch (family) {
|
90 |
95 |
case AF_INET:
|
91 |
96 |
gtp_sock->len = sizeof(struct sockaddr_in);
|
92 |
|
setup_sockaddr_in(>p_sock->sockaddr.fd1.in, 3386);
|
93 |
|
setup_sockaddr_in(>p_sock->sockaddr.fd2.in, 2152);
|
|
97 |
setup_sockaddr_in(>p_sock->sockaddr.fd1.in,
|
|
98 |
>p_sock->addr.v4, 3386);
|
|
99 |
setup_sockaddr_in(>p_sock->sockaddr.fd2.in,
|
|
100 |
>p_sock->addr.v4, 2152);
|
94 |
101 |
break;
|
95 |
102 |
case AF_INET6:
|
96 |
103 |
gtp_sock->len = sizeof(struct sockaddr_in6);
|
97 |
|
setup_sockaddr_in6(>p_sock->sockaddr.fd1.in6, 3386);
|
98 |
|
setup_sockaddr_in6(>p_sock->sockaddr.fd2.in6, 2152);
|
|
104 |
setup_sockaddr_in6(>p_sock->sockaddr.fd1.in6,
|
|
105 |
>p_sock->addr.v6, 3386);
|
|
106 |
setup_sockaddr_in6(>p_sock->sockaddr.fd2.in6,
|
|
107 |
>p_sock->addr.v6, 2152);
|
99 |
108 |
if (setsockopt(fd1, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof(one)) < 0)
|
100 |
109 |
perror("setsockopt IPV6_V6ONLY: ");
|
101 |
110 |
if (setsockopt(fd2, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof(one)) < 0)
|
... | ... | |
111 |
120 |
char buf[MNL_SOCKET_BUFFER_SIZE];
|
112 |
121 |
struct gtp_server_sock gtp_sock;
|
113 |
122 |
int ret, sgsn_mode = 0, family;
|
|
123 |
const char *addr = NULL;
|
|
124 |
|
|
125 |
memset(>p_sock, 0, sizeof(gtp_sock));
|
114 |
126 |
|
115 |
127 |
if (argc < 3) {
|
116 |
|
printf("Usage: %s add <device> <family> [--sgsn]\n", argv[0]);
|
|
128 |
printf("Usage: %s add <device> <family> [--sgsn] <address>\n", argv[0]);
|
117 |
129 |
printf(" %s del <device>\n", argv[0]);
|
118 |
130 |
exit(EXIT_FAILURE);
|
119 |
131 |
}
|
... | ... | |
126 |
138 |
return 0;
|
127 |
139 |
} else if (!strcmp(argv[1], "add")) {
|
128 |
140 |
if (argc < 4) {
|
129 |
|
printf("Usage: %s add <device> <family> [--sgsn]\n", argv[0]);
|
|
141 |
printf("Usage: %s add <device> <family> [--sgsn] <device>\n", argv[0]);
|
130 |
142 |
exit(EXIT_FAILURE);
|
131 |
143 |
}
|
132 |
144 |
|
133 |
|
if (argc == 5 && !strcmp(argv[4], "--sgsn"))
|
134 |
|
sgsn_mode = 1;
|
|
145 |
if (argc == 5) {
|
|
146 |
if (!strcmp(argv[4], "--sgsn")) {
|
|
147 |
sgsn_mode = 1;
|
|
148 |
} else {
|
|
149 |
addr = argv[4];
|
|
150 |
}
|
|
151 |
}
|
|
152 |
|
|
153 |
if (argc == 6) {
|
|
154 |
if (!strcmp(argv[4], "--sgsn"))
|
|
155 |
sgsn_mode = 1;
|
|
156 |
|
|
157 |
addr = argv[5];
|
|
158 |
}
|
135 |
159 |
}
|
136 |
160 |
|
137 |
161 |
if (!strcmp(argv[3], "ip"))
|
... | ... | |
144 |
168 |
exit(EXIT_FAILURE);
|
145 |
169 |
}
|
146 |
170 |
|
|
171 |
if (addr) {
|
|
172 |
if (!inet_pton(family, addr, >p_sock.addr)) {
|
|
173 |
fprintf(stderr, "invalid listener address: %s\n",
|
|
174 |
strerror(errno));
|
|
175 |
exit(EXIT_FAILURE);
|
|
176 |
}
|
|
177 |
} else {
|
|
178 |
switch (family) {
|
|
179 |
case AF_INET:
|
|
180 |
gtp_sock.addr.v4.s_addr = INADDR_ANY;
|
|
181 |
break;
|
|
182 |
case AF_INET6:
|
|
183 |
gtp_sock.addr.v6 = in6addr_any;
|
|
184 |
break;
|
|
185 |
}
|
|
186 |
}
|
|
187 |
|
147 |
188 |
if (setup_socket(>p_sock, family) < 0) {
|
148 |
189 |
perror("socket");
|
149 |
190 |
exit(EXIT_FAILURE);
|