1 /* $NetBSD: netbsd32_ioctl.c,v 1.46 2009/12/11 11:14:34 njoly 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.46 2009/12/11 11:14:34 njoly 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/malloc.h> 47 #include <sys/sockio.h> 48 #include <sys/socket.h> 49 #include <sys/ttycom.h> 50 #include <sys/mount.h> 51 #include <sys/syscallargs.h> 52 #include <sys/ktrace.h> 53 #include <sys/kmem.h> 54 55 #ifdef __sparc__ 56 #include <dev/sun/fbio.h> 57 #include <machine/openpromio.h> 58 #endif 59 60 #include <net/if.h> 61 #include <net/route.h> 62 63 #include <netinet/in.h> 64 #include <netinet/in_var.h> 65 #include <netinet/igmp.h> 66 #include <netinet/igmp_var.h> 67 #include <netinet/ip_mroute.h> 68 69 #include <compat/sys/sockio.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_oifreq(struct netbsd32_oifreq *, struct oifreq *, 83 u_long cmd); 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_oifreq(struct oifreq *, 106 struct netbsd32_oifreq *, u_long); 107 static inline void netbsd32_from_ifconf(struct ifconf *, 108 struct netbsd32_ifconf *, u_long); 109 static inline void netbsd32_from_ifmediareq(struct ifmediareq *, 110 struct netbsd32_ifmediareq *, 111 u_long); 112 static inline void netbsd32_from_ifdrv(struct ifdrv *, 113 struct netbsd32_ifdrv *, u_long); 114 static inline void netbsd32_from_sioc_vif_req(struct sioc_vif_req *, 115 struct netbsd32_sioc_vif_req *, 116 u_long); 117 static inline void netbsd32_from_sioc_sg_req(struct sioc_sg_req *, 118 struct netbsd32_sioc_sg_req *, 119 u_long); 120 121 /* convert to/from different structures */ 122 123 static inline void 124 netbsd32_to_partinfo(struct netbsd32_partinfo *s32p, struct partinfo *p, u_long cmd) 125 { 126 127 p->disklab = (struct disklabel *)NETBSD32PTR64(s32p->disklab); 128 p->part = (struct partition *)NETBSD32PTR64(s32p->part); 129 } 130 131 #if 0 132 static inline void 133 netbsd32_to_format_op(struct netbsd32_format_op *s32p, struct format_op *p, u_long cmd) 134 { 135 136 p->df_buf = (char *)NETBSD32PTR64(s32p->df_buf); 137 p->df_count = s32p->df_count; 138 p->df_startblk = s32p->df_startblk; 139 memcpy(p->df_reg, s32p->df_reg, sizeof(s32p->df_reg)); 140 } 141 #endif 142 143 static inline void 144 netbsd32_to_ifreq(struct netbsd32_ifreq *s32p, struct ifreq *p, u_long cmd) 145 { 146 147 memcpy(p, s32p, sizeof *s32p); 148 /* 149 * XXX 150 * struct ifreq says the same, but sometimes the ifr_data 151 * union member needs to be converted to 64 bits... this 152 * is very driver specific and so we ignore it for now.. 153 */ 154 if (cmd == SIOCGIFDATA || cmd == SIOCZIFDATA) 155 p->ifr_data = (void *)NETBSD32PTR64(s32p->ifr_data); 156 } 157 158 static inline void 159 netbsd32_to_oifreq(struct netbsd32_oifreq *s32p, struct oifreq *p, u_long cmd) 160 { 161 162 memcpy(p, s32p, sizeof *s32p); 163 /* 164 * XXX 165 * struct ifreq says the same, but sometimes the ifr_data 166 * union member needs to be converted to 64 bits... this 167 * is very driver specific and so we ignore it for now.. 168 */ 169 if (cmd == SIOCGIFDATA || cmd == SIOCZIFDATA) 170 p->ifr_data = (void *)NETBSD32PTR64(s32p->ifr_data); 171 } 172 173 static inline void 174 netbsd32_to_ifconf(struct netbsd32_ifconf *s32p, struct ifconf *p, u_long cmd) 175 { 176 177 p->ifc_len = s32p->ifc_len; 178 /* ifc_buf & ifc_req are the same size so this works */ 179 p->ifc_buf = (void *)NETBSD32PTR64(s32p->ifc_buf); 180 } 181 182 static inline void 183 netbsd32_to_ifmediareq(struct netbsd32_ifmediareq *s32p, struct ifmediareq *p, u_long cmd) 184 { 185 186 memcpy(p, s32p, sizeof *s32p); 187 p->ifm_ulist = (int *)NETBSD32PTR64(s32p->ifm_ulist); 188 } 189 190 static inline void 191 netbsd32_to_ifdrv(struct netbsd32_ifdrv *s32p, struct ifdrv *p, u_long cmd) 192 { 193 194 memcpy(p, s32p, sizeof *s32p); 195 p->ifd_data = (void *)NETBSD32PTR64(s32p->ifd_data); 196 } 197 198 static inline void 199 netbsd32_to_sioc_vif_req(struct netbsd32_sioc_vif_req *s32p, struct sioc_vif_req *p, u_long cmd) 200 { 201 202 p->vifi = s32p->vifi; 203 p->icount = (u_long)s32p->icount; 204 p->ocount = (u_long)s32p->ocount; 205 p->ibytes = (u_long)s32p->ibytes; 206 p->obytes = (u_long)s32p->obytes; 207 } 208 209 static inline void 210 netbsd32_to_sioc_sg_req(struct netbsd32_sioc_sg_req *s32p, struct sioc_sg_req *p, u_long cmd) 211 { 212 213 p->src = s32p->src; 214 p->grp = s32p->grp; 215 p->pktcnt = (u_long)s32p->pktcnt; 216 p->bytecnt = (u_long)s32p->bytecnt; 217 p->wrong_if = (u_long)s32p->wrong_if; 218 } 219 220 /* 221 * handle ioctl conversions from 64-bit kernel -> netbsd32 222 */ 223 224 static inline void 225 netbsd32_from_partinfo(struct partinfo *p, struct netbsd32_partinfo *s32p, u_long cmd) 226 { 227 228 NETBSD32PTR32(s32p->disklab, p->disklab); 229 NETBSD32PTR32(s32p->part, p->part); 230 } 231 232 #if 0 233 static inline void 234 netbsd32_from_format_op(struct format_op *p, struct netbsd32_format_op *s32p, u_long cmd) 235 { 236 237 /* filled in */ 238 #if 0 239 s32p->df_buf = (netbsd32_charp)p->df_buf; 240 #endif 241 s32p->df_count = p->df_count; 242 s32p->df_startblk = p->df_startblk; 243 memcpy(s32p->df_reg, p->df_reg, sizeof(p->df_reg)); 244 } 245 #endif 246 247 static inline void 248 netbsd32_from_ifreq(struct ifreq *p, struct netbsd32_ifreq *s32p, u_long cmd) 249 { 250 251 /* 252 * XXX 253 * struct ifreq says the same, but sometimes the ifr_data 254 * union member needs to be converted to 64 bits... this 255 * is very driver specific and so we ignore it for now.. 256 */ 257 memcpy(s32p, p, sizeof *s32p); 258 if (cmd == SIOCGIFDATA || cmd == SIOCZIFDATA) 259 NETBSD32PTR32(s32p->ifr_data, p->ifr_data); 260 } 261 262 static inline void 263 netbsd32_from_oifreq(struct oifreq *p, struct netbsd32_oifreq *s32p, u_long cmd) 264 { 265 266 /* 267 * XXX 268 * struct ifreq says the same, but sometimes the ifr_data 269 * union member needs to be converted to 64 bits... this 270 * is very driver specific and so we ignore it for now.. 271 */ 272 memcpy(s32p, p, sizeof *s32p); 273 if (cmd == SIOCGIFDATA || cmd == SIOCZIFDATA) 274 NETBSD32PTR32(s32p->ifr_data, p->ifr_data); 275 } 276 277 static inline void 278 netbsd32_from_ifconf(struct ifconf *p, struct netbsd32_ifconf *s32p, u_long cmd) 279 { 280 281 s32p->ifc_len = p->ifc_len; 282 /* ifc_buf & ifc_req are the same size so this works */ 283 NETBSD32PTR32(s32p->ifc_buf, p->ifc_buf); 284 } 285 286 static inline void 287 netbsd32_from_ifmediareq(struct ifmediareq *p, struct netbsd32_ifmediareq *s32p, u_long cmd) 288 { 289 290 memcpy(s32p, p, sizeof *p); 291 /* filled in? */ 292 #if 0 293 s32p->ifm_ulist = (netbsd32_intp_t)p->ifm_ulist; 294 #endif 295 } 296 297 static inline void 298 netbsd32_from_ifdrv(struct ifdrv *p, struct netbsd32_ifdrv *s32p, u_long cmd) 299 { 300 301 memcpy(s32p, p, sizeof *p); 302 /* filled in? */ 303 #if 0 304 s32p->ifm_data = (netbsd32_u_longp_t)p->ifm_data; 305 #endif 306 } 307 308 static inline void 309 netbsd32_from_sioc_vif_req(struct sioc_vif_req *p, struct netbsd32_sioc_vif_req *s32p, u_long cmd) 310 { 311 312 s32p->vifi = p->vifi; 313 s32p->icount = (netbsd32_u_long)p->icount; 314 s32p->ocount = (netbsd32_u_long)p->ocount; 315 s32p->ibytes = (netbsd32_u_long)p->ibytes; 316 s32p->obytes = (netbsd32_u_long)p->obytes; 317 } 318 319 static inline void 320 netbsd32_from_sioc_sg_req(struct sioc_sg_req *p, struct netbsd32_sioc_sg_req *s32p, u_long cmd) 321 { 322 323 s32p->src = p->src; 324 s32p->grp = p->grp; 325 s32p->pktcnt = (netbsd32_u_long)p->pktcnt; 326 s32p->bytecnt = (netbsd32_u_long)p->bytecnt; 327 s32p->wrong_if = (netbsd32_u_long)p->wrong_if; 328 } 329 330 331 /* 332 * main ioctl syscall. 333 * 334 * ok, here we are in the biggy. we have to do fix ups depending 335 * on the ioctl command before and afterwards. 336 */ 337 int 338 netbsd32_ioctl(struct lwp *l, const struct netbsd32_ioctl_args *uap, register_t *retval) 339 { 340 /* { 341 syscallarg(int) fd; 342 syscallarg(netbsd32_u_long) com; 343 syscallarg(netbsd32_voidp) data; 344 } */ 345 struct proc *p = l->l_proc; 346 struct file *fp; 347 struct filedesc *fdp; 348 u_long com; 349 int error = 0; 350 u_int size, size32; 351 void *data, *memp = NULL; 352 void *data32, *memp32 = NULL; 353 unsigned fd; 354 fdfile_t *ff; 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 fd = SCARG(uap, fd); 379 if ((fp = fd_getfile(fd)) == NULL) 380 return (EBADF); 381 if ((fp->f_flag & (FREAD | FWRITE)) == 0) { 382 error = EBADF; 383 goto out; 384 } 385 386 ff = fdp->fd_dt->dt_ff[SCARG(uap, fd)]; 387 switch (com = SCARG(uap, com)) { 388 case FIOCLEX: 389 ff->ff_exclose = true; 390 fdp->fd_exclose = true; 391 goto out; 392 393 case FIONCLEX: 394 ff->ff_exclose = false; 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 size = 0; 403 size32 = IOCPARM_LEN(com); 404 if (size32 > IOCPARM_MAX) { 405 error = ENOTTY; 406 goto out; 407 } 408 if (size32 > sizeof(stkbuf)) { 409 memp32 = kmem_alloc((size_t)size32, KM_SLEEP); 410 data32 = memp32; 411 } else 412 data32 = (void *)stkbuf32; 413 if (com&IOC_IN) { 414 if (size32) { 415 error = copyin(SCARG_P32(uap, data), data32, size32); 416 if (error) { 417 if (memp32) 418 kmem_free(memp32, (size_t)size32); 419 goto out; 420 } 421 ktrgenio(fd, UIO_WRITE, SCARG_P32(uap, data), 422 size32, 0); 423 } else 424 *(void **)data32 = SCARG_P32(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 *(void **)data32 = SCARG_P32(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 mutex_enter(&fp->f_lock); 441 if ((tmp = *(int *)data32) != 0) 442 fp->f_flag |= FNONBLOCK; 443 else 444 fp->f_flag &= ~FNONBLOCK; 445 mutex_exit(&fp->f_lock); 446 error = (*fp->f_ops->fo_ioctl)(fp, FIONBIO, (void *)&tmp); 447 break; 448 449 case FIOASYNC: 450 mutex_enter(&fp->f_lock); 451 if ((tmp = *(int *)data32) != 0) 452 fp->f_flag |= FASYNC; 453 else 454 fp->f_flag &= ~FASYNC; 455 mutex_exit(&fp->f_lock); 456 error = (*fp->f_ops->fo_ioctl)(fp, FIOASYNC, (void *)&tmp); 457 break; 458 459 case DIOCGPART32: 460 IOCTL_STRUCT_CONV_TO(DIOCGPART, partinfo); 461 #if 0 /* not implemented by anything */ 462 case DIOCRFORMAT32: 463 IOCTL_STRUCT_CONV_TO(DIOCRFORMAT, format_op); 464 case DIOCWFORMAT32: 465 IOCTL_STRUCT_CONV_TO(DIOCWFORMAT, format_op); 466 #endif 467 468 /* 469 * only a few ifreq syscalls need conversion and those are 470 * all driver specific... XXX 471 */ 472 #if 0 473 case SIOCGADDRROM3232: 474 IOCTL_STRUCT_CONV_TO(SIOCGADDRROM32, ifreq); 475 case SIOCGCHIPID32: 476 IOCTL_STRUCT_CONV_TO(SIOCGCHIPID, ifreq); 477 case SIOCSIFADDR32: 478 IOCTL_STRUCT_CONV_TO(SIOCSIFADDR, ifreq); 479 case OSIOCGIFADDR32: 480 IOCTL_STRUCT_CONV_TO(OSIOCGIFADDR, ifreq); 481 case SIOCGIFADDR32: 482 IOCTL_STRUCT_CONV_TO(SIOCGIFADDR, ifreq); 483 case SIOCSIFDSTADDR32: 484 IOCTL_STRUCT_CONV_TO(SIOCSIFDSTADDR, ifreq); 485 case OSIOCGIFDSTADDR32: 486 IOCTL_STRUCT_CONV_TO(OSIOCGIFDSTADDR, ifreq); 487 case SIOCGIFDSTADDR32: 488 IOCTL_STRUCT_CONV_TO(SIOCGIFDSTADDR, ifreq); 489 case OSIOCGIFBRDADDR32: 490 IOCTL_STRUCT_CONV_TO(OSIOCGIFBRDADDR, ifreq); 491 case SIOCGIFBRDADDR32: 492 IOCTL_STRUCT_CONV_TO(SIOCGIFBRDADDR, ifreq); 493 case SIOCSIFBRDADDR32: 494 IOCTL_STRUCT_CONV_TO(SIOCSIFBRDADDR, ifreq); 495 case OSIOCGIFNETMASK32: 496 IOCTL_STRUCT_CONV_TO(OSIOCGIFNETMASK, ifreq); 497 case SIOCGIFNETMASK32: 498 IOCTL_STRUCT_CONV_TO(SIOCGIFNETMASK, ifreq); 499 case SIOCSIFNETMASK32: 500 IOCTL_STRUCT_CONV_TO(SIOCSIFNETMASK, ifreq); 501 case SIOCGIFMETRIC32: 502 IOCTL_STRUCT_CONV_TO(SIOCGIFMETRIC, ifreq); 503 case SIOCSIFMETRIC32: 504 IOCTL_STRUCT_CONV_TO(SIOCSIFMETRIC, ifreq); 505 case SIOCDIFADDR32: 506 IOCTL_STRUCT_CONV_TO(SIOCDIFADDR, ifreq); 507 case SIOCADDMULTI32: 508 IOCTL_STRUCT_CONV_TO(SIOCADDMULTI, ifreq); 509 case SIOCDELMULTI32: 510 IOCTL_STRUCT_CONV_TO(SIOCDELMULTI, ifreq); 511 case SIOCSIFMEDIA32: 512 IOCTL_STRUCT_CONV_TO(SIOCSIFMEDIA, ifreq); 513 case SIOCSIFMTU32: 514 IOCTL_STRUCT_CONV_TO(SIOCSIFMTU, ifreq); 515 case SIOCGIFMTU32: 516 IOCTL_STRUCT_CONV_TO(SIOCGIFMTU, ifreq); 517 case BIOCGETIF32: 518 IOCTL_STRUCT_CONV_TO(BIOCGETIF, ifreq); 519 case BIOCSETIF32: 520 IOCTL_STRUCT_CONV_TO(BIOCSETIF, ifreq); 521 case SIOCPHASE132: 522 IOCTL_STRUCT_CONV_TO(SIOCPHASE1, ifreq); 523 case SIOCPHASE232: 524 IOCTL_STRUCT_CONV_TO(SIOCPHASE2, ifreq); 525 #endif 526 527 case OOSIOCGIFCONF32: 528 IOCTL_STRUCT_CONV_TO(OOSIOCGIFCONF, ifconf); 529 case OSIOCGIFCONF32: 530 IOCTL_STRUCT_CONV_TO(OSIOCGIFCONF, ifconf); 531 case SIOCGIFCONF32: 532 IOCTL_STRUCT_CONV_TO(SIOCGIFCONF, ifconf); 533 534 case SIOCGIFFLAGS32: 535 IOCTL_STRUCT_CONV_TO(SIOCGIFFLAGS, ifreq); 536 case SIOCSIFFLAGS32: 537 IOCTL_STRUCT_CONV_TO(SIOCSIFFLAGS, ifreq); 538 539 case OSIOCGIFFLAGS32: 540 IOCTL_STRUCT_CONV_TO(OSIOCGIFFLAGS, oifreq); 541 case OSIOCSIFFLAGS32: 542 IOCTL_STRUCT_CONV_TO(OSIOCSIFFLAGS, oifreq); 543 544 case SIOCGIFMEDIA32: 545 IOCTL_STRUCT_CONV_TO(SIOCGIFMEDIA, ifmediareq); 546 547 case SIOCSDRVSPEC32: 548 IOCTL_STRUCT_CONV_TO(SIOCSDRVSPEC, ifdrv); 549 550 case SIOCGETVIFCNT32: 551 IOCTL_STRUCT_CONV_TO(SIOCGETVIFCNT, sioc_vif_req); 552 553 case SIOCGETSGCNT32: 554 IOCTL_STRUCT_CONV_TO(SIOCGETSGCNT, sioc_sg_req); 555 556 default: 557 #ifdef NETBSD32_MD_IOCTL 558 error = netbsd32_md_ioctl(fp, com, data32, l); 559 #else 560 error = (*fp->f_ops->fo_ioctl)(fp, com, data32); 561 #endif 562 break; 563 } 564 565 if (error == EPASSTHROUGH) 566 error = ENOTTY; 567 568 /* 569 * Copy any data to user, size was 570 * already set and checked above. 571 */ 572 if (error == 0 && (com&IOC_OUT) && size32) { 573 error = copyout(data32, SCARG_P32(uap, data), size32); 574 ktrgenio(fd, UIO_READ, SCARG_P32(uap, data), 575 size32, error); 576 } 577 578 /* if we malloced data, free it here */ 579 if (memp32) 580 kmem_free(memp32, (size_t)size32); 581 if (memp) 582 kmem_free(memp, (size_t)size); 583 out: 584 fd_putfile(fd); 585 return (error); 586 } 587