Merge git://git.infradead.org/battery-2.6
[pandora-kernel.git] / arch / arm / kernel / sys_oabi-compat.c
index eafa8e5..8e2f9bc 100644 (file)
  *   struct sembuf loses its padding with EABI.  Since arrays of them are
  *   used they have to be copyed to remove the padding. Compatibility wrappers
  *   provided below.
+ *
+ * sys_bind:
+ * sys_connect:
+ * sys_sendmsg:
+ * sys_sendto:
+ * sys_socketcall:
+ *
+ *   struct sockaddr_un loses its padding with EABI.  Since the size of the
+ *   structure is used as a validation test in unix_mkname(), we need to
+ *   change the length argument to 110 whenever it is 112.  Compatibility
+ *   wrappers provided below.
  */
 
 #include <linux/syscalls.h>
@@ -67,6 +78,8 @@
 #include <linux/fcntl.h>
 #include <linux/eventpoll.h>
 #include <linux/sem.h>
+#include <linux/socket.h>
+#include <linux/net.h>
 #include <asm/ipc.h>
 #include <asm/uaccess.h>
 
@@ -337,3 +350,91 @@ asmlinkage int sys_oabi_ipc(uint call, int first, int second, int third,
                return sys_ipc(call, first, second, third, ptr, fifth);
        }
 }
+
+asmlinkage long sys_oabi_bind(int fd, struct sockaddr __user *addr, int addrlen)
+{
+       sa_family_t sa_family;
+       if (addrlen == 112 &&
+           get_user(sa_family, &addr->sa_family) == 0 &&
+           sa_family == AF_UNIX)
+                       addrlen = 110;
+       return sys_bind(fd, addr, addrlen);
+}
+
+asmlinkage long sys_oabi_connect(int fd, struct sockaddr __user *addr, int addrlen)
+{
+       sa_family_t sa_family;
+       if (addrlen == 112 &&
+           get_user(sa_family, &addr->sa_family) == 0 &&
+           sa_family == AF_UNIX)
+                       addrlen = 110;
+       return sys_connect(fd, addr, addrlen);
+}
+
+asmlinkage long sys_oabi_sendto(int fd, void __user *buff,
+                               size_t len, unsigned flags,
+                               struct sockaddr __user *addr,
+                               int addrlen)
+{
+       sa_family_t sa_family;
+       if (addrlen == 112 &&
+           get_user(sa_family, &addr->sa_family) == 0 &&
+           sa_family == AF_UNIX)
+                       addrlen = 110;
+       return sys_sendto(fd, buff, len, flags, addr, addrlen);
+}
+
+asmlinkage long sys_oabi_sendmsg(int fd, struct msghdr __user *msg, unsigned flags)
+{
+       struct sockaddr __user *addr;
+       int msg_namelen;
+       sa_family_t sa_family;
+       if (msg &&
+           get_user(msg_namelen, &msg->msg_namelen) == 0 &&
+           msg_namelen == 112 &&
+           get_user(addr, &msg->msg_name) == 0 &&
+           get_user(sa_family, &addr->sa_family) == 0 &&
+           sa_family == AF_UNIX)
+       {
+               /*
+                * HACK ALERT: there is a limit to how much backward bending
+                * we should do for what is actually a transitional
+                * compatibility layer.  This already has known flaws with
+                * a few ioctls that we don't intend to fix.  Therefore
+                * consider this blatent hack as another one... and take care
+                * to run for cover.  In most cases it will "just work fine".
+                * If it doesn't, well, tough.
+                */
+               put_user(110, &msg->msg_namelen);
+       }
+       return sys_sendmsg(fd, msg, flags);
+}
+
+asmlinkage long sys_oabi_socketcall(int call, unsigned long __user *args)
+{
+       unsigned long r = -EFAULT, a[6];
+
+       switch (call) {
+       case SYS_BIND:
+               if (copy_from_user(a, args, 3 * sizeof(long)) == 0)
+                       r = sys_oabi_bind(a[0], (struct sockaddr __user *)a[1], a[2]);
+               break;
+       case SYS_CONNECT:
+               if (copy_from_user(a, args, 3 * sizeof(long)) == 0)
+                       r = sys_oabi_connect(a[0], (struct sockaddr __user *)a[1], a[2]);
+               break;
+       case SYS_SENDTO:
+               if (copy_from_user(a, args, 6 * sizeof(long)) == 0)
+                       r = sys_oabi_sendto(a[0], (void __user *)a[1], a[2], a[3],
+                                           (struct sockaddr __user *)a[4], a[5]);
+               break;
+       case SYS_SENDMSG:
+               if (copy_from_user(a, args, 3 * sizeof(long)) == 0)
+                       r = sys_oabi_sendmsg(a[0], (struct msghdr __user *)a[1], a[2]);
+               break;
+       default:
+               r = sys_socketcall(call, args);
+       }
+
+       return r;
+}