• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/router/accel-pptp/src/pppd/plugins/pppol2tp/
1/* pppol2tp.c - pppd plugin to implement PPPoL2TP protocol
2 *   for Linux using kernel pppol2tp support.
3 *
4 * Requires kernel pppol2tp driver which is integrated into the kernel
5 * from 2.6.23 onwards. For earlier kernels, a version can be obtained
6 * from the OpenL2TP project at
7 * http://www.sourceforge.net/projects/openl2tp/
8 *
9 * Original by Martijn van Oosterhout <kleptog@svana.org>
10 * Modified by jchapman@katalix.com
11 *
12 * Heavily based upon pppoatm.c: original notice follows
13 *
14 * Copyright 2000 Mitchell Blank Jr.
15 * Based in part on work from Jens Axboe and Paul Mackerras.
16 * Updated to ppp-2.4.1 by Bernhard Kaindl
17 *
18 *  This program is free software; you can redistribute it and/or
19 *  modify it under the terms of the GNU General Public License
20 *  as published by the Free Software Foundation; either version
21 *  2 of the License, or (at your option) any later version.
22 */
23#include <unistd.h>
24#include <string.h>
25#include <stdlib.h>
26#include <errno.h>
27#include "pppd.h"
28#include "pathnames.h"
29#include "fsm.h"
30#include "lcp.h"
31#include "ccp.h"
32#include "ipcp.h"
33#include <sys/stat.h>
34#include <net/if.h>
35#include <sys/ioctl.h>
36#include <sys/socket.h>
37#include <netinet/in.h>
38#include <signal.h>
39#include <linux/version.h>
40#include <linux/sockios.h>
41#ifndef aligned_u64
42/* should be defined in sys/types.h */
43#define aligned_u64 unsigned long long __attribute__((aligned(8)))
44#endif
45#include <linux/types.h>
46#include <linux/if_ether.h>
47#include <linux/ppp_defs.h>
48#include <linux/if_ppp.h>
49#include <linux/if_pppox.h>
50#include <linux/if_pppol2tp.h>
51
52/* should be added to system's socket.h... */
53#ifndef SOL_PPPOL2TP
54#define SOL_PPPOL2TP	273
55#endif
56
57const char pppd_version[] = VERSION;
58
59static int setdevname_pppol2tp(char **argv);
60
61static int pppol2tp_fd = -1;
62static char *pppol2tp_fd_str;
63static bool pppol2tp_lns_mode = 0;
64static bool pppol2tp_recv_seq = 0;
65static bool pppol2tp_send_seq = 0;
66static int pppol2tp_debug_mask = 0;
67static int pppol2tp_reorder_timeout = 0;
68static char pppol2tp_ifname[32] = { 0, };
69int pppol2tp_tunnel_id = 0;
70int pppol2tp_session_id = 0;
71
72static int device_got_set = 0;
73struct channel pppol2tp_channel;
74
75static void (*old_snoop_recv_hook)(unsigned char *p, int len) = NULL;
76static void (*old_snoop_send_hook)(unsigned char *p, int len) = NULL;
77
78/* Hook provided to allow other plugins to handle ACCM changes */
79void (*pppol2tp_send_accm_hook)(int tunnel_id, int session_id,
80				uint32_t send_accm, uint32_t recv_accm) = NULL;
81
82/* Hook provided to allow other plugins to handle IP up/down */
83void (*pppol2tp_ip_updown_hook)(int tunnel_id, int session_id, int up) = NULL;
84
85static option_t pppol2tp_options[] = {
86	{ "pppol2tp", o_special, &setdevname_pppol2tp,
87	  "FD for PPPoL2TP socket", OPT_DEVNAM | OPT_A2STRVAL,
88          &pppol2tp_fd_str },
89	{ "pppol2tp_lns_mode", o_bool, &pppol2tp_lns_mode,
90	  "PPPoL2TP LNS behavior. Default off.",
91	  OPT_PRIO | OPRIO_CFGFILE },
92	{ "pppol2tp_send_seq", o_bool, &pppol2tp_send_seq,
93	  "PPPoL2TP enable sequence numbers in transmitted data packets. "
94	  "Default off.",
95	  OPT_PRIO | OPRIO_CFGFILE },
96	{ "pppol2tp_recv_seq", o_bool, &pppol2tp_recv_seq,
97	  "PPPoL2TP enforce sequence numbers in received data packets. "
98	  "Default off.",
99	  OPT_PRIO | OPRIO_CFGFILE },
100	{ "pppol2tp_reorderto", o_int, &pppol2tp_reorder_timeout,
101	  "PPPoL2TP data packet reorder timeout. Default 0 (no reordering).",
102	  OPT_PRIO },
103	{ "pppol2tp_debug_mask", o_int, &pppol2tp_debug_mask,
104	  "PPPoL2TP debug mask. Default: no debug.",
105	  OPT_PRIO },
106	{ "pppol2tp_ifname", o_string, &pppol2tp_ifname,
107	  "Set interface name of PPP interface",
108	  OPT_PRIO | OPT_PRIV | OPT_STATIC, NULL, 16 },
109	{ "pppol2tp_tunnel_id", o_int, &pppol2tp_tunnel_id,
110	  "PPPoL2TP tunnel_id.",
111	  OPT_PRIO },
112	{ "pppol2tp_session_id", o_int, &pppol2tp_session_id,
113	  "PPPoL2TP session_id.",
114	  OPT_PRIO },
115	{ NULL }
116};
117
118static int setdevname_pppol2tp(char **argv)
119{
120	struct sockaddr_pppol2tp sax;
121	int len = sizeof(sax);
122
123	if (device_got_set)
124		return 0;
125
126	if (!int_option(*argv, &pppol2tp_fd))
127		return 0;
128
129	if(getsockname(pppol2tp_fd, (struct sockaddr *)&sax, &len) < 0) {
130		fatal("Given FD for PPPoL2TP socket invalid (%s)",
131		      strerror(errno));
132	}
133	if(sax.sa_family != AF_PPPOX || sax.sa_protocol != PX_PROTO_OL2TP) {
134		fatal("Socket is not a PPPoL2TP socket");
135	}
136
137	/* Do a test getsockopt() to ensure that the kernel has the necessary
138	 * feature available.
139	 * driver returns -ENOTCONN until session established!
140	if (getsockopt(pppol2tp_fd, SOL_PPPOL2TP, PPPOL2TP_SO_DEBUG,
141		       &tmp, &tmp_len) < 0) {
142		fatal("PPPoL2TP kernel driver not installed");
143	} */
144
145	/* Setup option defaults. Compression options are disabled! */
146
147	modem = 0;
148
149	lcp_allowoptions[0].neg_accompression = 1;
150	lcp_wantoptions[0].neg_accompression = 0;
151
152	lcp_allowoptions[0].neg_pcompression = 1;
153	lcp_wantoptions[0].neg_pcompression = 0;
154
155	ccp_allowoptions[0].deflate = 0;
156	ccp_wantoptions[0].deflate = 0;
157
158	ipcp_allowoptions[0].neg_vj = 0;
159	ipcp_wantoptions[0].neg_vj = 0;
160
161	ccp_allowoptions[0].bsd_compress = 0;
162	ccp_wantoptions[0].bsd_compress = 0;
163
164	the_channel = &pppol2tp_channel;
165	device_got_set = 1;
166
167	return 1;
168}
169
170static int connect_pppol2tp(void)
171{
172	struct sockaddr_pppol2tp sax;
173	int len = sizeof(sax);
174
175	if(pppol2tp_fd == -1) {
176		fatal("No PPPoL2TP FD specified");
177	}
178
179	getsockname(pppol2tp_fd, (struct sockaddr *)&sax, &len);
180	sprintf(ppp_devnam, "l2tp (%s)", inet_ntoa(sax.pppol2tp.addr.sin_addr));
181
182	return pppol2tp_fd;
183}
184
185static void disconnect_pppol2tp(void)
186{
187	if (pppol2tp_fd >= 0) {
188		close(pppol2tp_fd);
189		pppol2tp_fd = -1;
190	}
191}
192
193static void send_config_pppol2tp(int mtu,
194			      u_int32_t asyncmap,
195			      int pcomp,
196			      int accomp)
197{
198	struct ifreq ifr;
199	int on = 1;
200	int fd;
201	char reorderto[16];
202	char tid[8];
203	char sid[8];
204
205	if (pppol2tp_ifname[0]) {
206		struct ifreq ifr;
207		int fd;
208
209		fd = socket(AF_INET, SOCK_DGRAM, 0);
210		if (fd >= 0) {
211			memset (&ifr, '\0', sizeof (ifr));
212			strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
213			strlcpy(ifr.ifr_newname, pppol2tp_ifname,
214				sizeof(ifr.ifr_name));
215			ioctl(fd, SIOCSIFNAME, (caddr_t) &ifr);
216			strlcpy(ifname, pppol2tp_ifname, 32);
217			if (pppol2tp_debug_mask & PPPOL2TP_MSG_CONTROL) {
218				dbglog("ppp%d: interface name %s",
219				       ifunit, ifname);
220			}
221		}
222		close(fd);
223	}
224
225	if ((lcp_allowoptions[0].mru > 0) && (mtu > lcp_allowoptions[0].mru)) {
226		warn("Overriding mtu %d to %d", mtu, lcp_allowoptions[0].mru);
227		mtu = lcp_allowoptions[0].mru;
228	}
229	netif_set_mtu(ifunit, mtu);
230
231	reorderto[0] = '\0';
232	if (pppol2tp_reorder_timeout > 0)
233		sprintf(&reorderto[0], "%d ", pppol2tp_reorder_timeout);
234	tid[0] = '\0';
235	if (pppol2tp_tunnel_id > 0)
236		sprintf(&tid[0], "%hu ", pppol2tp_tunnel_id);
237	sid[0] = '\0';
238	if (pppol2tp_session_id > 0)
239		sprintf(&sid[0], "%hu ", pppol2tp_session_id);
240
241	dbglog("PPPoL2TP options: %s%s%s%s%s%s%s%s%sdebugmask %d",
242	       pppol2tp_recv_seq ? "recvseq " : "",
243	       pppol2tp_send_seq ? "sendseq " : "",
244	       pppol2tp_lns_mode ? "lnsmode " : "",
245	       pppol2tp_reorder_timeout ? "reorderto " : "", reorderto,
246	       pppol2tp_tunnel_id ? "tid " : "", tid,
247	       pppol2tp_session_id ? "sid " : "", sid,
248	       pppol2tp_debug_mask);
249
250	if (pppol2tp_recv_seq)
251		if (setsockopt(pppol2tp_fd, SOL_PPPOL2TP, PPPOL2TP_SO_RECVSEQ,
252			       &on, sizeof(on)) < 0)
253			fatal("setsockopt(PPPOL2TP_RECVSEQ): %m");
254	if (pppol2tp_send_seq)
255		if (setsockopt(pppol2tp_fd, SOL_PPPOL2TP, PPPOL2TP_SO_SENDSEQ,
256			       &on, sizeof(on)) < 0)
257			fatal("setsockopt(PPPOL2TP_SENDSEQ): %m");
258	if (pppol2tp_lns_mode)
259		if (setsockopt(pppol2tp_fd, SOL_PPPOL2TP, PPPOL2TP_SO_LNSMODE,
260			       &on, sizeof(on)) < 0)
261			fatal("setsockopt(PPPOL2TP_LNSMODE): %m");
262	if (pppol2tp_reorder_timeout)
263		if (setsockopt(pppol2tp_fd, SOL_PPPOL2TP, PPPOL2TP_SO_REORDERTO,
264			       &pppol2tp_reorder_timeout,
265			       sizeof(pppol2tp_reorder_timeout)) < 0)
266			fatal("setsockopt(PPPOL2TP_REORDERTO): %m");
267	if (pppol2tp_debug_mask)
268		if (setsockopt(pppol2tp_fd, SOL_PPPOL2TP, PPPOL2TP_SO_DEBUG,
269			       &pppol2tp_debug_mask, sizeof(pppol2tp_debug_mask)) < 0)
270			fatal("setsockopt(PPPOL2TP_DEBUG): %m");
271}
272
273static void recv_config_pppol2tp(int mru,
274			      u_int32_t asyncmap,
275			      int pcomp,
276			      int accomp)
277{
278	if ((lcp_allowoptions[0].mru > 0) && (mru > lcp_allowoptions[0].mru)) {
279		warn("Overriding mru %d to mtu value %d", mru,
280		     lcp_allowoptions[0].mru);
281		mru = lcp_allowoptions[0].mru;
282	}
283	if ((ifunit >= 0) && ioctl(pppol2tp_fd, PPPIOCSMRU, (caddr_t) &mru) < 0)
284		error("Couldn't set PPP MRU: %m");
285}
286
287/*****************************************************************************
288 * Snoop LCP message exchanges to capture negotiated ACCM values.
289 * When asyncmap values have been seen from both sides, give the values to
290 * L2TP.
291 * This code is derived from Roaring Penguin L2TP.
292 *****************************************************************************/
293
294static void pppol2tp_lcp_snoop(unsigned char *buf, int len, int incoming)
295{
296	static bool got_send_accm = 0;
297	static bool got_recv_accm = 0;
298	static uint32_t recv_accm = 0xffffffff;
299	static uint32_t send_accm = 0xffffffff;
300	static bool snooping = 1;
301
302	uint16_t protocol;
303	uint16_t lcp_pkt_len;
304	int opt, opt_len;
305	int reject;
306	unsigned char const *opt_data;
307	uint32_t accm;
308
309	/* Skip HDLC header */
310	buf += 2;
311	len -= 2;
312
313	/* Unreasonably short frame?? */
314	if (len <= 0) return;
315
316	/* Get protocol */
317	if (buf[0] & 0x01) {
318		/* Compressed protcol field */
319		protocol = buf[0];
320	} else {
321		protocol = ((unsigned int) buf[0]) * 256 + buf[1];
322	}
323
324	/* If it's a network protocol, stop snooping */
325	if (protocol <= 0x3fff) {
326		if (pppol2tp_debug_mask & PPPOL2TP_MSG_DEBUG) {
327			dbglog("Turning off snooping: "
328			       "Network protocol %04x found.",
329			       protocol);
330		}
331		snooping = 0;
332		return;
333	}
334
335	/* If it's not LCP, do not snoop */
336	if (protocol != 0xc021) {
337		return;
338	}
339
340	/* Skip protocol; go to packet data */
341	buf += 2;
342	len -= 2;
343
344	/* Unreasonably short frame?? */
345	if (len <= 0) return;
346
347	/* Look for Configure-Ack or Configure-Reject code */
348	if (buf[0] != CONFACK && buf[0] != CONFREJ) return;
349
350	reject = (buf[0] == CONFREJ);
351
352	lcp_pkt_len = ((unsigned int) buf[2]) * 256 + buf[3];
353
354	/* Something fishy with length field? */
355	if (lcp_pkt_len > len) return;
356
357	/* Skip to options */
358	len = lcp_pkt_len - 4;
359	buf += 4;
360
361	while (len > 0) {
362		/* Pull off an option */
363		opt = buf[0];
364		opt_len = buf[1];
365		opt_data = &buf[2];
366		if (opt_len > len || opt_len < 2) break;
367		len -= opt_len;
368		buf += opt_len;
369		if (pppol2tp_debug_mask & PPPOL2TP_MSG_DEBUG) {
370			dbglog("Found option type %02x; len %d", opt, opt_len);
371		}
372
373		/* We are specifically interested in ACCM */
374		if (opt == CI_ASYNCMAP && opt_len == 0x06) {
375			if (reject) {
376				/* ACCM negotiation REJECTED; use default */
377				accm = 0xffffffff;
378				if (pppol2tp_debug_mask & PPPOL2TP_MSG_DATA) {
379					dbglog("Rejected ACCM negotiation; "
380					       "defaulting (%s)",
381					       incoming ? "incoming" : "outgoing");
382				}
383				recv_accm = accm;
384				send_accm = accm;
385				got_recv_accm = 1;
386				got_send_accm = 1;
387			} else {
388				memcpy(&accm, opt_data, sizeof(accm));
389				if (pppol2tp_debug_mask & PPPOL2TP_MSG_DATA) {
390					dbglog("Found ACCM of %08x (%s)", accm,
391					       incoming ? "incoming" : "outgoing");
392				}
393				if (incoming) {
394					recv_accm = accm;
395					got_recv_accm = 1;
396				} else {
397					send_accm = accm;
398					got_send_accm = 1;
399				}
400			}
401
402			if (got_recv_accm && got_send_accm) {
403				if (pppol2tp_debug_mask & PPPOL2TP_MSG_CONTROL) {
404					dbglog("Telling L2TP: Send ACCM = %08x; "
405					       "Receive ACCM = %08x", send_accm, recv_accm);
406				}
407				if (pppol2tp_send_accm_hook != NULL) {
408					(*pppol2tp_send_accm_hook)(pppol2tp_tunnel_id,
409								   pppol2tp_session_id,
410								   send_accm, recv_accm);
411				}
412				got_recv_accm = 0;
413				got_send_accm = 0;
414			}
415		}
416	}
417}
418
419static void pppol2tp_lcp_snoop_recv(unsigned char *p, int len)
420{
421	if (old_snoop_recv_hook != NULL)
422		(*old_snoop_recv_hook)(p, len);
423	pppol2tp_lcp_snoop(p, len, 1);
424}
425
426static void pppol2tp_lcp_snoop_send(unsigned char *p, int len)
427{
428	if (old_snoop_send_hook != NULL)
429		(*old_snoop_send_hook)(p, len);
430	pppol2tp_lcp_snoop(p, len, 0);
431}
432
433/*****************************************************************************
434 * Interface up/down events
435 *****************************************************************************/
436
437static void pppol2tp_ip_up(void *opaque, int arg)
438{
439	/* may get called twice (for IPv4 and IPv6) but the hook handles that well */
440	if (pppol2tp_ip_updown_hook != NULL) {
441		(*pppol2tp_ip_updown_hook)(pppol2tp_tunnel_id,
442					   pppol2tp_session_id, 1);
443	}
444}
445
446static void pppol2tp_ip_down(void *opaque, int arg)
447{
448	/* may get called twice (for IPv4 and IPv6) but the hook handles that well */
449	if (pppol2tp_ip_updown_hook != NULL) {
450		(*pppol2tp_ip_updown_hook)(pppol2tp_tunnel_id,
451					   pppol2tp_session_id, 0);
452	}
453}
454
455/*****************************************************************************
456 * Application init
457 *****************************************************************************/
458
459static void pppol2tp_check_options(void)
460{
461	/* Enable LCP snooping for ACCM options only for LNS */
462	if (pppol2tp_lns_mode) {
463		if ((pppol2tp_tunnel_id == 0) || (pppol2tp_session_id == 0)) {
464			fatal("tunnel_id/session_id values not specified");
465		}
466		if (pppol2tp_debug_mask & PPPOL2TP_MSG_CONTROL) {
467			dbglog("Enabling LCP snooping");
468		}
469		old_snoop_recv_hook = snoop_recv_hook;
470		old_snoop_send_hook = snoop_send_hook;
471
472		snoop_recv_hook = pppol2tp_lcp_snoop_recv;
473		snoop_send_hook = pppol2tp_lcp_snoop_send;
474	}
475}
476
477/* Called just before pppd exits.
478 */
479static void pppol2tp_cleanup(void)
480{
481	if (pppol2tp_debug_mask & PPPOL2TP_MSG_DEBUG) {
482		dbglog("pppol2tp: exiting.");
483	}
484	disconnect_pppol2tp();
485}
486
487void plugin_init(void)
488{
489#if defined(__linux__)
490	extern int new_style_driver;	/* From sys-linux.c */
491	if (!ppp_available() && !new_style_driver)
492		fatal("Kernel doesn't support ppp_generic - "
493		    "needed for PPPoL2TP");
494#else
495	fatal("No PPPoL2TP support on this OS");
496#endif
497	add_options(pppol2tp_options);
498
499	/* Hook up ip up/down notifiers to send indicator to openl2tpd
500	 * that the link is up
501	 */
502	add_notifier(&ip_up_notifier, pppol2tp_ip_up, NULL);
503	add_notifier(&ip_down_notifier, pppol2tp_ip_down, NULL);
504#ifdef INET6
505	add_notifier(&ipv6_up_notifier, pppol2tp_ip_up, NULL);
506	add_notifier(&ipv6_down_notifier, pppol2tp_ip_down, NULL);
507#endif
508}
509
510struct channel pppol2tp_channel = {
511    options: pppol2tp_options,
512    process_extra_options: NULL,
513    check_options: &pppol2tp_check_options,
514    connect: &connect_pppol2tp,
515    disconnect: &disconnect_pppol2tp,
516    establish_ppp: &generic_establish_ppp,
517    disestablish_ppp: &generic_disestablish_ppp,
518    send_config: &send_config_pppol2tp,
519    recv_config: &recv_config_pppol2tp,
520    close: NULL,
521    cleanup: NULL
522};
523