Changeset View
Changeset View
Standalone View
Standalone View
head/sys/compat/linux/linux_ioctl.c
Show First 20 Lines • Show All 75 Lines • ▼ Show 20 Lines | |||||
#ifdef COMPAT_LINUX32 | #ifdef COMPAT_LINUX32 | ||||
#include <machine/../linux32/linux.h> | #include <machine/../linux32/linux.h> | ||||
#include <machine/../linux32/linux32_proto.h> | #include <machine/../linux32/linux32_proto.h> | ||||
#else | #else | ||||
#include <machine/../linux/linux.h> | #include <machine/../linux/linux.h> | ||||
#include <machine/../linux/linux_proto.h> | #include <machine/../linux/linux_proto.h> | ||||
#endif | #endif | ||||
#include <compat/linux/linux_common.h> | |||||
#include <compat/linux/linux_ioctl.h> | #include <compat/linux/linux_ioctl.h> | ||||
#include <compat/linux/linux_mib.h> | #include <compat/linux/linux_mib.h> | ||||
#include <compat/linux/linux_socket.h> | #include <compat/linux/linux_socket.h> | ||||
#include <compat/linux/linux_timer.h> | #include <compat/linux/linux_timer.h> | ||||
#include <compat/linux/linux_util.h> | #include <compat/linux/linux_util.h> | ||||
#include <contrib/v4l/videodev.h> | #include <contrib/v4l/videodev.h> | ||||
#include <compat/linux/linux_videodev_compat.h> | #include <compat/linux/linux_videodev_compat.h> | ||||
▲ Show 20 Lines • Show All 2,025 Lines • ▼ Show 20 Lines | default: | ||||
break; | break; | ||||
} | } | ||||
fdrop(fp, td); | fdrop(fp, td); | ||||
return (error); | return (error); | ||||
} | } | ||||
/* | /* | ||||
* Criteria for interface name translation | |||||
*/ | |||||
#define IFP_IS_ETH(ifp) (ifp->if_type == IFT_ETHER) | |||||
/* | |||||
* Translate a Linux interface name to a FreeBSD interface name, | |||||
* and return the associated ifnet structure | |||||
* bsdname and lxname need to be least IFNAMSIZ bytes long, but | |||||
* can point to the same buffer. | |||||
*/ | |||||
static struct ifnet * | |||||
ifname_linux_to_bsd(struct thread *td, const char *lxname, char *bsdname) | |||||
{ | |||||
struct ifnet *ifp; | |||||
int len, unit; | |||||
char *ep; | |||||
int is_eth, index; | |||||
for (len = 0; len < LINUX_IFNAMSIZ; ++len) | |||||
if (!isalpha(lxname[len])) | |||||
break; | |||||
if (len == 0 || len == LINUX_IFNAMSIZ) | |||||
return (NULL); | |||||
unit = (int)strtoul(lxname + len, &ep, 10); | |||||
if (ep == NULL || ep == lxname + len || ep >= lxname + LINUX_IFNAMSIZ) | |||||
return (NULL); | |||||
index = 0; | |||||
is_eth = (len == 3 && !strncmp(lxname, "eth", len)) ? 1 : 0; | |||||
CURVNET_SET(TD_TO_VNET(td)); | |||||
IFNET_RLOCK(); | |||||
CK_STAILQ_FOREACH(ifp, &V_ifnet, if_link) { | |||||
/* | |||||
* Allow Linux programs to use FreeBSD names. Don't presume | |||||
* we never have an interface named "eth", so don't make | |||||
* the test optional based on is_eth. | |||||
*/ | |||||
if (strncmp(ifp->if_xname, lxname, LINUX_IFNAMSIZ) == 0) | |||||
break; | |||||
if (is_eth && IFP_IS_ETH(ifp) && unit == index++) | |||||
break; | |||||
} | |||||
IFNET_RUNLOCK(); | |||||
CURVNET_RESTORE(); | |||||
if (ifp != NULL) | |||||
strlcpy(bsdname, ifp->if_xname, IFNAMSIZ); | |||||
return (ifp); | |||||
} | |||||
/* | |||||
* Implement the SIOCGIFNAME ioctl | * Implement the SIOCGIFNAME ioctl | ||||
*/ | */ | ||||
static int | static int | ||||
linux_ioctl_ifname(struct thread *td, struct l_ifreq *uifr) | linux_ioctl_ifname(struct thread *td, struct l_ifreq *uifr) | ||||
{ | { | ||||
struct l_ifreq ifr; | struct l_ifreq ifr; | ||||
struct ifnet *ifp; | struct ifnet *ifp; | ||||
▲ Show 20 Lines • Show All 144 Lines • ▼ Show 20 Lines | again: | ||||
return (error); | return (error); | ||||
} | } | ||||
static int | static int | ||||
linux_gifflags(struct thread *td, struct ifnet *ifp, struct l_ifreq *ifr) | linux_gifflags(struct thread *td, struct ifnet *ifp, struct l_ifreq *ifr) | ||||
{ | { | ||||
l_short flags; | l_short flags; | ||||
flags = (ifp->if_flags | ifp->if_drv_flags) & 0xffff; | linux_ifflags(ifp, &flags); | ||||
/* these flags have no Linux equivalent */ | |||||
flags &= ~(IFF_DRV_OACTIVE|IFF_SIMPLEX| | |||||
IFF_LINK0|IFF_LINK1|IFF_LINK2); | |||||
/* Linux' multicast flag is in a different bit */ | |||||
if (flags & IFF_MULTICAST) { | |||||
flags &= ~IFF_MULTICAST; | |||||
flags |= 0x1000; | |||||
} | |||||
return (copyout(&flags, &ifr->ifr_flags, sizeof(flags))); | return (copyout(&flags, &ifr->ifr_flags, sizeof(flags))); | ||||
} | } | ||||
#define ARPHRD_ETHER 1 | |||||
#define ARPHRD_LOOPBACK 772 | |||||
static int | static int | ||||
linux_gifhwaddr(struct ifnet *ifp, struct l_ifreq *ifr) | linux_gifhwaddr(struct ifnet *ifp, struct l_ifreq *ifr) | ||||
{ | { | ||||
struct ifaddr *ifa; | |||||
struct sockaddr_dl *sdl; | |||||
struct l_sockaddr lsa; | struct l_sockaddr lsa; | ||||
if (ifp->if_type == IFT_LOOP) { | if (linux_ifhwaddr(ifp, &lsa) != 0) | ||||
bzero(&lsa, sizeof(lsa)); | |||||
lsa.sa_family = ARPHRD_LOOPBACK; | |||||
return (copyout(&lsa, &ifr->ifr_hwaddr, sizeof(lsa))); | |||||
} | |||||
if (ifp->if_type != IFT_ETHER) | |||||
return (ENOENT); | return (ENOENT); | ||||
CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { | |||||
sdl = (struct sockaddr_dl*)ifa->ifa_addr; | |||||
if (sdl != NULL && (sdl->sdl_family == AF_LINK) && | |||||
(sdl->sdl_type == IFT_ETHER)) { | |||||
bzero(&lsa, sizeof(lsa)); | |||||
lsa.sa_family = ARPHRD_ETHER; | |||||
bcopy(LLADDR(sdl), lsa.sa_data, LINUX_IFHWADDRLEN); | |||||
return (copyout(&lsa, &ifr->ifr_hwaddr, sizeof(lsa))); | return (copyout(&lsa, &ifr->ifr_hwaddr, sizeof(lsa))); | ||||
} | |||||
} | |||||
return (ENOENT); | |||||
} | } | ||||
/* | /* | ||||
* If we fault in bsd_to_linux_ifreq() then we will fault when we call | * 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 | * the native ioctl(). Thus, we don't really need to check the return | ||||
* value of this function. | * value of this function. | ||||
*/ | */ | ||||
▲ Show 20 Lines • Show All 1,498 Lines • Show Last 20 Lines |