/* $Id: ioctl32.c,v 1.26 1997/12/15 15:11:02 jj Exp $ * ioctl32.c: Conversion between 32bit and 64bit native ioctls. * * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) * * These routines maintain argument size conversion between 32bit and 64bit * ioctls. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* Ugly hack. */ #undef __KERNEL__ #include #define __KERNEL__ #include #include #include #include #include #include #include /* As gcc will warn about casting u32 to some ptr, we have to cast it to * unsigned long first, and that's what is A() for. * You just do (void *)A(x), instead of having to type (void *)((unsigned long)x) * or instead of just (void *)x, which will produce warnings. */ #define A(x) ((unsigned long)x) extern asmlinkage int sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg); static int w_long(unsigned int fd, unsigned int cmd, u32 arg) { mm_segment_t old_fs = get_fs(); int err; unsigned long val; set_fs (KERNEL_DS); err = sys_ioctl(fd, cmd, (unsigned long)&val); set_fs (old_fs); if (!err && put_user(val, (u32 *)A(arg))) return -EFAULT; return err; } struct ifmap32 { u32 mem_start; u32 mem_end; unsigned short base_addr; unsigned char irq; unsigned char dma; unsigned char port; }; struct ifreq32 { #define IFHWADDRLEN 6 #define IFNAMSIZ 16 union { char ifrn_name[IFNAMSIZ]; /* if name, e.g. "en0" */ } ifr_ifrn; union { struct sockaddr ifru_addr; struct sockaddr ifru_dstaddr; struct sockaddr ifru_broadaddr; struct sockaddr ifru_netmask; struct sockaddr ifru_hwaddr; short ifru_flags; int ifru_ivalue; int ifru_mtu; struct ifmap32 ifru_map; char ifru_slave[IFNAMSIZ]; /* Just fits the size */ __kernel_caddr_t32 ifru_data; } ifr_ifru; }; struct ifconf32 { int ifc_len; /* size of buffer */ __kernel_caddr_t32 ifcbuf; }; static inline int dev_ifconf(unsigned int fd, u32 arg) { struct ifconf32 ifc32; struct ifconf ifc; struct ifreq32 *ifr32; struct ifreq *ifr; mm_segment_t old_fs; unsigned int i, j; int err; if (copy_from_user(&ifc32, (struct ifconf32 *)A(arg), sizeof(struct ifconf32))) return -EFAULT; if(ifc32.ifcbuf == 0) { ifc32.ifc_len = 0; ifc.ifc_len = 0; ifc.ifc_buf = NULL; } else { ifc.ifc_len = ((ifc32.ifc_len / sizeof (struct ifreq32)) + 1) * sizeof (struct ifreq); ifc.ifc_buf = kmalloc (ifc.ifc_len, GFP_KERNEL); if (!ifc.ifc_buf) return -ENOMEM; } ifr = ifc.ifc_req; ifr32 = (struct ifreq32 *)A(ifc32.ifcbuf); for (i = 0; i < ifc32.ifc_len; i += sizeof (struct ifreq32)) { if (copy_from_user(ifr++, ifr32++, sizeof (struct ifreq32))) { kfree (ifc.ifc_buf); return -EFAULT; } } old_fs = get_fs(); set_fs (KERNEL_DS); err = sys_ioctl (fd, SIOCGIFCONF, (unsigned long)&ifc); set_fs (old_fs); if (!err) { ifr = ifc.ifc_req; ifr32 = (struct ifreq32 *)A(ifc32.ifcbuf); for (i = 0, j = 0; i < ifc32.ifc_len && j < ifc.ifc_len; i += sizeof (struct ifreq32), j += sizeof (struct ifreq)) { if (copy_to_user(ifr32++, ifr++, sizeof (struct ifreq32))) { err = -EFAULT; break; } } if (!err) { if (i <= ifc32.ifc_len) ifc32.ifc_len = i; else ifc32.ifc_len = i - sizeof (struct ifreq32); if (copy_to_user((struct ifconf32 *)A(arg), &ifc32, sizeof(struct ifconf32))) err = -EFAULT; } } if(ifc.ifc_buf != NULL) kfree (ifc.ifc_buf); return err; } static inline int dev_ifsioc(unsigned int fd, unsigned int cmd, u32 arg) { struct ifreq ifr; mm_segment_t old_fs; int err; switch (cmd) { case SIOCSIFMAP: if (copy_from_user(&ifr, (struct ifreq32 *)A(arg), sizeof(ifr.ifr_name)) || __get_user(ifr.ifr_map.mem_start, &(((struct ifreq32 *)A(arg))->ifr_ifru.ifru_map.mem_start)) || __get_user(ifr.ifr_map.mem_end, &(((struct ifreq32 *)A(arg))->ifr_ifru.ifru_map.mem_end)) || __get_user(ifr.ifr_map.base_addr, &(((struct ifreq32 *)A(arg))->ifr_ifru.ifru_map.base_addr)) || __get_user(ifr.ifr_map.irq, &(((struct ifreq32 *)A(arg))->ifr_ifru.ifru_map.irq)) || __get_user(ifr.ifr_map.dma, &(((struct ifreq32 *)A(arg))->ifr_ifru.ifru_map.dma)) || __get_user(ifr.ifr_map.port, &(((struct ifreq32 *)A(arg))->ifr_ifru.ifru_map.port))) return -EFAULT; break; case SIOCGPPPSTATS: case SIOCGPPPCSTATS: case SIOCGPPPVER: if (copy_from_user(&ifr, (struct ifreq32 *)A(arg), sizeof(struct ifreq32))) return -EFAULT; ifr.ifr_data = (__kernel_caddr_t)get_free_page(GFP_KERNEL); if (!ifr.ifr_data) return -EAGAIN; break; default: if (copy_from_user(&ifr, (struct ifreq32 *)A(arg), sizeof(struct ifreq32))) return -EFAULT; break; } old_fs = get_fs(); set_fs (KERNEL_DS); err = sys_ioctl (fd, cmd, (unsigned long)&ifr); set_fs (old_fs); if (!err) { switch (cmd) { case SIOCGIFFLAGS: case SIOCGIFMETRIC: case SIOCGIFMTU: case SIOCGIFMEM: case SIOCGIFHWADDR: case SIOCGIFINDEX: case SIOCGIFADDR: case SIOCGIFBRDADDR: case SIOCGIFDSTADDR: case SIOCGIFNETMASK: if (copy_to_user((struct ifreq32 *)A(arg), &ifr, sizeof(struct ifreq32))) return -EFAULT; break; case SIOCGPPPSTATS: case SIOCGPPPCSTATS: case SIOCGPPPVER: { u32 data; int len; __get_user(data, &(((struct ifreq32 *)A(arg))->ifr_ifru.ifru_data)); if(cmd == SIOCGPPPVER) len = strlen(PPP_VERSION) + 1; else if(cmd == SIOCGPPPCSTATS) len = sizeof(struct ppp_comp_stats); else len = sizeof(struct ppp_stats); if (copy_to_user((char *)A(data), ifr.ifr_data, len)) return -EFAULT; break; } case SIOCGIFMAP: if (copy_to_user((struct ifreq32 *)A(arg), &ifr, sizeof(ifr.ifr_name)) || __put_user(ifr.ifr_map.mem_start, &(((struct ifreq32 *)A(arg))->ifr_ifru.ifru_map.mem_start)) || __put_user(ifr.ifr_map.mem_end, &(((struct ifreq32 *)A(arg))->ifr_ifru.ifru_map.mem_end)) || __put_user(ifr.ifr_map.base_addr, &(((struct ifreq32 *)A(arg))->ifr_ifru.ifru_map.base_addr)) || __put_user(ifr.ifr_map.irq, &(((struct ifreq32 *)A(arg))->ifr_ifru.ifru_map.irq)) || __put_user(ifr.ifr_map.dma, &(((struct ifreq32 *)A(arg))->ifr_ifru.ifru_map.dma)) || __put_user(ifr.ifr_map.port, &(((struct ifreq32 *)A(arg))->ifr_ifru.ifru_map.port))) return -EFAULT; break; } } return err; } struct rtentry32 { u32 rt_pad1; struct sockaddr rt_dst; /* target address */ struct sockaddr rt_gateway; /* gateway addr (RTF_GATEWAY) */ struct sockaddr rt_genmask; /* target network mask (IP) */ unsigned short rt_flags; short rt_pad2; u32 rt_pad3; unsigned char rt_tos; unsigned char rt_class; short rt_pad4; short rt_metric; /* +1 for binary compatibility! */ /* char * */ u32 rt_dev; /* forcing the device at add */ u32 rt_mtu; /* per route MTU/Window */ u32 rt_window; /* Window clamping */ unsigned short rt_irtt; /* Initial RTT */ }; static inline int routing_ioctl(unsigned int fd, unsigned int cmd, u32 arg) { struct rtentry r; char devname[16]; u32 rtdev; int ret; mm_segment_t old_fs = get_fs(); if (copy_from_user (&r.rt_dst, &(((struct rtentry32 *)A(arg))->rt_dst), 3 * sizeof(struct sockaddr)) || __get_user (r.rt_flags, &(((struct rtentry32 *)A(arg))->rt_flags)) || __get_user (r.rt_metric, &(((struct rtentry32 *)A(arg))->rt_metric)) || __get_user (r.rt_mtu, &(((struct rtentry32 *)A(arg))->rt_mtu)) || __get_user (r.rt_window, &(((struct rtentry32 *)A(arg))->rt_window)) || __get_user (r.rt_irtt, &(((struct rtentry32 *)A(arg))->rt_irtt)) || __get_user (rtdev, &(((struct rtentry32 *)A(arg))->rt_dev)) || (rtdev && copy_from_user (devname, (char *)A(rtdev), 15))) return -EFAULT; if (rtdev) { r.rt_dev = devname; devname[15] = 0; } else r.rt_dev = 0; set_fs (KERNEL_DS); ret = sys_ioctl (fd, cmd, (long)&r); set_fs (old_fs); return ret; } struct hd_geometry32 { unsigned char heads; unsigned char sectors; unsigned short cylinders; u32 start; }; static inline int hdio_getgeo(unsigned int fd, u32 arg) { mm_segment_t old_fs = get_fs(); struct hd_geometry geo; int err; set_fs (KERNEL_DS); err = sys_ioctl(fd, HDIO_GETGEO, (unsigned long)&geo); set_fs (old_fs); if (!err) { if (copy_to_user ((struct hd_geometry32 *)A(arg), &geo, 4) || __put_user (geo.start, &(((struct hd_geometry32 *)A(arg))->start))) return -EFAULT; } return err; } struct fbcmap32 { int index; /* first element (0 origin) */ int count; u32 red; u32 green; u32 blue; }; #define FBIOPUTCMAP32 _IOW('F', 3, struct fbcmap32) #define FBIOGETCMAP32 _IOW('F', 4, struct fbcmap32) static inline int fbiogetputcmap(unsigned int fd, unsigned int cmd, u32 arg) { struct fbcmap f; int ret; char red[256], green[256], blue[256]; u32 r, g, b; mm_segment_t old_fs = get_fs(); if (get_user(f.index, &(((struct fbcmap32 *)A(arg))->index)) || __get_user(f.count, &(((struct fbcmap32 *)A(arg))->count)) || __get_user(r, &(((struct fbcmap32 *)A(arg))->red)) || __get_user(g, &(((struct fbcmap32 *)A(arg))->green)) || __get_user(b, &(((struct fbcmap32 *)A(arg))->blue))) return -EFAULT; if ((f.index < 0) || (f.index > 255)) return -EINVAL; if (f.index + f.count > 256) f.count = 256 - f.index; if (cmd == FBIOPUTCMAP32) { if (copy_from_user (red, (char *)A(r), f.count) || copy_from_user (green, (char *)A(g), f.count) || copy_from_user (blue, (char *)A(b), f.count)) return -EFAULT; } f.red = red; f.green = green; f.blue = blue; set_fs (KERNEL_DS); ret = sys_ioctl (fd, (cmd == FBIOPUTCMAP32) ? FBIOPUTCMAP : FBIOGETCMAP, (long)&f); set_fs (old_fs); if (!ret && cmd == FBIOGETCMAP32) { if (copy_to_user ((char *)A(r), red, f.count) || copy_to_user ((char *)A(g), green, f.count) || copy_to_user ((char *)A(b), blue, f.count)) return -EFAULT; } return ret; } struct fbcursor32 { short set; /* what to set, choose from the list above */ short enable; /* cursor on/off */ struct fbcurpos pos; /* cursor position */ struct fbcurpos hot; /* cursor hot spot */ struct fbcmap32 cmap; /* color map info */ struct fbcurpos size; /* cursor bit map size */ u32 image; /* cursor image bits */ u32 mask; /* cursor mask bits */ }; #define FBIOSCURSOR32 _IOW('F', 24, struct fbcursor32) #define FBIOGCURSOR32 _IOW('F', 25, struct fbcursor32) static inline int fbiogscursor(unsigned int fd, unsigned int cmd, u32 arg) { struct fbcursor f; int ret; char red[2], green[2], blue[2]; char image[128], mask[128]; u32 r, g, b; u32 m, i; mm_segment_t old_fs = get_fs(); if (copy_from_user (&f, (struct fbcursor32 *)A(arg), 2 * sizeof (short) + 2 * sizeof(struct fbcurpos)) || __get_user(f.size.fbx, &(((struct fbcursor32 *)A(arg))->size.fbx)) || __get_user(f.size.fby, &(((struct fbcursor32 *)A(arg))->size.fby)) || __get_user(f.cmap.index, &(((struct fbcursor32 *)A(arg))->cmap.index)) || __get_user(f.cmap.count, &(((struct fbcursor32 *)A(arg))->cmap.count)) || __get_user(r, &(((struct fbcursor32 *)A(arg))->cmap.red)) || __get_user(g, &(((struct fbcursor32 *)A(arg))->cmap.green)) || __get_user(b, &(((struct fbcursor32 *)A(arg))->cmap.blue)) || __get_user(m, &(((struct fbcursor32 *)A(arg))->mask)) || __get_user(i, &(((struct fbcursor32 *)A(arg))->image))) return -EFAULT; if (f.set & FB_CUR_SETCMAP) { if ((uint) f.size.fby > 32) return -EINVAL; if (copy_from_user (mask, (char *)A(m), f.size.fby * 4) || copy_from_user (image, (char *)A(i), f.size.fby * 4)) return -EFAULT; f.image = image; f.mask = mask; } if (f.set & FB_CUR_SETCMAP) { if (copy_from_user (red, (char *)A(r), 2) || copy_from_user (green, (char *)A(g), 2) || copy_from_user (blue, (char *)A(b), 2)) return -EFAULT; f.cmap.red = red; f.cmap.green = green; f.cmap.blue = blue; } set_fs (KERNEL_DS); ret = sys_ioctl (fd, FBIOSCURSOR, (long)&f); set_fs (old_fs); return ret; } static int hdio_ioctl_trans(unsigned int fd, unsigned int cmd, u32 arg) { mm_segment_t old_fs = get_fs(); unsigned long kval; unsigned int *uvp; int error; set_fs(KERNEL_DS); error = sys_ioctl(fd, cmd, (long)&kval); set_fs(old_fs); if(error == 0) { uvp = (unsigned int *)A(arg); if(put_user(kval, uvp)) error = -EFAULT; } return error; } struct floppy_struct32 { unsigned int size; unsigned int sect; unsigned int head; unsigned int track; unsigned int stretch; unsigned char gap; unsigned char rate; unsigned char spec1; unsigned char fmt_gap; const __kernel_caddr_t32 name; }; struct floppy_drive_params32 { char cmos; u32 max_dtr; u32 hlt; u32 hut; u32 srt; u32 spinup; u32 spindown; unsigned char spindown_offset; unsigned char select_delay; unsigned char rps; unsigned char tracks; u32 timeout; unsigned char interleave_sect; struct floppy_max_errors max_errors; char flags; char read_track; short autodetect[8]; int checkfreq; int native_format; }; struct floppy_drive_struct32 { signed char flags; u32 spinup_date; u32 select_date; u32 first_read_date; short probed_format; short track; short maxblock; short maxtrack; int generation; int keep_data; int fd_ref; int fd_device; int last_checked; __kernel_caddr_t32 dmabuf; int bufblocks; }; struct floppy_fdc_state32 { int spec1; int spec2; int dtr; unsigned char version; unsigned char dor; u32 address; unsigned int rawcmd:2; unsigned int reset:1; unsigned int need_configure:1; unsigned int perp_mode:2; unsigned int has_fifo:1; unsigned int driver_version; unsigned char track[4]; }; struct floppy_write_errors32 { unsigned int write_errors; u32 first_error_sector; int first_error_generation; u32 last_error_sector; int last_error_generation; unsigned int badness; }; #define FDSETPRM32 _IOW(2, 0x42, struct floppy_struct32) #define FDDEFPRM32 _IOW(2, 0x43, struct floppy_struct32) #define FDGETPRM32 _IOR(2, 0x04, struct floppy_struct32) #define FDSETDRVPRM32 _IOW(2, 0x90, struct floppy_drive_params32) #define FDGETDRVPRM32 _IOR(2, 0x11, struct floppy_drive_params32) #define FDGETDRVSTAT32 _IOR(2, 0x12, struct floppy_drive_struct32) #define FDPOLLDRVSTAT32 _IOR(2, 0x13, struct floppy_drive_struct32) #define FDGETFDCSTAT32 _IOR(2, 0x15, struct floppy_fdc_state32) #define FDWERRORGET32 _IOR(2, 0x17, struct floppy_write_errors32) static struct { unsigned int cmd32; unsigned int cmd; } fd_ioctl_trans_table[] = { { FDSETPRM32, FDSETPRM }, { FDDEFPRM32, FDDEFPRM }, { FDGETPRM32, FDGETPRM }, { FDSETDRVPRM32, FDSETDRVPRM }, { FDGETDRVPRM32, FDGETDRVPRM }, { FDGETDRVSTAT32, FDGETDRVSTAT }, { FDPOLLDRVSTAT32, FDPOLLDRVSTAT }, { FDGETFDCSTAT32, FDGETFDCSTAT }, { FDWERRORGET32, FDWERRORGET } }; #define NR_FD_IOCTL_TRANS (sizeof(fd_ioctl_trans_table)/sizeof(fd_ioctl_trans_table[0])) static int fd_ioctl_trans(unsigned int fd, unsigned int cmd, u32 arg) { mm_segment_t old_fs = get_fs(); void *karg; unsigned int kcmd = 0; int i, err; for (i = 0; i < NR_FD_IOCTL_TRANS; i++) if (cmd == fd_ioctl_trans_table[i].cmd32) { kcmd = fd_ioctl_trans_table[i].cmd; break; } if (!kcmd) return -EINVAL; switch (cmd) { case FDSETPRM32: case FDDEFPRM32: case FDGETPRM32: { struct floppy_struct *f; f = karg = kmalloc(GFP_KERNEL, sizeof(struct floppy_struct)); if (!karg) return -ENOMEM; if (cmd == FDGETPRM32) break; if (__get_user(f->size, &((struct floppy_struct32 *)A(arg))->size) || __get_user(f->sect, &((struct floppy_struct32 *)A(arg))->sect) || __get_user(f->head, &((struct floppy_struct32 *)A(arg))->head) || __get_user(f->track, &((struct floppy_struct32 *)A(arg))->track) || __get_user(f->stretch, &((struct floppy_struct32 *)A(arg))->stretch) || __get_user(f->gap, &((struct floppy_struct32 *)A(arg))->gap) || __get_user(f->rate, &((struct floppy_struct32 *)A(arg))->rate) || __get_user(f->spec1, &((struct floppy_struct32 *)A(arg))->spec1) || __get_user(f->fmt_gap, &((struct floppy_struct32 *)A(arg))->fmt_gap) || __get_user((u64)f->name, &((struct floppy_struct32 *)A(arg))->name)) { kfree(karg); return -EFAULT; } break; } case FDSETDRVPRM32: case FDGETDRVPRM32: { struct floppy_drive_params *f; f = karg = kmalloc(GFP_KERNEL, sizeof(struct floppy_drive_params)); if (!karg) return -ENOMEM; if (cmd == FDGETDRVPRM32) break; if (__get_user(f->cmos, &((struct floppy_drive_params32 *)A(arg))->cmos) || __get_user(f->max_dtr, &((struct floppy_drive_params32 *)A(arg))->max_dtr) || __get_user(f->hlt, &((struct floppy_drive_params32 *)A(arg))->hlt) || __get_user(f->hut, &((struct floppy_drive_params32 *)A(arg))->hut) || __get_user(f->srt, &((struct floppy_drive_params32 *)A(arg))->srt) || __get_user(f->spinup, &((struct floppy_drive_params32 *)A(arg))->spinup) || __get_user(f->spindown, &((struct floppy_drive_params32 *)A(arg))->spindown) || __get_user(f->spindown_offset, &((struct floppy_drive_params32 *)A(arg))->spindown_offset) || __get_user(f->select_delay, &((struct floppy_drive_params32 *)A(arg))->select_delay) || __get_user(f->rps, &((struct floppy_drive_params32 *)A(arg))->rps) || __get_user(f->tracks, &((struct floppy_drive_params32 *)A(arg))->tracks) || __get_user(f->timeout, &((struct floppy_drive_params32 *)A(arg))->timeout) || __get_user(f->interleave_sect, &((struct floppy_drive_params32 *)A(arg))->interleave_sect) || __copy_from_user(&f->max_errors, &((struct floppy_drive_params32 *)A(arg))->max_errors, sizeof(f->max_errors)) || __get_user(f->flags, &((struct floppy_drive_params32 *)A(arg))->flags) || __get_user(f->read_track, &((struct floppy_drive_params32 *)A(arg))->read_track) || __copy_from_user(f->autodetect, ((struct floppy_drive_params32 *)A(arg))->autodetect, sizeof(f->autodetect)) || __get_user(f->checkfreq, &((struct floppy_drive_params32 *)A(arg))->checkfreq) || __get_user(f->native_format, &((struct floppy_drive_params32 *)A(arg))->native_format)) { kfree(karg); return -EFAULT; } break; } case FDGETDRVSTAT32: case FDPOLLDRVSTAT32: karg = kmalloc(GFP_KERNEL, sizeof(struct floppy_drive_struct)); if (!karg) return -ENOMEM; break; case FDGETFDCSTAT32: karg = kmalloc(GFP_KERNEL, sizeof(struct floppy_fdc_state)); if (!karg) return -ENOMEM; break; case FDWERRORGET32: karg = kmalloc(GFP_KERNEL, sizeof(struct floppy_write_errors)); if (!karg) return -ENOMEM; break; default: return -EINVAL; } set_fs (KERNEL_DS); err = sys_ioctl (fd, kcmd, (unsigned long)karg); set_fs (old_fs); if (err) { kfree(karg); return err; } switch (cmd) { case FDGETPRM32: { struct floppy_struct *f = karg; if (__put_user(f->size, &((struct floppy_struct32 *)A(arg))->size) || __put_user(f->sect, &((struct floppy_struct32 *)A(arg))->sect) || __put_user(f->head, &((struct floppy_struct32 *)A(arg))->head) || __put_user(f->track, &((struct floppy_struct32 *)A(arg))->track) || __put_user(f->stretch, &((struct floppy_struct32 *)A(arg))->stretch) || __put_user(f->gap, &((struct floppy_struct32 *)A(arg))->gap) || __put_user(f->rate, &((struct floppy_struct32 *)A(arg))->rate) || __put_user(f->spec1, &((struct floppy_struct32 *)A(arg))->spec1) || __put_user(f->fmt_gap, &((struct floppy_struct32 *)A(arg))->fmt_gap) || __put_user((u64)f->name, &((struct floppy_struct32 *)A(arg))->name)) { kfree(karg); return -EFAULT; } break; } case FDGETDRVPRM32: { struct floppy_drive_params *f = karg; if (__put_user(f->cmos, &((struct floppy_drive_params32 *)A(arg))->cmos) || __put_user(f->max_dtr, &((struct floppy_drive_params32 *)A(arg))->max_dtr) || __put_user(f->hlt, &((struct floppy_drive_params32 *)A(arg))->hlt) || __put_user(f->hut, &((struct floppy_drive_params32 *)A(arg))->hut) || __put_user(f->srt, &((struct floppy_drive_params32 *)A(arg))->srt) || __put_user(f->spinup, &((struct floppy_drive_params32 *)A(arg))->spinup) || __put_user(f->spindown, &((struct floppy_drive_params32 *)A(arg))->spindown) || __put_user(f->spindown_offset, &((struct floppy_drive_params32 *)A(arg))->spindown_offset) || __put_user(f->select_delay, &((struct floppy_drive_params32 *)A(arg))->select_delay) || __put_user(f->rps, &((struct floppy_drive_params32 *)A(arg))->rps) || __put_user(f->tracks, &((struct floppy_drive_params32 *)A(arg))->tracks) || __put_user(f->timeout, &((struct floppy_drive_params32 *)A(arg))->timeout) || __put_user(f->interleave_sect, &((struct floppy_drive_params32 *)A(arg))->interleave_sect) || __copy_to_user(&((struct floppy_drive_params32 *)A(arg))->max_errors, &f->max_errors, sizeof(f->max_errors)) || __put_user(f->flags, &((struct floppy_drive_params32 *)A(arg))->flags) || __put_user(f->read_track, &((struct floppy_drive_params32 *)A(arg))->read_track) || __copy_to_user(((struct floppy_drive_params32 *)A(arg))->autodetect, f->autodetect, sizeof(f->autodetect)) || __put_user(f->checkfreq, &((struct floppy_drive_params32 *)A(arg))->checkfreq) || __put_user(f->native_format, &((struct floppy_drive_params32 *)A(arg))->native_format)) { kfree(karg); return -EFAULT; } break; } case FDGETDRVSTAT32: case FDPOLLDRVSTAT32: { struct floppy_drive_struct *f = karg; if (__put_user(f->flags, &((struct floppy_drive_struct32 *)A(arg))->flags) || __put_user(f->spinup_date, &((struct floppy_drive_struct32 *)A(arg))->spinup_date) || __put_user(f->select_date, &((struct floppy_drive_struct32 *)A(arg))->select_date) || __put_user(f->first_read_date, &((struct floppy_drive_struct32 *)A(arg))->first_read_date) || __put_user(f->probed_format, &((struct floppy_drive_struct32 *)A(arg))->probed_format) || __put_user(f->track, &((struct floppy_drive_struct32 *)A(arg))->track) || __put_user(f->maxblock, &((struct floppy_drive_struct32 *)A(arg))->maxblock) || __put_user(f->maxtrack, &((struct floppy_drive_struct32 *)A(arg))->maxtrack) || __put_user(f->generation, &((struct floppy_drive_struct32 *)A(arg))->generation) || __put_user(f->keep_data, &((struct floppy_drive_struct32 *)A(arg))->keep_data) || __put_user(f->fd_ref, &((struct floppy_drive_struct32 *)A(arg))->fd_ref) || __put_user(f->fd_device, &((struct floppy_drive_struct32 *)A(arg))->fd_device) || __put_user(f->last_checked, &((struct floppy_drive_struct32 *)A(arg))->last_checked) || __put_user((u64)f->dmabuf, &((struct floppy_drive_struct32 *)A(arg))->dmabuf) || __put_user((u64)f->bufblocks, &((struct floppy_drive_struct32 *)A(arg))->bufblocks)) { kfree(karg); return -EFAULT; } break; } case FDGETFDCSTAT32: { struct floppy_fdc_state *f = karg; if (__put_user(f->spec1, &((struct floppy_fdc_state32 *)A(arg))->spec1) || __put_user(f->spec2, &((struct floppy_fdc_state32 *)A(arg))->spec2) || __put_user(f->dtr, &((struct floppy_fdc_state32 *)A(arg))->dtr) || __put_user(f->version, &((struct floppy_fdc_state32 *)A(arg))->version) || __put_user(f->dor, &((struct floppy_fdc_state32 *)A(arg))->dor) || __put_user(f->address, &((struct floppy_fdc_state32 *)A(arg))->address) || __copy_to_user((char *)&((struct floppy_fdc_state32 *)A(arg))->address + sizeof(((struct floppy_fdc_state32 *)A(arg))->address), (char *)&f->address + sizeof(f->address), sizeof(int)) || __put_user(f->driver_version, &((struct floppy_fdc_state32 *)A(arg))->driver_version) || __copy_to_user(((struct floppy_fdc_state32 *)A(arg))->track, f->track, sizeof(f->track))) { kfree(karg); return -EFAULT; } break; } case FDWERRORGET32: { struct floppy_write_errors *f = karg; if (__put_user(f->write_errors, &((struct floppy_write_errors32 *)A(arg))->write_errors) || __put_user(f->first_error_sector, &((struct floppy_write_errors32 *)A(arg))->first_error_sector) || __put_user(f->first_error_generation, &((struct floppy_write_errors32 *)A(arg))->first_error_generation) || __put_user(f->last_error_sector, &((struct floppy_write_errors32 *)A(arg))->last_error_sector) || __put_user(f->last_error_generation, &((struct floppy_write_errors32 *)A(arg))->last_error_generation) || __put_user(f->badness, &((struct floppy_write_errors32 *)A(arg))->badness)) { kfree(karg); return -EFAULT; } break; } default: break; } kfree(karg); return 0; } struct ppp_option_data32 { __kernel_caddr_t32 ptr; __u32 length; int transmit; }; #define PPPIOCSCOMPRESS32 _IOW('t', 77, struct ppp_option_data32) struct ppp_idle32 { __kernel_time_t32 xmit_idle; __kernel_time_t32 recv_idle; }; #define PPPIOCGIDLE32 _IOR('t', 63, struct ppp_idle32) static int ppp_ioctl_trans(unsigned int fd, unsigned int cmd, u32 arg) { mm_segment_t old_fs = get_fs(); struct ppp_option_data32 data32; struct ppp_option_data data; struct ppp_idle32 idle32; struct ppp_idle idle; unsigned int kcmd; void *karg; int err = 0; switch (cmd) { case PPPIOCGIDLE32: kcmd = PPPIOCGIDLE; karg = &idle; break; case PPPIOCSCOMPRESS32: if (copy_from_user(&data32, (struct ppp_option_data32 *)A(arg), sizeof(struct ppp_option_data32))) return -EFAULT; data.ptr = kmalloc (data32.length, GFP_KERNEL); if (!data.ptr) return -ENOMEM; if (copy_from_user(data.ptr, (__u8 *)A(data32.ptr), data32.length)) { kfree(data.ptr); return -EFAULT; } data.length = data32.length; data.transmit = data32.transmit; kcmd = PPPIOCSCOMPRESS; karg = &data; break; default: printk("ppp_ioctl: Unknown cmd fd(%d) cmd(%08x) arg(%08x)\n", (int)fd, (unsigned int)cmd, (unsigned int)arg); return -EINVAL; } set_fs (KERNEL_DS); err = sys_ioctl (fd, kcmd, (unsigned long)karg); set_fs (old_fs); switch (cmd) { case PPPIOCGIDLE32: if (err) return err; idle32.xmit_idle = idle.xmit_idle; idle32.recv_idle = idle.recv_idle; if (copy_to_user((struct ppp_idle32 *)A(arg), &idle32, sizeof(struct ppp_idle32))) return -EFAULT; break; case PPPIOCSCOMPRESS32: kfree(data.ptr); break; default: break; } return err; } struct mtget32 { __u32 mt_type; __u32 mt_resid; __u32 mt_dsreg; __u32 mt_gstat; __u32 mt_erreg; __kernel_daddr_t32 mt_fileno; __kernel_daddr_t32 mt_blkno; }; #define MTIOCGET32 _IOR('m', 2, struct mtget32) struct mtpos32 { __u32 mt_blkno; }; #define MTIOCPOS32 _IOR('m', 3, struct mtpos32) struct mtconfiginfo32 { __u32 mt_type; __u32 ifc_type; __u16 irqnr; __u16 dmanr; __u16 port; __u32 debug; __u32 have_dens:1; __u32 have_bsf:1; __u32 have_fsr:1; __u32 have_bsr:1; __u32 have_eod:1; __u32 have_seek:1; __u32 have_tell:1; __u32 have_ras1:1; __u32 have_ras2:1; __u32 have_ras3:1; __u32 have_qfa:1; __u32 pad1:5; char reserved[10]; }; #define MTIOCGETCONFIG32 _IOR('m', 4, struct mtconfiginfo32) #define MTIOCSETCONFIG32 _IOW('m', 5, struct mtconfiginfo32) static int mt_ioctl_trans(unsigned int fd, unsigned int cmd, u32 arg) { mm_segment_t old_fs = get_fs(); struct mtconfiginfo info; struct mtget get; struct mtpos pos; unsigned long kcmd; void *karg; int err = 0; switch(cmd) { case MTIOCPOS32: kcmd = MTIOCPOS; karg = &pos; break; case MTIOCGET32: kcmd = MTIOCGET; karg = &get; break; case MTIOCGETCONFIG32: kcmd = MTIOCGETCONFIG; karg = &info; break; case MTIOCSETCONFIG32: kcmd = MTIOCSETCONFIG; karg = &info; if (__get_user(info.mt_type, &((struct mtconfiginfo32 *)A(arg))->mt_type) || __get_user(info.ifc_type, &((struct mtconfiginfo32 *)A(arg))->ifc_type) || __get_user(info.irqnr, &((struct mtconfiginfo32 *)A(arg))->irqnr) || __get_user(info.dmanr, &((struct mtconfiginfo32 *)A(arg))->dmanr) || __get_user(info.port, &((struct mtconfiginfo32 *)A(arg))->port) || __get_user(info.debug, &((struct mtconfiginfo32 *)A(arg))->debug) || __copy_from_user((char *)&info.debug + sizeof(info.debug), (char *)&((struct mtconfiginfo32 *)A(arg))->debug + sizeof(((struct mtconfiginfo32 *)A(arg))->debug), sizeof(__u32))) return -EFAULT; break; default: printk("mt_ioctl: Unknown cmd fd(%d) cmd(%08x) arg(%08x)\n", (int)fd, (unsigned int)cmd, (unsigned int)arg); return -EINVAL; } set_fs (KERNEL_DS); err = sys_ioctl (fd, kcmd, (unsigned long)karg); set_fs (old_fs); if (err) return err; switch (cmd) { case MTIOCPOS32: if (__put_user(pos.mt_blkno, &((struct mtpos32 *)A(arg))->mt_blkno)) return -EFAULT; break; case MTIOCGET32: if (__put_user(get.mt_type, &((struct mtget32 *)A(arg))->mt_type) || __put_user(get.mt_resid, &((struct mtget32 *)A(arg))->mt_resid) || __put_user(get.mt_dsreg, &((struct mtget32 *)A(arg))->mt_dsreg) || __put_user(get.mt_gstat, &((struct mtget32 *)A(arg))->mt_gstat) || __put_user(get.mt_erreg, &((struct mtget32 *)A(arg))->mt_erreg) || __put_user(get.mt_fileno, &((struct mtget32 *)A(arg))->mt_fileno) || __put_user(get.mt_blkno, &((struct mtget32 *)A(arg))->mt_blkno)) return -EFAULT; break; case MTIOCGETCONFIG32: if (__put_user(info.mt_type, &((struct mtconfiginfo32 *)A(arg))->mt_type) || __put_user(info.ifc_type, &((struct mtconfiginfo32 *)A(arg))->ifc_type) || __put_user(info.irqnr, &((struct mtconfiginfo32 *)A(arg))->irqnr) || __put_user(info.dmanr, &((struct mtconfiginfo32 *)A(arg))->dmanr) || __put_user(info.port, &((struct mtconfiginfo32 *)A(arg))->port) || __put_user(info.debug, &((struct mtconfiginfo32 *)A(arg))->debug) || __copy_to_user((char *)&((struct mtconfiginfo32 *)A(arg))->debug + sizeof(((struct mtconfiginfo32 *)A(arg))->debug), (char *)&info.debug + sizeof(info.debug), sizeof(__u32))) return -EFAULT; break; case MTIOCSETCONFIG32: break; } return 0; } asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, u32 arg) { struct file * filp; int error = -EBADF; lock_kernel(); if(fd >= NR_OPEN) goto out; filp = current->files->fd[fd]; if(!filp) goto out; if (!filp->f_op || !filp->f_op->ioctl) { error = sys_ioctl (fd, cmd, (unsigned long)arg); goto out; } error = -EFAULT; switch (cmd) { case SIOCGIFCONF: error = dev_ifconf(fd, arg); goto out; case SIOCGIFFLAGS: case SIOCSIFFLAGS: case SIOCGIFMETRIC: case SIOCSIFMETRIC: case SIOCGIFMTU: case SIOCSIFMTU: case SIOCGIFMEM: case SIOCSIFMEM: case SIOCGIFHWADDR: case SIOCSIFHWADDR: case SIOCADDMULTI: case SIOCDELMULTI: case SIOCGIFINDEX: case SIOCGIFMAP: case SIOCSIFMAP: case SIOCGIFADDR: case SIOCSIFADDR: case SIOCGIFBRDADDR: case SIOCSIFBRDADDR: case SIOCGIFDSTADDR: case SIOCSIFDSTADDR: case SIOCGIFNETMASK: case SIOCSIFNETMASK: case SIOCSIFPFLAGS: case SIOCGIFPFLAGS: case SIOCGPPPSTATS: case SIOCGPPPCSTATS: case SIOCGPPPVER: error = dev_ifsioc(fd, cmd, arg); goto out; case SIOCADDRT: case SIOCDELRT: error = routing_ioctl(fd, cmd, arg); goto out; case SIOCRTMSG: /* Note SIOCRTMSG is no longer, so this is safe and * the user would have seen just an -EINVAL anyways. */ error = -EINVAL; goto out; case HDIO_GETGEO: error = hdio_getgeo(fd, arg); goto out; case BLKRAGET: case BLKGETSIZE: error = w_long(fd, cmd, arg); goto out; case FBIOPUTCMAP32: case FBIOGETCMAP32: error = fbiogetputcmap(fd, cmd, arg); goto out; case FBIOSCURSOR32: error = fbiogscursor(fd, cmd, arg); goto out; case HDIO_GET_KEEPSETTINGS: case HDIO_GET_UNMASKINTR: case HDIO_GET_DMA: case HDIO_GET_32BIT: case HDIO_GET_MULTCOUNT: case HDIO_GET_NOWERR: case HDIO_GET_NICE: error = hdio_ioctl_trans(fd, cmd, arg); goto out; case FDSETPRM32: case FDDEFPRM32: case FDGETPRM32: case FDSETDRVPRM32: case FDGETDRVPRM32: case FDGETDRVSTAT32: case FDPOLLDRVSTAT32: case FDGETFDCSTAT32: case FDWERRORGET32: error = fd_ioctl_trans(fd, cmd, (unsigned long)arg); goto out; case PPPIOCGIDLE32: case PPPIOCSCOMPRESS32: error = ppp_ioctl_trans(fd, cmd, arg); goto out; case MTIOCGET32: case MTIOCPOS32: case MTIOCGETCONFIG32: case MTIOCSETCONFIG32: error = mt_ioctl_trans(fd, cmd, arg); goto out; /* List here exlicitly which ioctl's are known to have * compatable types passed or none at all... */ /* Bit T */ case TCGETA: case TCSETA: case TCSETAW: case TCSETAF: case TCSBRK: case TCXONC: case TCFLSH: case TCGETS: case TCSETS: case TCSETSW: case TCSETSF: case TIOCLINUX: /* Little t */ case TIOCGETD: case TIOCSETD: case TIOCEXCL: case TIOCNXCL: case TIOCCONS: case TIOCGSOFTCAR: case TIOCSSOFTCAR: case TIOCSWINSZ: case TIOCGWINSZ: case TIOCMGET: case TIOCMBIC: case TIOCMBIS: case TIOCMSET: case TIOCPKT: case TIOCNOTTY: case TIOCSTI: case TIOCOUTQ: case TIOCSPGRP: case TIOCGPGRP: case TIOCSCTTY: /* Big F */ case FBIOGTYPE: case FBIOSATTR: case FBIOGATTR: case FBIOSVIDEO: case FBIOGVIDEO: case FBIOGCURSOR32: /* This is not implemented yet. Later it should be converted... */ case FBIOSCURPOS: case FBIOGCURPOS: case FBIOGCURMAX: /* Little f */ case FIOCLEX: case FIONCLEX: case FIOASYNC: case FIONBIO: case FIONREAD: /* This is also TIOCINQ */ /* 0x00 */ case FIBMAP: case FIGETBSZ: /* 0x03 -- HD/IDE ioctl's used by hdparm and friends. * Some need translations, these do not. */ case HDIO_GET_IDENTITY: case HDIO_SET_DMA: case HDIO_SET_KEEPSETTINGS: case HDIO_SET_UNMASKINTR: case HDIO_SET_NOWERR: case HDIO_SET_32BIT: case HDIO_SET_MULTCOUNT: case HDIO_DRIVE_CMD: case HDIO_SET_PIO_MODE: case HDIO_SCAN_HWIF: case HDIO_SET_NICE: case BLKROSET: case BLKROGET: /* 0x02 -- Floppy ioctls */ case FDMSGON: case FDMSGOFF: case FDSETEMSGTRESH: case FDFLUSH: case FDWERRORCLR: case FDSETMAXERRS: case FDGETMAXERRS: case FDGETDRVTYP: case FDEJECT: case FDCLRPRM: case FDFMTBEG: case FDFMTEND: case FDRESET: case FDTWADDLE: case FDFMTTRK: case FDRAWCMD: /* 0x12 */ case BLKRRPART: case BLKFLSBUF: case BLKRASET: /* 0x09 */ case REGISTER_DEV: case START_MD: case STOP_MD: /* Big K */ case PIO_FONT: case GIO_FONT: case KDSIGACCEPT: case KDGETKEYCODE: case KDSETKEYCODE: case KIOCSOUND: case KDMKTONE: case KDGKBTYPE: case KDSETMODE: case KDGETMODE: case KDSKBMODE: case KDGKBMODE: case KDSKBMETA: case KDGKBMETA: case KDGKBENT: case KDSKBENT: case KDGKBSENT: case KDSKBSENT: case KDGKBDIACR: case KDSKBDIACR: case KDGKBLED: case KDSKBLED: case KDGETLED: case KDSETLED: /* Little k */ case KIOCTYPE: case KIOCLAYOUT: case KIOCGTRANS: case KIOCTRANS: case KIOCCMD: case KIOCSDIRECT: case KIOCSLED: case KIOCGLED: case KIOCSRATE: case KIOCGRATE: /* Big S */ case SCSI_IOCTL_GET_IDLUN: case SCSI_IOCTL_DOORLOCK: case SCSI_IOCTL_DOORUNLOCK: case SCSI_IOCTL_TEST_UNIT_READY: case SCSI_IOCTL_TAGGED_ENABLE: case SCSI_IOCTL_TAGGED_DISABLE: case SCSI_IOCTL_GET_BUS_NUMBER: /* Big V */ case VT_SETMODE: case VT_GETMODE: case VT_GETSTATE: case VT_OPENQRY: case VT_ACTIVATE: case VT_WAITACTIVE: case VT_RELDISP: case VT_DISALLOCATE: case VT_RESIZE: case VT_RESIZEX: case VT_LOCKSWITCH: case VT_UNLOCKSWITCH: /* Little v */ case VUIDSFORMAT: case VUIDGFORMAT: /* Little p (/dev/rtc etc.) */ case RTCGET: case RTCSET: /* Little m */ case MTIOCTOP: /* OPENPROMIO, SunOS/Solaris only, the NetBSD one's have * embedded pointers in the arg which we'd need to clean up... */ case OPROMGETOPT: case OPROMSETOPT: case OPROMNXTOPT: case OPROMSETOPT2: case OPROMNEXT: case OPROMCHILD: case OPROMGETPROP: case OPROMNXTPROP: case OPROMU2P: case OPROMGETCONS: case OPROMGETFBNAME: case OPROMGETBOOTARGS: /* Socket level stuff */ case FIOSETOWN: case SIOCSPGRP: case FIOGETOWN: case SIOCGPGRP: case SIOCATMARK: case SIOCGSTAMP: case SIOCSIFLINK: case SIOCSIFENCAP: case SIOCGIFENCAP: case SIOCSIFBR: case SIOCGIFBR: case SIOCSARP: case SIOCGARP: case SIOCDARP: #if 0 /* XXX No longer exist in new routing code. XXX */ case OLD_SIOCSARP: case OLD_SIOCGARP: case OLD_SIOCDARP: #endif case SIOCSRARP: case SIOCGRARP: case SIOCDRARP: case SIOCADDDLCI: case SIOCDELDLCI: /* PPP stuff */ case PPPIOCGFLAGS: case PPPIOCSFLAGS: case PPPIOCGASYNCMAP: case PPPIOCSASYNCMAP: case PPPIOCGUNIT: case PPPIOCGRASYNCMAP: case PPPIOCSRASYNCMAP: case PPPIOCGMRU: case PPPIOCSMRU: case PPPIOCSMAXCID: case PPPIOCGXASYNCMAP: case PPPIOCSXASYNCMAP: case PPPIOCXFERUNIT: case PPPIOCGNPMODE: case PPPIOCSNPMODE: case PPPIOCGDEBUG: case PPPIOCSDEBUG: error = sys_ioctl (fd, cmd, (unsigned long)arg); goto out; default: printk("sys32_ioctl: Unknown cmd fd(%d) cmd(%08x) arg(%08x)\n", (int)fd, (unsigned int)cmd, (unsigned int)arg); error = -EINVAL; goto out; break; } out: unlock_kernel(); return error; }