| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * DDP: An implementation of the AppleTalk DDP protocol for |
|---|
| 3 | 4 | * Ethernet 'ELAP'. |
|---|
| .. | .. |
|---|
| 43 | 44 | * shared skb support 8) |
|---|
| 44 | 45 | * Arnaldo C. de Melo : Move proc stuff to atalk_proc.c, |
|---|
| 45 | 46 | * use seq_file |
|---|
| 46 | | - * |
|---|
| 47 | | - * This program is free software; you can redistribute it and/or |
|---|
| 48 | | - * modify it under the terms of the GNU General Public License |
|---|
| 49 | | - * as published by the Free Software Foundation; either version |
|---|
| 50 | | - * 2 of the License, or (at your option) any later version. |
|---|
| 51 | | - * |
|---|
| 52 | 47 | */ |
|---|
| 53 | 48 | |
|---|
| 54 | 49 | #include <linux/capability.h> |
|---|
| .. | .. |
|---|
| 62 | 57 | #include <net/sock.h> |
|---|
| 63 | 58 | #include <net/tcp_states.h> |
|---|
| 64 | 59 | #include <net/route.h> |
|---|
| 60 | +#include <net/compat.h> |
|---|
| 65 | 61 | #include <linux/atalk.h> |
|---|
| 66 | 62 | #include <linux/highmem.h> |
|---|
| 67 | 63 | |
|---|
| .. | .. |
|---|
| 872 | 868 | return copy_to_user(arg, &atreq, sizeof(atreq)) ? -EFAULT : 0; |
|---|
| 873 | 869 | } |
|---|
| 874 | 870 | |
|---|
| 871 | +static int atrtr_ioctl_addrt(struct rtentry *rt) |
|---|
| 872 | +{ |
|---|
| 873 | + struct net_device *dev = NULL; |
|---|
| 874 | + |
|---|
| 875 | + if (rt->rt_dev) { |
|---|
| 876 | + char name[IFNAMSIZ]; |
|---|
| 877 | + |
|---|
| 878 | + if (copy_from_user(name, rt->rt_dev, IFNAMSIZ-1)) |
|---|
| 879 | + return -EFAULT; |
|---|
| 880 | + name[IFNAMSIZ-1] = '\0'; |
|---|
| 881 | + |
|---|
| 882 | + dev = __dev_get_by_name(&init_net, name); |
|---|
| 883 | + if (!dev) |
|---|
| 884 | + return -ENODEV; |
|---|
| 885 | + } |
|---|
| 886 | + return atrtr_create(rt, dev); |
|---|
| 887 | +} |
|---|
| 888 | + |
|---|
| 875 | 889 | /* Routing ioctl() calls */ |
|---|
| 876 | 890 | static int atrtr_ioctl(unsigned int cmd, void __user *arg) |
|---|
| 877 | 891 | { |
|---|
| .. | .. |
|---|
| 887 | 901 | return atrtr_delete(&((struct sockaddr_at *) |
|---|
| 888 | 902 | &rt.rt_dst)->sat_addr); |
|---|
| 889 | 903 | |
|---|
| 890 | | - case SIOCADDRT: { |
|---|
| 891 | | - struct net_device *dev = NULL; |
|---|
| 892 | | - if (rt.rt_dev) { |
|---|
| 893 | | - char name[IFNAMSIZ]; |
|---|
| 894 | | - if (copy_from_user(name, rt.rt_dev, IFNAMSIZ-1)) |
|---|
| 895 | | - return -EFAULT; |
|---|
| 896 | | - name[IFNAMSIZ-1] = '\0'; |
|---|
| 897 | | - dev = __dev_get_by_name(&init_net, name); |
|---|
| 898 | | - if (!dev) |
|---|
| 899 | | - return -ENODEV; |
|---|
| 900 | | - } |
|---|
| 901 | | - return atrtr_create(&rt, dev); |
|---|
| 902 | | - } |
|---|
| 904 | + case SIOCADDRT: |
|---|
| 905 | + return atrtr_ioctl_addrt(&rt); |
|---|
| 903 | 906 | } |
|---|
| 904 | 907 | return -EINVAL; |
|---|
| 905 | 908 | } |
|---|
| .. | .. |
|---|
| 958 | 961 | if (copy > len) |
|---|
| 959 | 962 | copy = len; |
|---|
| 960 | 963 | vaddr = kmap_atomic(skb_frag_page(frag)); |
|---|
| 961 | | - sum = atalk_sum_partial(vaddr + frag->page_offset + |
|---|
| 962 | | - offset - start, copy, sum); |
|---|
| 964 | + sum = atalk_sum_partial(vaddr + skb_frag_off(frag) + |
|---|
| 965 | + offset - start, copy, sum); |
|---|
| 963 | 966 | kunmap_atomic(vaddr); |
|---|
| 964 | 967 | |
|---|
| 965 | 968 | if (!(len -= copy)) |
|---|
| .. | .. |
|---|
| 1820 | 1823 | rc = put_user(amount, (int __user *)argp); |
|---|
| 1821 | 1824 | break; |
|---|
| 1822 | 1825 | } |
|---|
| 1823 | | - case SIOCGSTAMP: |
|---|
| 1824 | | - rc = sock_get_timestamp(sk, argp); |
|---|
| 1825 | | - break; |
|---|
| 1826 | | - case SIOCGSTAMPNS: |
|---|
| 1827 | | - rc = sock_get_timestampns(sk, argp); |
|---|
| 1828 | | - break; |
|---|
| 1829 | 1826 | /* Routing */ |
|---|
| 1830 | 1827 | case SIOCADDRT: |
|---|
| 1831 | 1828 | case SIOCDELRT: |
|---|
| .. | .. |
|---|
| 1852 | 1849 | |
|---|
| 1853 | 1850 | |
|---|
| 1854 | 1851 | #ifdef CONFIG_COMPAT |
|---|
| 1852 | +static int atalk_compat_routing_ioctl(struct sock *sk, unsigned int cmd, |
|---|
| 1853 | + struct compat_rtentry __user *ur) |
|---|
| 1854 | +{ |
|---|
| 1855 | + compat_uptr_t rtdev; |
|---|
| 1856 | + struct rtentry rt; |
|---|
| 1857 | + |
|---|
| 1858 | + if (copy_from_user(&rt.rt_dst, &ur->rt_dst, |
|---|
| 1859 | + 3 * sizeof(struct sockaddr)) || |
|---|
| 1860 | + get_user(rt.rt_flags, &ur->rt_flags) || |
|---|
| 1861 | + get_user(rt.rt_metric, &ur->rt_metric) || |
|---|
| 1862 | + get_user(rt.rt_mtu, &ur->rt_mtu) || |
|---|
| 1863 | + get_user(rt.rt_window, &ur->rt_window) || |
|---|
| 1864 | + get_user(rt.rt_irtt, &ur->rt_irtt) || |
|---|
| 1865 | + get_user(rtdev, &ur->rt_dev)) |
|---|
| 1866 | + return -EFAULT; |
|---|
| 1867 | + |
|---|
| 1868 | + switch (cmd) { |
|---|
| 1869 | + case SIOCDELRT: |
|---|
| 1870 | + if (rt.rt_dst.sa_family != AF_APPLETALK) |
|---|
| 1871 | + return -EINVAL; |
|---|
| 1872 | + return atrtr_delete(&((struct sockaddr_at *) |
|---|
| 1873 | + &rt.rt_dst)->sat_addr); |
|---|
| 1874 | + |
|---|
| 1875 | + case SIOCADDRT: |
|---|
| 1876 | + rt.rt_dev = compat_ptr(rtdev); |
|---|
| 1877 | + return atrtr_ioctl_addrt(&rt); |
|---|
| 1878 | + default: |
|---|
| 1879 | + return -EINVAL; |
|---|
| 1880 | + } |
|---|
| 1881 | +} |
|---|
| 1855 | 1882 | static int atalk_compat_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) |
|---|
| 1856 | 1883 | { |
|---|
| 1884 | + void __user *argp = compat_ptr(arg); |
|---|
| 1885 | + struct sock *sk = sock->sk; |
|---|
| 1886 | + |
|---|
| 1887 | + switch (cmd) { |
|---|
| 1888 | + case SIOCADDRT: |
|---|
| 1889 | + case SIOCDELRT: |
|---|
| 1890 | + return atalk_compat_routing_ioctl(sk, cmd, argp); |
|---|
| 1857 | 1891 | /* |
|---|
| 1858 | 1892 | * SIOCATALKDIFADDR is a SIOCPROTOPRIVATE ioctl number, so we |
|---|
| 1859 | 1893 | * cannot handle it in common code. The data we access if ifreq |
|---|
| 1860 | 1894 | * here is compatible, so we can simply call the native |
|---|
| 1861 | 1895 | * handler. |
|---|
| 1862 | 1896 | */ |
|---|
| 1863 | | - if (cmd == SIOCATALKDIFADDR) |
|---|
| 1864 | | - return atalk_ioctl(sock, cmd, (unsigned long)compat_ptr(arg)); |
|---|
| 1865 | | - |
|---|
| 1866 | | - return -ENOIOCTLCMD; |
|---|
| 1897 | + case SIOCATALKDIFADDR: |
|---|
| 1898 | + return atalk_ioctl(sock, cmd, (unsigned long)argp); |
|---|
| 1899 | + default: |
|---|
| 1900 | + return -ENOIOCTLCMD; |
|---|
| 1901 | + } |
|---|
| 1867 | 1902 | } |
|---|
| 1868 | | -#endif |
|---|
| 1903 | +#endif /* CONFIG_COMPAT */ |
|---|
| 1869 | 1904 | |
|---|
| 1870 | 1905 | |
|---|
| 1871 | 1906 | static const struct net_proto_family atalk_family_ops = { |
|---|
| .. | .. |
|---|
| 1885 | 1920 | .getname = atalk_getname, |
|---|
| 1886 | 1921 | .poll = datagram_poll, |
|---|
| 1887 | 1922 | .ioctl = atalk_ioctl, |
|---|
| 1923 | + .gettstamp = sock_gettstamp, |
|---|
| 1888 | 1924 | #ifdef CONFIG_COMPAT |
|---|
| 1889 | 1925 | .compat_ioctl = atalk_compat_ioctl, |
|---|
| 1890 | 1926 | #endif |
|---|
| 1891 | 1927 | .listen = sock_no_listen, |
|---|
| 1892 | 1928 | .shutdown = sock_no_shutdown, |
|---|
| 1893 | | - .setsockopt = sock_no_setsockopt, |
|---|
| 1894 | | - .getsockopt = sock_no_getsockopt, |
|---|
| 1895 | 1929 | .sendmsg = atalk_sendmsg, |
|---|
| 1896 | 1930 | .recvmsg = atalk_recvmsg, |
|---|
| 1897 | 1931 | .mmap = sock_no_mmap, |
|---|