diff --git a/sys/net/if.c b/sys/net/if.c --- a/sys/net/if.c +++ b/sys/net/if.c @@ -107,6 +107,8 @@ #include +#include + /* * Consumers of struct ifreq such as tcpdump assume no pad between ifr_name * and ifr_ifru when it is used in SIOCGIFCONF. @@ -1479,34 +1481,44 @@ static int if_getgroup(struct ifgroupreq *ifgr, struct ifnet *ifp) { - int len, error; - struct ifg_list *ifgl; - struct ifg_req ifgrq, *ifgp; - - NET_EPOCH_ASSERT(); + struct epoch_tracker et; + struct ifg_list *ifgl; + struct ifg_req ifgrq, *ifgp; + int len, error; if (ifgr->ifgr_len == 0) { + NET_EPOCH_ENTER(et); CK_STAILQ_FOREACH(ifgl, &ifp->if_groups, ifgl_next) ifgr->ifgr_len += sizeof(struct ifg_req); + NET_EPOCH_EXIT(et); return (0); } + error = vslock(ifgr->ifgr_groups, ifgr->ifgr_len); + if (error != 0) + return (error); + len = ifgr->ifgr_len; ifgp = ifgr->ifgr_groups; - /* XXX: wire */ + NET_EPOCH_ENTER(et); CK_STAILQ_FOREACH(ifgl, &ifp->if_groups, ifgl_next) { - if (len < sizeof(ifgrq)) - return (EINVAL); + if (len < sizeof(ifgrq)) { + error = EINVAL; + break; + } bzero(&ifgrq, sizeof ifgrq); strlcpy(ifgrq.ifgrq_group, ifgl->ifgl_group->ifg_group, sizeof(ifgrq.ifgrq_group)); if ((error = copyout(&ifgrq, ifgp, sizeof(struct ifg_req)))) - return (error); + break; len -= sizeof(ifgrq); ifgp++; } + NET_EPOCH_EXIT(et); - return (0); + vsunlock(ifgr->ifgr_groups, ifgr->ifgr_len); + + return (error); } /* @@ -2756,14 +2768,8 @@ break; } case SIOCGIFGROUP: - { - struct epoch_tracker et; - - NET_EPOCH_ENTER(et); error = if_getgroup((struct ifgroupreq *)data, ifp); - NET_EPOCH_EXIT(et); break; - } case SIOCDIFGROUP: {