1 /* $NetBSD: netbsd32_ioctl.c,v 1.47 2010/04/23 15:19:20 rmind 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 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 21 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 23 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29 /* 30 * handle ioctl conversions from netbsd32 -> 64-bit kernel 31 */ 32 33 #include <sys/cdefs.h> 34 __KERNEL_RCSID(0, "$NetBSD: netbsd32_ioctl.c,v 1.47 2010/04/23 15:19:20 rmind Exp $"); 35 36 #include <sys/param.h> 37 #include <sys/systm.h> 38 #include <sys/filedesc.h> 39 #include <sys/ioctl.h> 40 #include <sys/file.h> 41 #include <sys/proc.h> 42 #include <sys/socketvar.h> 43 #include <sys/audioio.h> 44 #include <sys/disklabel.h> 45 #include <sys/dkio.h> 46 #include <sys/sockio.h> 47 #include <sys/socket.h> 48 #include <sys/ttycom.h> 49 #include <sys/mount.h> 50 #include <sys/syscallargs.h> 51 #include <sys/ktrace.h> 52 #include <sys/kmem.h> 53 54 #ifdef __sparc__ 55 #include <dev/sun/fbio.h> 56 #include <machine/openpromio.h> 57 #endif 58 59 #include <net/if.h> 60 #include <net/route.h> 61 62 #include <netinet/in.h> 63 #include <netinet/in_var.h> 64 #include <netinet/igmp.h> 65 #include <netinet/igmp_var.h> 66 #include <netinet/ip_mroute.h> 67 68 #include <compat/sys/sockio.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 netbsd32_to_partinfo(struct netbsd32_partinfo *, 76 struct partinfo *, u_long); 77 #if 0 78 static inline void netbsd32_to_format_op(struct netbsd32_format_op *, 79 struct format_op *, u_long); 80 #endif 81 static inline void netbsd32_to_oifreq(struct netbsd32_oifreq *, struct oifreq *, 82 u_long cmd); 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_oifreq(struct oifreq *, 105 struct netbsd32_oifreq *, u_long); 106 static inline void netbsd32_from_ifconf(struct ifconf *, 107 struct netbsd32_ifconf *, u_long); 108 static inline void netbsd32_from_ifmediareq(struct ifmediareq *, 109 struct netbsd32_ifmediareq *, 110 u_long); 111 static inline void netbsd32_from_ifdrv(struct ifdrv *, 112 struct netbsd32_ifdrv *, u_long); 113 static inline void netbsd32_from_sioc_vif_req(struct sioc_vif_req *, 114 struct netbsd32_sioc_vif_req *, 115 u_long); 116 static inline void netbsd32_from_sioc_sg_req(struct sioc_sg_req *, 117 struct netbsd32_sioc_sg_req *, 118 u_long); 119 120 /* convert to/from different structures */ 121 122 static inline void 123 netbsd32_to_partinfo(struct netbsd32_partinfo *s32p, struct partinfo *p, 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(struct netbsd32_format_op *s32p, struct format_op *p, u_long cmd) 133 { 134 135 p->df_buf = (char *)NETBSD32PTR64(s32p->df_buf); 136 p->df_count = s32p->df_count; 137 p->df_startblk = s32p->df_startblk; 138 memcpy(p->df_reg, s32p->df_reg, sizeof(s32p->df_reg)); 139 } 140 #endif 141 142 static inline void 143 netbsd32_to_ifreq(struct netbsd32_ifreq *s32p, struct ifreq *p, u_long cmd) 144 { 145 146 memcpy(p, s32p, sizeof *s32p); 147 /* 148 * XXX 149 * struct ifreq says the same, but sometimes the ifr_data 150 * union member needs to be converted to 64 bits... this 151 * is very driver specific and so we ignore it for now.. 152 */ 153 if (cmd == SIOCGIFDATA || cmd == SIOCZIFDATA) 154 p->ifr_data = (void *)NETBSD32PTR64(s32p->ifr_data); 155 } 156 157 static inline void 158 netbsd32_to_oifreq(struct netbsd32_oifreq *s32p, struct oifreq *p, u_long cmd) 159 { 160 161 memcpy(p, s32p, sizeof *s32p); 162 /* 163 * XXX 164 * struct ifreq says the same, but sometimes the ifr_data 165 * union member needs to be converted to 64 bits... this 166 * is very driver specific and so we ignore it for now.. 167 */ 168 if (cmd == SIOCGIFDATA || cmd == SIOCZIFDATA) 169 p->ifr_data = (void *)NETBSD32PTR64(s32p->ifr_data); 170 } 171 172 static inline void 173 netbsd32_to_ifconf(struct netbsd32_ifconf *s32p, struct ifconf *p, u_long cmd) 174 { 175 176 p->ifc_len = s32p->ifc_len; 177 /* ifc_buf & ifc_req are the same size so this works */ 178 p->ifc_buf = (void *)NETBSD32PTR64(s32p->ifc_buf); 179 } 180 181 static inline void 182 netbsd32_to_ifmediareq(struct netbsd32_ifmediareq *s32p, struct ifmediareq *p, u_long cmd) 183 { 184 185 memcpy(p, s32p, sizeof *s32p); 186 p->ifm_ulist = (int *)NETBSD32PTR64(s32p->ifm_ulist); 187 } 188 189 static inline void 190 netbsd32_to_ifdrv(struct netbsd32_ifdrv *s32p, struct ifdrv *p, 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(struct netbsd32_sioc_vif_req *s32p, struct sioc_vif_req *p, u_long cmd) 199 { 200 201 p->vifi = s32p->vifi; 202 p->icount = (u_long)s32p->icount; 203 p->ocount = (u_long)s32p->ocount; 204 p->ibytes = (u_long)s32p->ibytes; 205 p->obytes = (u_long)s32p->obytes; 206 } 207 208 static inline void 209 netbsd32_to_sioc_sg_req(struct netbsd32_sioc_sg_req *s32p, struct sioc_sg_req *p, u_long cmd) 210 { 211 212 p->src = s32p->src; 213 p->grp = s32p->grp; 214 p->pktcnt = (u_long)s32p->pktcnt; 215 p->bytecnt = (u_long)s32p->bytecnt; 216 p->wrong_if = (u_long)s32p->wrong_if; 217 } 218 219 /* 220 * handle ioctl conversions from 64-bit kernel -> netbsd32 221 */ 222 223 static inline void 224 netbsd32_from_partinfo(struct partinfo *p, struct netbsd32_partinfo *s32p, u_long cmd) 225 { 226 227 NETBSD32PTR32(s32p->disklab, p->disklab); 228 NETBSD32PTR32(s32p->part, p->part); 229 } 230 231 #if 0 232 static inline void 233 netbsd32_from_format_op(struct format_op *p, struct netbsd32_format_op *s32p, u_long cmd) 234 { 235 236 /* filled in */ 237 #if 0 238 s32p->df_buf = (netbsd32_charp)p->df_buf; 239 #endif 240 s32p->df_count = p->df_count; 241 s32p->df_startblk = p->df_startblk; 242 memcpy(s32p->df_reg, p->df_reg, sizeof(p->df_reg)); 243 } 244 #endif 245 246 static inline void 247 netbsd32_from_ifreq(struct ifreq *p, struct netbsd32_ifreq *s32p, u_long cmd) 248 { 249 250 /* 251 * XXX 252 * struct ifreq says the same, but sometimes the ifr_data 253 * union member needs to be converted to 64 bits... this 254 * is very driver specific and so we ignore it for now.. 255 */ 256 memcpy(s32p, p, sizeof *s32p); 257 if (cmd == SIOCGIFDATA || cmd == SIOCZIFDATA) 258 NETBSD32PTR32(s32p->ifr_data, p->ifr_data); 259 } 260 261 static inline void 262 netbsd32_from_oifreq(struct oifreq *p, struct netbsd32_oifreq *s32p, 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 memcpy(s32p, p, sizeof *s32p); 272 if (cmd == SIOCGIFDATA || cmd == SIOCZIFDATA) 273 NETBSD32PTR32(s32p->ifr_data, p->ifr_data); 274 } 275 276 static inline void 277 netbsd32_from_ifconf(struct ifconf *p, struct netbsd32_ifconf *s32p, u_long cmd) 278 { 279 280 s32p->ifc_len = p->ifc_len; 281 /* ifc_buf & ifc_req are the same size so this works */ 282 NETBSD32PTR32(s32p->ifc_buf, p->ifc_buf); 283 } 284 285 static inline void 286 netbsd32_from_ifmediareq(struct ifmediareq *p, struct netbsd32_ifmediareq *s32p, u_long cmd) 287 { 288 289 memcpy(s32p, p, sizeof *p); 290 /* filled in? */ 291 #if 0 292 s32p->ifm_ulist = (netbsd32_intp_t)p->ifm_ulist; 293 #endif 294 } 295 296 static inline void 297 netbsd32_from_ifdrv(struct ifdrv *p, struct netbsd32_ifdrv *s32p, u_long cmd) 298 { 299 300 memcpy(s32p, p, sizeof *p); 301 /* filled in? */ 302 #if 0 303 s32p->ifm_data = (netbsd32_u_longp_t)p->ifm_data; 304 #endif 305 } 306 307 static inline void 308 netbsd32_from_sioc_vif_req(struct sioc_vif_req *p, struct netbsd32_sioc_vif_req *s32p, u_long cmd) 309 { 310 311 s32p->vifi = p->vifi; 312 s32p->icount = (netbsd32_u_long)p->icount; 313 s32p->ocount = (netbsd32_u_long)p->ocount; 314 s32p->ibytes = (netbsd32_u_long)p->ibytes; 315 s32p->obytes = (netbsd32_u_long)p->obytes; 316 } 317 318 static inline void 319 netbsd32_from_sioc_sg_req(struct sioc_sg_req *p, struct netbsd32_sioc_sg_req *s32p, u_long cmd) 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(struct lwp *l, const struct netbsd32_ioctl_args *uap, register_t *retval) 338 { 339 /* { 340 syscallarg(int) fd; 341 syscallarg(netbsd32_u_long) com; 342 syscallarg(netbsd32_voidp) data; 343 } */ 344 struct proc *p = l->l_proc; 345 struct file *fp; 346 struct filedesc *fdp; 347 u_long com; 348 int error = 0; 349 u_int size, size32; 350 void *data, *memp = NULL; 351 void *data32, *memp32 = NULL; 352 unsigned fd; 353 fdfile_t *ff; 354 int tmp; 355 #define STK_PARAMS 128 356 u_long stkbuf[STK_PARAMS/sizeof(u_long)]; 357 u_long stkbuf32[STK_PARAMS/sizeof(u_long)]; 358 359 /* 360 * we need to translate some commands (_IOW) before calling sys_ioctl, 361 * some after (_IOR), and some both (_IOWR). 362 */ 363 #if 0 364 { 365 char *dirs[8] = { "NONE!", "VOID", "OUT", "VOID|OUT!", "IN", "VOID|IN!", 366 "INOUT", "VOID|IN|OUT!" }; 367 368 printf("netbsd32_ioctl(%d, %x, %x): %s group %c base %d len %d\n", 369 SCARG(uap, fd), SCARG(uap, com), SCARG(uap, data), 370 dirs[((SCARG(uap, com) & IOC_DIRMASK)>>29)], 371 IOCGROUP(SCARG(uap, com)), IOCBASECMD(SCARG(uap, com)), 372 IOCPARM_LEN(SCARG(uap, com))); 373 } 374 #endif 375 376 fdp = p->p_fd; 377 fd = SCARG(uap, fd); 378 if ((fp = fd_getfile(fd)) == NULL) 379 return (EBADF); 380 if ((fp->f_flag & (FREAD | FWRITE)) == 0) { 381 error = EBADF; 382 goto out; 383 } 384 385 ff = fdp->fd_dt->dt_ff[SCARG(uap, fd)]; 386 switch (com = SCARG(uap, com)) { 387 case FIOCLEX: 388 ff->ff_exclose = true; 389 fdp->fd_exclose = true; 390 goto out; 391 392 case FIONCLEX: 393 ff->ff_exclose = false; 394 goto out; 395 } 396 397 /* 398 * Interpret high order word to find amount of data to be 399 * copied to/from the user's address space. 400 */ 401 size = 0; 402 size32 = IOCPARM_LEN(com); 403 if (size32 > IOCPARM_MAX) { 404 error = ENOTTY; 405 goto out; 406 } 407 if (size32 > sizeof(stkbuf)) { 408 memp32 = kmem_alloc((size_t)size32, KM_SLEEP); 409 data32 = memp32; 410 } else 411 data32 = (void *)stkbuf32; 412 if (com&IOC_IN) { 413 if (size32) { 414 error = copyin(SCARG_P32(uap, data), data32, size32); 415 if (error) { 416 if (memp32) 417 kmem_free(memp32, (size_t)size32); 418 goto out; 419 } 420 ktrgenio(fd, UIO_WRITE, SCARG_P32(uap, data), 421 size32, 0); 422 } else 423 *(void **)data32 = SCARG_P32(uap, data); 424 } else if ((com&IOC_OUT) && size32) 425 /* 426 * Zero the buffer so the user always 427 * gets back something deterministic. 428 */ 429 memset(data32, 0, size32); 430 else if (com&IOC_VOID) 431 *(void **)data32 = SCARG_P32(uap, data); 432 433 /* 434 * convert various structures, pointers, and other objects that 435 * change size from 32 bit -> 64 bit, for all ioctl commands. 436 */ 437 switch (SCARG(uap, com)) { 438 case FIONBIO: 439 mutex_enter(&fp->f_lock); 440 if ((tmp = *(int *)data32) != 0) 441 fp->f_flag |= FNONBLOCK; 442 else 443 fp->f_flag &= ~FNONBLOCK; 444 mutex_exit(&fp->f_lock); 445 error = (*fp->f_ops->fo_ioctl)(fp, FIONBIO, (void *)&tmp); 446 break; 447 448 case FIOASYNC: 449 mutex_enter(&fp->f_lock); 450 if ((tmp = *(int *)data32) != 0) 451 fp->f_flag |= FASYNC; 452 else 453 fp->f_flag &= ~FASYNC; 454 mutex_exit(&fp->f_lock); 455 error = (*fp->f_ops->fo_ioctl)(fp, FIOASYNC, (void *)&tmp); 456 break; 457 458 case DIOCGPART32: 459 IOCTL_STRUCT_CONV_TO(DIOCGPART, partinfo); 460 #if 0 /* not implemented by anything */ 461 case DIOCRFORMAT32: 462 IOCTL_STRUCT_CONV_TO(DIOCRFORMAT, format_op); 463 case DIOCWFORMAT32: 464 IOCTL_STRUCT_CONV_TO(DIOCWFORMAT, format_op); 465 #endif 466 467 /* 468 * only a few ifreq syscalls need conversion and those are 469 * all driver specific... XXX 470 */ 471 #if 0 472 case SIOCGADDRROM3232: 473 IOCTL_STRUCT_CONV_TO(SIOCGADDRROM32, ifreq); 474 case SIOCGCHIPID32: 475 IOCTL_STRUCT_CONV_TO(SIOCGCHIPID, ifreq); 476 case SIOCSIFADDR32: 477 IOCTL_STRUCT_CONV_TO(SIOCSIFADDR, ifreq); 478 case OSIOCGIFADDR32: 479 IOCTL_STRUCT_CONV_TO(OSIOCGIFADDR, ifreq); 480 case SIOCGIFADDR32: 481 IOCTL_STRUCT_CONV_TO(SIOCGIFADDR, ifreq); 482 case SIOCSIFDSTADDR32: 483 IOCTL_STRUCT_CONV_TO(SIOCSIFDSTADDR, ifreq); 484 case OSIOCGIFDSTADDR32: 485 IOCTL_STRUCT_CONV_TO(OSIOCGIFDSTADDR, ifreq); 486 case SIOCGIFDSTADDR32: 487 IOCTL_STRUCT_CONV_TO(SIOCGIFDSTADDR, ifreq); 488 case OSIOCGIFBRDADDR32: 489 IOCTL_STRUCT_CONV_TO(OSIOCGIFBRDADDR, ifreq); 490 case SIOCGIFBRDADDR32: 491 IOCTL_STRUCT_CONV_TO(SIOCGIFBRDADDR, ifreq); 492 case SIOCSIFBRDADDR32: 493 IOCTL_STRUCT_CONV_TO(SIOCSIFBRDADDR, ifreq); 494 case OSIOCGIFNETMASK32: 495 IOCTL_STRUCT_CONV_TO(OSIOCGIFNETMASK, ifreq); 496 case SIOCGIFNETMASK32: 497 IOCTL_STRUCT_CONV_TO(SIOCGIFNETMASK, ifreq); 498 case SIOCSIFNETMASK32: 499 IOCTL_STRUCT_CONV_TO(SIOCSIFNETMASK, ifreq); 500 case SIOCGIFMETRIC32: 501 IOCTL_STRUCT_CONV_TO(SIOCGIFMETRIC, ifreq); 502 case SIOCSIFMETRIC32: 503 IOCTL_STRUCT_CONV_TO(SIOCSIFMETRIC, ifreq); 504 case SIOCDIFADDR32: 505 IOCTL_STRUCT_CONV_TO(SIOCDIFADDR, ifreq); 506 case SIOCADDMULTI32: 507 IOCTL_STRUCT_CONV_TO(SIOCADDMULTI, ifreq); 508 case SIOCDELMULTI32: 509 IOCTL_STRUCT_CONV_TO(SIOCDELMULTI, ifreq); 510 case SIOCSIFMEDIA32: 511 IOCTL_STRUCT_CONV_TO(SIOCSIFMEDIA, ifreq); 512 case SIOCSIFMTU32: 513 IOCTL_STRUCT_CONV_TO(SIOCSIFMTU, ifreq); 514 case SIOCGIFMTU32: 515 IOCTL_STRUCT_CONV_TO(SIOCGIFMTU, ifreq); 516 case BIOCGETIF32: 517 IOCTL_STRUCT_CONV_TO(BIOCGETIF, ifreq); 518 case BIOCSETIF32: 519 IOCTL_STRUCT_CONV_TO(BIOCSETIF, ifreq); 520 case SIOCPHASE132: 521 IOCTL_STRUCT_CONV_TO(SIOCPHASE1, ifreq); 522 case SIOCPHASE232: 523 IOCTL_STRUCT_CONV_TO(SIOCPHASE2, ifreq); 524 #endif 525 526 case OOSIOCGIFCONF32: 527 IOCTL_STRUCT_CONV_TO(OOSIOCGIFCONF, ifconf); 528 case OSIOCGIFCONF32: 529 IOCTL_STRUCT_CONV_TO(OSIOCGIFCONF, ifconf); 530 case SIOCGIFCONF32: 531 IOCTL_STRUCT_CONV_TO(SIOCGIFCONF, ifconf); 532 533 case SIOCGIFFLAGS32: 534 IOCTL_STRUCT_CONV_TO(SIOCGIFFLAGS, ifreq); 535 case SIOCSIFFLAGS32: 536 IOCTL_STRUCT_CONV_TO(SIOCSIFFLAGS, ifreq); 537 538 case OSIOCGIFFLAGS32: 539 IOCTL_STRUCT_CONV_TO(OSIOCGIFFLAGS, oifreq); 540 case OSIOCSIFFLAGS32: 541 IOCTL_STRUCT_CONV_TO(OSIOCSIFFLAGS, oifreq); 542 543 case SIOCGIFMEDIA32: 544 IOCTL_STRUCT_CONV_TO(SIOCGIFMEDIA, ifmediareq); 545 546 case SIOCSDRVSPEC32: 547 IOCTL_STRUCT_CONV_TO(SIOCSDRVSPEC, ifdrv); 548 549 case SIOCGETVIFCNT32: 550 IOCTL_STRUCT_CONV_TO(SIOCGETVIFCNT, sioc_vif_req); 551 552 case SIOCGETSGCNT32: 553 IOCTL_STRUCT_CONV_TO(SIOCGETSGCNT, sioc_sg_req); 554 555 default: 556 #ifdef NETBSD32_MD_IOCTL 557 error = netbsd32_md_ioctl(fp, com, data32, l); 558 #else 559 error = (*fp->f_ops->fo_ioctl)(fp, com, data32); 560 #endif 561 break; 562 } 563 564 if (error == EPASSTHROUGH) 565 error = ENOTTY; 566 567 /* 568 * Copy any data to user, size was 569 * already set and checked above. 570 */ 571 if (error == 0 && (com&IOC_OUT) && size32) { 572 error = copyout(data32, SCARG_P32(uap, data), size32); 573 ktrgenio(fd, UIO_READ, SCARG_P32(uap, data), 574 size32, error); 575 } 576 577 /* If we allocated data, free it here. */ 578 if (memp32) 579 kmem_free(memp32, (size_t)size32); 580 if (memp) 581 kmem_free(memp, (size_t)size); 582 out: 583 fd_putfile(fd); 584 return (error); 585 } 586