diff --git a/sys/compat/linux/linux_ioctl.h b/sys/compat/linux/linux_ioctl.h --- a/sys/compat/linux/linux_ioctl.h +++ b/sys/compat/linux/linux_ioctl.h @@ -247,6 +247,7 @@ #define LINUX_SIOCGIFINDEX 0x8933 #define LINUX_SIOGIFINDEX LINUX_SIOCGIFINDEX #define LINUX_SIOCGIFCOUNT 0x8938 +#define LINUX_SIOCETHTOOL 0x8946 #define LINUX_IOCTL_SOCKET_MIN LINUX_FIOSETOWN #define LINUX_IOCTL_SOCKET_MAX LINUX_SIOCGIFCOUNT diff --git a/sys/compat/linux/linux_ioctl.c b/sys/compat/linux/linux_ioctl.c --- a/sys/compat/linux/linux_ioctl.c +++ b/sys/compat/linux/linux_ioctl.c @@ -2351,6 +2351,58 @@ return (copyout(&lifr, uifr, sizeof(lifr))); } +struct linux_ethtool_cmd { + unsigned int cmd; + unsigned int supported; + unsigned int advertising; + unsigned short speed; + unsigned char duplex; + unsigned char port; + unsigned char phy_address; + unsigned char transceiver; + unsigned char autoneg; + unsigned char mdio_support; + unsigned int maxtxpkt; + unsigned int maxrxpkt; + unsigned short speed_hi; + unsigned char eth_tp_mdix; + unsigned char eth_tp_mdix_ctrl; + unsigned int lp_advertising; + unsigned int reserved[2]; +}; + +static int +linux_ethtool(struct thread *td, struct l_ifreq *ulifr) +{ + struct l_ifreq lifr; + struct linux_ethtool_cmd lecmd, *p_ulecmd = NULL; + int error; + struct epoch_tracker et; + struct ifnet *ifp = NULL; + + error = copyin(ulifr, &lifr, sizeof(lifr)); + if (error != 0) + return (error); + + p_ulecmd = (struct linux_ethtool_cmd *)((uint64_t)(lifr.ifr_ifru.ifru_data)); + if ((error = copyin(p_ulecmd, &lecmd, sizeof(lecmd)))) + return error; + + CURVNET_SET(TD_TO_VNET(td)); + NET_EPOCH_ENTER(et); + ifp = ifname_linux_to_ifp(td, lifr.ifr_name); + if (ifp != NULL) { + lecmd.speed = ifp->if_baudrate / 1000 / 1000; + } + NET_EPOCH_EXIT(et); + CURVNET_RESTORE(); + + if (ifp != NULL) { + return copyout(&lecmd, p_ulecmd, sizeof(lecmd)); + } else { + return EINVAL; + } +} /* * Socket related ioctls */ @@ -2435,6 +2487,10 @@ error = 0; break; + case LINUX_SIOCETHTOOL: + error = linux_ethtool(td, (struct l_ifreq *)args->arg); + break; + default: error = linux_ioctl_socket_ifreq(td, args->fd, args->cmd, PTRIN(args->arg));