#include <linux/types.h>
#include <linux/compat.h>
#include <linux/kernel.h>
+#include <linux/compiler.h>
#include <linux/sched.h>
#include <linux/smp.h>
#include <linux/smp_lock.h>
#include <linux/i2c.h>
#include <linux/i2c-dev.h>
#include <linux/wireless.h>
+#include <linux/atalk.h>
#include <net/sock.h> /* siocdevprivate_ioctl */
#include <net/bluetooth/bluetooth.h>
#include <asm/module.h>
#include <linux/soundcard.h>
#include <linux/lp.h>
+#include <linux/ppdev.h>
#include <linux/atm.h>
#include <linux/atmarp.h>
#include <linux/random.h>
#include <linux/filter.h>
#include <linux/msdos_fs.h>
+#include <linux/pktcdvd.h>
+
+#include <linux/hiddev.h>
#undef INCLUDES
#endif
compat_int_t clipcount;
};
-static void free_kvideo_clips(struct video_window *kp)
-{
- struct video_clip *cp;
-
- cp = kp->clips;
- if(cp != NULL)
- kfree(cp);
-}
-
-static int get_video_window32(struct video_window *kp, struct video_window32 __user *up)
-{
- struct video_clip32 __user *ucp;
- struct video_clip *kcp;
- int nclips, err, i;
- u32 tmp;
-
- if(get_user(kp->x, &up->x))
- return -EFAULT;
- __get_user(kp->y, &up->y);
- __get_user(kp->width, &up->width);
- __get_user(kp->height, &up->height);
- __get_user(kp->chromakey, &up->chromakey);
- __get_user(kp->flags, &up->flags);
- __get_user(kp->clipcount, &up->clipcount);
- __get_user(tmp, &up->clips);
- ucp = compat_ptr(tmp);
- kp->clips = NULL;
-
- nclips = kp->clipcount;
- if(nclips == 0)
- return 0;
-
- if(ucp == 0)
- return -EINVAL;
-
- /* Peculiar interface... */
- if(nclips < 0)
- nclips = VIDEO_CLIPMAP_SIZE;
-
- kcp = kmalloc(nclips * sizeof(struct video_clip), GFP_KERNEL);
- err = -ENOMEM;
- if(kcp == NULL)
- goto cleanup_and_err;
-
- kp->clips = kcp;
- for(i = 0; i < nclips; i++) {
- __get_user(kcp[i].x, &ucp[i].x);
- __get_user(kcp[i].y, &ucp[i].y);
- __get_user(kcp[i].width, &ucp[i].width);
- __get_user(kcp[i].height, &ucp[i].height);
- kcp[nclips].next = NULL;
- }
-
- return 0;
-
-cleanup_and_err:
- free_kvideo_clips(kp);
- return err;
-}
-
/* You get back everything except the clips... */
static int put_video_window32(struct video_window *kp, struct video_window32 __user *up)
{
#define VIDIOCGFREQ32 _IOR('v',14, u32)
#define VIDIOCSFREQ32 _IOW('v',15, u32)
+enum {
+ MaxClips = (~0U-sizeof(struct video_window))/sizeof(struct video_clip)
+};
+
+static int do_set_window(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+ struct video_window32 __user *up = compat_ptr(arg);
+ struct video_window __user *vw;
+ struct video_clip __user *p;
+ int nclips;
+ u32 n;
+
+ if (get_user(nclips, &up->clipcount))
+ return -EFAULT;
+
+ /* Peculiar interface... */
+ if (nclips < 0)
+ nclips = VIDEO_CLIPMAP_SIZE;
+
+ if (nclips > MaxClips)
+ return -ENOMEM;
+
+ vw = compat_alloc_user_space(sizeof(struct video_window) +
+ nclips * sizeof(struct video_clip));
+
+ p = nclips ? (struct video_clip __user *)(vw + 1) : NULL;
+
+ if (get_user(n, &up->x) || put_user(n, &vw->x) ||
+ get_user(n, &up->y) || put_user(n, &vw->y) ||
+ get_user(n, &up->width) || put_user(n, &vw->width) ||
+ get_user(n, &up->height) || put_user(n, &vw->height) ||
+ get_user(n, &up->chromakey) || put_user(n, &vw->chromakey) ||
+ get_user(n, &up->flags) || put_user(n, &vw->flags) ||
+ get_user(n, &up->clipcount) || put_user(n, &vw->clipcount) ||
+ get_user(n, &up->clips) || put_user(p, &vw->clips))
+ return -EFAULT;
+
+ if (nclips) {
+ struct video_clip32 __user *u = compat_ptr(n);
+ int i;
+ if (!u)
+ return -EINVAL;
+ for (i = 0; i < nclips; i++, u++, p++) {
+ s32 v;
+ if (get_user(v, &u->x) ||
+ put_user(v, &p->x) ||
+ get_user(v, &u->y) ||
+ put_user(v, &p->y) ||
+ get_user(v, &u->width) ||
+ put_user(v, &p->width) ||
+ get_user(v, &u->height) ||
+ put_user(v, &p->height) ||
+ put_user(NULL, &p->next))
+ return -EFAULT;
+ }
+ }
+
+ return sys_ioctl(fd, VIDIOCSWIN, (unsigned long)p);
+}
+
static int do_video_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
{
union {
case VIDIOCGTUNER32: cmd = VIDIOCGTUNER; break;
case VIDIOCSTUNER32: cmd = VIDIOCSTUNER; break;
case VIDIOCGWIN32: cmd = VIDIOCGWIN; break;
- case VIDIOCSWIN32: cmd = VIDIOCSWIN; break;
case VIDIOCGFBUF32: cmd = VIDIOCGFBUF; break;
case VIDIOCSFBUF32: cmd = VIDIOCSFBUF; break;
case VIDIOCGFREQ32: cmd = VIDIOCGFREQ; break;
err = get_video_tuner32(&karg.vt, up);
break;
- case VIDIOCSWIN:
- err = get_video_window32(&karg.vw, up);
- break;
-
case VIDIOCSFBUF:
err = get_video_buffer32(&karg.vb, up);
break;
err = sys_ioctl(fd, cmd, (unsigned long)&karg);
set_fs(old_fs);
- if(cmd == VIDIOCSWIN)
- free_kvideo_clips(&karg.vw);
-
if(err == 0) {
switch(cmd) {
case VIDIOCGTUNER:
return err;
}
+#ifdef CONFIG_NET
static int do_siocgstamp(unsigned int fd, unsigned int cmd, unsigned long arg)
{
struct compat_timeval __user *up = compat_ptr(arg);
compat_caddr_t ifcbuf;
};
-#ifdef CONFIG_NET
static int dev_ifname32(unsigned int fd, unsigned int cmd, unsigned long arg)
{
struct net_device *dev;
err = copy_to_user(compat_ptr(arg), &ifr32, sizeof(ifr32));
return (err ? -EFAULT : 0);
}
-#endif
static int dev_ifconf(unsigned int fd, unsigned int cmd, unsigned long arg)
{
/* Don't check these user accesses, just let that get trapped
* in the ioctl handler instead.
*/
- copy_to_user(&u_ifreq64->ifr_ifrn.ifrn_name[0], &tmp_buf[0], IFNAMSIZ);
- __put_user(data64, &u_ifreq64->ifr_ifru.ifru_data);
+ if (copy_to_user(&u_ifreq64->ifr_ifrn.ifrn_name[0], &tmp_buf[0],
+ IFNAMSIZ))
+ return -EFAULT;
+ if (__put_user(data64, &u_ifreq64->ifr_ifru.ifru_data))
+ return -EFAULT;
return sys_ioctl(fd, cmd, (unsigned long) u_ifreq64);
}
set_fs (old_fs);
if (!err) {
switch (cmd) {
+ /* TUNSETIFF is defined as _IOW, it should be _IORW
+ * as the data is copied back to user space, but that
+ * cannot be fixed without breaking all existing apps.
+ */
+ case TUNSETIFF:
case SIOCGIFFLAGS:
case SIOCGIFMETRIC:
case SIOCGIFMTU:
ret |= copy_from_user (devname, compat_ptr(rtdev), 15);
r4.rt_dev = devname; devname[15] = 0;
} else
- r4.rt_dev = 0;
+ r4.rt_dev = NULL;
r = (void *) &r4;
}
return ret;
}
+#endif
struct hd_geometry32 {
unsigned char heads;
static int fb_getput_cmap(unsigned int fd, unsigned int cmd, unsigned long arg)
{
- struct fb_cmap __user *cmap;
+ struct fb_cmap_user __user *cmap;
struct fb_cmap32 __user *cmap32;
__u32 data;
int err;
return -EINVAL;
}
-static int ret_einval(unsigned int fd, unsigned int cmd, unsigned long arg)
+static __attribute_used__ int
+ret_einval(unsigned int fd, unsigned int cmd, unsigned long arg)
{
return -EINVAL;
}
#define CMTPGETCONNLIST _IOR('C', 210, int)
#define CMTPGETCONNINFO _IOR('C', 211, int)
+#define HIDPCONNADD _IOW('H', 200, int)
+#define HIDPCONNDEL _IOW('H', 201, int)
+#define HIDPGETCONNLIST _IOR('H', 210, int)
+#define HIDPGETCONNINFO _IOR('H', 211, int)
+
struct floppy_struct32 {
compat_uint_t size;
compat_uint_t sect;
__put_user(d->d_ino, &d32->d_ino);
__put_user(d->d_off, &d32->d_off);
__put_user(d->d_reclen, &d32->d_reclen);
- __copy_to_user(d32->d_name, d->d_name, d->d_reclen);
+ if (__copy_to_user(d32->d_name, d->d_name, d->d_reclen))
+ return -EFAULT;
+
return ret;
}
if (cmd == TIOCSSERIAL) {
if (verify_area(VERIFY_READ, ss32, sizeof(SS32)))
return -EFAULT;
- __copy_from_user(&ss, ss32, offsetof(SS32, iomem_base));
+ if (__copy_from_user(&ss, ss32, offsetof(SS32, iomem_base)))
+ return -EFAULT;
__get_user(udata, &ss32->iomem_base);
ss.iomem_base = compat_ptr(udata);
__get_user(ss.iomem_reg_shift, &ss32->iomem_reg_shift);
if (cmd == TIOCGSERIAL && err >= 0) {
if (verify_area(VERIFY_WRITE, ss32, sizeof(SS32)))
return -EFAULT;
- __copy_to_user(ss32,&ss,offsetof(SS32,iomem_base));
+ if (__copy_to_user(ss32,&ss,offsetof(SS32,iomem_base)))
+ return -EFAULT;
__put_user((unsigned long)ss.iomem_base >> 32 ?
0xffffffff : (unsigned)(unsigned long)ss.iomem_base,
&ss32->iomem_base);
static int do_usbdevfs_control(unsigned int fd, unsigned int cmd, unsigned long arg)
{
- struct usbdevfs_ctrltransfer kctrl;
- struct usbdevfs_ctrltransfer32 __user *uctrl;
- mm_segment_t old_fs;
+ struct usbdevfs_ctrltransfer32 __user *p32 = compat_ptr(arg);
+ struct usbdevfs_ctrltransfer __user *p;
__u32 udata;
- void __user *uptr;
- void *kptr;
- int err;
-
- uctrl = compat_ptr(arg);
-
- if (copy_from_user(&kctrl, uctrl,
- (sizeof(struct usbdevfs_ctrltransfer32) -
- sizeof(compat_caddr_t))))
- return -EFAULT;
-
- if (get_user(udata, &uctrl->data))
- return -EFAULT;
- uptr = compat_ptr(udata);
- /* In usbdevice_fs, it limits the control buffer to a page,
- * for simplicity so do we.
- */
- if (!uptr || kctrl.wLength > PAGE_SIZE)
- return -EINVAL;
-
- kptr = (void *)__get_free_page(GFP_KERNEL);
-
- if ((kctrl.bRequestType & USB_DIR_IN) == 0) {
- err = -EFAULT;
- if (copy_from_user(kptr, uptr, kctrl.wLength))
- goto out;
- }
-
- kctrl.data = kptr;
-
- old_fs = get_fs();
- set_fs(KERNEL_DS);
- err = sys_ioctl(fd, USBDEVFS_CONTROL, (unsigned long)&kctrl);
- set_fs(old_fs);
-
- if (err >= 0 &&
- ((kctrl.bRequestType & USB_DIR_IN) != 0)) {
- if (copy_to_user(uptr, kptr, kctrl.wLength))
- err = -EFAULT;
- }
-
-out:
- free_page((unsigned long) kptr);
- return err;
+ p = compat_alloc_user_space(sizeof(*p));
+ if (copy_in_user(p, p32, (sizeof(*p32) - sizeof(compat_caddr_t))) ||
+ get_user(udata, &p32->data) ||
+ put_user(compat_ptr(udata), &p->data))
+ return -EFAULT;
+ return sys_ioctl(fd, USBDEVFS_CONTROL, (unsigned long)p);
}
static int do_usbdevfs_bulk(unsigned int fd, unsigned int cmd, unsigned long arg)
{
- struct usbdevfs_bulktransfer kbulk;
- struct usbdevfs_bulktransfer32 __user *ubulk;
- mm_segment_t old_fs;
- __u32 udata;
- void __user *uptr;
- void *kptr;
- int err;
+ struct usbdevfs_bulktransfer32 __user *p32 = compat_ptr(arg);
+ struct usbdevfs_bulktransfer __user *p;
+ compat_uint_t n;
+ compat_caddr_t addr;
- ubulk = compat_ptr(arg);
+ p = compat_alloc_user_space(sizeof(*p));
- if (get_user(kbulk.ep, &ubulk->ep) ||
- get_user(kbulk.len, &ubulk->len) ||
- get_user(kbulk.timeout, &ubulk->timeout) ||
- get_user(udata, &ubulk->data))
+ if (get_user(n, &p32->ep) || put_user(n, &p->ep) ||
+ get_user(n, &p32->len) || put_user(n, &p->len) ||
+ get_user(n, &p32->timeout) || put_user(n, &p->timeout) ||
+ get_user(addr, &p32->data) || put_user(compat_ptr(addr), &p->data))
return -EFAULT;
- uptr = compat_ptr(udata);
-
- /* In usbdevice_fs, it limits the control buffer to a page,
- * for simplicity so do we.
- */
- if (!uptr || kbulk.len > PAGE_SIZE)
- return -EINVAL;
-
- kptr = (void *) __get_free_page(GFP_KERNEL);
-
- if ((kbulk.ep & 0x80) == 0) {
- err = -EFAULT;
- if (copy_from_user(kptr, uptr, kbulk.len))
- goto out;
- }
-
- kbulk.data = kptr;
-
- old_fs = get_fs();
- set_fs(KERNEL_DS);
- err = sys_ioctl(fd, USBDEVFS_BULK, (unsigned long) &kbulk);
- set_fs(old_fs);
-
- if (err >= 0 &&
- ((kbulk.ep & 0x80) != 0)) {
- if (copy_to_user(uptr, kptr, kbulk.len))
- err = -EFAULT;
- }
-
-out:
- free_page((unsigned long) kptr);
- return err;
+ return sys_ioctl(fd, USBDEVFS_BULK, (unsigned long)p);
}
/* This needs more work before we can enable it. Unfortunately
compat_caddr_t data; /* union i2c_smbus_data *data */
};
+struct i2c_rdwr_aligned {
+ struct i2c_rdwr_ioctl_data cmd;
+ struct i2c_msg msgs[0];
+};
+
static int do_i2c_rdwr_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
{
- struct i2c_rdwr_ioctl_data __user *tdata;
- struct i2c_rdwr_ioctl_data32 __user *udata;
+ struct i2c_rdwr_ioctl_data32 __user *udata = compat_ptr(arg);
+ struct i2c_rdwr_aligned __user *tdata;
struct i2c_msg __user *tmsgs;
struct i2c_msg32 __user *umsgs;
compat_caddr_t datap;
int nmsgs, i;
- tdata = compat_alloc_user_space(sizeof(*tdata));
- if (tdata == NULL)
- return -ENOMEM;
- if (verify_area(VERIFY_WRITE, tdata, sizeof(*tdata)))
- return -EFAULT;
-
- udata = compat_ptr(arg);
- if (verify_area(VERIFY_READ, udata, sizeof(*udata)))
- return -EFAULT;
- if (__get_user(nmsgs, &udata->nmsgs) || __put_user(nmsgs, &tdata->nmsgs))
+ if (get_user(nmsgs, &udata->nmsgs))
return -EFAULT;
if (nmsgs > I2C_RDRW_IOCTL_MAX_MSGS)
return -EINVAL;
- if (__get_user(datap, &udata->msgs))
+
+ if (get_user(datap, &udata->msgs))
return -EFAULT;
umsgs = compat_ptr(datap);
- if (verify_area(VERIFY_READ, umsgs, sizeof(struct i2c_msg) * nmsgs))
- return -EFAULT;
- tmsgs = compat_alloc_user_space(sizeof(struct i2c_msg) * nmsgs);
- if (tmsgs == NULL)
- return -ENOMEM;
- if (verify_area(VERIFY_WRITE, tmsgs, sizeof(struct i2c_msg) * nmsgs))
+ tdata = compat_alloc_user_space(sizeof(*tdata) +
+ nmsgs * sizeof(struct i2c_msg));
+ tmsgs = &tdata->msgs[0];
+
+ if (put_user(nmsgs, &tdata->cmd.nmsgs) ||
+ put_user(tmsgs, &tdata->cmd.msgs))
return -EFAULT;
- if (__put_user(tmsgs, &tdata->msgs))
- return -ENOMEM;
+
for (i = 0; i < nmsgs; i++) {
- if (__copy_in_user(&tmsgs[i].addr,
- &umsgs[i].addr,
- 3 * sizeof(u16)))
+ if (copy_in_user(&tmsgs[i].addr, &umsgs[i].addr, 3*sizeof(u16)))
return -EFAULT;
- if (__get_user(datap, &umsgs[i].buf) ||
- __put_user(compat_ptr(datap), &tmsgs[i].buf))
+ if (get_user(datap, &umsgs[i].buf) ||
+ put_user(compat_ptr(datap), &tmsgs[i].buf))
return -EFAULT;
}
return sys_ioctl(fd, cmd, (unsigned long)tdata);
HANDLE_IOCTL(MEMWRITEOOB32, mtd_rw_oob)
#ifdef CONFIG_NET
HANDLE_IOCTL(SIOCGIFNAME, dev_ifname32)
-#endif
HANDLE_IOCTL(SIOCGIFCONF, dev_ifconf)
HANDLE_IOCTL(SIOCGIFFLAGS, dev_ifsioc)
HANDLE_IOCTL(SIOCSIFFLAGS, dev_ifsioc)
HANDLE_IOCTL(SIOCSIFMAP, dev_ifsioc)
HANDLE_IOCTL(SIOCGIFADDR, dev_ifsioc)
HANDLE_IOCTL(SIOCSIFADDR, dev_ifsioc)
+
+/* ioctls used by appletalk ddp.c */
+HANDLE_IOCTL(SIOCATALKDIFADDR, dev_ifsioc)
+HANDLE_IOCTL(SIOCDIFADDR, dev_ifsioc)
+HANDLE_IOCTL(SIOCSARP, dev_ifsioc)
+HANDLE_IOCTL(SIOCDARP, dev_ifsioc)
+
HANDLE_IOCTL(SIOCGIFBRDADDR, dev_ifsioc)
HANDLE_IOCTL(SIOCSIFBRDADDR, dev_ifsioc)
HANDLE_IOCTL(SIOCGIFDSTADDR, dev_ifsioc)
/* Note SIOCRTMSG is no longer, so this is safe and * the user would have seen just an -EINVAL anyways. */
HANDLE_IOCTL(SIOCRTMSG, ret_einval)
HANDLE_IOCTL(SIOCGSTAMP, do_siocgstamp)
+#endif
HANDLE_IOCTL(HDIO_GETGEO, hdio_getgeo)
HANDLE_IOCTL(BLKRAGET, w_long)
HANDLE_IOCTL(BLKGETSIZE, w_long)
HANDLE_IOCTL(VIDIOCGTUNER32, do_video_ioctl)
HANDLE_IOCTL(VIDIOCSTUNER32, do_video_ioctl)
HANDLE_IOCTL(VIDIOCGWIN32, do_video_ioctl)
-HANDLE_IOCTL(VIDIOCSWIN32, do_video_ioctl)
+HANDLE_IOCTL(VIDIOCSWIN32, do_set_window)
HANDLE_IOCTL(VIDIOCGFBUF32, do_video_ioctl)
HANDLE_IOCTL(VIDIOCSFBUF32, do_video_ioctl)
HANDLE_IOCTL(VIDIOCGFREQ32, do_video_ioctl)