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