• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * ipl2tp.c	       "ip l2tp"
3  *
4  *		This program is free software; you can redistribute it and/or
5  *		modify it under the terms of the GNU General Public License
6  *		as published by the Free Software Foundation; either version
7  *		2 of the License, or (at your option) any later version.
8  *
9  * Original Author:	James Chapman <jchapman@katalix.com>
10  *
11  */
12 
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <string.h>
16 #include <unistd.h>
17 #include <errno.h>
18 #include <sys/types.h>
19 #include <sys/socket.h>
20 #include <arpa/inet.h>
21 #include <sys/ioctl.h>
22 #include <linux/if.h>
23 #include <linux/if_arp.h>
24 #include <linux/ip.h>
25 
26 #include <linux/genetlink.h>
27 #include <linux/l2tp.h>
28 #include "libgenl.h"
29 
30 #include "utils.h"
31 #include "ip_common.h"
32 
33 enum {
34 	L2TP_ADD,
35 	L2TP_CHG,
36 	L2TP_DEL,
37 	L2TP_GET
38 };
39 
40 struct l2tp_parm {
41 	uint32_t tunnel_id;
42 	uint32_t peer_tunnel_id;
43 	uint32_t session_id;
44 	uint32_t peer_session_id;
45 	uint32_t offset;
46 	uint32_t peer_offset;
47 	enum l2tp_encap_type encap;
48 	uint16_t local_udp_port;
49 	uint16_t peer_udp_port;
50 	int cookie_len;
51 	uint8_t cookie[8];
52 	int peer_cookie_len;
53 	uint8_t peer_cookie[8];
54 	inet_prefix local_ip;
55 	inet_prefix peer_ip;
56 
57 	uint16_t pw_type;
58 	uint16_t mtu;
59 	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;
68 	int reorder_timeout;
69 	const char *ifname;
70 	uint8_t l2spec_type;
71 	uint8_t l2spec_len;
72 };
73 
74 struct 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 
85 struct l2tp_data {
86 	struct l2tp_parm config;
87 	struct l2tp_stats stats;
88 };
89 
90 /* netlink socket */
91 static struct rtnl_handle genl_rth;
92 static int genl_family = -1;
93 
94 /*****************************************************************************
95  * Netlink actions
96  *****************************************************************************/
97 
create_tunnel(struct l2tp_parm * p)98 static int create_tunnel(struct l2tp_parm *p)
99 {
100 	uint32_t local_attr = L2TP_ATTR_IP_SADDR;
101 	uint32_t peer_attr = L2TP_ATTR_IP_DADDR;
102 
103 	GENL_REQUEST(req, 1024, genl_family, 0, L2TP_GENL_VERSION,
104 		     L2TP_CMD_TUNNEL_CREATE, NLM_F_REQUEST | NLM_F_ACK);
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 
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);
115 
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,
119 		  p->peer_ip.bytelen);
120 
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);
124 		if (p->udp_csum)
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);
130 	}
131 
132 	if (rtnl_talk(&genl_rth, &req.n, NULL, 0) < 0)
133 		return -2;
134 
135 	return 0;
136 }
137 
delete_tunnel(struct l2tp_parm * p)138 static int delete_tunnel(struct l2tp_parm *p)
139 {
140 	GENL_REQUEST(req, 128, genl_family, 0, L2TP_GENL_VERSION,
141 		     L2TP_CMD_TUNNEL_DELETE, NLM_F_REQUEST | NLM_F_ACK);
142 
143 	addattr32(&req.n, 128, L2TP_ATTR_CONN_ID, p->tunnel_id);
144 
145 	if (rtnl_talk(&genl_rth, &req.n, NULL, 0) < 0)
146 		return -2;
147 
148 	return 0;
149 }
150 
create_session(struct l2tp_parm * p)151 static int create_session(struct l2tp_parm *p)
152 {
153 	GENL_REQUEST(req, 1024, genl_family, 0, L2TP_GENL_VERSION,
154 		     L2TP_CMD_SESSION_CREATE, NLM_F_REQUEST | NLM_F_ACK);
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);
161 	addattr8(&req.n, 1024, L2TP_ATTR_L2SPEC_TYPE, p->l2spec_type);
162 	addattr8(&req.n, 1024, L2TP_ATTR_L2SPEC_LEN, p->l2spec_len);
163 
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,
176 					  p->reorder_timeout);
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);
185 	if (p->ifname)
186 		addattrstrz(&req.n, 1024, L2TP_ATTR_IFNAME, p->ifname);
187 
188 	if (rtnl_talk(&genl_rth, &req.n, NULL, 0) < 0)
189 		return -2;
190 
191 	return 0;
192 }
193 
delete_session(struct l2tp_parm * p)194 static int delete_session(struct l2tp_parm *p)
195 {
196 	GENL_REQUEST(req, 1024, genl_family, 0, L2TP_GENL_VERSION,
197 		     L2TP_CMD_SESSION_DELETE, NLM_F_REQUEST | NLM_F_ACK);
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);
201 	if (rtnl_talk(&genl_rth, &req.n, NULL, 0) < 0)
202 		return -2;
203 
204 	return 0;
205 }
206 
print_cookie(char * name,const uint8_t * cookie,int len)207 static 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 
print_tunnel(const struct l2tp_data * data)218 static void print_tunnel(const struct l2tp_data *data)
219 {
220 	const struct l2tp_parm *p = &data->config;
221 	char buf[INET6_ADDRSTRLEN];
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" : "??");
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)));
233 	printf("  Peer tunnel %u\n",
234 	       p->peer_tunnel_id);
235 
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);
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",
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" : "");
255 			break;
256 		}
257 	}
258 }
259 
print_session(struct l2tp_data * data)260 static 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 
269 	if (p->ifname != NULL)
270 		printf("  interface name: %s\n", p->ifname);
271 
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 
279 	if (p->reorder_timeout != 0)
280 		printf("  reorder timeout: %u\n", p->reorder_timeout);
281 	else
282 		printf("\n");
283 	if (p->send_seq || p->recv_seq) {
284 		printf("  sequence numbering:");
285 		if (p->send_seq)
286 			printf(" send");
287 		if (p->recv_seq)
288 			printf(" recv");
289 		printf("\n");
290 	}
291 }
292 
get_response(struct nlmsghdr * n,void * arg)293 static 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]);
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]);
333 
334 	if (attrs[L2TP_ATTR_UDP_CSUM])
335 		p->udp_csum = !!rta_getattr_u8(attrs[L2TP_ATTR_UDP_CSUM]);
336 
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 
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 
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]);
352 
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;
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 	}
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 
session_nlmsg(const struct sockaddr_nl * who,struct nlmsghdr * n,void * arg)415 static int session_nlmsg(const struct sockaddr_nl *who,
416 			 struct nlmsghdr *n, void *arg)
417 {
418 	int ret = get_response(n, arg);
419 
420 	if (ret == 0)
421 		print_session(arg);
422 
423 	return ret;
424 }
425 
get_session(struct l2tp_data * p)426 static int get_session(struct l2tp_data *p)
427 {
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);
431 
432 	req.n.nlmsg_seq = genl_rth.dump = ++genl_rth.seq;
433 
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);
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 
tunnel_nlmsg(const struct sockaddr_nl * who,struct nlmsghdr * n,void * arg)451 static int tunnel_nlmsg(const struct sockaddr_nl *who,
452 			struct nlmsghdr *n, void *arg)
453 {
454 	int ret = get_response(n, arg);
455 
456 	if (ret == 0)
457 		print_tunnel(arg);
458 
459 	return ret;
460 }
461 
get_tunnel(struct l2tp_data * p)462 static int get_tunnel(struct l2tp_data *p)
463 {
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);
467 
468 	req.n.nlmsg_seq = genl_rth.dump = ++genl_rth.seq;
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 
488 static void usage(void) __attribute__((noreturn));
489 
usage(void)490 static void usage(void)
491 {
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 
519 	exit(-1);
520 }
521 
parse_args(int argc,char ** argv,int cmd,struct l2tp_parm * p)522 static 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 
529 	/* Defaults */
530 	p->l2spec_type = L2TP_L2SPECTYPE_DEFAULT;
531 	p->l2spec_len = 4;
532 	p->udp6_csum_rx = 1;
533 	p->udp6_csum_tx = 1;
534 
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 {
543 				fprintf(stderr, "Unknown tunnel encapsulation \"%s\"\n", *argv);
544 				exit(-1);
545 			}
546 		} else if (strcmp(*argv, "name") == 0) {
547 			NEXT_ARG();
548 			if (check_ifname(*argv))
549 				invarg("\"name\" not a valid ifname", *argv);
550 			p->ifname = *argv;
551 		} else if (strcmp(*argv, "remote") == 0) {
552 			NEXT_ARG();
553 			if (get_addr(&p->peer_ip, *argv, AF_UNSPEC))
554 				invarg("invalid remote address\n", *argv);
555 		} else if (strcmp(*argv, "local") == 0) {
556 			NEXT_ARG();
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)) {
561 			__u32 uval;
562 
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;
570 
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;
578 
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;
586 
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;
593 
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;
600 
601 			NEXT_ARG();
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) {
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);
631 		} else if (strcmp(*argv, "offset") == 0) {
632 			__u8 uval;
633 
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;
640 
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;
647 
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;
658 
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);
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 {
676 				fprintf(stderr,
677 					"Unknown layer2specific header type \"%s\"\n",
678 					*argv);
679 				exit(-1);
680 			}
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 {
694 				fprintf(stderr,
695 					"Unknown seq value \"%s\"\n", *argv);
696 				exit(-1);
697 			}
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 
do_add(int argc,char ** argv)716 static 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) {
741 		if (p.local_ip.family == AF_UNSPEC)
742 			missarg("local");
743 
744 		if (p.peer_ip.family == AF_UNSPEC)
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 
do_del(int argc,char ** argv)767 static 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 
do_show(int argc,char ** argv)790 static 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 
do_ipl2tp(int argc,char ** argv)809 int do_ipl2tp(int argc, char **argv)
810 {
811 	if (argc < 1 || !matches(*argv, "help"))
812 		usage();
813 
814 	if (genl_init_handle(&genl_rth, L2TP_GENL_NAME, &genl_family))
815 		exit(1);
816 
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);
825 
826 	fprintf(stderr,
827 		"Command \"%s\" is unknown, try \"ip l2tp help\".\n", *argv);
828 	exit(-1);
829 }
830