1 /* $NetBSD: netbsd32_ioctl.c,v 1.35 2007/08/15 12:07:31 ad Exp $ */ 2 3 /* 4 * Copyright (c) 1998, 2001 Matthew R. Green 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. The name of the author may not be used to endorse or promote products 16 * derived from this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 23 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 24 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 25 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 * SUCH DAMAGE. 29 */ 30 31 /* 32 * handle ioctl conversions from netbsd32 -> 64-bit kernel 33 */ 34 35 #include <sys/cdefs.h> 36 __KERNEL_RCSID(0, "$NetBSD: netbsd32_ioctl.c,v 1.35 2007/08/15 12:07:31 ad Exp $"); 37 38 #include <sys/param.h> 39 #include <sys/systm.h> 40 #include <sys/filedesc.h> 41 #include <sys/ioctl.h> 42 #include <sys/file.h> 43 #include <sys/proc.h> 44 #include <sys/socketvar.h> 45 #include <sys/audioio.h> 46 #include <sys/disklabel.h> 47 #include <sys/dkio.h> 48 #include <sys/malloc.h> 49 #include <sys/sockio.h> 50 #include <sys/socket.h> 51 #include <sys/ttycom.h> 52 #include <sys/mount.h> 53 #include <sys/syscallargs.h> 54 #include <sys/ktrace.h> 55 56 #ifdef __sparc__ 57 #include <dev/sun/fbio.h> 58 #include <machine/openpromio.h> 59 #endif 60 61 #include <net/if.h> 62 #include <net/route.h> 63 64 #include <netinet/in.h> 65 #include <netinet/in_var.h> 66 #include <netinet/igmp.h> 67 #include <netinet/igmp_var.h> 68 #include <netinet/ip_mroute.h> 69 70 #include <compat/sys/sockio.h> 71 72 #include <compat/netbsd32/netbsd32.h> 73 #include <compat/netbsd32/netbsd32_ioctl.h> 74 #include <compat/netbsd32/netbsd32_syscallargs.h> 75 76 /* prototypes for the converters */ 77 static inline void netbsd32_to_partinfo(struct netbsd32_partinfo *, 78 struct partinfo *, u_long); 79 #if 0 80 static inline void netbsd32_to_format_op(struct netbsd32_format_op *, 81 struct format_op *, u_long); 82 #endif 83 static inline void netbsd32_to_ifreq(struct netbsd32_ifreq *, struct ifreq *, 84 u_long cmd); 85 static inline void netbsd32_to_ifconf(struct netbsd32_ifconf *, 86 struct ifconf *, u_long); 87 static inline void netbsd32_to_ifmediareq(struct netbsd32_ifmediareq *, 88 struct ifmediareq *, u_long); 89 static inline void netbsd32_to_ifdrv(struct netbsd32_ifdrv *, struct ifdrv *, 90 u_long); 91 static inline void netbsd32_to_sioc_vif_req(struct netbsd32_sioc_vif_req *, 92 struct sioc_vif_req *, u_long); 93 static inline void netbsd32_to_sioc_sg_req(struct netbsd32_sioc_sg_req *, 94 struct sioc_sg_req *, u_long); 95 static inline void netbsd32_from_partinfo(struct partinfo *, 96 struct netbsd32_partinfo *, u_long); 97 #if 0 98 static inline void netbsd32_from_format_op(struct format_op *, 99 struct netbsd32_format_op *, 100 u_long); 101 #endif 102 static inline void netbsd32_from_ifreq(struct ifreq *, 103 struct netbsd32_ifreq *, u_long); 104 static inline void netbsd32_from_ifconf(struct ifconf *, 105 struct netbsd32_ifconf *, u_long); 106 static inline void netbsd32_from_ifmediareq(struct ifmediareq *, 107 struct netbsd32_ifmediareq *, 108 u_long); 109 static inline void netbsd32_from_ifdrv(struct ifdrv *, 110 struct netbsd32_ifdrv *, u_long); 111 static inline void netbsd32_from_sioc_vif_req(struct sioc_vif_req *, 112 struct netbsd32_sioc_vif_req *, 113 u_long); 114 static inline void netbsd32_from_sioc_sg_req(struct sioc_sg_req *, 115 struct netbsd32_sioc_sg_req *, 116 u_long); 117 118 /* convert to/from different structures */ 119 120 static inline void 121 netbsd32_to_partinfo(s32p, p, cmd) 122 struct netbsd32_partinfo *s32p; 123 struct partinfo *p; 124 u_long cmd; 125 { 126 127 p->disklab = (struct disklabel *)NETBSD32PTR64(s32p->disklab); 128 p->part = (struct partition *)NETBSD32PTR64(s32p->part); 129 } 130 131 #if 0 132 static inline void 133 netbsd32_to_format_op(s32p, p, cmd) 134 struct netbsd32_format_op *s32p; 135 struct format_op *p; 136 u_long cmd; 137 { 138 139 p->df_buf = (char *)NETBSD32PTR64(s32p->df_buf); 140 p->df_count = s32p->df_count; 141 p->df_startblk = s32p->df_startblk; 142 memcpy(p->df_reg, s32p->df_reg, sizeof(s32p->df_reg)); 143 } 144 #endif 145 146 static inline void 147 netbsd32_to_ifreq(s32p, p, cmd) 148 struct netbsd32_ifreq *s32p; 149 struct ifreq *p; 150 u_long cmd; 151 { 152 153 memcpy(p, s32p, sizeof *s32p); 154 /* 155 * XXX 156 * struct ifreq says the same, but sometimes the ifr_data 157 * union member needs to be converted to 64 bits... this 158 * is very driver specific and so we ignore it for now.. 159 */ 160 if (cmd == SIOCGIFDATA || cmd == SIOCZIFDATA) 161 p->ifr_data = (void *)NETBSD32PTR64(s32p->ifr_data); 162 } 163 164 static inline void 165 netbsd32_to_ifconf(s32p, p, cmd) 166 struct netbsd32_ifconf *s32p; 167 struct ifconf *p; 168 u_long cmd; 169 { 170 171 p->ifc_len = s32p->ifc_len; 172 /* ifc_buf & ifc_req are the same size so this works */ 173 p->ifc_buf = (void *)NETBSD32PTR64(s32p->ifc_buf); 174 } 175 176 static inline void 177 netbsd32_to_ifmediareq(s32p, p, cmd) 178 struct netbsd32_ifmediareq *s32p; 179 struct ifmediareq *p; 180 u_long cmd; 181 { 182 183 memcpy(p, s32p, sizeof *s32p); 184 p->ifm_ulist = (int *)NETBSD32PTR64(s32p->ifm_ulist); 185 } 186 187 static inline void 188 netbsd32_to_ifdrv(s32p, p, cmd) 189 struct netbsd32_ifdrv *s32p; 190 struct ifdrv *p; 191 u_long cmd; 192 { 193 194 memcpy(p, s32p, sizeof *s32p); 195 p->ifd_data = (void *)NETBSD32PTR64(s32p->ifd_data); 196 } 197 198 static inline void 199 netbsd32_to_sioc_vif_req(s32p, p, cmd) 200 struct netbsd32_sioc_vif_req *s32p; 201 struct sioc_vif_req *p; 202 u_long cmd; 203 { 204 205 p->vifi = s32p->vifi; 206 p->icount = (u_long)s32p->icount; 207 p->ocount = (u_long)s32p->ocount; 208 p->ibytes = (u_long)s32p->ibytes; 209 p->obytes = (u_long)s32p->obytes; 210 } 211 212 static inline void 213 netbsd32_to_sioc_sg_req(s32p, p, cmd) 214 struct netbsd32_sioc_sg_req *s32p; 215 struct sioc_sg_req *p; 216 u_long cmd; 217 { 218 219 p->src = s32p->src; 220 p->grp = s32p->grp; 221 p->pktcnt = (u_long)s32p->pktcnt; 222 p->bytecnt = (u_long)s32p->bytecnt; 223 p->wrong_if = (u_long)s32p->wrong_if; 224 } 225 226 /* 227 * handle ioctl conversions from 64-bit kernel -> netbsd32 228 */ 229 230 static inline void 231 netbsd32_from_partinfo(p, s32p, cmd) 232 struct partinfo *p; 233 struct netbsd32_partinfo *s32p; 234 u_long cmd; 235 { 236 237 NETBSD32PTR32(s32p->disklab, p->disklab); 238 NETBSD32PTR32(s32p->part, p->part); 239 } 240 241 #if 0 242 static inline void 243 netbsd32_from_format_op(p, s32p, cmd) 244 struct format_op *p; 245 struct netbsd32_format_op *s32p; 246 u_long cmd; 247 { 248 249 /* filled in */ 250 #if 0 251 s32p->df_buf = (netbsd32_charp)p->df_buf; 252 #endif 253 s32p->df_count = p->df_count; 254 s32p->df_startblk = p->df_startblk; 255 memcpy(s32p->df_reg, p->df_reg, sizeof(p->df_reg)); 256 } 257 #endif 258 259 static inline void 260 netbsd32_from_ifreq(p, s32p, cmd) 261 struct ifreq *p; 262 struct netbsd32_ifreq *s32p; 263 u_long cmd; 264 { 265 266 /* 267 * XXX 268 * struct ifreq says the same, but sometimes the ifr_data 269 * union member needs to be converted to 64 bits... this 270 * is very driver specific and so we ignore it for now.. 271 */ 272 *s32p->ifr_name = *p->ifr_name; 273 if (cmd == SIOCGIFDATA || cmd == SIOCZIFDATA) 274 NETBSD32PTR32(s32p->ifr_data, p->ifr_data); 275 } 276 277 static inline void 278 netbsd32_from_ifconf(p, s32p, cmd) 279 struct ifconf *p; 280 struct netbsd32_ifconf *s32p; 281 u_long cmd; 282 { 283 284 s32p->ifc_len = p->ifc_len; 285 /* ifc_buf & ifc_req are the same size so this works */ 286 NETBSD32PTR32(s32p->ifc_buf, p->ifc_buf); 287 } 288 289 static inline void 290 netbsd32_from_ifmediareq(p, s32p, cmd) 291 struct ifmediareq *p; 292 struct netbsd32_ifmediareq *s32p; 293 u_long cmd; 294 { 295 296 memcpy(s32p, p, sizeof *p); 297 /* filled in? */ 298 #if 0 299 s32p->ifm_ulist = (netbsd32_intp_t)p->ifm_ulist; 300 #endif 301 } 302 303 static inline void 304 netbsd32_from_ifdrv(p, s32p, cmd) 305 struct ifdrv *p; 306 struct netbsd32_ifdrv *s32p; 307 u_long cmd; 308 { 309 310 memcpy(s32p, p, sizeof *p); 311 /* filled in? */ 312 #if 0 313 s32p->ifm_data = (netbsd32_u_longp_t)p->ifm_data; 314 #endif 315 } 316 317 static inline void 318 netbsd32_from_sioc_vif_req(p, s32p, cmd) 319 struct sioc_vif_req *p; 320 struct netbsd32_sioc_vif_req *s32p; 321 u_long cmd; 322 { 323 324 s32p->vifi = p->vifi; 325 s32p->icount = (netbsd32_u_long)p->icount; 326 s32p->ocount = (netbsd32_u_long)p->ocount; 327 s32p->ibytes = (netbsd32_u_long)p->ibytes; 328 s32p->obytes = (netbsd32_u_long)p->obytes; 329 } 330 331 static inline void 332 netbsd32_from_sioc_sg_req(p, s32p, cmd) 333 struct sioc_sg_req *p; 334 struct netbsd32_sioc_sg_req *s32p; 335 u_long cmd; 336 { 337 338 s32p->src = p->src; 339 s32p->grp = p->grp; 340 s32p->pktcnt = (netbsd32_u_long)p->pktcnt; 341 s32p->bytecnt = (netbsd32_u_long)p->bytecnt; 342 s32p->wrong_if = (netbsd32_u_long)p->wrong_if; 343 } 344 345 346 /* 347 * main ioctl syscall. 348 * 349 * ok, here we are in the biggy. we have to do fix ups depending 350 * on the ioctl command before and afterwards. 351 */ 352 int 353 netbsd32_ioctl(l, v, retval) 354 struct lwp *l; 355 void *v; 356 register_t *retval; 357 { 358 struct netbsd32_ioctl_args /* { 359 syscallarg(int) fd; 360 syscallarg(netbsd32_u_long) com; 361 syscallarg(netbsd32_voidp) data; 362 } */ *uap = v; 363 struct proc *p = l->l_proc; 364 struct file *fp; 365 struct filedesc *fdp; 366 u_long com; 367 int error = 0; 368 u_int size, size32; 369 void *data, *memp = NULL; 370 void *data32, *memp32 = NULL; 371 int tmp; 372 #define STK_PARAMS 128 373 u_long stkbuf[STK_PARAMS/sizeof(u_long)]; 374 u_long stkbuf32[STK_PARAMS/sizeof(u_long)]; 375 376 /* 377 * we need to translate some commands (_IOW) before calling sys_ioctl, 378 * some after (_IOR), and some both (_IOWR). 379 */ 380 #if 0 381 { 382 char *dirs[8] = { "NONE!", "VOID", "OUT", "VOID|OUT!", "IN", "VOID|IN!", 383 "INOUT", "VOID|IN|OUT!" }; 384 385 printf("netbsd32_ioctl(%d, %x, %x): %s group %c base %d len %d\n", 386 SCARG(uap, fd), SCARG(uap, com), SCARG(uap, data), 387 dirs[((SCARG(uap, com) & IOC_DIRMASK)>>29)], 388 IOCGROUP(SCARG(uap, com)), IOCBASECMD(SCARG(uap, com)), 389 IOCPARM_LEN(SCARG(uap, com))); 390 } 391 #endif 392 393 fdp = p->p_fd; 394 if ((fp = fd_getfile(fdp, SCARG(uap, fd))) == NULL) 395 return (EBADF); 396 397 FILE_USE(fp); 398 399 if ((fp->f_flag & (FREAD | FWRITE)) == 0) { 400 error = EBADF; 401 goto out; 402 } 403 404 switch (com = SCARG(uap, com)) { 405 case FIONCLEX: 406 fdp->fd_ofileflags[SCARG(uap, fd)] &= ~UF_EXCLOSE; 407 goto out; 408 409 case FIOCLEX: 410 fdp->fd_ofileflags[SCARG(uap, fd)] |= UF_EXCLOSE; 411 goto out; 412 } 413 414 /* 415 * Interpret high order word to find amount of data to be 416 * copied to/from the user's address space. 417 */ 418 size32 = IOCPARM_LEN(com); 419 if (size32 > IOCPARM_MAX) { 420 error = ENOTTY; 421 goto out; 422 } 423 memp = NULL; 424 if (size32 > sizeof(stkbuf)) { 425 memp32 = malloc((u_long)size32, M_IOCTLOPS, M_WAITOK); 426 data32 = memp32; 427 } else 428 data32 = (void *)stkbuf32; 429 if (com&IOC_IN) { 430 if (size32) { 431 error = copyin(SCARG_P32(uap, data), data32, size32); 432 if (error) { 433 if (memp32) 434 free(memp32, M_IOCTLOPS); 435 goto out; 436 } 437 ktrgenio(SCARG(uap, fd), UIO_WRITE, SCARG_P32(uap, data), 438 size32, 0); 439 } else 440 *(void **)data32 = SCARG_P32(uap, data); 441 } else if ((com&IOC_OUT) && size32) 442 /* 443 * Zero the buffer so the user always 444 * gets back something deterministic. 445 */ 446 memset(data32, 0, size32); 447 else if (com&IOC_VOID) 448 *(void **)data32 = SCARG_P32(uap, data); 449 450 /* 451 * convert various structures, pointers, and other objects that 452 * change size from 32 bit -> 64 bit, for all ioctl commands. 453 */ 454 switch (SCARG(uap, com)) { 455 case FIONBIO: 456 if ((tmp = *(int *)data32) != 0) 457 fp->f_flag |= FNONBLOCK; 458 else 459 fp->f_flag &= ~FNONBLOCK; 460 error = (*fp->f_ops->fo_ioctl)(fp, FIONBIO, (void *)&tmp, l); 461 break; 462 463 case FIOASYNC: 464 if ((tmp = *(int *)data32) != 0) 465 fp->f_flag |= FASYNC; 466 else 467 fp->f_flag &= ~FASYNC; 468 error = (*fp->f_ops->fo_ioctl)(fp, FIOASYNC, (void *)&tmp, l); 469 break; 470 471 case DIOCGPART32: 472 IOCTL_STRUCT_CONV_TO(DIOCGPART, partinfo); 473 #if 0 /* not implemented by anything */ 474 case DIOCRFORMAT32: 475 IOCTL_STRUCT_CONV_TO(DIOCRFORMAT, format_op); 476 case DIOCWFORMAT32: 477 IOCTL_STRUCT_CONV_TO(DIOCWFORMAT, format_op); 478 #endif 479 480 /* 481 * only a few ifreq syscalls need conversion and those are 482 * all driver specific... XXX 483 */ 484 #if 0 485 case SIOCGADDRROM3232: 486 IOCTL_STRUCT_CONV_TO(SIOCGADDRROM32, ifreq); 487 case SIOCGCHIPID32: 488 IOCTL_STRUCT_CONV_TO(SIOCGCHIPID, ifreq); 489 case SIOCSIFADDR32: 490 IOCTL_STRUCT_CONV_TO(SIOCSIFADDR, ifreq); 491 case OSIOCGIFADDR32: 492 IOCTL_STRUCT_CONV_TO(OSIOCGIFADDR, ifreq); 493 case SIOCGIFADDR32: 494 IOCTL_STRUCT_CONV_TO(SIOCGIFADDR, ifreq); 495 case SIOCSIFDSTADDR32: 496 IOCTL_STRUCT_CONV_TO(SIOCSIFDSTADDR, ifreq); 497 case OSIOCGIFDSTADDR32: 498 IOCTL_STRUCT_CONV_TO(OSIOCGIFDSTADDR, ifreq); 499 case SIOCGIFDSTADDR32: 500 IOCTL_STRUCT_CONV_TO(SIOCGIFDSTADDR, ifreq); 501 case OSIOCGIFBRDADDR32: 502 IOCTL_STRUCT_CONV_TO(OSIOCGIFBRDADDR, ifreq); 503 case SIOCGIFBRDADDR32: 504 IOCTL_STRUCT_CONV_TO(SIOCGIFBRDADDR, ifreq); 505 case SIOCSIFBRDADDR32: 506 IOCTL_STRUCT_CONV_TO(SIOCSIFBRDADDR, ifreq); 507 case OSIOCGIFNETMASK32: 508 IOCTL_STRUCT_CONV_TO(OSIOCGIFNETMASK, ifreq); 509 case SIOCGIFNETMASK32: 510 IOCTL_STRUCT_CONV_TO(SIOCGIFNETMASK, ifreq); 511 case SIOCSIFNETMASK32: 512 IOCTL_STRUCT_CONV_TO(SIOCSIFNETMASK, ifreq); 513 case SIOCGIFMETRIC32: 514 IOCTL_STRUCT_CONV_TO(SIOCGIFMETRIC, ifreq); 515 case SIOCSIFMETRIC32: 516 IOCTL_STRUCT_CONV_TO(SIOCSIFMETRIC, ifreq); 517 case SIOCDIFADDR32: 518 IOCTL_STRUCT_CONV_TO(SIOCDIFADDR, ifreq); 519 case SIOCADDMULTI32: 520 IOCTL_STRUCT_CONV_TO(SIOCADDMULTI, ifreq); 521 case SIOCDELMULTI32: 522 IOCTL_STRUCT_CONV_TO(SIOCDELMULTI, ifreq); 523 case SIOCSIFMEDIA32: 524 IOCTL_STRUCT_CONV_TO(SIOCSIFMEDIA, ifreq); 525 case SIOCSIFMTU32: 526 IOCTL_STRUCT_CONV_TO(SIOCSIFMTU, ifreq); 527 case SIOCGIFMTU32: 528 IOCTL_STRUCT_CONV_TO(SIOCGIFMTU, ifreq); 529 case BIOCGETIF32: 530 IOCTL_STRUCT_CONV_TO(BIOCGETIF, ifreq); 531 case BIOCSETIF32: 532 IOCTL_STRUCT_CONV_TO(BIOCSETIF, ifreq); 533 case SIOCPHASE132: 534 IOCTL_STRUCT_CONV_TO(SIOCPHASE1, ifreq); 535 case SIOCPHASE232: 536 IOCTL_STRUCT_CONV_TO(SIOCPHASE2, ifreq); 537 #endif 538 539 case OSIOCGIFCONF32: 540 IOCTL_STRUCT_CONV_TO(OSIOCGIFCONF, ifconf); 541 case SIOCGIFCONF32: 542 IOCTL_STRUCT_CONV_TO(SIOCGIFCONF, ifconf); 543 544 case SIOCGIFFLAGS32: 545 IOCTL_STRUCT_CONV_TO(SIOCGIFFLAGS, ifreq); 546 case SIOCSIFFLAGS32: 547 IOCTL_STRUCT_CONV_TO(SIOCSIFFLAGS, ifreq); 548 549 case SIOCGIFMEDIA32: 550 IOCTL_STRUCT_CONV_TO(SIOCGIFMEDIA, ifmediareq); 551 552 case SIOCSDRVSPEC32: 553 IOCTL_STRUCT_CONV_TO(SIOCSDRVSPEC, ifdrv); 554 555 case SIOCGETVIFCNT32: 556 IOCTL_STRUCT_CONV_TO(SIOCGETVIFCNT, sioc_vif_req); 557 558 case SIOCGETSGCNT32: 559 IOCTL_STRUCT_CONV_TO(SIOCGETSGCNT, sioc_sg_req); 560 561 default: 562 #ifdef NETBSD32_MD_IOCTL 563 error = netbsd32_md_ioctl(fp, com, data32, l); 564 #else 565 error = (*fp->f_ops->fo_ioctl)(fp, com, data32, l); 566 #endif 567 break; 568 } 569 570 if (error == EPASSTHROUGH) 571 error = ENOTTY; 572 573 /* 574 * Copy any data to user, size was 575 * already set and checked above. 576 */ 577 if (error == 0 && (com&IOC_OUT) && size32) { 578 error = copyout(data32, SCARG_P32(uap, data), size32); 579 ktrgenio(SCARG(uap, fd), UIO_READ, SCARG_P32(uap, data), 580 size32, error); 581 } 582 583 /* if we malloced data, free it here */ 584 if (memp32) 585 free(memp32, M_IOCTLOPS); 586 if (memp) 587 free(memp, M_IOCTLOPS); 588 589 out: 590 FILE_UNUSE(fp, l); 591 return (error); 592 } 593