aboutsummaryrefslogtreecommitdiff
path: root/sys/compat/linux/linux_ioctl.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/compat/linux/linux_ioctl.c')
-rw-r--r--sys/compat/linux/linux_ioctl.c626
1 files changed, 305 insertions, 321 deletions
diff --git a/sys/compat/linux/linux_ioctl.c b/sys/compat/linux/linux_ioctl.c
index e3ce41ed38f8..ceb17bd040b5 100644
--- a/sys/compat/linux/linux_ioctl.c
+++ b/sys/compat/linux/linux_ioctl.c
@@ -1,5 +1,5 @@
/*-
- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ * SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 1994-1995 Søren Schmidt
* All rights reserved.
@@ -26,27 +26,13 @@
* SUCH DAMAGE.
*/
-#include "opt_compat.h"
-
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
#include <sys/param.h>
-#include <sys/systm.h>
-#include <sys/sysproto.h>
-#ifdef COMPAT_LINUX32
-#include <sys/abi_compat.h>
-#endif
#include <sys/capsicum.h>
#include <sys/cdio.h>
-#include <sys/dvdio.h>
-#include <sys/conf.h>
-#include <sys/disk.h>
#include <sys/consio.h>
-#include <sys/ctype.h>
+#include <sys/disk.h>
+#include <sys/dvdio.h>
#include <sys/fcntl.h>
-#include <sys/file.h>
-#include <sys/filedesc.h>
#include <sys/filio.h>
#include <sys/jail.h>
#include <sys/kbio.h>
@@ -55,19 +41,16 @@ __FBSDID("$FreeBSD$");
#include <sys/linker_set.h>
#include <sys/lock.h>
#include <sys/malloc.h>
+#include <sys/mman.h>
#include <sys/proc.h>
#include <sys/sbuf.h>
-#include <sys/socket.h>
#include <sys/sockio.h>
#include <sys/soundcard.h>
-#include <sys/stdint.h>
-#include <sys/sx.h>
+#include <sys/syscallsubr.h>
#include <sys/sysctl.h>
+#include <sys/sysproto.h>
+#include <sys/sx.h>
#include <sys/tty.h>
-#include <sys/uio.h>
-#include <sys/types.h>
-#include <sys/mman.h>
-#include <sys/resourcevar.h>
#include <net/if.h>
#include <net/if_var.h>
@@ -89,7 +72,7 @@ __FBSDID("$FreeBSD$");
#include <compat/linux/linux_ioctl.h>
#include <compat/linux/linux_mib.h>
#include <compat/linux/linux_socket.h>
-#include <compat/linux/linux_timer.h>
+#include <compat/linux/linux_time.h>
#include <compat/linux/linux_util.h>
#include <contrib/v4l/videodev.h>
@@ -100,7 +83,7 @@ __FBSDID("$FreeBSD$");
#include <cam/scsi/scsi_sg.h>
-CTASSERT(LINUX_IFNAMSIZ == IFNAMSIZ);
+#include <dev/nvme/nvme_linux.h>
#define DEFINE_LINUX_IOCTL_SET(shortname, SHORTNAME) \
static linux_ioctl_function_t linux_ioctl_ ## shortname; \
@@ -127,6 +110,9 @@ DEFINE_LINUX_IOCTL_SET(v4l2, VIDEO2);
DEFINE_LINUX_IOCTL_SET(fbsd_usb, FBSD_LUSB);
DEFINE_LINUX_IOCTL_SET(evdev, EVDEV);
DEFINE_LINUX_IOCTL_SET(kcov, KCOV);
+#ifndef COMPAT_LINUX32
+DEFINE_LINUX_IOCTL_SET(nvme, NVME);
+#endif
#undef DEFINE_LINUX_IOCTL_SET
@@ -159,17 +145,17 @@ static TAILQ_HEAD(, linux_ioctl_handler_element) linux32_ioctl_handlers =
*/
struct linux_hd_geometry {
- u_int8_t heads;
- u_int8_t sectors;
- u_int16_t cylinders;
- u_int32_t start;
+ uint8_t heads;
+ uint8_t sectors;
+ uint16_t cylinders;
+ uint32_t start;
};
struct linux_hd_big_geometry {
- u_int8_t heads;
- u_int8_t sectors;
- u_int32_t cylinders;
- u_int32_t start;
+ uint8_t heads;
+ uint8_t sectors;
+ uint32_t cylinders;
+ uint32_t start;
};
static int
@@ -285,7 +271,7 @@ linux_ioctl_disk(struct thread *td, struct linux_ioctl_args *args)
fdrop(fp, td);
if (error)
return (error);
- blksize64 = mediasize;;
+ blksize64 = mediasize;
return (copyout(&blksize64, (void *)args->arg,
sizeof(blksize64)));
case LINUX_BLKSSZGET:
@@ -435,6 +421,8 @@ bsd_to_linux_termios(struct termios *bios, struct linux_termios *lios)
lios->c_iflag |= LINUX_IXOFF;
if (bios->c_iflag & IMAXBEL)
lios->c_iflag |= LINUX_IMAXBEL;
+ if (bios->c_iflag & IUTF8)
+ lios->c_iflag |= LINUX_IUTF8;
lios->c_oflag = 0;
if (bios->c_oflag & OPOST)
@@ -552,6 +540,8 @@ linux_to_bsd_termios(struct linux_termios *lios, struct termios *bios)
bios->c_iflag |= IXOFF;
if (lios->c_iflag & LINUX_IMAXBEL)
bios->c_iflag |= IMAXBEL;
+ if (lios->c_iflag & LINUX_IUTF8)
+ bios->c_iflag |= IUTF8;
bios->c_oflag = 0;
if (lios->c_oflag & LINUX_OPOST)
@@ -1020,9 +1010,17 @@ linux_ioctl_termio(struct thread *td, struct linux_ioctl_args *args)
sizeof(int));
break;
}
+ case LINUX_TIOCGPTPEER:
+ linux_msg(td, "unsupported ioctl TIOCGPTPEER");
+ error = ENOIOCTL;
+ break;
case LINUX_TIOCSPTLCK:
- /* Our unlockpt() does nothing. */
- error = 0;
+ /*
+ * Our unlockpt() does nothing. Check that fd refers
+ * to a pseudo-terminal master device.
+ */
+ args->cmd = TIOCPTMASTER;
+ error = (sys_ioctl(td, (struct ioctl_args *)args));
break;
default:
error = ENOIOCTL;
@@ -1103,9 +1101,9 @@ struct l_dvd_layer {
u_char track_density:4;
u_char linear_density:4;
u_char bca:1;
- u_int32_t start_sector;
- u_int32_t end_sector;
- u_int32_t end_sector_l0;
+ uint32_t start_sector;
+ uint32_t end_sector;
+ uint32_t end_sector_l0;
};
struct l_dvd_physical {
@@ -1460,7 +1458,7 @@ linux_ioctl_cdrom(struct thread *td, struct linux_ioctl_args *args)
if (!error) {
lth.cdth_trk0 = th.starting_track;
lth.cdth_trk1 = th.ending_track;
- copyout(&lth, (void *)args->arg, sizeof(lth));
+ error = copyout(&lth, (void *)args->arg, sizeof(lth));
}
break;
}
@@ -1622,7 +1620,8 @@ linux_ioctl_cdrom(struct thread *td, struct linux_ioctl_args *args)
if (error) {
if (lda.type == LINUX_DVD_HOST_SEND_KEY2) {
lda.type = LINUX_DVD_AUTH_FAILURE;
- copyout(&lda, (void *)args->arg, sizeof(lda));
+ (void)copyout(&lda, (void *)args->arg,
+ sizeof(lda));
}
break;
}
@@ -1690,7 +1689,7 @@ struct linux_old_mixer_info {
char name[32];
};
-static u_int32_t dirbits[4] = { IOC_VOID, IOC_IN, IOC_OUT, IOC_INOUT };
+static uint32_t dirbits[4] = { IOC_VOID, IOC_IN, IOC_OUT, IOC_INOUT };
#define SETDIR(c) (((c) & ~IOC_DIRMASK) | dirbits[args->cmd >> 30])
@@ -1782,9 +1781,10 @@ linux_ioctl_sound(struct thread *td, struct linux_ioctl_args *args)
struct linux_old_mixer_info info;
bzero(&info, sizeof(info));
strncpy(info.id, "OSS", sizeof(info.id) - 1);
- strncpy(info.name, "FreeBSD OSS Mixer", sizeof(info.name) - 1);
- copyout(&info, (void *)args->arg, sizeof(info));
- return (0);
+ strncpy(info.name, "FreeBSD OSS Mixer",
+ sizeof(info.name) - 1);
+ return (copyout(&info, (void *)args->arg,
+ sizeof(info)));
}
default:
return (ENOIOCTL);
@@ -2103,195 +2103,273 @@ static int
linux_ioctl_ifname(struct thread *td, struct l_ifreq *uifr)
{
struct l_ifreq ifr;
- struct ifnet *ifp;
- int error, ethno, index;
+ int error, ret;
error = copyin(uifr, &ifr, sizeof(ifr));
if (error != 0)
return (error);
-
- CURVNET_SET(TD_TO_VNET(curthread));
- IFNET_RLOCK();
- index = 1; /* ifr.ifr_ifindex starts from 1 */
- ethno = 0;
- error = ENODEV;
- CK_STAILQ_FOREACH(ifp, &V_ifnet, if_link) {
- if (ifr.ifr_ifindex == index) {
- if (IFP_IS_ETH(ifp))
- snprintf(ifr.ifr_name, LINUX_IFNAMSIZ,
- "eth%d", ethno);
- else
- strlcpy(ifr.ifr_name, ifp->if_xname,
- LINUX_IFNAMSIZ);
- error = 0;
- break;
- }
- if (IFP_IS_ETH(ifp))
- ethno++;
- index++;
- }
- IFNET_RUNLOCK();
- if (error == 0)
- error = copyout(&ifr, uifr, sizeof(ifr));
- CURVNET_RESTORE();
-
- return (error);
+ ret = ifname_bsd_to_linux_idx(ifr.ifr_index, ifr.ifr_name,
+ LINUX_IFNAMSIZ);
+ if (ret > 0)
+ return (copyout(&ifr, uifr, sizeof(ifr)));
+ else
+ return (ENODEV);
}
/*
* Implement the SIOCGIFCONF ioctl
*/
+static u_int
+linux_ifconf_ifaddr_cb(void *arg, struct ifaddr *ifa, u_int count)
+{
+#ifdef COMPAT_LINUX32
+ struct l_ifconf *ifc;
+#else
+ struct ifconf *ifc;
+#endif
+
+ ifc = arg;
+ ifc->ifc_len += sizeof(struct l_ifreq);
+ return (1);
+}
+
+static int
+linux_ifconf_ifnet_cb(if_t ifp, void *arg)
+{
+
+ if_foreach_addr_type(ifp, AF_INET, linux_ifconf_ifaddr_cb, arg);
+ return (0);
+}
+
+struct linux_ifconfig_ifaddr_cb2_s {
+ struct l_ifreq ifr;
+ struct sbuf *sb;
+ size_t max_len;
+ size_t valid_len;
+};
+
+static u_int
+linux_ifconf_ifaddr_cb2(void *arg, struct ifaddr *ifa, u_int len)
+{
+ struct linux_ifconfig_ifaddr_cb2_s *cbs = arg;
+ struct sockaddr *sa = ifa->ifa_addr;
+
+ cbs->ifr.ifr_addr.sa_family = LINUX_AF_INET;
+ memcpy(cbs->ifr.ifr_addr.sa_data, sa->sa_data,
+ sizeof(cbs->ifr.ifr_addr.sa_data));
+ sbuf_bcat(cbs->sb, &cbs->ifr, sizeof(cbs->ifr));
+ cbs->max_len += sizeof(cbs->ifr);
+
+ if (sbuf_error(cbs->sb) == 0)
+ cbs->valid_len = sbuf_len(cbs->sb);
+ return (1);
+}
+
+static int
+linux_ifconf_ifnet_cb2(if_t ifp, void *arg)
+{
+ struct linux_ifconfig_ifaddr_cb2_s *cbs = arg;
+
+ bzero(&cbs->ifr, sizeof(cbs->ifr));
+ ifname_bsd_to_linux_ifp(ifp, cbs->ifr.ifr_name,
+ sizeof(cbs->ifr.ifr_name));
+
+ /* Walk the address list */
+ if_foreach_addr_type(ifp, AF_INET, linux_ifconf_ifaddr_cb2, cbs);
+ return (0);
+}
static int
linux_ifconf(struct thread *td, struct ifconf *uifc)
{
+ struct linux_ifconfig_ifaddr_cb2_s cbs;
+ struct epoch_tracker et;
#ifdef COMPAT_LINUX32
struct l_ifconf ifc;
#else
struct ifconf ifc;
#endif
- struct l_ifreq ifr;
- struct ifnet *ifp;
- struct ifaddr *ifa;
struct sbuf *sb;
- int error, ethno, full = 0, valid_len, max_len;
+ int error, full;
error = copyin(uifc, &ifc, sizeof(ifc));
if (error != 0)
return (error);
- max_len = maxphys - 1;
-
- CURVNET_SET(TD_TO_VNET(td));
/* handle the 'request buffer size' case */
- if ((l_uintptr_t)ifc.ifc_buf == PTROUT(NULL)) {
+ if (PTRIN(ifc.ifc_buf) == NULL) {
ifc.ifc_len = 0;
- IFNET_RLOCK();
- CK_STAILQ_FOREACH(ifp, &V_ifnet, if_link) {
- CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
- struct sockaddr *sa = ifa->ifa_addr;
- if (sa->sa_family == AF_INET)
- ifc.ifc_len += sizeof(ifr);
- }
- }
- IFNET_RUNLOCK();
- error = copyout(&ifc, uifc, sizeof(ifc));
- CURVNET_RESTORE();
- return (error);
+ NET_EPOCH_ENTER(et);
+ if_foreach(linux_ifconf_ifnet_cb, &ifc);
+ NET_EPOCH_EXIT(et);
+ return (copyout(&ifc, uifc, sizeof(ifc)));
}
-
- if (ifc.ifc_len <= 0) {
- CURVNET_RESTORE();
+ if (ifc.ifc_len <= 0)
return (EINVAL);
- }
+
+ full = 0;
+ cbs.max_len = maxphys - 1;
again:
- /* Keep track of eth interfaces */
- ethno = 0;
- if (ifc.ifc_len <= max_len) {
- max_len = ifc.ifc_len;
+ if (ifc.ifc_len <= cbs.max_len) {
+ cbs.max_len = ifc.ifc_len;
full = 1;
}
- sb = sbuf_new(NULL, NULL, max_len + 1, SBUF_FIXEDLEN);
- max_len = 0;
- valid_len = 0;
+ cbs.sb = sb = sbuf_new(NULL, NULL, cbs.max_len + 1, SBUF_FIXEDLEN);
+ cbs.max_len = 0;
+ cbs.valid_len = 0;
/* Return all AF_INET addresses of all interfaces */
- IFNET_RLOCK();
- CK_STAILQ_FOREACH(ifp, &V_ifnet, if_link) {
- int addrs = 0;
-
- bzero(&ifr, sizeof(ifr));
- if (IFP_IS_ETH(ifp))
- snprintf(ifr.ifr_name, LINUX_IFNAMSIZ, "eth%d",
- ethno++);
- else
- strlcpy(ifr.ifr_name, ifp->if_xname, LINUX_IFNAMSIZ);
-
- /* Walk the address list */
- CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
- struct sockaddr *sa = ifa->ifa_addr;
-
- if (sa->sa_family == AF_INET) {
- ifr.ifr_addr.sa_family = LINUX_AF_INET;
- memcpy(ifr.ifr_addr.sa_data, sa->sa_data,
- sizeof(ifr.ifr_addr.sa_data));
- sbuf_bcat(sb, &ifr, sizeof(ifr));
- max_len += sizeof(ifr);
- addrs++;
- }
-
- if (sbuf_error(sb) == 0)
- valid_len = sbuf_len(sb);
- }
- if (addrs == 0) {
- bzero((caddr_t)&ifr.ifr_addr, sizeof(ifr.ifr_addr));
- sbuf_bcat(sb, &ifr, sizeof(ifr));
- max_len += sizeof(ifr);
+ NET_EPOCH_ENTER(et);
+ if_foreach(linux_ifconf_ifnet_cb2, &cbs);
+ NET_EPOCH_EXIT(et);
- if (sbuf_error(sb) == 0)
- valid_len = sbuf_len(sb);
- }
- }
- IFNET_RUNLOCK();
-
- if (valid_len != max_len && !full) {
+ if (cbs.valid_len != cbs.max_len && !full) {
sbuf_delete(sb);
goto again;
}
- ifc.ifc_len = valid_len;
+ ifc.ifc_len = cbs.valid_len;
sbuf_finish(sb);
error = copyout(sbuf_data(sb), PTRIN(ifc.ifc_buf), ifc.ifc_len);
if (error == 0)
error = copyout(&ifc, uifc, sizeof(ifc));
sbuf_delete(sb);
- CURVNET_RESTORE();
return (error);
}
static int
-linux_gifflags(struct thread *td, struct ifnet *ifp, struct l_ifreq *ifr)
+linux_ioctl_socket_ifreq(struct thread *td, int fd, u_int cmd,
+ struct l_ifreq *uifr)
{
- l_short flags;
+ struct l_ifreq lifr;
+ struct ifreq bifr;
+ size_t ifrusiz;
+ int error, temp_flags;
- linux_ifflags(ifp, &flags);
-
- return (copyout(&flags, &ifr->ifr_flags, sizeof(flags)));
-}
-
-static int
-linux_gifhwaddr(struct ifnet *ifp, struct l_ifreq *ifr)
-{
- struct l_sockaddr lsa;
-
- if (linux_ifhwaddr(ifp, &lsa) != 0)
- return (ENOENT);
+ switch (cmd) {
+ case LINUX_SIOCGIFINDEX:
+ cmd = SIOCGIFINDEX;
+ break;
+ case LINUX_SIOCGIFFLAGS:
+ cmd = SIOCGIFFLAGS;
+ break;
+ case LINUX_SIOCGIFADDR:
+ cmd = SIOCGIFADDR;
+ break;
+ case LINUX_SIOCSIFADDR:
+ cmd = SIOCSIFADDR;
+ break;
+ case LINUX_SIOCGIFDSTADDR:
+ cmd = SIOCGIFDSTADDR;
+ break;
+ case LINUX_SIOCGIFBRDADDR:
+ cmd = SIOCGIFBRDADDR;
+ break;
+ case LINUX_SIOCGIFNETMASK:
+ cmd = SIOCGIFNETMASK;
+ break;
+ case LINUX_SIOCSIFNETMASK:
+ cmd = SIOCSIFNETMASK;
+ break;
+ case LINUX_SIOCGIFMTU:
+ cmd = SIOCGIFMTU;
+ break;
+ case LINUX_SIOCSIFMTU:
+ cmd = SIOCSIFMTU;
+ break;
+ case LINUX_SIOCGIFHWADDR:
+ cmd = SIOCGHWADDR;
+ break;
+ case LINUX_SIOCGIFMETRIC:
+ cmd = SIOCGIFMETRIC;
+ break;
+ case LINUX_SIOCSIFMETRIC:
+ cmd = SIOCSIFMETRIC;
+ break;
+ /*
+ * XXX This is slightly bogus, but these ioctls are currently
+ * XXX only used by the aironet (if_an) network driver.
+ */
+ case LINUX_SIOCDEVPRIVATE:
+ cmd = SIOCGPRIVATE_0;
+ break;
+ case LINUX_SIOCDEVPRIVATE+1:
+ cmd = SIOCGPRIVATE_1;
+ break;
+ default:
+ LINUX_RATELIMIT_MSG_OPT2(
+ "ioctl_socket_ifreq fd=%d, cmd=0x%x is not implemented",
+ fd, cmd);
+ return (ENOIOCTL);
+ }
- return (copyout(&lsa, &ifr->ifr_hwaddr, sizeof(lsa)));
-}
+ error = copyin(uifr, &lifr, sizeof(lifr));
+ if (error != 0)
+ return (error);
+ bzero(&bifr, sizeof(bifr));
- /*
-* If we fault in bsd_to_linux_ifreq() then we will fault when we call
-* the native ioctl(). Thus, we don't really need to check the return
-* value of this function.
-*/
-static int
-bsd_to_linux_ifreq(struct ifreq *arg)
-{
- struct ifreq ifr;
- size_t ifr_len = sizeof(struct ifreq);
- int error;
+ /*
+ * The size of Linux enum ifr_ifru is bigger than
+ * the FreeBSD size due to the struct ifmap.
+ */
+ ifrusiz = (sizeof(lifr) > sizeof(bifr) ? sizeof(bifr) :
+ sizeof(lifr)) - offsetof(struct l_ifreq, ifr_ifru);
+ bcopy(&lifr.ifr_ifru, &bifr.ifr_ifru, ifrusiz);
- if ((error = copyin(arg, &ifr, ifr_len)))
+ error = ifname_linux_to_bsd(td, lifr.ifr_name, bifr.ifr_name);
+ if (error != 0)
return (error);
- *(u_short *)&ifr.ifr_addr = ifr.ifr_addr.sa_family;
+ /* Translate in values. */
+ switch (cmd) {
+ case SIOCGIFINDEX:
+ bifr.ifr_index = lifr.ifr_index;
+ break;
+ case SIOCSIFADDR:
+ case SIOCSIFNETMASK:
+ bifr.ifr_addr.sa_len = sizeof(struct sockaddr);
+ bifr.ifr_addr.sa_family =
+ linux_to_bsd_domain(lifr.ifr_addr.sa_family);
+ break;
+ default:
+ break;
+ }
- error = copyout(&ifr, arg, ifr_len);
+ error = kern_ioctl(td, fd, cmd, (caddr_t)&bifr);
+ if (error != 0)
+ return (error);
+ bzero(&lifr.ifr_ifru, sizeof(lifr.ifr_ifru));
+
+ /* Translate out values. */
+ switch (cmd) {
+ case SIOCGIFINDEX:
+ lifr.ifr_index = bifr.ifr_index;
+ break;
+ case SIOCGIFFLAGS:
+ temp_flags = bifr.ifr_flags | (bifr.ifr_flagshigh << 16);
+ lifr.ifr_flags = bsd_to_linux_ifflags(temp_flags);
+ break;
+ case SIOCGIFADDR:
+ case SIOCSIFADDR:
+ case SIOCGIFDSTADDR:
+ case SIOCGIFBRDADDR:
+ case SIOCGIFNETMASK:
+ bcopy(&bifr.ifr_addr, &lifr.ifr_addr, sizeof(bifr.ifr_addr));
+ lifr.ifr_addr.sa_family =
+ bsd_to_linux_domain(bifr.ifr_addr.sa_family);
+ break;
+ case SIOCGHWADDR:
+ bcopy(&bifr.ifr_addr, &lifr.ifr_hwaddr, sizeof(bifr.ifr_addr));
+ lifr.ifr_hwaddr.sa_family = LINUX_ARPHRD_ETHER;
+ break;
+ default:
+ bcopy(&bifr.ifr_ifru, &lifr.ifr_ifru, ifrusiz);
+ break;
+ }
- return (error);
+ return (copyout(&lifr, uifr, sizeof(lifr)));
}
/*
@@ -2301,84 +2379,34 @@ bsd_to_linux_ifreq(struct ifreq *arg)
static int
linux_ioctl_socket(struct thread *td, struct linux_ioctl_args *args)
{
- char lifname[LINUX_IFNAMSIZ], ifname[IFNAMSIZ];
- struct ifnet *ifp;
struct file *fp;
int error, type;
- ifp = NULL;
- error = 0;
-
error = fget(td, args->fd, &cap_ioctl_rights, &fp);
if (error != 0)
return (error);
type = fp->f_type;
fdrop(fp, td);
+
+ CURVNET_SET(TD_TO_VNET(td));
+
if (type != DTYPE_SOCKET) {
/* not a socket - probably a tap / vmnet device */
switch (args->cmd) {
case LINUX_SIOCGIFADDR:
case LINUX_SIOCSIFADDR:
case LINUX_SIOCGIFFLAGS:
- return (linux_ioctl_special(td, args));
+ error = linux_ioctl_special(td, args);
+ break;
default:
- return (ENOIOCTL);
+ error = ENOIOCTL;
+ break;
}
+ CURVNET_RESTORE();
+ return (error);
}
- switch (args->cmd & 0xffff) {
- case LINUX_FIOGETOWN:
- case LINUX_FIOSETOWN:
- case LINUX_SIOCADDMULTI:
- case LINUX_SIOCATMARK:
- case LINUX_SIOCDELMULTI:
- case LINUX_SIOCGIFNAME:
- case LINUX_SIOCGIFCONF:
- case LINUX_SIOCGPGRP:
- case LINUX_SIOCSPGRP:
- case LINUX_SIOCGIFCOUNT:
- /* these ioctls don't take an interface name */
- break;
-
- case LINUX_SIOCGIFFLAGS:
- case LINUX_SIOCGIFADDR:
- case LINUX_SIOCSIFADDR:
- case LINUX_SIOCGIFDSTADDR:
- case LINUX_SIOCGIFBRDADDR:
- case LINUX_SIOCGIFNETMASK:
- case LINUX_SIOCSIFNETMASK:
- case LINUX_SIOCGIFMTU:
- case LINUX_SIOCSIFMTU:
- case LINUX_SIOCSIFNAME:
- case LINUX_SIOCGIFHWADDR:
- case LINUX_SIOCSIFHWADDR:
- case LINUX_SIOCDEVPRIVATE:
- case LINUX_SIOCDEVPRIVATE+1:
- case LINUX_SIOCGIFINDEX:
- /* copy in the interface name and translate it. */
- error = copyin((void *)args->arg, lifname, LINUX_IFNAMSIZ);
- if (error != 0)
- return (error);
- memset(ifname, 0, sizeof(ifname));
- ifp = ifname_linux_to_bsd(td, lifname, ifname);
- if (ifp == NULL)
- return (EINVAL);
- /*
- * We need to copy it back out in case we pass the
- * request on to our native ioctl(), which will expect
- * the ifreq to be in user space and have the correct
- * interface name.
- */
- error = copyout(ifname, (void *)args->arg, IFNAMSIZ);
- if (error != 0)
- return (error);
- break;
-
- default:
- return (ENOIOCTL);
- }
-
- switch (args->cmd & 0xffff) {
+ switch (args->cmd) {
case LINUX_FIOSETOWN:
args->cmd = FIOSETOWN;
error = sys_ioctl(td, (struct ioctl_args *)args);
@@ -2414,67 +2442,6 @@ linux_ioctl_socket(struct thread *td, struct linux_ioctl_args *args)
error = linux_ifconf(td, (struct ifconf *)args->arg);
break;
- case LINUX_SIOCGIFFLAGS:
- args->cmd = SIOCGIFFLAGS;
- error = linux_gifflags(td, ifp, (struct l_ifreq *)args->arg);
- break;
-
- case LINUX_SIOCGIFADDR:
- args->cmd = SIOCGIFADDR;
- error = sys_ioctl(td, (struct ioctl_args *)args);
- bsd_to_linux_ifreq((struct ifreq *)args->arg);
- break;
-
- case LINUX_SIOCSIFADDR:
- /* XXX probably doesn't work, included for completeness */
- args->cmd = SIOCSIFADDR;
- error = sys_ioctl(td, (struct ioctl_args *)args);
- break;
-
- case LINUX_SIOCGIFDSTADDR:
- args->cmd = SIOCGIFDSTADDR;
- error = sys_ioctl(td, (struct ioctl_args *)args);
- bsd_to_linux_ifreq((struct ifreq *)args->arg);
- break;
-
- case LINUX_SIOCGIFBRDADDR:
- args->cmd = SIOCGIFBRDADDR;
- error = sys_ioctl(td, (struct ioctl_args *)args);
- bsd_to_linux_ifreq((struct ifreq *)args->arg);
- break;
-
- case LINUX_SIOCGIFNETMASK:
- args->cmd = SIOCGIFNETMASK;
- error = sys_ioctl(td, (struct ioctl_args *)args);
- bsd_to_linux_ifreq((struct ifreq *)args->arg);
- break;
-
- case LINUX_SIOCSIFNETMASK:
- error = ENOIOCTL;
- break;
-
- case LINUX_SIOCGIFMTU:
- args->cmd = SIOCGIFMTU;
- error = sys_ioctl(td, (struct ioctl_args *)args);
- break;
-
- case LINUX_SIOCSIFMTU:
- args->cmd = SIOCSIFMTU;
- error = sys_ioctl(td, (struct ioctl_args *)args);
- break;
-
- case LINUX_SIOCSIFNAME:
- error = ENOIOCTL;
- break;
-
- case LINUX_SIOCGIFHWADDR:
- error = linux_gifhwaddr(ifp, (struct l_ifreq *)args->arg);
- break;
-
- case LINUX_SIOCSIFHWADDR:
- error = ENOIOCTL;
- break;
-
case LINUX_SIOCADDMULTI:
args->cmd = SIOCADDMULTI;
error = sys_ioctl(td, (struct ioctl_args *)args);
@@ -2485,34 +2452,17 @@ linux_ioctl_socket(struct thread *td, struct linux_ioctl_args *args)
error = sys_ioctl(td, (struct ioctl_args *)args);
break;
- case LINUX_SIOCGIFINDEX:
- args->cmd = SIOCGIFINDEX;
- error = sys_ioctl(td, (struct ioctl_args *)args);
- break;
-
case LINUX_SIOCGIFCOUNT:
error = 0;
break;
- /*
- * XXX This is slightly bogus, but these ioctls are currently
- * XXX only used by the aironet (if_an) network driver.
- */
- case LINUX_SIOCDEVPRIVATE:
- args->cmd = SIOCGPRIVATE_0;
- error = sys_ioctl(td, (struct ioctl_args *)args);
- break;
-
- case LINUX_SIOCDEVPRIVATE+1:
- args->cmd = SIOCGPRIVATE_1;
- error = sys_ioctl(td, (struct ioctl_args *)args);
+ default:
+ error = linux_ioctl_socket_ifreq(td, args->fd, args->cmd,
+ PTRIN(args->arg));
break;
}
- if (ifp != NULL)
- /* restore the original interface name */
- copyout(lifname, (void *)args->arg, LINUX_IFNAMSIZ);
-
+ CURVNET_RESTORE();
return (error);
}
@@ -3275,7 +3225,9 @@ linux_ioctl_v4l2(struct thread *td, struct linux_ioctl_args *args)
error = fo_ioctl(fp, VIDIOC_TRY_FMT, &vformat,
td->td_ucred, td);
bsd_to_linux_v4l2_format(&vformat, &l_vformat);
- copyout(&l_vformat, (void *)args->arg, sizeof(l_vformat));
+ if (error == 0)
+ error = copyout(&l_vformat, (void *)args->arg,
+ sizeof(l_vformat));
fdrop(fp, td);
return (error);
@@ -3344,7 +3296,9 @@ linux_ioctl_v4l2(struct thread *td, struct linux_ioctl_args *args)
error = fo_ioctl(fp, VIDIOC_DQBUF, &vbuf,
td->td_ucred, td);
bsd_to_linux_v4l2_buffer(&vbuf, &l_vbuf);
- copyout(&l_vbuf, (void *)args->arg, sizeof(l_vbuf));
+ if (error == 0)
+ error = copyout(&l_vbuf, (void *)args->arg,
+ sizeof(l_vbuf));
fdrop(fp, td);
return (error);
@@ -3586,6 +3540,36 @@ linux_ioctl_kcov(struct thread *td, struct linux_ioctl_args *args)
return (error);
}
+#ifndef COMPAT_LINUX32
+static int
+linux_ioctl_nvme(struct thread *td, struct linux_ioctl_args *args)
+{
+
+ /*
+ * The NVMe drivers for namespace and controller implement these
+ * commands using their native format. All the others are not
+ * implemented yet.
+ */
+ switch (args->cmd & 0xffff) {
+ case LINUX_NVME_IOCTL_ID:
+ args->cmd = NVME_IOCTL_ID;
+ break;
+ case LINUX_NVME_IOCTL_RESET:
+ args->cmd = NVME_IOCTL_RESET;
+ break;
+ case LINUX_NVME_IOCTL_ADMIN_CMD:
+ args->cmd = NVME_IOCTL_ADMIN_CMD;
+ break;
+ case LINUX_NVME_IOCTL_IO_CMD:
+ args->cmd = NVME_IOCTL_IO_CMD;
+ break;
+ default:
+ return (ENODEV);
+ }
+ return (sys_ioctl(td, (struct ioctl_args *)args));
+}
+#endif
+
/*
* main ioctl syscall function
*/