/*
* Copyright (c) 1998, 2001 Matthew R. Green
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
memcpy(p, s32p, sizeof *s32p);
/*
* XXX
* struct ifreq says the same, but sometimes the ifr_data
* union member needs to be converted to 64 bits... this
* is very driver specific and so we ignore it for now..
*/
switch (cmd) {
case SIOCGIFDATA:
case SIOCZIFDATA:
case SIOCGIFGENERIC:
case SIOCSIFGENERIC:
p->ifr_data = (void *)NETBSD32PTR64(s32p->ifr_data);
break;
}
}
memcpy(p, s32p, sizeof *s32p);
/*
* XXX
* struct ifreq says the same, but sometimes the ifr_data
* union member needs to be converted to 64 bits... this
* is very driver specific and so we ignore it for now..
*/
if (cmd == SIOCGIFDATA || cmd == SIOCZIFDATA)
p->ifr_data = (void *)NETBSD32PTR64(s32p->ifr_data);
}
/*
* XXX
* struct ifreq says the same, but sometimes the ifr_data
* union member needs to be converted to 64 bits... this
* is very driver specific and so we ignore it for now..
*/
memcpy(s32p, p, sizeof *s32p);
switch (cmd) {
case SIOCGIFDATA:
case SIOCZIFDATA:
case SIOCGIFGENERIC:
case SIOCSIFGENERIC:
NETBSD32PTR32(s32p->ifr_data, p->ifr_data);
break;
}
}
/*
* XXX
* struct ifreq says the same, but sometimes the ifr_data
* union member needs to be converted to 64 bits... this
* is very driver specific and so we ignore it for now..
*/
memcpy(s32p, p, sizeof *s32p);
if (cmd == SIOCGIFDATA || cmd == SIOCZIFDATA)
NETBSD32PTR32(s32p->ifr_data, p->ifr_data);
}
/*
* main ioctl syscall.
*
* ok, here we are in the biggy. we have to do fix ups depending
* on the ioctl command before and afterwards.
*/
int
netbsd32_ioctl(struct lwp *l,
const struct netbsd32_ioctl_args *uap, register_t *retval)
{
/* {
syscallarg(int) fd;
syscallarg(netbsd32_u_long) com;
syscallarg(netbsd32_voidp) data;
} */
struct file *fp;
u_long com;
int error = 0;
size_t size;
size_t alloc_size32, size32;
void *data, *memp = NULL;
void *data32, *memp32 = NULL;
unsigned int fd;
int tmp;
#define STK_PARAMS 128
uint64_t stkbuf[STK_PARAMS/sizeof(uint64_t)];
uint64_t stkbuf32[STK_PARAMS/sizeof(uint64_t)];
/*
* we need to translate some commands (_IOW) before calling sys_ioctl,
* some after (_IOR), and some both (_IOWR).
*/
#if 0
{
const char * const dirs[8] = {
"NONE!", "VOID", "OUT", "VOID|OUT!", "IN", "VOID|IN!",
"INOUT", "VOID|IN|OUT!"
};
printf("netbsd32_ioctl(%d, %x, %x): "
"%s group %c base %d len %d\n",
SCARG(uap, fd), SCARG(uap, com), SCARG(uap, data).i32,
dirs[((SCARG(uap, com) & IOC_DIRMASK)>>29)],
IOCGROUP(SCARG(uap, com)), IOCBASECMD(SCARG(uap, com)),
IOCPARM_LEN(SCARG(uap, com)));
}
#endif
switch (com = SCARG(uap, com)) {
case FIONCLEX:
case FIOCLEX:
fd_set_exclose(l, fd, com == FIOCLEX);
goto out;
}
/*
* Interpret high order word to find amount of data to be
* copied to/from the user's address space.
*/
size32 = IOCPARM_LEN(com);
alloc_size32 = size32;
/*
* The disklabel is now padded to a multiple of 8 bytes however the old
* disklabel on 32bit platforms wasn't. This leaves a difference in
* size of 4 bytes between the two but are otherwise identical.
* To deal with this, we allocate enough space for the new disklabel
* but only copyin/out the smaller amount.
*/
if (IOCGROUP(com) == 'd') {
u_long ncom = com ^ (DIOCGDINFO ^ DIOCGDINFO32);
switch (ncom) {
case DIOCGDINFO:
case DIOCWDINFO:
case DIOCSDINFO:
case DIOCGDEFLABEL:
com = ncom;
if (IOCPARM_LEN(DIOCGDINFO32) < IOCPARM_LEN(DIOCGDINFO))
alloc_size32 = IOCPARM_LEN(DIOCGDINFO);
break;
}
}
if (alloc_size32 > IOCPARM_MAX) {
error = ENOTTY;
goto out;
}
if (alloc_size32 > sizeof(stkbuf)) {
memp32 = kmem_alloc(alloc_size32, KM_SLEEP);
data32 = memp32;
} else
data32 = (void *)stkbuf32;
if ((com >> IOCPARM_SHIFT) == 0) {
/* UNIX-style ioctl. */
data32 = SCARG_P32(uap, data);
} else {
if (com&IOC_IN) {
if (size32) {
error = copyin(SCARG_P32(uap, data), data32,
size32);
if (error) {
goto out;
}
/*
* The data between size and alloc_size has
* not been overwritten. It shouldn't matter
* but let's clear that anyway.
*/
if (__predict_false(size32 < alloc_size32)) {
memset((char *)data32+size32, 0,
alloc_size32 - size32);
}
ktrgenio(fd, UIO_WRITE, SCARG_P32(uap, data),
size32, 0);
} else
*(void **)data32 = SCARG_P32(uap, data);
} else if ((com&IOC_OUT) && size32) {
/*
* Zero the buffer so the user always
* gets back something deterministic.
*/
memset(data32, 0, alloc_size32);
} else if (com&IOC_VOID) {
*(void **)data32 = SCARG_P32(uap, data);
}
}
/*
* convert various structures, pointers, and other objects that
* change size from 32 bit -> 64 bit, for all ioctl commands.
*/
switch (SCARG(uap, com)) {
case FIONBIO:
mutex_enter(&fp->f_lock);
if ((tmp = *(int *)data32) != 0)
fp->f_flag |= FNONBLOCK;
else
fp->f_flag &= ~FNONBLOCK;
mutex_exit(&fp->f_lock);
error = (*fp->f_ops->fo_ioctl)(fp, FIONBIO, (void *)&tmp);
break;
case AUDIO_WSEEK32:
IOCTL_CONV_TO(AUDIO_WSEEK, u_long);
#if 0 /* not implemented by anything */
case DIOCRFORMAT32:
IOCTL_STRUCT_CONV_TO(DIOCRFORMAT, format_op);
case DIOCWFORMAT32:
IOCTL_STRUCT_CONV_TO(DIOCWFORMAT, format_op);
#endif
case KFILTER_BYFILTER32:
IOCTL_STRUCT_CONV_TO(KFILTER_BYFILTER, kfilter_mapping);
case KFILTER_BYNAME32:
IOCTL_STRUCT_CONV_TO(KFILTER_BYNAME, kfilter_mapping);
case ATAIOCCOMMAND32:
IOCTL_STRUCT_CONV_TO(ATAIOCCOMMAND, atareq);
/*
* only a few ifreq syscalls need conversion and those are
* all driver specific... XXX
*/
#if 0
case SIOCGADDRROM3232:
IOCTL_STRUCT_CONV_TO(SIOCGADDRROM32, ifreq);
case SIOCGCHIPID32:
IOCTL_STRUCT_CONV_TO(SIOCGCHIPID, ifreq);
case SIOCSIFADDR32:
IOCTL_STRUCT_CONV_TO(SIOCSIFADDR, ifreq);
case OSIOCGIFADDR32:
IOCTL_STRUCT_CONV_TO(OSIOCGIFADDR, ifreq);
case SIOCGIFADDR32:
IOCTL_STRUCT_CONV_TO(SIOCGIFADDR, ifreq);
case SIOCSIFDSTADDR32:
IOCTL_STRUCT_CONV_TO(SIOCSIFDSTADDR, ifreq);
case OSIOCGIFDSTADDR32:
IOCTL_STRUCT_CONV_TO(OSIOCGIFDSTADDR, ifreq);
case SIOCGIFDSTADDR32:
IOCTL_STRUCT_CONV_TO(SIOCGIFDSTADDR, ifreq);
case OSIOCGIFBRDADDR32:
IOCTL_STRUCT_CONV_TO(OSIOCGIFBRDADDR, ifreq);
case SIOCGIFBRDADDR32:
IOCTL_STRUCT_CONV_TO(SIOCGIFBRDADDR, ifreq);
case SIOCSIFBRDADDR32:
IOCTL_STRUCT_CONV_TO(SIOCSIFBRDADDR, ifreq);
case OSIOCGIFNETMASK32:
IOCTL_STRUCT_CONV_TO(OSIOCGIFNETMASK, ifreq);
case SIOCGIFNETMASK32:
IOCTL_STRUCT_CONV_TO(SIOCGIFNETMASK, ifreq);
case SIOCSIFNETMASK32:
IOCTL_STRUCT_CONV_TO(SIOCSIFNETMASK, ifreq);
case SIOCGIFMETRIC32:
IOCTL_STRUCT_CONV_TO(SIOCGIFMETRIC, ifreq);
case SIOCSIFMETRIC32:
IOCTL_STRUCT_CONV_TO(SIOCSIFMETRIC, ifreq);
case SIOCDIFADDR32:
IOCTL_STRUCT_CONV_TO(SIOCDIFADDR, ifreq);
case SIOCADDMULTI32:
IOCTL_STRUCT_CONV_TO(SIOCADDMULTI, ifreq);
case SIOCDELMULTI32:
IOCTL_STRUCT_CONV_TO(SIOCDELMULTI, ifreq);
case SIOCSIFMEDIA32:
IOCTL_STRUCT_CONV_TO(SIOCSIFMEDIA, ifreq);
case SIOCSIFMTU32:
IOCTL_STRUCT_CONV_TO(SIOCSIFMTU, ifreq);
case SIOCGIFMTU32:
IOCTL_STRUCT_CONV_TO(SIOCGIFMTU, ifreq);
case BIOCGETIF32:
IOCTL_STRUCT_CONV_TO(BIOCGETIF, ifreq);
case BIOCSETIF32:
IOCTL_STRUCT_CONV_TO(BIOCSETIF, ifreq);
case SIOCPHASE132:
IOCTL_STRUCT_CONV_TO(SIOCPHASE1, ifreq);
case SIOCPHASE232:
IOCTL_STRUCT_CONV_TO(SIOCPHASE2, ifreq);
#endif
case OOSIOCGIFCONF32:
IOCTL_STRUCT_CONV_TO(OOSIOCGIFCONF, ifconf);
case OSIOCGIFCONF32:
IOCTL_STRUCT_CONV_TO(OSIOCGIFCONF, ifconf);
case SIOCGIFCONF32:
IOCTL_STRUCT_CONV_TO(SIOCGIFCONF, ifconf);
case SIOCGIFFLAGS32:
IOCTL_STRUCT_CONV_TO(SIOCGIFFLAGS, ifreq);
case SIOCSIFFLAGS32:
IOCTL_STRUCT_CONV_TO(SIOCSIFFLAGS, ifreq);
case SIOCGIFADDRPREF32:
IOCTL_STRUCT_CONV_TO(SIOCGIFADDRPREF, if_addrprefreq);
case SIOCSIFADDRPREF32:
IOCTL_STRUCT_CONV_TO(SIOCSIFADDRPREF, if_addrprefreq);
case SIOCGIFDATA32:
IOCTL_STRUCT_CONV_TO(SIOCGIFDATA, ifdatareq);
case SIOCZIFDATA32:
IOCTL_STRUCT_CONV_TO(SIOCZIFDATA, ifdatareq);
case OSIOCGIFFLAGS32:
IOCTL_STRUCT_CONV_TO(OSIOCGIFFLAGS, oifreq);
case OSIOCSIFFLAGS32:
IOCTL_STRUCT_CONV_TO(OSIOCSIFFLAGS, oifreq);
case SIOCGIFMEDIA32_80:
IOCTL_STRUCT_CONV_TO(SIOCGIFMEDIA_80, ifmediareq);
case SIOCGIFMEDIA32:
IOCTL_STRUCT_CONV_TO(SIOCGIFMEDIA, ifmediareq);
case SIOCGNBRINFO32:
IOCTL_STRUCT_CONV_TO(SIOCGNBRINFO, in_nbrinfo);
case SIOCGNBRINFO_IN632:
IOCTL_STRUCT_CONV_TO(SIOCGNBRINFO_IN6, in6_nbrinfo);
case SIOCGIFGENERIC32:
IOCTL_STRUCT_CONV_TO(SIOCGIFGENERIC, ifreq);
case SIOCSIFGENERIC32:
IOCTL_STRUCT_CONV_TO(SIOCSIFGENERIC, ifreq);
case PPPOESETPARMS32:
IOCTL_STRUCT_CONV_TO(PPPOESETPARMS, pppoediscparms);
case PPPOEGETPARMS32:
IOCTL_STRUCT_CONV_TO(PPPOEGETPARMS, pppoediscparms);
case SPPPGETAUTHCFG32:
IOCTL_STRUCT_CONV_TO(SPPPGETAUTHCFG, spppauthcfg);
case SPPPSETAUTHCFG32:
IOCTL_STRUCT_CONV_TO(SPPPSETAUTHCFG, spppauthcfg);
case SIOCSDRVSPEC32:
IOCTL_STRUCT_CONV_TO(SIOCSDRVSPEC, ifdrv);
case SIOCGDRVSPEC32:
IOCTL_STRUCT_CONV_TO(SIOCGDRVSPEC, ifdrv);
case SIOCGETVIFCNT32:
IOCTL_STRUCT_CONV_TO(SIOCGETVIFCNT, sioc_vif_req);
case SIOCGETSGCNT32:
IOCTL_STRUCT_CONV_TO(SIOCGETSGCNT, sioc_sg_req);
case FSSIOCSET32: /* XXX FSSIOCSET50 not yet handled */
IOCTL_STRUCT_CONV_TO(FSSIOCSET, fss_set);
case FSSIOCGET32: /* XXX FSSIOCGET50 not yet handled */
IOCTL_STRUCT_CONV_TO(FSSIOCGET, fss_get);
case VNDIOCSET32:
IOCTL_STRUCT_CONV_TO(VNDIOCSET, vnd_ioctl);
case VNDIOCCLR32:
IOCTL_STRUCT_CONV_TO(VNDIOCCLR, vnd_ioctl);
case VNDIOCGET32:
IOCTL_STRUCT_CONV_TO(VNDIOCGET, vnd_user);
case VNDIOCSET5032:
IOCTL_STRUCT_CONV_TO(VNDIOCSET50, vnd_ioctl50);
case VNDIOCCLR5032:
IOCTL_STRUCT_CONV_TO(VNDIOCCLR50, vnd_ioctl50);
case ENVSYS_GETDICTIONARY32:
IOCTL_STRUCT_CONV_TO(ENVSYS_GETDICTIONARY, plistref);
case ENVSYS_SETDICTIONARY32:
IOCTL_STRUCT_CONV_TO(ENVSYS_SETDICTIONARY, plistref);
case ENVSYS_REMOVEPROPS32:
IOCTL_STRUCT_CONV_TO(ENVSYS_REMOVEPROPS, plistref);
case WDOGIOC_GWDOGS32:
IOCTL_STRUCT_CONV_TO(WDOGIOC_GWDOGS, wdog_conf);
case BIOCSETF32:
IOCTL_STRUCT_CONV_TO(BIOCSETF, bpf_program);
case BIOCSETWF32:
IOCTL_STRUCT_CONV_TO(BIOCSETWF, bpf_program);
case BIOCSTCPF32:
IOCTL_STRUCT_CONV_TO(BIOCSTCPF, bpf_program);
case BIOCSUDPF32:
IOCTL_STRUCT_CONV_TO(BIOCSUDPF, bpf_program);
case BIOCGDLTLIST32:
IOCTL_STRUCT_CONV_TO(BIOCGDLTLIST, bpf_dltlist);
case BIOCSRTIMEOUT32:
#define netbsd32_to_timeval(s32p, p, cmd) netbsd32_to_timeval(s32p, p)
#define netbsd32_from_timeval(p, s32p, cmd) netbsd32_from_timeval(p, s32p)
IOCTL_STRUCT_CONV_TO(BIOCSRTIMEOUT, timeval);
#undef netbsd32_to_timeval
#undef netbsd32_from_timeval
case WSDISPLAYIO_ADDSCREEN32:
IOCTL_STRUCT_CONV_TO(WSDISPLAYIO_ADDSCREEN,
wsdisplay_addscreendata);
case WSDISPLAYIO_GCURSOR32:
IOCTL_STRUCT_CONV_TO(WSDISPLAYIO_GCURSOR, wsdisplay_cursor);
case WSDISPLAYIO_SCURSOR32:
IOCTL_STRUCT_CONV_TO(WSDISPLAYIO_SCURSOR, wsdisplay_cursor);
case WSDISPLAYIO_GETCMAP32:
IOCTL_STRUCT_CONV_TO(WSDISPLAYIO_GETCMAP, wsdisplay_cmap);
case WSDISPLAYIO_PUTCMAP32:
IOCTL_STRUCT_CONV_TO(WSDISPLAYIO_PUTCMAP, wsdisplay_cmap);
case WSDISPLAYIO_LDFONT32:
IOCTL_STRUCT_CONV_TO(WSDISPLAYIO_LDFONT, wsdisplay_font);
case WSDISPLAYIO_SFONT32:
IOCTL_STRUCT_CONV_TO(WSDISPLAYIO_SFONT, wsdisplay_usefontdata);
case SIOCS8021132:
IOCTL_STRUCT_CONV_TO(SIOCS80211, ieee80211req);
case SIOCG8021132:
IOCTL_STRUCT_CONV_TO(SIOCG80211, ieee80211req);
case SIOCS80211NWKEY32:
IOCTL_STRUCT_CONV_TO(SIOCS80211NWKEY, ieee80211_nwkey);
case SIOCG80211NWKEY32:
IOCTL_STRUCT_CONV_TO(SIOCG80211NWKEY, ieee80211_nwkey);
case POWER_EVENT_RECVDICT32:
IOCTL_STRUCT_CONV_TO(POWER_EVENT_RECVDICT, plistref);
case CLOCKCTL_SETTIMEOFDAY32:
IOCTL_STRUCT_CONV_TO(CLOCKCTL_SETTIMEOFDAY,
clockctl_settimeofday);
case CLOCKCTL_ADJTIME32:
IOCTL_STRUCT_CONV_TO(CLOCKCTL_ADJTIME, clockctl_adjtime);
case CLOCKCTL_CLOCK_SETTIME32:
IOCTL_STRUCT_CONV_TO(CLOCKCTL_CLOCK_SETTIME,
clockctl_clock_settime);
case CLOCKCTL_NTP_ADJTIME32:
#ifdef NTP
{
size = IOCPARM_LEN(CLOCKCTL_NTP_ADJTIME);
if (size > sizeof(stkbuf))
data = memp = kmem_alloc(size, KM_SLEEP);
else
data = (void *)stkbuf;
case KIOCGSYMBOL32:
IOCTL_STRUCT_CONV_TO(KIOCGSYMBOL, ksyms_gsymbol);
case KIOCGVALUE32:
IOCTL_STRUCT_CONV_TO(KIOCGVALUE, ksyms_gvalue);
case IOC_NPF_LOAD32:
IOCTL_CONV_TO(IOC_NPF_LOAD, nvlist_ref_t);
case IOC_NPF_TABLE32:
IOCTL_STRUCT_CONV_TO(IOC_NPF_TABLE, npf_ioctl_table);
case IOC_NPF_STATS32:
IOCTL_CONV_TO(IOC_NPF_STATS, voidp);
case IOC_NPF_SAVE32:
IOCTL_CONV_TO(IOC_NPF_SAVE, nvlist_ref_t);
case IOC_NPF_RULE32:
IOCTL_CONV_TO(IOC_NPF_RULE, nvlist_ref_t);
case IOC_NPF_CONN_LOOKUP32:
IOCTL_CONV_TO(IOC_NPF_CONN_LOOKUP, nvlist_ref_t);
case DRVRESCANBUS32:
IOCTL_STRUCT_CONV_TO(DRVRESCANBUS, devrescanargs);
case DRVLISTDEV32:
IOCTL_STRUCT_CONV_TO(DRVLISTDEV, devlistargs);
case DRVCTLCOMMAND32:
IOCTL_STRUCT_CONV_TO(DRVCTLCOMMAND, plistref);
case DRVGETEVENT32:
IOCTL_STRUCT_CONV_TO(DRVGETEVENT, plistref);
case DIOCGSTRATEGY32:
IOCTL_STRUCT_CONV_TO(DIOCGSTRATEGY, disk_strategy);
case DIOCSSTRATEGY32:
IOCTL_STRUCT_CONV_TO(DIOCSSTRATEGY, disk_strategy);
case DIOCGDISKINFO32:
IOCTL_STRUCT_CONV_TO(DIOCGDISKINFO, plistref);
case DIOCLWEDGES32:
IOCTL_STRUCT_CONV_TO(DIOCLWEDGES, dkwedge_list);
case IOC_LOCKSTAT_ENABLE32:
IOCTL_STRUCT_CONV_TO(IOC_LOCKSTAT_ENABLE, lsenable);
case IOC_LOCKSTAT_DISABLE32:
IOCTL_STRUCT_CONV_TO(IOC_LOCKSTAT_DISABLE, lsdisable);
/*
* Copy any data to user, size was
* already set and checked above.
*/
if (error == 0 && (com&IOC_OUT) && size32) {
error = copyout(data32, SCARG_P32(uap, data), size32);
ktrgenio(fd, UIO_READ, SCARG_P32(uap, data),
size32, error);
}
out:
/* If we allocated data, free it here. */
if (memp32)
kmem_free(memp32, alloc_size32);
if (memp)
kmem_free(memp, size);
fd_putfile(fd);
return error;
}