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