]> git.proxmox.com Git - mirror_iproute2.git/blame - ip/ipl2tp.c
rdma: Ignore unknown netlink attributes
[mirror_iproute2.git] / ip / ipl2tp.c
CommitLineData
38cd311a
SH
1/*
2 * ipl2tp.c "ip l2tp"
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version
7 * 2 of the License, or (at your option) any later version.
8 *
9 * Original Author: James Chapman <jchapman@katalix.com>
10 *
11 */
12
13#include <stdio.h>
14#include <stdlib.h>
15#include <string.h>
16#include <unistd.h>
17#include <errno.h>
18#include <sys/types.h>
19#include <sys/socket.h>
20#include <arpa/inet.h>
21#include <sys/ioctl.h>
22#include <linux/if.h>
23#include <linux/if_arp.h>
24#include <linux/ip.h>
25
38cd311a
SH
26#include <linux/genetlink.h>
27#include <linux/l2tp.h>
4ef9ff2a 28#include "libgenl.h"
38cd311a
SH
29
30#include "utils.h"
31#include "ip_common.h"
32
33enum {
34 L2TP_ADD,
35 L2TP_CHG,
36 L2TP_DEL,
37 L2TP_GET
38};
39
40struct l2tp_parm {
41 uint32_t tunnel_id;
42 uint32_t peer_tunnel_id;
43 uint32_t session_id;
44 uint32_t peer_session_id;
45 uint32_t offset;
46 uint32_t peer_offset;
47 enum l2tp_encap_type encap;
48 uint16_t local_udp_port;
49 uint16_t peer_udp_port;
50 int cookie_len;
51 uint8_t cookie[8];
52 int peer_cookie_len;
53 uint8_t peer_cookie[8];
6618e334
CE
54 inet_prefix local_ip;
55 inet_prefix peer_ip;
38cd311a
SH
56
57 uint16_t pw_type;
58 uint16_t mtu;
31f63e7c
AST
59 unsigned int udp6_csum_tx:1;
60 unsigned int udp6_csum_rx:1;
61 unsigned int udp_csum:1;
62 unsigned int recv_seq:1;
63 unsigned int send_seq:1;
64 unsigned int lns_mode:1;
65 unsigned int data_seq:2;
66 unsigned int tunnel:1;
67 unsigned int session:1;
38cd311a
SH
68 int reorder_timeout;
69 const char *ifname;
dd10baa5
JC
70 uint8_t l2spec_type;
71 uint8_t l2spec_len;
38cd311a
SH
72};
73
74struct l2tp_stats {
75 uint64_t data_rx_packets;
76 uint64_t data_rx_bytes;
77 uint64_t data_rx_errors;
78 uint64_t data_rx_oos_packets;
79 uint64_t data_rx_oos_discards;
80 uint64_t data_tx_packets;
81 uint64_t data_tx_bytes;
82 uint64_t data_tx_errors;
83};
84
85struct l2tp_data {
86 struct l2tp_parm config;
87 struct l2tp_stats stats;
88};
89
90/* netlink socket */
91static struct rtnl_handle genl_rth;
92static int genl_family = -1;
93
94/*****************************************************************************
95 * Netlink actions
96 *****************************************************************************/
97
98static int create_tunnel(struct l2tp_parm *p)
99{
6618e334
CE
100 uint32_t local_attr = L2TP_ATTR_IP_SADDR;
101 uint32_t peer_attr = L2TP_ATTR_IP_DADDR;
38cd311a 102
328d482c
JA
103 GENL_REQUEST(req, 1024, genl_family, 0, L2TP_GENL_VERSION,
104 L2TP_CMD_TUNNEL_CREATE, NLM_F_REQUEST | NLM_F_ACK);
38cd311a
SH
105
106 addattr32(&req.n, 1024, L2TP_ATTR_CONN_ID, p->tunnel_id);
107 addattr32(&req.n, 1024, L2TP_ATTR_PEER_CONN_ID, p->peer_tunnel_id);
108 addattr8(&req.n, 1024, L2TP_ATTR_PROTO_VERSION, 3);
109 addattr16(&req.n, 1024, L2TP_ATTR_ENCAP_TYPE, p->encap);
110
6618e334
CE
111 if (p->local_ip.family == AF_INET6)
112 local_attr = L2TP_ATTR_IP6_SADDR;
281db53f
SH
113 addattr_l(&req.n, 1024, local_attr, &p->local_ip.data,
114 p->local_ip.bytelen);
6618e334
CE
115
116 if (p->peer_ip.family == AF_INET6)
117 peer_attr = L2TP_ATTR_IP6_DADDR;
281db53f
SH
118 addattr_l(&req.n, 1024, peer_attr, &p->peer_ip.data,
119 p->peer_ip.bytelen);
6618e334 120
38cd311a
SH
121 if (p->encap == L2TP_ENCAPTYPE_UDP) {
122 addattr16(&req.n, 1024, L2TP_ATTR_UDP_SPORT, p->local_udp_port);
123 addattr16(&req.n, 1024, L2TP_ATTR_UDP_DPORT, p->peer_udp_port);
9bf9d05b 124 if (p->udp_csum)
c73fad78 125 addattr8(&req.n, 1024, L2TP_ATTR_UDP_CSUM, 1);
9bf9d05b
SW
126 if (!p->udp6_csum_tx)
127 addattr(&req.n, 1024, L2TP_ATTR_UDP_ZERO_CSUM6_TX);
128 if (!p->udp6_csum_rx)
129 addattr(&req.n, 1024, L2TP_ATTR_UDP_ZERO_CSUM6_RX);
38cd311a
SH
130 }
131
86bf43c7 132 if (rtnl_talk(&genl_rth, &req.n, NULL) < 0)
38cd311a
SH
133 return -2;
134
135 return 0;
136}
137
138static int delete_tunnel(struct l2tp_parm *p)
139{
328d482c
JA
140 GENL_REQUEST(req, 128, genl_family, 0, L2TP_GENL_VERSION,
141 L2TP_CMD_TUNNEL_DELETE, NLM_F_REQUEST | NLM_F_ACK);
38cd311a
SH
142
143 addattr32(&req.n, 128, L2TP_ATTR_CONN_ID, p->tunnel_id);
144
86bf43c7 145 if (rtnl_talk(&genl_rth, &req.n, NULL) < 0)
38cd311a
SH
146 return -2;
147
148 return 0;
149}
150
151static int create_session(struct l2tp_parm *p)
152{
328d482c
JA
153 GENL_REQUEST(req, 1024, genl_family, 0, L2TP_GENL_VERSION,
154 L2TP_CMD_SESSION_CREATE, NLM_F_REQUEST | NLM_F_ACK);
38cd311a
SH
155
156 addattr32(&req.n, 1024, L2TP_ATTR_CONN_ID, p->tunnel_id);
157 addattr32(&req.n, 1024, L2TP_ATTR_PEER_CONN_ID, p->peer_tunnel_id);
158 addattr32(&req.n, 1024, L2TP_ATTR_SESSION_ID, p->session_id);
159 addattr32(&req.n, 1024, L2TP_ATTR_PEER_SESSION_ID, p->peer_session_id);
160 addattr16(&req.n, 1024, L2TP_ATTR_PW_TYPE, p->pw_type);
dd10baa5
JC
161 addattr8(&req.n, 1024, L2TP_ATTR_L2SPEC_TYPE, p->l2spec_type);
162 addattr8(&req.n, 1024, L2TP_ATTR_L2SPEC_LEN, p->l2spec_len);
38cd311a 163
281db53f
SH
164 if (p->mtu)
165 addattr16(&req.n, 1024, L2TP_ATTR_MTU, p->mtu);
166 if (p->recv_seq)
167 addattr8(&req.n, 1024, L2TP_ATTR_RECV_SEQ, 1);
168 if (p->send_seq)
169 addattr8(&req.n, 1024, L2TP_ATTR_SEND_SEQ, 1);
170 if (p->lns_mode)
171 addattr(&req.n, 1024, L2TP_ATTR_LNS_MODE);
172 if (p->data_seq)
173 addattr8(&req.n, 1024, L2TP_ATTR_DATA_SEQ, p->data_seq);
174 if (p->reorder_timeout)
175 addattr64(&req.n, 1024, L2TP_ATTR_RECV_TIMEOUT,
38cd311a 176 p->reorder_timeout);
281db53f
SH
177 if (p->offset)
178 addattr16(&req.n, 1024, L2TP_ATTR_OFFSET, p->offset);
179 if (p->cookie_len)
180 addattr_l(&req.n, 1024, L2TP_ATTR_COOKIE,
181 p->cookie, p->cookie_len);
182 if (p->peer_cookie_len)
183 addattr_l(&req.n, 1024, L2TP_ATTR_PEER_COOKIE,
184 p->peer_cookie, p->peer_cookie_len);
625df645 185 if (p->ifname)
38cd311a
SH
186 addattrstrz(&req.n, 1024, L2TP_ATTR_IFNAME, p->ifname);
187
86bf43c7 188 if (rtnl_talk(&genl_rth, &req.n, NULL) < 0)
38cd311a
SH
189 return -2;
190
191 return 0;
192}
193
194static int delete_session(struct l2tp_parm *p)
195{
328d482c
JA
196 GENL_REQUEST(req, 1024, genl_family, 0, L2TP_GENL_VERSION,
197 L2TP_CMD_SESSION_DELETE, NLM_F_REQUEST | NLM_F_ACK);
38cd311a
SH
198
199 addattr32(&req.n, 1024, L2TP_ATTR_CONN_ID, p->tunnel_id);
200 addattr32(&req.n, 1024, L2TP_ATTR_SESSION_ID, p->session_id);
86bf43c7 201 if (rtnl_talk(&genl_rth, &req.n, NULL) < 0)
38cd311a
SH
202 return -2;
203
204 return 0;
205}
206
98453b65
SH
207static void print_cookie(const char *name, const char *fmt,
208 const uint8_t *cookie, int len)
38cd311a 209{
98453b65
SH
210 char abuf[32];
211 size_t n;
212
213 n = snprintf(abuf, sizeof(abuf),
214 "%02x%02x%02x%02x",
215 cookie[0], cookie[1], cookie[2], cookie[3]);
38cd311a 216 if (len == 8)
98453b65
SH
217 snprintf(abuf + n, sizeof(abuf) - n,
218 "%02x%02x%02x%02x",
219 cookie[4], cookie[5],
220 cookie[6], cookie[7]);
221
222 print_string(PRINT_ANY, name, fmt, abuf);
38cd311a
SH
223}
224
225static void print_tunnel(const struct l2tp_data *data)
226{
227 const struct l2tp_parm *p = &data->config;
6618e334 228 char buf[INET6_ADDRSTRLEN];
38cd311a 229
98453b65
SH
230 open_json_object(NULL);
231 print_uint(PRINT_ANY, "tunnel_id", "Tunnel %u,", p->tunnel_id);
232 print_string(PRINT_ANY, "encap", " encap %s",
233 p->encap == L2TP_ENCAPTYPE_UDP ? "UDP" :
234 p->encap == L2TP_ENCAPTYPE_IP ? "IP" : "??");
235 print_string(PRINT_FP, NULL, "%s", _SL_);
236
237 print_string(PRINT_ANY, "local", " From %s ",
238 inet_ntop(p->local_ip.family, p->local_ip.data,
239 buf, sizeof(buf)));
240 print_string(PRINT_ANY, "peer", "to %s",
241 inet_ntop(p->peer_ip.family, p->peer_ip.data,
242 buf, sizeof(buf)));
243 print_string(PRINT_FP, NULL, "%s", _SL_);
244
245 print_uint(PRINT_ANY, "peer_tunnel", " Peer tunnel %u",
246 p->peer_tunnel_id);
247 print_string(PRINT_FP, NULL, "%s", _SL_);
38cd311a 248
f7982f5c 249 if (p->encap == L2TP_ENCAPTYPE_UDP) {
98453b65
SH
250 print_string(PRINT_FP, NULL,
251 " UDP source / dest ports:", NULL);
252
253 print_uint(PRINT_ANY, "local_port", " %hu",
254 p->local_udp_port);
255 print_uint(PRINT_ANY, "peer_port", "/%hu",
256 p->peer_udp_port);
257 print_string(PRINT_FP, NULL, "%s", _SL_);
f7982f5c
AST
258
259 switch (p->local_ip.family) {
260 case AF_INET:
98453b65
SH
261 print_bool(PRINT_JSON, "checksum",
262 NULL, p->udp_csum);
263 print_string(PRINT_FP, NULL,
264 " UDP checksum: %s\n",
265 p->udp_csum ? "enabled" : "disabled");
f7982f5c
AST
266 break;
267 case AF_INET6:
98453b65
SH
268 if (is_json_context()) {
269 print_bool(PRINT_JSON, "checksum_tx",
270 NULL, p->udp6_csum_tx);
271
272 print_bool(PRINT_JSON, "checksum_rx",
273 NULL, p->udp6_csum_tx);
274 } else {
275 printf(" UDP checksum: %s%s%s%s\n",
276 p->udp6_csum_tx && p->udp6_csum_rx
277 ? "enabled" : "",
278 p->udp6_csum_tx && !p->udp6_csum_rx
279 ? "tx" : "",
280 !p->udp6_csum_tx && p->udp6_csum_rx
281 ? "rx" : "",
282 !p->udp6_csum_tx && !p->udp6_csum_rx
283 ? "disabled" : "");
284 }
f7982f5c
AST
285 break;
286 }
287 }
98453b65 288 close_json_object();
38cd311a
SH
289}
290
291static void print_session(struct l2tp_data *data)
292{
293 struct l2tp_parm *p = &data->config;
294
98453b65 295 open_json_object(NULL);
38cd311a 296
98453b65
SH
297 print_uint(PRINT_ANY, "session_id", "Session %u", p->session_id);
298 print_uint(PRINT_ANY, "tunnel_id", " in tunnel %u", p->tunnel_id);
299 print_string(PRINT_FP, NULL, "%s", _SL_);
300
301 print_uint(PRINT_ANY, "peer_session_id",
302 " Peer session %u,", p->peer_session_id);
303 print_uint(PRINT_ANY, "peer_tunnel_id",
304 " tunnel %u", p->peer_tunnel_id);
305 print_string(PRINT_FP, NULL, "%s", _SL_);
306
307 if (p->ifname != NULL) {
308 print_color_string(PRINT_ANY, COLOR_IFNAME,
309 "interface", " interface name: %s" , p->ifname);
310 print_string(PRINT_FP, NULL, "%s", _SL_);
311 }
312
313 print_uint(PRINT_ANY, "offset", " offset %u,", p->offset);
314 print_uint(PRINT_ANY, "peer_offset", " peer offset %u\n", p->peer_offset);
281db53f 315
38cd311a 316 if (p->cookie_len > 0)
98453b65
SH
317 print_cookie("cookie", "cookie",
318 p->cookie, p->cookie_len);
38cd311a 319 if (p->peer_cookie_len > 0)
98453b65
SH
320 print_cookie("peer_cookie", "peer cookie",
321 p->peer_cookie, p->peer_cookie_len);
38cd311a 322
3649d018 323 if (p->reorder_timeout != 0)
98453b65
SH
324 print_uint(PRINT_ANY, "reorder_timeout",
325 " reorder timeout: %u", p->reorder_timeout);
326
327
8a11421a 328 if (p->send_seq || p->recv_seq) {
98453b65
SH
329 print_string(PRINT_FP, NULL, "%s sequence numbering:", _SL_);
330
281db53f 331 if (p->send_seq)
98453b65 332 print_null(PRINT_ANY, "send_seq", " send", NULL);
281db53f 333 if (p->recv_seq)
98453b65
SH
334 print_null(PRINT_ANY, "recv_seq", " recv", NULL);
335
8a11421a 336 }
98453b65
SH
337 print_string(PRINT_FP, NULL, "\n", NULL);
338 close_json_object();
38cd311a
SH
339}
340
341static int get_response(struct nlmsghdr *n, void *arg)
342{
343 struct genlmsghdr *ghdr;
344 struct l2tp_data *data = arg;
345 struct l2tp_parm *p = &data->config;
346 struct rtattr *attrs[L2TP_ATTR_MAX + 1];
62f9f94a 347 struct rtattr *nla_stats, *rta;
38cd311a
SH
348 int len;
349
350 /* Validate message and parse attributes */
351 if (n->nlmsg_type == NLMSG_ERROR)
352 return -EBADMSG;
353
354 ghdr = NLMSG_DATA(n);
355 len = n->nlmsg_len - NLMSG_LENGTH(sizeof(*ghdr));
356 if (len < 0)
357 return -1;
358
359 parse_rtattr(attrs, L2TP_ATTR_MAX, (void *)ghdr + GENL_HDRLEN, len);
360
361 if (attrs[L2TP_ATTR_PW_TYPE])
362 p->pw_type = rta_getattr_u16(attrs[L2TP_ATTR_PW_TYPE]);
363 if (attrs[L2TP_ATTR_ENCAP_TYPE])
364 p->encap = rta_getattr_u16(attrs[L2TP_ATTR_ENCAP_TYPE]);
365 if (attrs[L2TP_ATTR_OFFSET])
366 p->offset = rta_getattr_u16(attrs[L2TP_ATTR_OFFSET]);
367 if (attrs[L2TP_ATTR_DATA_SEQ])
368 p->data_seq = rta_getattr_u16(attrs[L2TP_ATTR_DATA_SEQ]);
369 if (attrs[L2TP_ATTR_CONN_ID])
370 p->tunnel_id = rta_getattr_u32(attrs[L2TP_ATTR_CONN_ID]);
371 if (attrs[L2TP_ATTR_PEER_CONN_ID])
372 p->peer_tunnel_id = rta_getattr_u32(attrs[L2TP_ATTR_PEER_CONN_ID]);
373 if (attrs[L2TP_ATTR_SESSION_ID])
374 p->session_id = rta_getattr_u32(attrs[L2TP_ATTR_SESSION_ID]);
375 if (attrs[L2TP_ATTR_PEER_SESSION_ID])
376 p->peer_session_id = rta_getattr_u32(attrs[L2TP_ATTR_PEER_SESSION_ID]);
dd10baa5
JC
377 if (attrs[L2TP_ATTR_L2SPEC_TYPE])
378 p->l2spec_type = rta_getattr_u8(attrs[L2TP_ATTR_L2SPEC_TYPE]);
379 if (attrs[L2TP_ATTR_L2SPEC_LEN])
380 p->l2spec_len = rta_getattr_u8(attrs[L2TP_ATTR_L2SPEC_LEN]);
38cd311a 381
c73fad78
AST
382 if (attrs[L2TP_ATTR_UDP_CSUM])
383 p->udp_csum = !!rta_getattr_u8(attrs[L2TP_ATTR_UDP_CSUM]);
384
35cc6ded
AST
385 p->udp6_csum_tx = !attrs[L2TP_ATTR_UDP_ZERO_CSUM6_TX];
386 p->udp6_csum_rx = !attrs[L2TP_ATTR_UDP_ZERO_CSUM6_RX];
387
38cd311a
SH
388 if (attrs[L2TP_ATTR_COOKIE])
389 memcpy(p->cookie, RTA_DATA(attrs[L2TP_ATTR_COOKIE]),
390 p->cookie_len = RTA_PAYLOAD(attrs[L2TP_ATTR_COOKIE]));
391
392 if (attrs[L2TP_ATTR_PEER_COOKIE])
393 memcpy(p->peer_cookie, RTA_DATA(attrs[L2TP_ATTR_PEER_COOKIE]),
394 p->peer_cookie_len = RTA_PAYLOAD(attrs[L2TP_ATTR_PEER_COOKIE]));
395
4d51b333
AST
396 if (attrs[L2TP_ATTR_RECV_SEQ])
397 p->recv_seq = !!rta_getattr_u8(attrs[L2TP_ATTR_RECV_SEQ]);
398 if (attrs[L2TP_ATTR_SEND_SEQ])
399 p->send_seq = !!rta_getattr_u8(attrs[L2TP_ATTR_SEND_SEQ]);
38cd311a
SH
400
401 if (attrs[L2TP_ATTR_RECV_TIMEOUT])
402 p->reorder_timeout = rta_getattr_u64(attrs[L2TP_ATTR_RECV_TIMEOUT]);
62f9f94a
SP
403
404 rta = attrs[L2TP_ATTR_IP_SADDR];
405 p->local_ip.family = AF_INET;
406 if (!rta) {
407 rta = attrs[L2TP_ATTR_IP6_SADDR];
6618e334 408 p->local_ip.family = AF_INET6;
6618e334 409 }
62f9f94a
SP
410 if (rta && get_addr_rta(&p->local_ip, rta, p->local_ip.family))
411 return -1;
412
413 rta = attrs[L2TP_ATTR_IP_DADDR];
414 p->peer_ip.family = AF_INET;
415 if (!rta) {
416 rta = attrs[L2TP_ATTR_IP6_DADDR];
6618e334 417 p->peer_ip.family = AF_INET6;
6618e334 418 }
62f9f94a
SP
419 if (rta && get_addr_rta(&p->peer_ip, rta, p->peer_ip.family))
420 return -1;
421
38cd311a
SH
422 if (attrs[L2TP_ATTR_UDP_SPORT])
423 p->local_udp_port = rta_getattr_u16(attrs[L2TP_ATTR_UDP_SPORT]);
424 if (attrs[L2TP_ATTR_UDP_DPORT])
425 p->peer_udp_port = rta_getattr_u16(attrs[L2TP_ATTR_UDP_DPORT]);
426 if (attrs[L2TP_ATTR_MTU])
427 p->mtu = rta_getattr_u16(attrs[L2TP_ATTR_MTU]);
428 if (attrs[L2TP_ATTR_IFNAME])
429 p->ifname = rta_getattr_str(attrs[L2TP_ATTR_IFNAME]);
430
431 nla_stats = attrs[L2TP_ATTR_STATS];
432 if (nla_stats) {
433 struct rtattr *tb[L2TP_ATTR_STATS_MAX + 1];
434
435 parse_rtattr_nested(tb, L2TP_ATTR_STATS_MAX, nla_stats);
436
437 if (tb[L2TP_ATTR_TX_PACKETS])
438 data->stats.data_tx_packets = rta_getattr_u64(tb[L2TP_ATTR_TX_PACKETS]);
439 if (tb[L2TP_ATTR_TX_BYTES])
440 data->stats.data_tx_bytes = rta_getattr_u64(tb[L2TP_ATTR_TX_BYTES]);
441 if (tb[L2TP_ATTR_TX_ERRORS])
442 data->stats.data_tx_errors = rta_getattr_u64(tb[L2TP_ATTR_TX_ERRORS]);
443 if (tb[L2TP_ATTR_RX_PACKETS])
444 data->stats.data_rx_packets = rta_getattr_u64(tb[L2TP_ATTR_RX_PACKETS]);
445 if (tb[L2TP_ATTR_RX_BYTES])
446 data->stats.data_rx_bytes = rta_getattr_u64(tb[L2TP_ATTR_RX_BYTES]);
447 if (tb[L2TP_ATTR_RX_ERRORS])
448 data->stats.data_rx_errors = rta_getattr_u64(tb[L2TP_ATTR_RX_ERRORS]);
449 if (tb[L2TP_ATTR_RX_SEQ_DISCARDS])
450 data->stats.data_rx_oos_discards = rta_getattr_u64(tb[L2TP_ATTR_RX_SEQ_DISCARDS]);
451 if (tb[L2TP_ATTR_RX_OOS_PACKETS])
452 data->stats.data_rx_oos_packets = rta_getattr_u64(tb[L2TP_ATTR_RX_OOS_PACKETS]);
453 }
454
455 return 0;
456}
457
281db53f
SH
458static int session_nlmsg(const struct sockaddr_nl *who,
459 struct nlmsghdr *n, void *arg)
38cd311a
SH
460{
461 int ret = get_response(n, arg);
462
463 if (ret == 0)
464 print_session(arg);
465
466 return ret;
467}
468
469static int get_session(struct l2tp_data *p)
470{
328d482c
JA
471 GENL_REQUEST(req, 128, genl_family, 0, L2TP_GENL_VERSION,
472 L2TP_CMD_SESSION_GET,
473 NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST);
38cd311a 474
328d482c 475 req.n.nlmsg_seq = genl_rth.dump = ++genl_rth.seq;
38cd311a
SH
476
477 if (p->config.tunnel_id && p->config.session_id) {
478 addattr32(&req.n, 128, L2TP_ATTR_CONN_ID, p->config.tunnel_id);
281db53f
SH
479 addattr32(&req.n, 128, L2TP_ATTR_SESSION_ID,
480 p->config.session_id);
38cd311a
SH
481 }
482
483 if (rtnl_send(&genl_rth, &req, req.n.nlmsg_len) < 0)
484 return -2;
485
98453b65 486 new_json_obj(json);
38cd311a
SH
487 if (rtnl_dump_filter(&genl_rth, session_nlmsg, p) < 0) {
488 fprintf(stderr, "Dump terminated\n");
489 exit(1);
490 }
98453b65
SH
491 delete_json_obj();
492 fflush(stdout);
38cd311a
SH
493
494 return 0;
495}
496
281db53f
SH
497static int tunnel_nlmsg(const struct sockaddr_nl *who,
498 struct nlmsghdr *n, void *arg)
38cd311a
SH
499{
500 int ret = get_response(n, arg);
501
502 if (ret == 0)
503 print_tunnel(arg);
504
505 return ret;
506}
507
508static int get_tunnel(struct l2tp_data *p)
509{
328d482c
JA
510 GENL_REQUEST(req, 1024, genl_family, 0, L2TP_GENL_VERSION,
511 L2TP_CMD_TUNNEL_GET,
512 NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST);
38cd311a 513
328d482c 514 req.n.nlmsg_seq = genl_rth.dump = ++genl_rth.seq;
38cd311a
SH
515
516 if (p->config.tunnel_id)
517 addattr32(&req.n, 1024, L2TP_ATTR_CONN_ID, p->config.tunnel_id);
518
519 if (rtnl_send(&genl_rth, &req, req.n.nlmsg_len) < 0)
520 return -2;
521
98453b65 522 new_json_obj(json);
38cd311a
SH
523 if (rtnl_dump_filter(&genl_rth, tunnel_nlmsg, p) < 0) {
524 fprintf(stderr, "Dump terminated\n");
525 exit(1);
526 }
98453b65
SH
527 delete_json_obj();
528 fflush(stdout);
38cd311a
SH
529
530 return 0;
531}
532
533/*****************************************************************************
534 * Command parser
535 *****************************************************************************/
536
38cd311a
SH
537static void usage(void) __attribute__((noreturn));
538
539static void usage(void)
540{
281db53f
SH
541 fprintf(stderr, "Usage: ip l2tp add tunnel\n"
542 " remote ADDR local ADDR\n"
543 " tunnel_id ID peer_tunnel_id ID\n"
544 " [ encap { ip | udp } ]\n"
545 " [ udp_sport PORT ] [ udp_dport PORT ]\n"
546 " [ udp_csum { on | off } ]\n"
547 " [ udp6_csum_tx { on | off } ]\n"
548 " [ udp6_csum_rx { on | off } ]\n"
549 "Usage: ip l2tp add session [ name NAME ]\n"
550 " tunnel_id ID\n"
551 " session_id ID peer_session_id ID\n"
552 " [ cookie HEXSTR ] [ peer_cookie HEXSTR ]\n"
553 " [ offset OFFSET ] [ peer_offset OFFSET ]\n"
554 " [ seq { none | send | recv | both } ]\n"
555 " [ l2spec_type L2SPEC ]\n"
556 " ip l2tp del tunnel tunnel_id ID\n"
557 " ip l2tp del session tunnel_id ID session_id ID\n"
558 " ip l2tp show tunnel [ tunnel_id ID ]\n"
559 " ip l2tp show session [ tunnel_id ID ] [ session_id ID ]\n"
560 "\n"
561 "Where: NAME := STRING\n"
562 " ADDR := { IP_ADDRESS | any }\n"
563 " PORT := { 0..65535 }\n"
564 " ID := { 1..4294967295 }\n"
565 " HEXSTR := { 8 or 16 hex digits (4 / 8 bytes) }\n"
566 " L2SPEC := { none | default }\n");
567
38cd311a
SH
568 exit(-1);
569}
570
571static int parse_args(int argc, char **argv, int cmd, struct l2tp_parm *p)
572{
573 memset(p, 0, sizeof(*p));
574
575 if (argc == 0)
576 usage();
577
dd10baa5
JC
578 /* Defaults */
579 p->l2spec_type = L2TP_L2SPECTYPE_DEFAULT;
580 p->l2spec_len = 4;
9bf9d05b
SW
581 p->udp6_csum_rx = 1;
582 p->udp6_csum_tx = 1;
dd10baa5 583
38cd311a
SH
584 while (argc > 0) {
585 if (strcmp(*argv, "encap") == 0) {
586 NEXT_ARG();
587 if (strcmp(*argv, "ip") == 0) {
588 p->encap = L2TP_ENCAPTYPE_IP;
589 } else if (strcmp(*argv, "udp") == 0) {
590 p->encap = L2TP_ENCAPTYPE_UDP;
591 } else {
14645ec2 592 fprintf(stderr, "Unknown tunnel encapsulation \"%s\"\n", *argv);
38cd311a
SH
593 exit(-1);
594 }
ae5555d3
JV
595 } else if (strcmp(*argv, "name") == 0) {
596 NEXT_ARG();
625df645
PS
597 if (check_ifname(*argv))
598 invarg("\"name\" not a valid ifname", *argv);
ae5555d3 599 p->ifname = *argv;
38cd311a
SH
600 } else if (strcmp(*argv, "remote") == 0) {
601 NEXT_ARG();
6618e334
CE
602 if (get_addr(&p->peer_ip, *argv, AF_UNSPEC))
603 invarg("invalid remote address\n", *argv);
38cd311a
SH
604 } else if (strcmp(*argv, "local") == 0) {
605 NEXT_ARG();
6618e334
CE
606 if (get_addr(&p->local_ip, *argv, AF_UNSPEC))
607 invarg("invalid local address\n", *argv);
38cd311a
SH
608 } else if ((strcmp(*argv, "tunnel_id") == 0) ||
609 (strcmp(*argv, "tid") == 0)) {
610 __u32 uval;
56f5daac 611
38cd311a
SH
612 NEXT_ARG();
613 if (get_u32(&uval, *argv, 0))
614 invarg("invalid ID\n", *argv);
615 p->tunnel_id = uval;
616 } else if ((strcmp(*argv, "peer_tunnel_id") == 0) ||
617 (strcmp(*argv, "ptid") == 0)) {
618 __u32 uval;
56f5daac 619
38cd311a
SH
620 NEXT_ARG();
621 if (get_u32(&uval, *argv, 0))
622 invarg("invalid ID\n", *argv);
623 p->peer_tunnel_id = uval;
624 } else if ((strcmp(*argv, "session_id") == 0) ||
625 (strcmp(*argv, "sid") == 0)) {
626 __u32 uval;
56f5daac 627
38cd311a
SH
628 NEXT_ARG();
629 if (get_u32(&uval, *argv, 0))
630 invarg("invalid ID\n", *argv);
631 p->session_id = uval;
632 } else if ((strcmp(*argv, "peer_session_id") == 0) ||
633 (strcmp(*argv, "psid") == 0)) {
634 __u32 uval;
56f5daac 635
38cd311a
SH
636 NEXT_ARG();
637 if (get_u32(&uval, *argv, 0))
638 invarg("invalid ID\n", *argv);
639 p->peer_session_id = uval;
640 } else if (strcmp(*argv, "udp_sport") == 0) {
641 __u16 uval;
56f5daac 642
38cd311a
SH
643 NEXT_ARG();
644 if (get_u16(&uval, *argv, 0))
645 invarg("invalid port\n", *argv);
646 p->local_udp_port = uval;
647 } else if (strcmp(*argv, "udp_dport") == 0) {
648 __u16 uval;
56f5daac 649
38cd311a
SH
650 NEXT_ARG();
651 if (get_u16(&uval, *argv, 0))
652 invarg("invalid port\n", *argv);
653 p->peer_udp_port = uval;
9bf9d05b
SW
654 } else if (strcmp(*argv, "udp_csum") == 0) {
655 NEXT_ARG();
656 if (strcmp(*argv, "on") == 0)
657 p->udp_csum = 1;
658 else if (strcmp(*argv, "off") == 0)
659 p->udp_csum = 0;
660 else
661 invarg("invalid option for udp_csum\n", *argv);
662 } else if (strcmp(*argv, "udp6_csum_rx") == 0) {
663 NEXT_ARG();
664 if (strcmp(*argv, "on") == 0)
665 p->udp6_csum_rx = 1;
666 else if (strcmp(*argv, "off") == 0)
667 p->udp6_csum_rx = 0;
668 else
669 invarg("invalid option for udp6_csum_rx\n"
670 , *argv);
671 } else if (strcmp(*argv, "udp6_csum_tx") == 0) {
672 NEXT_ARG();
673 if (strcmp(*argv, "on") == 0)
674 p->udp6_csum_tx = 1;
675 else if (strcmp(*argv, "off") == 0)
676 p->udp6_csum_tx = 0;
677 else
678 invarg("invalid option for udp6_csum_tx\n"
679 , *argv);
38cd311a
SH
680 } else if (strcmp(*argv, "offset") == 0) {
681 __u8 uval;
56f5daac 682
38cd311a
SH
683 NEXT_ARG();
684 if (get_u8(&uval, *argv, 0))
685 invarg("invalid offset\n", *argv);
686 p->offset = uval;
687 } else if (strcmp(*argv, "peer_offset") == 0) {
688 __u8 uval;
56f5daac 689
38cd311a
SH
690 NEXT_ARG();
691 if (get_u8(&uval, *argv, 0))
692 invarg("invalid offset\n", *argv);
693 p->peer_offset = uval;
694 } else if (strcmp(*argv, "cookie") == 0) {
695 int slen;
56f5daac 696
38cd311a
SH
697 NEXT_ARG();
698 slen = strlen(*argv);
699 if ((slen != 8) && (slen != 16))
700 invarg("cookie must be either 8 or 16 hex digits\n", *argv);
701
702 p->cookie_len = slen / 2;
703 if (hex2mem(*argv, p->cookie, p->cookie_len) < 0)
704 invarg("cookie must be a hex string\n", *argv);
705 } else if (strcmp(*argv, "peer_cookie") == 0) {
706 int slen;
56f5daac 707
38cd311a
SH
708 NEXT_ARG();
709 slen = strlen(*argv);
710 if ((slen != 8) && (slen != 16))
711 invarg("cookie must be either 8 or 16 hex digits\n", *argv);
712
713 p->peer_cookie_len = slen / 2;
714 if (hex2mem(*argv, p->peer_cookie, p->peer_cookie_len) < 0)
715 invarg("cookie must be a hex string\n", *argv);
dd10baa5
JC
716 } else if (strcmp(*argv, "l2spec_type") == 0) {
717 NEXT_ARG();
718 if (strcasecmp(*argv, "default") == 0) {
719 p->l2spec_type = L2TP_L2SPECTYPE_DEFAULT;
720 p->l2spec_len = 4;
721 } else if (strcasecmp(*argv, "none") == 0) {
722 p->l2spec_type = L2TP_L2SPECTYPE_NONE;
723 p->l2spec_len = 0;
724 } else {
281db53f
SH
725 fprintf(stderr,
726 "Unknown layer2specific header type \"%s\"\n",
727 *argv);
dd10baa5
JC
728 exit(-1);
729 }
8a11421a
AST
730 } else if (strcmp(*argv, "seq") == 0) {
731 NEXT_ARG();
732 if (strcasecmp(*argv, "both") == 0) {
733 p->recv_seq = 1;
734 p->send_seq = 1;
735 } else if (strcasecmp(*argv, "recv") == 0) {
736 p->recv_seq = 1;
737 } else if (strcasecmp(*argv, "send") == 0) {
738 p->send_seq = 1;
739 } else if (strcasecmp(*argv, "none") == 0) {
740 p->recv_seq = 0;
741 p->send_seq = 0;
742 } else {
281db53f
SH
743 fprintf(stderr,
744 "Unknown seq value \"%s\"\n", *argv);
8a11421a
AST
745 exit(-1);
746 }
38cd311a
SH
747 } else if (strcmp(*argv, "tunnel") == 0) {
748 p->tunnel = 1;
749 } else if (strcmp(*argv, "session") == 0) {
750 p->session = 1;
751 } else if (matches(*argv, "help") == 0) {
752 usage();
753 } else {
754 fprintf(stderr, "Unknown command: %s\n", *argv);
755 usage();
756 }
757
758 argc--; argv++;
759 }
760
761 return 0;
762}
763
764
765static int do_add(int argc, char **argv)
766{
767 struct l2tp_parm p;
768 int ret = 0;
769
770 if (parse_args(argc, argv, L2TP_ADD, &p) < 0)
771 return -1;
772
773 if (!p.tunnel && !p.session)
774 missarg("tunnel or session");
775
776 if (p.tunnel_id == 0)
777 missarg("tunnel_id");
778
779 /* session_id and peer_session_id must be provided for sessions */
780 if ((p.session) && (p.peer_session_id == 0))
781 missarg("peer_session_id");
782 if ((p.session) && (p.session_id == 0))
783 missarg("session_id");
784
785 /* peer_tunnel_id is needed for tunnels */
786 if ((p.tunnel) && (p.peer_tunnel_id == 0))
787 missarg("peer_tunnel_id");
788
789 if (p.tunnel) {
6618e334 790 if (p.local_ip.family == AF_UNSPEC)
38cd311a
SH
791 missarg("local");
792
6618e334 793 if (p.peer_ip.family == AF_UNSPEC)
38cd311a
SH
794 missarg("remote");
795
796 if (p.encap == L2TP_ENCAPTYPE_UDP) {
797 if (p.local_udp_port == 0)
798 missarg("udp_sport");
799 if (p.peer_udp_port == 0)
800 missarg("udp_dport");
801 }
802
803 ret = create_tunnel(&p);
804 }
805
806 if (p.session) {
807 /* Only ethernet pseudowires supported */
808 p.pw_type = L2TP_PWTYPE_ETH;
809
810 ret = create_session(&p);
811 }
812
813 return ret;
814}
815
816static int do_del(int argc, char **argv)
817{
818 struct l2tp_parm p;
819
820 if (parse_args(argc, argv, L2TP_DEL, &p) < 0)
821 return -1;
822
823 if (!p.tunnel && !p.session)
824 missarg("tunnel or session");
825
826 if ((p.tunnel) && (p.tunnel_id == 0))
827 missarg("tunnel_id");
828 if ((p.session) && (p.session_id == 0))
829 missarg("session_id");
830
831 if (p.session_id)
832 return delete_session(&p);
833 else
834 return delete_tunnel(&p);
835
836 return -1;
837}
838
839static int do_show(int argc, char **argv)
840{
841 struct l2tp_data data;
842 struct l2tp_parm *p = &data.config;
843
844 if (parse_args(argc, argv, L2TP_GET, p) < 0)
845 return -1;
846
847 if (!p->tunnel && !p->session)
848 missarg("tunnel or session");
849
850 if (p->session)
851 get_session(&data);
852 else
853 get_tunnel(&data);
854
855 return 0;
856}
857
38cd311a
SH
858int do_ipl2tp(int argc, char **argv)
859{
e8977766
PS
860 if (argc < 1 || !matches(*argv, "help"))
861 usage();
862
2b68cb77
SD
863 if (genl_init_handle(&genl_rth, L2TP_GENL_NAME, &genl_family))
864 exit(1);
38cd311a 865
38cd311a
SH
866 if (matches(*argv, "add") == 0)
867 return do_add(argc-1, argv+1);
6e30461e 868 if (matches(*argv, "delete") == 0)
38cd311a
SH
869 return do_del(argc-1, argv+1);
870 if (matches(*argv, "show") == 0 ||
871 matches(*argv, "lst") == 0 ||
872 matches(*argv, "list") == 0)
873 return do_show(argc-1, argv+1);
38cd311a 874
281db53f
SH
875 fprintf(stderr,
876 "Command \"%s\" is unknown, try \"ip l2tp help\".\n", *argv);
38cd311a
SH
877 exit(-1);
878}