Signed-off-by: Sebastian Smolorz <[email protected]> --- kernel/drivers/net/stack/ipv4/ip_sock.c | 127 ++++++++++++++++-------- 1 file changed, 88 insertions(+), 39 deletions(-)
diff --git a/kernel/drivers/net/stack/ipv4/ip_sock.c b/kernel/drivers/net/stack/ipv4/ip_sock.c index 20f27feff..1ae3a9eeb 100644 --- a/kernel/drivers/net/stack/ipv4/ip_sock.c +++ b/kernel/drivers/net/stack/ipv4/ip_sock.c @@ -4,6 +4,7 @@ * * Copyright (C) 2003 Hans-Peter Bock <[email protected]> * 2004, 2005 Jan Kiszka <[email protected]> + * 2019 Sebastian Smolorz <[email protected]> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -28,11 +29,11 @@ #include <rtnet_socket.h> -int rt_ip_setsockopt(struct rtsocket *s, int level, int optname, - const void *optval, socklen_t optlen) +int rt_ip_setsockopt(struct rtdm_fd *fd, struct rtsocket *s, int level, + int optname, const void __user *optval, socklen_t optlen) { int err = 0; - + unsigned int _tos, *tos; if (level != SOL_IP) return -ENOPROTOOPT; @@ -42,7 +43,11 @@ int rt_ip_setsockopt(struct rtsocket *s, int level, int optname, switch (optname) { case IP_TOS: - s->prot.inet.tos = *(unsigned int *)optval; + tos = rtnet_get_arg(fd, &_tos, optval, sizeof(_tos)); + if (IS_ERR(tos)) + return PTR_ERR(tos); + else + s->prot.inet.tos = *tos; break; default: @@ -55,19 +60,29 @@ int rt_ip_setsockopt(struct rtsocket *s, int level, int optname, -int rt_ip_getsockopt(struct rtsocket *s, int level, int optname, - void *optval, socklen_t *optlen) +int rt_ip_getsockopt(struct rtdm_fd *fd, struct rtsocket *s, int level, + int optname, void __user *optval, + socklen_t __user *optlen) { int err = 0; + unsigned int tos; + socklen_t _len, *len; + len = rtnet_get_arg(fd, &_len, optlen, sizeof(_len)); + if (IS_ERR(len)) + return PTR_ERR(len); - if (*optlen < sizeof(unsigned int)) + if (*len < sizeof(unsigned int)) return -EINVAL; switch (optname) { case IP_TOS: - *(unsigned int *)optval = s->prot.inet.tos; - *optlen = sizeof(unsigned int); + tos = s->prot.inet.tos; + err = rtnet_put_arg(fd, optval, &tos, sizeof(tos)); + if (!err) { + *len = sizeof(unsigned int); + err = rtnet_put_arg(fd, optlen, len, sizeof(socklen_t)); + } break; default: @@ -80,72 +95,106 @@ int rt_ip_getsockopt(struct rtsocket *s, int level, int optname, -int rt_ip_getsockname(struct rtsocket *s, struct sockaddr *addr, - socklen_t *addrlen) +int rt_ip_getsockname(struct rtdm_fd *fd, struct rtsocket *s, + struct sockaddr __user *addr, + socklen_t __user *addrlen) { - struct sockaddr_in *usin = (struct sockaddr_in *)addr; + struct sockaddr_in _sin; + socklen_t *len, _len; + int ret; + len = rtnet_get_arg(fd, &_len, addrlen, sizeof(_len)); + if (IS_ERR(len)) + return PTR_ERR(len); - if (*addrlen < sizeof(struct sockaddr_in)) + if (*len < sizeof(struct sockaddr_in)) return -EINVAL; - usin->sin_family = AF_INET; - usin->sin_addr.s_addr = s->prot.inet.saddr; - usin->sin_port = s->prot.inet.sport; - - memset(usin->sin_zero, 0, sizeof(usin->sin_zero)); + _sin.sin_family = AF_INET; + _sin.sin_addr.s_addr = s->prot.inet.saddr; + _sin.sin_port = s->prot.inet.sport; + memset(&_sin.sin_zero, 0, sizeof(_sin.sin_zero)); + ret = rtnet_put_arg(fd, addr, &_sin, sizeof(_sin)); + if (ret) + return ret; - *addrlen = sizeof(struct sockaddr_in); + *len = sizeof(struct sockaddr_in); + ret = rtnet_put_arg(fd, addrlen, len, sizeof(socklen_t)); - return 0; + return ret; } -int rt_ip_getpeername(struct rtsocket *s, struct sockaddr *addr, - socklen_t *addrlen) +int rt_ip_getpeername(struct rtdm_fd *fd, struct rtsocket *s, + struct sockaddr __user *addr, + socklen_t __user *addrlen) { - struct sockaddr_in *usin = (struct sockaddr_in *)addr; + struct sockaddr_in _sin; + socklen_t *len, _len; + int ret; + len = rtnet_get_arg(fd, &_len, addrlen, sizeof(_len)); + if (IS_ERR(len)) + return PTR_ERR(len); - if (*addrlen < sizeof(struct sockaddr_in)) + if (*len < sizeof(struct sockaddr_in)) return -EINVAL; - usin->sin_family = AF_INET; - usin->sin_addr.s_addr = s->prot.inet.daddr; - usin->sin_port = s->prot.inet.dport; + _sin.sin_family = AF_INET; + _sin.sin_addr.s_addr = s->prot.inet.daddr; + _sin.sin_port = s->prot.inet.dport; + memset(&_sin.sin_zero, 0, sizeof(_sin.sin_zero)); + ret = rtnet_put_arg(fd, addr, &_sin, sizeof(_sin)); + if (ret) + return ret; - memset(usin->sin_zero, 0, sizeof(usin->sin_zero)); + *len = sizeof(struct sockaddr_in); + ret = rtnet_put_arg(fd, addrlen, len, sizeof(socklen_t)); - *addrlen = sizeof(struct sockaddr_in); - - return 0; + return ret; } -int rt_ip_ioctl(struct rtdm_fd *fd, int request, void *arg) +int rt_ip_ioctl(struct rtdm_fd *fd, int request, void __user *arg) { struct rtsocket *sock = rtdm_fd_to_private(fd); - struct _rtdm_getsockaddr_args *getaddr = arg; - struct _rtdm_getsockopt_args *getopt = arg; - struct _rtdm_setsockopt_args *setopt = arg; + struct _rtdm_getsockaddr_args _getaddr, *getaddr; + struct _rtdm_getsockopt_args _getopt, *getopt; + struct _rtdm_setsockopt_args _setopt, *setopt; switch (request) { case _RTIOC_SETSOCKOPT: - return rt_ip_setsockopt(sock, setopt->level, setopt->optname, + setopt = rtnet_get_arg(fd, &_setopt, arg, sizeof(_setopt)); + if (IS_ERR(setopt)) + return PTR_ERR(setopt); + + return rt_ip_setsockopt(fd, sock, setopt->level, setopt->optname, setopt->optval, setopt->optlen); case _RTIOC_GETSOCKOPT: - return rt_ip_getsockopt(sock, getopt->level, getopt->optname, + getopt = rtnet_get_arg(fd, &_getopt, arg, sizeof(_getopt)); + if (IS_ERR(getopt)) + return PTR_ERR(getopt); + + return rt_ip_getsockopt(fd, sock, getopt->level, getopt->optname, getopt->optval, getopt->optlen); case _RTIOC_GETSOCKNAME: - return rt_ip_getsockname(sock, getaddr->addr, getaddr->addrlen); + getaddr = rtnet_get_arg(fd, &_getaddr, arg, sizeof(_getaddr)); + if (IS_ERR(getaddr)) + return PTR_ERR(getaddr); + + return rt_ip_getsockname(fd, sock, getaddr->addr, getaddr->addrlen); case _RTIOC_GETPEERNAME: - return rt_ip_getpeername(sock, getaddr->addr, getaddr->addrlen); + getaddr = rtnet_get_arg(fd, &_getaddr, arg, sizeof(_getaddr)); + if (IS_ERR(getaddr)) + return PTR_ERR(getaddr); + + return rt_ip_getpeername(fd, sock, getaddr->addr, getaddr->addrlen); default: return rt_socket_if_ioctl(fd, request, arg); -- 2.19.1
