1 /* $NetBSD: netbsd32_ioctl.c,v 1.14 2002/01/03 02:29:39 mrg 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.14 2002/01/03 02:29:39 mrg 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/proc.h> 50 #include <sys/sockio.h> 51 #include <sys/socket.h> 52 #include <sys/ttycom.h> 53 #include <sys/mount.h> 54 #include <sys/syscallargs.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/netbsd32/netbsd32.h> 71 #include <compat/netbsd32/netbsd32_ioctl.h> 72 #include <compat/netbsd32/netbsd32_syscallargs.h> 73 74 /* prototypes for the converters */ 75 static __inline void 76 netbsd32_to_partinfo(struct netbsd32_partinfo *, struct partinfo *, u_long); 77 static __inline void 78 netbsd32_to_format_op(struct netbsd32_format_op *, struct format_op *, u_long); 79 static __inline void 80 netbsd32_to_ifconf(struct netbsd32_ifconf *, struct ifconf *, u_long); 81 static __inline void 82 netbsd32_to_ifmediareq(struct netbsd32_ifmediareq *, struct ifmediareq *, u_long); 83 static __inline void 84 netbsd32_to_ifdrv(struct netbsd32_ifdrv *, struct ifdrv *, u_long); 85 static __inline void 86 netbsd32_to_sioc_vif_req(struct netbsd32_sioc_vif_req *, struct sioc_vif_req *, u_long); 87 static __inline void 88 netbsd32_to_sioc_sg_req(struct netbsd32_sioc_sg_req *, struct sioc_sg_req *, u_long); 89 static __inline void 90 netbsd32_from_partinfo(struct partinfo *, struct netbsd32_partinfo *); 91 static __inline void 92 netbsd32_from_format_op(struct format_op *, struct netbsd32_format_op *); 93 static __inline void 94 netbsd32_from_ifconf(struct ifconf *, struct netbsd32_ifconf *); 95 static __inline void 96 netbsd32_from_ifmediareq(struct ifmediareq *, struct netbsd32_ifmediareq *); 97 static __inline void 98 netbsd32_from_ifdrv(struct ifdrv *, struct netbsd32_ifdrv *); 99 static __inline void 100 netbsd32_from_sioc_vif_req(struct sioc_vif_req *, struct netbsd32_sioc_vif_req *); 101 static __inline void 102 netbsd32_from_sioc_sg_req(struct sioc_sg_req *, struct netbsd32_sioc_sg_req *); 103 104 /* convert to/from different structures */ 105 106 static __inline void 107 netbsd32_to_partinfo(s32p, p, cmd) 108 struct netbsd32_partinfo *s32p; 109 struct partinfo *p; 110 u_long cmd; 111 { 112 113 p->disklab = (struct disklabel *)(u_long)s32p->disklab; 114 p->part = (struct partition *)(u_long)s32p->part; 115 } 116 117 static __inline void 118 netbsd32_to_format_op(s32p, p, cmd) 119 struct netbsd32_format_op *s32p; 120 struct format_op *p; 121 u_long cmd; 122 { 123 124 p->df_buf = (char *)(u_long)s32p->df_buf; 125 p->df_count = s32p->df_count; 126 p->df_startblk = s32p->df_startblk; 127 memcpy(p->df_reg, s32p->df_reg, sizeof(s32p->df_reg)); 128 } 129 130 #if 0 /* XXX see below */ 131 static __inline void 132 netbsd32_to_ifreq(s32p, p, cmd) 133 struct netbsd32_ifreq *s32p; 134 struct ifreq *p; 135 u_long cmd; /* XXX unused yet */ 136 { 137 138 /* 139 * XXX 140 * struct ifreq says the same, but sometimes the ifr_data 141 * union member needs to be converted to 64 bits... this 142 * is very driver specific and so we ignore it for now.. 143 */ 144 memcpy(p, s32p, sizeof *s32p); 145 } 146 #endif 147 148 static __inline void 149 netbsd32_to_ifconf(s32p, p, cmd) 150 struct netbsd32_ifconf *s32p; 151 struct ifconf *p; 152 u_long cmd; 153 { 154 155 p->ifc_len = s32p->ifc_len; 156 /* ifc_buf & ifc_req are the same size so this works */ 157 p->ifc_buf = (caddr_t)(u_long)s32p->ifc_buf; 158 } 159 160 static __inline void 161 netbsd32_to_ifmediareq(s32p, p, cmd) 162 struct netbsd32_ifmediareq *s32p; 163 struct ifmediareq *p; 164 u_long cmd; 165 { 166 167 memcpy(p, s32p, sizeof *s32p); 168 p->ifm_ulist = (int *)(u_long)s32p->ifm_ulist; 169 } 170 171 static __inline void 172 netbsd32_to_ifdrv(s32p, p, cmd) 173 struct netbsd32_ifdrv *s32p; 174 struct ifdrv *p; 175 u_long cmd; 176 { 177 178 memcpy(p, s32p, sizeof *s32p); 179 p->ifd_data = (void *)(u_long)s32p->ifd_data; 180 } 181 182 static __inline void 183 netbsd32_to_sioc_vif_req(s32p, p, cmd) 184 struct netbsd32_sioc_vif_req *s32p; 185 struct sioc_vif_req *p; 186 u_long cmd; 187 { 188 189 p->vifi = s32p->vifi; 190 p->icount = (u_long)s32p->icount; 191 p->ocount = (u_long)s32p->ocount; 192 p->ibytes = (u_long)s32p->ibytes; 193 p->obytes = (u_long)s32p->obytes; 194 } 195 196 static __inline void 197 netbsd32_to_sioc_sg_req(s32p, p, cmd) 198 struct netbsd32_sioc_sg_req *s32p; 199 struct sioc_sg_req *p; 200 u_long cmd; 201 { 202 203 p->src = s32p->src; 204 p->grp = s32p->grp; 205 p->pktcnt = (u_long)s32p->pktcnt; 206 p->bytecnt = (u_long)s32p->bytecnt; 207 p->wrong_if = (u_long)s32p->wrong_if; 208 } 209 210 /* 211 * handle ioctl conversions from 64-bit kernel -> netbsd32 212 */ 213 214 static __inline void 215 netbsd32_from_partinfo(p, s32p) 216 struct partinfo *p; 217 struct netbsd32_partinfo *s32p; 218 { 219 220 s32p->disklab = (netbsd32_disklabel_tp_t)(u_long)p->disklab; 221 s32p->part = s32p->part; 222 } 223 224 static __inline void 225 netbsd32_from_format_op(p, s32p) 226 struct format_op *p; 227 struct netbsd32_format_op *s32p; 228 { 229 230 /* filled in */ 231 #if 0 232 s32p->df_buf = (netbsd32_charp)p->df_buf; 233 #endif 234 s32p->df_count = p->df_count; 235 s32p->df_startblk = p->df_startblk; 236 memcpy(s32p->df_reg, p->df_reg, sizeof(p->df_reg)); 237 } 238 239 #if 0 /* XXX see below */ 240 static __inline void 241 netbsd32_from_ifreq(p, s32p, cmd) 242 struct ifreq *p; 243 struct netbsd32_ifreq *s32p; 244 u_long cmd; /* XXX unused yet */ 245 { 246 247 /* 248 * XXX 249 * struct ifreq says the same, but sometimes the ifr_data 250 * union member needs to be converted to 64 bits... this 251 * is very driver specific and so we ignore it for now.. 252 */ 253 *s32p = *p; 254 } 255 #endif 256 257 static __inline void 258 netbsd32_from_ifconf(p, s32p) 259 struct ifconf *p; 260 struct netbsd32_ifconf *s32p; 261 { 262 263 s32p->ifc_len = p->ifc_len; 264 /* ifc_buf & ifc_req are the same size so this works */ 265 s32p->ifc_buf = (netbsd32_caddr_t)(u_long)p->ifc_buf; 266 } 267 268 static __inline void 269 netbsd32_from_ifmediareq(p, s32p) 270 struct ifmediareq *p; 271 struct netbsd32_ifmediareq *s32p; 272 { 273 274 memcpy(s32p, p, sizeof *p); 275 /* filled in? */ 276 #if 0 277 s32p->ifm_ulist = (netbsd32_intp_t)p->ifm_ulist; 278 #endif 279 } 280 281 static __inline void 282 netbsd32_from_ifdrv(p, s32p) 283 struct ifdrv *p; 284 struct netbsd32_ifdrv *s32p; 285 { 286 287 memcpy(s32p, p, sizeof *p); 288 /* filled in? */ 289 #if 0 290 s32p->ifm_data = (netbsd32_u_longp_t)p->ifm_data; 291 #endif 292 } 293 294 static __inline void 295 netbsd32_from_sioc_vif_req(p, s32p) 296 struct sioc_vif_req *p; 297 struct netbsd32_sioc_vif_req *s32p; 298 { 299 300 s32p->vifi = p->vifi; 301 s32p->icount = (netbsd32_u_long)p->icount; 302 s32p->ocount = (netbsd32_u_long)p->ocount; 303 s32p->ibytes = (netbsd32_u_long)p->ibytes; 304 s32p->obytes = (netbsd32_u_long)p->obytes; 305 } 306 307 static __inline void 308 netbsd32_from_sioc_sg_req(p, s32p) 309 struct sioc_sg_req *p; 310 struct netbsd32_sioc_sg_req *s32p; 311 { 312 313 s32p->src = p->src; 314 s32p->grp = p->grp; 315 s32p->pktcnt = (netbsd32_u_long)p->pktcnt; 316 s32p->bytecnt = (netbsd32_u_long)p->bytecnt; 317 s32p->wrong_if = (netbsd32_u_long)p->wrong_if; 318 } 319 320 321 /* 322 * main ioctl syscall. 323 * 324 * ok, here we are in the biggy. we have to do fix ups depending 325 * on the ioctl command before and afterwards. 326 */ 327 int 328 netbsd32_ioctl(p, v, retval) 329 struct proc *p; 330 void *v; 331 register_t *retval; 332 { 333 struct netbsd32_ioctl_args /* { 334 syscallarg(int) fd; 335 syscallarg(netbsd32_u_long) com; 336 syscallarg(netbsd32_voidp) data; 337 } */ *uap = v; 338 struct file *fp; 339 struct filedesc *fdp; 340 u_long com; 341 int error = 0; 342 u_int size, size32; 343 caddr_t data, memp = NULL; 344 caddr_t data32, memp32 = NULL; 345 int tmp; 346 #define STK_PARAMS 128 347 u_long stkbuf[STK_PARAMS/sizeof(u_long)]; 348 u_long stkbuf32[STK_PARAMS/sizeof(u_long)]; 349 350 /* 351 * we need to translate some commands (_IOW) before calling sys_ioctl, 352 * some after (_IOR), and some both (_IOWR). 353 */ 354 #if 0 355 { 356 char *dirs[8] = { "NONE!", "VOID", "OUT", "VOID|OUT!", "IN", "VOID|IN!", 357 "INOUT", "VOID|IN|OUT!" }; 358 359 printf("netbsd32_ioctl(%d, %x, %x): %s group %c base %d len %d\n", 360 SCARG(uap, fd), SCARG(uap, com), SCARG(uap, data), 361 dirs[((SCARG(uap, com) & IOC_DIRMASK)>>29)], 362 IOCGROUP(SCARG(uap, com)), IOCBASECMD(SCARG(uap, com)), 363 IOCPARM_LEN(SCARG(uap, com))); 364 } 365 #endif 366 367 fdp = p->p_fd; 368 if ((fp = fd_getfile(fdp, SCARG(uap, fd))) == NULL) 369 return (EBADF); 370 371 FILE_USE(fp); 372 373 if ((fp->f_flag & (FREAD | FWRITE)) == 0) { 374 error = EBADF; 375 goto out; 376 } 377 378 switch (com = SCARG(uap, com)) { 379 case FIONCLEX: 380 fdp->fd_ofileflags[SCARG(uap, fd)] &= ~UF_EXCLOSE; 381 goto out; 382 383 case FIOCLEX: 384 fdp->fd_ofileflags[SCARG(uap, fd)] |= UF_EXCLOSE; 385 goto out; 386 } 387 388 /* 389 * Interpret high order word to find amount of data to be 390 * copied to/from the user's address space. 391 */ 392 size32 = IOCPARM_LEN(com); 393 if (size32 > IOCPARM_MAX) { 394 error = ENOTTY; 395 goto out; 396 } 397 memp = NULL; 398 if (size32 > sizeof(stkbuf)) { 399 memp32 = (caddr_t)malloc((u_long)size32, M_IOCTLOPS, M_WAITOK); 400 data32 = memp32; 401 } else 402 data32 = (caddr_t)stkbuf32; 403 if (com&IOC_IN) { 404 if (size32) { 405 error = copyin((caddr_t)(u_long)SCARG(uap, data), 406 data32, size32); 407 if (error) { 408 if (memp32) 409 free(memp32, M_IOCTLOPS); 410 goto out; 411 } 412 } else 413 *(caddr_t *)data32 = (caddr_t)(u_long)SCARG(uap, data); 414 } else if ((com&IOC_OUT) && size32) 415 /* 416 * Zero the buffer so the user always 417 * gets back something deterministic. 418 */ 419 memset(data32, 0, size32); 420 else if (com&IOC_VOID) 421 *(caddr_t *)data32 = (caddr_t)(u_long)SCARG(uap, data); 422 423 /* 424 * convert various structures, pointers, and other objects that 425 * change size from 32 bit -> 64 bit, for all ioctl commands. 426 */ 427 switch (SCARG(uap, com)) { 428 case FIONBIO: 429 if ((tmp = *(int *)data32) != 0) 430 fp->f_flag |= FNONBLOCK; 431 else 432 fp->f_flag &= ~FNONBLOCK; 433 error = (*fp->f_ops->fo_ioctl)(fp, FIONBIO, (caddr_t)&tmp, p); 434 break; 435 436 case FIOASYNC: 437 if ((tmp = *(int *)data32) != 0) 438 fp->f_flag |= FASYNC; 439 else 440 fp->f_flag &= ~FASYNC; 441 error = (*fp->f_ops->fo_ioctl)(fp, FIOASYNC, (caddr_t)&tmp, p); 442 break; 443 444 case FIOSETOWN: 445 tmp = *(int *)data32; 446 if (fp->f_type == DTYPE_SOCKET) { 447 ((struct socket *)fp->f_data)->so_pgid = tmp; 448 error = 0; 449 break; 450 } 451 if (tmp <= 0) { 452 tmp = -tmp; 453 } else { 454 struct proc *p1 = pfind(tmp); 455 if (p1 == 0) { 456 error = ESRCH; 457 break; 458 } 459 tmp = p1->p_pgrp->pg_id; 460 } 461 error = (*fp->f_ops->fo_ioctl) 462 (fp, TIOCSPGRP, (caddr_t)&tmp, p); 463 break; 464 465 case FIOGETOWN: 466 if (fp->f_type == DTYPE_SOCKET) { 467 error = 0; 468 *(int *)data32 = ((struct socket *)fp->f_data)->so_pgid; 469 break; 470 } 471 error = (*fp->f_ops->fo_ioctl)(fp, TIOCGPGRP, data32, p); 472 *(int *)data32 = -*(int *)data32; 473 break; 474 475 case DIOCGPART32: 476 IOCTL_STRUCT_CONV_TO(DIOCGPART, partinfo); 477 478 case DIOCRFORMAT32: 479 IOCTL_STRUCT_CONV_TO(DIOCRFORMAT, format_op); 480 case DIOCWFORMAT32: 481 IOCTL_STRUCT_CONV_TO(DIOCWFORMAT, format_op); 482 483 /* 484 * only a few ifreq syscalls need conversion and those are 485 * all driver specific... XXX 486 */ 487 #if 0 488 case SIOCGADDRROM3232: 489 IOCTL_STRUCT_CONV_TO(SIOCGADDRROM32, ifreq); 490 case SIOCGCHIPID32: 491 IOCTL_STRUCT_CONV_TO(SIOCGCHIPID, ifreq); 492 case SIOCSIFADDR32: 493 IOCTL_STRUCT_CONV_TO(SIOCSIFADDR, ifreq); 494 case OSIOCGIFADDR32: 495 IOCTL_STRUCT_CONV_TO(OSIOCGIFADDR, ifreq); 496 case SIOCGIFADDR32: 497 IOCTL_STRUCT_CONV_TO(SIOCGIFADDR, ifreq); 498 case SIOCSIFDSTADDR32: 499 IOCTL_STRUCT_CONV_TO(SIOCSIFDSTADDR, ifreq); 500 case OSIOCGIFDSTADDR32: 501 IOCTL_STRUCT_CONV_TO(OSIOCGIFDSTADDR, ifreq); 502 case SIOCGIFDSTADDR32: 503 IOCTL_STRUCT_CONV_TO(SIOCGIFDSTADDR, ifreq); 504 case SIOCSIFFLAGS32: 505 IOCTL_STRUCT_CONV_TO(SIOCSIFFLAGS, ifreq); 506 case SIOCGIFFLAGS32: 507 IOCTL_STRUCT_CONV_TO(SIOCGIFFLAGS, ifreq); 508 case OSIOCGIFBRDADDR32: 509 IOCTL_STRUCT_CONV_TO(OSIOCGIFBRDADDR, ifreq); 510 case SIOCGIFBRDADDR32: 511 IOCTL_STRUCT_CONV_TO(SIOCGIFBRDADDR, ifreq); 512 case SIOCSIFBRDADDR32: 513 IOCTL_STRUCT_CONV_TO(SIOCSIFBRDADDR, ifreq); 514 case OSIOCGIFNETMASK32: 515 IOCTL_STRUCT_CONV_TO(OSIOCGIFNETMASK, ifreq); 516 case SIOCGIFNETMASK32: 517 IOCTL_STRUCT_CONV_TO(SIOCGIFNETMASK, ifreq); 518 case SIOCSIFNETMASK32: 519 IOCTL_STRUCT_CONV_TO(SIOCSIFNETMASK, ifreq); 520 case SIOCGIFMETRIC32: 521 IOCTL_STRUCT_CONV_TO(SIOCGIFMETRIC, ifreq); 522 case SIOCSIFMETRIC32: 523 IOCTL_STRUCT_CONV_TO(SIOCSIFMETRIC, ifreq); 524 case SIOCDIFADDR32: 525 IOCTL_STRUCT_CONV_TO(SIOCDIFADDR, ifreq); 526 case SIOCADDMULTI32: 527 IOCTL_STRUCT_CONV_TO(SIOCADDMULTI, ifreq); 528 case SIOCDELMULTI32: 529 IOCTL_STRUCT_CONV_TO(SIOCDELMULTI, ifreq); 530 case SIOCSIFMEDIA32: 531 IOCTL_STRUCT_CONV_TO(SIOCSIFMEDIA, ifreq); 532 case SIOCSIFMTU32: 533 IOCTL_STRUCT_CONV_TO(SIOCSIFMTU, ifreq); 534 case SIOCGIFMTU32: 535 IOCTL_STRUCT_CONV_TO(SIOCGIFMTU, ifreq); 536 case SIOCSIFASYNCMAP32: 537 IOCTL_STRUCT_CONV_TO(SIOCSIFASYNCMAP, ifreq); 538 case SIOCGIFASYNCMAP32: 539 IOCTL_STRUCT_CONV_TO(SIOCGIFASYNCMAP, ifreq); 540 /* IOCTL_STRUCT_CONV_TO(BIOCGETIF, ifreq); READ ONLY */ 541 case BIOCSETIF32: 542 IOCTL_STRUCT_CONV_TO(BIOCSETIF, ifreq); 543 case SIOCPHASE132: 544 IOCTL_STRUCT_CONV_TO(SIOCPHASE1, ifreq); 545 case SIOCPHASE232: 546 IOCTL_STRUCT_CONV_TO(SIOCPHASE2, ifreq); 547 #endif 548 549 case OSIOCGIFCONF32: 550 IOCTL_STRUCT_CONV_TO(OSIOCGIFCONF, ifconf); 551 case SIOCGIFCONF32: 552 IOCTL_STRUCT_CONV_TO(SIOCGIFCONF, ifconf); 553 554 case SIOCGIFMEDIA32: 555 IOCTL_STRUCT_CONV_TO(SIOCGIFMEDIA, ifmediareq); 556 557 case SIOCSDRVSPEC32: 558 IOCTL_STRUCT_CONV_TO(SIOCSDRVSPEC, ifdrv); 559 560 case SIOCGETVIFCNT32: 561 IOCTL_STRUCT_CONV_TO(SIOCGETVIFCNT, sioc_vif_req); 562 563 case SIOCGETSGCNT32: 564 IOCTL_STRUCT_CONV_TO(SIOCGETSGCNT, sioc_sg_req); 565 566 default: 567 #ifdef NETBSD32_MD_IOCTL 568 error = netbsd32_md_ioctl(fp, com, data32, p); 569 #else 570 error = (*fp->f_ops->fo_ioctl)(fp, com, data32, p); 571 #endif 572 break; 573 } 574 575 /* 576 * Copy any data to user, size was 577 * already set and checked above. 578 */ 579 if (error == 0 && (com&IOC_OUT) && size32) 580 error = copyout(data32, (caddr_t)(u_long)SCARG(uap, data), size32); 581 582 /* if we malloced data, free it here */ 583 if (memp32) 584 free(memp32, M_IOCTLOPS); 585 if (memp) 586 free(memp, M_IOCTLOPS); 587 588 out: 589 FILE_UNUSE(fp, p); 590 return (error); 591 } 592