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