[NET]: Replace skb_pull/skb_postpull_rcsum with skb_pull_rcsum

We're now starting to have quite a number of places that do skb_pull
followed immediately by an skb_postpull_rcsum.  We can merge these two
operations into one function with skb_pull_rcsum.  This makes sense
since most pull operations on receive skb's need to update the
checksum.

I've decided to make this out-of-line since it is fairly big and the
fast path where hardware checksums are enabled need to call
csum_partial anyway.

Since this is a brand new function we get to add an extra check on the
len argument.  As it is most callers of skb_pull ignore its return
value which essentially means that there is no check on the len
argument.

Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
diff --git a/drivers/net/ppp_generic.c b/drivers/net/ppp_generic.c
index 0245e40..f608c12 100644
--- a/drivers/net/ppp_generic.c
+++ b/drivers/net/ppp_generic.c
@@ -1691,8 +1691,8 @@
 		    || ppp->npmode[npi] != NPMODE_PASS) {
 			kfree_skb(skb);
 		} else {
-			skb_pull(skb, 2);	/* chop off protocol */
-			skb_postpull_rcsum(skb, skb->data - 2, 2);
+			/* chop off protocol */
+			skb_pull_rcsum(skb, 2);
 			skb->dev = ppp->dev;
 			skb->protocol = htons(npindex_to_ethertype[npi]);
 			skb->mac.raw = skb->data;
diff --git a/drivers/net/pppoe.c b/drivers/net/pppoe.c
index 9369f81..475dc93 100644
--- a/drivers/net/pppoe.c
+++ b/drivers/net/pppoe.c
@@ -337,8 +337,7 @@
 	if (sk->sk_state & PPPOX_BOUND) {
 		struct pppoe_hdr *ph = (struct pppoe_hdr *) skb->nh.raw;
 		int len = ntohs(ph->length);
-		skb_pull(skb, sizeof(struct pppoe_hdr));
-		skb_postpull_rcsum(skb, ph, sizeof(*ph));
+		skb_pull_rcsum(skb, sizeof(struct pppoe_hdr));
 		if (pskb_trim_rcsum(skb, len))
 			goto abort_kfree;
 
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index 75c9631..613b951 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -1159,12 +1159,14 @@
  */
 
 static inline void skb_postpull_rcsum(struct sk_buff *skb,
-					 const void *start, int len)
+				      const void *start, unsigned int len)
 {
 	if (skb->ip_summed == CHECKSUM_HW)
 		skb->csum = csum_sub(skb->csum, csum_partial(start, len, 0));
 }
 
+unsigned char *skb_pull_rcsum(struct sk_buff *skb, unsigned int len);
+
 /**
  *	pskb_trim_rcsum - trim received skb and update checksum
  *	@skb: buffer to trim
diff --git a/net/802/psnap.c b/net/802/psnap.c
index 34e4296..97c95ee 100644
--- a/net/802/psnap.c
+++ b/net/802/psnap.c
@@ -61,8 +61,7 @@
 		/* Pass the frame on. */
 		u8 *hdr = skb->data;
 		skb->h.raw  += 5;
-		skb_pull(skb, 5);
-		skb_postpull_rcsum(skb, hdr, 5);
+		skb_pull_rcsum(skb, 5);
 		rc = proto->rcvfunc(skb, dev, &snap_packet_type, orig_dev);
 	} else {
 		skb->sk = NULL;
diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c
index 0f604d22..da9cfe9 100644
--- a/net/8021q/vlan_dev.c
+++ b/net/8021q/vlan_dev.c
@@ -163,10 +163,8 @@
 	stats->rx_packets++;
 	stats->rx_bytes += skb->len;
 
-	skb_pull(skb, VLAN_HLEN); /* take off the VLAN header (4 bytes currently) */
-
-	/* Need to correct hardware checksum */
-	skb_postpull_rcsum(skb, vhdr, VLAN_HLEN);
+	/* Take off the VLAN header (4 bytes currently) */
+	skb_pull_rcsum(skb, VLAN_HLEN);
 
 	/* Ok, lets check to make sure the device (dev) we
 	 * came in on is what this VLAN is attached to.
diff --git a/net/bridge/br_netfilter.c b/net/bridge/br_netfilter.c
index e060aad..6787bc5 100644
--- a/net/bridge/br_netfilter.c
+++ b/net/bridge/br_netfilter.c
@@ -425,8 +425,7 @@
 
 		if (skb->protocol == __constant_htons(ETH_P_8021Q)) {
 			u8 *vhdr = skb->data;
-			skb_pull(skb, VLAN_HLEN);
-			skb_postpull_rcsum(skb, vhdr, VLAN_HLEN);
+			skb_pull_rcsum(skb, VLAN_HLEN);
 			skb->nh.raw += VLAN_HLEN;
 		}
 		return br_nf_pre_routing_ipv6(hook, skb, in, out, okfn);
@@ -444,8 +443,7 @@
 
 	if (skb->protocol == __constant_htons(ETH_P_8021Q)) {
 		u8 *vhdr = skb->data;
-		skb_pull(skb, VLAN_HLEN);
-		skb_postpull_rcsum(skb, vhdr, VLAN_HLEN);
+		skb_pull_rcsum(skb, VLAN_HLEN);
 		skb->nh.raw += VLAN_HLEN;
 	}
 
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index 01abf1e..2960c8b 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -1795,6 +1795,27 @@
 	return 0;
 }
 
+/**
+ *	skb_pull_rcsum - pull skb and update receive checksum
+ *	@skb: buffer to update
+ *	@start: start of data before pull
+ *	@len: length of data pulled
+ *
+ *	This function performs an skb_pull on the packet and updates
+ *	update the CHECKSUM_HW checksum.  It should be used on receive
+ *	path processing instead of skb_pull unless you know that the
+ *	checksum difference is zero (e.g., a valid IP header) or you
+ *	are setting ip_summed to CHECKSUM_NONE.
+ */
+unsigned char *skb_pull_rcsum(struct sk_buff *skb, unsigned int len)
+{
+	BUG_ON(len > skb->len);
+	skb->len -= len;
+	BUG_ON(skb->len < skb->data_len);
+	skb_postpull_rcsum(skb, skb->data, len);
+	return skb->data += len;
+}
+
 void __init skb_init(void)
 {
 	skbuff_head_cache = kmem_cache_create("skbuff_head_cache",