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.
9 * Original Author: James Chapman <jchapman@katalix.com>
18 #include <sys/types.h>
19 #include <sys/socket.h>
20 #include <arpa/inet.h>
21 #include <sys/ioctl.h>
23 #include <linux/if_arp.h>
26 #include <linux/genetlink.h>
27 #include <linux/l2tp.h>
31 #include "ip_common.h"
42 uint32_t peer_tunnel_id
;
44 uint32_t peer_session_id
;
47 enum l2tp_encap_type encap
;
48 uint16_t local_udp_port
;
49 uint16_t peer_udp_port
;
53 uint8_t peer_cookie
[8];
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;
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
;
86 struct l2tp_parm config
;
87 struct l2tp_stats stats
;
91 static struct rtnl_handle genl_rth
;
92 static int genl_family
= -1;
94 /*****************************************************************************
96 *****************************************************************************/
98 static int create_tunnel(struct l2tp_parm
*p
)
100 uint32_t local_attr
= L2TP_ATTR_IP_SADDR
;
101 uint32_t peer_attr
= L2TP_ATTR_IP_DADDR
;
103 GENL_REQUEST(req
, 1024, genl_family
, 0, L2TP_GENL_VERSION
,
104 L2TP_CMD_TUNNEL_CREATE
, NLM_F_REQUEST
| NLM_F_ACK
);
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
);
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
,
114 p
->local_ip
.bytelen
);
116 if (p
->peer_ip
.family
== AF_INET6
)
117 peer_attr
= L2TP_ATTR_IP6_DADDR
;
118 addattr_l(&req
.n
, 1024, peer_attr
, &p
->peer_ip
.data
,
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
);
125 addattr8(&req
.n
, 1024, L2TP_ATTR_UDP_CSUM
, 1);
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
);
132 if (rtnl_talk(&genl_rth
, &req
.n
, NULL
) < 0)
138 static int delete_tunnel(struct l2tp_parm
*p
)
140 GENL_REQUEST(req
, 128, genl_family
, 0, L2TP_GENL_VERSION
,
141 L2TP_CMD_TUNNEL_DELETE
, NLM_F_REQUEST
| NLM_F_ACK
);
143 addattr32(&req
.n
, 128, L2TP_ATTR_CONN_ID
, p
->tunnel_id
);
145 if (rtnl_talk(&genl_rth
, &req
.n
, NULL
) < 0)
151 static int create_session(struct l2tp_parm
*p
)
153 GENL_REQUEST(req
, 1024, genl_family
, 0, L2TP_GENL_VERSION
,
154 L2TP_CMD_SESSION_CREATE
, NLM_F_REQUEST
| NLM_F_ACK
);
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
);
161 addattr8(&req
.n
, 1024, L2TP_ATTR_L2SPEC_TYPE
, p
->l2spec_type
);
162 addattr8(&req
.n
, 1024, L2TP_ATTR_L2SPEC_LEN
, p
->l2spec_len
);
165 addattr16(&req
.n
, 1024, L2TP_ATTR_MTU
, p
->mtu
);
167 addattr8(&req
.n
, 1024, L2TP_ATTR_RECV_SEQ
, 1);
169 addattr8(&req
.n
, 1024, L2TP_ATTR_SEND_SEQ
, 1);
171 addattr(&req
.n
, 1024, L2TP_ATTR_LNS_MODE
);
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
,
178 addattr16(&req
.n
, 1024, L2TP_ATTR_OFFSET
, p
->offset
);
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
);
186 addattrstrz(&req
.n
, 1024, L2TP_ATTR_IFNAME
, p
->ifname
);
188 if (rtnl_talk(&genl_rth
, &req
.n
, NULL
) < 0)
194 static int delete_session(struct l2tp_parm
*p
)
196 GENL_REQUEST(req
, 1024, genl_family
, 0, L2TP_GENL_VERSION
,
197 L2TP_CMD_SESSION_DELETE
, NLM_F_REQUEST
| NLM_F_ACK
);
199 addattr32(&req
.n
, 1024, L2TP_ATTR_CONN_ID
, p
->tunnel_id
);
200 addattr32(&req
.n
, 1024, L2TP_ATTR_SESSION_ID
, p
->session_id
);
201 if (rtnl_talk(&genl_rth
, &req
.n
, NULL
) < 0)
207 static void print_cookie(char *name
, const uint8_t *cookie
, int len
)
209 printf(" %s %02x%02x%02x%02x", name
,
210 cookie
[0], cookie
[1],
211 cookie
[2], cookie
[3]);
213 printf("%02x%02x%02x%02x",
214 cookie
[4], cookie
[5],
215 cookie
[6], cookie
[7]);
218 static void print_tunnel(const struct l2tp_data
*data
)
220 const struct l2tp_parm
*p
= &data
->config
;
221 char buf
[INET6_ADDRSTRLEN
];
223 printf("Tunnel %u, encap %s\n",
225 p
->encap
== L2TP_ENCAPTYPE_UDP
? "UDP" :
226 p
->encap
== L2TP_ENCAPTYPE_IP
? "IP" : "??");
228 inet_ntop(p
->local_ip
.family
, p
->local_ip
.data
,
231 inet_ntop(p
->peer_ip
.family
, p
->peer_ip
.data
,
233 printf(" Peer tunnel %u\n",
236 if (p
->encap
== L2TP_ENCAPTYPE_UDP
) {
237 printf(" UDP source / dest ports: %hu/%hu\n",
238 p
->local_udp_port
, p
->peer_udp_port
);
240 switch (p
->local_ip
.family
) {
242 printf(" UDP checksum: %s\n",
243 p
->udp_csum
? "enabled" : "disabled");
246 printf(" UDP checksum: %s%s%s%s\n",
247 p
->udp6_csum_tx
&& p
->udp6_csum_rx
249 p
->udp6_csum_tx
&& !p
->udp6_csum_rx
251 !p
->udp6_csum_tx
&& p
->udp6_csum_rx
253 !p
->udp6_csum_tx
&& !p
->udp6_csum_rx
260 static void print_session(struct l2tp_data
*data
)
262 struct l2tp_parm
*p
= &data
->config
;
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
);
269 if (p
->ifname
!= NULL
)
270 printf(" interface name: %s\n", p
->ifname
);
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
);
279 if (p
->reorder_timeout
!= 0)
280 printf(" reorder timeout: %u\n", p
->reorder_timeout
);
283 if (p
->send_seq
|| p
->recv_seq
) {
284 printf(" sequence numbering:");
293 static int get_response(struct nlmsghdr
*n
, void *arg
)
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
;
302 /* Validate message and parse attributes */
303 if (n
->nlmsg_type
== NLMSG_ERROR
)
306 ghdr
= NLMSG_DATA(n
);
307 len
= n
->nlmsg_len
- NLMSG_LENGTH(sizeof(*ghdr
));
311 parse_rtattr(attrs
, L2TP_ATTR_MAX
, (void *)ghdr
+ GENL_HDRLEN
, len
);
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
]);
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
]);
334 if (attrs
[L2TP_ATTR_UDP_CSUM
])
335 p
->udp_csum
= !!rta_getattr_u8(attrs
[L2TP_ATTR_UDP_CSUM
]);
337 p
->udp6_csum_tx
= !attrs
[L2TP_ATTR_UDP_ZERO_CSUM6_TX
];
338 p
->udp6_csum_rx
= !attrs
[L2TP_ATTR_UDP_ZERO_CSUM6_RX
];
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
]));
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
]));
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
]);
353 if (attrs
[L2TP_ATTR_RECV_TIMEOUT
])
354 p
->reorder_timeout
= rta_getattr_u64(attrs
[L2TP_ATTR_RECV_TIMEOUT
]);
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;
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;
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;
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;
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
]);
388 nla_stats
= attrs
[L2TP_ATTR_STATS
];
390 struct rtattr
*tb
[L2TP_ATTR_STATS_MAX
+ 1];
392 parse_rtattr_nested(tb
, L2TP_ATTR_STATS_MAX
, nla_stats
);
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
]);
415 static int session_nlmsg(const struct sockaddr_nl
*who
,
416 struct nlmsghdr
*n
, void *arg
)
418 int ret
= get_response(n
, arg
);
426 static int get_session(struct l2tp_data
*p
)
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
);
432 req
.n
.nlmsg_seq
= genl_rth
.dump
= ++genl_rth
.seq
;
434 if (p
->config
.tunnel_id
&& p
->config
.session_id
) {
435 addattr32(&req
.n
, 128, L2TP_ATTR_CONN_ID
, p
->config
.tunnel_id
);
436 addattr32(&req
.n
, 128, L2TP_ATTR_SESSION_ID
,
437 p
->config
.session_id
);
440 if (rtnl_send(&genl_rth
, &req
, req
.n
.nlmsg_len
) < 0)
443 if (rtnl_dump_filter(&genl_rth
, session_nlmsg
, p
) < 0) {
444 fprintf(stderr
, "Dump terminated\n");
451 static int tunnel_nlmsg(const struct sockaddr_nl
*who
,
452 struct nlmsghdr
*n
, void *arg
)
454 int ret
= get_response(n
, arg
);
462 static int get_tunnel(struct l2tp_data
*p
)
464 GENL_REQUEST(req
, 1024, genl_family
, 0, L2TP_GENL_VERSION
,
466 NLM_F_ROOT
| NLM_F_MATCH
| NLM_F_REQUEST
);
468 req
.n
.nlmsg_seq
= genl_rth
.dump
= ++genl_rth
.seq
;
470 if (p
->config
.tunnel_id
)
471 addattr32(&req
.n
, 1024, L2TP_ATTR_CONN_ID
, p
->config
.tunnel_id
);
473 if (rtnl_send(&genl_rth
, &req
, req
.n
.nlmsg_len
) < 0)
476 if (rtnl_dump_filter(&genl_rth
, tunnel_nlmsg
, p
) < 0) {
477 fprintf(stderr
, "Dump terminated\n");
484 /*****************************************************************************
486 *****************************************************************************/
488 static void usage(void) __attribute__((noreturn
));
490 static void usage(void)
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"
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"
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");
522 static int parse_args(int argc
, char **argv
, int cmd
, struct l2tp_parm
*p
)
524 memset(p
, 0, sizeof(*p
));
530 p
->l2spec_type
= L2TP_L2SPECTYPE_DEFAULT
;
536 if (strcmp(*argv
, "encap") == 0) {
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
;
543 fprintf(stderr
, "Unknown tunnel encapsulation \"%s\"\n", *argv
);
546 } else if (strcmp(*argv
, "name") == 0) {
548 if (check_ifname(*argv
))
549 invarg("\"name\" not a valid ifname", *argv
);
551 } else if (strcmp(*argv
, "remote") == 0) {
553 if (get_addr(&p
->peer_ip
, *argv
, AF_UNSPEC
))
554 invarg("invalid remote address\n", *argv
);
555 } else if (strcmp(*argv
, "local") == 0) {
557 if (get_addr(&p
->local_ip
, *argv
, AF_UNSPEC
))
558 invarg("invalid local address\n", *argv
);
559 } else if ((strcmp(*argv
, "tunnel_id") == 0) ||
560 (strcmp(*argv
, "tid") == 0)) {
564 if (get_u32(&uval
, *argv
, 0))
565 invarg("invalid ID\n", *argv
);
567 } else if ((strcmp(*argv
, "peer_tunnel_id") == 0) ||
568 (strcmp(*argv
, "ptid") == 0)) {
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)) {
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)) {
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) {
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) {
602 if (get_u16(&uval
, *argv
, 0))
603 invarg("invalid port\n", *argv
);
604 p
->peer_udp_port
= uval
;
605 } else if (strcmp(*argv
, "udp_csum") == 0) {
607 if (strcmp(*argv
, "on") == 0)
609 else if (strcmp(*argv
, "off") == 0)
612 invarg("invalid option for udp_csum\n", *argv
);
613 } else if (strcmp(*argv
, "udp6_csum_rx") == 0) {
615 if (strcmp(*argv
, "on") == 0)
617 else if (strcmp(*argv
, "off") == 0)
620 invarg("invalid option for udp6_csum_rx\n"
622 } else if (strcmp(*argv
, "udp6_csum_tx") == 0) {
624 if (strcmp(*argv
, "on") == 0)
626 else if (strcmp(*argv
, "off") == 0)
629 invarg("invalid option for udp6_csum_tx\n"
631 } else if (strcmp(*argv
, "offset") == 0) {
635 if (get_u8(&uval
, *argv
, 0))
636 invarg("invalid offset\n", *argv
);
638 } else if (strcmp(*argv
, "peer_offset") == 0) {
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) {
649 slen
= strlen(*argv
);
650 if ((slen
!= 8) && (slen
!= 16))
651 invarg("cookie must be either 8 or 16 hex digits\n", *argv
);
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) {
660 slen
= strlen(*argv
);
661 if ((slen
!= 8) && (slen
!= 16))
662 invarg("cookie must be either 8 or 16 hex digits\n", *argv
);
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
);
667 } else if (strcmp(*argv
, "l2spec_type") == 0) {
669 if (strcasecmp(*argv
, "default") == 0) {
670 p
->l2spec_type
= L2TP_L2SPECTYPE_DEFAULT
;
672 } else if (strcasecmp(*argv
, "none") == 0) {
673 p
->l2spec_type
= L2TP_L2SPECTYPE_NONE
;
677 "Unknown layer2specific header type \"%s\"\n",
681 } else if (strcmp(*argv
, "seq") == 0) {
683 if (strcasecmp(*argv
, "both") == 0) {
686 } else if (strcasecmp(*argv
, "recv") == 0) {
688 } else if (strcasecmp(*argv
, "send") == 0) {
690 } else if (strcasecmp(*argv
, "none") == 0) {
695 "Unknown seq value \"%s\"\n", *argv
);
698 } else if (strcmp(*argv
, "tunnel") == 0) {
700 } else if (strcmp(*argv
, "session") == 0) {
702 } else if (matches(*argv
, "help") == 0) {
705 fprintf(stderr
, "Unknown command: %s\n", *argv
);
716 static int do_add(int argc
, char **argv
)
721 if (parse_args(argc
, argv
, L2TP_ADD
, &p
) < 0)
724 if (!p
.tunnel
&& !p
.session
)
725 missarg("tunnel or session");
727 if (p
.tunnel_id
== 0)
728 missarg("tunnel_id");
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");
736 /* peer_tunnel_id is needed for tunnels */
737 if ((p
.tunnel
) && (p
.peer_tunnel_id
== 0))
738 missarg("peer_tunnel_id");
741 if (p
.local_ip
.family
== AF_UNSPEC
)
744 if (p
.peer_ip
.family
== AF_UNSPEC
)
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");
754 ret
= create_tunnel(&p
);
758 /* Only ethernet pseudowires supported */
759 p
.pw_type
= L2TP_PWTYPE_ETH
;
761 ret
= create_session(&p
);
767 static int do_del(int argc
, char **argv
)
771 if (parse_args(argc
, argv
, L2TP_DEL
, &p
) < 0)
774 if (!p
.tunnel
&& !p
.session
)
775 missarg("tunnel or session");
777 if ((p
.tunnel
) && (p
.tunnel_id
== 0))
778 missarg("tunnel_id");
779 if ((p
.session
) && (p
.session_id
== 0))
780 missarg("session_id");
783 return delete_session(&p
);
785 return delete_tunnel(&p
);
790 static int do_show(int argc
, char **argv
)
792 struct l2tp_data data
;
793 struct l2tp_parm
*p
= &data
.config
;
795 if (parse_args(argc
, argv
, L2TP_GET
, p
) < 0)
798 if (!p
->tunnel
&& !p
->session
)
799 missarg("tunnel or session");
809 int do_ipl2tp(int argc
, char **argv
)
811 if (argc
< 1 || !matches(*argv
, "help"))
814 if (genl_init_handle(&genl_rth
, L2TP_GENL_NAME
, &genl_family
))
817 if (matches(*argv
, "add") == 0)
818 return do_add(argc
-1, argv
+1);
819 if (matches(*argv
, "delete") == 0)
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);
827 "Command \"%s\" is unknown, try \"ip l2tp help\".\n", *argv
);