static int hidp_sock_compat_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) { if (cmd == HIDPGETCONNLIST) { struct hidp_connlist_req cl; u32 uci; int err; if (get_user(cl.cnum, (u32 __user *) arg) || get_user(uci, (u32 __user *) (arg + 4))) return -EFAULT; cl.ci = compat_ptr(uci); if (cl.cnum <= 0) return -EINVAL; err = hidp_get_connlist(&cl); if (!err && put_user(cl.cnum, (u32 __user *) arg)) err = -EFAULT; return err; } else if (cmd == HIDPCONNADD) { struct compat_hidp_connadd_req ca; struct hidp_connadd_req __user *uca; uca = compat_alloc_user_space(sizeof(*uca)); if (copy_from_user(&ca, (void __user *) arg, sizeof(ca))) return -EFAULT; if (put_user(ca.ctrl_sock, &uca->ctrl_sock) || put_user(ca.intr_sock, &uca->intr_sock) || put_user(ca.parser, &uca->parser) || put_user(ca.rd_size, &uca->rd_size) || put_user(compat_ptr(ca.rd_data), &uca->rd_data) || put_user(ca.country, &uca->country) || put_user(ca.subclass, &uca->subclass) || put_user(ca.vendor, &uca->vendor) || put_user(ca.product, &uca->product) || put_user(ca.version, &uca->version) || put_user(ca.flags, &uca->flags) || put_user(ca.idle_to, &uca->idle_to) || copy_to_user(&uca->name[0], &ca.name[0], 128)) return -EFAULT; arg = (unsigned long) uca; /* Fall through. We don't actually write back any _changes_ to the structure anyway, so there's no need to copy back into the original compat version */ } return hidp_sock_ioctl(sock, cmd, arg); }
static int hidp_sock_compat_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) { void __user *argp = compat_ptr(arg); int err; if (cmd == HIDPGETCONNLIST) { struct hidp_connlist_req cl; u32 __user *p = argp; u32 uci; if (get_user(cl.cnum, p) || get_user(uci, p + 1)) return -EFAULT; cl.ci = compat_ptr(uci); if (cl.cnum <= 0) return -EINVAL; err = hidp_get_connlist(&cl); if (!err && put_user(cl.cnum, p)) err = -EFAULT; return err; } else if (cmd == HIDPCONNADD) { struct compat_hidp_connadd_req ca32; struct hidp_connadd_req ca; struct socket *csock; struct socket *isock; if (!capable(CAP_NET_ADMIN)) return -EPERM; if (copy_from_user(&ca32, (void __user *) arg, sizeof(ca32))) return -EFAULT; ca.ctrl_sock = ca32.ctrl_sock; ca.intr_sock = ca32.intr_sock; ca.parser = ca32.parser; ca.rd_size = ca32.rd_size; ca.rd_data = compat_ptr(ca32.rd_data); ca.country = ca32.country; ca.subclass = ca32.subclass; ca.vendor = ca32.vendor; ca.product = ca32.product; ca.version = ca32.version; ca.flags = ca32.flags; ca.idle_to = ca32.idle_to; memcpy(ca.name, ca32.name, 128); csock = sockfd_lookup(ca.ctrl_sock, &err); if (!csock) return err; isock = sockfd_lookup(ca.intr_sock, &err); if (!isock) { sockfd_put(csock); return err; } err = hidp_connection_add(&ca, csock, isock); if (!err && copy_to_user(argp, &ca32, sizeof(ca32))) err = -EFAULT; sockfd_put(csock); sockfd_put(isock); return err; } return hidp_sock_ioctl(sock, cmd, arg); }