patch-2.1.31 linux/net/ipv4/udp.c
Next file: linux/net/netlink.c
Previous file: linux/net/ipv4/timer.c
Back to the patch index
Back to the overall index
- Lines: 195
- Date:
Wed Apr 2 17:45:33 1997
- Orig file:
v2.1.30/linux/net/ipv4/udp.c
- Orig date:
Thu Mar 27 14:40:16 1997
diff -u --recursive --new-file v2.1.30/linux/net/ipv4/udp.c linux/net/ipv4/udp.c
@@ -52,6 +52,7 @@
* David S. Miller : New socket lookup architecture.
* Last socket cache retained as it
* does have a high hit rate.
+ * Olaf Kirch : Don't linearise iovec on sendmsg.
*
*
* This program is free software; you can redistribute it and/or
@@ -505,7 +506,8 @@
u32 saddr;
u32 daddr;
u32 other;
- const char *from;
+ struct iovec *iov;
+ int nriov;
u32 wcheck;
};
@@ -519,20 +521,36 @@
static int udp_getfrag(const void *p, char * to, unsigned int offset, unsigned int fraglen)
{
struct udpfakehdr *ufh = (struct udpfakehdr *)p;
- const char *src;
- char *dst;
+ struct iovec *iov;
+ char *src;
+ char *dst = to;
unsigned int len;
- if (offset) {
- len = fraglen;
- src = ufh->from+(offset-sizeof(struct udphdr));
- dst = to;
- } else {
- len = fraglen-sizeof(struct udphdr);
- src = ufh->from;
- dst = to+sizeof(struct udphdr);
+ if (offset == 0) {
+ fraglen -= sizeof(struct udphdr);
+ dst += sizeof(struct udphdr);
}
- ufh->wcheck = csum_partial_copy_fromuser(src, dst, len, ufh->wcheck);
+
+ iov = ufh->iov;
+ do {
+ if ((len = iov->iov_len) > fraglen)
+ len = fraglen;
+ src = (char *) iov->iov_base + iov->iov_len - len;
+ ufh->wcheck = csum_partial_copy_fromuser(src,
+ dst + fraglen - len, len,
+ ufh->wcheck);
+ if ((iov->iov_len -= len) == 0) {
+ if (--(ufh->nriov) < 0) {
+ printk(KERN_NOTICE "udp_getfrag: nriov = %d\n",
+ ufh->nriov);
+ return -EINVAL;
+ }
+ iov--;
+ }
+ fraglen -= len;
+ } while (fraglen);
+ ufh->iov = iov;
+
if (offset == 0) {
ufh->wcheck = csum_partial((char *)ufh, sizeof(struct udphdr),
ufh->wcheck);
@@ -556,29 +574,42 @@
static int udp_getfrag_nosum(const void *p, char * to, unsigned int offset, unsigned int fraglen)
{
struct udpfakehdr *ufh = (struct udpfakehdr *)p;
- const char *src;
- char *dst;
+ struct iovec *iov;
+ char *src;
+ char *dst = to;
int err;
unsigned int len;
- if (offset) {
- len = fraglen;
- src = ufh->from+(offset-sizeof(struct udphdr));
- dst = to;
- } else {
- len = fraglen-sizeof(struct udphdr);
- src = ufh->from;
- dst = to+sizeof(struct udphdr);
+ if (offset == 0) {
+ fraglen -= sizeof(struct udphdr);
+ dst += sizeof(struct udphdr);
}
- err = copy_from_user(dst,src,len);
+
+ iov = ufh->iov;
+ do {
+ if ((len = iov->iov_len) > fraglen)
+ len = fraglen;
+ src = (char *) iov->iov_base + iov->iov_len - len;
+ err = copy_from_user(dst + fraglen - len, src, len);
+ fraglen -= len;
+ if ((iov->iov_len -= len) == 0) {
+ if (--(ufh->nriov) < 0) {
+ printk(KERN_NOTICE "udp_getfrag: nriov = %d\n",
+ ufh->nriov);
+ return -EINVAL;
+ }
+ iov--;
+ }
+ } while (fraglen && err >= 0);
+ ufh->iov = iov;
+
if (offset == 0)
memcpy(to, ufh, sizeof(struct udphdr));
return err;
}
-static int udp_sendto(struct sock *sk, const unsigned char *from, int len,
- struct msghdr *msg)
+int udp_sendmsg(struct sock *sk, struct msghdr *msg, int len)
{
int ulen = len + sizeof(struct udphdr);
struct device *dev = NULL;
@@ -675,7 +706,8 @@
ufh.uh.len = htons(ulen);
ufh.uh.check = 0;
ufh.other = (htons(ulen) << 16) + IPPROTO_UDP*256;
- ufh.from = from;
+ ufh.iov = msg->msg_iov + msg->msg_iovlen - 1;
+ ufh.nriov = msg->msg_iovlen;
ufh.wcheck = 0;
/* RFC1122: OK. Provides the checksumming facility (MUST) as per */
@@ -703,44 +735,6 @@
}
/*
- * Temporary
- */
-
-int udp_sendmsg(struct sock *sk, struct msghdr *msg, int len)
-{
- if(msg->msg_iovlen==1)
- return udp_sendto(sk,msg->msg_iov[0].iov_base,len, msg);
- else {
- /*
- * For awkward cases we linearise the buffer first. In theory this is only frames
- * whose iovec's don't split on 4 byte boundaries, and soon encrypted stuff (to keep
- * skip happy). We are a bit more general about it.
- */
-
- unsigned char *buf;
- int fs;
- int err;
- if(len>65515)
- return -EMSGSIZE;
- buf=kmalloc(len, GFP_KERNEL);
- if(buf==NULL)
- return -ENOBUFS;
- err = memcpy_fromiovec(buf, msg->msg_iov, len);
- if (err)
- err = -EFAULT;
- if (!err)
- {
- fs=get_fs();
- set_fs(get_ds());
- err=udp_sendto(sk,buf,len, msg);
- set_fs(fs);
- }
- kfree_s(buf,len);
- return err;
- }
-}
-
-/*
* IOCTL requests applicable to the UDP protocol
*/
@@ -1063,7 +1057,7 @@
ulen = ntohs(uh->len);
if (ulen > len || len < sizeof(*uh) || ulen < sizeof(*uh)) {
- NETDEBUG(printk("UDP: short packet: %d/%d\n", ulen, len));
+ NETDEBUG(printk(KERN_DEBUG "UDP: short packet: %d/%d\n", ulen, len));
udp_statistics.UdpInErrors++;
kfree_skb(skb, FREE_WRITE);
return(0);
@@ -1086,7 +1080,7 @@
/* RFC1122: OK. Discards the bad packet silently (as far as */
/* the network is concerned, anyway) as per 4.1.3.4 (MUST). */
- NETDEBUG(printk("UDP: bad checksum. From %08lX:%d to %08lX:%d ulen %d\n",
+ NETDEBUG(printk(KERN_DEBUG "UDP: bad checksum. From %08lX:%d to %08lX:%d ulen %d\n",
ntohl(saddr),ntohs(uh->source),
ntohl(daddr),ntohs(uh->dest),
ulen));
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov