diff options
Diffstat (limited to 'sys/compat/linux/common/linux_socket.c')
| -rw-r--r-- | sys/compat/linux/common/linux_socket.c | 53 |
1 files changed, 40 insertions, 13 deletions
diff --git a/sys/compat/linux/common/linux_socket.c b/sys/compat/linux/common/linux_socket.c index 7b7e07d3583..2c2e7cdb6d4 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.126 2015/07/24 13:02:52 maxv Exp $ */ +/* $NetBSD: linux_socket.c,v 1.127 2016/05/12 02:24:16 ozaki-r 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.126 2015/07/24 13:02:52 maxv Exp $"); +__KERNEL_RCSID(0, "$NetBSD: linux_socket.c,v 1.127 2016/05/12 02:24:16 ozaki-r Exp $"); #if defined(_KERNEL_OPT) #include "opt_inet.h" @@ -1118,6 +1118,9 @@ linux_getifconf(struct lwp *l, register_t *retval, void *data) int space = 0, error; const int sz = (int)sizeof(ifr); bool docopy; + int s; + int bound = curlwp->l_pflag & LP_BOUND; + struct psref psref; error = copyin(data, &ifc, sizeof(ifc)); if (error) @@ -1129,11 +1132,18 @@ linux_getifconf(struct lwp *l, register_t *retval, void *data) ifrp = ifc.ifc_req; } - IFNET_FOREACH(ifp) { + curlwp->l_pflag |= LP_BOUND; + s = pserialize_read_enter(); + IFNET_READER_FOREACH(ifp) { + psref_acquire(&psref, &ifp->if_psref, ifnet_psref_class); + pserialize_read_exit(s); + (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 (ifr.ifr_name[sizeof(ifr.ifr_name) - 1] != '\0') { + error = ENAMETOOLONG; + goto release_exit; + } if (IFADDR_EMPTY(ifp)) continue; IFADDR_FOREACH(ifa, ifp) { @@ -1147,12 +1157,17 @@ linux_getifconf(struct lwp *l, register_t *retval, void *data) if (space >= sz) { error = copyout(&ifr, ifrp, sz); if (error != 0) - return error; + goto release_exit; ifrp++; } space -= sz; } + + s = pserialize_read_enter(); + psref_release(&psref, &ifp->if_psref, ifnet_psref_class); } + pserialize_read_exit(s); + curlwp->l_pflag ^= bound ^ LP_BOUND; if (docopy) ifc.ifc_len -= space; @@ -1160,6 +1175,11 @@ linux_getifconf(struct lwp *l, register_t *retval, void *data) ifc.ifc_len = -space; return copyout(&ifc, data, sizeof(ifc)); + +release_exit: + psref_release(&psref, &ifp->if_psref, ifnet_psref_class); + curlwp->l_pflag ^= bound ^ LP_BOUND; + return error; } int @@ -1174,6 +1194,7 @@ linux_getifhwaddr(struct lwp *l, register_t *retval, u_int fd, struct sockaddr_dl *sadl; int error, found; int index, ifnum; + int s; /* * We can't emulate this ioctl by calling sys_ioctl() to run @@ -1205,14 +1226,17 @@ linux_getifhwaddr(struct lwp *l, register_t *retval, u_int fd, * Try real interface name first, then fake "ethX" */ found = 0; - IFNET_FOREACH(ifp) { + s = pserialize_read_enter(); + IFNET_READER_FOREACH(ifp) { if (found) break; if (strcmp(lreq.ifr_name, ifp->if_xname)) /* not this interface */ continue; + found=1; if (IFADDR_EMPTY(ifp)) { + pserialize_read_exit(s); error = ENODEV; goto out; } @@ -1228,10 +1252,13 @@ linux_getifhwaddr(struct lwp *l, register_t *retval, u_int fd, sizeof(lreq.ifr_hwaddr.sa_data))); lreq.ifr_hwaddr.sa_family = sadl->sdl_family; + pserialize_read_exit(s); + error = copyout(&lreq, data, sizeof(lreq)); goto out; } } + pserialize_read_exit(s); if (strncmp(lreq.ifr_name, "eth", 3) != 0) { /* unknown interface, not even an "eth*" name */ @@ -1247,10 +1274,8 @@ linux_getifhwaddr(struct lwp *l, register_t *retval, u_int fd, } error = EINVAL; /* in case we don't find one */ - found = 0; - IFNET_FOREACH(ifp) { - if (found) - break; + s = pserialize_read_enter(); + IFNET_READER_FOREACH(ifp) { memcpy(lreq.ifr_name, ifp->if_xname, MIN(LINUX_IFNAMSIZ, IFNAMSIZ)); IFADDR_FOREACH(ifa, ifp) { @@ -1269,11 +1294,13 @@ linux_getifhwaddr(struct lwp *l, register_t *retval, u_int fd, sizeof(lreq.ifr_hwaddr.sa_data))); lreq.ifr_hwaddr.sa_family = sadl->sdl_family; + pserialize_read_exit(s); + error = copyout(&lreq, data, sizeof(lreq)); - found = 1; - break; + goto out; } } + pserialize_read_exit(s); out: KERNEL_UNLOCK_ONE(NULL); |
