1 /* $NetBSD: netbsd32_ioctl.c,v 1.15 2002/10/23 13:16:43 scw 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.15 2002/10/23 13:16:43 scw 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 *)NETBSD32PTR64(s32p->disklab); 114 p->part = (struct partition *)NETBSD32PTR64(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 *)NETBSD32PTR64(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)NETBSD32PTR64(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 *)NETBSD32PTR64(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 *)NETBSD32PTR64(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)NETBSD32PTR64(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 = 414 (caddr_t)NETBSD32PTR64(SCARG(uap, data)); 415 } else if ((com&IOC_OUT) && size32) 416 /* 417 * Zero the buffer so the user always 418 * gets back something deterministic. 419 */ 420 memset(data32, 0, size32); 421 else if (com&IOC_VOID) 422 *(caddr_t *)data32 = (caddr_t)NETBSD32PTR64(SCARG(uap, data)); 423 424 /* 425 * convert various structures, pointers, and other objects that 426 * change size from 32 bit -> 64 bit, for all ioctl commands. 427 */ 428 switch (SCARG(uap, com)) { 429 case FIONBIO: 430 if ((tmp = *(int *)data32) != 0) 431 fp->f_flag |= FNONBLOCK; 432 else 433 fp->f_flag &= ~FNONBLOCK; 434 error = (*fp->f_ops->fo_ioctl)(fp, FIONBIO, (caddr_t)&tmp, p); 435 break; 436 437 case FIOASYNC: 438 if ((tmp = *(int *)data32) != 0) 439 fp->f_flag |= FASYNC; 440 else 441 fp->f_flag &= ~FASYNC; 442 error = (*fp->f_ops->fo_ioctl)(fp, FIOASYNC, (caddr_t)&tmp, p); 443 break; 444 445 case FIOSETOWN: 446 tmp = *(int *)data32; 447 if (fp->f_type == DTYPE_SOCKET) { 448 ((struct socket *)fp->f_data)->so_pgid = tmp; 449 error = 0; 450 break; 451 } 452 if (tmp <= 0) { 453 tmp = -tmp; 454 } else { 455 struct proc *p1 = pfind(tmp); 456 if (p1 == 0) { 457 error = ESRCH; 458 break; 459 } 460 tmp = p1->p_pgrp->pg_id; 461 } 462 error = (*fp->f_ops->fo_ioctl) 463 (fp, TIOCSPGRP, (caddr_t)&tmp, p); 464 break; 465 466 case FIOGETOWN: 467 if (fp->f_type == DTYPE_SOCKET) { 468 error = 0; 469 *(int *)data32 = ((struct socket *)fp->f_data)->so_pgid; 470 break; 471 } 472 error = (*fp->f_ops->fo_ioctl)(fp, TIOCGPGRP, data32, p); 473 *(int *)data32 = -*(int *)data32; 474 break; 475 476 case DIOCGPART32: 477 IOCTL_STRUCT_CONV_TO(DIOCGPART, partinfo); 478 479 case DIOCRFORMAT32: 480 IOCTL_STRUCT_CONV_TO(DIOCRFORMAT, format_op); 481 case DIOCWFORMAT32: 482 IOCTL_STRUCT_CONV_TO(DIOCWFORMAT, format_op); 483 484 /* 485 * only a few ifreq syscalls need conversion and those are 486 * all driver specific... XXX 487 */ 488 #if 0 489 case SIOCGADDRROM3232: 490 IOCTL_STRUCT_CONV_TO(SIOCGADDRROM32, ifreq); 491 case SIOCGCHIPID32: 492 IOCTL_STRUCT_CONV_TO(SIOCGCHIPID, ifreq); 493 case SIOCSIFADDR32: 494 IOCTL_STRUCT_CONV_TO(SIOCSIFADDR, ifreq); 495 case OSIOCGIFADDR32: 496 IOCTL_STRUCT_CONV_TO(OSIOCGIFADDR, ifreq); 497 case SIOCGIFADDR32: 498 IOCTL_STRUCT_CONV_TO(SIOCGIFADDR, ifreq); 499 case SIOCSIFDSTADDR32: 500 IOCTL_STRUCT_CONV_TO(SIOCSIFDSTADDR, ifreq); 501 case OSIOCGIFDSTADDR32: 502 IOCTL_STRUCT_CONV_TO(OSIOCGIFDSTADDR, ifreq); 503 case SIOCGIFDSTADDR32: 504 IOCTL_STRUCT_CONV_TO(SIOCGIFDSTADDR, ifreq); 505 case SIOCSIFFLAGS32: 506 IOCTL_STRUCT_CONV_TO(SIOCSIFFLAGS, ifreq); 507 case SIOCGIFFLAGS32: 508 IOCTL_STRUCT_CONV_TO(SIOCGIFFLAGS, ifreq); 509 case OSIOCGIFBRDADDR32: 510 IOCTL_STRUCT_CONV_TO(OSIOCGIFBRDADDR, ifreq); 511 case SIOCGIFBRDADDR32: 512 IOCTL_STRUCT_CONV_TO(SIOCGIFBRDADDR, ifreq); 513 case SIOCSIFBRDADDR32: 514 IOCTL_STRUCT_CONV_TO(SIOCSIFBRDADDR, ifreq); 515 case OSIOCGIFNETMASK32: 516 IOCTL_STRUCT_CONV_TO(OSIOCGIFNETMASK, ifreq); 517 case SIOCGIFNETMASK32: 518 IOCTL_STRUCT_CONV_TO(SIOCGIFNETMASK, ifreq); 519 case SIOCSIFNETMASK32: 520 IOCTL_STRUCT_CONV_TO(SIOCSIFNETMASK, ifreq); 521 case SIOCGIFMETRIC32: 522 IOCTL_STRUCT_CONV_TO(SIOCGIFMETRIC, ifreq); 523 case SIOCSIFMETRIC32: 524 IOCTL_STRUCT_CONV_TO(SIOCSIFMETRIC, ifreq); 525 case SIOCDIFADDR32: 526 IOCTL_STRUCT_CONV_TO(SIOCDIFADDR, ifreq); 527 case SIOCADDMULTI32: 528 IOCTL_STRUCT_CONV_TO(SIOCADDMULTI, ifreq); 529 case SIOCDELMULTI32: 530 IOCTL_STRUCT_CONV_TO(SIOCDELMULTI, ifreq); 531 case SIOCSIFMEDIA32: 532 IOCTL_STRUCT_CONV_TO(SIOCSIFMEDIA, ifreq); 533 case SIOCSIFMTU32: 534 IOCTL_STRUCT_CONV_TO(SIOCSIFMTU, ifreq); 535 case SIOCGIFMTU32: 536 IOCTL_STRUCT_CONV_TO(SIOCGIFMTU, ifreq); 537 case SIOCSIFASYNCMAP32: 538 IOCTL_STRUCT_CONV_TO(SIOCSIFASYNCMAP, ifreq); 539 case SIOCGIFASYNCMAP32: 540 IOCTL_STRUCT_CONV_TO(SIOCGIFASYNCMAP, ifreq); 541 /* IOCTL_STRUCT_CONV_TO(BIOCGETIF, ifreq); READ ONLY */ 542 case BIOCSETIF32: 543 IOCTL_STRUCT_CONV_TO(BIOCSETIF, ifreq); 544 case SIOCPHASE132: 545 IOCTL_STRUCT_CONV_TO(SIOCPHASE1, ifreq); 546 case SIOCPHASE232: 547 IOCTL_STRUCT_CONV_TO(SIOCPHASE2, ifreq); 548 #endif 549 550 case OSIOCGIFCONF32: 551 IOCTL_STRUCT_CONV_TO(OSIOCGIFCONF, ifconf); 552 case SIOCGIFCONF32: 553 IOCTL_STRUCT_CONV_TO(SIOCGIFCONF, ifconf); 554 555 case SIOCGIFMEDIA32: 556 IOCTL_STRUCT_CONV_TO(SIOCGIFMEDIA, ifmediareq); 557 558 case SIOCSDRVSPEC32: 559 IOCTL_STRUCT_CONV_TO(SIOCSDRVSPEC, ifdrv); 560 561 case SIOCGETVIFCNT32: 562 IOCTL_STRUCT_CONV_TO(SIOCGETVIFCNT, sioc_vif_req); 563 564 case SIOCGETSGCNT32: 565 IOCTL_STRUCT_CONV_TO(SIOCGETSGCNT, sioc_sg_req); 566 567 default: 568 #ifdef NETBSD32_MD_IOCTL 569 error = netbsd32_md_ioctl(fp, com, data32, p); 570 #else 571 error = (*fp->f_ops->fo_ioctl)(fp, com, data32, p); 572 #endif 573 break; 574 } 575 576 /* 577 * Copy any data to user, size was 578 * already set and checked above. 579 */ 580 if (error == 0 && (com&IOC_OUT) && size32) 581 error = copyout(data32, 582 (caddr_t)NETBSD32PTR64(SCARG(uap, data)), size32); 583 584 /* if we malloced data, free it here */ 585 if (memp32) 586 free(memp32, M_IOCTLOPS); 587 if (memp) 588 free(memp, M_IOCTLOPS); 589 590 out: 591 FILE_UNUSE(fp, p); 592 return (error); 593 } 594