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