diff options
| author | njoly <njoly@NetBSD.org> | 2008-07-03 14:07:09 +0000 |
|---|---|---|
| committer | njoly <njoly@NetBSD.org> | 2008-07-03 14:07:09 +0000 |
| commit | 153124ee21fc19eb74e09e9cb5aaaafd25915828 (patch) | |
| tree | 3327a7a40578477199551310f4ef0998dede3c88 /sys/compat/linux/common/linux_socket.c | |
| parent | 54745077e8070ef5ababecc434b068f2af90f6e0 (diff) | |
Fix SIOCGIFCONF ioctl for 64bit platforms. Add a new linux_ifreq
structure and linux_getifconf function (cleaned up version from
compat_ifconf).
While here, update linux_getifhwaddr to use the new structure.
Ok by christos.
Diffstat (limited to 'sys/compat/linux/common/linux_socket.c')
| -rw-r--r-- | sys/compat/linux/common/linux_socket.c | 91 |
1 files changed, 69 insertions, 22 deletions
diff --git a/sys/compat/linux/common/linux_socket.c b/sys/compat/linux/common/linux_socket.c index 86265511c2f..7a3d503f51b 100644 --- a/sys/compat/linux/common/linux_socket.c +++ b/sys/compat/linux/common/linux_socket.c @@ -1,4 +1,4 @@ -/* $NetBSD: linux_socket.c,v 1.96 2008/06/24 11:18:15 ad Exp $ */ +/* $NetBSD: linux_socket.c,v 1.97 2008/07/03 14:07:09 njoly Exp $ */ /*- * Copyright (c) 1995, 1998, 2008 The NetBSD Foundation, Inc. @@ -35,7 +35,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: linux_socket.c,v 1.96 2008/06/24 11:18:15 ad Exp $"); +__KERNEL_RCSID(0, "$NetBSD: linux_socket.c,v 1.97 2008/07/03 14:07:09 njoly Exp $"); #if defined(_KERNEL_OPT) #include "opt_inet.h" @@ -116,6 +116,7 @@ int linux_to_bsd_so_sockopt(int); int linux_to_bsd_ip_sockopt(int); int linux_to_bsd_tcp_sockopt(int); int linux_to_bsd_udp_sockopt(int); +int linux_getifconf(struct lwp *, register_t *, void *); int linux_getifhwaddr(struct lwp *, register_t *, u_int, void *); static int linux_get_sa(struct lwp *, int, struct mbuf **, const struct osockaddr *, unsigned int); @@ -966,17 +967,63 @@ linux_sys_getsockopt(struct lwp *l, const struct linux_sys_getsockopt_args *uap, return sys_getsockopt(l, &bga, retval); } -#define IF_NAME_LEN 16 +int +linux_getifconf(struct lwp *l, register_t *retval, void *data) +{ + struct linux_ifreq ifr, *ifrp; + struct ifconf *ifc = data; + struct ifnet *ifp; + struct ifaddr *ifa; + struct sockaddr *sa; + struct osockaddr *osa; + int space, error = 0; + const int sz = (int)sizeof(ifr); + + ifrp = (struct linux_ifreq *)ifc->ifc_req; + if (ifrp == NULL) + space = 0; + else + space = ifc->ifc_len; + + IFNET_FOREACH(ifp) { + (void)strncpy(ifr.ifr_name, ifp->if_xname, + sizeof(ifr.ifr_name)); + if (ifr.ifr_name[sizeof(ifr.ifr_name) - 1] != '\0') + return ENAMETOOLONG; + if (IFADDR_EMPTY(ifp)) + continue; + IFADDR_FOREACH(ifa, ifp) { + sa = ifa->ifa_addr; + if (sa->sa_family != AF_INET || + sa->sa_len > sizeof(*osa)) + continue; + memcpy(&ifr.ifr_addr, sa, sa->sa_len); + osa = (struct osockaddr *)&ifr.ifr_addr; + osa->sa_family = sa->sa_family; + if (space >= sz) { + error = copyout(&ifr, ifrp, sz); + if (error != 0) + return error; + ifrp++; + } + space -= sz; + } + } + + if (ifrp != NULL) + ifc->ifc_len -= space; + else + ifc->ifc_len = -space; + + return 0; +} int linux_getifhwaddr(struct lwp *l, register_t *retval, u_int fd, void *data) { /* Not the full structure, just enough to map what we do here */ - struct linux_ifreq { - char if_name[IF_NAME_LEN]; - struct osockaddr hwaddr; - } lreq; + struct linux_ifreq lreq; file_t *fp; struct ifaddr *ifa; struct ifnet *ifp; @@ -1008,7 +1055,7 @@ linux_getifhwaddr(struct lwp *l, register_t *retval, u_int fd, error = copyin(data, &lreq, sizeof(lreq)); if (error) goto out; - lreq.if_name[IF_NAME_LEN-1] = '\0'; /* just in case */ + lreq.ifr_name[LINUX_IFNAMSIZ-1] = '\0'; /* just in case */ /* * Try real interface name first, then fake "ethX" @@ -1017,7 +1064,7 @@ linux_getifhwaddr(struct lwp *l, register_t *retval, u_int fd, IFNET_FOREACH(ifp) { if (found) break; - if (strcmp(lreq.if_name, ifp->if_xname)) + if (strcmp(lreq.ifr_name, ifp->if_xname)) /* not this interface */ continue; found=1; @@ -1032,22 +1079,22 @@ linux_getifhwaddr(struct lwp *l, register_t *retval, u_int fd, if (sadl->sdl_family != AF_LINK || sadl->sdl_type != IFT_ETHER) continue; - memcpy(&lreq.hwaddr.sa_data, CLLADDR(sadl), + memcpy(&lreq.ifr_hwaddr.sa_data, CLLADDR(sadl), MIN(sadl->sdl_alen, - sizeof(lreq.hwaddr.sa_data))); - lreq.hwaddr.sa_family = + 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.if_name, "eth", 3) == 0) { + if (strncmp(lreq.ifr_name, "eth", 3) == 0) { for (ifnum = 0, index = 3; - lreq.if_name[index] != '\0' && index < IF_NAME_LEN; + lreq.ifr_name[index] != '\0' && index < LINUX_IFNAMSIZ; index++) { ifnum *= 10; - ifnum += lreq.if_name[index] - '0'; + ifnum += lreq.ifr_name[index] - '0'; } error = EINVAL; /* in case we don't find one */ @@ -1055,8 +1102,8 @@ linux_getifhwaddr(struct lwp *l, register_t *retval, u_int fd, IFNET_FOREACH(ifp) { if (found) break; - memcpy(lreq.if_name, ifp->if_xname, - MIN(IF_NAME_LEN, IFNAMSIZ)); + memcpy(lreq.ifr_name, ifp->if_xname, + MIN(LINUX_IFNAMSIZ, IFNAMSIZ)); IFADDR_FOREACH(ifa, ifp) { sadl = satosdl(ifa->ifa_addr); /* only return ethernet addresses */ @@ -1067,11 +1114,11 @@ linux_getifhwaddr(struct lwp *l, register_t *retval, u_int fd, if (ifnum--) /* not the reqested iface */ continue; - memcpy(&lreq.hwaddr.sa_data, + memcpy(&lreq.ifr_hwaddr.sa_data, CLLADDR(sadl), MIN(sadl->sdl_alen, - sizeof(lreq.hwaddr.sa_data))); - lreq.hwaddr.sa_family = + sizeof(lreq.ifr_hwaddr.sa_data))); + lreq.ifr_hwaddr.sa_family = sadl->sdl_family; error = copyout(&lreq, data, sizeof(lreq)); found = 1; @@ -1088,7 +1135,6 @@ out: fd_putfile(fd); return error; } -#undef IF_NAME_LEN int linux_ioctl_socket(struct lwp *l, const struct linux_sys_ioctl_args *uap, register_t *retval) @@ -1143,7 +1189,8 @@ linux_ioctl_socket(struct lwp *l, const struct linux_sys_ioctl_args *uap, regist switch (com) { case LINUX_SIOCGIFCONF: - SCARG(&ia, com) = OOSIOCGIFCONF; + error = linux_getifconf(l, retval, SCARG(uap, data)); + dosys = 0; break; case LINUX_SIOCGIFFLAGS: SCARG(&ia, com) = OSIOCGIFFLAGS; |
