aboutsummaryrefslogtreecommitdiff
path: root/sys/compat/linux
diff options
context:
space:
mode:
Diffstat (limited to 'sys/compat/linux')
-rw-r--r--sys/compat/linux/linux_file.c180
-rw-r--r--sys/compat/linux/linux_if.c11
-rw-r--r--sys/compat/linux/linux_ioctl.c120
-rw-r--r--sys/compat/linux/linux_ioctl.h29
-rw-r--r--sys/compat/linux/linux_netlink.c1
-rw-r--r--sys/compat/linux/linux_timer.c4
6 files changed, 267 insertions, 78 deletions
diff --git a/sys/compat/linux/linux_file.c b/sys/compat/linux/linux_file.c
index daddafa325ad..ca089585bb95 100644
--- a/sys/compat/linux/linux_file.c
+++ b/sys/compat/linux/linux_file.c
@@ -398,12 +398,50 @@ struct l_dirent64 {
roundup(offsetof(struct l_dirent64, d_name) + (namlen) + 1, \
sizeof(uint64_t))
+/*
+ * Do kern_getdirentries() and then skip over any invalid entries.
+ * (Repeat, if there are no valid entries.)
+ * Adjust bufp and lenp.
+ */
+static int
+linux_getdirentries(struct thread *td, int fd, caddr_t *bufp, int buflen,
+ off_t *basep, int *lenp)
+{
+ struct dirent *bdp;
+ caddr_t buf;
+ int error, len;
+
+ /* Loop around until a valid entry is found or at EOF. */
+ for (;;) {
+ error = kern_getdirentries(td, fd, *bufp, buflen,
+ basep, NULL, UIO_SYSSPACE);
+ if (error != 0)
+ return (error);
+ len = td->td_retval[0];
+ if (len == 0) {
+ *lenp = 0;
+ return (0);
+ }
+ buf = *bufp;
+ while (len > 0) {
+ bdp = (struct dirent *)buf;
+ if (bdp->d_fileno != 0) {
+ *bufp = buf;
+ *lenp = len;
+ return (0);
+ }
+ buf += bdp->d_reclen;
+ len -= bdp->d_reclen;
+ }
+ }
+}
+
#ifdef LINUX_LEGACY_SYSCALLS
int
linux_getdents(struct thread *td, struct linux_getdents_args *args)
{
struct dirent *bdp;
- caddr_t inp, buf; /* BSD-format */
+ caddr_t inp, buf, bufsav; /* BSD-format */
int len, reclen; /* BSD-format */
caddr_t outp; /* Linux-format */
int resid, linuxreclen; /* Linux-format */
@@ -413,11 +451,11 @@ linux_getdents(struct thread *td, struct linux_getdents_args *args)
int buflen, error;
size_t retval;
- buflen = min(args->count, MAXBSIZE);
- buf = malloc(buflen, M_LINUX, M_WAITOK);
+ buflen = min(roundup2(args->count, DEV_BSIZE), MAXBSIZE);
+ bufsav = buf = malloc(buflen, M_LINUX, M_WAITOK);
- error = kern_getdirentries(td, args->fd, buf, buflen,
- &base, NULL, UIO_SYSSPACE);
+ error = linux_getdirentries(td, args->fd, &buf, buflen,
+ &base, &len);
if (error != 0) {
error = linux_getdents_error(td, args->fd, error);
goto out1;
@@ -425,7 +463,6 @@ linux_getdents(struct thread *td, struct linux_getdents_args *args)
lbuf = malloc(LINUX_RECLEN(LINUX_NAME_MAX), M_LINUX, M_WAITOK | M_ZERO);
- len = td->td_retval[0];
inp = buf;
outp = (caddr_t)args->dent;
resid = args->count;
@@ -434,44 +471,47 @@ linux_getdents(struct thread *td, struct linux_getdents_args *args)
while (len > 0) {
bdp = (struct dirent *) inp;
reclen = bdp->d_reclen;
- linuxreclen = LINUX_RECLEN(bdp->d_namlen);
- /*
- * No more space in the user supplied dirent buffer.
- * Return EINVAL.
- */
- if (resid < linuxreclen) {
- error = EINVAL;
- goto out;
+ /* Copy a valid entry out. */
+ if (bdp->d_fileno != 0) {
+ linuxreclen = LINUX_RECLEN(bdp->d_namlen);
+ /*
+ * No more space in the user supplied dirent buffer.
+ * Return EINVAL.
+ */
+ if (resid < linuxreclen) {
+ error = EINVAL;
+ goto out;
+ }
+
+ linux_dirent = (struct l_dirent*)lbuf;
+ linux_dirent->d_ino = bdp->d_fileno;
+ linux_dirent->d_off = bdp->d_off;
+ linux_dirent->d_reclen = linuxreclen;
+ /*
+ * Copy d_type to last byte of l_dirent buffer
+ */
+ lbuf[linuxreclen - 1] = bdp->d_type;
+ strlcpy(linux_dirent->d_name, bdp->d_name,
+ linuxreclen - offsetof(struct l_dirent, d_name)-1);
+ error = copyout(linux_dirent, outp, linuxreclen);
+ if (error != 0)
+ goto out;
+ retval += linuxreclen;
+ outp += linuxreclen;
+ resid -= linuxreclen;
}
- linux_dirent = (struct l_dirent*)lbuf;
- linux_dirent->d_ino = bdp->d_fileno;
- linux_dirent->d_off = bdp->d_off;
- linux_dirent->d_reclen = linuxreclen;
- /*
- * Copy d_type to last byte of l_dirent buffer
- */
- lbuf[linuxreclen - 1] = bdp->d_type;
- strlcpy(linux_dirent->d_name, bdp->d_name,
- linuxreclen - offsetof(struct l_dirent, d_name)-1);
- error = copyout(linux_dirent, outp, linuxreclen);
- if (error != 0)
- goto out;
-
inp += reclen;
base += reclen;
len -= reclen;
- retval += linuxreclen;
- outp += linuxreclen;
- resid -= linuxreclen;
}
td->td_retval[0] = retval;
out:
free(lbuf, M_LINUX);
out1:
- free(buf, M_LINUX);
+ free(bufsav, M_LINUX);
return (error);
}
#endif
@@ -480,7 +520,7 @@ int
linux_getdents64(struct thread *td, struct linux_getdents64_args *args)
{
struct dirent *bdp;
- caddr_t inp, buf; /* BSD-format */
+ caddr_t inp, buf, bufsav; /* BSD-format */
int len, reclen; /* BSD-format */
caddr_t outp; /* Linux-format */
int resid, linuxreclen; /* Linux-format */
@@ -489,11 +529,11 @@ linux_getdents64(struct thread *td, struct linux_getdents64_args *args)
int buflen, error;
size_t retval;
- buflen = min(args->count, MAXBSIZE);
- buf = malloc(buflen, M_LINUX, M_WAITOK);
+ buflen = min(roundup2(args->count, DEV_BSIZE), MAXBSIZE);
+ bufsav = buf = malloc(buflen, M_LINUX, M_WAITOK);
- error = kern_getdirentries(td, args->fd, buf, buflen,
- &base, NULL, UIO_SYSSPACE);
+ error = linux_getdirentries(td, args->fd, &buf, buflen,
+ &base, &len);
if (error != 0) {
error = linux_getdents_error(td, args->fd, error);
goto out1;
@@ -502,7 +542,6 @@ linux_getdents64(struct thread *td, struct linux_getdents64_args *args)
linux_dirent64 = malloc(LINUX_RECLEN64(LINUX_NAME_MAX), M_LINUX,
M_WAITOK | M_ZERO);
- len = td->td_retval[0];
inp = buf;
outp = (caddr_t)args->dirent;
resid = args->count;
@@ -511,40 +550,43 @@ linux_getdents64(struct thread *td, struct linux_getdents64_args *args)
while (len > 0) {
bdp = (struct dirent *) inp;
reclen = bdp->d_reclen;
- linuxreclen = LINUX_RECLEN64(bdp->d_namlen);
- /*
- * No more space in the user supplied dirent buffer.
- * Return EINVAL.
- */
- if (resid < linuxreclen) {
- error = EINVAL;
- goto out;
+ /* Copy a valid entry out. */
+ if (bdp->d_fileno != 0) {
+ linuxreclen = LINUX_RECLEN64(bdp->d_namlen);
+ /*
+ * No more space in the user supplied dirent buffer.
+ * Return EINVAL.
+ */
+ if (resid < linuxreclen) {
+ error = EINVAL;
+ goto out;
+ }
+
+ linux_dirent64->d_ino = bdp->d_fileno;
+ linux_dirent64->d_off = bdp->d_off;
+ linux_dirent64->d_reclen = linuxreclen;
+ linux_dirent64->d_type = bdp->d_type;
+ strlcpy(linux_dirent64->d_name, bdp->d_name,
+ linuxreclen - offsetof(struct l_dirent64, d_name));
+ error = copyout(linux_dirent64, outp, linuxreclen);
+ if (error != 0)
+ goto out;
+ retval += linuxreclen;
+ outp += linuxreclen;
+ resid -= linuxreclen;
}
- linux_dirent64->d_ino = bdp->d_fileno;
- linux_dirent64->d_off = bdp->d_off;
- linux_dirent64->d_reclen = linuxreclen;
- linux_dirent64->d_type = bdp->d_type;
- strlcpy(linux_dirent64->d_name, bdp->d_name,
- linuxreclen - offsetof(struct l_dirent64, d_name));
- error = copyout(linux_dirent64, outp, linuxreclen);
- if (error != 0)
- goto out;
-
inp += reclen;
base += reclen;
len -= reclen;
- retval += linuxreclen;
- outp += linuxreclen;
- resid -= linuxreclen;
}
td->td_retval[0] = retval;
out:
free(linux_dirent64, M_LINUX);
out1:
- free(buf, M_LINUX);
+ free(bufsav, M_LINUX);
return (error);
}
@@ -553,22 +595,22 @@ int
linux_readdir(struct thread *td, struct linux_readdir_args *args)
{
struct dirent *bdp;
- caddr_t buf; /* BSD-format */
+ caddr_t buf, bufsav; /* BSD-format */
int linuxreclen; /* Linux-format */
off_t base;
struct l_dirent *linux_dirent; /* Linux-format */
- int buflen, error;
+ int buflen, error, len;
- buflen = sizeof(*bdp);
- buf = malloc(buflen, M_LINUX, M_WAITOK);
+ buflen = DEV_BSIZE;
+ bufsav = buf = malloc(buflen, M_LINUX, M_WAITOK);
- error = kern_getdirentries(td, args->fd, buf, buflen,
- &base, NULL, UIO_SYSSPACE);
+ error = linux_getdirentries(td, args->fd, &buf, buflen,
+ &base, &len);
if (error != 0) {
error = linux_getdents_error(td, args->fd, error);
goto out;
}
- if (td->td_retval[0] == 0)
+ if (len == 0)
goto out;
linux_dirent = malloc(LINUX_RECLEN(LINUX_NAME_MAX), M_LINUX,
@@ -588,7 +630,7 @@ linux_readdir(struct thread *td, struct linux_readdir_args *args)
free(linux_dirent, M_LINUX);
out:
- free(buf, M_LINUX);
+ free(bufsav, M_LINUX);
return (error);
}
#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
@@ -1171,7 +1213,7 @@ linux_oldumount(struct thread *td, struct linux_oldumount_args *args)
int
linux_umount(struct thread *td, struct linux_umount_args *args)
{
- int flags;
+ uint64_t flags;
flags = 0;
if ((args->flags & LINUX_MNT_FORCE) != 0) {
diff --git a/sys/compat/linux/linux_if.c b/sys/compat/linux/linux_if.c
index f201f7c4b128..ca4e3a4079ed 100644
--- a/sys/compat/linux/linux_if.c
+++ b/sys/compat/linux/linux_if.c
@@ -105,12 +105,13 @@ static void
linux_ifnet_vnet_uninit(void *arg __unused)
{
/*
- * At a normal vnet shutdown all interfaces are gone at this point.
- * But when we kldunload linux.ko, the vnet_deregister_sysuninit()
- * would call this function for the default vnet.
+ * All cloned interfaces are already gone at this point, as well
+ * as interfaces that were if_vmove'd into this vnet. However,
+ * if a jail has created IFT_ETHER interfaces in self, or has had
+ * physical Ethernet drivers attached in self, than we may have
+ * allocated entries in the unr(9), so clear it to avoid KASSERT.
*/
- if (IS_DEFAULT_VNET(curvnet))
- clear_unrhdr(V_linux_eth_unr);
+ clear_unrhdr(V_linux_eth_unr);
delete_unrhdr(V_linux_eth_unr);
}
VNET_SYSUNINIT(linux_ifnet_vnet_uninit, SI_SUB_PROTO_IF, SI_ORDER_ANY,
diff --git a/sys/compat/linux/linux_ioctl.c b/sys/compat/linux/linux_ioctl.c
index ceb17bd040b5..d2fa0331026b 100644
--- a/sys/compat/linux/linux_ioctl.c
+++ b/sys/compat/linux/linux_ioctl.c
@@ -58,6 +58,7 @@
#include <net/if_types.h>
#include <dev/evdev/input.h>
+#include <dev/hid/hidraw.h>
#include <dev/usb/usb_ioctl.h>
#ifdef COMPAT_LINUX32
@@ -113,6 +114,7 @@ DEFINE_LINUX_IOCTL_SET(kcov, KCOV);
#ifndef COMPAT_LINUX32
DEFINE_LINUX_IOCTL_SET(nvme, NVME);
#endif
+DEFINE_LINUX_IOCTL_SET(hidraw, HIDRAW);
#undef DEFINE_LINUX_IOCTL_SET
@@ -331,6 +333,17 @@ struct linux_termios {
unsigned char c_cc[LINUX_NCCS];
};
+struct linux_termios2 {
+ unsigned int c_iflag;
+ unsigned int c_oflag;
+ unsigned int c_cflag;
+ unsigned int c_lflag;
+ unsigned char c_line;
+ unsigned char c_cc[LINUX_NCCS];
+ unsigned int c_ispeed;
+ unsigned int c_ospeed;
+};
+
struct linux_winsize {
unsigned short ws_row, ws_col;
unsigned short ws_xpixel, ws_ypixel;
@@ -386,7 +399,7 @@ bsd_to_linux_speed(int speed, struct speedtab *table)
for ( ; table->sp_speed != -1; table++)
if (table->sp_speed == speed)
return (table->sp_code);
- return (-1);
+ return (LINUX_BOTHER);
}
static void
@@ -509,6 +522,14 @@ bsd_to_linux_termios(struct termios *bios, struct linux_termios *lios)
}
static void
+bsd_to_linux_termios2(struct termios *bios, struct linux_termios2 *lios2)
+{
+ bsd_to_linux_termios(bios, (struct linux_termios *)lios2);
+ lios2->c_ospeed = bios->c_ospeed;
+ lios2->c_ispeed = bios->c_ispeed;
+}
+
+static void
linux_to_bsd_termios(struct linux_termios *lios, struct termios *bios)
{
int i;
@@ -629,6 +650,16 @@ linux_to_bsd_termios(struct linux_termios *lios, struct termios *bios)
}
static void
+linux_to_bsd_termios2(struct linux_termios2 *lios2, struct termios *bios)
+{
+ linux_to_bsd_termios((struct linux_termios *)lios2, bios);
+ if ((lios2->c_cflag & LINUX_CBAUD) == LINUX_BOTHER)
+ bios->c_ospeed = lios2->c_ospeed;
+ if ((lios2->c_cflag & LINUX_CIBAUD) == LINUX_BOTHER << LINUX_IBSHIFT)
+ bios->c_ispeed = lios2->c_ispeed;
+}
+
+static void
bsd_to_linux_termio(struct termios *bios, struct linux_termio *lio)
{
struct linux_termios lios;
@@ -664,6 +695,7 @@ linux_ioctl_termio(struct thread *td, struct linux_ioctl_args *args)
{
struct termios bios;
struct linux_termios lios;
+ struct linux_termios2 lios2;
struct linux_termio lio;
struct file *fp;
int error;
@@ -1001,6 +1033,43 @@ linux_ioctl_termio(struct thread *td, struct linux_ioctl_args *args)
args->cmd = TIOCCBRK;
error = (sys_ioctl(td, (struct ioctl_args *)args));
break;
+
+ case LINUX_TCGETS2:
+ error = fo_ioctl(fp, TIOCGETA, (caddr_t)&bios, td->td_ucred,
+ td);
+ if (error)
+ break;
+ bsd_to_linux_termios2(&bios, &lios2);
+ error = copyout(&lios2, (void *)args->arg, sizeof(lios2));
+ break;
+
+ case LINUX_TCSETS2:
+ error = copyin((void *)args->arg, &lios2, sizeof(lios2));
+ if (error)
+ break;
+ linux_to_bsd_termios2(&lios2, &bios);
+ error = (fo_ioctl(fp, TIOCSETA, (caddr_t)&bios, td->td_ucred,
+ td));
+ break;
+
+ case LINUX_TCSETSW2:
+ error = copyin((void *)args->arg, &lios2, sizeof(lios2));
+ if (error)
+ break;
+ linux_to_bsd_termios2(&lios2, &bios);
+ error = (fo_ioctl(fp, TIOCSETAW, (caddr_t)&bios, td->td_ucred,
+ td));
+ break;
+
+ case LINUX_TCSETSF2:
+ error = copyin((void *)args->arg, &lios2, sizeof(lios2));
+ if (error)
+ break;
+ linux_to_bsd_termios2(&lios2, &bios);
+ error = (fo_ioctl(fp, TIOCSETAF, (caddr_t)&bios, td->td_ucred,
+ td));
+ break;
+
case LINUX_TIOCGPTN: {
int nb;
@@ -3570,6 +3639,55 @@ linux_ioctl_nvme(struct thread *td, struct linux_ioctl_args *args)
}
#endif
+static int
+linux_ioctl_hidraw(struct thread *td, struct linux_ioctl_args *args)
+{
+ int len = (args->cmd & 0x3fff0000) >> 16;
+ if (len > 8192)
+ return (EINVAL);
+
+ switch (args->cmd & 0xffff) {
+ case LINUX_HIDIOCGRDESCSIZE:
+ args->cmd = HIDIOCGRDESCSIZE;
+ break;
+ case LINUX_HIDIOCGRDESC:
+ args->cmd = HIDIOCGRDESC;
+ break;
+ case LINUX_HIDIOCGRAWINFO:
+ args->cmd = HIDIOCGRAWINFO;
+ break;
+ case LINUX_HIDIOCGRAWNAME:
+ args->cmd = HIDIOCGRAWNAME(len);
+ break;
+ case LINUX_HIDIOCGRAWPHYS:
+ args->cmd = HIDIOCGRAWPHYS(len);
+ break;
+ case LINUX_HIDIOCSFEATURE:
+ args->cmd = HIDIOCSFEATURE(len);
+ break;
+ case LINUX_HIDIOCGFEATURE:
+ args->cmd = HIDIOCGFEATURE(len);
+ break;
+ case LINUX_HIDIOCGRAWUNIQ:
+ args->cmd = HIDIOCGRAWUNIQ(len);
+ break;
+ case LINUX_HIDIOCSINPUT:
+ args->cmd = HIDIOCSINPUT(len);
+ break;
+ case LINUX_HIDIOCGINPUT:
+ args->cmd = HIDIOCGINPUT(len);
+ break;
+ case LINUX_HIDIOCSOUTPUT:
+ args->cmd = HIDIOCSOUTPUT(len);
+ break;
+ case LINUX_HIDIOCGOUTPUT:
+ args->cmd = HIDIOCGOUTPUT(len);
+ break;
+ }
+
+ return (sys_ioctl(td, (struct ioctl_args *)args));
+}
+
/*
* main ioctl syscall function
*/
diff --git a/sys/compat/linux/linux_ioctl.h b/sys/compat/linux/linux_ioctl.h
index 8345b7e4b719..116a4e676228 100644
--- a/sys/compat/linux/linux_ioctl.h
+++ b/sys/compat/linux/linux_ioctl.h
@@ -383,6 +383,11 @@
#define LINUX_TIOCSBRK 0x5427
#define LINUX_TIOCCBRK 0x5428
+#define LINUX_TCGETS2 0x542A
+#define LINUX_TCSETS2 0x542B
+#define LINUX_TCSETSW2 0x542C
+#define LINUX_TCSETSF2 0x542D
+
#define LINUX_TIOCGPTN 0x5430
#define LINUX_TIOCSPTLCK 0x5431
@@ -501,6 +506,7 @@
#define LINUX_FF1 0x0008000
#define LINUX_CBAUD 0x0000100f
+#define LINUX_CIBAUD (LINUX_CBAUD << LINUX_IBSHIFT)
#define LINUX_B0 0x00000000
#define LINUX_B50 0x00000001
@@ -537,8 +543,12 @@
#define LINUX_HUPCL 0x00000400
#define LINUX_CLOCAL 0x00000800
+#define LINUX_BOTHER 0x00001000
+
#define LINUX_CRTSCTS 0x80000000
+#define LINUX_IBSHIFT 16
+
/* Linux c_lflag masks */
#define LINUX_ISIG 0x00000001
#define LINUX_ICANON 0x00000002
@@ -797,6 +807,25 @@
#define LINUX_IOCTL_NVME_MAX LINUX_NVME_IOCTL_RESCAN
/*
+ * hidraw
+ */
+#define LINUX_HIDIOCGRDESCSIZE 0x4801
+#define LINUX_HIDIOCGRDESC 0x4802
+#define LINUX_HIDIOCGRAWINFO 0x4803
+#define LINUX_HIDIOCGRAWNAME 0x4804
+#define LINUX_HIDIOCGRAWPHYS 0x4805
+#define LINUX_HIDIOCSFEATURE 0x4806
+#define LINUX_HIDIOCGFEATURE 0x4807
+#define LINUX_HIDIOCGRAWUNIQ 0x4808
+#define LINUX_HIDIOCSINPUT 0x4809
+#define LINUX_HIDIOCGINPUT 0x480A
+#define LINUX_HIDIOCSOUTPUT 0x480B
+#define LINUX_HIDIOCGOUTPUT 0x480C
+
+#define LINUX_IOCTL_HIDRAW_MIN LINUX_HIDIOCGRDESCSIZE
+#define LINUX_IOCTL_HIDRAW_MAX LINUX_HIDIOCGOUTPUT
+
+/*
* Pluggable ioctl handlers
*/
struct linux_ioctl_args;
diff --git a/sys/compat/linux/linux_netlink.c b/sys/compat/linux/linux_netlink.c
index 6dd2ad7ad8b0..256f188385ce 100644
--- a/sys/compat/linux/linux_netlink.c
+++ b/sys/compat/linux/linux_netlink.c
@@ -340,7 +340,6 @@ rtnl_if_flags_to_linux(unsigned int if_flags)
case IFF_STATICARP:
case IFF_STICKYARP:
case IFF_DYING:
- case IFF_RENAMING:
/* No Linux analogue */
break;
case IFF_MULTICAST:
diff --git a/sys/compat/linux/linux_timer.c b/sys/compat/linux/linux_timer.c
index ed9133359302..230be9572b85 100644
--- a/sys/compat/linux/linux_timer.c
+++ b/sys/compat/linux/linux_timer.c
@@ -131,7 +131,7 @@ linux_timer_settime(struct thread *td, struct linux_timer_settime_args *uap)
return (error);
error = kern_ktimer_settime(td, uap->timerid, flags, &val, ovalp);
if (error == 0 && uap->old != NULL) {
- error = native_to_linux_itimerspec(&l_val, &val);
+ error = native_to_linux_itimerspec(&l_oval, &oval);
if (error == 0)
error = copyout(&l_oval, uap->old, sizeof(l_oval));
}
@@ -158,7 +158,7 @@ linux_timer_settime64(struct thread *td, struct linux_timer_settime64_args *uap)
return (error);
error = kern_ktimer_settime(td, uap->timerid, flags, &val, ovalp);
if (error == 0 && uap->old != NULL) {
- error = native_to_linux_itimerspec64(&l_val, &val);
+ error = native_to_linux_itimerspec64(&l_oval, &oval);
if (error == 0)
error = copyout(&l_oval, uap->old, sizeof(l_oval));
}