Linus, The patch below adds the ability to filter packets going through a PPP interface. This allows users to specify that certain types of packets are not to count as activity, i.e. they don't reset the idle timer or bring up a demand-dialled link. This is something I have been getting a lot of requests for. It also allows users to specify that certain types of packets are to be dropped - this isn't a substitute for the netfilter stuff of course, but it comes virtually for free and it can sometimes be useful. (Users will need to use ppp-2.4.0 and compile pppd with the line in pppd/Makefile.linux that says "FILTER=y" uncommented.) I hope this can go into 2.4. It is a relatively small and self-contained set of changes. The only change to things outside the PPP generic module is a small change to make sure that sk_chk_filter is exported from the socket filtering code. There is also a small change where I have removed an unnecessary #include from ppp_channel.h. The files affected are: Documentation/Configure.help drivers/net/ppp_generic.c include/linux/filter.h include/linux/if_ppp.h include/linux/ppp_channel.h net/netsyms.c Regards, Paul. diff -urN linux/Documentation/Configure.help pmac/Documentation/Configure.help --- linux/Documentation/Configure.help Sat Sep 2 15:08:58 2000 +++ pmac/Documentation/Configure.help Sat Sep 2 14:58:22 2000 @@ -1748,6 +1748,10 @@ certain types of data to get through the socket. Linux Socket Filtering works on all socket types except TCP for now. See the text file Documentation/networking/filter.txt for more information. + + You need to say Y here if you want to use PPP packet filtering + (see the CONFIG_PPP_FILTER option below). + If unsure, say N. Network packet filtering @@ -6719,6 +6723,17 @@ This has to be supported at the other end as well and you need a version of the pppd daemon which understands the multilink protocol. + + If unsure, say N. + +PPP filtering (EXPERIMENTAL) +CONFIG_PPP_FILTER + Say Y here if you want to be able to filter the packets passing over + PPP interfaces. This allows you to control which packets count as + activity (i.e. which packets will reset the idle timer or bring up + a demand-dialled link) and which packets are to be dropped entirely. + You need to say Y here if you wish to use the pass-filter and + active-filter options to pppd. If unsure, say N. diff -urN linux/drivers/net/ppp_generic.c pmac/drivers/net/ppp_generic.c --- linux/drivers/net/ppp_generic.c Fri Jul 14 14:41:43 2000 +++ pmac/drivers/net/ppp_generic.c Sat Sep 2 15:14:02 2000 @@ -19,7 +19,7 @@ * PPP driver, written by Michael Callahan and Al Longyear, and * subsequently hacked by Paul Mackerras. * - * ==FILEVERSION 20000417== + * ==FILEVERSION 20000902== */ #include <linux/config.h> @@ -32,6 +32,7 @@ #include <linux/netdevice.h> #include <linux/poll.h> #include <linux/ppp_defs.h> +#include <linux/filter.h> #include <linux/if_ppp.h> #include <linux/ppp_channel.h> #include <linux/ppp-comp.h> @@ -121,6 +122,10 @@ struct sk_buff_head mrq; /* MP: receive reconstruction queue */ #endif /* CONFIG_PPP_MULTILINK */ struct net_device_stats stats; /* statistics */ +#ifdef CONFIG_PPP_FILTER + struct sock_fprog pass_filter; /* filter for packets to pass */ + struct sock_fprog active_filter;/* filter for pkts to reset idle */ +#endif /* CONFIG_PPP_FILTER */ }; /* @@ -621,6 +626,43 @@ err = 0; break; +#ifdef CONFIG_PPP_FILTER + case PPPIOCSPASS: + case PPPIOCSACTIVE: + { + struct sock_fprog uprog, *filtp; + struct sock_filter *code = NULL; + int len; + + if (copy_from_user(&uprog, (void *) arg, sizeof(uprog))) + break; + if (uprog.len > 0) { + err = -ENOMEM; + len = uprog.len * sizeof(struct sock_filter); + code = kmalloc(len, GFP_KERNEL); + if (code == 0) + break; + err = -EFAULT; + if (copy_from_user(code, uprog.filter, len)) + break; + err = sk_chk_filter(code, uprog.len); + if (err) { + kfree(code); + break; + } + } + filtp = (cmd == PPPIOCSPASS)? &ppp->pass_filter: &ppp->active_filter; + ppp_lock(ppp); + if (filtp->filter) + kfree(filtp->filter); + filtp->filter = code; + filtp->len = uprog.len; + ppp_unlock(ppp); + err = 0; + break; + } +#endif /* CONFIG_PPP_FILTER */ + #ifdef CONFIG_PPP_MULTILINK case PPPIOCSMRRU: if (get_user(val, (int *) arg)) @@ -892,6 +934,33 @@ int len; unsigned char *cp; + if (proto < 0x8000) { +#ifdef CONFIG_PPP_FILTER + /* check if we should pass this packet */ + /* the filter instructions are constructed assuming + a four-byte PPP header on each packet */ + *skb_push(skb, 2) = 1; + if (ppp->pass_filter.filter + && sk_run_filter(skb, ppp->pass_filter.filter, + ppp->pass_filter.len) == 0) { + if (ppp->debug & 1) { + printk(KERN_DEBUG "PPP: outbound frame not passed\n"); + kfree_skb(skb); + return; + } + } + /* if this packet passes the active filter, record the time */ + if (!(ppp->active_filter.filter + && sk_run_filter(skb, ppp->active_filter.filter, + ppp->active_filter.len) == 0)) + ppp->last_xmit = jiffies; + skb_pull(skb, 2); +#else + /* for data packets, record the time */ + ppp->last_xmit = jiffies; +#endif /* CONFIG_PPP_FILTER */ + } + ++ppp->stats.tx_packets; ppp->stats.tx_bytes += skb->len - 2; @@ -964,10 +1033,6 @@ } } - /* for data packets, record the time */ - if (proto < 0x8000) - ppp->last_xmit = jiffies; - /* * If we are waiting for traffic (demand dialling), * queue it up for pppd to receive. @@ -1402,7 +1467,29 @@ } else { /* network protocol frame - give it to the kernel */ + +#ifdef CONFIG_PPP_FILTER + /* check if the packet passes the pass and active filters */ + /* the filter instructions are constructed assuming + a four-byte PPP header on each packet */ + *skb_push(skb, 2) = 0; + if (ppp->pass_filter.filter + && sk_run_filter(skb, ppp->pass_filter.filter, + ppp->pass_filter.len) == 0) { + if (ppp->debug & 1) + printk(KERN_DEBUG "PPP: inbound frame not passed\n"); + kfree_skb(skb); + return; + } + if (!(ppp->active_filter.filter + && sk_run_filter(skb, ppp->active_filter.filter, + ppp->active_filter.len) == 0)) + ppp->last_recv = jiffies; + skb_pull(skb, 2); +#else ppp->last_recv = jiffies; +#endif /* CONFIG_PPP_FILTER */ + if ((ppp->dev->flags & IFF_UP) == 0 || ppp->npmode[npi] != NPMODE_PASS) { kfree_skb(skb); @@ -2193,6 +2280,7 @@ ppp->file.index = unit; ppp->mru = PPP_MRU; init_ppp_file(&ppp->file, INTERFACE); + ppp->file.hdrlen = PPP_HDRLEN - 2; /* don't count proto bytes */ for (i = 0; i < NUM_NP; ++i) ppp->npmode[i] = NPMODE_PASS; INIT_LIST_HEAD(&ppp->channels); @@ -2264,6 +2352,16 @@ #ifdef CONFIG_PPP_MULTILINK skb_queue_purge(&ppp->mrq); #endif /* CONFIG_PPP_MULTILINK */ +#ifdef CONFIG_PPP_FILTER + if (ppp->pass_filter.filter) { + kfree(ppp->pass_filter.filter); + ppp->pass_filter.filter = NULL; + } + if (ppp->active_filter.filter) { + kfree(ppp->active_filter.filter); + ppp->active_filter.filter = 0; + } +#endif /* CONFIG_PPP_FILTER */ dev = ppp->dev; ppp->dev = 0; ppp_unlock(ppp); diff -urN linux/include/linux/filter.h pmac/include/linux/filter.h --- linux/include/linux/filter.h Fri Apr 28 08:55:09 2000 +++ pmac/include/linux/filter.h Mon Aug 7 11:29:07 2000 @@ -135,6 +135,7 @@ #ifdef __KERNEL__ extern int sk_run_filter(struct sk_buff *skb, struct sock_filter *filter, int flen); extern int sk_attach_filter(struct sock_fprog *fprog, struct sock *sk); +extern int sk_chk_filter(struct sock_filter *filter, int flen); #endif /* __KERNEL__ */ #endif /* __LINUX_FILTER_H__ */ diff -urN linux/include/linux/if_ppp.h pmac/include/linux/if_ppp.h --- linux/include/linux/if_ppp.h Tue Mar 28 04:28:55 2000 +++ pmac/include/linux/if_ppp.h Tue Jul 25 12:17:07 2000 @@ -1,4 +1,4 @@ -/* $Id: if_ppp.h,v 1.19 1999/03/31 06:07:57 paulus Exp $ */ +/* $Id: if_ppp.h,v 1.21 2000/03/27 06:03:36 paulus Exp $ */ /* * if_ppp.h - Point-to-Point Protocol definitions. @@ -21,7 +21,7 @@ */ /* - * ==FILEVERSION 20000324== + * ==FILEVERSION 20000724== * * NOTE TO MAINTAINERS: * If you modify this file at all, please set the above date. @@ -130,6 +130,8 @@ #define PPPIOCSCOMPRESS _IOW('t', 77, struct ppp_option_data) #define PPPIOCGNPMODE _IOWR('t', 76, struct npioctl) /* get NP mode */ #define PPPIOCSNPMODE _IOW('t', 75, struct npioctl) /* set NP mode */ +#define PPPIOCSPASS _IOW('t', 71, struct sock_fprog) /* set pass filter */ +#define PPPIOCSACTIVE _IOW('t', 70, struct sock_fprog) /* set active filt */ #define PPPIOCGDEBUG _IOR('t', 65, int) /* Read debug level */ #define PPPIOCSDEBUG _IOW('t', 64, int) /* Set debug level */ #define PPPIOCGIDLE _IOR('t', 63, struct ppp_idle) /* get idle time */ diff -urN linux/include/linux/ppp_channel.h pmac/include/linux/ppp_channel.h --- linux/include/linux/ppp_channel.h Thu May 25 12:53:48 2000 +++ pmac/include/linux/ppp_channel.h Wed Aug 30 14:48:06 2000 @@ -22,7 +22,6 @@ #include <linux/list.h> #include <linux/skbuff.h> #include <linux/poll.h> -#include <asm/atomic.h> struct ppp_channel; @@ -32,7 +31,6 @@ int (*start_xmit)(struct ppp_channel *, struct sk_buff *); /* Handle an ioctl call that has come in via /dev/ppp. */ int (*ioctl)(struct ppp_channel *, unsigned int, unsigned long); - }; struct ppp_channel { diff -urN linux/net/netsyms.c pmac/net/netsyms.c --- linux/net/netsyms.c Thu Aug 24 17:52:19 2000 +++ pmac/net/netsyms.c Fri Aug 25 11:20:12 2000 @@ -141,6 +141,7 @@ EXPORT_SYMBOL(sock_kfree_s); #ifdef CONFIG_FILTER +EXPORT_SYMBOL(sk_chk_filter); EXPORT_SYMBOL(sk_run_filter); #endif - To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to [EMAIL PROTECTED] Please read the FAQ at http://www.tux.org/lkml/