Module: xenomai-3 Branch: wip/rtnet-fixes Commit: 968caacaf6c34ddd91d86bcc773b2d8fa74bb511 URL: http://git.xenomai.org/?p=xenomai-3.git;a=commit;h=968caacaf6c34ddd91d86bcc773b2d8fa74bb511
Author: Philippe Gerum <r...@xenomai.org> Date: Wed Dec 6 12:45:58 2017 +0100 net/udp: sendmsg: remove direct references to user memory --- kernel/drivers/net/stack/ipv4/udp/udp.c | 126 +++++++++++++++++++------------ 1 file changed, 79 insertions(+), 47 deletions(-) diff --git a/kernel/drivers/net/stack/ipv4/udp/udp.c b/kernel/drivers/net/stack/ipv4/udp/udp.c index 4ec5ab3..c460e40 100644 --- a/kernel/drivers/net/stack/ipv4/udp/udp.c +++ b/kernel/drivers/net/stack/ipv4/udp/udp.c @@ -515,6 +515,7 @@ struct udpfakehdr struct udphdr uh; u32 daddr; u32 saddr; + struct rtdm_fd *fd; struct iovec *iov; int iovlen; u32 wcheck; @@ -529,35 +530,36 @@ static int rt_udp_getfrag(const void *p, unsigned char *to, unsigned int offset, unsigned int fraglen) { struct udpfakehdr *ufh = (struct udpfakehdr *)p; - int i; + int i, ret; // We should optimize this function a bit (copy+csum...)! - if (offset==0) { - /* Checksum of the complete data part of the UDP message: */ - for (i = 0; i < ufh->iovlen; i++) { + if (offset) + return rtnet_read_from_iov(ufh->fd, ufh->iov, ufh->iovlen, to, fraglen); + + /* Checksum of the complete data part of the UDP message: */ + for (i = 0; i < ufh->iovlen; i++) { ufh->wcheck = csum_partial(ufh->iov[i].iov_base, ufh->iov[i].iov_len, ufh->wcheck); - } - - rt_memcpy_fromkerneliovec(to + sizeof(struct udphdr), ufh->iov, - fraglen - sizeof(struct udphdr)); + } - /* Checksum of the udp header: */ - ufh->wcheck = csum_partial((unsigned char *)ufh, - sizeof(struct udphdr), ufh->wcheck); + ret = rtnet_read_from_iov(ufh->fd, ufh->iov, ufh->iovlen, + to + sizeof(struct udphdr), + fraglen - sizeof(struct udphdr)); + if (ret) + return ret; - ufh->uh.check = csum_tcpudp_magic(ufh->saddr, ufh->daddr, ntohs(ufh->uh.len), - IPPROTO_UDP, ufh->wcheck); + /* Checksum of the udp header: */ + ufh->wcheck = csum_partial((unsigned char *)ufh, + sizeof(struct udphdr), ufh->wcheck); + + ufh->uh.check = csum_tcpudp_magic(ufh->saddr, ufh->daddr, ntohs(ufh->uh.len), + IPPROTO_UDP, ufh->wcheck); - if (ufh->uh.check == 0) + if (ufh->uh.check == 0) ufh->uh.check = -1; - memcpy(to, ufh, sizeof(struct udphdr)); - return 0; - } - - rt_memcpy_fromkerneliovec(to, ufh->iov, fraglen); + memcpy(to, ufh, sizeof(struct udphdr)); return 0; } @@ -570,9 +572,9 @@ static int rt_udp_getfrag(const void *p, unsigned char *to, ssize_t rt_udp_sendmsg(struct rtdm_fd *fd, const 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); - int ulen = len + sizeof(struct udphdr); - struct sockaddr_in *usin; + size_t len; + int ulen; + struct sockaddr_in _sin, *sin; struct udpfakehdr ufh; struct dest_route rt; u32 saddr; @@ -580,10 +582,8 @@ ssize_t rt_udp_sendmsg(struct rtdm_fd *fd, const struct user_msghdr *msg, int ms u16 dport; int err; rtdm_lockctx_t context; - - - if ((len < 0) || (len > 0xFFFF-sizeof(struct iphdr)-sizeof(struct udphdr))) - return -EMSGSIZE; + struct user_msghdr _msg; + struct iovec iov_fast[RTDM_IOV_FASTMAX], *iov; if (msg_flags & MSG_OOB) /* Mirror BSD error message compatibility */ return -EOPNOTSUPP; @@ -591,39 +591,70 @@ ssize_t rt_udp_sendmsg(struct rtdm_fd *fd, const struct user_msghdr *msg, int ms if (msg_flags & ~(MSG_DONTROUTE|MSG_DONTWAIT) ) return -EINVAL; - if ((msg->msg_name) && (msg->msg_namelen==sizeof(struct sockaddr_in))) { - usin = (struct sockaddr_in*) msg->msg_name; + msg = rtnet_get_arg(fd, &_msg, msg, sizeof(*msg)); + if (IS_ERR(msg)) + return PTR_ERR(msg); - if ((usin->sin_family != AF_INET) && (usin->sin_family != AF_UNSPEC)) - return -EINVAL; + if (msg->msg_iovlen < 0) + return -EINVAL; + + if (msg->msg_iovlen == 0) + return 0; + + err = rtdm_get_iovec(fd, &iov, msg, iov_fast); + if (err) + return err; - daddr = usin->sin_addr.s_addr; - dport = usin->sin_port; + len = rt_iovec_len(iov, msg->msg_iovlen); + if ((len < 0) || (len > 0xFFFF-sizeof(struct iphdr)-sizeof(struct udphdr))) { + err = -EMSGSIZE; + goto out; + } - rtdm_lock_get_irqsave(&udp_socket_base_lock, context); + ulen = len + sizeof(struct udphdr); + + if (msg->msg_name && msg->msg_namelen == sizeof(*sin)) { + sin = rtnet_get_arg(fd, &_sin, msg->msg_name, sizeof(_sin)); + if (IS_ERR(sin)) { + err = PTR_ERR(sin); + goto out; + } + + if (sin->sin_family != AF_INET && sin->sin_family != AF_UNSPEC) { + err = -EINVAL; + goto out; + } + + daddr = sin->sin_addr.s_addr; + dport = sin->sin_port; + rtdm_lock_get_irqsave(&udp_socket_base_lock, context); } else { - rtdm_lock_get_irqsave(&udp_socket_base_lock, context); + rtdm_lock_get_irqsave(&udp_socket_base_lock, context); - if (sock->prot.inet.state != TCP_ESTABLISHED) { - rtdm_lock_put_irqrestore(&udp_socket_base_lock, context); - return -ENOTCONN; - } + if (sock->prot.inet.state != TCP_ESTABLISHED) { + rtdm_lock_put_irqrestore(&udp_socket_base_lock, context); + err = -ENOTCONN; + goto out; + } - daddr = sock->prot.inet.daddr; - dport = sock->prot.inet.dport; + daddr = sock->prot.inet.daddr; + dport = sock->prot.inet.dport; } + saddr = sock->prot.inet.saddr; ufh.uh.source = sock->prot.inet.sport; rtdm_lock_put_irqrestore(&udp_socket_base_lock, context); - if ((daddr | dport) == 0) - return -EINVAL; + if ((daddr | dport) == 0) { + err = -EINVAL; + goto out; + } /* get output route */ err = rt_ip_route_output(&rt, daddr, saddr); if (err) - return err; + goto out; /* we found a route, remember the routing dest-addr could be the netmask */ ufh.saddr = saddr != INADDR_ANY ? saddr : rt.rtdev->local_ip; @@ -631,18 +662,19 @@ ssize_t rt_udp_sendmsg(struct rtdm_fd *fd, const struct user_msghdr *msg, int ms ufh.uh.dest = dport; ufh.uh.len = htons(ulen); ufh.uh.check = 0; + ufh.fd = fd; ufh.iov = msg->msg_iov; ufh.iovlen = msg->msg_iovlen; ufh.wcheck = 0; err = rt_ip_build_xmit(sock, rt_udp_getfrag, &ufh, ulen, &rt, msg_flags); + /* Drop the reference obtained in rt_ip_route_output() */ rtdev_dereference(rt.rtdev); +out: + rtdm_drop_iovec(iov, iov_fast); - if (!err) - return len; - else - return err; + return err ?: len; } _______________________________________________ Xenomai-git mailing list Xenomai-git@xenomai.org https://xenomai.org/mailman/listinfo/xenomai-git