Module: xenomai-3 Branch: wip/rtnet-fixes Commit: 6670cf25851d474b3ac1b876d7369e15c6468c75 URL: http://git.xenomai.org/?p=xenomai-3.git;a=commit;h=6670cf25851d474b3ac1b876d7369e15c6468c75
Author: Philippe Gerum <r...@xenomai.org> Date: Wed Dec 6 12:45:31 2017 +0100 net/udp: recvmsg: remove direct references to user memory --- kernel/drivers/net/stack/ipv4/udp/udp.c | 95 +++++++++++++++++++++---------- 1 file changed, 65 insertions(+), 30 deletions(-) diff --git a/kernel/drivers/net/stack/ipv4/udp/udp.c b/kernel/drivers/net/stack/ipv4/udp/udp.c index f8eeadd..8284ff7 100644 --- a/kernel/drivers/net/stack/ipv4/udp/udp.c +++ b/kernel/drivers/net/stack/ipv4/udp/udp.c @@ -377,20 +377,39 @@ int rt_udp_ioctl(struct rtdm_fd *fd, unsigned int request, void __user *arg) /*** * rt_udp_recvmsg */ +/*** + * rt_udp_recvmsg + */ ssize_t rt_udp_recvmsg(struct rtdm_fd *fd, struct user_msghdr *msg, int msg_flags) { struct rtsocket *sock = rtdm_fd_to_private(fd); - size_t len = rt_iovec_len(msg->msg_iov, msg->msg_iovlen); + size_t len; struct rtskb *skb; struct rtskb *first_skb; size_t copied = 0; size_t block_size; size_t data_len; struct udphdr *uh; - struct sockaddr_in *sin; + struct sockaddr_in sin; nanosecs_rel_t timeout = sock->timeout; - int ret; + int ret, flags; + struct user_msghdr _msg; + socklen_t namelen; + struct iovec iov_fast[RTDM_IOV_FASTMAX], *iov; + + msg = rtnet_get_arg(fd, &_msg, msg, sizeof(*msg)); + if (IS_ERR(msg)) + return PTR_ERR(msg); + if (msg->msg_iovlen < 0) + return -EINVAL; + + if (msg->msg_iovlen == 0) + return 0; + + ret = rtdm_get_iovec(fd, &iov, msg, iov_fast); + if (ret) + return ret; /* non-blocking receive? */ if (msg_flags & MSG_DONTWAIT) @@ -398,35 +417,44 @@ ssize_t rt_udp_recvmsg(struct rtdm_fd *fd, struct user_msghdr *msg, int msg_flag ret = rtdm_sem_timeddown(&sock->pending_sem, timeout, NULL); if (unlikely(ret < 0)) - switch (ret) { - case -EWOULDBLOCK: - case -ETIMEDOUT: - case -EINTR: - return ret; - - default: - return -EBADF; /* socket has been closed */ - } + switch (ret) { + default: + ret = -EBADF; /* socket has been closed */ + case -EWOULDBLOCK: + case -ETIMEDOUT: + case -EINTR: + rtdm_drop_iovec(iov, iov_fast); + return ret; + } skb = rtskb_dequeue_chain(&sock->incoming); RTNET_ASSERT(skb != NULL, return -EFAULT;); - uh = skb->h.uh; - data_len = ntohs(uh->len) - sizeof(struct udphdr); - sin = msg->msg_name; + first_skb = skb; + namelen = sizeof(sin); + ret = rtnet_put_arg(fd, &msg->msg_namelen, &namelen, sizeof(namelen)); + if (ret) + goto fail; + /* copy the address */ - msg->msg_namelen = sizeof(*sin); - if (sin) { - sin->sin_family = AF_INET; - sin->sin_port = uh->source; - sin->sin_addr.s_addr = skb->nh.iph->saddr; + if (msg->msg_name) { + memset(&sin, 0, sizeof(sin)); + sin.sin_family = AF_INET; + sin.sin_port = uh->source; + sin.sin_addr.s_addr = skb->nh.iph->saddr; + ret = rtnet_put_arg(fd, &msg->msg_name, &sin, sizeof(sin)); + if (ret) + goto fail; } + data_len = ntohs(uh->len) - sizeof(struct udphdr); + /* remove the UDP header */ __rtskb_pull(skb, sizeof(struct udphdr)); - first_skb = skb; + flags = msg->msg_flags & ~MSG_TRUNC; + len = rt_iovec_len(iov, msg->msg_iovlen); /* iterate over all IP fragments */ do { @@ -440,25 +468,28 @@ ssize_t rt_udp_recvmsg(struct rtdm_fd *fd, struct user_msghdr *msg, int msg_flag if (copied > len) { block_size -= copied - len; copied = len; - msg->msg_flags |= MSG_TRUNC; - - /* copy the data */ - rt_memcpy_tokerneliovec(msg->msg_iov, skb->data, block_size); - - break; + flags |= MSG_TRUNC; } /* copy the data */ - rt_memcpy_tokerneliovec(msg->msg_iov, skb->data, block_size); + ret = rtnet_write_to_iov(fd, iov, msg->msg_iovlen, skb->data, block_size); + if (ret) + goto fail; /* next fragment */ skb = skb->next; - } while (skb != NULL); + } while (skb && !(flags & MSG_TRUNC)); /* did we copied all bytes? */ if (data_len > 0) - msg->msg_flags |= MSG_TRUNC; + flags |= MSG_TRUNC; + if (flags != msg->msg_flags) { + ret = rtnet_put_arg(fd, &msg->msg_flags, &flags, sizeof(flags)); + if (ret) + goto fail; + } +out: if ((msg_flags & MSG_PEEK) == 0) kfree_rtskb(first_skb); else { @@ -466,8 +497,12 @@ ssize_t rt_udp_recvmsg(struct rtdm_fd *fd, struct user_msghdr *msg, int msg_flag rtskb_queue_head(&sock->incoming, first_skb); rtdm_sem_up(&sock->pending_sem); } + rtdm_drop_iovec(iov, iov_fast); return copied; +fail: + copied = ret; + goto out; } _______________________________________________ Xenomai-git mailing list Xenomai-git@xenomai.org https://xenomai.org/mailman/listinfo/xenomai-git