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