Add SIOCGIFHWADDR support.

Tested by Cem Kayali.
This commit is contained in:
njoly 2008-06-27 12:38:25 +00:00
parent c82e679e68
commit 9084eed1a8
2 changed files with 184 additions and 6 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: linux32_socket.c,v 1.7 2008/06/24 09:00:04 njoly Exp $ */
/* $NetBSD: linux32_socket.c,v 1.8 2008/06/27 12:38:25 njoly Exp $ */
/*-
* Copyright (c) 2006 Emmanuel Dreyfus, all rights reserved.
@ -33,7 +33,7 @@
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: linux32_socket.c,v 1.7 2008/06/24 09:00:04 njoly Exp $");
__KERNEL_RCSID(0, "$NetBSD: linux32_socket.c,v 1.8 2008/06/27 12:38:25 njoly Exp $");
#include <sys/types.h>
#include <sys/param.h>
@ -53,6 +53,8 @@ __KERNEL_RCSID(0, "$NetBSD: linux32_socket.c,v 1.7 2008/06/24 09:00:04 njoly Exp
#include <machine/types.h>
#include <net/if.h>
#include <net/if_dl.h>
#include <net/if_types.h>
#include <net/route.h>
#include <netinet/in.h>
@ -64,6 +66,8 @@ __KERNEL_RCSID(0, "$NetBSD: linux32_socket.c,v 1.7 2008/06/24 09:00:04 njoly Exp
#include <compat/netbsd32/netbsd32_ioctl.h>
#include <compat/netbsd32/netbsd32_conv.h>
#include <compat/netbsd32/netbsd32_syscallargs.h>
#include <compat/sys/socket.h>
#include <compat/sys/sockio.h>
#include <compat/linux/common/linux_types.h>
@ -81,9 +85,12 @@ __KERNEL_RCSID(0, "$NetBSD: linux32_socket.c,v 1.7 2008/06/24 09:00:04 njoly Exp
#include <compat/linux32/common/linux32_machdep.h>
#include <compat/linux32/common/linux32_sysctl.h>
#include <compat/linux32/common/linux32_socketcall.h>
#include <compat/linux32/common/linux32_sockio.h>
#include <compat/linux32/common/linux32_ioctl.h>
#include <compat/linux32/linux32_syscallargs.h>
int linux32_getifhwaddr(struct lwp *, register_t *, u_int, void *);
int
linux32_sys_socketpair(struct lwp *l, const struct linux32_sys_socketpair_args *uap, register_t *retval)
{
@ -376,6 +383,123 @@ linux32_sys_recv(struct lwp *l, const struct linux32_sys_recv_args *uap, registe
return sys_recvfrom(l, &ua, retval);
}
int
linux32_getifhwaddr(struct lwp *l, register_t *retval, u_int fd,
void *data)
{
struct linux32_ifreq lreq;
file_t *fp;
struct ifaddr *ifa;
struct ifnet *ifp;
struct sockaddr_dl *sadl;
int error, found;
int index, ifnum;
/*
* We can't emulate this ioctl by calling sys_ioctl() to run
* SIOCGIFCONF, because the user buffer is not of the right
* type to take those results. We can't use kernel buffers to
* receive the results, as the implementation of sys_ioctl()
* and ifconf() [which implements SIOCGIFCONF] use
* copyin()/copyout() which will fail on kernel addresses.
*
* So, we must duplicate code from sys_ioctl() and ifconf(). Ugh.
*/
if ((fp = fd_getfile(fd)) == NULL)
return (EBADF);
KERNEL_LOCK(1, NULL);
if ((fp->f_flag & (FREAD | FWRITE)) == 0) {
error = EBADF;
goto out;
}
error = copyin(data, &lreq, sizeof(lreq));
if (error)
goto out;
lreq.ifr_name[LINUX32_IFNAMSIZ-1] = '\0'; /* just in case */
/*
* Try real interface name first, then fake "ethX"
*/
found = 0;
IFNET_FOREACH(ifp) {
if (found)
break;
if (strcmp(lreq.ifr_name, ifp->if_xname))
/* not this interface */
continue;
found=1;
if (IFADDR_EMPTY(ifp)) {
error = ENODEV;
goto out;
}
IFADDR_FOREACH(ifa, ifp) {
sadl = satosdl(ifa->ifa_addr);
/* only return ethernet addresses */
/* XXX what about FDDI, etc. ? */
if (sadl->sdl_family != AF_LINK ||
sadl->sdl_type != IFT_ETHER)
continue;
memcpy(&lreq.ifr_hwaddr.sa_data, CLLADDR(sadl),
MIN(sadl->sdl_alen,
sizeof(lreq.ifr_hwaddr.sa_data)));
lreq.ifr_hwaddr.sa_family =
sadl->sdl_family;
error = copyout(&lreq, data, sizeof(lreq));
goto out;
}
}
if (strncmp(lreq.ifr_name, "eth", 3) == 0) {
for (ifnum = 0, index = 3;
lreq.ifr_name[index] != '\0' && index < LINUX32_IFNAMSIZ;
index++) {
ifnum *= 10;
ifnum += lreq.ifr_name[index] - '0';
}
error = EINVAL; /* in case we don't find one */
found = 0;
IFNET_FOREACH(ifp) {
if (found)
break;
memcpy(lreq.ifr_name, ifp->if_xname,
MIN(LINUX32_IFNAMSIZ, IFNAMSIZ));
IFADDR_FOREACH(ifa, ifp) {
sadl = satosdl(ifa->ifa_addr);
/* only return ethernet addresses */
/* XXX what about FDDI, etc. ? */
if (sadl->sdl_family != AF_LINK ||
sadl->sdl_type != IFT_ETHER)
continue;
if (ifnum--)
/* not the reqested iface */
continue;
memcpy(&lreq.ifr_hwaddr.sa_data,
CLLADDR(sadl),
MIN(sadl->sdl_alen,
sizeof(lreq.ifr_hwaddr.sa_data)));
lreq.ifr_hwaddr.sa_family =
sadl->sdl_family;
error = copyout(&lreq, data, sizeof(lreq));
found = 1;
break;
}
}
} else {
/* unknown interface, not even an "eth*" name */
error = ENODEV;
}
out:
KERNEL_UNLOCK_ONE(NULL);
fd_putfile(fd);
return error;
}
int
linux32_ioctl_socket(struct lwp *l, const struct linux32_sys_ioctl_args *uap, register_t *retval)
{
@ -455,13 +579,11 @@ linux32_ioctl_socket(struct lwp *l, const struct linux32_sys_ioctl_args *uap, re
case LINUX_SIOCDELMULTI:
SCARG(&ia, com) = OSIOCDELMULTI;
break;
#ifdef notyet
case LINUX_SIOCGIFHWADDR:
error = linux_getifhwaddr(l, retval, SCARG(uap, fd),
SCARG(uap, data));
error = linux32_getifhwaddr(l, retval, SCARG(uap, fd),
SCARG_P32(uap, data));
dosys = 0;
break;
#endif
default:
error = EINVAL;
}

View File

@ -0,0 +1,56 @@
/* $NetBSD: linux32_sockio.h,v 1.1 2008/06/27 12:38:25 njoly Exp $ */
/*
* Copyright (c) 2008 Nicolas Joly
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _LINUX32_SOCKIO_H
#define _LINUX32_SOCKIO_H
#define LINUX32_IFNAMSIZ 16
struct linux32_ifmap {
netbsd32_u_long mem_start;
netbsd32_u_long mem_end;
unsigned short base_addr;
unsigned char irq;
unsigned char dma;
unsigned char port;
};
struct linux32_ifreq {
union {
char ifrn_name[LINUX32_IFNAMSIZ];
} ifr_ifrn;
union {
struct osockaddr ifru_hwaddr;
struct linux32_ifmap ifru_map;
} ifr_ifru;
#define ifr_name ifr_ifrn.ifrn_name /* interface name */
#define ifr_hwaddr ifr_ifru.ifru_hwaddr /* MAC address */
#define ifr_map ifr_ifru.ifru_map /* device map */
};
#endif /* !_LINUX32_SOCKIO_H */