patch-2.1.8 linux/net/core/iovec.c

Next file: linux/net/core/skbuff.c
Previous file: linux/net/core/dev.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.1.7/linux/net/core/iovec.c linux/net/core/iovec.c
@@ -9,6 +9,8 @@
  *
  *	Fixes:
  *		Andrew Lunn	:	Errors in iovec copying.
+ *		Pedro Roque	:	Added memcpy_fromiovecend and
+ *					csum_..._fromiovecend.
  */
 
 
@@ -17,8 +19,10 @@
 #include <linux/kernel.h>
 #include <linux/mm.h>
 #include <linux/net.h>
+#include <linux/in6.h>
 #include <asm/uaccess.h>
-
+#include <asm/byteorder.h>
+#include <asm/checksum.h>
 
 extern inline int min(int x, int y)
 {
@@ -103,4 +107,131 @@
 		}
 		iov++;
 	}
+}
+
+
+/*
+ *	For use with ip_build_xmit
+ */
+
+void memcpy_fromiovecend(unsigned char *kdata, struct iovec *iov, int offset, 
+			 int len)
+{
+	while(offset>0)
+	{
+		if (offset > iov->iov_len)
+		{
+			offset -= iov->iov_len;
+
+		}
+		else
+		{
+			u8 *base;
+			int copy;
+
+			base = iov->iov_base + offset;
+			copy = min(len, iov->iov_len - offset);
+			offset = 0;
+
+			copy_from_user(kdata, base, copy);
+			len-=copy;
+			kdata+=copy;
+		}
+		iov++;	
+	}
+
+	while (len>0)
+	{
+		int copy=min(len, iov->iov_len);
+		copy_from_user(kdata, iov->iov_base, copy);
+		len-=copy;
+		kdata+=copy;
+		iov++;
+	}
+}
+
+/*
+ *	And now for the all-in-one: copy and checksum from a user iovec
+ *	directly to a datagram
+ *	Calls to csum_partial but the last must be in 32 bit chunks
+ *
+ *	ip_build_xmit must ensure that when fragmenting only the last
+ *	call to this function will be unaligned also.
+ */
+
+unsigned int csum_partial_copy_fromiovecend(unsigned char *kdata, 
+					    struct iovec *iov, int offset, 
+					    int len, int csum)
+{
+	__u32	partial;
+	__u32	partial_cnt = 0;
+
+	while(offset>0)
+	{
+		if (offset > iov->iov_len)
+		{
+			offset -= iov->iov_len;
+
+		}
+		else
+		{
+			u8 *base;
+			int copy;
+
+			base = iov->iov_base + offset;
+			copy = min(len, iov->iov_len - offset);
+			offset = 0;
+
+			partial_cnt = copy % 4;
+			if (partial_cnt)
+			{
+				copy -= partial_cnt;
+				copy_from_user(&partial, base + copy,
+					       partial_cnt);
+			}
+
+			csum = csum_partial_copy_fromuser(base, kdata, 
+							  copy, csum);
+
+			len   -= copy + partial_cnt;
+			kdata += copy + partial_cnt;
+		}
+		iov++;			
+	}
+
+	while (len>0)
+	{
+		u8 *base = iov->iov_base;
+		int copy=min(len, iov->iov_len);
+		
+		if (partial_cnt)
+		{
+			int par_len = 4 - partial_cnt;
+
+			copy_from_user(&partial, base + partial_cnt, par_len);
+			csum = csum_partial((u8*) &partial, 4, csum);
+			base += par_len;
+			copy -= par_len;
+			partial_cnt = 0;
+		}
+
+		if (len - copy > 0)
+		{
+			partial_cnt = copy % 4;
+			if (partial_cnt)
+			{
+				copy -= partial_cnt;
+				copy_from_user(&partial, base + copy,
+					       partial_cnt);
+			}
+		}
+
+		csum = csum_partial_copy_fromuser(base, kdata, 
+						  copy, csum);
+		len   -= copy + partial_cnt;
+		kdata += copy + partial_cnt;
+		iov++;
+	}
+
+	return csum;
 }

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov