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