Commit a69c4ac5 authored by Philippe Gerum's avatar Philippe Gerum
Browse files

net/udp: sendmsg: remove direct references to user memory

parent 1fc267b5
...@@ -534,6 +534,7 @@ struct udpfakehdr ...@@ -534,6 +534,7 @@ struct udpfakehdr
struct udphdr uh; struct udphdr uh;
u32 daddr; u32 daddr;
u32 saddr; u32 saddr;
struct rtdm_fd *fd;
struct iovec *iov; struct iovec *iov;
int iovlen; int iovlen;
u32 wcheck; u32 wcheck;
...@@ -548,35 +549,36 @@ static int rt_udp_getfrag(const void *p, unsigned char *to, ...@@ -548,35 +549,36 @@ static int rt_udp_getfrag(const void *p, unsigned char *to,
unsigned int offset, unsigned int fraglen) unsigned int offset, unsigned int fraglen)
{ {
struct udpfakehdr *ufh = (struct udpfakehdr *)p; struct udpfakehdr *ufh = (struct udpfakehdr *)p;
int i; int i, ret;
// We should optimize this function a bit (copy+csum...)! // We should optimize this function a bit (copy+csum...)!
if (offset==0) { if (offset)
/* Checksum of the complete data part of the UDP message: */ return rtnet_read_from_iov(ufh->fd, ufh->iov, ufh->iovlen, to, fraglen);
for (i = 0; i < ufh->iovlen; i++) {
/* 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 = csum_partial(ufh->iov[i].iov_base, ufh->iov[i].iov_len,
ufh->wcheck); ufh->wcheck);
} }
rt_memcpy_fromkerneliovec(to + sizeof(struct udphdr), ufh->iov,
fraglen - sizeof(struct udphdr));
/* Checksum of the udp header: */ ret = rtnet_read_from_iov(ufh->fd, ufh->iov, ufh->iovlen,
ufh->wcheck = csum_partial((unsigned char *)ufh, to + sizeof(struct udphdr),
sizeof(struct udphdr), ufh->wcheck); fraglen - sizeof(struct udphdr));
if (ret)
return ret;
ufh->uh.check = csum_tcpudp_magic(ufh->saddr, ufh->daddr, ntohs(ufh->uh.len), /* Checksum of the udp header: */
IPPROTO_UDP, ufh->wcheck); 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; ufh->uh.check = -1;
memcpy(to, ufh, sizeof(struct udphdr)); memcpy(to, ufh, sizeof(struct udphdr));
return 0;
}
rt_memcpy_fromkerneliovec(to, ufh->iov, fraglen);
return 0; return 0;
} }
...@@ -589,9 +591,9 @@ static int rt_udp_getfrag(const void *p, unsigned char *to, ...@@ -589,9 +591,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) 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); struct rtsocket *sock = rtdm_fd_to_private(fd);
size_t len = rt_iovec_len(msg->msg_iov, msg->msg_iovlen); size_t len;
int ulen = len + sizeof(struct udphdr); int ulen;
struct sockaddr_in *usin; struct sockaddr_in _sin, *sin;
struct udpfakehdr ufh; struct udpfakehdr ufh;
struct dest_route rt; struct dest_route rt;
u32 saddr; u32 saddr;
...@@ -599,10 +601,8 @@ ssize_t rt_udp_sendmsg(struct rtdm_fd *fd, const struct user_msghdr *msg, int ms ...@@ -599,10 +601,8 @@ ssize_t rt_udp_sendmsg(struct rtdm_fd *fd, const struct user_msghdr *msg, int ms
u16 dport; u16 dport;
int err; int err;
rtdm_lockctx_t context; rtdm_lockctx_t context;
struct user_msghdr _msg;
struct iovec iov_fast[RTDM_IOV_FASTMAX], *iov;
if ((len < 0) || (len > 0xFFFF-sizeof(struct iphdr)-sizeof(struct udphdr)))
return -EMSGSIZE;
if (msg_flags & MSG_OOB) /* Mirror BSD error message compatibility */ if (msg_flags & MSG_OOB) /* Mirror BSD error message compatibility */
return -EOPNOTSUPP; return -EOPNOTSUPP;
...@@ -610,39 +610,70 @@ ssize_t rt_udp_sendmsg(struct rtdm_fd *fd, const struct user_msghdr *msg, int ms ...@@ -610,39 +610,70 @@ ssize_t rt_udp_sendmsg(struct rtdm_fd *fd, const struct user_msghdr *msg, int ms
if (msg_flags & ~(MSG_DONTROUTE|MSG_DONTWAIT) ) if (msg_flags & ~(MSG_DONTROUTE|MSG_DONTWAIT) )
return -EINVAL; return -EINVAL;
if ((msg->msg_name) && (msg->msg_namelen==sizeof(struct sockaddr_in))) { msg = rtnet_get_arg(fd, &_msg, msg, sizeof(*msg));
usin = (struct sockaddr_in*) msg->msg_name; if (IS_ERR(msg))
return PTR_ERR(msg);
if ((usin->sin_family != AF_INET) && (usin->sin_family != AF_UNSPEC)) if (msg->msg_iovlen < 0)
return -EINVAL; return -EINVAL;
if (msg->msg_iovlen == 0)
return 0;
err = rtdm_get_iovec(fd, &iov, msg, iov_fast);
if (err)
return err;
len = rt_iovec_len(iov, msg->msg_iovlen);
if ((len < 0) || (len > 0xFFFF-sizeof(struct iphdr)-sizeof(struct udphdr))) {
err = -EMSGSIZE;
goto out;
}
daddr = usin->sin_addr.s_addr; ulen = len + sizeof(struct udphdr);
dport = usin->sin_port;
rtdm_lock_get_irqsave(&udp_socket_base_lock, context); 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 { } 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) { if (sock->prot.inet.state != TCP_ESTABLISHED) {
rtdm_lock_put_irqrestore(&udp_socket_base_lock, context); rtdm_lock_put_irqrestore(&udp_socket_base_lock, context);
return -ENOTCONN; err = -ENOTCONN;
} goto out;
}
daddr = sock->prot.inet.daddr; daddr = sock->prot.inet.daddr;
dport = sock->prot.inet.dport; dport = sock->prot.inet.dport;
} }
saddr = sock->prot.inet.saddr; saddr = sock->prot.inet.saddr;
ufh.uh.source = sock->prot.inet.sport; ufh.uh.source = sock->prot.inet.sport;
rtdm_lock_put_irqrestore(&udp_socket_base_lock, context); rtdm_lock_put_irqrestore(&udp_socket_base_lock, context);
if ((daddr | dport) == 0) if ((daddr | dport) == 0) {
return -EINVAL; err = -EINVAL;
goto out;
}
/* get output route */ /* get output route */
err = rt_ip_route_output(&rt, daddr, saddr); err = rt_ip_route_output(&rt, daddr, saddr);
if (err) if (err)
return err; goto out;
/* we found a route, remember the routing dest-addr could be the netmask */ /* we found a route, remember the routing dest-addr could be the netmask */
ufh.saddr = saddr != INADDR_ANY ? saddr : rt.rtdev->local_ip; ufh.saddr = saddr != INADDR_ANY ? saddr : rt.rtdev->local_ip;
...@@ -650,18 +681,19 @@ ssize_t rt_udp_sendmsg(struct rtdm_fd *fd, const struct user_msghdr *msg, int ms ...@@ -650,18 +681,19 @@ ssize_t rt_udp_sendmsg(struct rtdm_fd *fd, const struct user_msghdr *msg, int ms
ufh.uh.dest = dport; ufh.uh.dest = dport;
ufh.uh.len = htons(ulen); ufh.uh.len = htons(ulen);
ufh.uh.check = 0; ufh.uh.check = 0;
ufh.fd = fd;
ufh.iov = msg->msg_iov; ufh.iov = msg->msg_iov;
ufh.iovlen = msg->msg_iovlen; ufh.iovlen = msg->msg_iovlen;
ufh.wcheck = 0; ufh.wcheck = 0;
err = rt_ip_build_xmit(sock, rt_udp_getfrag, &ufh, ulen, &rt, msg_flags); 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); rtdev_dereference(rt.rtdev);
out:
rtdm_drop_iovec(iov, iov_fast);
if (!err) return err ?: len;
return len;
else
return err;
} }
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment