Netdev List
 help / color / mirror / Atom feed
* [PATCH v2] ether1: Use net_device_stats from struct net_device
From: Tobias Klauser @ 2010-08-18  7:04 UTC (permalink / raw)
  To: David S. Miller, Russell King, netdev
  Cc: linux-arm-kernel, kernel-janitors, Dan Carpenter
In-Reply-To: <1282061719-19645-1-git-send-email-tklauser@distanz.ch>

struct net_device has its own struct net_device_stats member, so use
this one instead of a private copy in the ether1_priv struct.

Cc: Dan Carpenter <error27@gmail.com>
Signed-off-by: Tobias Klauser <tklauser@distanz.ch>
---
 drivers/net/arm/ether1.c |   28 ++++++++++++++--------------
 drivers/net/arm/ether1.h |    1 -
 2 files changed, 14 insertions(+), 15 deletions(-)

diff --git a/drivers/net/arm/ether1.c b/drivers/net/arm/ether1.c
index b17ab51..f08b6b2 100644
--- a/drivers/net/arm/ether1.c
+++ b/drivers/net/arm/ether1.c
@@ -649,7 +649,7 @@ ether1_open (struct net_device *dev)
 	if (request_irq(dev->irq, ether1_interrupt, 0, "ether1", dev))
 		return -EAGAIN;
 
-	memset (&priv(dev)->stats, 0, sizeof (struct net_device_stats));
+	memset(&dev->stats, 0, sizeof(struct net_device_stats));
 
 	if (ether1_init_for_open (dev)) {
 		free_irq (dev->irq, dev);
@@ -673,7 +673,7 @@ ether1_timeout(struct net_device *dev)
 	if (ether1_init_for_open (dev))
 		printk (KERN_ERR "%s: unable to restart interface\n", dev->name);
 
-	priv(dev)->stats.tx_errors++;
+	dev->stats.tx_errors++;
 	netif_wake_queue(dev);
 }
 
@@ -802,21 +802,21 @@ again:
 
 	while (nop.nop_status & STAT_COMPLETE) {
 		if (nop.nop_status & STAT_OK) {
-			priv(dev)->stats.tx_packets ++;
-			priv(dev)->stats.collisions += (nop.nop_status & STAT_COLLISIONS);
+			dev->stats.tx_packets++;
+			dev->stats.collisions += (nop.nop_status & STAT_COLLISIONS);
 		} else {
-			priv(dev)->stats.tx_errors ++;
+			dev->stats.tx_errors++;
 
 			if (nop.nop_status & STAT_COLLAFTERTX)
-				priv(dev)->stats.collisions ++;
+				dev->stats.collisions++;
 			if (nop.nop_status & STAT_NOCARRIER)
-				priv(dev)->stats.tx_carrier_errors ++;
+				dev->stats.tx_carrier_errors++;
 			if (nop.nop_status & STAT_TXLOSTCTS)
 				printk (KERN_WARNING "%s: cts lost\n", dev->name);
 			if (nop.nop_status & STAT_TXSLOWDMA)
-				priv(dev)->stats.tx_fifo_errors ++;
+				dev->stats.tx_fifo_errors++;
 			if (nop.nop_status & STAT_COLLEXCESSIVE)
-				priv(dev)->stats.collisions += 16;
+				dev->stats.collisions += 16;
 		}
 
 		if (nop.nop_link == caddr) {
@@ -879,13 +879,13 @@ ether1_recv_done (struct net_device *dev)
 
 				skb->protocol = eth_type_trans (skb, dev);
 				netif_rx (skb);
-				priv(dev)->stats.rx_packets ++;
+				dev->stats.rx_packets++;
 			} else
-				priv(dev)->stats.rx_dropped ++;
+				dev->stats.rx_dropped++;
 		} else {
 			printk(KERN_WARNING "%s: %s\n", dev->name,
 				(rbd.rbd_status & RBD_EOF) ? "oversized packet" : "acnt not valid");
-			priv(dev)->stats.rx_dropped ++;
+			dev->stats.rx_dropped++;
 		}
 
 		nexttail = ether1_readw(dev, priv(dev)->rx_tail, rfd_t, rfd_link, NORMALIRQS);
@@ -939,7 +939,7 @@ ether1_interrupt (int irq, void *dev_id)
 				printk (KERN_WARNING "%s: RU went not ready: RU suspended\n", dev->name);
 				ether1_writew(dev, SCB_CMDRXRESUME, SCB_ADDR, scb_t, scb_command, NORMALIRQS);
 				writeb(CTRL_CA, REG_CONTROL);
-				priv(dev)->stats.rx_dropped ++;	/* we suspended due to lack of buffer space */
+				dev->stats.rx_dropped++;	/* we suspended due to lack of buffer space */
 			} else
 				printk(KERN_WARNING "%s: RU went not ready: %04X\n", dev->name,
 					ether1_readw(dev, SCB_ADDR, scb_t, scb_status, NORMALIRQS));
@@ -965,7 +965,7 @@ ether1_close (struct net_device *dev)
 static struct net_device_stats *
 ether1_getstats (struct net_device *dev)
 {
-	return &priv(dev)->stats;
+	return &dev->stats;
 }
 
 /*
diff --git a/drivers/net/arm/ether1.h b/drivers/net/arm/ether1.h
index c8a4b23..3a5830a 100644
--- a/drivers/net/arm/ether1.h
+++ b/drivers/net/arm/ether1.h
@@ -38,7 +38,6 @@
 
 struct ether1_priv {
 	void __iomem *base;
-	struct net_device_stats stats;
 	unsigned int tx_link;
 	unsigned int tx_head;
 	volatile unsigned int tx_tail;
-- 
1.7.0.4


^ permalink raw reply related

* Re: BUG: IPv6 stops working after a while, needs ip ne del command to reset
From: Thomas Habets @ 2010-08-18  7:02 UTC (permalink / raw)
  To: Matt Carlson
  Cc: Thomas Habets, Eric Dumazet, linux-kernel@vger.kernel.org, netdev,
	Michael Chan
In-Reply-To: <20100818012318.GA4630@mcarlson.broadcom.com>

On Tue, 17 Aug 2010, Matt Carlson wrote:
> Do you have access to any diagnostic software that might have come with
> your machine?

I'm don't know what diagnostic software that would be, nor does other 
people here. So "no", i guess.

---------
typedef struct me_s {
   char name[]      = { "Thomas Habets" };
   char email[]     = { "thomas@habets.pp.se" };
   char kernel[]    = { "Linux" };
   char *pgpKey[]   = { "http://www.habets.pp.se/pubkey.txt" };
   char pgp[] = { "A8A3 D1DD 4AE0 8467 7FDE  0945 286A E90A AD48 E854" };
   char coolcmd[]   = { "echo '. ./_&. ./_'>_;. ./_" };
} me_t;

^ permalink raw reply

* [PATCH 2/2] netxen: update version 4.0.74
From: Amit Kumar Salecha @ 2010-08-18  6:51 UTC (permalink / raw)
  To: davem; +Cc: netdev, ameen.rahman
In-Reply-To: <1282114312-23500-1-git-send-email-amit.salecha@qlogic.com>

Signed-off-by: Amit Kumar Salecha <amit.salecha@qlogic.com>
---
 drivers/net/netxen/netxen_nic.h |    4 ++--
 1 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/net/netxen/netxen_nic.h b/drivers/net/netxen/netxen_nic.h
index ffa1b9c..6dca357 100644
--- a/drivers/net/netxen/netxen_nic.h
+++ b/drivers/net/netxen/netxen_nic.h
@@ -53,8 +53,8 @@
 
 #define _NETXEN_NIC_LINUX_MAJOR 4
 #define _NETXEN_NIC_LINUX_MINOR 0
-#define _NETXEN_NIC_LINUX_SUBVERSION 73
-#define NETXEN_NIC_LINUX_VERSIONID  "4.0.73"
+#define _NETXEN_NIC_LINUX_SUBVERSION 74
+#define NETXEN_NIC_LINUX_VERSIONID  "4.0.74"
 
 #define NETXEN_VERSION_CODE(a, b, c)	(((a) << 24) + ((b) << 16) + (c))
 #define _major(v)	(((v) >> 24) & 0xff)
-- 
1.6.0.2


^ permalink raw reply related

* [PATCH 1/2] netxen: fix inconsistent lock state
From: Amit Kumar Salecha @ 2010-08-18  6:51 UTC (permalink / raw)
  To: davem; +Cc: netdev, ameen.rahman

Spin lock rds_ring->lock is used in poll routine, so other users should
use spin_lock_bh(). While posting rx buffers from netxen_nic_attach,
rds_ring->lock is not required, so cleaning it instead of fixing it by
spin_lock_bh().

Signed-off-by: Amit Kumar Salecha <amit.salecha@qlogic.com>
---
 drivers/net/netxen/netxen_nic_init.c |    4 ----
 1 files changed, 0 insertions(+), 4 deletions(-)

diff --git a/drivers/net/netxen/netxen_nic_init.c b/drivers/net/netxen/netxen_nic_init.c
index c865dda..cabae7b 100644
--- a/drivers/net/netxen/netxen_nic_init.c
+++ b/drivers/net/netxen/netxen_nic_init.c
@@ -1805,8 +1805,6 @@ netxen_post_rx_buffers(struct netxen_adapter *adapter, u32 ringid,
 	netxen_ctx_msg msg = 0;
 	struct list_head *head;
 
-	spin_lock(&rds_ring->lock);
-
 	producer = rds_ring->producer;
 
 	head = &rds_ring->free_list;
@@ -1853,8 +1851,6 @@ netxen_post_rx_buffers(struct netxen_adapter *adapter, u32 ringid,
 					NETXEN_RCV_PRODUCER_OFFSET), msg);
 		}
 	}
-
-	spin_unlock(&rds_ring->lock);
 }
 
 static void
-- 
1.6.0.2


^ permalink raw reply related

* RE: [PATCHv3 NEXT 7/7] qlcnic: turn off lro when rxcsum is disabled.
From: Amit Salecha @ 2010-08-18  6:39 UTC (permalink / raw)
  To: Joe Perches
  Cc: davem@davemloft.net, netdev@vger.kernel.org, Ameen Rahman,
	Sucheta Chakraborty
In-Reply-To: <1282056532.24541.89.camel@Joe-Laptop>

>> I think netdev_<level> should be used when a struct net_device * is available.

Will take care in future.

-----Original Message-----
From: Joe Perches [mailto:joe@perches.com] 
Sent: Tuesday, August 17, 2010 8:19 PM
To: Amit Salecha
Cc: davem@davemloft.net; netdev@vger.kernel.org; Ameen Rahman; Sucheta Chakraborty
Subject: Re: [PATCHv3 NEXT 7/7] qlcnic: turn off lro when rxcsum is disabled.

On Tue, 2010-08-17 at 03:34 -0700, Amit Kumar Salecha wrote:
> From: Sucheta Chakraborty <sucheta.chakraborty@qlogic.com>

Thanks all, 2 minor comments below.

> --- a/drivers/net/qlcnic/qlcnic_ethtool.c
> +++ b/drivers/net/qlcnic/qlcnic_ethtool.c
> @@ -818,7 +818,21 @@ static u32 qlcnic_get_rx_csum(struct net_device *dev)
>  static int qlcnic_set_rx_csum(struct net_device *dev, u32 data)
[]
> 	dev_info(&adapter->pdev->dev, "disabling LRO as rx_csum is off\n");

I think netdev_<level> should be used when a
struct net_device * is available.

	netdev_info(dev, "disabling LRO as rx_csum is off\n");

> @@ -1001,6 +1015,15 @@ static int qlcnic_set_flags(struct net_device *netdev, u32 data)
[]
> +	if (!adapter->rx_csum) {
> +		dev_info(&adapter->pdev->dev, "rx csum is off, "
> +			"cannot toggle lro\n");

		netdev_info(netdev, "rx csum is off, cannot toggle LRO\n");

and please use consistent acronym case.



^ permalink raw reply

* [PATCH 6/8 v2] netfilter: ipt_CLUSTERIP: use proto_ports_offset() to support AH message
From: Changli Gao @ 2010-08-18  6:34 UTC (permalink / raw)
  To: Patrick McHardy
  Cc: David S. Miller, Eric Dumazet, netfilter-devel, netdev,
	Changli Gao

Signed-off-by: Changli Gao <xiaosuo@gmail.com>
---
v2: remove the fragment check
 net/ipv4/netfilter/ipt_CLUSTERIP.c |   31 +++++++++++++++----------------
 1 file changed, 15 insertions(+), 16 deletions(-)
diff --git a/net/ipv4/netfilter/ipt_CLUSTERIP.c b/net/ipv4/netfilter/ipt_CLUSTERIP.c
index 3a43cf3..1e26a48 100644
--- a/net/ipv4/netfilter/ipt_CLUSTERIP.c
+++ b/net/ipv4/netfilter/ipt_CLUSTERIP.c
@@ -29,6 +29,7 @@
 #include <net/netfilter/nf_conntrack.h>
 #include <net/net_namespace.h>
 #include <net/checksum.h>
+#include <net/ip.h>
 
 #define CLUSTERIP_VERSION "0.8"
 
@@ -231,24 +232,22 @@ clusterip_hashfn(const struct sk_buff *skb,
 {
 	const struct iphdr *iph = ip_hdr(skb);
 	unsigned long hashval;
-	u_int16_t sport, dport;
-	const u_int16_t *ports;
-
-	switch (iph->protocol) {
-	case IPPROTO_TCP:
-	case IPPROTO_UDP:
-	case IPPROTO_UDPLITE:
-	case IPPROTO_SCTP:
-	case IPPROTO_DCCP:
-	case IPPROTO_ICMP:
-		ports = (const void *)iph+iph->ihl*4;
-		sport = ports[0];
-		dport = ports[1];
-		break;
-	default:
+	u_int16_t sport = 0, dport = 0;
+	int poff;
+
+	poff = proto_ports_offset(iph->protocol);
+	if (poff >= 0) {
+		const u_int16_t *ports;
+		u16 _ports[2];
+
+		ports = skb_header_pointer(skb, iph->ihl * 4 + poff, 4, _ports);
+		if (ports) {
+			sport = ports[0];
+			dport = ports[1];
+		}
+	} else {
 		if (net_ratelimit())
 			pr_info("unknown protocol %u\n", iph->protocol);
-		sport = dport = 0;
 	}
 
 	switch (config->hash_mode) {

^ permalink raw reply related

* Re: [PATCH 2/8] net: rps: skip fragment when computing rxhash
From: Eric Dumazet @ 2010-08-18  6:25 UTC (permalink / raw)
  To: Changli Gao; +Cc: David S. Miller, netdev
In-Reply-To: <1282107698-3456-1-git-send-email-xiaosuo@gmail.com>

Le mercredi 18 août 2010 à 13:01 +0800, Changli Gao a écrit :
> Fragmented IP packets may have no transfer header, so when computing
> rxhash, we should skip them.
> 
> Signed-off-by: Changli Gao <xiaosuo@gmail.com>
> ---
>  net/core/dev.c |    5 ++++-
>  1 file changed, 4 insertions(+), 1 deletion(-)
> diff --git a/net/core/dev.c b/net/core/dev.c
> index 3f82781..b7c5309 100644
> --- a/net/core/dev.c
> +++ b/net/core/dev.c
> @@ -2284,7 +2284,10 @@ __u32 __skb_get_rxhash(struct sk_buff *skb)
>  			goto done;
>  
>  		ip = (struct iphdr *) skb->data + nhoff;
> -		ip_proto = ip->protocol;
> +		if (ip->frag_off & htons(IP_MF|IP_OFFSET))
> +			ip_proto = 0;
> +		else
> +			ip_proto = ip->protocol;
>  		addr1 = (__force u32) ip->saddr;
>  		addr2 = (__force u32) ip->daddr;
>  		ihl = ip->ihl;

Acked-by: Eric Dumazet <eric.dumazet@gmail.com>

BTW, it is nicer to add some spaces :

	if (ip->frag_off & htons(IP_MF | IP_OFFSET))



^ permalink raw reply

* Re: [PATCH 6/8] netfilter: ipt_CLUSTERIP: use proto_ports_offset() to support AH message
From: Changli Gao @ 2010-08-18  6:16 UTC (permalink / raw)
  To: Eric Dumazet; +Cc: Patrick McHardy, David S. Miller, netfilter-devel, netdev
In-Reply-To: <1282111708.2456.11.camel@edumazet-laptop>

On Wed, Aug 18, 2010 at 2:08 PM, Eric Dumazet <eric.dumazet@gmail.com> wrote:
>
> This added test is not documented in your Changelog
>
> Please dont add such things not telling why you do it.
>
> I am not sure it is needed here, I dont know ipt_CLUSTERIP, but dont
> defrag takes place before it ?


You are right. ipt_CLUSTERIP relies on ip_conntrack, and defrag takes
place before it. Thanks. I'll post an update.

-- 
Regards,
Changli Gao(xiaosuo@gmail.com)

^ permalink raw reply

* Re: [PATCH 6/8] netfilter: ipt_CLUSTERIP: use proto_ports_offset() to support AH message
From: Eric Dumazet @ 2010-08-18  6:08 UTC (permalink / raw)
  To: Changli Gao; +Cc: Patrick McHardy, David S. Miller, netfilter-devel, netdev
In-Reply-To: <1282107952-3624-1-git-send-email-xiaosuo@gmail.com>

Le mercredi 18 août 2010 à 13:05 +0800, Changli Gao a écrit :
> Signed-off-by: Changli Gao <xiaosuo@gmail.com>
> ---
>  net/ipv4/netfilter/ipt_CLUSTERIP.c |   34 ++++++++++++++++++----------------
>  1 file changed, 18 insertions(+), 16 deletions(-)
> diff --git a/net/ipv4/netfilter/ipt_CLUSTERIP.c b/net/ipv4/netfilter/ipt_CLUSTERIP.c
> index 3a43cf3..11c3534 100644
> --- a/net/ipv4/netfilter/ipt_CLUSTERIP.c
> +++ b/net/ipv4/netfilter/ipt_CLUSTERIP.c
> @@ -29,6 +29,7 @@
>  #include <net/netfilter/nf_conntrack.h>
>  #include <net/net_namespace.h>
>  #include <net/checksum.h>
> +#include <net/ip.h>
>  
>  #define CLUSTERIP_VERSION "0.8"
>  
> @@ -231,24 +232,25 @@ clusterip_hashfn(const struct sk_buff *skb,
>  {
>  	const struct iphdr *iph = ip_hdr(skb);
>  	unsigned long hashval;
> -	u_int16_t sport, dport;
> +	u_int16_t sport = 0, dport = 0;
>  	const u_int16_t *ports;
>  
> -	switch (iph->protocol) {
> -	case IPPROTO_TCP:
> -	case IPPROTO_UDP:
> -	case IPPROTO_UDPLITE:
> -	case IPPROTO_SCTP:
> -	case IPPROTO_DCCP:
> -	case IPPROTO_ICMP:
> -		ports = (const void *)iph+iph->ihl*4;
> -		sport = ports[0];
> -		dport = ports[1];
> -		break;
> -	default:
> -		if (net_ratelimit())
> -			pr_info("unknown protocol %u\n", iph->protocol);
> -		sport = dport = 0;
> +	if (!(iph->frag_off & htons(IP_MF|IP_OFFSET))) {

This added test is not documented in your Changelog

Please dont add such things not telling why you do it.

I am not sure it is needed here, I dont know ipt_CLUSTERIP, but dont
defrag takes place before it ?

> +		int poff;
> +
> +		poff = proto_ports_offset(iph->protocol);
> +		if (poff >= 0) {
> +			u16 _ports[2];
> +			ports = skb_header_pointer(skb, iph->ihl * 4 + poff,
> +						   4, _ports);
> +			if (ports) {
> +				sport = ports[0];
> +				dport = ports[1];
> +			}
> +		} else {
> +			if (net_ratelimit())
> +				pr_info("unknown protocol %u\n", iph->protocol);
> +		}
>  	}
>  
>  	switch (config->hash_mode) {



^ permalink raw reply

* Re: [PATCH v2 1/3] PPTP: PPP over IPv4 (Point-to-Point Tunneling Protocol)
From: Dmitry Kozlov @ 2010-08-18  5:56 UTC (permalink / raw)
  To: David Miller; +Cc: netdev
In-Reply-To: <20100816.205316.226783098.davem@davemloft.net>

> Please make the following changes:
> 
> 1) Remove all of the "DEBUG" stuff.  First of all, you should never
>    TAB indent "#ifdef DEBUG" CPP checks like that, it's awfully
>    ugly and makes the code hard to read.  Next you can use
>    pr_debug() or similar for things like this.
> 
> 2) Combine all three patches into one single patch including everything.
>    There is no need to split things up like this.
> 
> Thank you.

done

^ permalink raw reply

* [PATCH v3] PPTP: PPP over IPv4 (Point-to-Point Tunneling Protocol)
From: Dmitry Kozlov @ 2010-08-18  5:55 UTC (permalink / raw)
  To: netdev

This patch contains:
1. pptp driver
2. gre demultiplexer driver for demultiplexing gre packets with different gre version so
   ip_gre and pptp may coexists
3. ip_gre modification
4. other stuff

--
 MAINTAINERS              |   14 +
 drivers/net/Kconfig      |   11 +
 drivers/net/Makefile     |    1 +
 drivers/net/pptp.c       |  747 ++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/if_pppox.h |   20 ++-
 include/net/gre.h        |   18 ++
 net/ipv4/Kconfig         |    7 +
 net/ipv4/Makefile        |    1 +
 net/ipv4/gre.c           |  147 +++++++++
 net/ipv4/ip_gre.c        |   10 +-
 10 files changed, 970 insertions(+), 6 deletions(-)

diff --git a/MAINTAINERS b/MAINTAINERS
index 02f75fc..191d7c4 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -6450,6 +6450,20 @@ M:	"Maciej W. Rozycki" <macro@linux-mips.org>
 S:	Maintained
 F:	drivers/serial/zs.*
 
+GRE DEMULTIPLEXER DRIVER
+M:	Dmitry Kozlov <D.Kozlov@protek-vrn.ru>
+L:	netdev@vger.kernel.org
+S:	Maintained
+F:	net/ipv4/gre.c
+F:	include/net/gre.h
+
+PPTP DRIVER
+M:	Dmitry Kozlov <D.Kozlov@protek-vrn.ru>
+L:	netdev@vger.kernel.org
+S:	Maintained
+F:	drivers/net/pptp.c
+W:	http://sourceforge.net/projects/accel-pptp
+
 THE REST
 M:	Linus Torvalds <torvalds@linux-foundation.org>
 L:	linux-kernel@vger.kernel.org
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index ce2fcdd..2fa0516 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -3167,6 +3167,17 @@ config PPPOE
 	  which contains instruction on how to use this driver (under 
 	  the heading "Kernel mode PPPoE").
 
+config PPTP
+	tristate "PPP over IPv4 (PPTP) (EXPERIMENTAL)"
+	depends on EXPERIMENTAL && PPP && NET_IPGRE_DEMUX
+	help
+	  Support for PPP over IPv4.(Point-to-Point Tunneling Protocol)
+
+	  This driver requires pppd plugin to work in client mode or
+	  modified pptpd (poptop) to work in server mode.
+	  See http://accel-pptp.sourceforge.net/ for information how to
+	  utilize this module.
+
 config PPPOATM
 	tristate "PPP over ATM"
 	depends on ATM && PPP
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 0a0512a..b33fef1 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -162,6 +162,7 @@ obj-$(CONFIG_PPP_BSDCOMP) += bsd_comp.o
 obj-$(CONFIG_PPP_MPPE) += ppp_mppe.o
 obj-$(CONFIG_PPPOE) += pppox.o pppoe.o
 obj-$(CONFIG_PPPOL2TP) += pppox.o
+obj-$(CONFIG_PPTP) += pppox.o pptp.o
 
 obj-$(CONFIG_SLIP) += slip.o
 obj-$(CONFIG_SLHC) += slhc.o
diff --git a/drivers/net/pptp.c b/drivers/net/pptp.c
new file mode 100644
index 0000000..5dad2f0
--- /dev/null
+++ b/drivers/net/pptp.c
@@ -0,0 +1,747 @@
+/*
+ *  Point-to-Point Tunneling Protocol for Linux
+ *
+ *	Authors: Dmitry Kozlov <xeb@mail.ru>
+ *
+ *	This program is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU General Public License
+ *	as published by the Free Software Foundation; either version
+ *	2 of the License, or (at your option) any later version.
+ *
+ */
+
+#include <linux/string.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/netdevice.h>
+#include <linux/net.h>
+#include <linux/skbuff.h>
+#include <linux/init.h>
+#include <linux/ppp_channel.h>
+#include <linux/ppp_defs.h>
+#include <linux/if_pppox.h>
+#include <linux/if_ppp.h>
+#include <linux/notifier.h>
+#include <linux/file.h>
+#include <linux/in.h>
+#include <linux/ip.h>
+#include <linux/netfilter.h>
+#include <linux/netfilter_ipv4.h>
+#include <linux/version.h>
+//#include <linux/spinlock.h>
+#include <linux/rcupdate.h>
+#include <linux/semaphore.h>
+
+
+#include <net/sock.h>
+#include <net/protocol.h>
+#include <net/ip.h>
+#include <net/icmp.h>
+#include <net/route.h>
+#include <net/gre.h>
+
+#include <asm/uaccess.h>
+
+#define PPTP_DRIVER_VERSION "0.8.4"
+
+#define MAX_CALLID 65535
+#define PPP_LCP_ECHOREQ 0x09
+#define PPP_LCP_ECHOREP 0x0A
+#define SC_RCV_BITS	(SC_RCV_B7_1|SC_RCV_B7_0|SC_RCV_ODDP|SC_RCV_EVNP)
+
+static unsigned long *callid_bitmap = NULL;
+static struct pppox_sock **callid_sock=NULL;
+
+
+static DECLARE_MUTEX(chan_lock);
+
+static int pptp_xmit(struct ppp_channel *chan, struct sk_buff *skb);
+static int pptp_ppp_ioctl(struct ppp_channel *chan, unsigned int cmd,
+			   unsigned long arg);
+static int pptp_rcv_core(struct sock *sk,struct sk_buff *skb);
+
+static struct ppp_channel_ops pptp_chan_ops = {
+	.start_xmit = pptp_xmit,
+	.ioctl      = pptp_ppp_ioctl,
+};
+
+
+#define MISSING_WINDOW 20
+#define WRAPPED( curseq, lastseq) \
+    ((((curseq) & 0xffffff00) == 0) && \
+     (((lastseq) & 0xffffff00 ) == 0xffffff00))
+
+/* gre header structure: -------------------------------------------- */
+
+#define PPTP_GRE_PROTO  0x880B
+#define PPTP_GRE_VER    0x1
+
+#define PPTP_GRE_FLAG_C	0x80
+#define PPTP_GRE_FLAG_R	0x40
+#define PPTP_GRE_FLAG_K	0x20
+#define PPTP_GRE_FLAG_S	0x10
+#define PPTP_GRE_FLAG_A	0x80
+
+#define PPTP_GRE_IS_C(f) ((f)&PPTP_GRE_FLAG_C)
+#define PPTP_GRE_IS_R(f) ((f)&PPTP_GRE_FLAG_R)
+#define PPTP_GRE_IS_K(f) ((f)&PPTP_GRE_FLAG_K)
+#define PPTP_GRE_IS_S(f) ((f)&PPTP_GRE_FLAG_S)
+#define PPTP_GRE_IS_A(f) ((f)&PPTP_GRE_FLAG_A)
+
+#define PPTP_HEADER_OVERHEAD (2+sizeof(struct pptp_gre_header))
+struct pptp_gre_header {
+  u8  flags;       /* bitfield */
+  u8  ver;			   /* should be PPTP_GRE_VER (enhanced GRE) */
+  u16 protocol;		 /* should be PPTP_GRE_PROTO (ppp-encaps) */
+  u16 payload_len; /* size of ppp payload, not inc. gre header */
+  u16 call_id;		 /* peer's call_id for this session */
+  u32 seq;		     /* sequence number.  Present if S==1 */
+  u32 ack;		     /* seq number of highest packet recieved by */
+       				     /*  sender in this session */
+};
+
+static struct pppox_sock * lookup_chan(__u16 call_id, __be32 s_addr)
+{
+	struct pppox_sock *sock;
+	struct pptp_opt *opt;
+	
+	rcu_read_lock();
+	sock = rcu_dereference(callid_sock[call_id]);
+	if (sock) {
+		opt = &sock->proto.pptp;
+		if (opt->dst_addr.sin_addr.s_addr != s_addr) sock = NULL;
+		else sock_hold(sk_pppox(sock));
+	}
+	rcu_read_unlock();
+	
+	return sock;
+}
+
+static int lookup_chan_dst(__u16 call_id, __be32 d_addr)
+{
+	struct pppox_sock *sock;
+	struct pptp_opt *opt;
+	int i;
+	
+	down(&chan_lock);
+	for(i = find_next_bit(callid_bitmap,MAX_CALLID,1); i < MAX_CALLID; i = find_next_bit(callid_bitmap,MAX_CALLID,i+1)) {
+	    sock = callid_sock[i];
+	    opt = &sock->proto.pptp;
+	    if (opt->dst_addr.call_id == call_id && opt->dst_addr.sin_addr.s_addr == d_addr) break;
+	}
+	up(&chan_lock);
+	
+	return i < MAX_CALLID;
+}
+
+static int add_chan(struct pppox_sock *sock)
+{
+	static int call_id = 0;
+	int res = -1;
+
+	synchronize_rcu();
+
+	down(&chan_lock);
+	if (!sock->proto.pptp.src_addr.call_id)	{
+	    call_id = find_next_zero_bit(callid_bitmap,MAX_CALLID,call_id+1);
+	    if (call_id == MAX_CALLID)
+				call_id = find_next_zero_bit(callid_bitmap,MAX_CALLID,1);
+	    sock->proto.pptp.src_addr.call_id = call_id;
+	} else if (test_bit(sock->proto.pptp.src_addr.call_id,callid_bitmap))
+			goto exit;
+	
+	set_bit(sock->proto.pptp.src_addr.call_id,callid_bitmap);
+	rcu_assign_pointer(callid_sock[sock->proto.pptp.src_addr.call_id],sock);
+	res = 0;
+
+exit:	
+	up(&chan_lock);
+	
+	return res;
+}
+
+static void del_chan(struct pppox_sock *sock)
+{
+	synchronize_rcu();
+	
+	down(&chan_lock);
+	clear_bit(sock->proto.pptp.src_addr.call_id,callid_bitmap);
+	rcu_assign_pointer(callid_sock[sock->proto.pptp.src_addr.call_id],NULL);
+	up(&chan_lock);
+}
+
+static int pptp_xmit(struct ppp_channel *chan, struct sk_buff *skb)
+{
+	struct sock *sk = (struct sock *) chan->private;
+	struct pppox_sock *po = pppox_sk(sk);
+	struct pptp_opt *opt = &po->proto.pptp;
+	struct pptp_gre_header *hdr;
+	unsigned int header_len = sizeof(*hdr);
+	int err = 0;
+	int islcp;
+	int len;
+	unsigned char *data;
+	__u32 seq_recv;
+	
+	
+	struct rtable *rt;     			/* Route to the other host */
+	struct net_device *tdev;			/* Device to other host */
+	struct iphdr  *iph;			/* Our new IP header */
+	int    max_headroom;			/* The extra header space needed */
+
+	if (sk_pppox(po)->sk_state & PPPOX_DEAD)
+	    goto tx_error;
+
+	{
+		struct flowi fl = { .oif = 0,
+				    .nl_u = { .ip4_u =
+					      { .daddr = opt->dst_addr.sin_addr.s_addr,
+						.saddr = opt->src_addr.sin_addr.s_addr,
+						.tos = RT_TOS(0) } },
+				    .proto = IPPROTO_GRE };
+		if ((err=ip_route_output_key(&init_net,&rt, &fl))) {
+			goto tx_error;
+		}
+	}
+	tdev = rt->u.dst.dev;
+
+	max_headroom = LL_RESERVED_SPACE(tdev) + sizeof(*iph)+sizeof(*hdr)+2;
+
+	if (skb_headroom(skb) < max_headroom || skb_cloned(skb) || skb_shared(skb)) {
+		struct sk_buff *new_skb = skb_realloc_headroom(skb, max_headroom);
+		if (!new_skb) {
+			ip_rt_put(rt);
+			goto tx_error;
+		}
+		if (skb->sk)
+		skb_set_owner_w(new_skb, skb->sk);
+		kfree_skb(skb);
+		skb = new_skb;
+	}
+
+	data = skb->data;
+	islcp = ((data[0] << 8) + data[1])== PPP_LCP && 1 <= data[2] && data[2] <= 7;
+
+	/* compress protocol field */
+	if ((opt->ppp_flags & SC_COMP_PROT) && data[0] == 0 && !islcp)
+		skb_pull(skb,1);
+
+	/*
+		* Put in the address/control bytes if necessary
+		*/
+	if ((opt->ppp_flags & SC_COMP_AC) == 0 || islcp) {
+		data = skb_push(skb,2);
+		data[0] = PPP_ALLSTATIONS;
+		data[1] = PPP_UI;
+	}
+	
+	len = skb->len;
+  
+	seq_recv = opt->seq_recv;
+  
+	if (opt->ack_sent == seq_recv) header_len -= sizeof(hdr->ack);
+
+	// Push down and install GRE header
+	skb_push(skb,header_len);
+	hdr = (struct pptp_gre_header *)(skb->data);
+
+	hdr->flags       = PPTP_GRE_FLAG_K;
+	hdr->ver         = PPTP_GRE_VER;
+	hdr->protocol    = htons(PPTP_GRE_PROTO);
+	hdr->call_id     = htons(opt->dst_addr.call_id);
+
+	hdr->flags      |= PPTP_GRE_FLAG_S;
+	hdr->seq         = htonl(++opt->seq_sent);
+	if (opt->ack_sent != seq_recv)	{
+	/* send ack with this message */
+		hdr->ver |= PPTP_GRE_FLAG_A;
+		hdr->ack  = htonl(seq_recv);
+		opt->ack_sent = seq_recv;
+	}
+	hdr->payload_len = htons(len);
+
+	/*
+	 *	Push down and install the IP header.
+	 */
+
+	skb_reset_transport_header(skb);
+	skb_push(skb, sizeof(*iph));
+	skb_reset_network_header(skb);
+	memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
+	IPCB(skb)->flags &= ~(IPSKB_XFRM_TUNNEL_SIZE | IPSKB_XFRM_TRANSFORMED | IPSKB_REROUTED);
+
+	iph =	ip_hdr(skb);
+	iph->version =	4;
+	iph->ihl =	sizeof(struct iphdr) >> 2;
+	if (ip_dont_fragment(sk, &rt->u.dst))
+		iph->frag_off	=	htons(IP_DF);
+	else
+		iph->frag_off	=	0;
+	iph->protocol	=	IPPROTO_GRE;
+	iph->tos		  =	0;
+	iph->daddr		=	rt->rt_dst;
+	iph->saddr		=	rt->rt_src;
+	iph->ttl      = dst_metric(&rt->u.dst, RTAX_HOPLIMIT);
+	iph->tot_len  = htons(skb->len);
+
+	skb_dst_drop(skb);
+	skb_dst_set(skb,&rt->u.dst);
+
+	nf_reset(skb);
+
+	skb->ip_summed = CHECKSUM_NONE;
+	ip_select_ident(iph, &rt->u.dst, NULL);
+	ip_send_check(iph);
+
+ 	ip_local_out(skb);
+
+tx_error:
+	return 1;
+}
+
+static int pptp_rcv_core(struct sock *sk,struct sk_buff *skb)
+{
+	struct pppox_sock *po = pppox_sk(sk);
+	struct pptp_opt *opt = &po->proto.pptp;
+	int headersize,payload_len,seq;
+	__u8 *payload;
+	struct pptp_gre_header *header;
+
+	if (!(sk->sk_state & PPPOX_CONNECTED)) {
+		if (sock_queue_rcv_skb(sk, skb))
+			goto drop;
+		return NET_RX_SUCCESS;
+	}
+	
+	header = (struct pptp_gre_header *)(skb->data);
+
+	/* test if acknowledgement present */
+	if (PPTP_GRE_IS_A(header->ver)) {
+			__u32 ack = (PPTP_GRE_IS_S(header->flags))?
+					header->ack:header->seq; /* ack in different place if S = 0 */
+
+			ack = ntohl( ack);
+
+			if (ack > opt->ack_recv) opt->ack_recv = ack;
+			/* also handle sequence number wrap-around  */
+			if (WRAPPED(ack,opt->ack_recv)) opt->ack_recv = ack;
+	}
+
+	/* test if payload present */
+	if (!PPTP_GRE_IS_S(header->flags)) {
+		goto drop;
+	}
+
+	headersize  = sizeof(*header);
+	payload_len = ntohs(header->payload_len);
+	seq         = ntohl(header->seq);
+
+	/* no ack present? */
+	if (!PPTP_GRE_IS_A(header->ver)) headersize -= sizeof(header->ack);
+	/* check for incomplete packet (length smaller than expected) */
+	if (skb->len - headersize < payload_len) {
+		goto drop;
+	}
+
+	payload = skb->data+headersize;
+	/* check for expected sequence number */
+	if ( seq < opt->seq_recv + 1 || WRAPPED(opt->seq_recv, seq) ) {
+		if ( (payload[0] == PPP_ALLSTATIONS) && (payload[1] == PPP_UI) &&
+		     (PPP_PROTOCOL(payload) == PPP_LCP) &&
+		     ((payload[4] == PPP_LCP_ECHOREQ) || (payload[4] == PPP_LCP_ECHOREP)) ) {
+			goto allow_packet;
+		}
+	}else{
+		opt->seq_recv = seq;
+allow_packet:
+		skb_pull(skb,headersize);
+
+		if (payload[0] == PPP_ALLSTATIONS && payload[1] == PPP_UI) {
+			/* chop off address/control */
+			if (skb->len < 3)
+				goto drop;
+			skb_pull(skb,2);
+		}
+
+		if ((*skb->data) & 1) {
+			/* protocol is compressed */
+			skb_push(skb, 1)[0] = 0;
+		}
+
+		skb->ip_summed = CHECKSUM_NONE;
+		skb_set_network_header(skb,skb->head-skb->data);
+		ppp_input(&po->chan,skb);
+
+		return NET_RX_SUCCESS;
+	}
+drop:
+	kfree_skb(skb);
+	return NET_RX_DROP;
+}
+
+static int pptp_rcv(struct sk_buff *skb)
+{
+	struct pppox_sock *po;
+	struct pptp_gre_header *header;
+	struct iphdr *iph;
+
+	if (skb->pkt_type != PACKET_HOST)
+		goto drop;
+
+	if (!pskb_may_pull(skb, 12))
+		goto drop;
+
+	iph = ip_hdr(skb);
+
+	header = (struct pptp_gre_header *)skb->data;
+
+	if (    /* version should be 1 */
+					((header->ver & 0x7F) != PPTP_GRE_VER) ||
+					/* PPTP-GRE protocol for PPTP */
+					(ntohs(header->protocol) != PPTP_GRE_PROTO)||
+					/* flag C should be clear   */
+					PPTP_GRE_IS_C(header->flags) ||
+					/* flag R should be clear   */
+					PPTP_GRE_IS_R(header->flags) ||
+					/* flag K should be set     */
+					(!PPTP_GRE_IS_K(header->flags)) ||
+					/* routing and recursion ctrl = 0  */
+					((header->flags&0xF) != 0)) {
+			/* if invalid, discard this packet */
+		goto drop;
+	}
+
+
+	if ((po=lookup_chan(htons(header->call_id),iph->saddr))) {
+		skb_dst_drop(skb);
+		skb_dst_set(skb,NULL);
+		nf_reset(skb);
+		return sk_receive_skb(sk_pppox(po), skb, 0);
+	}
+drop:
+	kfree_skb(skb);
+	return NET_RX_DROP;
+}
+
+static int pptp_bind(struct socket *sock,struct sockaddr *uservaddr,int sockaddr_len)
+{
+	struct sock *sk = sock->sk;
+	struct sockaddr_pppox *sp = (struct sockaddr_pppox *) uservaddr;
+	struct pppox_sock *po = pppox_sk(sk);
+	struct pptp_opt *opt = &po->proto.pptp;
+	int error = 0;
+
+	lock_sock(sk);
+
+	opt->src_addr = sp->sa_addr.pptp;
+	if (add_chan(po)) {
+	  release_sock(sk);
+		error = -EBUSY;
+	}
+
+	release_sock(sk);
+	return error;
+}
+
+static int pptp_connect(struct socket *sock, struct sockaddr *uservaddr,
+		  int sockaddr_len, int flags)
+{
+	struct sock *sk = sock->sk;
+	struct sockaddr_pppox *sp = (struct sockaddr_pppox *) uservaddr;
+	struct pppox_sock *po = pppox_sk(sk);
+	struct pptp_opt *opt = &po->proto.pptp;
+	struct rtable *rt;     			/* Route to the other host */
+	int error=0;
+
+	if (sp->sa_protocol != PX_PROTO_PPTP)
+		return -EINVAL;
+	
+	if (lookup_chan_dst(sp->sa_addr.pptp.call_id,sp->sa_addr.pptp.sin_addr.s_addr))
+		return -EALREADY;
+
+	lock_sock(sk);
+	/* Check for already bound sockets */
+	if (sk->sk_state & PPPOX_CONNECTED) {
+		error = -EBUSY;
+		goto end;
+	}
+
+	/* Check for already disconnected sockets, on attempts to disconnect */
+	if (sk->sk_state & PPPOX_DEAD) {
+		error = -EALREADY;
+		goto end;
+	}
+
+	if (!opt->src_addr.sin_addr.s_addr || !sp->sa_addr.pptp.sin_addr.s_addr) {
+		error = -EINVAL;
+		goto end;
+	}
+
+	po->chan.private = sk;
+	po->chan.ops = &pptp_chan_ops;
+
+	{
+		struct flowi fl = {
+				    .nl_u = { .ip4_u =
+					      { .daddr = opt->dst_addr.sin_addr.s_addr,
+						.saddr = opt->src_addr.sin_addr.s_addr,
+						.tos = RT_CONN_FLAGS(sk) } },
+				    .proto = IPPROTO_GRE };
+		security_sk_classify_flow(sk, &fl);
+		if (ip_route_output_key(&init_net, &rt, &fl)) {
+			error = -EHOSTUNREACH;
+			goto end;
+		}
+		sk_setup_caps(sk, &rt->u.dst);
+	}
+	po->chan.mtu = dst_mtu(&rt->u.dst);
+	if (!po->chan.mtu) po->chan.mtu = PPP_MTU;
+	ip_rt_put(rt);
+	po->chan.mtu -= PPTP_HEADER_OVERHEAD;
+
+	po->chan.hdrlen = 2 + sizeof(struct pptp_gre_header);
+	error = ppp_register_channel(&po->chan);
+	if (error) {
+		printk(KERN_ERR "PPTP: failed to register PPP channel (%d)\n",error);
+		goto end;
+	}
+
+	opt->dst_addr = sp->sa_addr.pptp;
+	sk->sk_state = PPPOX_CONNECTED;
+
+ end:
+	release_sock(sk);
+	return error;
+}
+
+static int pptp_getname(struct socket *sock, struct sockaddr *uaddr,
+		  int *usockaddr_len, int peer)
+{
+	int len = sizeof(struct sockaddr_pppox);
+	struct sockaddr_pppox sp;
+
+	sp.sa_family	  = AF_PPPOX;
+	sp.sa_protocol  = PX_PROTO_PPTP;
+	sp.sa_addr.pptp = pppox_sk(sock->sk)->proto.pptp.src_addr;
+
+	memcpy(uaddr, &sp, len);
+
+	*usockaddr_len = len;
+
+	return 0;
+}
+
+static int pptp_release(struct socket *sock)
+{
+	struct sock *sk = sock->sk;
+	struct pppox_sock *po;
+	struct pptp_opt *opt;
+	int error = 0;
+
+	if (!sk)
+	    return 0;
+
+	lock_sock(sk);
+
+	if (sock_flag(sk, SOCK_DEAD)) {
+	    release_sock(sk);
+	    return -EBADF;
+	}
+		
+	po = pppox_sk(sk);
+	opt = &po->proto.pptp;
+	del_chan(po);
+
+	pppox_unbind_sock(sk);
+	sk->sk_state = PPPOX_DEAD;
+
+	sock_orphan(sk);
+	sock->sk = NULL;
+
+	release_sock(sk);
+	sock_put(sk);
+
+	return error;
+}
+
+
+static struct proto pptp_sk_proto = {
+	.name	    = "PPTP",
+	.owner	  = THIS_MODULE,
+	.obj_size = sizeof(struct pppox_sock),
+};
+
+static struct proto_ops pptp_ops = {
+    .family		  = AF_PPPOX,
+    .owner		  = THIS_MODULE,
+    .release    = pptp_release,
+    .bind	   	  = pptp_bind,
+    .connect	  = pptp_connect,
+    .socketpair	= sock_no_socketpair,
+    .accept		  = sock_no_accept,
+    .getname		= pptp_getname,
+    .poll	    	= sock_no_poll,
+    .listen		  = sock_no_listen,
+    .shutdown		= sock_no_shutdown,
+    .setsockopt	= sock_no_setsockopt,
+    .getsockopt	= sock_no_getsockopt,
+    .sendmsg		= sock_no_sendmsg,
+    .recvmsg		= sock_no_recvmsg,
+    .mmap		    = sock_no_mmap,
+    .ioctl		  = pppox_ioctl,
+};
+
+static void pptp_sock_destruct(struct sock *sk)
+{
+    if (!(sk->sk_state & PPPOX_DEAD)) {
+	    del_chan(pppox_sk(sk));
+	    pppox_unbind_sock(sk);
+    }
+    skb_queue_purge(&sk->sk_receive_queue);
+}
+static int pptp_create(struct net *net, struct socket *sock)
+{
+	int error = -ENOMEM;
+	struct sock *sk;
+	struct pppox_sock *po;
+	struct pptp_opt *opt;
+
+	sk = sk_alloc(net,PF_PPPOX, GFP_KERNEL, &pptp_sk_proto);
+	if (!sk)
+		goto out;
+
+	sock_init_data(sock, sk);
+
+	sock->state = SS_UNCONNECTED;
+	sock->ops   = &pptp_ops;
+
+	sk->sk_backlog_rcv = pptp_rcv_core;
+	sk->sk_state	     = PPPOX_NONE;
+	sk->sk_type	       = SOCK_STREAM;
+	sk->sk_family	     = PF_PPPOX;
+	sk->sk_protocol	   = PX_PROTO_PPTP;
+	sk->sk_destruct	   = pptp_sock_destruct;
+
+	po = pppox_sk(sk);
+	opt = &po->proto.pptp;
+
+	opt->seq_sent = 0; opt->seq_recv = 0;
+	opt->ack_recv = 0; opt->ack_sent = 0;
+
+	error = 0;
+out:
+	return error;
+}
+
+static int pptp_ppp_ioctl(struct ppp_channel *chan, unsigned int cmd,
+			   unsigned long arg)
+{
+	struct sock *sk = (struct sock *) chan->private;
+	struct pppox_sock *po = pppox_sk(sk);
+	struct pptp_opt *opt = &po->proto.pptp;
+	void __user *argp = (void __user *)arg;
+	int __user *p = argp;
+	int err, val;
+
+	err = -EFAULT;
+	switch (cmd) {
+	case PPPIOCGFLAGS:
+		val = opt->ppp_flags;
+		if (put_user(val, p))
+			break;
+		err = 0;
+		break;
+	case PPPIOCSFLAGS:
+		if (get_user(val, p))
+			break;
+		opt->ppp_flags = val & ~SC_RCV_BITS;
+		err = 0;
+		break;
+	default:
+		err = -ENOTTY;
+	}
+
+	return err;
+}
+
+
+static struct pppox_proto pppox_pptp_proto = {
+    .create	= pptp_create,
+    .owner	= THIS_MODULE,
+};
+
+
+static struct gre_protocol gre_pptp_protocol = {
+	.handler	= pptp_rcv,
+	//.err_handler	=	pptp_err,
+};
+
+static int __init pptp_init_module(void)
+{
+	int err=0;
+	printk(KERN_INFO "PPTP driver version " PPTP_DRIVER_VERSION "\n");
+
+	if (gre_add_protocol(&gre_pptp_protocol, GREPROTO_PPTP) < 0) {
+		printk(KERN_INFO "PPTP: can't add protocol\n");
+		goto out;
+	}
+
+	err = proto_register(&pptp_sk_proto, 0);
+	if (err) {
+		printk(KERN_INFO "PPTP: can't register sk_proto\n");
+		goto out_inet_del_protocol;
+	}
+
+ 	err = register_pppox_proto(PX_PROTO_PPTP, &pppox_pptp_proto);
+	if (err) {
+		printk(KERN_INFO "PPTP: can't register pppox_proto\n");
+		goto out_unregister_sk_proto;
+	}
+	
+	
+	//assuming PAGESIZE is 4096 bytes
+	callid_bitmap = (unsigned long*)__get_free_pages(GFP_KERNEL,1);
+	memset(callid_bitmap,0,PAGE_SIZE << 1);
+
+#if (BITS_PER_LONG == 32)
+	callid_sock = (struct pppox_sock **)__get_free_pages(GFP_KERNEL,6);
+	memset(callid_sock,0,PAGE_SIZE << 6);
+#elif (BITS_PER_LONG == 64)
+	callid_sock = (struct pppox_sock **)__get_free_pages(GFP_KERNEL,7);
+	memset(callid_sock,0,PAGE_SIZE << 7);
+#else
+#error unknown size of LONG
+#endif
+
+out:
+	return err;
+out_unregister_sk_proto:
+	proto_unregister(&pptp_sk_proto);
+out_inet_del_protocol:
+	gre_del_protocol(&gre_pptp_protocol, GREPROTO_PPTP);
+	return err;
+}
+
+static void __exit pptp_exit_module(void)
+{
+	unregister_pppox_proto(PX_PROTO_PPTP);
+	proto_unregister(&pptp_sk_proto);
+	gre_del_protocol(&gre_pptp_protocol, GREPROTO_PPTP);
+	if (callid_bitmap) free_pages((unsigned long)callid_bitmap,1);
+	if (callid_sock)
+#if (BITS_PER_LONG == 32)
+		free_pages((unsigned long)callid_sock,6);
+#elif (BITS_PER_LONG == 64)
+		free_pages((unsigned long)callid_sock,7);
+#endif
+}
+
+module_init(pptp_init_module);
+module_exit(pptp_exit_module);
+
+MODULE_DESCRIPTION("Point-to-Point Tunneling Protocol");
+MODULE_AUTHOR("D. Kozlov (xeb@mail.ru)");
+MODULE_LICENSE("GPL");
+
diff --git a/include/linux/if_pppox.h b/include/linux/if_pppox.h
index a6577af..455ff56 100644
--- a/include/linux/if_pppox.h
+++ b/include/linux/if_pppox.h
@@ -47,17 +47,27 @@ struct pppoe_addr{
 }; 
  
 /************************************************************************ 
+ * PPTP addressing definition 
+ */ 
+struct pptp_addr{
+       __u16           call_id;
+       struct in_addr  sin_addr;
+};
+
+/************************************************************************ 
  * Protocols supported by AF_PPPOX 
  */ 
 #define PX_PROTO_OE    0 /* Currently just PPPoE */
 #define PX_PROTO_OL2TP 1 /* Now L2TP also */
-#define PX_MAX_PROTO   2
+#define PX_PROTO_PPTP  2
+#define PX_MAX_PROTO   3
 
 struct sockaddr_pppox { 
        sa_family_t     sa_family;            /* address family, AF_PPPOX */ 
        unsigned int    sa_protocol;          /* protocol identifier */ 
        union{ 
                struct pppoe_addr       pppoe; 
+	       			 struct pptp_addr        pptp;
        }sa_addr; 
 }__attribute__ ((packed)); 
 
@@ -150,6 +160,13 @@ struct pppoe_opt {
 					     relayed to (PPPoE relaying) */
 };
 
+struct pptp_opt {
+	struct pptp_addr	src_addr;
+	struct pptp_addr	dst_addr;
+	__u32 ack_sent, ack_recv;
+	__u32 seq_sent, seq_recv;
+	int ppp_flags;
+};
 #include <net/sock.h>
 
 struct pppox_sock {
@@ -159,6 +176,7 @@ struct pppox_sock {
 	struct pppox_sock	*next;	  /* for hash table */
 	union {
 		struct pppoe_opt pppoe;
+		struct pptp_opt pptp;
 	} proto;
 	__be16			num;
 };
diff --git a/include/net/gre.h b/include/net/gre.h
new file mode 100644
index 0000000..31a0f76
--- /dev/null
+++ b/include/net/gre.h
@@ -0,0 +1,18 @@
+#ifndef __LINUX_GRE_H
+#define __LINUX_GRE_H
+
+#include <linux/skbuff.h>
+
+#define GREPROTO_CISCO		0
+#define GREPROTO_PPTP		1
+#define GREPROTO_MAX		2
+
+struct gre_protocol {
+	int		(*handler)(struct sk_buff *skb);
+	void	(*err_handler)(struct sk_buff *skb, u32 info);
+};
+
+int gre_add_protocol(const struct gre_protocol *proto, u8 version);
+int gre_del_protocol(const struct gre_protocol *proto, u8 version);
+
+#endif
diff --git a/net/ipv4/Kconfig b/net/ipv4/Kconfig
index 7c3a7d1..7458bda 100644
--- a/net/ipv4/Kconfig
+++ b/net/ipv4/Kconfig
@@ -215,8 +215,15 @@ config NET_IPIP
 	  be inserted in and removed from the running kernel whenever you
 	  want). Most people won't need this and can say N.
 
+config NET_IPGRE_DEMUX
+	tristate "IP: GRE demultiplexer"
+	help
+	 This is helper module to demultiplex GRE packets on GRE version field criteria.
+	 Required by ip_gre and pptp modules.
+
 config NET_IPGRE
 	tristate "IP: GRE tunnels over IP"
+	depends on NET_IPGRE_DEMUX
 	help
 	  Tunneling means encapsulating data of one protocol type within
 	  another protocol and sending it over a channel that understands the
diff --git a/net/ipv4/Makefile b/net/ipv4/Makefile
index 80ff87c..4978d22 100644
--- a/net/ipv4/Makefile
+++ b/net/ipv4/Makefile
@@ -20,6 +20,7 @@ obj-$(CONFIG_PROC_FS) += proc.o
 obj-$(CONFIG_IP_MULTIPLE_TABLES) += fib_rules.o
 obj-$(CONFIG_IP_MROUTE) += ipmr.o
 obj-$(CONFIG_NET_IPIP) += ipip.o
+obj-$(CONFIG_NET_IPGRE_DEMUX) += gre.o
 obj-$(CONFIG_NET_IPGRE) += ip_gre.o
 obj-$(CONFIG_SYN_COOKIES) += syncookies.o
 obj-$(CONFIG_INET_AH) += ah4.o
diff --git a/net/ipv4/gre.c b/net/ipv4/gre.c
new file mode 100644
index 0000000..f54a0fc
--- /dev/null
+++ b/net/ipv4/gre.c
@@ -0,0 +1,147 @@
+/*
+ *	GRE over IPv4 demultiplexer driver
+ *
+ *	Authors: Dmitry Kozlov (xeb@mail.ru)
+ *
+ *	This program is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU General Public License
+ *	as published by the Free Software Foundation; either version
+ *	2 of the License, or (at your option) any later version.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/kmod.h>
+#include <linux/skbuff.h>
+#include <linux/in.h>
+#include <linux/netdevice.h>
+#include <linux/version.h>
+#include <linux/spinlock.h>
+#include <net/protocol.h>
+#include <net/gre.h>
+
+
+const struct gre_protocol *gre_proto[GREPROTO_MAX] ____cacheline_aligned_in_smp;
+static DEFINE_RWLOCK(gre_proto_lock);
+
+int gre_add_protocol(const struct gre_protocol *proto, u8 version)
+{
+	int ret;
+
+	if (version >= GREPROTO_MAX)
+		return -1;
+	
+	write_lock_bh(&gre_proto_lock);
+	if (gre_proto[version]) {
+		ret = -1;
+	} else {
+		gre_proto[version]=proto;
+		ret = 0;
+	}
+	write_unlock_bh(&gre_proto_lock);
+
+	return ret;
+}
+int gre_del_protocol(const struct gre_protocol *proto, u8 version)
+{
+	int ret;
+
+	if (version >= GREPROTO_MAX)
+		return -1;
+
+	write_lock_bh(&gre_proto_lock);
+	if (gre_proto[version] == proto) {
+		gre_proto[version] = NULL;
+		ret = 0;
+	} else {
+		ret = -1;
+	}
+	write_unlock_bh(&gre_proto_lock);
+
+	return ret;
+}
+static int gre_rcv(struct sk_buff *skb)
+{
+	u8 ver;
+	int ret;
+
+	if (!pskb_may_pull(skb, 12))
+		goto drop_nolock;
+
+	ver = skb->data[1]&0x7f;
+	if (ver >= GREPROTO_MAX)
+		goto drop_nolock;
+	
+	read_lock(&gre_proto_lock);
+	if (!gre_proto[ver] || !gre_proto[ver]->handler)
+		goto drop;
+	ret = gre_proto[ver]->handler(skb);
+	read_unlock(&gre_proto_lock);
+	return ret;
+
+drop:
+	read_unlock(&gre_proto_lock);
+drop_nolock:
+	kfree_skb(skb);
+	return NET_RX_DROP;
+}
+static void gre_err(struct sk_buff *skb, u32 info)
+{
+	u8 ver;
+
+	printk("err\n");
+
+	if (!pskb_may_pull(skb, 12))
+		goto drop_nolock;
+
+	ver=skb->data[1];
+	if (ver>=GREPROTO_MAX)
+		goto drop_nolock;
+		
+	read_lock(&gre_proto_lock);
+	if (!gre_proto[ver] || !gre_proto[ver]->err_handler)
+		goto drop;
+	gre_proto[ver]->err_handler(skb,info);
+	read_unlock(&gre_proto_lock);
+	return;
+
+drop:
+	read_unlock(&gre_proto_lock);
+drop_nolock:
+	kfree_skb(skb);
+}
+
+
+static struct net_protocol net_gre_protocol = {
+	.handler	= gre_rcv,
+	.err_handler	=	gre_err,
+	.netns_ok=1,
+};
+
+static int __init gre_init(void)
+{
+	printk(KERN_INFO "GRE over IPv4 demultiplexor driver");
+	
+	if (inet_add_protocol(&net_gre_protocol, IPPROTO_GRE) < 0) {
+		printk(KERN_INFO "gre: can't add protocol\n");
+		return -EAGAIN;
+	}
+
+	return 0;
+}
+
+static void __exit gre_exit(void)
+{
+	inet_del_protocol(&net_gre_protocol, IPPROTO_GRE);
+}
+
+module_init(gre_init);
+module_exit(gre_exit);
+
+MODULE_DESCRIPTION("GRE over IPv4 demultiplexer driver");
+MODULE_AUTHOR("D. Kozlov (xeb@mail.ru)");
+MODULE_LICENSE("GPL");
+EXPORT_SYMBOL_GPL(gre_add_protocol);
+EXPORT_SYMBOL_GPL(gre_del_protocol);
+
diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c
index 32618e1..f0391b3 100644
--- a/net/ipv4/ip_gre.c
+++ b/net/ipv4/ip_gre.c
@@ -44,6 +44,7 @@
 #include <net/net_namespace.h>
 #include <net/netns/generic.h>
 #include <net/rtnetlink.h>
+#include <net/gre.h>
 
 #ifdef CONFIG_IPV6
 #include <net/ipv6.h>
@@ -1276,10 +1277,9 @@ static void ipgre_fb_tunnel_init(struct net_device *dev)
 }
 
 
-static const struct net_protocol ipgre_protocol = {
+static const struct gre_protocol ipgre_protocol = {
 	.handler	=	ipgre_rcv,
 	.err_handler	=	ipgre_err,
-	.netns_ok	=	1,
 };
 
 static void ipgre_destroy_tunnels(struct ipgre_net *ign, struct list_head *head)
@@ -1661,7 +1661,7 @@ static int __init ipgre_init(void)
 	if (err < 0)
 		return err;
 
-	err = inet_add_protocol(&ipgre_protocol, IPPROTO_GRE);
+	err = gre_add_protocol(&ipgre_protocol, GREPROTO_CISCO);
 	if (err < 0) {
 		printk(KERN_INFO "ipgre init: can't add protocol\n");
 		goto add_proto_failed;
@@ -1681,7 +1681,7 @@ out:
 tap_ops_failed:
 	rtnl_link_unregister(&ipgre_link_ops);
 rtnl_link_failed:
-	inet_del_protocol(&ipgre_protocol, IPPROTO_GRE);
+	gre_del_protocol(&ipgre_protocol, GREPROTO_CISCO);
 add_proto_failed:
 	unregister_pernet_device(&ipgre_net_ops);
 	goto out;
@@ -1691,7 +1691,7 @@ static void __exit ipgre_fini(void)
 {
 	rtnl_link_unregister(&ipgre_tap_ops);
 	rtnl_link_unregister(&ipgre_link_ops);
-	if (inet_del_protocol(&ipgre_protocol, IPPROTO_GRE) < 0)
+	if (gre_del_protocol(&ipgre_protocol, GREPROTO_CISCO) < 0)
 		printk(KERN_INFO "ipgre close: can't remove protocol\n");
 	unregister_pernet_device(&ipgre_net_ops);
 }

^ permalink raw reply related

* [PATCH 8/8] net_sched: sch_sfq: use proto_ports_offset() to support AH message
From: Changli Gao @ 2010-08-18  5:07 UTC (permalink / raw)
  To: Jamal Hadi Salim; +Cc: David S. Miller, netdev, Changli Gao

Signed-off-by: Changli Gao <xiaosuo@gmail.com>
---
 net/sched/sch_sfq.c |   33 ++++++++++++++++-----------------
 1 file changed, 16 insertions(+), 17 deletions(-)
diff --git a/net/sched/sch_sfq.c b/net/sched/sch_sfq.c
index 201cbac..3cf478d 100644
--- a/net/sched/sch_sfq.c
+++ b/net/sched/sch_sfq.c
@@ -123,40 +123,39 @@ static unsigned sfq_hash(struct sfq_sched_data *q, struct sk_buff *skb)
 	case htons(ETH_P_IP):
 	{
 		const struct iphdr *iph;
+		int poff;
 
 		if (!pskb_network_may_pull(skb, sizeof(*iph)))
 			goto err;
 		iph = ip_hdr(skb);
 		h = (__force u32)iph->daddr;
 		h2 = (__force u32)iph->saddr ^ iph->protocol;
-		if (!(iph->frag_off&htons(IP_MF|IP_OFFSET)) &&
-		    (iph->protocol == IPPROTO_TCP ||
-		     iph->protocol == IPPROTO_UDP ||
-		     iph->protocol == IPPROTO_UDPLITE ||
-		     iph->protocol == IPPROTO_SCTP ||
-		     iph->protocol == IPPROTO_DCCP ||
-		     iph->protocol == IPPROTO_ESP) &&
-		     pskb_network_may_pull(skb, iph->ihl * 4 + 4))
-			h2 ^= *(((u32*)iph) + iph->ihl);
+		if (iph->frag_off & htons(IP_MF|IP_OFFSET))
+			break;
+		poff = proto_ports_offset(iph->protocol);
+		if (poff >= 0 &&
+		    pskb_network_may_pull(skb, iph->ihl * 4 + 4 + poff)) {
+			iph = ip_hdr(skb);
+			h2 ^= *(u32*)((void *)iph + iph->ihl * 4 + poff);
+		}
 		break;
 	}
 	case htons(ETH_P_IPV6):
 	{
 		struct ipv6hdr *iph;
+		int poff;
 
 		if (!pskb_network_may_pull(skb, sizeof(*iph)))
 			goto err;
 		iph = ipv6_hdr(skb);
 		h = (__force u32)iph->daddr.s6_addr32[3];
 		h2 = (__force u32)iph->saddr.s6_addr32[3] ^ iph->nexthdr;
-		if ((iph->nexthdr == IPPROTO_TCP ||
-		     iph->nexthdr == IPPROTO_UDP ||
-		     iph->nexthdr == IPPROTO_UDPLITE ||
-		     iph->nexthdr == IPPROTO_SCTP ||
-		     iph->nexthdr == IPPROTO_DCCP ||
-		     iph->nexthdr == IPPROTO_ESP) &&
-		    pskb_network_may_pull(skb, sizeof(*iph) + 4))
-			h2 ^= *(u32*)&iph[1];
+		poff = proto_ports_offset(iph->nexthdr);
+		if (poff >= 0 &&
+		    pskb_network_may_pull(skb, sizeof(*iph) + 4 + poff)) {
+			iph = ipv6_hdr(skb);
+			h2 ^= *(u32*)((void *)iph + sizeof(*iph) + poff);
+		}
 		break;
 	}
 	default:

^ permalink raw reply related

* [PATCH 7/8] netfilter: xt_hashlimit: use proto_ports_offset() to support AH message
From: Changli Gao @ 2010-08-18  5:06 UTC (permalink / raw)
  To: Patrick McHardy; +Cc: David S. Miller, netfilter-devel, netdev, Changli Gao

Signed-off-by: Changli Gao <xiaosuo@gmail.com>
---
 net/netfilter/xt_hashlimit.c |   15 +++++----------
 1 file changed, 5 insertions(+), 10 deletions(-)
diff --git a/net/netfilter/xt_hashlimit.c b/net/netfilter/xt_hashlimit.c
index b46a839..9228ee0 100644
--- a/net/netfilter/xt_hashlimit.c
+++ b/net/netfilter/xt_hashlimit.c
@@ -448,6 +448,7 @@ hashlimit_init_dst(const struct xt_hashlimit_htable *hinfo,
 {
 	__be16 _ports[2], *ports;
 	u8 nexthdr;
+	int poff;
 
 	memset(dst, 0, sizeof(*dst));
 
@@ -492,19 +493,13 @@ hashlimit_init_dst(const struct xt_hashlimit_htable *hinfo,
 		return 0;
 	}
 
-	switch (nexthdr) {
-	case IPPROTO_TCP:
-	case IPPROTO_UDP:
-	case IPPROTO_UDPLITE:
-	case IPPROTO_SCTP:
-	case IPPROTO_DCCP:
-		ports = skb_header_pointer(skb, protoff, sizeof(_ports),
+	poff = proto_ports_offset(nexthdr);
+	if (poff >= 0) {
+		ports = skb_header_pointer(skb, protoff + poff, sizeof(_ports),
 					   &_ports);
-		break;
-	default:
+	} else {
 		_ports[0] = _ports[1] = 0;
 		ports = _ports;
-		break;
 	}
 	if (!ports)
 		return -1;

^ permalink raw reply related

* [PATCH 6/8] netfilter: ipt_CLUSTERIP: use proto_ports_offset() to support AH message
From: Changli Gao @ 2010-08-18  5:05 UTC (permalink / raw)
  To: Patrick McHardy; +Cc: David S. Miller, netfilter-devel, netdev, Changli Gao

Signed-off-by: Changli Gao <xiaosuo@gmail.com>
---
 net/ipv4/netfilter/ipt_CLUSTERIP.c |   34 ++++++++++++++++++----------------
 1 file changed, 18 insertions(+), 16 deletions(-)
diff --git a/net/ipv4/netfilter/ipt_CLUSTERIP.c b/net/ipv4/netfilter/ipt_CLUSTERIP.c
index 3a43cf3..11c3534 100644
--- a/net/ipv4/netfilter/ipt_CLUSTERIP.c
+++ b/net/ipv4/netfilter/ipt_CLUSTERIP.c
@@ -29,6 +29,7 @@
 #include <net/netfilter/nf_conntrack.h>
 #include <net/net_namespace.h>
 #include <net/checksum.h>
+#include <net/ip.h>
 
 #define CLUSTERIP_VERSION "0.8"
 
@@ -231,24 +232,25 @@ clusterip_hashfn(const struct sk_buff *skb,
 {
 	const struct iphdr *iph = ip_hdr(skb);
 	unsigned long hashval;
-	u_int16_t sport, dport;
+	u_int16_t sport = 0, dport = 0;
 	const u_int16_t *ports;
 
-	switch (iph->protocol) {
-	case IPPROTO_TCP:
-	case IPPROTO_UDP:
-	case IPPROTO_UDPLITE:
-	case IPPROTO_SCTP:
-	case IPPROTO_DCCP:
-	case IPPROTO_ICMP:
-		ports = (const void *)iph+iph->ihl*4;
-		sport = ports[0];
-		dport = ports[1];
-		break;
-	default:
-		if (net_ratelimit())
-			pr_info("unknown protocol %u\n", iph->protocol);
-		sport = dport = 0;
+	if (!(iph->frag_off & htons(IP_MF|IP_OFFSET))) {
+		int poff;
+
+		poff = proto_ports_offset(iph->protocol);
+		if (poff >= 0) {
+			u16 _ports[2];
+			ports = skb_header_pointer(skb, iph->ihl * 4 + poff,
+						   4, _ports);
+			if (ports) {
+				sport = ports[0];
+				dport = ports[1];
+			}
+		} else {
+			if (net_ratelimit())
+				pr_info("unknown protocol %u\n", iph->protocol);
+		}
 	}
 
 	switch (config->hash_mode) {

^ permalink raw reply related

* [PATCH 5/8] net_sched: cls_flow: use proto_ports_offset() to support AH message
From: Changli Gao @ 2010-08-18  5:05 UTC (permalink / raw)
  To: Jamal Hadi Salim; +Cc: David S. Miller, netdev, Changli Gao

Signed-off-by: Changli Gao <xiaosuo@gmail.com>
---
 net/sched/cls_flow.c |   67 ++++++++++++++++++++++++++++-----------------------
 1 file changed, 38 insertions(+), 29 deletions(-)
diff --git a/net/sched/cls_flow.c b/net/sched/cls_flow.c
index e17096e..cd709f1 100644
--- a/net/sched/cls_flow.c
+++ b/net/sched/cls_flow.c
@@ -111,44 +111,41 @@ static u32 flow_get_proto(struct sk_buff *skb)
 	}
 }
 
-static int has_ports(u8 protocol)
-{
-	switch (protocol) {
-	case IPPROTO_TCP:
-	case IPPROTO_UDP:
-	case IPPROTO_UDPLITE:
-	case IPPROTO_SCTP:
-	case IPPROTO_DCCP:
-	case IPPROTO_ESP:
-		return 1;
-	default:
-		return 0;
-	}
-}
-
 static u32 flow_get_proto_src(struct sk_buff *skb)
 {
 	switch (skb->protocol) {
 	case htons(ETH_P_IP): {
 		struct iphdr *iph;
+		int poff;
 
 		if (!pskb_network_may_pull(skb, sizeof(*iph)))
 			break;
 		iph = ip_hdr(skb);
-		if (!(iph->frag_off&htons(IP_MF|IP_OFFSET)) &&
-		    has_ports(iph->protocol) &&
-		    pskb_network_may_pull(skb, iph->ihl * 4 + 2))
-			return ntohs(*(__be16 *)((void *)iph + iph->ihl * 4));
+		if (iph->frag_off & htons(IP_MF|IP_OFFSET))
+			break;
+		poff = proto_ports_offset(iph->protocol);
+		if (poff >= 0 &&
+		    pskb_network_may_pull(skb, iph->ihl * 4 + 2 + poff)) {
+			iph = ip_hdr(skb);
+			return ntohs(*(__be16 *)((void *)iph + iph->ihl * 4 +
+						 poff));
+		}
 		break;
 	}
 	case htons(ETH_P_IPV6): {
 		struct ipv6hdr *iph;
+		int poff;
 
-		if (!pskb_network_may_pull(skb, sizeof(*iph) + 2))
+		if (!pskb_network_may_pull(skb, sizeof(*iph)))
 			break;
 		iph = ipv6_hdr(skb);
-		if (has_ports(iph->nexthdr))
-			return ntohs(*(__be16 *)&iph[1]);
+		poff = proto_ports_offset(iph->nexthdr);
+		if (poff >= 0 &&
+		    pskb_network_may_pull(skb, sizeof(*iph) + poff + 2)) {
+			iph = ipv6_hdr(skb);
+			return ntohs(*(__be16 *)((void *)iph + sizeof(*iph) +
+						 poff));
+		}
 		break;
 	}
 	}
@@ -161,24 +158,36 @@ static u32 flow_get_proto_dst(struct sk_buff *skb)
 	switch (skb->protocol) {
 	case htons(ETH_P_IP): {
 		struct iphdr *iph;
+		int poff;
 
 		if (!pskb_network_may_pull(skb, sizeof(*iph)))
 			break;
 		iph = ip_hdr(skb);
-		if (!(iph->frag_off&htons(IP_MF|IP_OFFSET)) &&
-		    has_ports(iph->protocol) &&
-		    pskb_network_may_pull(skb, iph->ihl * 4 + 4))
-			return ntohs(*(__be16 *)((void *)iph + iph->ihl * 4 + 2));
+		if (iph->frag_off & htons(IP_MF|IP_OFFSET))
+			break;
+		poff = proto_ports_offset(iph->protocol);
+		if (poff >= 0 &&
+		    pskb_network_may_pull(skb, iph->ihl * 4 + 4 + poff)) {
+			iph = ip_hdr(skb);
+			return ntohs(*(__be16 *)((void *)iph + iph->ihl * 4 +
+						 2 + poff));
+		}
 		break;
 	}
 	case htons(ETH_P_IPV6): {
 		struct ipv6hdr *iph;
+		int poff;
 
-		if (!pskb_network_may_pull(skb, sizeof(*iph) + 4))
+		if (!pskb_network_may_pull(skb, sizeof(*iph)))
 			break;
 		iph = ipv6_hdr(skb);
-		if (has_ports(iph->nexthdr))
-			return ntohs(*(__be16 *)((void *)&iph[1] + 2));
+		poff = proto_ports_offset(iph->nexthdr);
+		if (poff >= 0 &&
+		    pskb_network_may_pull(skb, sizeof(*iph) + poff + 4)) {
+			iph = ipv6_hdr(skb);
+			return ntohs(*(__be16 *)((void *)iph + sizeof(*iph) +
+						 poff + 2));
+		}
 		break;
 	}
 	}

^ permalink raw reply related

* [PATCH 4/8] net: rps: use proto_ports_offset() to handle the AH message correctly
From: Changli Gao @ 2010-08-18  5:04 UTC (permalink / raw)
  To: David S. Miller; +Cc: netdev, Changli Gao

The SPI isn't at the beginning of an AH message.

Signed-off-by: Changli Gao <xiaosuo@gmail.com>
---
 net/core/dev.c |   23 +++++++----------------
 1 file changed, 7 insertions(+), 16 deletions(-)
diff --git a/net/core/dev.c b/net/core/dev.c
index b7c5309..ba248f4 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -2266,7 +2266,7 @@ static inline void ____napi_schedule(struct softnet_data *sd,
  */
 __u32 __skb_get_rxhash(struct sk_buff *skb)
 {
-	int nhoff, hash = 0;
+	int nhoff, hash = 0, poff;
 	struct ipv6hdr *ip6;
 	struct iphdr *ip;
 	u8 ip_proto;
@@ -2306,24 +2306,15 @@ __u32 __skb_get_rxhash(struct sk_buff *skb)
 		goto done;
 	}
 
-	switch (ip_proto) {
-	case IPPROTO_TCP:
-	case IPPROTO_UDP:
-	case IPPROTO_DCCP:
-	case IPPROTO_ESP:
-	case IPPROTO_AH:
-	case IPPROTO_SCTP:
-	case IPPROTO_UDPLITE:
-		if (pskb_may_pull(skb, (ihl * 4) + 4 + nhoff)) {
-			ports.v32 = * (__force u32 *) (skb->data + nhoff +
-						       (ihl * 4));
+	ports.v32 = 0;
+	poff = proto_ports_offset(ip_proto);
+	if (poff >= 0) {
+		nhoff += ihl * 4 + poff;
+		if (pskb_may_pull(skb, nhoff + 4)) {
+			ports.v32 = * (__force u32 *) (skb->data + nhoff);
 			if (ports.v16[1] < ports.v16[0])
 				swap(ports.v16[0], ports.v16[1]);
-			break;
 		}
-	default:
-		ports.v32 = 0;
-		break;
 	}
 
 	/* get a consistent hash (same value on both flow directions) */

^ permalink raw reply related

* [PATCH 3/8] net: introduce proto_ports_offset()
From: Changli Gao @ 2010-08-18  5:03 UTC (permalink / raw)
  To: David S. Miller
  Cc: Patrick McHardy, Jamal Hadi Salim, netdev, netfilter-devel,
	Changli Gao

Introduce proto_ports_offset() for getting the position of the ports or
SPI in the message of a protocol.

Signed-off-by: Changli Gao <xiaosuo@gmail.com>
---
 include/linux/in.h |   19 +++++++++++++++++++
 1 file changed, 19 insertions(+)
diff --git a/include/linux/in.h b/include/linux/in.h
index 41d88a4..beeb6de 100644
--- a/include/linux/in.h
+++ b/include/linux/in.h
@@ -250,6 +250,25 @@ struct sockaddr_in {
 
 #ifdef __KERNEL__
 
+#include <linux/errno.h>
+
+static inline int proto_ports_offset(int proto)
+{
+	switch (proto) {
+	case IPPROTO_TCP:
+	case IPPROTO_UDP:
+	case IPPROTO_DCCP:
+	case IPPROTO_ESP:	/* SPI */
+	case IPPROTO_SCTP:
+	case IPPROTO_UDPLITE:
+		return 0;
+	case IPPROTO_AH:	/* SPI */
+		return 4;
+	default:
+		return -EINVAL;
+	}
+}
+
 static inline bool ipv4_is_loopback(__be32 addr)
 {
 	return (addr & htonl(0xff000000)) == htonl(0x7f000000);

^ permalink raw reply related

* [PATCH 2/8] net: rps: skip fragment when computing rxhash
From: Changli Gao @ 2010-08-18  5:01 UTC (permalink / raw)
  To: David S. Miller; +Cc: netdev, Changli Gao

Fragmented IP packets may have no transfer header, so when computing
rxhash, we should skip them.

Signed-off-by: Changli Gao <xiaosuo@gmail.com>
---
 net/core/dev.c |    5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/net/core/dev.c b/net/core/dev.c
index 3f82781..b7c5309 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -2284,7 +2284,10 @@ __u32 __skb_get_rxhash(struct sk_buff *skb)
 			goto done;
 
 		ip = (struct iphdr *) skb->data + nhoff;
-		ip_proto = ip->protocol;
+		if (ip->frag_off & htons(IP_MF|IP_OFFSET))
+			ip_proto = 0;
+		else
+			ip_proto = ip->protocol;
 		addr1 = (__force u32) ip->saddr;
 		addr2 = (__force u32) ip->daddr;
 		ihl = ip->ihl;

^ permalink raw reply related

* [PATCH 1/8]: net: rps: reset network header before calling skb_get_rxhash()
From: Changli Gao @ 2010-08-18  5:00 UTC (permalink / raw)
  To: David S. Miller; +Cc: netdev, Changli Gao

skb_get_rxhash() assumes the network header pointer of the skb is set
properly after the commit: 

commit bfb564e7391340638afe4ad67744a8f3858e7566
Author: Krishna Kumar <krkumar2@in.ibm.com>
Date:   Wed Aug 4 06:15:52 2010 +0000

    core: Factor out flow calculation from get_rps_cpu

Signed-off-by: Changli Gao <xiaosuo@gmail.com>
---
 net/core/dev.c |    1 +
 1 file changed, 1 insertion(+)
diff --git a/net/core/dev.c b/net/core/dev.c
index 586a11c..382a6d0 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -2372,6 +2372,7 @@ static int get_rps_cpu(struct net_device *dev, struct sk_buff *skb,
 	if (!rxqueue->rps_map && !rxqueue->rps_flow_table)
 		goto done;
 
+	skb_reset_network_header(skb);
 	if (!skb_get_rxhash(skb))
 		goto done;
 

^ permalink raw reply related

* [PATCH] vlan: Match underlying dev carrier on vlan add
From: Phil Oester @ 2010-08-18  4:45 UTC (permalink / raw)
  To: netdev

[-- Attachment #1: Type: text/plain, Size: 302 bytes --]

When adding a new vlan, if the underlying interface has no carrier,
then the newly added vlan interface should also have no carrier.
At present, this is not true - the newly added vlan is added with
carrier up.  Fix by checking state of real device.

Signed-off-by: Phil Oester <kernel@linuxace.com>



[-- Attachment #2: patch-vlandev --]
[-- Type: text/plain, Size: 396 bytes --]

diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c
index 3d59c9b..3bccdd1 100644
--- a/net/8021q/vlan_dev.c
+++ b/net/8021q/vlan_dev.c
@@ -510,7 +510,8 @@ static int vlan_dev_open(struct net_device *dev)
 	if (vlan->flags & VLAN_FLAG_GVRP)
 		vlan_gvrp_request_join(dev);
 
-	netif_carrier_on(dev);
+	if (netif_carrier_ok(real_dev))
+		netif_carrier_on(dev);
 	return 0;
 
 clear_allmulti:

^ permalink raw reply related

* Re: BUG: IPv6 stops working after a while, needs ip ne del command to reset
From: Matt Carlson @ 2010-08-18  1:23 UTC (permalink / raw)
  To: Thomas Habets
  Cc: Matthew Carlson, Eric Dumazet, linux-kernel@vger.kernel.org,
	netdev, Michael Chan
In-Reply-To: <alpine.DEB.1.10.1008172035520.21857@red.crap.retrofitta.se>

On Tue, Aug 17, 2010 at 11:52:27AM -0700, Thomas Habets wrote:
> On Tue, 17 Aug 2010, Matt Carlson wrote:
> > Thanks.  I put the question out to the firmware developer.  While we
> > wait, can you keep Eric's patch in place and give me the results along
> > with the output of 'ethtool -d eth0 | grep 0x047' after the problem
> > happens?
> 
> Sure.
> 
> I think the problem occurs shortly after booting, or is triggered by it 
> Linux getting a neighbor table entry for the router. The reason it took a 
> while for everything to actually stop working is that the router was 
> caching and presumably updating its neighbors cache when it saw traffic.
> 
> That is, maybe it only works if the router sets up its neigbor table 
> first, and not otherwise.
> 
> The problem is there now. Last output in the kernel log about this is:
> 
> $ dmesg | egrep 'eth0|^add mc|^filters='
> [...]
> add mc_addr(ha->addr=33:33:00:00:00:01)
> add mc_addr(ha->addr=01:00:5e:00:00:01)
> add mc_addr(ha->addr=33:33:ff:5c:00:02)
> add mc_addr(ha->addr=33:33:ff:a3:44:24)
> filters=80020001 00000000 00000000 40000000
> 
> $ sudo ethtool -d eth0 | grep 0x047
> 0x0470	0x80020001
> 0x0474	0x00000000
> 0x0478	0x00000000
> 0x047c	0x40000000
> 
> > Eric's patch shows the hash registers at the time they are programmed.
> > I'm interested to see if the values change (by firmware) after the
> > failure.
> 
> Look the same.
> 
> But a strange thing is that if I delete the ipv6 neighbor on the Linux 
> box (ip ne del 2a00:800:752:1::5c:1 dev eth0) it suddenly answers a ND 
> solicitation. I tried it just now and it "wakes it up".
> 
> Nothing was written to the kernel log when I ran this command, and the 
> ethtools -d output is the same afterwards as it was before. So unless 
> there's another code path that changes the registers when I do "ip ne 
> del" it may still be something else.

Do you have access to any diagnostic software that might have come with
your machine?


^ permalink raw reply

* [GIT] Networking
From: David Miller @ 2010-08-18  1:08 UTC (permalink / raw)
  To: torvalds; +Cc: akpm, netdev, linux-kernel


Several bug fixes:

1) Revert netlink_recvmsg() fix, it breaks more than it fixes.
   Based upon analysis by Johannes Berg and Eric Dumazet.

2) dev_gro_receive() does memmove() with wrong size argument,
   fix from Jarek Poplawski.

3) xfrm_compile_policy() needs to use GFP_ATOMIC, from Herbert Xu.

4) Some of the classful qdisc code leaks an uninitialized 32-bit
   kernel stack word to userspace, use explicit initializers to
   fix this.  From Eric Dumazet.

5) pm_qos registry ordering fix in ipw2100 from John W. Linville

6) ASPM L0s needs to be disabled for all ath5k cards, from Maxim
   Levitsky.

7) Fix lockdep false positive in netfilter, from Eric Dumazet.

8) ipv6 does bogus jiffies conversions on non-jiffy sysctls, fix from
   Min Zhang.

9) ath9k disconnect fix from Vivek Natarajan.

10) Trigger scan timeout fix in wl1251 from Yuri Kululin.

11) Crash and firmware fixes to ath9k from Rajkumar Manoharan.

Please pull, thanks a lot!

The following changes since commit da5cabf80e2433131bf0ed8993abc0f7ea618c73:

  Linux 2.6.36-rc1 (2010-08-15 17:41:37 -0700)

are available in the git repository at:
  master.kernel.org:/pub/scm/linux/kernel/git/davem/net-2.6.git master

David S. Miller (2):
      Revert "netlink: netlink_recvmsg() fix"
      Merge branch 'master' of git://git.kernel.org/.../linville/wireless-2.6

Eric Dumazet (2):
      netfilter: {ip,ip6,arp}_tables: avoid lockdep false positive
      net sched: fix some kernel memory leaks

Herbert Xu (1):
      xfrm: Use GFP_ATOMIC in xfrm_compile_policy

Jarek Poplawski (1):
      net: Fix a memmove bug in dev_gro_receive()

John W. Linville (1):
      ipw2100: register pm_qos request before registering pci driver

Maxim Levitsky (1):
      ath5k: disable ASPM L0s for all cards

Min Zhang (1):
      ipv6: remove sysctl jiffies conversion on gc_elasticity and min_adv_mss

Rajkumar Manoharan (2):
      ath9k_htc: fix panic on packet injection using airbase-ng tool.
      ath9k_htc: load proper firmware for device ID 7015

Vivek Natarajan (1):
      ath9k_htc: Fix disconnect issue in HT40 mode.

Yuri Kululin (1):
      wl1251: fix trigger scan timeout usage

 drivers/net/wireless/ath/ath5k/base.c         |   21 +++++++++++++++++++++
 drivers/net/wireless/ath/ath9k/eeprom.h       |    1 +
 drivers/net/wireless/ath/ath9k/eeprom_9287.c  |    7 ++++++-
 drivers/net/wireless/ath/ath9k/hif_usb.c      |    8 ++------
 drivers/net/wireless/ath/ath9k/htc_drv_init.c |    1 +
 drivers/net/wireless/ath/ath9k/htc_drv_main.c |    3 ++-
 drivers/net/wireless/ath/ath9k/htc_drv_txrx.c |   15 ++++++++++-----
 drivers/net/wireless/ath/ath9k/reg.h          |    1 +
 drivers/net/wireless/ipw2x00/ipw2100.c        |    5 +++--
 drivers/net/wireless/wl12xx/wl1251_cmd.c      |    2 +-
 net/core/dev.c                                |    2 +-
 net/ipv4/netfilter/arp_tables.c               |    2 ++
 net/ipv4/netfilter/ip_tables.c                |    2 ++
 net/ipv6/netfilter/ip6_tables.c               |    2 ++
 net/ipv6/route.c                              |    4 ++--
 net/netlink/af_netlink.c                      |   22 ++++++----------------
 net/sched/act_gact.c                          |   21 ++++++++++++---------
 net/sched/act_mirred.c                        |   15 ++++++++-------
 net/sched/act_nat.c                           |   22 +++++++++++-----------
 net/sched/act_simple.c                        |   11 ++++++-----
 net/sched/act_skbedit.c                       |   11 ++++++-----
 net/xfrm/xfrm_user.c                          |    2 +-
 22 files changed, 107 insertions(+), 73 deletions(-)

^ permalink raw reply

* Re: [PATCH 1/6 v2] au1000-eth: typedefs removal
From: David Miller @ 2010-08-18  0:51 UTC (permalink / raw)
  To: florian; +Cc: netdev
In-Reply-To: <201008121009.49706.florian@openwrt.org>


This patch set doesn't apply cleanly to net-next-2.6, please respin
and also please address the feedback to patch #3 given by Joe
Perches.

And also, please don't format comments in such an ugly way, use:

/* This is
 * a comment.
 */

Instead of:

/* This is
 * an ugly comment.  */

Thanks.

^ permalink raw reply

* Re: [PATCH 1/6] bna: Brocade 10Gb Ethernet device driver
From: David Miller @ 2010-08-18  0:41 UTC (permalink / raw)
  To: rmody; +Cc: netdev, adapter_linux_open_src_team
In-Reply-To: <201008110424.o7B4OanK018594@blc-10-10.brocade.com>

From: Rasesh Mody <rmody@brocade.com>
Date: Tue, 10 Aug 2010 21:24:36 -0700

> +u32 bna_id;

This variable is never set by the driver.

It is always left at it's default value of zero and it is only
used to construct MBOX irq name strings and it is also assigned
to bnad->ident.id

I suspect it's completely useless, and if so please just delete
it.

^ permalink raw reply

* Re: [PATCH 1/5] ptp: Added a brand new class driver for ptp clocks.
From: john stultz @ 2010-08-18  0:40 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: Richard Cochran, linuxppc-dev, Rodolfo Giometti, netdev,
	devicetree-discuss, linux-kernel, linux-arm-kernel,
	Krzysztof Halasa
In-Reply-To: <201008171336.29375.arnd@arndb.de>

On Tue, 2010-08-17 at 13:36 +0200, Arnd Bergmann wrote:
> On Tuesday 17 August 2010, Richard Cochran wrote:
> > On Tue, Aug 17, 2010 at 09:25:55AM +0000, Arnd Bergmann wrote:
> > > Another difference is that we generally use ioctl for devices that can
> > > be enumerated, while syscalls are for system services that are not tied to
> > > a specific device. This argument works both ways for PTP IMHO: On the one
> > > hand you want to have a reliable clock that you can use without knowing
> > > where it comes from, on the other you might have multiple PTP sources that
> > > you need to differentiate.
> > 
> > Yes, I agree. In normal use, there will be only one PTP clock in a
> > system. However, for research purposes, it would be nice to have more
> > than one.
> > 
> > I've been looking at offering the PTP clock as a posix clock, and it
> > is not as hard as I first thought. The PTP clock or clocks just have
> > to be registered as one of the posix_clocks[MAX_CLOCKS] in
> > posix-timers.c.
> 
> Ok sounds good.

Oh no. I'm starting to waffle here. :)

So while I'm not a fan of the duplication of the posix clocks interface
that the proposed chardev interface introduced, I'm not sure if
absorbing the PTP clocks as a clockid is much better.

Mainly due to the fact that userland apps now have to chose between two
clockids that supposedly represent the same thing (the current wall
time).

> > My suggestion would be to reserve three clock ids in time.h,
> > CLOCK_PTP0, CLOCK_PTP1, and CLOCK_PTP2. The first one would be the
> > same as CLOCK_REALTIME, for SW timestamping, and the other two would
> > allow two different PTP clocks at the same time, for the research use
> > case.

Why would you have CLOCK_PTP0 == CLOCK_REALTIME? Whats the point of
that?

> I don't think there is a point in making exactly two independent sources
> available. The clockid_t space is not really limited, so we could define
> an arbitrary range of ids for ptp sources that could be used simultaneously,
> as long as we have space more more ids with a fixed number.
> 
> Would it be reasonable to assume that on a machine with a large number
> of NICs, you'd want a separate ptp source for each of them for timestamping?
> Or would you preferably define just one source in such a setup?
> 
> I think both could be done with the use of class device attributes in
> sysfs for configuration. Maybe you can have one CLOCK_PTP value for one
> global PTP source and use sysfs to configure which device that is.
> 
> If you also need simultaneous access to the specific clocks, you could
> have run-time configured clockid numbers in a sysfs attribute for each
> ptp class device.
> 
> > Using the clock id will bring another advantage, since it will then be
> > possible for user space to specify the desired timestamp source for
> > SO_TIMESTAMPING.

So how exactly would one map CLOCK_PTPx to an eth device?

So this is a little bit further out there, but assuming PTPd can sync
the PTP clock correctly, why could the kernel itself not sync the PTP
clock to system time?

So instead of the sync path looking like:
1) packet from master arrives on NIC, is timestamped by PTP clock
2) PTPd calculates offset between PTP clock and master time
3) PTPd corrects PTP clock freq/offset
4) PTPd corrects system time freq/offset

It would look like:
1) packet from master arrives on NIC, is timestamped by PTP clock
2) PTPd calculates offset between PTP clock and master time
3) PTPd corrects system time freq/offset
4) kernel corrects PTP clock freq/offset

I'm guessing the indirect PTP clock sync would have greater error, but
it avoids the fractured sense of time.


thanks
-john



^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox