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