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