]> git.proxmox.com Git - mirror_iproute2.git/blob - ip/ipl2tp.c
libnetlink: add size argument to rtnl_talk
[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 }
240 }
241
242 static int get_response(struct nlmsghdr *n, void *arg)
243 {
244 struct genlmsghdr *ghdr;
245 struct l2tp_data *data = arg;
246 struct l2tp_parm *p = &data->config;
247 struct rtattr *attrs[L2TP_ATTR_MAX + 1];
248 struct rtattr *nla_stats;
249 int len;
250
251 /* Validate message and parse attributes */
252 if (n->nlmsg_type == NLMSG_ERROR)
253 return -EBADMSG;
254
255 ghdr = NLMSG_DATA(n);
256 len = n->nlmsg_len - NLMSG_LENGTH(sizeof(*ghdr));
257 if (len < 0)
258 return -1;
259
260 parse_rtattr(attrs, L2TP_ATTR_MAX, (void *)ghdr + GENL_HDRLEN, len);
261
262 if (attrs[L2TP_ATTR_PW_TYPE])
263 p->pw_type = rta_getattr_u16(attrs[L2TP_ATTR_PW_TYPE]);
264 if (attrs[L2TP_ATTR_ENCAP_TYPE])
265 p->encap = rta_getattr_u16(attrs[L2TP_ATTR_ENCAP_TYPE]);
266 if (attrs[L2TP_ATTR_OFFSET])
267 p->offset = rta_getattr_u16(attrs[L2TP_ATTR_OFFSET]);
268 if (attrs[L2TP_ATTR_DATA_SEQ])
269 p->data_seq = rta_getattr_u16(attrs[L2TP_ATTR_DATA_SEQ]);
270 if (attrs[L2TP_ATTR_CONN_ID])
271 p->tunnel_id = rta_getattr_u32(attrs[L2TP_ATTR_CONN_ID]);
272 if (attrs[L2TP_ATTR_PEER_CONN_ID])
273 p->peer_tunnel_id = rta_getattr_u32(attrs[L2TP_ATTR_PEER_CONN_ID]);
274 if (attrs[L2TP_ATTR_SESSION_ID])
275 p->session_id = rta_getattr_u32(attrs[L2TP_ATTR_SESSION_ID]);
276 if (attrs[L2TP_ATTR_PEER_SESSION_ID])
277 p->peer_session_id = rta_getattr_u32(attrs[L2TP_ATTR_PEER_SESSION_ID]);
278 if (attrs[L2TP_ATTR_L2SPEC_TYPE])
279 p->l2spec_type = rta_getattr_u8(attrs[L2TP_ATTR_L2SPEC_TYPE]);
280 if (attrs[L2TP_ATTR_L2SPEC_LEN])
281 p->l2spec_len = rta_getattr_u8(attrs[L2TP_ATTR_L2SPEC_LEN]);
282
283 p->udp_csum = !!attrs[L2TP_ATTR_UDP_CSUM];
284 if (attrs[L2TP_ATTR_COOKIE])
285 memcpy(p->cookie, RTA_DATA(attrs[L2TP_ATTR_COOKIE]),
286 p->cookie_len = RTA_PAYLOAD(attrs[L2TP_ATTR_COOKIE]));
287
288 if (attrs[L2TP_ATTR_PEER_COOKIE])
289 memcpy(p->peer_cookie, RTA_DATA(attrs[L2TP_ATTR_PEER_COOKIE]),
290 p->peer_cookie_len = RTA_PAYLOAD(attrs[L2TP_ATTR_PEER_COOKIE]));
291
292 p->recv_seq = !!attrs[L2TP_ATTR_RECV_SEQ];
293 p->send_seq = !!attrs[L2TP_ATTR_SEND_SEQ];
294
295 if (attrs[L2TP_ATTR_RECV_TIMEOUT])
296 p->reorder_timeout = rta_getattr_u64(attrs[L2TP_ATTR_RECV_TIMEOUT]);
297 if (attrs[L2TP_ATTR_IP_SADDR]) {
298 p->local_ip.family = AF_INET;
299 p->local_ip.data[0] = rta_getattr_u32(attrs[L2TP_ATTR_IP_SADDR]);
300 p->local_ip.bytelen = 4;
301 p->local_ip.bitlen = -1;
302 }
303 if (attrs[L2TP_ATTR_IP_DADDR]) {
304 p->peer_ip.family = AF_INET;
305 p->peer_ip.data[0] = rta_getattr_u32(attrs[L2TP_ATTR_IP_DADDR]);
306 p->peer_ip.bytelen = 4;
307 p->peer_ip.bitlen = -1;
308 }
309 if (attrs[L2TP_ATTR_IP6_SADDR]) {
310 p->local_ip.family = AF_INET6;
311 memcpy(&p->local_ip.data, RTA_DATA(attrs[L2TP_ATTR_IP6_SADDR]),
312 p->local_ip.bytelen = 16);
313 p->local_ip.bitlen = -1;
314 }
315 if (attrs[L2TP_ATTR_IP6_DADDR]) {
316 p->peer_ip.family = AF_INET6;
317 memcpy(&p->peer_ip.data, RTA_DATA(attrs[L2TP_ATTR_IP6_DADDR]),
318 p->peer_ip.bytelen = 16);
319 p->peer_ip.bitlen = -1;
320 }
321 if (attrs[L2TP_ATTR_UDP_SPORT])
322 p->local_udp_port = rta_getattr_u16(attrs[L2TP_ATTR_UDP_SPORT]);
323 if (attrs[L2TP_ATTR_UDP_DPORT])
324 p->peer_udp_port = rta_getattr_u16(attrs[L2TP_ATTR_UDP_DPORT]);
325 if (attrs[L2TP_ATTR_MTU])
326 p->mtu = rta_getattr_u16(attrs[L2TP_ATTR_MTU]);
327 if (attrs[L2TP_ATTR_IFNAME])
328 p->ifname = rta_getattr_str(attrs[L2TP_ATTR_IFNAME]);
329
330 nla_stats = attrs[L2TP_ATTR_STATS];
331 if (nla_stats) {
332 struct rtattr *tb[L2TP_ATTR_STATS_MAX + 1];
333
334 parse_rtattr_nested(tb, L2TP_ATTR_STATS_MAX, nla_stats);
335
336 if (tb[L2TP_ATTR_TX_PACKETS])
337 data->stats.data_tx_packets = rta_getattr_u64(tb[L2TP_ATTR_TX_PACKETS]);
338 if (tb[L2TP_ATTR_TX_BYTES])
339 data->stats.data_tx_bytes = rta_getattr_u64(tb[L2TP_ATTR_TX_BYTES]);
340 if (tb[L2TP_ATTR_TX_ERRORS])
341 data->stats.data_tx_errors = rta_getattr_u64(tb[L2TP_ATTR_TX_ERRORS]);
342 if (tb[L2TP_ATTR_RX_PACKETS])
343 data->stats.data_rx_packets = rta_getattr_u64(tb[L2TP_ATTR_RX_PACKETS]);
344 if (tb[L2TP_ATTR_RX_BYTES])
345 data->stats.data_rx_bytes = rta_getattr_u64(tb[L2TP_ATTR_RX_BYTES]);
346 if (tb[L2TP_ATTR_RX_ERRORS])
347 data->stats.data_rx_errors = rta_getattr_u64(tb[L2TP_ATTR_RX_ERRORS]);
348 if (tb[L2TP_ATTR_RX_SEQ_DISCARDS])
349 data->stats.data_rx_oos_discards = rta_getattr_u64(tb[L2TP_ATTR_RX_SEQ_DISCARDS]);
350 if (tb[L2TP_ATTR_RX_OOS_PACKETS])
351 data->stats.data_rx_oos_packets = rta_getattr_u64(tb[L2TP_ATTR_RX_OOS_PACKETS]);
352 }
353
354 return 0;
355 }
356
357 static int session_nlmsg(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
358 {
359 int ret = get_response(n, arg);
360
361 if (ret == 0)
362 print_session(arg);
363
364 return ret;
365 }
366
367 static int get_session(struct l2tp_data *p)
368 {
369 GENL_REQUEST(req, 128, genl_family, 0, L2TP_GENL_VERSION,
370 L2TP_CMD_SESSION_GET,
371 NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST);
372
373 req.n.nlmsg_seq = genl_rth.dump = ++genl_rth.seq;
374
375 if (p->config.tunnel_id && p->config.session_id) {
376 addattr32(&req.n, 128, L2TP_ATTR_CONN_ID, p->config.tunnel_id);
377 addattr32(&req.n, 128, L2TP_ATTR_SESSION_ID, p->config.session_id);
378 }
379
380 if (rtnl_send(&genl_rth, &req, req.n.nlmsg_len) < 0)
381 return -2;
382
383 if (rtnl_dump_filter(&genl_rth, session_nlmsg, p) < 0) {
384 fprintf(stderr, "Dump terminated\n");
385 exit(1);
386 }
387
388 return 0;
389 }
390
391 static int tunnel_nlmsg(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
392 {
393 int ret = get_response(n, arg);
394
395 if (ret == 0)
396 print_tunnel(arg);
397
398 return ret;
399 }
400
401 static int get_tunnel(struct l2tp_data *p)
402 {
403 GENL_REQUEST(req, 1024, genl_family, 0, L2TP_GENL_VERSION,
404 L2TP_CMD_TUNNEL_GET,
405 NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST);
406
407 req.n.nlmsg_seq = genl_rth.dump = ++genl_rth.seq;
408
409 if (p->config.tunnel_id)
410 addattr32(&req.n, 1024, L2TP_ATTR_CONN_ID, p->config.tunnel_id);
411
412 if (rtnl_send(&genl_rth, &req, req.n.nlmsg_len) < 0)
413 return -2;
414
415 if (rtnl_dump_filter(&genl_rth, tunnel_nlmsg, p) < 0) {
416 fprintf(stderr, "Dump terminated\n");
417 exit(1);
418 }
419
420 return 0;
421 }
422
423 /*****************************************************************************
424 * Command parser
425 *****************************************************************************/
426
427 static int hex(char ch)
428 {
429 if ((ch >= 'a') && (ch <= 'f'))
430 return ch - 'a' + 10;
431 if ((ch >= '0') && (ch <= '9'))
432 return ch - '0';
433 if ((ch >= 'A') && (ch <= 'F'))
434 return ch - 'A' + 10;
435 return -1;
436 }
437
438 static int hex2mem(const char *buf, uint8_t *mem, int count)
439 {
440 int i, j;
441 int c;
442
443 for (i = 0, j = 0; i < count; i++, j += 2) {
444 c = hex(buf[j]);
445 if (c < 0)
446 goto err;
447
448 mem[i] = c << 4;
449
450 c = hex(buf[j + 1]);
451 if (c < 0)
452 goto err;
453
454 mem[i] |= c;
455 }
456
457 return 0;
458
459 err:
460 return -1;
461 }
462
463 static void usage(void) __attribute__((noreturn));
464
465 static void usage(void)
466 {
467 fprintf(stderr, "Usage: ip l2tp add tunnel\n");
468 fprintf(stderr, " remote ADDR local ADDR\n");
469 fprintf(stderr, " tunnel_id ID peer_tunnel_id ID\n");
470 fprintf(stderr, " [ encap { ip | udp } ]\n");
471 fprintf(stderr, " [ udp_sport PORT ] [ udp_dport PORT ]\n");
472 fprintf(stderr, "Usage: ip l2tp add session [ name NAME ]\n");
473 fprintf(stderr, " tunnel_id ID\n");
474 fprintf(stderr, " session_id ID peer_session_id ID\n");
475 fprintf(stderr, " [ cookie HEXSTR ] [ peer_cookie HEXSTR ]\n");
476 fprintf(stderr, " [ offset OFFSET ] [ peer_offset OFFSET ]\n");
477 fprintf(stderr, " [ l2spec_type L2SPEC ]\n");
478 fprintf(stderr, " ip l2tp del tunnel tunnel_id ID\n");
479 fprintf(stderr, " ip l2tp del session tunnel_id ID session_id ID\n");
480 fprintf(stderr, " ip l2tp show tunnel [ tunnel_id ID ]\n");
481 fprintf(stderr, " ip l2tp show session [ tunnel_id ID ] [ session_id ID ]\n");
482 fprintf(stderr, "\n");
483 fprintf(stderr, "Where: NAME := STRING\n");
484 fprintf(stderr, " ADDR := { IP_ADDRESS | any }\n");
485 fprintf(stderr, " PORT := { 0..65535 }\n");
486 fprintf(stderr, " ID := { 1..4294967295 }\n");
487 fprintf(stderr, " HEXSTR := { 8 or 16 hex digits (4 / 8 bytes) }\n");
488 fprintf(stderr, " L2SPEC := { none | default }\n");
489 exit(-1);
490 }
491
492 static int parse_args(int argc, char **argv, int cmd, struct l2tp_parm *p)
493 {
494 memset(p, 0, sizeof(*p));
495
496 if (argc == 0)
497 usage();
498
499 /* Defaults */
500 p->l2spec_type = L2TP_L2SPECTYPE_DEFAULT;
501 p->l2spec_len = 4;
502
503 while (argc > 0) {
504 if (strcmp(*argv, "encap") == 0) {
505 NEXT_ARG();
506 if (strcmp(*argv, "ip") == 0) {
507 p->encap = L2TP_ENCAPTYPE_IP;
508 } else if (strcmp(*argv, "udp") == 0) {
509 p->encap = L2TP_ENCAPTYPE_UDP;
510 } else {
511 fprintf(stderr, "Unknown tunnel encapsulation \"%s\"\n", *argv);
512 exit(-1);
513 }
514 } else if (strcmp(*argv, "name") == 0) {
515 NEXT_ARG();
516 p->ifname = *argv;
517 } else if (strcmp(*argv, "remote") == 0) {
518 NEXT_ARG();
519 if (get_addr(&p->peer_ip, *argv, AF_UNSPEC))
520 invarg("invalid remote address\n", *argv);
521 } else if (strcmp(*argv, "local") == 0) {
522 NEXT_ARG();
523 if (get_addr(&p->local_ip, *argv, AF_UNSPEC))
524 invarg("invalid local address\n", *argv);
525 } else if ((strcmp(*argv, "tunnel_id") == 0) ||
526 (strcmp(*argv, "tid") == 0)) {
527 __u32 uval;
528 NEXT_ARG();
529 if (get_u32(&uval, *argv, 0))
530 invarg("invalid ID\n", *argv);
531 p->tunnel_id = uval;
532 } else if ((strcmp(*argv, "peer_tunnel_id") == 0) ||
533 (strcmp(*argv, "ptid") == 0)) {
534 __u32 uval;
535 NEXT_ARG();
536 if (get_u32(&uval, *argv, 0))
537 invarg("invalid ID\n", *argv);
538 p->peer_tunnel_id = uval;
539 } else if ((strcmp(*argv, "session_id") == 0) ||
540 (strcmp(*argv, "sid") == 0)) {
541 __u32 uval;
542 NEXT_ARG();
543 if (get_u32(&uval, *argv, 0))
544 invarg("invalid ID\n", *argv);
545 p->session_id = uval;
546 } else if ((strcmp(*argv, "peer_session_id") == 0) ||
547 (strcmp(*argv, "psid") == 0)) {
548 __u32 uval;
549 NEXT_ARG();
550 if (get_u32(&uval, *argv, 0))
551 invarg("invalid ID\n", *argv);
552 p->peer_session_id = uval;
553 } else if (strcmp(*argv, "udp_sport") == 0) {
554 __u16 uval;
555 NEXT_ARG();
556 if (get_u16(&uval, *argv, 0))
557 invarg("invalid port\n", *argv);
558 p->local_udp_port = uval;
559 } else if (strcmp(*argv, "udp_dport") == 0) {
560 __u16 uval;
561 NEXT_ARG();
562 if (get_u16(&uval, *argv, 0))
563 invarg("invalid port\n", *argv);
564 p->peer_udp_port = uval;
565 } else if (strcmp(*argv, "offset") == 0) {
566 __u8 uval;
567 NEXT_ARG();
568 if (get_u8(&uval, *argv, 0))
569 invarg("invalid offset\n", *argv);
570 p->offset = uval;
571 } else if (strcmp(*argv, "peer_offset") == 0) {
572 __u8 uval;
573 NEXT_ARG();
574 if (get_u8(&uval, *argv, 0))
575 invarg("invalid offset\n", *argv);
576 p->peer_offset = uval;
577 } else if (strcmp(*argv, "cookie") == 0) {
578 int slen;
579 NEXT_ARG();
580 slen = strlen(*argv);
581 if ((slen != 8) && (slen != 16))
582 invarg("cookie must be either 8 or 16 hex digits\n", *argv);
583
584 p->cookie_len = slen / 2;
585 if (hex2mem(*argv, p->cookie, p->cookie_len) < 0)
586 invarg("cookie must be a hex string\n", *argv);
587 } else if (strcmp(*argv, "peer_cookie") == 0) {
588 int slen;
589 NEXT_ARG();
590 slen = strlen(*argv);
591 if ((slen != 8) && (slen != 16))
592 invarg("cookie must be either 8 or 16 hex digits\n", *argv);
593
594 p->peer_cookie_len = slen / 2;
595 if (hex2mem(*argv, p->peer_cookie, p->peer_cookie_len) < 0)
596 invarg("cookie must be a hex string\n", *argv);
597 } else if (strcmp(*argv, "l2spec_type") == 0) {
598 NEXT_ARG();
599 if (strcasecmp(*argv, "default") == 0) {
600 p->l2spec_type = L2TP_L2SPECTYPE_DEFAULT;
601 p->l2spec_len = 4;
602 } else if (strcasecmp(*argv, "none") == 0) {
603 p->l2spec_type = L2TP_L2SPECTYPE_NONE;
604 p->l2spec_len = 0;
605 } else {
606 fprintf(stderr, "Unknown layer2specific header type \"%s\"\n", *argv);
607 exit(-1);
608 }
609 } else if (strcmp(*argv, "tunnel") == 0) {
610 p->tunnel = 1;
611 } else if (strcmp(*argv, "session") == 0) {
612 p->session = 1;
613 } else if (matches(*argv, "help") == 0) {
614 usage();
615 } else {
616 fprintf(stderr, "Unknown command: %s\n", *argv);
617 usage();
618 }
619
620 argc--; argv++;
621 }
622
623 return 0;
624 }
625
626
627 static int do_add(int argc, char **argv)
628 {
629 struct l2tp_parm p;
630 int ret = 0;
631
632 if (parse_args(argc, argv, L2TP_ADD, &p) < 0)
633 return -1;
634
635 if (!p.tunnel && !p.session)
636 missarg("tunnel or session");
637
638 if (p.tunnel_id == 0)
639 missarg("tunnel_id");
640
641 /* session_id and peer_session_id must be provided for sessions */
642 if ((p.session) && (p.peer_session_id == 0))
643 missarg("peer_session_id");
644 if ((p.session) && (p.session_id == 0))
645 missarg("session_id");
646
647 /* peer_tunnel_id is needed for tunnels */
648 if ((p.tunnel) && (p.peer_tunnel_id == 0))
649 missarg("peer_tunnel_id");
650
651 if (p.tunnel) {
652 if (p.local_ip.family == AF_UNSPEC)
653 missarg("local");
654
655 if (p.peer_ip.family == AF_UNSPEC)
656 missarg("remote");
657
658 if (p.encap == L2TP_ENCAPTYPE_UDP) {
659 if (p.local_udp_port == 0)
660 missarg("udp_sport");
661 if (p.peer_udp_port == 0)
662 missarg("udp_dport");
663 }
664
665 ret = create_tunnel(&p);
666 }
667
668 if (p.session) {
669 /* Only ethernet pseudowires supported */
670 p.pw_type = L2TP_PWTYPE_ETH;
671
672 ret = create_session(&p);
673 }
674
675 return ret;
676 }
677
678 static int do_del(int argc, char **argv)
679 {
680 struct l2tp_parm p;
681
682 if (parse_args(argc, argv, L2TP_DEL, &p) < 0)
683 return -1;
684
685 if (!p.tunnel && !p.session)
686 missarg("tunnel or session");
687
688 if ((p.tunnel) && (p.tunnel_id == 0))
689 missarg("tunnel_id");
690 if ((p.session) && (p.session_id == 0))
691 missarg("session_id");
692
693 if (p.session_id)
694 return delete_session(&p);
695 else
696 return delete_tunnel(&p);
697
698 return -1;
699 }
700
701 static int do_show(int argc, char **argv)
702 {
703 struct l2tp_data data;
704 struct l2tp_parm *p = &data.config;
705
706 if (parse_args(argc, argv, L2TP_GET, p) < 0)
707 return -1;
708
709 if (!p->tunnel && !p->session)
710 missarg("tunnel or session");
711
712 if (p->session)
713 get_session(&data);
714 else
715 get_tunnel(&data);
716
717 return 0;
718 }
719
720 int do_ipl2tp(int argc, char **argv)
721 {
722 if (genl_family < 0) {
723 if (rtnl_open_byproto(&genl_rth, 0, NETLINK_GENERIC) < 0) {
724 fprintf(stderr, "Cannot open generic netlink socket\n");
725 exit(1);
726 }
727
728 genl_family = genl_resolve_family(&genl_rth, L2TP_GENL_NAME);
729 if (genl_family < 0)
730 exit(1);
731 }
732
733 if (argc < 1)
734 usage();
735
736 if (matches(*argv, "add") == 0)
737 return do_add(argc-1, argv+1);
738 if (matches(*argv, "delete") == 0)
739 return do_del(argc-1, argv+1);
740 if (matches(*argv, "show") == 0 ||
741 matches(*argv, "lst") == 0 ||
742 matches(*argv, "list") == 0)
743 return do_show(argc-1, argv+1);
744 if (matches(*argv, "help") == 0)
745 usage();
746
747 fprintf(stderr, "Command \"%s\" is unknown, try \"ip l2tp help\".\n", *argv);
748 exit(-1);
749 }