Module: xenomai-3 Branch: wip/rtnet-fixes Commit: d0c48d747bb90cac8ab9f87896345c6898e6048b URL: http://git.xenomai.org/?p=xenomai-3.git;a=commit;h=d0c48d747bb90cac8ab9f87896345c6898e6048b
Author: Philippe Gerum <r...@xenomai.org> Date: Mon Dec 4 19:20:48 2017 +0100 net/socket: add get_arg/put_arg helpers --- kernel/drivers/net/stack/include/rtnet_socket.h | 10 +- kernel/drivers/net/stack/socket.c | 218 +++++++++++++++-------- 2 files changed, 150 insertions(+), 78 deletions(-) diff --git a/kernel/drivers/net/stack/include/rtnet_socket.h b/kernel/drivers/net/stack/include/rtnet_socket.h index cddf328..37f411a 100644 --- a/kernel/drivers/net/stack/include/rtnet_socket.h +++ b/kernel/drivers/net/stack/include/rtnet_socket.h @@ -88,6 +88,12 @@ static inline struct rtdm_fd *rt_socket_fd(struct rtsocket *sock) return rtdm_private_to_fd(sock); } +void *rtnet_get_arg(struct rtdm_fd *fd, void *tmp, + const void *src, size_t len); + +int rtnet_put_arg(struct rtdm_fd *fd, void *dst, + const void *src, size_t len); + #define rt_socket_reference(sock) \ rtdm_fd_lock(rt_socket_fd(sock)) #define rt_socket_dereference(sock) \ @@ -99,8 +105,8 @@ int __rt_socket_init(struct rtdm_fd *fd, unsigned short protocol, __rt_socket_init(fd, proto, THIS_MODULE) void rt_socket_cleanup(struct rtdm_fd *fd); -int rt_socket_common_ioctl(struct rtdm_fd *fd, int request, void *arg); -int rt_socket_if_ioctl(struct rtdm_fd *fd, int request, void *arg); +int rt_socket_common_ioctl(struct rtdm_fd *fd, int request, void __user *arg); +int rt_socket_if_ioctl(struct rtdm_fd *fd, int request, void __user *arg); int rt_socket_select_bind(struct rtdm_fd *fd, rtdm_selector_t *selector, enum rtdm_selecttype type, diff --git a/kernel/drivers/net/stack/socket.c b/kernel/drivers/net/stack/socket.c index 7dacb25..66665b2 100644 --- a/kernel/drivers/net/stack/socket.c +++ b/kernel/drivers/net/stack/socket.c @@ -27,6 +27,7 @@ #include <linux/spinlock.h> #include <linux/socket.h> #include <linux/in.h> +#include <linux/err.h> #include <linux/ip.h> #include <linux/tcp.h> #include <asm/bitops.h> @@ -141,23 +142,32 @@ EXPORT_SYMBOL_GPL(rt_socket_cleanup); /*** * rt_socket_common_ioctl */ -int rt_socket_common_ioctl(struct rtdm_fd *fd, int request, void *arg) +int rt_socket_common_ioctl(struct rtdm_fd *fd, int request, void __user *arg) { struct rtsocket *sock = rtdm_fd_to_private(fd); int ret = 0; - struct rtnet_callback *callback = arg; - unsigned int rtskbs; + struct rtnet_callback *callback; + const unsigned int *val; + unsigned int _val; + const nanosecs_rel_t *timeout; + nanosecs_rel_t _timeout; rtdm_lockctx_t context; switch (request) { case RTNET_RTIOC_XMITPARAMS: - sock->priority = *(unsigned int *)arg; - break; + val = rtnet_get_arg(fd, &_val, arg, sizeof(_val)); + if (IS_ERR(val)) + return PTR_ERR(val); + sock->priority = *val; + break; case RTNET_RTIOC_TIMEOUT: - sock->timeout = *(nanosecs_rel_t *)arg; - break; + timeout = rtnet_get_arg(fd, &_timeout, arg, sizeof(_timeout)); + if (IS_ERR(timeout)) + return PTR_ERR(timeout); + sock->timeout = *timeout; + break; case RTNET_RTIOC_CALLBACK: if (rtdm_fd_is_user(fd)) @@ -165,6 +175,7 @@ int rt_socket_common_ioctl(struct rtdm_fd *fd, int request, void *arg) rtdm_lock_get_irqsave(&sock->param_lock, context); + callback = arg; sock->callback_func = callback->func; sock->callback_arg = callback->arg; @@ -172,44 +183,48 @@ int rt_socket_common_ioctl(struct rtdm_fd *fd, int request, void *arg) break; case RTNET_RTIOC_EXTPOOL: - rtskbs = *(unsigned int *)arg; + val = rtnet_get_arg(fd, &_val, arg, sizeof(_val)); + if (IS_ERR(val)) + return PTR_ERR(val); - if (rtdm_in_rt_context()) - return -ENOSYS; + if (rtdm_in_rt_context()) + return -ENOSYS; - mutex_lock(&sock->pool_nrt_lock); + mutex_lock(&sock->pool_nrt_lock); - if (test_bit(SKB_POOL_CLOSED, &sock->flags)) { - mutex_unlock(&sock->pool_nrt_lock); - return -EBADF; - } - ret = rtskb_pool_extend(&sock->skb_pool, rtskbs); - sock->pool_size += ret; + if (test_bit(SKB_POOL_CLOSED, &sock->flags)) { + mutex_unlock(&sock->pool_nrt_lock); + return -EBADF; + } + ret = rtskb_pool_extend(&sock->skb_pool, *val); + sock->pool_size += ret; - mutex_unlock(&sock->pool_nrt_lock); + mutex_unlock(&sock->pool_nrt_lock); - if (ret == 0 && rtskbs > 0) - ret = -ENOMEM; + if (ret == 0 && *val > 0) + ret = -ENOMEM; - break; + break; case RTNET_RTIOC_SHRPOOL: - rtskbs = *(unsigned int *)arg; + val = rtnet_get_arg(fd, &_val, arg, sizeof(_val)); + if (IS_ERR(val)) + return PTR_ERR(val); - if (rtdm_in_rt_context()) - return -ENOSYS; + if (rtdm_in_rt_context()) + return -ENOSYS; - mutex_lock(&sock->pool_nrt_lock); + mutex_lock(&sock->pool_nrt_lock); - ret = rtskb_pool_shrink(&sock->skb_pool, rtskbs); - sock->pool_size -= ret; + ret = rtskb_pool_shrink(&sock->skb_pool, *val); + sock->pool_size -= ret; - mutex_unlock(&sock->pool_nrt_lock); + mutex_unlock(&sock->pool_nrt_lock); - if (ret == 0 && rtskbs > 0) - ret = -EBUSY; + if (ret == 0 && *val > 0) + ret = -EBUSY; - break; + break; default: ret = -EOPNOTSUPP; @@ -225,87 +240,111 @@ EXPORT_SYMBOL_GPL(rt_socket_common_ioctl); /*** * rt_socket_if_ioctl */ -int rt_socket_if_ioctl(struct rtdm_fd *fd, int request, void *arg) +int rt_socket_if_ioctl(struct rtdm_fd *fd, int request, void __user *arg) { struct rtnet_device *rtdev; - struct ifreq *ifr = arg; - struct sockaddr_in *sin; - int ret = 0; + const struct ifreq *ifr; + struct ifreq _ifr, *ifrw; + struct sockaddr_in _sin; + const struct ifconf *ifc; + struct ifconf _ifc, *ifcw; + int ret = 0, size = 0, i; + short flags; if (request == SIOCGIFCONF) { - struct ifconf *ifc = arg; - struct ifreq *cur_ifr = ifc->ifc_req; - int size = 0; - int i; - - for (i = 1; i <= MAX_RT_DEVICES; i++) { - rtdev = rtdev_get_by_index(i); - if (rtdev != NULL) { + ifc = rtnet_get_arg(fd, &_ifc, arg, sizeof(_ifc)); + if (IS_ERR(ifc)) + return PTR_ERR(ifc); + + for (ifrw = ifc->ifc_req, i = 1; i <= MAX_RT_DEVICES; i++) { + ifrw = (struct ifreq *)rtnet_get_arg(fd, &_ifr, ifrw, sizeof(_ifr)); + if (IS_ERR(ifrw)) + return PTR_ERR(ifrw); + + rtdev = rtdev_get_by_index(i); + if (rtdev == NULL) + continue; + if ((rtdev->flags & IFF_UP) == 0) { - rtdev_dereference(rtdev); - continue; + rtdev_dereference(rtdev); + continue; } size += sizeof(struct ifreq); if (size > ifc->ifc_len) { - rtdev_dereference(rtdev); - size = ifc->ifc_len; - break; + rtdev_dereference(rtdev); + size = ifc->ifc_len; + break; } - strlcpy(cur_ifr->ifr_name, rtdev->name, - IFNAMSIZ); - sin = (struct sockaddr_in *)&cur_ifr->ifr_addr; - sin->sin_family = AF_INET; - sin->sin_addr.s_addr = rtdev->local_ip; - - cur_ifr++; + ret = rtnet_put_arg(fd, ifrw->ifr_name, rtdev->name, IFNAMSIZ); + if (ret == 0) { + memset(&_sin, 0, sizeof(_sin)); + _sin.sin_family = AF_INET; + _sin.sin_addr.s_addr = rtdev->local_ip; + ret = rtnet_put_arg(fd, &ifrw->ifr_addr, &_sin, sizeof(ifrw->ifr_addr)); + } + rtdev_dereference(rtdev); - } + if (ret) + return ret; + ifrw++; } - ifc->ifc_len = size; - return 0; + ifcw = arg; + return rtnet_put_arg(fd, &ifcw->ifc_len, &size, sizeof(size)); } + + ifrw = arg; + ifr = rtnet_get_arg(fd, &_ifr, arg, sizeof(_ifr)); + if (IS_ERR(ifr)) + return PTR_ERR(ifr); + if (request == SIOCGIFNAME) { rtdev = rtdev_get_by_index(ifr->ifr_ifindex); if (rtdev == NULL) return -ENODEV; - strlcpy(ifr->ifr_name, rtdev->name, IFNAMSIZ); - ret = 0; + ret = rtnet_put_arg(fd, ifrw->ifr_name, rtdev->name, IFNAMSIZ); goto out; } rtdev = rtdev_get_by_name(ifr->ifr_name); if (rtdev == NULL) - return -ENODEV; + return -ENODEV; switch (request) { case SIOCGIFINDEX: - ifr->ifr_ifindex = rtdev->ifindex; - break; + ret = rtnet_put_arg(fd, &ifrw->ifr_ifindex, &rtdev->ifindex, + sizeof(ifrw->ifr_ifindex)); + break; case SIOCGIFFLAGS: - ifr->ifr_flags = rtdev->flags; - if ((ifr->ifr_flags & IFF_UP) + flags = rtdev->flags; + if ((ifr->ifr_flags & IFF_UP) && (rtdev->link_state - & (RTNET_LINK_STATE_PRESENT - | RTNET_LINK_STATE_NOCARRIER)) + & (RTNET_LINK_STATE_PRESENT + | RTNET_LINK_STATE_NOCARRIER)) == RTNET_LINK_STATE_PRESENT) - ifr->ifr_flags |= IFF_RUNNING; - break; + flags |= IFF_RUNNING; + ret = rtnet_put_arg(fd, &ifrw->ifr_flags, &flags, + sizeof(ifrw->ifr_flags)); + break; case SIOCGIFHWADDR: - memcpy(ifr->ifr_hwaddr.sa_data, rtdev->dev_addr, rtdev->addr_len); - ifr->ifr_hwaddr.sa_family = rtdev->type; - break; + ret = rtnet_put_arg(fd, &ifrw->ifr_hwaddr.sa_data, rtdev->dev_addr, + rtdev->addr_len); + if (!ret) + ret = rtnet_put_arg(fd, &ifrw->ifr_hwaddr.sa_family, &rtdev->type, + sizeof(ifrw->ifr_hwaddr.sa_family)); + break; case SIOCGIFADDR: - sin = (struct sockaddr_in *)&ifr->ifr_addr; - sin->sin_family = AF_INET; - sin->sin_addr.s_addr = rtdev->local_ip; - break; + memset(&_sin, 0, sizeof(_sin)); + _sin.sin_family = AF_INET; + _sin.sin_addr.s_addr = rtdev->local_ip; + ret = rtnet_put_arg(fd, &ifrw->ifr_addr, &_sin, sizeof(ifrw->ifr_addr)); + break; case SIOCETHTOOL: if (rtdev->do_ioctl != NULL) @@ -344,3 +383,30 @@ int rt_socket_select_bind(struct rtdm_fd *fd, return -EINVAL; } EXPORT_SYMBOL_GPL(rt_socket_select_bind); + +void *rtnet_get_arg(struct rtdm_fd *fd, void *tmp, const void *src, size_t len) +{ + int ret; + + if (!rtdm_fd_is_user(fd)) + return (void *)src; + + ret = rtdm_copy_from_user(fd, tmp, src, len); + if (ret) + return ERR_PTR(ret); + + return tmp; +} +EXPORT_SYMBOL_GPL(rtnet_get_arg); + +int rtnet_put_arg(struct rtdm_fd *fd, void *dst, const void *src, size_t len) +{ + if (!rtdm_fd_is_user(fd)) { + if (dst != src) + memcpy(dst, src, len); + return 0; + } + + return rtdm_copy_to_user(fd, dst, src, len); +} +EXPORT_SYMBOL_GPL(rtnet_put_arg); _______________________________________________ Xenomai-git mailing list Xenomai-git@xenomai.org https://xenomai.org/mailman/listinfo/xenomai-git