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