diff options
Diffstat (limited to 'sys/compat/linux')
| -rw-r--r-- | sys/compat/linux/linux_file.c | 180 | ||||
| -rw-r--r-- | sys/compat/linux/linux_if.c | 11 | ||||
| -rw-r--r-- | sys/compat/linux/linux_ioctl.c | 120 | ||||
| -rw-r--r-- | sys/compat/linux/linux_ioctl.h | 29 | ||||
| -rw-r--r-- | sys/compat/linux/linux_netlink.c | 1 | ||||
| -rw-r--r-- | sys/compat/linux/linux_timer.c | 4 |
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)); } |
