[NET]: Revert sk_buff walker cleanups.

This reverts eefa3906283a2b60a6d02a2cda593a7d7d7946c5

The simplification made in that change works with the assumption that
the 'offset' parameter to these functions is always positive or zero,
which is not true.  It can be and often is negative in order to access
SKB header values in front of skb->data.

Signed-off-by: David S. Miller <davem@davemloft.net>
diff --git a/net/core/datagram.c b/net/core/datagram.c
index e1afa76..cb056f4 100644
--- a/net/core/datagram.c
+++ b/net/core/datagram.c
@@ -247,8 +247,8 @@
 int skb_copy_datagram_iovec(const struct sk_buff *skb, int offset,
 			    struct iovec *to, int len)
 {
-	int end = skb_headlen(skb);
-	int i, copy = end - offset;
+	int start = skb_headlen(skb);
+	int i, copy = start - offset;
 
 	/* Copy header. */
 	if (copy > 0) {
@@ -263,9 +263,11 @@
 
 	/* Copy paged appendix. Hmm... why does this look so complicated? */
 	for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
-		BUG_TRAP(len >= 0);
+		int end;
 
-		end = offset + skb_shinfo(skb)->frags[i].size;
+		BUG_TRAP(start <= offset + len);
+
+		end = start + skb_shinfo(skb)->frags[i].size;
 		if ((copy = end - offset) > 0) {
 			int err;
 			u8  *vaddr;
@@ -275,8 +277,8 @@
 			if (copy > len)
 				copy = len;
 			vaddr = kmap(page);
-			err = memcpy_toiovec(to, vaddr + frag->page_offset,
-					     copy);
+			err = memcpy_toiovec(to, vaddr + frag->page_offset +
+					     offset - start, copy);
 			kunmap(page);
 			if (err)
 				goto fault;
@@ -284,24 +286,30 @@
 				return 0;
 			offset += copy;
 		}
+		start = end;
 	}
 
 	if (skb_shinfo(skb)->frag_list) {
 		struct sk_buff *list = skb_shinfo(skb)->frag_list;
 
 		for (; list; list = list->next) {
-			BUG_TRAP(len >= 0);
+			int end;
 
-			end = offset + list->len;
+			BUG_TRAP(start <= offset + len);
+
+			end = start + list->len;
 			if ((copy = end - offset) > 0) {
 				if (copy > len)
 					copy = len;
-				if (skb_copy_datagram_iovec(list, 0, to, copy))
+				if (skb_copy_datagram_iovec(list,
+							    offset - start,
+							    to, copy))
 					goto fault;
 				if ((len -= copy) == 0)
 					return 0;
 				offset += copy;
 			}
+			start = end;
 		}
 	}
 	if (!len)
@@ -315,9 +323,9 @@
 				      u8 __user *to, int len,
 				      __wsum *csump)
 {
-	int end = skb_headlen(skb);
+	int start = skb_headlen(skb);
 	int pos = 0;
-	int i, copy = end - offset;
+	int i, copy = start - offset;
 
 	/* Copy header. */
 	if (copy > 0) {
@@ -336,9 +344,11 @@
 	}
 
 	for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
-		BUG_TRAP(len >= 0);
+		int end;
 
-		end = offset + skb_shinfo(skb)->frags[i].size;
+		BUG_TRAP(start <= offset + len);
+
+		end = start + skb_shinfo(skb)->frags[i].size;
 		if ((copy = end - offset) > 0) {
 			__wsum csum2;
 			int err = 0;
@@ -350,7 +360,8 @@
 				copy = len;
 			vaddr = kmap(page);
 			csum2 = csum_and_copy_to_user(vaddr +
-							frag->page_offset,
+							frag->page_offset +
+							offset - start,
 						      to, copy, 0, &err);
 			kunmap(page);
 			if (err)
@@ -362,20 +373,24 @@
 			to += copy;
 			pos += copy;
 		}
+		start = end;
 	}
 
 	if (skb_shinfo(skb)->frag_list) {
 		struct sk_buff *list = skb_shinfo(skb)->frag_list;
 
 		for (; list; list=list->next) {
-			BUG_TRAP(len >= 0);
+			int end;
 
-			end = offset + list->len;
+			BUG_TRAP(start <= offset + len);
+
+			end = start + list->len;
 			if ((copy = end - offset) > 0) {
 				__wsum csum2 = 0;
 				if (copy > len)
 					copy = len;
-				if (skb_copy_and_csum_datagram(list, 0,
+				if (skb_copy_and_csum_datagram(list,
+							       offset - start,
 							       to, copy,
 							       &csum2))
 					goto fault;
@@ -386,6 +401,7 @@
 				to += copy;
 				pos += copy;
 			}
+			start = end;
 		}
 	}
 	if (!len)