📄 ioctl32.c
字号:
/* $Id: ioctl32.c,v 1.12 2002/07/08 20:52:15 grundler Exp $ * ioctl32.c: Conversion between 32bit and 64bit native ioctls. * * Copyright (C) 1997-2000 Jakub Jelinek (jakub@redhat.com) * Copyright (C) 1998 Eddie C. Dost (ecd@skynet.be) * * These routines maintain argument size conversion between 32bit and 64bit * ioctls. */#include <linux/config.h>#include <linux/types.h>#include "sys32.h"#include <linux/kernel.h>#include <linux/sched.h>#include <linux/smp.h>#include <linux/smp_lock.h>#include <linux/ioctl.h>#include <linux/if.h>#include <linux/slab.h>#include <linux/hdreg.h>#include <linux/raid/md.h>#include <linux/kd.h>#include <linux/route.h>#include <linux/skbuff.h>#include <linux/netlink.h>#include <linux/vt.h>#include <linux/fs.h>#include <linux/file.h>#include <linux/fd.h>#include <linux/ppp_defs.h>#include <linux/if_ppp.h>#include <linux/if_pppox.h>#include <linux/mtio.h>#include <linux/cdrom.h>#include <linux/loop.h>#include <linux/auto_fs.h>#include <linux/devfs_fs.h>#include <linux/tty.h>#include <linux/vt_kern.h>#include <linux/fb.h>#include <linux/ext2_fs.h>#include <linux/videodev.h>#include <linux/netdevice.h>#include <linux/raw.h>#include <linux/smb_fs.h>#include <linux/blkpg.h>#include <linux/blk.h>#include <linux/elevator.h>#include <linux/rtc.h>#include <linux/serial.h>#if defined(CONFIG_BLK_DEV_LVM) || defined(CONFIG_BLK_DEV_LVM_MODULE)/* Ugh. This header really is not clean *//* #define min min#define max max */#include <linux/lvm.h>#endif /* LVM */#include <scsi/scsi.h>/* Ugly hack. */#undef __KERNEL__#include <scsi/scsi_ioctl.h>#define __KERNEL__#include <scsi/sg.h>#include <asm/types.h>#include <asm/uaccess.h>#include <asm/perf.h>#include <linux/ethtool.h>#include <linux/soundcard.h>#include <linux/atm.h>#include <linux/atmarp.h>#include <linux/atmclip.h>#include <linux/atmdev.h>#include <linux/atmioc.h>#include <linux/atmlec.h>#include <linux/atmmpc.h>#include <linux/atmsvc.h>#include <linux/atm_tcp.h>#include <linux/sonet.h>#include <linux/atm_suni.h>#include <asm/module.h> /* get #define module_map() *//* Use this to get at 32-bit user passed pointers. See sys_sparc32.c for description about these. */#define A(__x) ((unsigned long)(__x))/* Aiee. Someone does not find a difference between int and long */#define EXT2_IOC32_GETFLAGS _IOR('f', 1, int)#define EXT2_IOC32_SETFLAGS _IOW('f', 2, int)#define EXT2_IOC32_GETVERSION _IOR('v', 1, int)#define EXT2_IOC32_SETVERSION _IOW('v', 2, int)extern asmlinkage int sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg);static int w_long(unsigned int fd, unsigned int cmd, unsigned long 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 *)arg)) return -EFAULT; return err;} static int rw_long(unsigned int fd, unsigned int cmd, unsigned long arg){ mm_segment_t old_fs = get_fs(); int err; unsigned long val; if(get_user(val, (u32 *)arg)) return -EFAULT; set_fs (KERNEL_DS); err = sys_ioctl(fd, cmd, (unsigned long)&val); set_fs (old_fs); if (!err && put_user(val, (u32 *)arg)) return -EFAULT; return err;}static int siocprivate(unsigned int fd, unsigned int cmd, unsigned long arg){ int err = sys_ioctl(fd, cmd, arg); if ((unsigned) err > -4095) printk(KERN_WARNING "ioctl(%d, 0x%x, %p) -- SIOCDEVPRIVATE-based ioctls aren't really\n" "supported, though some will work by accident.\n", fd, cmd, (void *)arg); return err;}static int do_ext2_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg){ /* These are just misnamed, they actually get/put from/to user an int */ switch (cmd) { case EXT2_IOC32_GETFLAGS: cmd = EXT2_IOC_GETFLAGS; break; case EXT2_IOC32_SETFLAGS: cmd = EXT2_IOC_SETFLAGS; break; case EXT2_IOC32_GETVERSION: cmd = EXT2_IOC_GETVERSION; break; case EXT2_IOC32_SETVERSION: cmd = EXT2_IOC_SETVERSION; break; } return sys_ioctl(fd, cmd, arg);} static int do_siocgstamp(unsigned int fd, unsigned int cmd, unsigned long arg){ struct timeval32 *up = (struct timeval32 *)arg; struct timeval ktv; mm_segment_t old_fs = get_fs(); int err; set_fs(KERNEL_DS); err = sys_ioctl(fd, cmd, (unsigned long)&ktv); set_fs(old_fs); if(!err) { err = put_user(ktv.tv_sec, &up->tv_sec); err |= __put_user(ktv.tv_usec, &up->tv_usec); } 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 */ char ifru_newname[IFNAMSIZ]; __kernel_caddr_t32 ifru_data; } ifr_ifru;};struct ifconf32 { int ifc_len; /* size of buffer */ __kernel_caddr_t32 ifcbuf;};static int dev_ifname32(unsigned int fd, unsigned int cmd, unsigned long arg){ struct net_device *dev; struct ifreq32 ifr32; int err; if (copy_from_user(&ifr32, (struct ifreq32 *)arg, sizeof(struct ifreq32))) return -EFAULT; dev = dev_get_by_index(ifr32.ifr_ifindex); if (!dev) return -ENODEV; strcpy(ifr32.ifr_name, dev->name); err = copy_to_user((struct ifreq32 *)arg, &ifr32, sizeof(struct ifreq32)); return (err ? -EFAULT : 0);}static inline int dev_ifconf(unsigned int fd, unsigned int cmd, unsigned long 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 *)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 *)arg, &ifc32, sizeof(struct ifconf32))) err = -EFAULT; } } if(ifc.ifc_buf != NULL) kfree (ifc.ifc_buf); return err;}static int dev_ifsioc(unsigned int fd, unsigned int cmd, unsigned long arg){ struct ifreq ifr; mm_segment_t old_fs; int err; switch (cmd) { case SIOCSIFMAP: err = copy_from_user(&ifr, (struct ifreq32 *)arg, sizeof(ifr.ifr_name)); err |= __get_user(ifr.ifr_map.mem_start, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_map.mem_start)); err |= __get_user(ifr.ifr_map.mem_end, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_map.mem_end)); err |= __get_user(ifr.ifr_map.base_addr, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_map.base_addr)); err |= __get_user(ifr.ifr_map.irq, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_map.irq)); err |= __get_user(ifr.ifr_map.dma, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_map.dma)); err |= __get_user(ifr.ifr_map.port, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_map.port)); if (err) return -EFAULT; break; case SIOCGPPPSTATS: case SIOCGPPPCSTATS: case SIOCGPPPVER: case SIOCETHTOOL: if (copy_from_user(&ifr, (struct ifreq32 *)arg, sizeof(struct ifreq32))) return -EFAULT; ifr.ifr_data = (__kernel_caddr_t)get_free_page(GFP_KERNEL); if (!ifr.ifr_data) return -EAGAIN; if(cmd == SIOCETHTOOL) { u32 data; __get_user(data, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_data)); if(copy_from_user(ifr.ifr_data, (char *)A(data), sizeof(struct ethtool_cmd))) { free_page((unsigned long)ifr.ifr_data); return -EFAULT; } } break; default: if (copy_from_user(&ifr, (struct ifreq32 *)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: case SIOCGIFTXQLEN: if (copy_to_user((struct ifreq32 *)arg, &ifr, sizeof(struct ifreq32))) return -EFAULT; break; case SIOCGPPPSTATS: case SIOCGPPPCSTATS: case SIOCGPPPVER: case SIOCETHTOOL: { u32 data; int len; __get_user(data, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_data)); if(cmd == SIOCETHTOOL) len = sizeof(struct ethtool_cmd); if(cmd == SIOCGPPPVER) len = strlen((char *)ifr.ifr_data) + 1; else if(cmd == SIOCGPPPCSTATS) len = sizeof(struct ppp_comp_stats); else len = sizeof(struct ppp_stats); len = copy_to_user((char *)A(data), ifr.ifr_data, len); free_page((unsigned long)ifr.ifr_data); if(len) return -EFAULT; break; } case SIOCGIFMAP: err = copy_to_user((struct ifreq32 *)arg, &ifr, sizeof(ifr.ifr_name)); err |= __put_user(ifr.ifr_map.mem_start, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_map.mem_start)); err |= __put_user(ifr.ifr_map.mem_end, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_map.mem_end)); err |= __put_user(ifr.ifr_map.base_addr, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_map.base_addr)); err |= __put_user(ifr.ifr_map.irq, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_map.irq)); err |= __put_user(ifr.ifr_map.dma, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_map.dma)); err |= __put_user(ifr.ifr_map.port, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_map.port)); if (err) err = -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, unsigned long arg){ struct rtentry r; char devname[16]; u32 rtdev; int ret; mm_segment_t old_fs = get_fs(); ret = copy_from_user (&r.rt_dst, &(((struct rtentry32 *)arg)->rt_dst), 3 * sizeof(struct sockaddr)); ret |= __get_user (r.rt_flags, &(((struct rtentry32 *)arg)->rt_flags)); ret |= __get_user (r.rt_metric, &(((struct rtentry32 *)arg)->rt_metric)); ret |= __get_user (r.rt_mtu, &(((struct rtentry32 *)arg)->rt_mtu)); ret |= __get_user (r.rt_window, &(((struct rtentry32 *)arg)->rt_window)); ret |= __get_user (r.rt_irtt, &(((struct rtentry32 *)arg)->rt_irtt)); ret |= __get_user (rtdev, &(((struct rtentry32 *)arg)->rt_dev)); if (rtdev) { ret |= copy_from_user (devname, (char *)A(rtdev), 15); r.rt_dev = devname; devname[15] = 0; } else r.rt_dev = 0; if (ret) return -EFAULT; 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, unsigned int cmd, unsigned long 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) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -