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