netbsd32_ioctl.c revision 1.46.4.1 1 /* $NetBSD: netbsd32_ioctl.c,v 1.46.4.1 2010/05/30 05:17:15 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.46.4.1 2010/05/30 05:17:15 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