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