1/* 2 * ioctl32.c: Conversion between 32bit and 64bit native ioctls. 3 * 4 * S390 version 5 * Copyright (C) 2000 IBM Deutschland Entwicklung GmbH, IBM Corporation 6 * Author(s): Gerhard Tonn (ton@de.ibm.com) 7 * 8 * Heavily inspired by the 32-bit Sparc compat code which is 9 * Copyright (C) 2000 Silicon Graphics, Inc. 10 * Written by Ulf Carlsson (ulfc@engr.sgi.com) 11 * 12 */ 13 14#include <linux/types.h> 15#include <linux/kernel.h> 16#include <linux/fs.h> 17#include <linux/sched.h> 18#include <linux/mm.h> 19#include <linux/init.h> 20#include <linux/file.h> 21#include <linux/vt.h> 22#include <linux/kd.h> 23#include <linux/netdevice.h> 24#include <linux/route.h> 25#include <linux/ext2_fs.h> 26#include <linux/hdreg.h> 27#include <linux/if_bonding.h> 28#include <asm/types.h> 29#include <asm/uaccess.h> 30#include <asm/dasd.h> 31#include <asm/sockios.h> 32 33#include "linux32.h" 34 35long sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg); 36 37struct hd_geometry32 { 38 unsigned char heads; 39 unsigned char sectors; 40 unsigned short cylinders; 41 __u32 start; 42}; 43 44static inline int hd_geometry_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) 45{ 46 struct hd_geometry32 *hg32 = (struct hd_geometry32 *) A(arg); 47 struct hd_geometry hg; 48 int ret; 49 mm_segment_t old_fs = get_fs(); 50 51 set_fs (KERNEL_DS); 52 ret = sys_ioctl (fd, cmd, (long)&hg); 53 set_fs (old_fs); 54 55 if (ret) 56 return ret; 57 58 ret = put_user (hg.heads, &(hg32->heads)); 59 ret |= __put_user (hg.sectors, &(hg32->sectors)); 60 ret |= __put_user (hg.cylinders, &(hg32->cylinders)); 61 ret |= __put_user (hg.start, &(hg32->start)); 62 63 return ret; 64} 65 66struct timeval32 { 67 int tv_sec; 68 int tv_usec; 69}; 70 71#define EXT2_IOC32_GETFLAGS _IOR('f', 1, int) 72#define EXT2_IOC32_SETFLAGS _IOW('f', 2, int) 73#define EXT2_IOC32_GETVERSION _IOR('v', 1, int) 74#define EXT2_IOC32_SETVERSION _IOW('v', 2, int) 75 76struct ifmap32 { 77 unsigned int mem_start; 78 unsigned int mem_end; 79 unsigned short base_addr; 80 unsigned char irq; 81 unsigned char dma; 82 unsigned char port; 83}; 84 85struct ifreq32 { 86#define IFHWADDRLEN 6 87#define IFNAMSIZ 16 88 union { 89 char ifrn_name[IFNAMSIZ]; /* if name, e.g. "en0" */ 90 } ifr_ifrn; 91 union { 92 struct sockaddr ifru_addr; 93 struct sockaddr ifru_dstaddr; 94 struct sockaddr ifru_broadaddr; 95 struct sockaddr ifru_netmask; 96 struct sockaddr ifru_hwaddr; 97 short ifru_flags; 98 int ifru_ivalue; 99 int ifru_mtu; 100 struct ifmap32 ifru_map; 101 char ifru_slave[IFNAMSIZ]; /* Just fits the size */ 102 char ifru_newname[IFNAMSIZ]; 103 __u32 ifru_data; 104 } ifr_ifru; 105}; 106 107struct ifconf32 { 108 int ifc_len; /* size of buffer */ 109 __u32 ifcbuf; 110}; 111 112static int dev_ifname32(unsigned int fd, unsigned int cmd, unsigned long arg) 113{ 114 struct ireq32 *uir32 = (struct ireq32 *) A(arg); 115 struct net_device *dev; 116 struct ifreq32 ifr32; 117 118 if (copy_from_user(&ifr32, uir32, sizeof(struct ifreq32))) 119 return -EFAULT; 120 121 read_lock(&dev_base_lock); 122 dev = __dev_get_by_index(ifr32.ifr_ifindex); 123 if (!dev) { 124 read_unlock(&dev_base_lock); 125 return -ENODEV; 126 } 127 128 strcpy(ifr32.ifr_name, dev->name); 129 read_unlock(&dev_base_lock); 130 131 if (copy_to_user(uir32, &ifr32, sizeof(struct ifreq32))) 132 return -EFAULT; 133 134 return 0; 135} 136 137static inline int dev_ifconf(unsigned int fd, unsigned int cmd, 138 unsigned long arg) 139{ 140 struct ioconf32 *uifc32 = (struct ioconf32 *) A(arg); 141 struct ifconf32 ifc32; 142 struct ifconf ifc; 143 struct ifreq32 *ifr32; 144 struct ifreq *ifr; 145 mm_segment_t old_fs; 146 int len; 147 int err; 148 149 if (copy_from_user(&ifc32, uifc32, sizeof(struct ifconf32))) 150 return -EFAULT; 151 152 if(ifc32.ifcbuf == 0) { 153 ifc32.ifc_len = 0; 154 ifc.ifc_len = 0; 155 ifc.ifc_buf = NULL; 156 } else { 157 ifc.ifc_len = ((ifc32.ifc_len / sizeof (struct ifreq32))) * 158 sizeof (struct ifreq); 159 ifc.ifc_buf = kmalloc (ifc.ifc_len, GFP_KERNEL); 160 if (!ifc.ifc_buf) 161 return -ENOMEM; 162 } 163 ifr = ifc.ifc_req; 164 ifr32 = (struct ifreq32 *) A(ifc32.ifcbuf); 165 len = ifc32.ifc_len / sizeof (struct ifreq32); 166 while (len--) { 167 if (copy_from_user(ifr++, ifr32++, sizeof (struct ifreq32))) { 168 err = -EFAULT; 169 goto out; 170 } 171 } 172 173 old_fs = get_fs(); 174 set_fs (KERNEL_DS); 175 err = sys_ioctl (fd, SIOCGIFCONF, (unsigned long)&ifc); 176 set_fs (old_fs); 177 if (err) 178 goto out; 179 180 ifr = ifc.ifc_req; 181 ifr32 = (struct ifreq32 *) A(ifc32.ifcbuf); 182 len = ifc.ifc_len / sizeof (struct ifreq); 183 ifc32.ifc_len = len * sizeof (struct ifreq32); 184 185 while (len--) { 186 if (copy_to_user(ifr32++, ifr++, sizeof (struct ifreq32))) { 187 err = -EFAULT; 188 goto out; 189 } 190 } 191 192 if (copy_to_user(uifc32, &ifc32, sizeof(struct ifconf32))) { 193 err = -EFAULT; 194 goto out; 195 } 196out: 197 if(ifc.ifc_buf != NULL) 198 kfree (ifc.ifc_buf); 199 return err; 200} 201 202static int bond_ioctl(unsigned long fd, unsigned int cmd, unsigned long arg) 203{ 204 struct ifreq ifr; 205 mm_segment_t old_fs; 206 int err, len; 207 u32 data; 208 209 if (copy_from_user(&ifr, (struct ifreq32 *)arg, sizeof(struct ifreq32))) 210 return -EFAULT; 211 ifr.ifr_data = (__kernel_caddr_t)get_free_page(GFP_KERNEL); 212 if (!ifr.ifr_data) 213 return -EAGAIN; 214 215 switch (cmd) { 216 case SIOCBONDENSLAVE: 217 case SIOCBONDRELEASE: 218 case SIOCBONDSETHWADDR: 219 case SIOCBONDCHANGEACTIVE: 220 len = IFNAMSIZ * sizeof(char); 221 break; 222 case SIOCBONDSLAVEINFOQUERY: 223 len = sizeof(struct ifslave); 224 break; 225 case SIOCBONDINFOQUERY: 226 len = sizeof(struct ifbond); 227 break; 228 default: 229 err = -EINVAL; 230 goto out; 231 }; 232 233 __get_user(data, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_data)); 234 if (copy_from_user(ifr.ifr_data, (char *)A(data), len)) { 235 err = -EFAULT; 236 goto out; 237 } 238 239 old_fs = get_fs(); 240 set_fs (KERNEL_DS); 241 err = sys_ioctl (fd, cmd, (unsigned long)&ifr); 242 set_fs (old_fs); 243 if (!err) { 244 len = copy_to_user((char *)A(data), ifr.ifr_data, len); 245 if (len) 246 err = -EFAULT; 247 } 248 249out: 250 free_page((unsigned long)ifr.ifr_data); 251 return err; 252} 253 254static inline int dev_ifsioc(unsigned int fd, unsigned int cmd, 255 unsigned long arg) 256{ 257 struct ifreq32 *uifr = (struct ifreq32 *) A(arg); 258 struct ifreq ifr; 259 mm_segment_t old_fs; 260 int err; 261 262 switch (cmd) { 263 case SIOCSIFMAP: 264 err = copy_from_user(&ifr, uifr, sizeof(ifr.ifr_name)); 265 err |= __get_user(ifr.ifr_map.mem_start, &(uifr->ifr_ifru.ifru_map.mem_start)); 266 err |= __get_user(ifr.ifr_map.mem_end, &(uifr->ifr_ifru.ifru_map.mem_end)); 267 err |= __get_user(ifr.ifr_map.base_addr, &(uifr->ifr_ifru.ifru_map.base_addr)); 268 err |= __get_user(ifr.ifr_map.irq, &(uifr->ifr_ifru.ifru_map.irq)); 269 err |= __get_user(ifr.ifr_map.dma, &(uifr->ifr_ifru.ifru_map.dma)); 270 err |= __get_user(ifr.ifr_map.port, &(uifr->ifr_ifru.ifru_map.port)); 271 if (err) 272 return -EFAULT; 273 break; 274 default: 275 if (copy_from_user(&ifr, uifr, sizeof(struct ifreq32))) 276 return -EFAULT; 277 break; 278 } 279 old_fs = get_fs(); 280 set_fs (KERNEL_DS); 281 err = sys_ioctl (fd, cmd, (unsigned long)&ifr); 282 set_fs (old_fs); 283 if (!err) { 284 switch (cmd) { 285 case SIOCGIFFLAGS: 286 case SIOCGIFMETRIC: 287 case SIOCGIFMTU: 288 case SIOCGIFMEM: 289 case SIOCGIFHWADDR: 290 case SIOCGIFINDEX: 291 case SIOCGIFADDR: 292 case SIOCGIFBRDADDR: 293 case SIOCGIFDSTADDR: 294 case SIOCGIFNETMASK: 295 case SIOCGIFTXQLEN: 296 if (copy_to_user(uifr, &ifr, sizeof(struct ifreq32))) 297 return -EFAULT; 298 break; 299 case SIOCGIFMAP: 300 err = copy_to_user(uifr, &ifr, sizeof(ifr.ifr_name)); 301 err |= __put_user(ifr.ifr_map.mem_start, &(uifr->ifr_ifru.ifru_map.mem_start)); 302 err |= __put_user(ifr.ifr_map.mem_end, &(uifr->ifr_ifru.ifru_map.mem_end)); 303 err |= __put_user(ifr.ifr_map.base_addr, &(uifr->ifr_ifru.ifru_map.base_addr)); 304 err |= __put_user(ifr.ifr_map.irq, &(uifr->ifr_ifru.ifru_map.irq)); 305 err |= __put_user(ifr.ifr_map.dma, &(uifr->ifr_ifru.ifru_map.dma)); 306 err |= __put_user(ifr.ifr_map.port, &(uifr->ifr_ifru.ifru_map.port)); 307 if (err) 308 err = -EFAULT; 309 break; 310 } 311 } 312 return err; 313} 314 315struct rtentry32 316{ 317 unsigned int rt_pad1; 318 struct sockaddr rt_dst; /* target address */ 319 struct sockaddr rt_gateway; /* gateway addr (RTF_GATEWAY) */ 320 struct sockaddr rt_genmask; /* target network mask (IP) */ 321 unsigned short rt_flags; 322 short rt_pad2; 323 unsigned int rt_pad3; 324 unsigned int rt_pad4; 325 short rt_metric; /* +1 for binary compatibility! */ 326 unsigned int rt_dev; /* forcing the device at add */ 327 unsigned int rt_mtu; /* per route MTU/Window */ 328#ifndef __KERNEL__ 329#define rt_mss rt_mtu /* Compatibility :-( */ 330#endif 331 unsigned int rt_window; /* Window clamping */ 332 unsigned short rt_irtt; /* Initial RTT */ 333}; 334 335static inline int routing_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) 336{ 337 struct rtentry32 *ur = (struct rtentry32 *) A(arg); 338 struct rtentry r; 339 char devname[16]; 340 u32 rtdev; 341 int ret; 342 mm_segment_t old_fs = get_fs(); 343 344 ret = copy_from_user (&r.rt_dst, &(ur->rt_dst), 3 * sizeof(struct sockaddr)); 345 ret |= __get_user (r.rt_flags, &(ur->rt_flags)); 346 ret |= __get_user (r.rt_metric, &(ur->rt_metric)); 347 ret |= __get_user (r.rt_mtu, &(ur->rt_mtu)); 348 ret |= __get_user (r.rt_window, &(ur->rt_window)); 349 ret |= __get_user (r.rt_irtt, &(ur->rt_irtt)); 350 ret |= __get_user (rtdev, &(ur->rt_dev)); 351 if (rtdev) { 352 ret |= copy_from_user (devname, (char *) A(rtdev), 15); 353 r.rt_dev = devname; devname[15] = 0; 354 } else 355 r.rt_dev = 0; 356 if (ret) 357 return -EFAULT; 358 set_fs (KERNEL_DS); 359 ret = sys_ioctl (fd, cmd, (long)&r); 360 set_fs (old_fs); 361 return ret; 362} 363 364static int do_ext2_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) 365{ 366 /* These are just misnamed, they actually get/put from/to user an int */ 367 switch (cmd) { 368 case EXT2_IOC32_GETFLAGS: cmd = EXT2_IOC_GETFLAGS; break; 369 case EXT2_IOC32_SETFLAGS: cmd = EXT2_IOC_SETFLAGS; break; 370 case EXT2_IOC32_GETVERSION: cmd = EXT2_IOC_GETVERSION; break; 371 case EXT2_IOC32_SETVERSION: cmd = EXT2_IOC_SETVERSION; break; 372 } 373 return sys_ioctl(fd, cmd, arg); 374} 375 376static int w_long(unsigned int fd, unsigned int cmd, unsigned long arg) 377{ 378 mm_segment_t old_fs = get_fs(); 379 int err; 380 unsigned long val; 381 382 set_fs (KERNEL_DS); 383 err = sys_ioctl(fd, cmd, (unsigned long)&val); 384 set_fs (old_fs); 385 if (!err && put_user((unsigned int) val, (u32 *)arg)) 386 return -EFAULT; 387 return err; 388} 389 390struct ioctl32_handler { 391 unsigned int cmd; 392 int (*function)(unsigned int, unsigned int, unsigned long); 393}; 394 395struct ioctl32_list { 396 struct ioctl32_handler handler; 397 struct ioctl32_list *next; 398}; 399 400#define IOCTL32_DEFAULT(cmd) { { cmd, (void *) sys_ioctl }, 0 } 401#define IOCTL32_HANDLER(cmd, handler) { { cmd, (void *) handler }, 0 } 402 403static struct ioctl32_list ioctl32_handler_table[] = { 404 IOCTL32_DEFAULT(FIBMAP), 405 IOCTL32_DEFAULT(FIGETBSZ), 406 407 IOCTL32_DEFAULT(DASDAPIVER), 408 IOCTL32_DEFAULT(BIODASDDISABLE), 409 IOCTL32_DEFAULT(BIODASDENABLE), 410 IOCTL32_DEFAULT(BIODASDRSRV), 411 IOCTL32_DEFAULT(BIODASDRLSE), 412 IOCTL32_DEFAULT(BIODASDSLCK), 413 IOCTL32_DEFAULT(BIODASDINFO), 414 IOCTL32_DEFAULT(BIODASDFMT), 415 416 IOCTL32_DEFAULT(BLKRRPART), 417 418 IOCTL32_HANDLER(HDIO_GETGEO, hd_geometry_ioctl), 419 420 IOCTL32_DEFAULT(TCGETA), 421 IOCTL32_DEFAULT(TCSETA), 422 IOCTL32_DEFAULT(TCSETAW), 423 IOCTL32_DEFAULT(TCSETAF), 424 IOCTL32_DEFAULT(TCSBRK), 425 IOCTL32_DEFAULT(TCXONC), 426 IOCTL32_DEFAULT(TCFLSH), 427 IOCTL32_DEFAULT(TCGETS), 428 IOCTL32_DEFAULT(TCSETS), 429 IOCTL32_DEFAULT(TCSETSW), 430 IOCTL32_DEFAULT(TCSETSF), 431 IOCTL32_DEFAULT(TIOCLINUX), 432 433 IOCTL32_DEFAULT(TIOCGETD), 434 IOCTL32_DEFAULT(TIOCSETD), 435 IOCTL32_DEFAULT(TIOCEXCL), 436 IOCTL32_DEFAULT(TIOCNXCL), 437 IOCTL32_DEFAULT(TIOCCONS), 438 IOCTL32_DEFAULT(TIOCGSOFTCAR), 439 IOCTL32_DEFAULT(TIOCSSOFTCAR), 440 IOCTL32_DEFAULT(TIOCSWINSZ), 441 IOCTL32_DEFAULT(TIOCGWINSZ), 442 IOCTL32_DEFAULT(TIOCMGET), 443 IOCTL32_DEFAULT(TIOCMBIC), 444 IOCTL32_DEFAULT(TIOCMBIS), 445 IOCTL32_DEFAULT(TIOCMSET), 446 IOCTL32_DEFAULT(TIOCPKT), 447 IOCTL32_DEFAULT(TIOCNOTTY), 448 IOCTL32_DEFAULT(TIOCSTI), 449 IOCTL32_DEFAULT(TIOCOUTQ), 450 IOCTL32_DEFAULT(TIOCSPGRP), 451 IOCTL32_DEFAULT(TIOCGPGRP), 452 IOCTL32_DEFAULT(TIOCSCTTY), 453 IOCTL32_DEFAULT(TIOCGPTN), 454 IOCTL32_DEFAULT(TIOCSPTLCK), 455 IOCTL32_DEFAULT(TIOCGSERIAL), 456 IOCTL32_DEFAULT(TIOCSSERIAL), 457 IOCTL32_DEFAULT(TIOCSERGETLSR), 458 459 IOCTL32_DEFAULT(FIOCLEX), 460 IOCTL32_DEFAULT(FIONCLEX), 461 IOCTL32_DEFAULT(FIOASYNC), 462 IOCTL32_DEFAULT(FIONBIO), 463 IOCTL32_DEFAULT(FIONREAD), 464 465 IOCTL32_DEFAULT(PIO_FONT), 466 IOCTL32_DEFAULT(GIO_FONT), 467 IOCTL32_DEFAULT(KDSIGACCEPT), 468 IOCTL32_DEFAULT(KDGETKEYCODE), 469 IOCTL32_DEFAULT(KDSETKEYCODE), 470 IOCTL32_DEFAULT(KIOCSOUND), 471 IOCTL32_DEFAULT(KDMKTONE), 472 IOCTL32_DEFAULT(KDGKBTYPE), 473 IOCTL32_DEFAULT(KDSETMODE), 474 IOCTL32_DEFAULT(KDGETMODE), 475 IOCTL32_DEFAULT(KDSKBMODE), 476 IOCTL32_DEFAULT(KDGKBMODE), 477 IOCTL32_DEFAULT(KDSKBMETA), 478 IOCTL32_DEFAULT(KDGKBMETA), 479 IOCTL32_DEFAULT(KDGKBENT), 480 IOCTL32_DEFAULT(KDSKBENT), 481 IOCTL32_DEFAULT(KDGKBSENT), 482 IOCTL32_DEFAULT(KDSKBSENT), 483 IOCTL32_DEFAULT(KDGKBDIACR), 484 IOCTL32_DEFAULT(KDSKBDIACR), 485 IOCTL32_DEFAULT(KDGKBLED), 486 IOCTL32_DEFAULT(KDSKBLED), 487 IOCTL32_DEFAULT(KDGETLED), 488 IOCTL32_DEFAULT(KDSETLED), 489 IOCTL32_DEFAULT(GIO_SCRNMAP), 490 IOCTL32_DEFAULT(PIO_SCRNMAP), 491 IOCTL32_DEFAULT(GIO_UNISCRNMAP), 492 IOCTL32_DEFAULT(PIO_UNISCRNMAP), 493 IOCTL32_DEFAULT(PIO_FONTRESET), 494 IOCTL32_DEFAULT(PIO_UNIMAPCLR), 495 496 IOCTL32_DEFAULT(VT_SETMODE), 497 IOCTL32_DEFAULT(VT_GETMODE), 498 IOCTL32_DEFAULT(VT_GETSTATE), 499 IOCTL32_DEFAULT(VT_OPENQRY), 500 IOCTL32_DEFAULT(VT_ACTIVATE), 501 IOCTL32_DEFAULT(VT_WAITACTIVE), 502 IOCTL32_DEFAULT(VT_RELDISP), 503 IOCTL32_DEFAULT(VT_DISALLOCATE), 504 IOCTL32_DEFAULT(VT_RESIZE), 505 IOCTL32_DEFAULT(VT_RESIZEX), 506 IOCTL32_DEFAULT(VT_LOCKSWITCH), 507 IOCTL32_DEFAULT(VT_UNLOCKSWITCH), 508 509 IOCTL32_DEFAULT(SIOCGSTAMP), 510 511 IOCTL32_HANDLER(SIOCGIFNAME, dev_ifname32), 512 IOCTL32_HANDLER(SIOCGIFCONF, dev_ifconf), 513 IOCTL32_HANDLER(SIOCGIFFLAGS, dev_ifsioc), 514 IOCTL32_HANDLER(SIOCSIFFLAGS, dev_ifsioc), 515 IOCTL32_HANDLER(SIOCGIFMETRIC, dev_ifsioc), 516 IOCTL32_HANDLER(SIOCSIFMETRIC, dev_ifsioc), 517 IOCTL32_HANDLER(SIOCGIFMTU, dev_ifsioc), 518 IOCTL32_HANDLER(SIOCSIFMTU, dev_ifsioc), 519 IOCTL32_HANDLER(SIOCGIFMEM, dev_ifsioc), 520 IOCTL32_HANDLER(SIOCSIFMEM, dev_ifsioc), 521 IOCTL32_HANDLER(SIOCGIFHWADDR, dev_ifsioc), 522 IOCTL32_HANDLER(SIOCSIFHWADDR, dev_ifsioc), 523 IOCTL32_HANDLER(SIOCADDMULTI, dev_ifsioc), 524 IOCTL32_HANDLER(SIOCDELMULTI, dev_ifsioc), 525 IOCTL32_HANDLER(SIOCGIFINDEX, dev_ifsioc), 526 IOCTL32_HANDLER(SIOCGIFMAP, dev_ifsioc), 527 IOCTL32_HANDLER(SIOCSIFMAP, dev_ifsioc), 528 IOCTL32_HANDLER(SIOCGIFADDR, dev_ifsioc), 529 IOCTL32_HANDLER(SIOCSIFADDR, dev_ifsioc), 530 IOCTL32_HANDLER(SIOCGIFBRDADDR, dev_ifsioc), 531 IOCTL32_HANDLER(SIOCSIFBRDADDR, dev_ifsioc), 532 IOCTL32_HANDLER(SIOCGIFDSTADDR, dev_ifsioc), 533 IOCTL32_HANDLER(SIOCSIFDSTADDR, dev_ifsioc), 534 IOCTL32_HANDLER(SIOCGIFNETMASK, dev_ifsioc), 535 IOCTL32_HANDLER(SIOCSIFNETMASK, dev_ifsioc), 536 IOCTL32_HANDLER(SIOCSIFPFLAGS, dev_ifsioc), 537 IOCTL32_HANDLER(SIOCGIFPFLAGS, dev_ifsioc), 538 IOCTL32_HANDLER(SIOCGIFTXQLEN, dev_ifsioc), 539 IOCTL32_HANDLER(SIOCSIFTXQLEN, dev_ifsioc), 540 IOCTL32_HANDLER(SIOCADDRT, routing_ioctl), 541 IOCTL32_HANDLER(SIOCDELRT, routing_ioctl), 542 543 IOCTL32_HANDLER(SIOCBONDENSLAVE, bond_ioctl), 544 IOCTL32_HANDLER(SIOCBONDRELEASE, bond_ioctl), 545 IOCTL32_HANDLER(SIOCBONDSETHWADDR, bond_ioctl), 546 IOCTL32_HANDLER(SIOCBONDSLAVEINFOQUERY, bond_ioctl), 547 IOCTL32_HANDLER(SIOCBONDINFOQUERY, bond_ioctl), 548 IOCTL32_HANDLER(SIOCBONDCHANGEACTIVE, bond_ioctl), 549 550 IOCTL32_HANDLER(EXT2_IOC32_GETFLAGS, do_ext2_ioctl), 551 IOCTL32_HANDLER(EXT2_IOC32_SETFLAGS, do_ext2_ioctl), 552 IOCTL32_HANDLER(EXT2_IOC32_GETVERSION, do_ext2_ioctl), 553 IOCTL32_HANDLER(EXT2_IOC32_SETVERSION, do_ext2_ioctl), 554 555 IOCTL32_HANDLER(BLKGETSIZE, w_long) 556 557}; 558 559#define NR_IOCTL32_HANDLERS (sizeof(ioctl32_handler_table) / \ 560 sizeof(ioctl32_handler_table[0])) 561 562static struct ioctl32_list *ioctl32_hash_table[1024]; 563 564static inline int ioctl32_hash(unsigned int cmd) 565{ 566 return ((cmd >> 6) ^ (cmd >> 4) ^ cmd) & 0x3ff; 567} 568 569int sys32_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) 570{ 571 int (*handler)(unsigned int, unsigned int, unsigned long, struct file * filp); 572 struct file *filp; 573 struct ioctl32_list *l; 574 int error; 575 576 l = ioctl32_hash_table[ioctl32_hash(cmd)]; 577 578 error = -EBADF; 579 580 filp = fget(fd); 581 if (!filp) 582 return error; 583 584 if (!filp->f_op || !filp->f_op->ioctl) { 585 error = sys_ioctl (fd, cmd, arg); 586 goto out; 587 } 588 589 while (l && l->handler.cmd != cmd) 590 l = l->next; 591 592 if (l) { 593 handler = (void *)l->handler.function; 594 error = handler(fd, cmd, arg, filp); 595 } else { 596 error = -EINVAL; 597 printk("unknown ioctl: %08x\n", cmd); 598 } 599out: 600 fput(filp); 601 return error; 602} 603 604static void ioctl32_insert(struct ioctl32_list *entry) 605{ 606 int hash = ioctl32_hash(entry->handler.cmd); 607 if (!ioctl32_hash_table[hash]) 608 ioctl32_hash_table[hash] = entry; 609 else { 610 struct ioctl32_list *l; 611 l = ioctl32_hash_table[hash]; 612 while (l->next) 613 l = l->next; 614 l->next = entry; 615 entry->next = 0; 616 } 617} 618 619static int __init init_ioctl32(void) 620{ 621 int i; 622 for (i = 0; i < NR_IOCTL32_HANDLERS; i++) 623 ioctl32_insert(&ioctl32_handler_table[i]); 624 return 0; 625} 626 627__initcall(init_ioctl32); 628