1 /* $NetBSD: netbsd32_ioctl.c,v 1.45 2009/12/10 15:47:23 njoly Exp $ */
4 * Copyright (c) 1998, 2001 Matthew R. Green
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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.
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
30 * handle ioctl conversions from netbsd32 -> 64-bit kernel
33 #include <sys/cdefs.h>
34 __KERNEL_RCSID(0, "$NetBSD: netbsd32_ioctl.c,v 1.45 2009/12/10 15:47:23 njoly Exp $");
36 #include <sys/param.h>
37 #include <sys/systm.h>
38 #include <sys/filedesc.h>
39 #include <sys/ioctl.h>
42 #include <sys/socketvar.h>
43 #include <sys/audioio.h>
44 #include <sys/disklabel.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>
56 #include <dev/sun/fbio.h>
57 #include <machine/openpromio.h>
61 #include <net/route.h>
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>
69 #include <compat/sys/sockio.h>
71 #include <compat/netbsd32/netbsd32.h>
72 #include <compat/netbsd32/netbsd32_ioctl.h>
73 #include <compat/netbsd32/netbsd32_syscallargs.h>
75 /* prototypes for the converters */
76 static inline void netbsd32_to_partinfo(struct netbsd32_partinfo
*,
77 struct partinfo
*, u_long
);
79 static inline void netbsd32_to_format_op(struct netbsd32_format_op
*,
80 struct format_op
*, u_long
);
82 static inline void netbsd32_to_oifreq(struct netbsd32_oifreq
*, struct oifreq
*,
84 static inline void netbsd32_to_ifreq(struct netbsd32_ifreq
*, struct ifreq
*,
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
*,
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
);
99 static inline void netbsd32_from_format_op(struct format_op
*,
100 struct netbsd32_format_op
*,
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
*,
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
*,
117 static inline void netbsd32_from_sioc_sg_req(struct sioc_sg_req
*,
118 struct netbsd32_sioc_sg_req
*,
121 /* convert to/from different structures */
124 netbsd32_to_partinfo(struct netbsd32_partinfo
*s32p
, struct partinfo
*p
, u_long cmd
)
127 p
->disklab
= (struct disklabel
*)NETBSD32PTR64(s32p
->disklab
);
128 p
->part
= (struct partition
*)NETBSD32PTR64(s32p
->part
);
133 netbsd32_to_format_op(struct netbsd32_format_op
*s32p
, struct format_op
*p
, u_long cmd
)
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
));
144 netbsd32_to_ifreq(struct netbsd32_ifreq
*s32p
, struct ifreq
*p
, u_long cmd
)
147 memcpy(p
, s32p
, sizeof *s32p
);
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..
154 if (cmd
== SIOCGIFDATA
|| cmd
== SIOCZIFDATA
)
155 p
->ifr_data
= (void *)NETBSD32PTR64(s32p
->ifr_data
);
159 netbsd32_to_oifreq(struct netbsd32_oifreq
*s32p
, struct oifreq
*p
, u_long cmd
)
162 memcpy(p
, s32p
, sizeof *s32p
);
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..
169 if (cmd
== SIOCGIFDATA
|| cmd
== SIOCZIFDATA
)
170 p
->ifr_data
= (void *)NETBSD32PTR64(s32p
->ifr_data
);
174 netbsd32_to_ifconf(struct netbsd32_ifconf
*s32p
, struct ifconf
*p
, u_long cmd
)
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
);
183 netbsd32_to_ifmediareq(struct netbsd32_ifmediareq
*s32p
, struct ifmediareq
*p
, u_long cmd
)
186 memcpy(p
, s32p
, sizeof *s32p
);
187 p
->ifm_ulist
= (int *)NETBSD32PTR64(s32p
->ifm_ulist
);
191 netbsd32_to_ifdrv(struct netbsd32_ifdrv
*s32p
, struct ifdrv
*p
, u_long cmd
)
194 memcpy(p
, s32p
, sizeof *s32p
);
195 p
->ifd_data
= (void *)NETBSD32PTR64(s32p
->ifd_data
);
199 netbsd32_to_sioc_vif_req(struct netbsd32_sioc_vif_req
*s32p
, struct sioc_vif_req
*p
, u_long cmd
)
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
;
210 netbsd32_to_sioc_sg_req(struct netbsd32_sioc_sg_req
*s32p
, struct sioc_sg_req
*p
, u_long cmd
)
215 p
->pktcnt
= (u_long
)s32p
->pktcnt
;
216 p
->bytecnt
= (u_long
)s32p
->bytecnt
;
217 p
->wrong_if
= (u_long
)s32p
->wrong_if
;
221 * handle ioctl conversions from 64-bit kernel -> netbsd32
225 netbsd32_from_partinfo(struct partinfo
*p
, struct netbsd32_partinfo
*s32p
, u_long cmd
)
228 NETBSD32PTR32(s32p
->disklab
, p
->disklab
);
229 NETBSD32PTR32(s32p
->part
, p
->part
);
234 netbsd32_from_format_op(struct format_op
*p
, struct netbsd32_format_op
*s32p
, u_long cmd
)
239 s32p
->df_buf
= (netbsd32_charp
)p
->df_buf
;
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
));
248 netbsd32_from_ifreq(struct ifreq
*p
, struct netbsd32_ifreq
*s32p
, u_long cmd
)
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..
257 memcpy(s32p
, p
, sizeof *s32p
);
258 if (cmd
== SIOCGIFDATA
|| cmd
== SIOCZIFDATA
)
259 NETBSD32PTR32(s32p
->ifr_data
, p
->ifr_data
);
263 netbsd32_from_oifreq(struct oifreq
*p
, struct netbsd32_oifreq
*s32p
, u_long cmd
)
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..
272 memcpy(s32p
, p
, sizeof *s32p
);
273 if (cmd
== SIOCGIFDATA
|| cmd
== SIOCZIFDATA
)
274 NETBSD32PTR32(s32p
->ifr_data
, p
->ifr_data
);
278 netbsd32_from_ifconf(struct ifconf
*p
, struct netbsd32_ifconf
*s32p
, u_long cmd
)
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
);
287 netbsd32_from_ifmediareq(struct ifmediareq
*p
, struct netbsd32_ifmediareq
*s32p
, u_long cmd
)
290 memcpy(s32p
, p
, sizeof *p
);
293 s32p
->ifm_ulist
= (netbsd32_intp_t
)p
->ifm_ulist
;
298 netbsd32_from_ifdrv(struct ifdrv
*p
, struct netbsd32_ifdrv
*s32p
, u_long cmd
)
301 memcpy(s32p
, p
, sizeof *p
);
304 s32p
->ifm_data
= (netbsd32_u_longp_t
)p
->ifm_data
;
309 netbsd32_from_sioc_vif_req(struct sioc_vif_req
*p
, struct netbsd32_sioc_vif_req
*s32p
, u_long cmd
)
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
;
320 netbsd32_from_sioc_sg_req(struct sioc_sg_req
*p
, struct netbsd32_sioc_sg_req
*s32p
, u_long cmd
)
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
;
332 * main ioctl syscall.
334 * ok, here we are in the biggy. we have to do fix ups depending
335 * on the ioctl command before and afterwards.
338 netbsd32_ioctl(struct lwp
*l
, const struct netbsd32_ioctl_args
*uap
, register_t
*retval
)
342 syscallarg(netbsd32_u_long) com;
343 syscallarg(netbsd32_voidp) data;
345 struct proc
*p
= l
->l_proc
;
347 struct filedesc
*fdp
;
351 void *data
, *memp
= NULL
;
352 void *data32
, *memp32
= NULL
;
356 #define STK_PARAMS 128
357 u_long stkbuf
[STK_PARAMS
/sizeof(u_long
)];
358 u_long stkbuf32
[STK_PARAMS
/sizeof(u_long
)];
361 * we need to translate some commands (_IOW) before calling sys_ioctl,
362 * some after (_IOR), and some both (_IOWR).
366 char *dirs
[8] = { "NONE!", "VOID", "OUT", "VOID|OUT!", "IN", "VOID|IN!",
367 "INOUT", "VOID|IN|OUT!" };
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
)));
379 if ((fp
= fd_getfile(fd
)) == NULL
)
381 if ((fp
->f_flag
& (FREAD
| FWRITE
)) == 0) {
386 ff
= fdp
->fd_dt
->dt_ff
[SCARG(uap
, fd
)];
387 switch (com
= SCARG(uap
, com
)) {
389 ff
->ff_exclose
= true;
390 fdp
->fd_exclose
= true;
394 ff
->ff_exclose
= false;
399 * Interpret high order word to find amount of data to be
400 * copied to/from the user's address space.
403 size32
= IOCPARM_LEN(com
);
404 if (size32
> IOCPARM_MAX
) {
408 if (size32
> sizeof(stkbuf
)) {
409 memp32
= kmem_alloc((size_t)size32
, KM_SLEEP
);
412 data32
= (void *)stkbuf32
;
415 error
= copyin(SCARG_P32(uap
, data
), data32
, size32
);
418 kmem_free(memp32
, (size_t)size32
);
421 ktrgenio(fd
, UIO_WRITE
, SCARG_P32(uap
, data
),
424 *(void **)data32
= SCARG_P32(uap
, data
);
425 } else if ((com
&IOC_OUT
) && size32
)
427 * Zero the buffer so the user always
428 * gets back something deterministic.
430 memset(data32
, 0, size32
);
431 else if (com
&IOC_VOID
)
432 *(void **)data32
= SCARG_P32(uap
, data
);
435 * convert various structures, pointers, and other objects that
436 * change size from 32 bit -> 64 bit, for all ioctl commands.
438 switch (SCARG(uap
, com
)) {
440 mutex_enter(&fp
->f_lock
);
441 if ((tmp
= *(int *)data32
) != 0)
442 fp
->f_flag
|= FNONBLOCK
;
444 fp
->f_flag
&= ~FNONBLOCK
;
445 mutex_exit(&fp
->f_lock
);
446 error
= (*fp
->f_ops
->fo_ioctl
)(fp
, FIONBIO
, (void *)&tmp
);
450 mutex_enter(&fp
->f_lock
);
451 if ((tmp
= *(int *)data32
) != 0)
452 fp
->f_flag
|= FASYNC
;
454 fp
->f_flag
&= ~FASYNC
;
455 mutex_exit(&fp
->f_lock
);
456 error
= (*fp
->f_ops
->fo_ioctl
)(fp
, FIOASYNC
, (void *)&tmp
);
460 IOCTL_STRUCT_CONV_TO(DIOCGPART
, partinfo
);
461 #if 0 /* not implemented by anything */
463 IOCTL_STRUCT_CONV_TO(DIOCRFORMAT
, format_op
);
465 IOCTL_STRUCT_CONV_TO(DIOCWFORMAT
, format_op
);
469 * only a few ifreq syscalls need conversion and those are
470 * all driver specific... XXX
473 case SIOCGADDRROM3232
:
474 IOCTL_STRUCT_CONV_TO(SIOCGADDRROM32
, ifreq
);
476 IOCTL_STRUCT_CONV_TO(SIOCGCHIPID
, ifreq
);
478 IOCTL_STRUCT_CONV_TO(SIOCSIFADDR
, ifreq
);
480 IOCTL_STRUCT_CONV_TO(OSIOCGIFADDR
, ifreq
);
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
);
506 IOCTL_STRUCT_CONV_TO(SIOCDIFADDR
, ifreq
);
508 IOCTL_STRUCT_CONV_TO(SIOCADDMULTI
, ifreq
);
510 IOCTL_STRUCT_CONV_TO(SIOCDELMULTI
, ifreq
);
512 IOCTL_STRUCT_CONV_TO(SIOCSIFMEDIA
, ifreq
);
514 IOCTL_STRUCT_CONV_TO(SIOCSIFMTU
, ifreq
);
516 IOCTL_STRUCT_CONV_TO(SIOCGIFMTU
, ifreq
);
518 IOCTL_STRUCT_CONV_TO(BIOCGETIF
, ifreq
);
520 IOCTL_STRUCT_CONV_TO(BIOCSETIF
, ifreq
);
522 IOCTL_STRUCT_CONV_TO(SIOCPHASE1
, ifreq
);
524 IOCTL_STRUCT_CONV_TO(SIOCPHASE2
, ifreq
);
527 case OOSIOCGIFCONF32
:
528 IOCTL_STRUCT_CONV_TO(OOSIOCGIFCONF
, ifconf
);
530 IOCTL_STRUCT_CONV_TO(OSIOCGIFCONF
, ifconf
);
532 IOCTL_STRUCT_CONV_TO(SIOCGIFCONF
, ifconf
);
535 IOCTL_STRUCT_CONV_TO(SIOCGIFFLAGS
, ifreq
);
537 IOCTL_STRUCT_CONV_TO(SIOCSIFFLAGS
, ifreq
);
539 case OSIOCGIFFLAGS32
:
540 IOCTL_STRUCT_CONV_TO(OSIOCGIFFLAGS
, oifreq
);
541 case OSIOCSIFFLAGS32
:
542 IOCTL_STRUCT_CONV_TO(OSIOCSIFFLAGS
, oifreq
);
545 IOCTL_STRUCT_CONV_TO(SIOCGIFMEDIA
, ifmediareq
);
548 IOCTL_STRUCT_CONV_TO(SIOCSDRVSPEC
, ifdrv
);
550 case SIOCGETVIFCNT32
:
551 IOCTL_STRUCT_CONV_TO(SIOCGETVIFCNT
, sioc_vif_req
);
554 IOCTL_STRUCT_CONV_TO(SIOCGETSGCNT
, sioc_sg_req
);
557 #ifdef NETBSD32_MD_IOCTL
558 error
= netbsd32_md_ioctl(fp
, com
, data32
, l
);
560 error
= (*fp
->f_ops
->fo_ioctl
)(fp
, com
, data32
);
565 if (error
== EPASSTHROUGH
)
569 * Copy any data to user, size was
570 * already set and checked above.
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
),
578 /* if we malloced data, free it here */
580 kmem_free(memp32
, (size_t)size32
);
582 kmem_free(memp
, (size_t)size
);