ipv4,appletalk: move SIOCADDRT and SIOCDELRT handling into ->compat_ioctl
[linux-2.6-microblaze.git] / net / appletalk / ddp.c
index 4177a74..15787e8 100644 (file)
@@ -57,6 +57,7 @@
 #include <net/sock.h>
 #include <net/tcp_states.h>
 #include <net/route.h>
+#include <net/compat.h>
 #include <linux/atalk.h>
 #include <linux/highmem.h>
 
@@ -1839,20 +1840,58 @@ static int atalk_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
 
 
 #ifdef CONFIG_COMPAT
+static int atalk_compat_routing_ioctl(struct sock *sk, unsigned int cmd,
+               struct compat_rtentry __user *ur)
+{
+       compat_uptr_t rtdev;
+       struct rtentry rt;
+
+       if (copy_from_user(&rt.rt_dst, &ur->rt_dst,
+                       3 * sizeof(struct sockaddr)) ||
+           get_user(rt.rt_flags, &ur->rt_flags) ||
+           get_user(rt.rt_metric, &ur->rt_metric) ||
+           get_user(rt.rt_mtu, &ur->rt_mtu) ||
+           get_user(rt.rt_window, &ur->rt_window) ||
+           get_user(rt.rt_irtt, &ur->rt_irtt) ||
+           get_user(rtdev, &ur->rt_dev))
+               return -EFAULT;
+
+       switch (cmd) {
+       case SIOCDELRT:
+               if (rt.rt_dst.sa_family != AF_APPLETALK)
+                       return -EINVAL;
+               return atrtr_delete(&((struct sockaddr_at *)
+                                     &rt.rt_dst)->sat_addr);
+
+       case SIOCADDRT:
+               rt.rt_dev = compat_ptr(rtdev);
+               return atrtr_ioctl_addrt(&rt);
+       default:
+               return -EINVAL;
+       }
+}
 static int atalk_compat_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
 {
+       void __user *argp = compat_ptr(arg);
+       struct sock *sk = sock->sk;
+
+       switch (cmd) {
+       case SIOCADDRT:
+       case SIOCDELRT:
+               return atalk_compat_routing_ioctl(sk, cmd, argp);
        /*
         * SIOCATALKDIFADDR is a SIOCPROTOPRIVATE ioctl number, so we
         * cannot handle it in common code. The data we access if ifreq
         * here is compatible, so we can simply call the native
         * handler.
         */
-       if (cmd == SIOCATALKDIFADDR)
-               return atalk_ioctl(sock, cmd, (unsigned long)compat_ptr(arg));
-
-       return -ENOIOCTLCMD;
+       case SIOCATALKDIFADDR:
+               return atalk_ioctl(sock, cmd, (unsigned long)argp);
+       default:
+               return -ENOIOCTLCMD;
+       }
 }
-#endif
+#endif /* CONFIG_COMPAT */
 
 
 static const struct net_proto_family atalk_family_ops = {