Apply pserialize and psref to struct ifaddr and its variants

This change makes struct ifaddr and its variants (in_ifaddr and in6_ifaddr)
MP-safe by using pserialize and psref. At this moment, pserialize_perform
and psref_target_destroy are disabled because (1) we don't need them
because of softnet_lock (2) they cause a deadlock because of softnet_lock.
So we'll enable them when we remove softnet_lock in the future.
This commit is contained in:
ozaki-r 2016-08-01 03:15:30 +00:00
parent 74fbff1628
commit a403cbd4f5
43 changed files with 1844 additions and 561 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: vmt.c,v 1.13 2016/07/07 09:32:01 ozaki-r Exp $ */
/* $NetBSD: vmt.c,v 1.14 2016/08/01 03:15:30 ozaki-r Exp $ */
/* $OpenBSD: vmt.c,v 1.11 2011/01/27 21:29:25 dtucker Exp $ */
/*
@ -801,15 +801,16 @@ vmt_tclo_tick(void *xarg)
sc->sc_rpc_error = 1;
}
} else if (strcmp(sc->sc_rpc_buf, "Set_Option broadcastIP 1") == 0) {
struct ifaddr *iface_addr = NULL;
struct ifnet *iface;
struct sockaddr_in *guest_ip;
int s;
struct psref psref;
/* find first available ipv4 address */
guest_ip = NULL;
s = pserialize_read_enter();
IFNET_READER_FOREACH(iface) {
struct ifaddr *iface_addr;
/* skip loopback */
if (strncmp(iface->if_xname, "lo", 2) == 0 &&
@ -823,6 +824,7 @@ vmt_tclo_tick(void *xarg)
}
guest_ip = satosin(iface_addr->ifa_addr);
ifa_acquire(iface_addr, &psref);
break;
}
}
@ -834,6 +836,7 @@ vmt_tclo_tick(void *xarg)
device_printf(sc->sc_dev, "unable to send guest IP address\n");
sc->sc_rpc_error = 1;
}
ifa_release(iface_addr, &psref);
if (vm_rpc_send_str(&sc->sc_tclo_rpc, VM_RPC_REPLY_OK) != 0) {
device_printf(sc->sc_dev, "error sending broadcastIP response\n");

View File

@ -1,9 +1,9 @@
/* $NetBSD: uipc_syscalls_40.c,v 1.11 2016/07/07 09:32:02 ozaki-r Exp $ */
/* $NetBSD: uipc_syscalls_40.c,v 1.12 2016/08/01 03:15:30 ozaki-r Exp $ */
/* written by Pavel Cahyna, 2006. Public domain. */
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: uipc_syscalls_40.c,v 1.11 2016/07/07 09:32:02 ozaki-r Exp $");
__KERNEL_RCSID(0, "$NetBSD: uipc_syscalls_40.c,v 1.12 2016/08/01 03:15:30 ozaki-r Exp $");
/*
* System call interface to the socket abstraction.
@ -34,7 +34,6 @@ compat_ifconf(u_long cmd, void *data)
{
struct oifconf *ifc = data;
struct ifnet *ifp;
struct ifaddr *ifa;
struct oifreq ifr, *ifrp = NULL;
int space = 0, error = 0;
const int sz = (int)sizeof(ifr);
@ -51,8 +50,9 @@ compat_ifconf(u_long cmd, void *data)
bound = curlwp_bind();
s = pserialize_read_enter();
IFNET_READER_FOREACH(ifp) {
struct ifaddr *ifa;
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));
@ -74,6 +74,10 @@ compat_ifconf(u_long cmd, void *data)
IFADDR_READER_FOREACH(ifa, ifp) {
struct sockaddr *sa = ifa->ifa_addr;
struct psref psref_ifa;
ifa_acquire(ifa, &psref_ifa);
pserialize_read_exit(s);
#ifdef COMPAT_OSOCK
if (cmd == OOSIOCGIFCONF) {
struct osockaddr *osa =
@ -81,8 +85,11 @@ compat_ifconf(u_long cmd, void *data)
/*
* If it does not fit, we don't bother with it
*/
if (sa->sa_len > sizeof(*osa))
if (sa->sa_len > sizeof(*osa)) {
s = pserialize_read_enter();
ifa_release(ifa, &psref_ifa);
continue;
}
memcpy(&ifr.ifr_addr, sa, sa->sa_len);
osa->sa_family = sa->sa_family;
if (space >= sz) {
@ -112,12 +119,13 @@ compat_ifconf(u_long cmd, void *data)
(char *)&ifrp->ifr_addr);
}
}
s = pserialize_read_enter();
ifa_release(ifa, &psref_ifa);
if (error != 0)
goto release_exit;
space -= sz;
}
s = pserialize_read_enter();
psref_release(&psref, &ifp->if_psref, ifnet_psref_class);
}
pserialize_read_exit(s);
@ -130,6 +138,7 @@ compat_ifconf(u_long cmd, void *data)
return (0);
release_exit:
pserialize_read_exit(s);
psref_release(&psref, &ifp->if_psref, ifnet_psref_class);
curlwp_bindx(bound);
return error;

View File

@ -1,4 +1,4 @@
/* $NetBSD: linux_socket.c,v 1.131 2016/07/07 09:32:02 ozaki-r Exp $ */
/* $NetBSD: linux_socket.c,v 1.132 2016/08/01 03:15:30 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.131 2016/07/07 09:32:02 ozaki-r Exp $");
__KERNEL_RCSID(0, "$NetBSD: linux_socket.c,v 1.132 2016/08/01 03:15:30 ozaki-r Exp $");
#if defined(_KERNEL_OPT)
#include "opt_inet.h"
@ -1117,7 +1117,6 @@ linux_getifconf(struct lwp *l, register_t *retval, void *data)
struct linux_ifreq ifr, *ifrp = NULL;
struct linux_ifconf ifc;
struct ifnet *ifp;
struct ifaddr *ifa;
struct sockaddr *sa;
struct osockaddr *osa;
int space = 0, error;
@ -1140,8 +1139,8 @@ linux_getifconf(struct lwp *l, register_t *retval, void *data)
bound = curlwp_bind();
s = pserialize_read_enter();
IFNET_READER_FOREACH(ifp) {
struct ifaddr *ifa;
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));
@ -1151,23 +1150,32 @@ linux_getifconf(struct lwp *l, register_t *retval, void *data)
}
IFADDR_READER_FOREACH(ifa, ifp) {
struct psref psref_ifa;
ifa_acquire(ifa, &psref_ifa);
pserialize_read_exit(s);
sa = ifa->ifa_addr;
if (sa->sa_family != AF_INET ||
sa->sa_len > sizeof(*osa))
continue;
goto next;
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)
if (error != 0) {
s = pserialize_read_enter();
ifa_release(ifa, &psref_ifa);
goto release_exit;
}
ifrp++;
}
space -= sz;
next:
s = pserialize_read_enter();
ifa_release(ifa, &psref_ifa);
}
s = pserialize_read_enter();
psref_release(&psref, &ifp->if_psref, ifnet_psref_class);
}
pserialize_read_exit(s);
@ -1181,6 +1189,7 @@ linux_getifconf(struct lwp *l, register_t *retval, void *data)
return copyout(&ifc, data, sizeof(ifc));
release_exit:
pserialize_read_exit(s);
psref_release(&psref, &ifp->if_psref, ifnet_psref_class);
curlwp_bindx(bound);
return error;

View File

@ -1,4 +1,4 @@
/* $NetBSD: linux32_socket.c,v 1.25 2016/07/07 09:32:02 ozaki-r Exp $ */
/* $NetBSD: linux32_socket.c,v 1.26 2016/08/01 03:15:30 ozaki-r 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.25 2016/07/07 09:32:02 ozaki-r Exp $");
__KERNEL_RCSID(0, "$NetBSD: linux32_socket.c,v 1.26 2016/08/01 03:15:30 ozaki-r Exp $");
#include <sys/types.h>
#include <sys/param.h>
@ -418,7 +418,6 @@ linux32_getifconf(struct lwp *l, register_t *retval, void *data)
struct linux32_ifreq ifr, *ifrp = NULL;
struct linux32_ifconf ifc;
struct ifnet *ifp;
struct ifaddr *ifa;
struct sockaddr *sa;
struct osockaddr *osa;
int space = 0, error;
@ -441,8 +440,8 @@ linux32_getifconf(struct lwp *l, register_t *retval, void *data)
bound = curlwp_bind();
s = pserialize_read_enter();
IFNET_READER_FOREACH(ifp) {
struct ifaddr *ifa;
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));
@ -452,23 +451,32 @@ linux32_getifconf(struct lwp *l, register_t *retval, void *data)
}
IFADDR_READER_FOREACH(ifa, ifp) {
struct psref psref_ifa;
ifa_acquire(ifa, &psref_ifa);
pserialize_read_exit(s);
sa = ifa->ifa_addr;
if (sa->sa_family != AF_INET ||
sa->sa_len > sizeof(*osa))
continue;
goto next;
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)
if (error != 0) {
s = pserialize_read_enter();
ifa_release(ifa, &psref_ifa);
goto release_exit;
}
ifrp++;
}
space -= sz;
next:
s = pserialize_read_enter();
ifa_release(ifa, &psref_ifa);
}
s = pserialize_read_enter();
psref_release(&psref, &ifp->if_psref, ifnet_psref_class);
}
pserialize_read_exit(s);
@ -482,6 +490,7 @@ linux32_getifconf(struct lwp *l, register_t *retval, void *data)
return copyout(&ifc, data, sizeof(ifc));
release_exit:
pserialize_read_exit(s);
psref_release(&psref, &ifp->if_psref, ifnet_psref_class);
curlwp_bindx(bound);
return error;

View File

@ -1,4 +1,4 @@
/* $NetBSD: if.c,v 1.356 2016/07/22 07:13:56 knakahara Exp $ */
/* $NetBSD: if.c,v 1.357 2016/08/01 03:15:30 ozaki-r Exp $ */
/*-
* Copyright (c) 1999, 2000, 2001, 2008 The NetBSD Foundation, Inc.
@ -90,7 +90,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: if.c,v 1.356 2016/07/22 07:13:56 knakahara Exp $");
__KERNEL_RCSID(0, "$NetBSD: if.c,v 1.357 2016/08/01 03:15:30 ozaki-r Exp $");
#if defined(_KERNEL_OPT)
#include "opt_inet.h"
@ -183,6 +183,8 @@ static kmutex_t if_clone_mtx;
struct ifnet *lo0ifp;
int ifqmaxlen = IFQ_MAXLEN;
struct psref_class *ifa_psref_class __read_mostly;
static int if_rt_walktree(struct rtentry *, void *);
static struct if_clone *if_clone_lookup(const char *, int *);
@ -281,11 +283,14 @@ void
ifinit1(void)
{
mutex_init(&if_clone_mtx, MUTEX_DEFAULT, IPL_NONE);
TAILQ_INIT(&ifnet_list);
mutex_init(&ifnet_mtx, MUTEX_DEFAULT, IPL_NONE);
ifnet_psz = pserialize_create();
ifnet_psref_class = psref_class_create("ifnet", IPL_SOFTNET);
ifa_psref_class = psref_class_create("ifa", IPL_SOFTNET);
PSLIST_INIT(&ifnet_pslist);
if_indexlim = 8;
if_pfil = pfil_head_create(PFIL_TYPE_IFNET, NULL);
@ -427,6 +432,7 @@ if_dl_create(const struct ifnet *ifp, const struct sockaddr_dl **sdlp)
ifa->ifa_rtrequest = link_rtrequest;
ifa->ifa_addr = (struct sockaddr *)sdl;
ifa->ifa_netmask = (struct sockaddr *)mask;
ifa_psref_init(ifa);
*sdlp = sdl;
@ -486,20 +492,34 @@ if_deactivate_sadl(struct ifnet *ifp)
}
void
if_activate_sadl(struct ifnet *ifp, struct ifaddr *ifa,
if_activate_sadl(struct ifnet *ifp, struct ifaddr *ifa0,
const struct sockaddr_dl *sdl)
{
int s;
int s, ss;
struct ifaddr *ifa;
int bound = curlwp_bind();
s = splnet();
if_deactivate_sadl(ifp);
if_sadl_setrefs(ifp, ifa);
IFADDR_READER_FOREACH(ifa, ifp)
if_sadl_setrefs(ifp, ifa0);
ss = pserialize_read_enter();
IFADDR_READER_FOREACH(ifa, ifp) {
struct psref psref;
ifa_acquire(ifa, &psref);
pserialize_read_exit(ss);
rtinit(ifa, RTM_LLINFO_UPD, 0);
ss = pserialize_read_enter();
ifa_release(ifa, &psref);
}
pserialize_read_exit(ss);
splx(s);
curlwp_bindx(bound);
}
/*
@ -1023,13 +1043,20 @@ void
if_purgeaddrs(struct ifnet *ifp, int family, void (*purgeaddr)(struct ifaddr *))
{
struct ifaddr *ifa, *nifa;
int s;
s = pserialize_read_enter();
for (ifa = IFADDR_READER_FIRST(ifp); ifa; ifa = nifa) {
nifa = IFADDR_READER_NEXT(ifa);
if (ifa->ifa_addr->sa_family != family)
continue;
pserialize_read_exit(s);
(*purgeaddr)(ifa);
s = pserialize_read_enter();
}
pserialize_read_exit(s);
}
#ifdef IFAREF_DEBUG
@ -1134,6 +1161,10 @@ if_detach(struct ifnet *ifp)
pserialize_perform(ifnet_psz);
IFNET_UNLOCK();
/* Wait for all readers to drain before freeing. */
psref_target_destroy(&ifp->if_psref, ifnet_psref_class);
PSLIST_ENTRY_DESTROY(ifp, if_pslist_entry);
mutex_obj_free(ifp->if_ioctl_lock);
ifp->if_ioctl_lock = NULL;
@ -1178,6 +1209,10 @@ if_detach(struct ifnet *ifp)
* least one ifaddr.
*/
again:
/*
* At this point, no other one tries to remove ifa in the list,
* so we don't need to take a lock or psref.
*/
IFADDR_READER_FOREACH(ifa, ifp) {
family = ifa->ifa_addr->sa_family;
#ifdef IFAREF_DEBUG
@ -1303,10 +1338,6 @@ again:
xc = xc_broadcast(0, (xcfunc_t)nullop, NULL, NULL);
xc_wait(xc);
/* Wait for all readers to drain before freeing. */
psref_target_destroy(&ifp->if_psref, ifnet_psref_class);
PSLIST_ENTRY_DESTROY(ifp, if_pslist_entry);
if (ifp->if_percpuq != NULL) {
if_percpuq_destroy(ifp->if_percpuq);
ifp->if_percpuq = NULL;
@ -1542,6 +1573,13 @@ if_clone_list(int buf_count, char *buffer, int *total)
return error;
}
void
ifa_psref_init(struct ifaddr *ifa)
{
psref_target_init(&ifa->ifa_psref, ifa_psref_class);
}
void
ifaref(struct ifaddr *ifa)
{
@ -1562,24 +1600,63 @@ ifafree(struct ifaddr *ifa)
void
ifa_insert(struct ifnet *ifp, struct ifaddr *ifa)
{
ifa->ifa_ifp = ifp;
IFNET_LOCK();
TAILQ_INSERT_TAIL(&ifp->if_addrlist, ifa, ifa_list);
IFADDR_ENTRY_INIT(ifa);
IFADDR_WRITER_INSERT_TAIL(ifp, ifa);
IFNET_UNLOCK();
ifaref(ifa);
}
void
ifa_remove(struct ifnet *ifp, struct ifaddr *ifa)
{
KASSERT(ifa->ifa_ifp == ifp);
IFNET_LOCK();
TAILQ_REMOVE(&ifp->if_addrlist, ifa, ifa_list);
IFADDR_WRITER_REMOVE(ifa);
/* TODO psref_target_destroy */
IFADDR_ENTRY_DESTROY(ifa);
#if notyet
pserialize_perform(ifnet_psz);
#endif
IFNET_UNLOCK();
#if notyet
psref_target_destroy(&ifa->ifa_psref, ifa_psref_class);
#endif
ifafree(ifa);
}
void
ifa_acquire(struct ifaddr *ifa, struct psref *psref)
{
psref_acquire(psref, &ifa->ifa_psref, ifa_psref_class);
}
void
ifa_release(struct ifaddr *ifa, struct psref *psref)
{
if (ifa == NULL)
return;
psref_release(psref, &ifa->ifa_psref, ifa_psref_class);
}
bool
ifa_held(struct ifaddr *ifa)
{
return psref_held(&ifa->ifa_psref, ifa_psref_class);
}
static inline int
equal(const struct sockaddr *sa1, const struct sockaddr *sa2)
{
@ -1595,9 +1672,7 @@ ifa_ifwithaddr(const struct sockaddr *addr)
{
struct ifnet *ifp;
struct ifaddr *ifa;
int s;
s = pserialize_read_enter();
IFNET_READER_FOREACH(ifp) {
if (if_is_deactivated(ifp))
continue;
@ -1614,10 +1689,23 @@ ifa_ifwithaddr(const struct sockaddr *addr)
return ifa;
}
}
pserialize_read_exit(s);
return NULL;
}
struct ifaddr *
ifa_ifwithaddr_psref(const struct sockaddr *addr, struct psref *psref)
{
struct ifaddr *ifa;
int s = pserialize_read_enter();
ifa = ifa_ifwithaddr(addr);
if (ifa != NULL)
ifa_acquire(ifa, psref);
pserialize_read_exit(s);
return ifa;
}
/*
* Locate the point to point interface with a given destination address.
*/
@ -1627,9 +1715,7 @@ ifa_ifwithdstaddr(const struct sockaddr *addr)
{
struct ifnet *ifp;
struct ifaddr *ifa;
int s;
s = pserialize_read_enter();
IFNET_READER_FOREACH(ifp) {
if (if_is_deactivated(ifp))
continue;
@ -1643,10 +1729,25 @@ ifa_ifwithdstaddr(const struct sockaddr *addr)
return ifa;
}
}
pserialize_read_exit(s);
return NULL;
}
struct ifaddr *
ifa_ifwithdstaddr_psref(const struct sockaddr *addr, struct psref *psref)
{
struct ifaddr *ifa;
int s;
s = pserialize_read_enter();
ifa = ifa_ifwithdstaddr(addr);
if (ifa != NULL)
ifa_acquire(ifa, psref);
pserialize_read_exit(s);
return ifa;
}
/*
* Find an interface on a specific network. If many, choice
* is most specific found.
@ -1655,12 +1756,10 @@ struct ifaddr *
ifa_ifwithnet(const struct sockaddr *addr)
{
struct ifnet *ifp;
struct ifaddr *ifa;
struct ifaddr *ifa, *ifa_maybe = NULL;
const struct sockaddr_dl *sdl;
struct ifaddr *ifa_maybe = 0;
u_int af = addr->sa_family;
const char *addr_data = addr->sa_data, *cplim;
int s;
if (af == AF_LINK) {
sdl = satocsdl(addr);
@ -1674,7 +1773,6 @@ ifa_ifwithnet(const struct sockaddr *addr)
if (af == AF_APPLETALK) {
const struct sockaddr_at *sat, *sat2;
sat = (const struct sockaddr_at *)addr;
s = pserialize_read_enter();
IFNET_READER_FOREACH(ifp) {
if (if_is_deactivated(ifp))
continue;
@ -1689,11 +1787,9 @@ ifa_ifwithnet(const struct sockaddr *addr)
ifa_maybe = ifa;
}
}
pserialize_read_exit(s);
return ifa_maybe;
}
#endif
s = pserialize_read_enter();
IFNET_READER_FOREACH(ifp) {
if (if_is_deactivated(ifp))
continue;
@ -1720,10 +1816,24 @@ ifa_ifwithnet(const struct sockaddr *addr)
ifa_maybe = ifa;
}
}
pserialize_read_exit(s);
return ifa_maybe;
}
struct ifaddr *
ifa_ifwithnet_psref(const struct sockaddr *addr, struct psref *psref)
{
struct ifaddr *ifa;
int s;
s = pserialize_read_enter();
ifa = ifa_ifwithnet(addr);
if (ifa != NULL)
ifa_acquire(ifa, psref);
pserialize_read_exit(s);
return ifa;
}
/*
* Find the interface of the addresss.
*/
@ -1738,6 +1848,21 @@ ifa_ifwithladdr(const struct sockaddr *addr)
return NULL;
}
struct ifaddr *
ifa_ifwithladdr_psref(const struct sockaddr *addr, struct psref *psref)
{
struct ifaddr *ifa;
int s;
s = pserialize_read_enter();
ifa = ifa_ifwithladdr(addr);
if (ifa != NULL)
ifa_acquire(ifa, psref);
pserialize_read_exit(s);
return ifa;
}
/*
* Find an interface using a specific address family
*/
@ -1806,6 +1931,22 @@ ifaof_ifpforaddr(const struct sockaddr *addr, struct ifnet *ifp)
return ifa_maybe;
}
struct ifaddr *
ifaof_ifpforaddr_psref(const struct sockaddr *addr, struct ifnet *ifp,
struct psref *psref)
{
struct ifaddr *ifa;
int s;
s = pserialize_read_enter();
ifa = ifaof_ifpforaddr(addr, ifp);
if (ifa != NULL)
ifa_acquire(ifa, psref);
pserialize_read_exit(s);
return ifa;
}
/*
* Default action when installing a route with a Link Level gateway.
* Lookup an appropriate real ifa to point to.
@ -1817,14 +1958,16 @@ link_rtrequest(int cmd, struct rtentry *rt, const struct rt_addrinfo *info)
struct ifaddr *ifa;
const struct sockaddr *dst;
struct ifnet *ifp;
struct psref psref;
if (cmd != RTM_ADD || (ifa = rt->rt_ifa) == NULL ||
(ifp = ifa->ifa_ifp) == NULL || (dst = rt_getkey(rt)) == NULL)
return;
if ((ifa = ifaof_ifpforaddr(dst, ifp)) != NULL) {
if ((ifa = ifaof_ifpforaddr_psref(dst, ifp, &psref)) != NULL) {
rt_replace_ifa(rt, ifa);
if (ifa->ifa_rtrequest && ifa->ifa_rtrequest != link_rtrequest)
ifa->ifa_rtrequest(cmd, rt, info);
ifa_release(ifa, &psref);
}
}
@ -2026,6 +2169,7 @@ p2p_rtrequest(int req, struct rtentry *rt,
{
struct ifnet *ifp = rt->rt_ifp;
struct ifaddr *ifa, *lo0ifa;
int s = pserialize_read_enter();
switch (req) {
case RTM_ADD:
@ -2064,6 +2208,7 @@ p2p_rtrequest(int req, struct rtentry *rt,
default:
break;
}
pserialize_read_exit(s);
}
/*
@ -2076,11 +2221,26 @@ if_down(struct ifnet *ifp)
{
struct ifaddr *ifa;
struct domain *dp;
int s, bound;
struct psref psref;
ifp->if_flags &= ~IFF_UP;
nanotime(&ifp->if_lastchange);
IFADDR_READER_FOREACH(ifa, ifp)
bound = curlwp_bind();
s = pserialize_read_enter();
IFADDR_READER_FOREACH(ifa, ifp) {
ifa_acquire(ifa, &psref);
pserialize_read_exit(s);
pfctlinput(PRC_IFDOWN, ifa->ifa_addr);
s = pserialize_read_enter();
ifa_release(ifa, &psref);
}
pserialize_read_exit(s);
curlwp_bindx(bound);
IFQ_PURGE(&ifp->if_snd);
#if NCARP > 0
if (ifp->if_carp)
@ -2296,7 +2456,12 @@ if_put(const struct ifnet *ifp, struct psref *psref)
ifnet_t *
if_byindex(u_int idx)
{
return (idx < if_indexlim) ? ifindex2ifnet[idx] : NULL;
ifnet_t *ifp;
ifp = (idx < if_indexlim) ? ifindex2ifnet[idx] : NULL;
if (ifp != NULL && if_is_deactivated(ifp))
ifp = NULL;
return ifp;
}
/*
@ -2312,6 +2477,8 @@ if_get_byindex(u_int idx, struct psref *psref)
s = pserialize_read_enter();
ifp = (__predict_true(idx < if_indexlim)) ? ifindex2ifnet[idx] : NULL;
if (ifp != NULL && if_is_deactivated(ifp))
ifp = NULL;
if (__predict_true(ifp != NULL))
psref_acquire(psref, &ifp->if_psref, ifnet_psref_class);
pserialize_read_exit(s);
@ -2503,6 +2670,7 @@ ifaddrpref_ioctl(struct socket *so, u_long cmd, void *data, struct ifnet *ifp)
struct sockaddr sa;
struct sockaddr_storage ss;
} u, v;
int s, error = 0;
switch (cmd) {
case SIOCSIFADDRPREF:
@ -2531,6 +2699,7 @@ ifaddrpref_ioctl(struct socket *so, u_long cmd, void *data, struct ifnet *ifp)
sockaddr_externalize(&v.sa, sizeof(v.ss), sa);
s = pserialize_read_enter();
IFADDR_READER_FOREACH(ifa, ifp) {
if (ifa->ifa_addr->sa_family != sa->sa_family)
continue;
@ -2538,22 +2707,27 @@ ifaddrpref_ioctl(struct socket *so, u_long cmd, void *data, struct ifnet *ifp)
if (sockaddr_cmp(&u.sa, &v.sa) == 0)
break;
}
if (ifa == NULL)
return EADDRNOTAVAIL;
if (ifa == NULL) {
error = EADDRNOTAVAIL;
goto out;
}
switch (cmd) {
case SIOCSIFADDRPREF:
ifa->ifa_preference = ifap->ifap_preference;
return 0;
goto out;
case SIOCGIFADDRPREF:
/* fill in the if_laddrreq structure */
(void)sockaddr_copy(sstosa(&ifap->ifap_addr),
sizeof(ifap->ifap_addr), ifa->ifa_addr);
ifap->ifap_preference = ifa->ifa_preference;
return 0;
goto out;
default:
return EOPNOTSUPP;
error = EOPNOTSUPP;
}
out:
pserialize_read_exit(s);
return error;
}
/*

View File

@ -1,4 +1,4 @@
/* $NetBSD: if.h,v 1.223 2016/08/01 02:50:03 ozaki-r Exp $ */
/* $NetBSD: if.h,v 1.224 2016/08/01 03:15:30 ozaki-r Exp $ */
/*-
* Copyright (c) 1999, 2000, 2001 The NetBSD Foundation, Inc.
@ -598,6 +598,7 @@ struct ifaddr {
int16_t ifa_preference; /* preference level for this address */
#ifdef _KERNEL
struct pslist_entry ifa_pslist_entry;
struct psref_target ifa_psref;
#endif
};
#define IFA_ROUTE RTF_UP /* (0x01) route installed */
@ -984,17 +985,29 @@ void
void ifa_insert(struct ifnet *, struct ifaddr *);
void ifa_remove(struct ifnet *, struct ifaddr *);
void ifa_psref_init(struct ifaddr *);
void ifa_acquire(struct ifaddr *, struct psref *);
void ifa_release(struct ifaddr *, struct psref *);
bool ifa_held(struct ifaddr *);
void ifaref(struct ifaddr *);
void ifafree(struct ifaddr *);
struct ifaddr *ifa_ifwithaddr(const struct sockaddr *);
struct ifaddr *ifa_ifwithaddr_psref(const struct sockaddr *, struct psref *);
struct ifaddr *ifa_ifwithaf(int);
struct ifaddr *ifa_ifwithdstaddr(const struct sockaddr *);
struct ifaddr *ifa_ifwithdstaddr_psref(const struct sockaddr *,
struct psref *);
struct ifaddr *ifa_ifwithnet(const struct sockaddr *);
struct ifaddr *ifa_ifwithnet_psref(const struct sockaddr *, struct psref *);
struct ifaddr *ifa_ifwithladdr(const struct sockaddr *);
struct ifaddr *ifa_ifwithroute(int, const struct sockaddr *,
const struct sockaddr *);
struct ifaddr *ifa_ifwithladdr_psref(const struct sockaddr *, struct psref *);
struct ifaddr *ifa_ifwithroute_psref(int, const struct sockaddr *,
const struct sockaddr *, struct psref *);
struct ifaddr *ifaof_ifpforaddr(const struct sockaddr *, struct ifnet *);
struct ifaddr *ifaof_ifpforaddr_psref(const struct sockaddr *, struct ifnet *,
struct psref *);
void link_rtrequest(int, struct rtentry *, const struct rt_addrinfo *);
void p2p_rtrequest(int, struct rtentry *, const struct rt_addrinfo *);

View File

@ -1,4 +1,4 @@
/* $NetBSD: if_ethersubr.c,v 1.226 2016/07/25 23:46:09 rjs Exp $ */
/* $NetBSD: if_ethersubr.c,v 1.227 2016/08/01 03:15:30 ozaki-r Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@ -61,7 +61,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: if_ethersubr.c,v 1.226 2016/07/25 23:46:09 rjs Exp $");
__KERNEL_RCSID(0, "$NetBSD: if_ethersubr.c,v 1.227 2016/08/01 03:15:30 ozaki-r Exp $");
#ifdef _KERNEL_OPT
#include "opt_inet.h"
@ -218,12 +218,17 @@ ether_output(struct ifnet * const ifp0, struct mbuf * const m0,
#if NCARP > 0
if (ifp->if_type == IFT_CARP) {
struct ifaddr *ifa;
int s = pserialize_read_enter();
/* loop back if this is going to the carp interface */
if (dst != NULL && ifp0->if_link_state == LINK_STATE_UP &&
(ifa = ifa_ifwithaddr(dst)) != NULL &&
ifa->ifa_ifp == ifp0)
return looutput(ifp0, m, dst, rt);
(ifa = ifa_ifwithaddr(dst)) != NULL) {
if (ifa->ifa_ifp == ifp0) {
pserialize_read_exit(s);
return looutput(ifp0, m, dst, rt);
}
}
pserialize_read_exit(s);
ifp = ifp->if_carpdev;
/* ac = (struct arpcom *)ifp; */
@ -298,7 +303,10 @@ ether_output(struct ifnet * const ifp0, struct mbuf * const m0,
break;
#endif
#ifdef NETATALK
case AF_APPLETALK:
case AF_APPLETALK: {
struct ifaddr *ifa;
int s;
KERNEL_LOCK(1, NULL);
if (!aarpresolve(ifp, m, (const struct sockaddr_at *)dst, edst)) {
#ifdef NETATALKDEBUG
@ -310,12 +318,14 @@ ether_output(struct ifnet * const ifp0, struct mbuf * const m0,
/*
* ifaddr is the first thing in at_ifaddr
*/
aa = (struct at_ifaddr *) at_ifawithnet(
(const struct sockaddr_at *)dst, ifp);
if (aa == NULL) {
KERNEL_UNLOCK_ONE(NULL);
goto bad;
s = pserialize_read_enter();
ifa = at_ifawithnet((const struct sockaddr_at *)dst, ifp);
if (ifa == NULL) {
pserialize_read_exit(s);
KERNEL_UNLOCK_ONE(NULL);
goto bad;
}
aa = (struct at_ifaddr *)ifa;
/*
* In the phase 2 case, we need to prepend an mbuf for the
@ -336,8 +346,10 @@ ether_output(struct ifnet * const ifp0, struct mbuf * const m0,
} else {
etype = htons(ETHERTYPE_ATALK);
}
pserialize_read_exit(s);
KERNEL_UNLOCK_ONE(NULL);
break;
}
#endif /* NETATALK */
case pseudo_AF_HDRCMPLT:
hdrcmplt = 1;

View File

@ -1,4 +1,4 @@
/* $NetBSD: if_fddisubr.c,v 1.99 2016/04/28 00:16:56 ozaki-r Exp $ */
/* $NetBSD: if_fddisubr.c,v 1.100 2016/08/01 03:15:30 ozaki-r Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@ -96,7 +96,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: if_fddisubr.c,v 1.99 2016/04/28 00:16:56 ozaki-r Exp $");
__KERNEL_RCSID(0, "$NetBSD: if_fddisubr.c,v 1.100 2016/08/01 03:15:30 ozaki-r Exp $");
#ifdef _KERNEL_OPT
#include "opt_gateway.h"
@ -203,10 +203,16 @@ fddi_output(struct ifnet *ifp0, struct mbuf *m0, const struct sockaddr *dst,
struct ifaddr *ifa;
/* loop back if this is going to the carp interface */
if (dst != NULL && ifp0->if_link_state == LINK_STATE_UP &&
(ifa = ifa_ifwithaddr(dst)) != NULL &&
ifa->ifa_ifp == ifp0)
return (looutput(ifp0, m, dst, rt));
if (dst != NULL && ifp0->if_link_state == LINK_STATE_UP) {
int s = pserialize_read_enter();
ifa = ifa_ifwithaddr(dst);
if (ifa != NULL &&
ifa->ifa_ifp == ifp0) {
pserialize_read_exit(s);
return (looutput(ifp0, m, dst, rt));
}
pserialize_read_exit(s);
}
ifp = ifp->if_carpdev;
/* ac = (struct arpcom *)ifp; */
@ -285,6 +291,9 @@ fddi_output(struct ifnet *ifp0, struct mbuf *m0, const struct sockaddr *dst,
#ifdef NETATALK
case AF_APPLETALK: {
struct at_ifaddr *aa;
struct ifaddr *ifa;
int s;
if (!aarpresolve(ifp, m, (const struct sockaddr_at *)dst, edst)) {
#ifdef NETATALKDEBUG
printf("aarpresolv: failed\n");
@ -294,9 +303,13 @@ fddi_output(struct ifnet *ifp0, struct mbuf *m0, const struct sockaddr *dst,
/*
* ifaddr is the first thing in at_ifaddr
*/
if ((aa = (struct at_ifaddr *)at_ifawithnet(
(const struct sockaddr_at *)dst, ifp)) == NULL)
s = pserialize_read_enter();
ifa = at_ifawithnet((const struct sockaddr_at *)dst, ifp);
if (ifa == NULL) {
pserialize_read_exit(s);
goto bad;
}
aa = (struct at_ifaddr *)ifa;
/*
* In the phase 2 case, we need to prepend an mbuf for the llc
@ -320,6 +333,7 @@ fddi_output(struct ifnet *ifp0, struct mbuf *m0, const struct sockaddr *dst,
} else {
etype = htons(ETHERTYPE_ATALK);
}
pserialize_read_exit(s);
break;
}
#endif /* NETATALK */

View File

@ -1,4 +1,4 @@
/* $NetBSD: if_stf.c,v 1.96 2016/07/08 04:33:30 ozaki-r Exp $ */
/* $NetBSD: if_stf.c,v 1.97 2016/08/01 03:15:30 ozaki-r Exp $ */
/* $KAME: if_stf.c,v 1.62 2001/06/07 22:32:16 itojun Exp $ */
/*
@ -75,7 +75,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: if_stf.c,v 1.96 2016/07/08 04:33:30 ozaki-r Exp $");
__KERNEL_RCSID(0, "$NetBSD: if_stf.c,v 1.97 2016/08/01 03:15:30 ozaki-r Exp $");
#ifdef _KERNEL_OPT
#include "opt_inet.h"
@ -312,9 +312,10 @@ stf_getsrcifa6(struct ifnet *ifp)
struct in_ifaddr *ia4;
struct sockaddr_in6 *sin6;
struct in_addr in;
int s;
IFADDR_READER_FOREACH(ifa, ifp)
{
s = pserialize_read_enter();
IFADDR_READER_FOREACH(ifa, ifp) {
if (ifa->ifa_addr->sa_family != AF_INET6)
continue;
sin6 = (struct sockaddr_in6 *)ifa->ifa_addr;
@ -326,8 +327,11 @@ stf_getsrcifa6(struct ifnet *ifp)
if (ia4 == NULL)
continue;
pserialize_read_exit(s);
/* TODO NOMPSAFE */
return (struct in6_ifaddr *)ifa;
}
pserialize_read_exit(s);
return NULL;
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: if_tokensubr.c,v 1.76 2016/04/28 00:16:56 ozaki-r Exp $ */
/* $NetBSD: if_tokensubr.c,v 1.77 2016/08/01 03:15:30 ozaki-r Exp $ */
/*
* Copyright (c) 1982, 1989, 1993
@ -92,7 +92,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: if_tokensubr.c,v 1.76 2016/04/28 00:16:56 ozaki-r Exp $");
__KERNEL_RCSID(0, "$NetBSD: if_tokensubr.c,v 1.77 2016/08/01 03:15:30 ozaki-r Exp $");
#ifdef _KERNEL_OPT
#include "opt_inet.h"
@ -175,10 +175,16 @@ token_output(struct ifnet *ifp0, struct mbuf *m0, const struct sockaddr *dst,
struct ifaddr *ifa;
/* loop back if this is going to the carp interface */
if (dst != NULL && ifp0->if_link_state == LINK_STATE_UP &&
(ifa = ifa_ifwithaddr(dst)) != NULL &&
ifa->ifa_ifp == ifp0)
return (looutput(ifp0, m, dst, rt));
if (dst != NULL && ifp0->if_link_state == LINK_STATE_UP) {
int s = pserialize_read_enter();
ifa = ifa_ifwithaddr(dst);
if (ifa != NULL &&
ifa->ifa_ifp == ifp0) {
pserialize_read_exit(s);
return (looutput(ifp0, m, dst, rt));
}
pserialize_read_exit(s);
}
ifp = ifp->if_carpdev;
ah = (struct arphdr *)ifp;

View File

@ -1,4 +1,4 @@
/* $NetBSD: route.c,v 1.172 2016/07/15 09:25:47 martin Exp $ */
/* $NetBSD: route.c,v 1.173 2016/08/01 03:15:30 ozaki-r Exp $ */
/*-
* Copyright (c) 1998, 2008 The NetBSD Foundation, Inc.
@ -96,7 +96,7 @@
#endif
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: route.c,v 1.172 2016/07/15 09:25:47 martin Exp $");
__KERNEL_RCSID(0, "$NetBSD: route.c,v 1.173 2016/08/01 03:15:30 ozaki-r Exp $");
#include <sys/param.h>
#ifdef RTFLUSH_DEBUG
@ -495,9 +495,10 @@ rtredirect(const struct sockaddr *dst, const struct sockaddr *gateway,
uint64_t *stat = NULL;
struct rt_addrinfo info;
struct ifaddr *ifa;
struct psref psref;
/* verify the gateway is directly reachable */
if ((ifa = ifa_ifwithnet(gateway)) == NULL) {
if ((ifa = ifa_ifwithnet_psref(gateway, &psref)) == NULL) {
error = ENETUNREACH;
goto out;
}
@ -511,8 +512,15 @@ rtredirect(const struct sockaddr *dst, const struct sockaddr *gateway,
if (!(flags & RTF_DONE) && rt &&
(sockaddr_cmp(src, rt->rt_gateway) != 0 || rt->rt_ifa != ifa))
error = EINVAL;
else if (ifa_ifwithaddr(gateway))
error = EHOSTUNREACH;
else {
int s = pserialize_read_enter();
struct ifaddr *_ifa;
_ifa = ifa_ifwithaddr(gateway);
if (_ifa != NULL)
error = EHOSTUNREACH;
pserialize_read_exit(s);
}
if (error)
goto done;
/*
@ -580,6 +588,7 @@ out:
info.rti_info[RTAX_NETMASK] = netmask;
info.rti_info[RTAX_AUTHOR] = src;
rt_missmsg(RTM_REDIRECT, &info, flags, error);
ifa_release(ifa, &psref);
}
/*
@ -610,10 +619,11 @@ rtdeletemsg(struct rtentry *rt)
}
struct ifaddr *
ifa_ifwithroute(int flags, const struct sockaddr *dst,
const struct sockaddr *gateway)
ifa_ifwithroute_psref(int flags, const struct sockaddr *dst,
const struct sockaddr *gateway, struct psref *psref)
{
struct ifaddr *ifa;
struct ifaddr *ifa = NULL;
if ((flags & RTF_GATEWAY) == 0) {
/*
* If we are adding a route to an interface,
@ -622,35 +632,55 @@ ifa_ifwithroute(int flags, const struct sockaddr *dst,
* as our clue to the interface. Otherwise
* we can use the local address.
*/
ifa = NULL;
if ((flags & RTF_HOST) && gateway->sa_family != AF_LINK)
ifa = ifa_ifwithdstaddr(dst);
ifa = ifa_ifwithdstaddr_psref(dst, psref);
if (ifa == NULL)
ifa = ifa_ifwithaddr(gateway);
ifa = ifa_ifwithaddr_psref(gateway, psref);
} else {
/*
* If we are adding a route to a remote net
* or host, the gateway may still be on the
* other end of a pt to pt link.
*/
ifa = ifa_ifwithdstaddr(gateway);
ifa = ifa_ifwithdstaddr_psref(gateway, psref);
}
if (ifa == NULL)
ifa = ifa_ifwithnet(gateway);
ifa = ifa_ifwithnet_psref(gateway, psref);
if (ifa == NULL) {
struct rtentry *rt = rtalloc1(dst, 0);
int s;
struct rtentry *rt;
rt = rtalloc1(dst, 0);
if (rt == NULL)
return NULL;
ifa = rt->rt_ifa;
/*
* Just in case. May not need to do this workaround.
* Revisit when working on rtentry MP-ification.
*/
s = pserialize_read_enter();
IFADDR_READER_FOREACH(ifa, rt->rt_ifp) {
if (ifa == rt->rt_ifa)
break;
}
if (ifa != NULL)
ifa_acquire(ifa, psref);
pserialize_read_exit(s);
rtfree(rt);
if (ifa == NULL)
return NULL;
}
if (ifa->ifa_addr->sa_family != dst->sa_family) {
struct ifaddr *oifa = ifa;
ifa = ifaof_ifpforaddr(dst, ifa->ifa_ifp);
if (ifa == NULL)
ifa = oifa;
struct ifaddr *nifa;
int s;
s = pserialize_read_enter();
nifa = ifaof_ifpforaddr(dst, ifa->ifa_ifp);
if (nifa != NULL) {
ifa_release(ifa, psref);
ifa_acquire(nifa, psref);
ifa = nifa;
}
pserialize_read_exit(s);
}
return ifa;
}
@ -699,48 +729,69 @@ rtrequest_newmsg(const int req, const struct sockaddr *dst,
return 0;
}
int
rt_getifa(struct rt_addrinfo *info)
struct ifnet *
rt_getifp(struct rt_addrinfo *info, struct psref *psref)
{
const struct sockaddr *ifpaddr = info->rti_info[RTAX_IFP];
if (info->rti_ifp != NULL)
return NULL;
/*
* ifp may be specified by sockaddr_dl when protocol address
* is ambiguous
*/
if (ifpaddr != NULL && ifpaddr->sa_family == AF_LINK) {
struct ifaddr *ifa;
int s = pserialize_read_enter();
ifa = ifa_ifwithnet(ifpaddr);
if (ifa != NULL)
info->rti_ifp = if_get_byindex(ifa->ifa_ifp->if_index,
psref);
pserialize_read_exit(s);
}
return info->rti_ifp;
}
struct ifaddr *
rt_getifa(struct rt_addrinfo *info, struct psref *psref)
{
struct ifaddr *ifa;
const struct sockaddr *dst = info->rti_info[RTAX_DST];
const struct sockaddr *gateway = info->rti_info[RTAX_GATEWAY];
const struct sockaddr *ifaaddr = info->rti_info[RTAX_IFA];
const struct sockaddr *ifpaddr = info->rti_info[RTAX_IFP];
int flags = info->rti_flags;
const struct sockaddr *sa;
/*
* ifp may be specified by sockaddr_dl when protocol address
* is ambiguous
*/
if (info->rti_ifp == NULL && ifpaddr != NULL
&& ifpaddr->sa_family == AF_LINK &&
(ifa = ifa_ifwithnet(ifpaddr)) != NULL)
info->rti_ifp = ifa->ifa_ifp;
if (info->rti_ifa == NULL && ifaaddr != NULL)
info->rti_ifa = ifa_ifwithaddr(ifaaddr);
if (info->rti_ifa == NULL) {
const struct sockaddr *sa;
sa = ifaaddr != NULL ? ifaaddr :
(gateway != NULL ? gateway : dst);
if (sa != NULL && info->rti_ifp != NULL)
info->rti_ifa = ifaof_ifpforaddr(sa, info->rti_ifp);
else if (dst != NULL && gateway != NULL)
info->rti_ifa = ifa_ifwithroute(flags, dst, gateway);
else if (sa != NULL)
info->rti_ifa = ifa_ifwithroute(flags, sa, sa);
if (info->rti_ifa == NULL && ifaaddr != NULL) {
ifa = ifa_ifwithaddr_psref(ifaaddr, psref);
if (ifa != NULL)
goto got;
}
if ((ifa = info->rti_ifa) == NULL)
return ENETUNREACH;
sa = ifaaddr != NULL ? ifaaddr :
(gateway != NULL ? gateway : dst);
if (sa != NULL && info->rti_ifp != NULL)
ifa = ifaof_ifpforaddr_psref(sa, info->rti_ifp, psref);
else if (dst != NULL && gateway != NULL)
ifa = ifa_ifwithroute_psref(flags, dst, gateway, psref);
else if (sa != NULL)
ifa = ifa_ifwithroute_psref(flags, sa, sa, psref);
if (ifa == NULL)
return NULL;
got:
if (ifa->ifa_getifa != NULL) {
info->rti_ifa = ifa = (*ifa->ifa_getifa)(ifa, dst);
/* FIXME NOMPSAFE */
ifa = (*ifa->ifa_getifa)(ifa, dst);
if (ifa == NULL)
return ENETUNREACH;
return NULL;
ifa_acquire(ifa, psref);
}
info->rti_ifa = ifa;
if (info->rti_ifp == NULL)
info->rti_ifp = ifa->ifa_ifp;
return 0;
return ifa;
}
/*
@ -750,18 +801,23 @@ rt_getifa(struct rt_addrinfo *info)
int
rtrequest1(int req, struct rt_addrinfo *info, struct rtentry **ret_nrt)
{
int s = splsoftnet();
int s = splsoftnet(), ss;
int error = 0, rc;
struct rtentry *rt;
rtbl_t *rtbl;
struct ifaddr *ifa, *ifa2;
struct ifaddr *ifa = NULL, *ifa2 = NULL;
struct sockaddr_storage maskeddst;
const struct sockaddr *dst = info->rti_info[RTAX_DST];
const struct sockaddr *gateway = info->rti_info[RTAX_GATEWAY];
const struct sockaddr *netmask = info->rti_info[RTAX_NETMASK];
int flags = info->rti_flags;
struct psref psref_ifp, psref_ifa;
int bound = 0;
struct ifnet *ifp = NULL;
bool need_to_release_ifa = true;
#define senderr(x) { error = x ; goto bad; }
bound = curlwp_bind();
if ((rtbl = rt_gettable(dst->sa_family)) == NULL)
senderr(ESRCH);
if (flags & RTF_HOST)
@ -788,6 +844,7 @@ rtrequest1(int req, struct rt_addrinfo *info, struct rtentry **ret_nrt)
}
if (ifa->ifa_rtrequest)
ifa->ifa_rtrequest(RTM_DELETE, rt, info);
ifa = NULL;
}
rttrash++;
if (ret_nrt) {
@ -802,9 +859,16 @@ rtrequest1(int req, struct rt_addrinfo *info, struct rtentry **ret_nrt)
break;
case RTM_ADD:
if (info->rti_ifa == NULL && (error = rt_getifa(info)))
senderr(error);
ifa = info->rti_ifa;
if (info->rti_ifa == NULL) {
ifp = rt_getifp(info, &psref_ifp);
ifa = rt_getifa(info, &psref_ifa);
if (ifa == NULL)
senderr(ENETUNREACH);
} else {
/* Caller should have a reference of ifa */
ifa = info->rti_ifa;
need_to_release_ifa = false;
}
rt = pool_get(&rtentry_pool, PR_NOWAIT);
if (rt == NULL)
senderr(ENOBUFS);
@ -835,17 +899,23 @@ rtrequest1(int req, struct rt_addrinfo *info, struct rtentry **ret_nrt)
senderr(ENOBUFS);
}
RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key);
if (info->rti_info[RTAX_IFP] != NULL &&
(ifa2 = ifa_ifwithnet(info->rti_info[RTAX_IFP])) != NULL &&
ifa2->ifa_ifp != NULL)
rt->rt_ifp = ifa2->ifa_ifp;
else
ss = pserialize_read_enter();
if (info->rti_info[RTAX_IFP] != NULL) {
ifa2 = ifa_ifwithnet(info->rti_info[RTAX_IFP]);
if (ifa2 != NULL)
rt->rt_ifp = ifa2->ifa_ifp;
else
rt->rt_ifp = ifa->ifa_ifp;
} else
rt->rt_ifp = ifa->ifa_ifp;
pserialize_read_exit(ss);
RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key);
rc = rt_addaddr(rtbl, rt, netmask);
RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key);
if (rc != 0) {
ifafree(ifa);
ifafree(ifa); /* for rt_set_ifa above */
rt_destroy(rt);
pool_put(&rtentry_pool, rt);
senderr(rc);
@ -853,6 +923,11 @@ rtrequest1(int req, struct rt_addrinfo *info, struct rtentry **ret_nrt)
RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key);
if (ifa->ifa_rtrequest)
ifa->ifa_rtrequest(req, rt, info);
if (need_to_release_ifa)
ifa_release(ifa, &psref_ifa);
ifa = NULL;
if_put(ifp, &psref_ifp);
ifp = NULL;
RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key);
if (ret_nrt) {
*ret_nrt = rt;
@ -875,6 +950,10 @@ rtrequest1(int req, struct rt_addrinfo *info, struct rtentry **ret_nrt)
break;
}
bad:
if (need_to_release_ifa)
ifa_release(ifa, &psref_ifa);
if_put(ifp, &psref_ifp);
curlwp_bindx(bound);
splx(s);
return error;
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: route.h,v 1.101 2016/04/28 00:16:56 ozaki-r Exp $ */
/* $NetBSD: route.h,v 1.102 2016/08/01 03:15:30 ozaki-r Exp $ */
/*
* Copyright (c) 1980, 1986, 1993
@ -396,7 +396,10 @@ int rt_ifa_addlocal(struct ifaddr *);
int rt_ifa_remlocal(struct ifaddr *, struct ifaddr *);
struct ifaddr *
rt_get_ifa(struct rtentry *);
int rt_getifa(struct rt_addrinfo *);
struct ifaddr *
rt_getifa(struct rt_addrinfo *, struct psref *);
struct ifnet *
rt_getifp(struct rt_addrinfo *, struct psref *);
void rt_replace_ifa(struct rtentry *, struct ifaddr *);
int rt_setgate(struct rtentry *, const struct sockaddr *);

View File

@ -1,4 +1,4 @@
/* $NetBSD: rtsock.c,v 1.193 2016/07/28 07:54:31 martin Exp $ */
/* $NetBSD: rtsock.c,v 1.194 2016/08/01 03:15:30 ozaki-r Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@ -61,7 +61,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: rtsock.c,v 1.193 2016/07/28 07:54:31 martin Exp $");
__KERNEL_RCSID(0, "$NetBSD: rtsock.c,v 1.194 2016/08/01 03:15:30 ozaki-r Exp $");
#ifdef _KERNEL_OPT
#include "opt_inet.h"
@ -541,13 +541,13 @@ route_output_report(struct rtentry *rt, struct rt_addrinfo *info,
static struct ifaddr *
route_output_get_ifa(const struct rt_addrinfo info, const struct rtentry *rt,
struct ifnet **ifp)
struct ifnet **ifp, struct psref *psref)
{
struct ifaddr *ifa = NULL;
*ifp = NULL;
if (info.rti_info[RTAX_IFP] != NULL) {
ifa = ifa_ifwithnet(info.rti_info[RTAX_IFP]);
ifa = ifa_ifwithnet_psref(info.rti_info[RTAX_IFP], psref);
if (ifa == NULL)
goto next;
*ifp = ifa->ifa_ifp;
@ -556,29 +556,29 @@ route_output_get_ifa(const struct rt_addrinfo info, const struct rtentry *rt,
goto next;
if (info.rti_info[RTAX_IFA] == NULL) {
/* route change <dst> <gw> -ifp <if> */
ifa = ifaof_ifpforaddr(info.rti_info[RTAX_GATEWAY],
*ifp);
ifa = ifaof_ifpforaddr_psref(info.rti_info[RTAX_GATEWAY],
*ifp, psref);
} else {
/* route change <dst> -ifp <if> -ifa <addr> */
ifa = ifa_ifwithaddr(info.rti_info[RTAX_IFA]);
ifa = ifa_ifwithaddr_psref(info.rti_info[RTAX_IFA], psref);
if (ifa != NULL)
goto out;
ifa = ifaof_ifpforaddr(info.rti_info[RTAX_IFA],
*ifp);
ifa = ifaof_ifpforaddr_psref(info.rti_info[RTAX_IFA],
*ifp, psref);
}
goto out;
}
next:
if (info.rti_info[RTAX_IFA] != NULL) {
/* route change <dst> <gw> -ifa <addr> */
ifa = ifa_ifwithaddr(info.rti_info[RTAX_IFA]);
ifa = ifa_ifwithaddr_psref(info.rti_info[RTAX_IFA], psref);
if (ifa != NULL)
goto out;
}
if (info.rti_info[RTAX_GATEWAY] != NULL) {
/* route change <dst> <gw> */
ifa = ifa_ifwithroute(rt->rt_flags, rt_getkey(rt),
info.rti_info[RTAX_GATEWAY]);
ifa = ifa_ifwithroute_psref(rt->rt_flags, rt_getkey(rt),
info.rti_info[RTAX_GATEWAY], psref);
}
out:
if (ifa != NULL && *ifp == NULL)
@ -601,11 +601,15 @@ COMPATNAME(route_output)(struct mbuf *m, struct socket *so)
struct ifaddr *ifa = NULL;
sa_family_t family;
struct sockaddr_dl sdl;
struct psref psref;
int bound = curlwp_bind();
#define senderr(e) do { error = e; goto flush;} while (/*CONSTCOND*/ 0)
if (m == NULL || ((m->m_len < sizeof(int32_t)) &&
(m = m_pullup(m, sizeof(int32_t))) == NULL))
return ENOBUFS;
(m = m_pullup(m, sizeof(int32_t))) == NULL)) {
error = ENOBUFS;
goto out;
}
if ((m->m_flags & M_PKTHDR) == 0)
panic("%s", __func__);
len = m->m_pkthdr.len;
@ -807,30 +811,45 @@ COMPATNAME(route_output)(struct mbuf *m, struct socket *so)
}
break;
case RTM_CHANGE:
case RTM_CHANGE: {
struct ifnet *_ifp;
struct ifaddr *_ifa;
struct psref _psref, psref_ifp;
/*
* new gateway could require new ifaddr, ifp;
* flags may also be different; ifp may be specified
* by ll sockaddr when protocol address is ambiguous
*/
if ((error = rt_getifa(&info)) != 0)
senderr(error);
_ifp = rt_getifp(&info, &psref_ifp);
ifa = rt_getifa(&info, &psref);
if (ifa == NULL) {
if_put(_ifp, &psref_ifp);
senderr(ENETUNREACH);
}
if (info.rti_info[RTAX_GATEWAY]) {
error = rt_setgate(rt,
info.rti_info[RTAX_GATEWAY]);
if (error != 0)
if (error != 0) {
if_put(_ifp, &psref_ifp);
senderr(error);
}
}
if (info.rti_info[RTAX_TAG]) {
const struct sockaddr *tag;
tag = rt_settag(rt, info.rti_info[RTAX_TAG]);
if (tag == NULL)
if (tag == NULL) {
if_put(_ifp, &psref_ifp);
senderr(ENOBUFS);
}
}
/* new gateway could require new ifaddr, ifp;
flags may also be different; ifp may be specified
by ll sockaddr when protocol address is ambiguous */
ifa = route_output_get_ifa(info, rt, &ifp);
_ifa = route_output_get_ifa(info, rt, &ifp, &_psref);
if (_ifa != NULL) {
ifa_release(ifa, &psref);
ifa = _ifa;
}
if (ifa) {
struct ifaddr *oifa = rt->rt_ifa;
if (oifa != ifa) {
@ -841,7 +860,10 @@ COMPATNAME(route_output)(struct mbuf *m, struct socket *so)
rt_replace_ifa(rt, ifa);
rt->rt_ifp = ifp;
}
if (_ifa == NULL)
ifa_release(ifa, &psref);
}
ifa_release(_ifa, &_psref);
if (ifp && rt->rt_ifp != ifp)
rt->rt_ifp = ifp;
rt_setmetrics(rtm->rtm_inits, rtm, rt);
@ -850,7 +872,9 @@ COMPATNAME(route_output)(struct mbuf *m, struct socket *so)
| (rt->rt_flags & PRESERVED_RTF);
if (rt->rt_ifa && rt->rt_ifa->ifa_rtrequest)
rt->rt_ifa->ifa_rtrequest(RTM_ADD, rt, &info);
if_put(_ifp, &psref_ifp);
/*FALLTHROUGH*/
}
case RTM_LOCK:
rt->rt_rmx.rmx_locks &= ~(rtm->rtm_inits);
rt->rt_rmx.rmx_locks |=
@ -890,7 +914,7 @@ flush:
if (rtm)
Free(rtm);
m_freem(m);
return error;
goto out;
}
/* There is another listener, so construct message */
rp = sotorawcb(so);
@ -914,6 +938,8 @@ flush:
if (rp)
rp->rcb_proto.sp_family = PF_XROUTE;
}
out:
curlwp_bindx(bound);
return error;
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: aarp.c,v 1.38 2016/07/07 09:32:02 ozaki-r Exp $ */
/* $NetBSD: aarp.c,v 1.39 2016/08/01 03:15:30 ozaki-r Exp $ */
/*
* Copyright (c) 1990,1991 Regents of The University of Michigan.
@ -27,7 +27,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: aarp.c,v 1.38 2016/07/07 09:32:02 ozaki-r Exp $");
__KERNEL_RCSID(0, "$NetBSD: aarp.c,v 1.39 2016/08/01 03:15:30 ozaki-r Exp $");
#include "opt_mbuftrace.h"
@ -131,7 +131,7 @@ aarptimer(void *ignored)
struct ifaddr *
at_ifawithnet(const struct sockaddr_at *sat, struct ifnet *ifp)
{
struct ifaddr *ifa;
struct ifaddr *ifa;
struct sockaddr_at *sat2;
struct netrange *nr;
@ -149,6 +149,7 @@ at_ifawithnet(const struct sockaddr_at *sat, struct ifnet *ifp)
&& (ntohs(nr->nr_lastnet) >= ntohs(sat->sat_addr.s_net)))
break;
}
return ifa;
}
@ -251,17 +252,24 @@ aarpresolve(struct ifnet *ifp, struct mbuf *m,
int s;
if (at_broadcast(destsat)) {
aa = (struct at_ifaddr *) at_ifawithnet(destsat, ifp);
if (aa == NULL) {
struct ifaddr *ifa;
s = pserialize_read_enter();
ifa = at_ifawithnet(destsat, ifp);
if (ifa == NULL) {
pserialize_read_exit(s);
m_freem(m);
return (0);
}
aa = (struct at_ifaddr *)ifa;
if (aa->aa_flags & AFA_PHASE2)
memcpy(desten, atmulticastaddr,
sizeof(atmulticastaddr));
else
memcpy(desten, etherbroadcastaddr,
sizeof(etherbroadcastaddr));
pserialize_read_exit(s);
return 1;
}
s = splnet();
@ -331,7 +339,6 @@ at_aarpinput(struct ifnet *ifp, struct mbuf *m)
{
struct ether_aarp *ea;
struct at_ifaddr *aa;
struct ifaddr *ia;
struct aarptab *aat;
struct ether_header *eh;
struct llc *llc;
@ -340,6 +347,9 @@ at_aarpinput(struct ifnet *ifp, struct mbuf *m)
struct at_addr spa, tpa, ma;
int op;
u_int16_t net;
int s;
struct psref psref;
struct ifaddr *ifa;
ea = mtod(m, struct ether_aarp *);
@ -355,11 +365,18 @@ at_aarpinput(struct ifnet *ifp, struct mbuf *m)
sat.sat_len = sizeof(struct sockaddr_at);
sat.sat_family = AF_APPLETALK;
sat.sat_addr.s_net = net;
aa = (struct at_ifaddr *) at_ifawithnet(&sat, ifp);
if (aa == NULL) {
s = pserialize_read_enter();
ifa = at_ifawithnet(&sat, ifp);
if (ifa == NULL) {
pserialize_read_exit(s);
m_freem(m);
return;
}
ifa_acquire(ifa, &psref);
pserialize_read_exit(s);
aa = (struct at_ifaddr *)ifa;
memcpy(&spa.s_net, ea->aarp_spnet, sizeof(spa.s_net));
memcpy(&tpa.s_net, ea->aarp_tpnet, sizeof(tpa.s_net));
} else {
@ -367,13 +384,18 @@ at_aarpinput(struct ifnet *ifp, struct mbuf *m)
* Since we don't know the net, we just look for the first
* phase 1 address on the interface.
*/
IFADDR_READER_FOREACH(ia, ifp) {
aa = (struct at_ifaddr *)ia;
s = pserialize_read_enter();
IFADDR_READER_FOREACH(ifa, ifp) {
aa = (struct at_ifaddr *)ifa;
if (AA_SAT(aa)->sat_family == AF_APPLETALK &&
(aa->aa_flags & AFA_PHASE2) == 0)
(aa->aa_flags & AFA_PHASE2) == 0) {
ifa_acquire(ifa, &psref);
break;
}
}
if (ia == NULL) {
pserialize_read_exit(s);
if (ifa == NULL) {
m_freem(m);
return;
}
@ -398,7 +420,7 @@ at_aarpinput(struct ifnet *ifp, struct mbuf *m)
callout_stop(&aa->aa_probe_ch);
wakeup(aa);
m_freem(m);
return;
goto out;
} else if (op != AARPOP_PROBE) {
/*
* This is not a probe, and we're not probing.
@ -408,7 +430,7 @@ at_aarpinput(struct ifnet *ifp, struct mbuf *m)
log(LOG_ERR, "aarp: duplicate AT address!! %s\n",
ether_sprintf(ea->aarp_sha));
m_freem(m);
return;
goto out;
}
}
AARPTAB_LOOK(aat, spa);
@ -421,7 +443,7 @@ at_aarpinput(struct ifnet *ifp, struct mbuf *m)
*/
aarptfree(aat);
m_freem(m);
return;
goto out;
}
memcpy(aat->aat_enaddr, ea->aarp_sha, sizeof(ea->aarp_sha));
aat->aat_flags |= ATF_COM;
@ -449,7 +471,7 @@ at_aarpinput(struct ifnet *ifp, struct mbuf *m)
if (tpa.s_net != ma.s_net || tpa.s_node != ma.s_node ||
op == AARPOP_RESPONSE || (aa->aa_flags & AFA_PROBING)) {
m_freem(m);
return;
goto out;
}
/*
@ -467,7 +489,7 @@ at_aarpinput(struct ifnet *ifp, struct mbuf *m)
if (aa->aa_flags & AFA_PHASE2) {
M_PREPEND(m, sizeof(struct llc), M_DONTWAIT);
if (m == NULL)
return;
goto out;
llc = mtod(m, struct llc *);
llc->llc_dsap = llc->llc_ssap = LLC_SNAP_LSAP;
@ -489,6 +511,8 @@ at_aarpinput(struct ifnet *ifp, struct mbuf *m)
sa.sa_len = sizeof(struct sockaddr);
sa.sa_family = AF_UNSPEC;
(*ifp->if_output) (ifp, m, &sa, NULL); /* XXX */
out:
ifa_release(ifa, &psref);
return;
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: at_control.c,v 1.38 2016/07/07 09:32:02 ozaki-r Exp $ */
/* $NetBSD: at_control.c,v 1.39 2016/08/01 03:15:30 ozaki-r Exp $ */
/*
* Copyright (c) 1990,1994 Regents of The University of Michigan.
@ -27,7 +27,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: at_control.c,v 1.38 2016/07/07 09:32:02 ozaki-r Exp $");
__KERNEL_RCSID(0, "$NetBSD: at_control.c,v 1.39 2016/08/01 03:15:30 ozaki-r Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@ -194,6 +194,7 @@ at_control(u_long cmd, void *data, struct ifnet *ifp)
TAILQ_INSERT_TAIL(&at_ifaddr, aa, aa_list);
}
ifaref(&aa->aa_ifa);
ifa_psref_init(&aa->aa_ifa);
/*
* Find the end of the interface's addresses

View File

@ -1,4 +1,4 @@
/* $NetBSD: if_arp.c,v 1.220 2016/07/28 09:03:50 ozaki-r Exp $ */
/* $NetBSD: if_arp.c,v 1.221 2016/08/01 03:15:30 ozaki-r Exp $ */
/*-
* Copyright (c) 1998, 2000, 2008 The NetBSD Foundation, Inc.
@ -68,7 +68,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: if_arp.c,v 1.220 2016/07/28 09:03:50 ozaki-r Exp $");
__KERNEL_RCSID(0, "$NetBSD: if_arp.c,v 1.221 2016/08/01 03:15:30 ozaki-r Exp $");
#ifdef _KERNEL_OPT
#include "opt_ddb.h"
@ -446,6 +446,8 @@ arp_rtrequest(int req, struct rtentry *rt, const struct rt_addrinfo *info)
struct in_ifaddr *ia;
struct ifaddr *ifa;
struct ifnet *ifp = rt->rt_ifp;
int bound;
int s;
if (req == RTM_LLINFO_UPD) {
struct in_addr *in;
@ -553,10 +555,13 @@ arp_rtrequest(int req, struct rtentry *rt, const struct rt_addrinfo *info)
if (rt->rt_flags & RTF_CONNECTED)
break;
}
bound = curlwp_bind();
/* Announce a new entry if requested. */
if (rt->rt_flags & RTF_ANNOUNCE) {
ia = in_get_ia_on_iface(
satocsin(rt_getkey(rt))->sin_addr, ifp);
struct psref psref;
ia = in_get_ia_on_iface_psref(
satocsin(rt_getkey(rt))->sin_addr, ifp, &psref);
if (ia == NULL ||
ia->ia4_flags & (IN_IFF_NOTREADY | IN_IFF_DETACHED))
;
@ -565,12 +570,14 @@ arp_rtrequest(int req, struct rtentry *rt, const struct rt_addrinfo *info)
&satocsin(rt_getkey(rt))->sin_addr,
&satocsin(rt_getkey(rt))->sin_addr,
CLLADDR(satocsdl(gate)));
if (ia != NULL)
ia4_release(ia, &psref);
}
if (gate->sa_family != AF_LINK ||
gate->sa_len < sockaddr_dl_measure(0, ifp->if_addrlen)) {
log(LOG_DEBUG, "%s: bad gateway value\n", __func__);
break;
goto out;
}
satosdl(gate)->sdl_type = ifp->if_type;
@ -586,7 +593,7 @@ arp_rtrequest(int req, struct rtentry *rt, const struct rt_addrinfo *info)
rt->rt_flags |= RTF_BROADCAST;
/* There is little point in resolving the broadcast address */
if (rt->rt_flags & RTF_BROADCAST)
break;
goto out;
/*
* When called from rt_ifa_addlocal, we cannot depend on that
@ -599,12 +606,15 @@ arp_rtrequest(int req, struct rtentry *rt, const struct rt_addrinfo *info)
rt->rt_ifp = lo0ifp;
rt->rt_rmx.rmx_mtu = 0;
}
break;
goto out;
}
s = pserialize_read_enter();
ia = in_get_ia_on_iface(satocsin(rt_getkey(rt))->sin_addr, ifp);
if (ia == NULL)
break;
if (ia == NULL) {
pserialize_read_exit(s);
goto out;
}
rt->rt_expire = 0;
if (useloopback) {
@ -619,7 +629,11 @@ arp_rtrequest(int req, struct rtentry *rt, const struct rt_addrinfo *info)
*/
ifa = &ia->ia_ifa;
if (ifa != rt->rt_ifa)
/* Assume it doesn't sleep */
rt_replace_ifa(rt, ifa);
pserialize_read_exit(s);
out:
curlwp_bindx(bound);
break;
}
}
@ -971,7 +985,7 @@ in_arpinput(struct mbuf *m)
struct arphdr *ah;
struct ifnet *ifp, *rcvif = NULL;
struct llentry *la = NULL;
struct in_ifaddr *ia;
struct in_ifaddr *ia = NULL;
#if NBRIDGE > 0
struct in_ifaddr *bridge_ia = NULL;
#endif
@ -983,7 +997,8 @@ in_arpinput(struct mbuf *m)
int op;
void *tha;
uint64_t *arps;
struct psref psref;
struct psref psref, psref_ia;
int s;
if (__predict_false(m_makewritable(&m, 0, m->m_pkthdr.len, M_DONTWAIT)))
goto out;
@ -1024,6 +1039,7 @@ in_arpinput(struct mbuf *m)
* or any address on the interface to use
* as a dummy address in the rest of this function
*/
s = pserialize_read_enter();
IN_ADDRHASH_READER_FOREACH(ia, itaddr.s_addr) {
if (!in_hosteq(ia->ia_addr.sin_addr, itaddr))
continue;
@ -1064,11 +1080,14 @@ in_arpinput(struct mbuf *m)
ifp = bridge_ia->ia_ifp;
}
#endif
if (ia != NULL)
ia4_acquire(ia, &psref_ia);
pserialize_read_exit(s);
if (ia == NULL) {
ia = in_get_ia_on_iface(isaddr, rcvif);
ia = in_get_ia_on_iface_psref(isaddr, rcvif, &psref_ia);
if (ia == NULL) {
ia = in_get_ia_from_ifp(ifp);
ia = in_get_ia_from_ifp_psref(ifp, &psref_ia);
if (ia == NULL) {
ARP_STATINC(ARP_STAT_RCVNOINT);
goto out;
@ -1289,7 +1308,6 @@ reply:
struct llentry *lle = NULL;
struct sockaddr_in sin;
#if NCARP > 0
int s;
struct ifnet *_rcvif = m_get_rcvif(m, &s);
if (ifp->if_type == IFT_CARP && _rcvif->if_type != IFT_CARP)
goto out;
@ -1314,6 +1332,7 @@ reply:
goto drop;
}
}
ia4_release(ia, &psref_ia);
memcpy(ar_tpa(ah), ar_spa(ah), ah->ar_pln);
memcpy(ar_spa(ah), &itaddr, ah->ar_pln);
@ -1350,6 +1369,8 @@ out:
if (la != NULL)
LLE_WUNLOCK(la);
drop:
if (ia != NULL)
ia4_release(ia, &psref_ia);
if (rcvif != NULL)
m_put_rcvif_psref(rcvif, &psref);
m_freem(m);

View File

@ -1,4 +1,4 @@
/* $NetBSD: igmp.c,v 1.61 2016/07/08 04:33:30 ozaki-r Exp $ */
/* $NetBSD: igmp.c,v 1.62 2016/08/01 03:15:30 ozaki-r Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@ -40,7 +40,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: igmp.c,v 1.61 2016/07/08 04:33:30 ozaki-r Exp $");
__KERNEL_RCSID(0, "$NetBSD: igmp.c,v 1.62 2016/08/01 03:15:30 ozaki-r Exp $");
#ifdef _KERNEL_OPT
#include "opt_mrouting.h"
@ -361,9 +361,11 @@ igmp_input(struct mbuf *m, ...)
* determine the arrival interface of an incoming packet.
*/
if ((ip->ip_src.s_addr & IN_CLASSA_NET) == 0) {
ia = in_get_ia_from_ifp(ifp); /* XXX */
int s = pserialize_read_enter();
ia = in_get_ia_from_ifp(ifp); /* XXX */
if (ia)
ip->ip_src.s_addr = ia->ia_subnet;
pserialize_read_exit(s);
}
/*
@ -394,26 +396,32 @@ igmp_input(struct mbuf *m, ...)
in_multi_unlock();
break;
case IGMP_v2_HOST_MEMBERSHIP_REPORT:
case IGMP_v2_HOST_MEMBERSHIP_REPORT: {
int s = pserialize_read_enter();
#ifdef MROUTING
/*
* Make sure we don't hear our own membership report. Fast
* leave requires knowing that we are the only member of a
* group.
*/
ia = in_get_ia_from_ifp(ifp); /* XXX */
if (ia && in_hosteq(ip->ip_src, ia->ia_addr.sin_addr))
ia = in_get_ia_from_ifp(ifp); /* XXX */
if (ia && in_hosteq(ip->ip_src, ia->ia_addr.sin_addr)) {
pserialize_read_exit(s);
break;
}
#endif
IGMP_STATINC(IGMP_STAT_RCV_REPORTS);
if (ifp->if_flags & IFF_LOOPBACK)
if (ifp->if_flags & IFF_LOOPBACK) {
pserialize_read_exit(s);
break;
}
if (!IN_MULTICAST(igmp->igmp_group.s_addr) ||
!in_hosteq(igmp->igmp_group, ip->ip_dst)) {
IGMP_STATINC(IGMP_STAT_RCV_BADREPORTS);
pserialize_read_exit(s);
goto drop;
}
@ -428,11 +436,12 @@ igmp_input(struct mbuf *m, ...)
*/
if ((ip->ip_src.s_addr & IN_CLASSA_NET) == 0) {
#ifndef MROUTING
ia = in_get_ia_from_ifp(ifp); /* XXX */
ia = in_get_ia_from_ifp(ifp); /* XXX */
#endif
if (ia)
ip->ip_src.s_addr = ia->ia_subnet;
}
pserialize_read_exit(s);
/*
* If we belong to the group being reported, stop
@ -457,7 +466,7 @@ igmp_input(struct mbuf *m, ...)
}
in_multi_unlock();
break;
}
}
m_put_rcvif_psref(ifp, &psref);

View File

@ -1,4 +1,4 @@
/* $NetBSD: in.c,v 1.177 2016/07/28 09:03:50 ozaki-r Exp $ */
/* $NetBSD: in.c,v 1.178 2016/08/01 03:15:30 ozaki-r Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@ -91,7 +91,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: in.c,v 1.177 2016/07/28 09:03:50 ozaki-r Exp $");
__KERNEL_RCSID(0, "$NetBSD: in.c,v 1.178 2016/08/01 03:15:30 ozaki-r Exp $");
#include "arp.h"
@ -189,6 +189,7 @@ static krwlock_t in_multilock;
struct in_ifaddrhashhead * in_ifaddrhashtbl;
u_long in_ifaddrhash;
struct in_ifaddrhead in_ifaddrhead;
static kmutex_t in_ifaddr_lock;
struct pslist_head * in_ifaddrhashtbl_pslist;
u_long in_ifaddrhash_pslist;
@ -204,8 +205,11 @@ in_init(void)
in_ifaddrhashtbl = hashinit(IN_IFADDR_HASH_SIZE, HASH_LIST, true,
&in_ifaddrhash);
in_ifaddrhashtbl_pslist = hashinit(IN_IFADDR_HASH_SIZE, HASH_PSLIST,
true, &in_ifaddrhash_pslist);
mutex_init(&in_ifaddr_lock, MUTEX_DEFAULT, IPL_NONE);
in_multihashtbl = hashinit(IN_IFADDR_HASH_SIZE, HASH_LIST, true,
&in_multihash);
rw_init(&in_multilock);
@ -223,19 +227,27 @@ int
in_localaddr(struct in_addr in)
{
struct in_ifaddr *ia;
int localaddr = 0;
int s = pserialize_read_enter();
if (subnetsarelocal) {
IN_ADDRLIST_READER_FOREACH(ia) {
if ((in.s_addr & ia->ia_netmask) == ia->ia_net)
return (1);
if ((in.s_addr & ia->ia_netmask) == ia->ia_net) {
localaddr = 1;
break;
}
}
} else {
IN_ADDRLIST_READER_FOREACH(ia) {
if ((in.s_addr & ia->ia_subnetmask) == ia->ia_subnet)
return (1);
if ((in.s_addr & ia->ia_subnetmask) == ia->ia_subnet) {
localaddr = 1;
break;
}
}
}
return (0);
pserialize_read_exit(s);
return localaddr;
}
/*
@ -307,6 +319,7 @@ in_setmaxmtu(void)
struct in_ifaddr *ia;
struct ifnet *ifp;
unsigned long maxmtu = 0;
int s = pserialize_read_enter();
IN_ADDRLIST_READER_FOREACH(ia) {
if ((ifp = ia->ia_ifp) == 0)
@ -318,6 +331,7 @@ in_setmaxmtu(void)
}
if (maxmtu)
in_maxmtu = maxmtu;
pserialize_read_exit(s);
}
static u_int
@ -371,6 +385,8 @@ in_control0(struct socket *so, u_long cmd, void *data, struct ifnet *ifp)
int newifaddr = 0;
bool run_hook = false;
bool need_reinsert = false;
struct psref psref;
int bound;
switch (cmd) {
case SIOCALIFADDR:
@ -386,11 +402,12 @@ in_control0(struct socket *so, u_long cmd, void *data, struct ifnet *ifp)
return ifaddrpref_ioctl(so, cmd, data, ifp);
}
bound = curlwp_bind();
/*
* Find address for this interface, if it exists.
*/
if (ifp != NULL)
ia = in_get_ia_from_ifp(ifp);
ia = in_get_ia_from_ifp_psref(ifp, &psref);
hostIsNew = 1; /* moved here to appease gcc */
switch (cmd) {
@ -399,6 +416,11 @@ in_control0(struct socket *so, u_long cmd, void *data, struct ifnet *ifp)
case SIOCGIFALIAS:
case SIOCGIFAFLAG_IN:
if (ifra->ifra_addr.sin_family == AF_INET) {
int s;
if (ia != NULL)
ia4_release(ia, &psref);
s = pserialize_read_enter();
IN_ADDRHASH_READER_FOREACH(ia,
ifra->ifra_addr.sin_addr.s_addr) {
if (ia->ia_ifp == ifp &&
@ -406,12 +428,17 @@ in_control0(struct socket *so, u_long cmd, void *data, struct ifnet *ifp)
ifra->ifra_addr.sin_addr))
break;
}
if (ia != NULL)
ia4_acquire(ia, &psref);
pserialize_read_exit(s);
}
if ((cmd == SIOCDIFADDR ||
cmd == SIOCGIFALIAS ||
cmd == SIOCGIFAFLAG_IN) &&
ia == NULL)
return (EADDRNOTAVAIL);
ia == NULL) {
error = EADDRNOTAVAIL;
goto out;
}
if (cmd == SIOCDIFADDR &&
ifra->ifra_addr.sin_family == AF_UNSPEC) {
@ -429,8 +456,10 @@ in_control0(struct socket *so, u_long cmd, void *data, struct ifnet *ifp)
hostIsNew = 0;
/* FALLTHROUGH */
case SIOCSIFDSTADDR:
if (ifra->ifra_addr.sin_family != AF_INET)
return (EAFNOSUPPORT);
if (ifra->ifra_addr.sin_family != AF_INET) {
error = EAFNOSUPPORT;
goto out;
}
/* FALLTHROUGH */
case SIOCSIFNETMASK:
if (ifp == NULL)
@ -440,18 +469,24 @@ in_control0(struct socket *so, u_long cmd, void *data, struct ifnet *ifp)
break;
if (ia == NULL &&
(cmd == SIOCSIFNETMASK || cmd == SIOCSIFDSTADDR))
return (EADDRNOTAVAIL);
(cmd == SIOCSIFNETMASK || cmd == SIOCSIFDSTADDR)) {
error = EADDRNOTAVAIL;
goto out;
}
if (kauth_authorize_network(curlwp->l_cred, KAUTH_NETWORK_INTERFACE,
KAUTH_REQ_NETWORK_INTERFACE_SETPRIV, ifp, (void *)cmd,
NULL) != 0)
return (EPERM);
NULL) != 0) {
error = EPERM;
goto out;
}
if (ia == NULL) {
ia = malloc(sizeof(*ia), M_IFADDR, M_WAITOK|M_ZERO);
if (ia == NULL)
return (ENOBUFS);
if (ia == NULL) {
error = ENOBUFS;
goto out;
}
ia->ia_ifa.ifa_addr = sintosa(&ia->ia_addr);
ia->ia_ifa.ifa_dstaddr = sintosa(&ia->ia_dstaddr);
ia->ia_ifa.ifa_netmask = sintosa(&ia->ia_sockmask);
@ -471,6 +506,7 @@ in_control0(struct socket *so, u_long cmd, void *data, struct ifnet *ifp)
LIST_INIT(&ia->ia_multiaddrs);
IN_ADDRHASH_ENTRY_INIT(ia);
IN_ADDRLIST_ENTRY_INIT(ia);
ifa_psref_init(&ia->ia_ifa);
newifaddr = 1;
}
@ -479,16 +515,20 @@ in_control0(struct socket *so, u_long cmd, void *data, struct ifnet *ifp)
case SIOCSIFBRDADDR:
if (kauth_authorize_network(curlwp->l_cred, KAUTH_NETWORK_INTERFACE,
KAUTH_REQ_NETWORK_INTERFACE_SETPRIV, ifp, (void *)cmd,
NULL) != 0)
return (EPERM);
NULL) != 0) {
error = EPERM;
goto out;
}
/* FALLTHROUGH */
case SIOCGIFADDR:
case SIOCGIFNETMASK:
case SIOCGIFDSTADDR:
case SIOCGIFBRDADDR:
if (ia == NULL)
return (EADDRNOTAVAIL);
if (ia == NULL) {
error = EADDRNOTAVAIL;
goto out;
}
break;
}
error = 0;
@ -499,14 +539,18 @@ in_control0(struct socket *so, u_long cmd, void *data, struct ifnet *ifp)
break;
case SIOCGIFBRDADDR:
if ((ifp->if_flags & IFF_BROADCAST) == 0)
return (EINVAL);
if ((ifp->if_flags & IFF_BROADCAST) == 0) {
error = EINVAL;
goto out;
}
ifreq_setdstaddr(cmd, ifr, sintocsa(&ia->ia_broadaddr));
break;
case SIOCGIFDSTADDR:
if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
return (EINVAL);
if ((ifp->if_flags & IFF_POINTOPOINT) == 0) {
error = EINVAL;
goto out;
}
ifreq_setdstaddr(cmd, ifr, sintocsa(&ia->ia_dstaddr));
break;
@ -522,13 +566,15 @@ in_control0(struct socket *so, u_long cmd, void *data, struct ifnet *ifp)
break;
case SIOCSIFDSTADDR:
if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
return (EINVAL);
if ((ifp->if_flags & IFF_POINTOPOINT) == 0) {
error = EINVAL;
goto out;
}
oldaddr = ia->ia_dstaddr;
ia->ia_dstaddr = *satocsin(ifreq_getdstaddr(cmd, ifr));
if ((error = if_addr_init(ifp, &ia->ia_ifa, false)) != 0) {
ia->ia_dstaddr = oldaddr;
return error;
goto out;
}
if (ia->ia_flags & IFA_ROUTE) {
ia->ia_ifa.ifa_dstaddr = sintosa(&oldaddr);
@ -539,15 +585,19 @@ in_control0(struct socket *so, u_long cmd, void *data, struct ifnet *ifp)
break;
case SIOCSIFBRDADDR:
if ((ifp->if_flags & IFF_BROADCAST) == 0)
return EINVAL;
if ((ifp->if_flags & IFF_BROADCAST) == 0) {
error = EINVAL;
goto out;
}
ia->ia_broadaddr = *satocsin(ifreq_getbroadaddr(cmd, ifr));
break;
case SIOCSIFADDR:
if (!newifaddr) {
mutex_enter(&in_ifaddr_lock);
LIST_REMOVE(ia, ia_hash);
IN_ADDRHASH_WRITER_REMOVE(ia);
mutex_exit(&in_ifaddr_lock);
need_reinsert = true;
}
error = in_ifinit(ifp, ia, satocsin(ifreq_getaddr(cmd, ifr)),
@ -561,8 +611,10 @@ in_control0(struct socket *so, u_long cmd, void *data, struct ifnet *ifp)
ia->ia_sockmask = *satocsin(ifreq_getaddr(cmd, ifr));
ia->ia_subnetmask = ia->ia_sockmask.sin_addr.s_addr;
if (!newifaddr) {
mutex_enter(&in_ifaddr_lock);
LIST_REMOVE(ia, ia_hash);
IN_ADDRHASH_WRITER_REMOVE(ia);
mutex_exit(&in_ifaddr_lock);
need_reinsert = true;
}
error = in_ifinit(ifp, ia, NULL, 0, 0);
@ -591,8 +643,10 @@ in_control0(struct socket *so, u_long cmd, void *data, struct ifnet *ifp)
if (ifra->ifra_addr.sin_family == AF_INET &&
(hostIsNew || maskIsNew)) {
if (!newifaddr) {
mutex_enter(&in_ifaddr_lock);
LIST_REMOVE(ia, ia_hash);
IN_ADDRHASH_WRITER_REMOVE(ia);
mutex_exit(&in_ifaddr_lock);
need_reinsert = true;
}
error = in_ifinit(ifp, ia, &ifra->ifra_addr, 0,
@ -622,7 +676,9 @@ in_control0(struct socket *so, u_long cmd, void *data, struct ifnet *ifp)
break;
case SIOCDIFADDR:
ia4_release(ia, &psref);
in_purgeaddr(&ia->ia_ifa);
ia = NULL;
run_hook = true;
break;
@ -634,7 +690,8 @@ in_control0(struct socket *so, u_long cmd, void *data, struct ifnet *ifp)
#endif /* MROUTING */
default:
return ENOTTY;
error = ENOTTY;
goto out;
}
/*
@ -642,17 +699,22 @@ in_control0(struct socket *so, u_long cmd, void *data, struct ifnet *ifp)
* Need to improve.
*/
if (newifaddr) {
TAILQ_INSERT_TAIL(&in_ifaddrhead, ia, ia_list);
ifaref(&ia->ia_ifa);
ifa_insert(ifp, &ia->ia_ifa);
mutex_enter(&in_ifaddr_lock);
TAILQ_INSERT_TAIL(&in_ifaddrhead, ia, ia_list);
IN_ADDRLIST_WRITER_INSERT_TAIL(ia);
LIST_INSERT_HEAD(&IN_IFADDR_HASH(ia->ia_addr.sin_addr.s_addr),
ia, ia_hash);
IN_ADDRHASH_WRITER_INSERT_HEAD(ia);
mutex_exit(&in_ifaddr_lock);
} else if (need_reinsert) {
mutex_enter(&in_ifaddr_lock);
LIST_INSERT_HEAD(&IN_IFADDR_HASH(ia->ia_addr.sin_addr.s_addr),
ia, ia_hash);
IN_ADDRHASH_WRITER_INSERT_HEAD(ia);
mutex_exit(&in_ifaddr_lock);
}
if (error == 0) {
@ -662,8 +724,13 @@ in_control0(struct socket *so, u_long cmd, void *data, struct ifnet *ifp)
} else if (newifaddr) {
KASSERT(ia != NULL);
in_purgeaddr(&ia->ia_ifa);
ia = NULL;
}
out:
if (!newifaddr && ia != NULL)
ia4_release(ia, &psref);
curlwp_bindx(bound);
return error;
}
@ -704,10 +771,14 @@ in_ifremlocal(struct ifaddr *ifa)
struct in_ifaddr *ia, *p;
struct ifaddr *alt_ifa = NULL;
int ia_count = 0;
int s;
struct psref psref;
int bound = curlwp_bind();
ia = (struct in_ifaddr *)ifa;
/* Delete the entry if exactly one ifaddr matches the
* address, ifa->ifa_addr. */
s = pserialize_read_enter();
IN_ADDRLIST_READER_FOREACH(p) {
if (!in_hosteq(p->ia_addr.sin_addr, ia->ia_addr.sin_addr))
continue;
@ -716,35 +787,54 @@ in_ifremlocal(struct ifaddr *ifa)
if (++ia_count > 1 && alt_ifa != NULL)
break;
}
if (alt_ifa != NULL && ia_count > 1)
ifa_acquire(alt_ifa, &psref);
pserialize_read_exit(s);
if (ia_count == 0)
return;
goto out;
rt_ifa_remlocal(ifa, ia_count == 1 ? NULL : alt_ifa);
if (alt_ifa != NULL && ia_count > 1)
ifa_release(alt_ifa, &psref);
out:
curlwp_bindx(bound);
}
/*
* Depends on it isn't called in concurrent. It should be guaranteed
* by ifa->ifa_ifp's ioctl lock. The possible callers are in_control
* and if_purgeaddrs; the former is called iva ifa->ifa_ifp's ioctl
* and the latter is called via ifa->ifa_ifp's if_detach. The functions
* never be executed in concurrent.
*/
void
in_purgeaddr(struct ifaddr *ifa)
{
struct ifnet *ifp = ifa->ifa_ifp;
struct in_ifaddr *ia = (void *) ifa;
KASSERT(!ifa_held(ifa));
/* stop DAD processing */
if (ia->ia_dad_stop != NULL)
ia->ia_dad_stop(ifa);
in_ifscrub(ifp, ia);
in_ifremlocal(ifa);
LIST_REMOVE(ia, ia_hash);
IN_ADDRHASH_WRITER_REMOVE(ia);
IN_ADDRHASH_ENTRY_DESTROY(ia);
ifa_remove(ifp, &ia->ia_ifa);
TAILQ_REMOVE(&in_ifaddrhead, ia, ia_list);
IN_ADDRLIST_WRITER_REMOVE(ia);
IN_ADDRLIST_ENTRY_DESTROY(ia);
if (ia->ia_allhosts != NULL)
in_delmulti(ia->ia_allhosts);
mutex_enter(&in_ifaddr_lock);
LIST_REMOVE(ia, ia_hash);
IN_ADDRHASH_WRITER_REMOVE(ia);
TAILQ_REMOVE(&in_ifaddrhead, ia, ia_list);
IN_ADDRLIST_WRITER_REMOVE(ia);
ifa_remove(ifp, &ia->ia_ifa);
mutex_exit(&in_ifaddr_lock);
IN_ADDRHASH_ENTRY_DESTROY(ia);
IN_ADDRLIST_ENTRY_DESTROY(ia);
ifafree(&ia->ia_ifa);
in_setmaxmtu();
}
@ -1078,6 +1168,7 @@ in_addprefix(struct in_ifaddr *target, int flags)
struct in_ifaddr *ia;
struct in_addr prefix, mask, p;
int error;
int s;
if ((flags & RTF_HOST) != 0)
prefix = target->ia_dstaddr.sin_addr;
@ -1087,6 +1178,7 @@ in_addprefix(struct in_ifaddr *target, int flags)
prefix.s_addr &= mask.s_addr;
}
s = pserialize_read_enter();
IN_ADDRLIST_READER_FOREACH(ia) {
if (rtinitflags(ia))
p = ia->ia_dstaddr.sin_addr;
@ -1104,9 +1196,12 @@ in_addprefix(struct in_ifaddr *target, int flags)
*
* XXX RADIX_MPATH implications here? -dyoung
*/
if (ia->ia_flags & IFA_ROUTE)
if (ia->ia_flags & IFA_ROUTE) {
pserialize_read_exit(s);
return 0;
}
}
pserialize_read_exit(s);
/*
* noone seem to have prefix route. insert it.
@ -1134,6 +1229,7 @@ in_scrubprefix(struct in_ifaddr *target)
struct in_ifaddr *ia;
struct in_addr prefix, mask, p;
int error;
int s;
/* If we don't have IFA_ROUTE we should still inform userland */
if ((target->ia_flags & IFA_ROUTE) == 0)
@ -1147,6 +1243,7 @@ in_scrubprefix(struct in_ifaddr *target)
prefix.s_addr &= mask.s_addr;
}
s = pserialize_read_enter();
IN_ADDRLIST_READER_FOREACH(ia) {
if (rtinitflags(ia))
p = ia->ia_dstaddr.sin_addr;
@ -1162,6 +1259,12 @@ in_scrubprefix(struct in_ifaddr *target)
* if we got a matching prefix route, move IFA_ROUTE to him
*/
if ((ia->ia_flags & IFA_ROUTE) == 0) {
struct psref psref;
int bound = curlwp_bind();
ia4_acquire(ia, &psref);
pserialize_read_exit(s);
rtinit(&target->ia_ifa, RTM_DELETE,
rtinitflags(target));
target->ia_flags &= ~IFA_ROUTE;
@ -1170,9 +1273,14 @@ in_scrubprefix(struct in_ifaddr *target)
rtinitflags(ia) | RTF_UP);
if (error == 0)
ia->ia_flags |= IFA_ROUTE;
ia4_release(ia, &psref);
curlwp_bindx(bound);
return error;
}
}
pserialize_read_exit(s);
/*
* noone seem to have prefix route. remove it.
@ -1191,6 +1299,9 @@ int
in_broadcast(struct in_addr in, struct ifnet *ifp)
{
struct ifaddr *ifa;
int s;
KASSERT(ifp != NULL);
if (in.s_addr == INADDR_BROADCAST ||
in_nullhost(in))
@ -1202,7 +1313,8 @@ in_broadcast(struct in_addr in, struct ifnet *ifp)
* with a broadcast address.
*/
#define ia (ifatoia(ifa))
IFADDR_READER_FOREACH(ifa, ifp)
s = pserialize_read_enter();
IFADDR_READER_FOREACH(ifa, ifp) {
if (ifa->ifa_addr->sa_family == AF_INET &&
!in_hosteq(in, ia->ia_addr.sin_addr) &&
(in_hosteq(in, ia->ia_broadaddr.sin_addr) ||
@ -1212,8 +1324,12 @@ in_broadcast(struct in_addr in, struct ifnet *ifp)
* Check for old-style (host 0) broadcast.
*/
(in.s_addr == ia->ia_subnet ||
in.s_addr == ia->ia_net))))
in.s_addr == ia->ia_net)))) {
pserialize_read_exit(s);
return 1;
}
}
pserialize_read_exit(s);
return (0);
#undef ia
}
@ -1505,13 +1621,14 @@ in_multi_lock_held(void)
return rw_lock_held(&in_multilock);
}
struct sockaddr_in *
struct in_ifaddr *
in_selectsrc(struct sockaddr_in *sin, struct route *ro,
int soopts, struct ip_moptions *mopts, int *errorp)
int soopts, struct ip_moptions *mopts, int *errorp, struct psref *psref)
{
struct rtentry *rt = NULL;
struct in_ifaddr *ia = NULL;
KASSERT(ISSET(curlwp->l_pflag, LP_BOUND));
/*
* If route is known or can be allocated now, take the
* source address from the interface. Otherwise, punt.
@ -1535,20 +1652,45 @@ in_selectsrc(struct sockaddr_in *sin, struct route *ro,
*
* XXX Is this still true? Do we care?
*/
if (rt != NULL && (rt->rt_ifp->if_flags & IFF_LOOPBACK) == 0)
ia = ifatoia(rt->rt_ifa);
if (rt != NULL && (rt->rt_ifp->if_flags & IFF_LOOPBACK) == 0) {
int s;
struct ifaddr *ifa;
/*
* Just in case. May not need to do this workaround.
* Revisit when working on rtentry MP-ification.
*/
s = pserialize_read_enter();
IFADDR_READER_FOREACH(ifa, rt->rt_ifp) {
if (ifa == rt->rt_ifa)
break;
}
if (ifa != NULL)
ifa_acquire(ifa, psref);
pserialize_read_exit(s);
ia = ifatoia(ifa);
}
if (ia == NULL) {
u_int16_t fport = sin->sin_port;
struct ifaddr *ifa;
int s;
sin->sin_port = 0;
ia = ifatoia(ifa_ifwithladdr(sintosa(sin)));
ifa = ifa_ifwithladdr_psref(sintosa(sin), psref);
sin->sin_port = fport;
if (ia == NULL) {
if (ifa == NULL) {
/* Find 1st non-loopback AF_INET address */
s = pserialize_read_enter();
IN_ADDRLIST_READER_FOREACH(ia) {
if (!(ia->ia_ifp->if_flags & IFF_LOOPBACK))
break;
}
if (ia != NULL)
ia4_acquire(ia, psref);
pserialize_read_exit(s);
} else {
/* ia is already referenced by psref */
ia = ifatoia(ifa);
}
if (ia == NULL) {
*errorp = EADDRNOTAVAIL;
@ -1566,15 +1708,21 @@ in_selectsrc(struct sockaddr_in *sin, struct route *ro,
imo = mopts;
if (imo->imo_multicast_if_index != 0) {
struct ifnet *ifp;
int s = pserialize_read_enter();
int s;
if (ia != NULL)
ia4_release(ia, psref);
s = pserialize_read_enter();
ifp = if_byindex(imo->imo_multicast_if_index);
if (ifp != NULL) {
ia = in_get_ia_from_ifp(ifp); /* XXX */
/* XXX */
ia = in_get_ia_from_ifp_psref(ifp, psref);
} else
ia = NULL;
if (ia == NULL || ia->ia4_flags & IN_IFF_NOTREADY) {
pserialize_read_exit(s);
if (ia != NULL)
ia4_release(ia, psref);
*errorp = EADDRNOTAVAIL;
return NULL;
}
@ -1588,12 +1736,14 @@ in_selectsrc(struct sockaddr_in *sin, struct route *ro,
*errorp = EADDRNOTAVAIL;
return NULL;
}
/* FIXME NOMPSAFE */
ia4_acquire(ia, psref);
}
#ifdef GETIFA_DEBUG
else
printf("%s: missing ifa_getifa\n", __func__);
#endif
return &ia->ia_addr;
return ia;
}
#if NARP > 0

View File

@ -1,4 +1,4 @@
/* $NetBSD: in.h,v 1.98 2015/10/13 21:28:35 rjs Exp $ */
/* $NetBSD: in.h,v 1.99 2016/08/01 03:15:30 ozaki-r Exp $ */
/*
* Copyright (c) 1982, 1986, 1990, 1993
@ -507,6 +507,8 @@ struct ip_mreq {
#undef __KAME_NETINET_IN_H_INCLUDED_
#ifdef _KERNEL
#include <sys/psref.h>
/*
* in_cksum_phdr:
*
@ -576,8 +578,8 @@ void in_if_link_state_change(struct ifnet *, int);
struct route;
struct ip_moptions;
struct sockaddr_in *in_selectsrc(struct sockaddr_in *,
struct route *, int, struct ip_moptions *, int *);
struct in_ifaddr *in_selectsrc(struct sockaddr_in *,
struct route *, int, struct ip_moptions *, int *, struct psref *);
#define in_hosteq(s,t) ((s).s_addr == (t).s_addr)
#define in_nullhost(x) ((x).s_addr == INADDR_ANY)

View File

@ -1,4 +1,4 @@
/* $NetBSD: in_gif.c,v 1.81 2016/07/06 08:42:34 ozaki-r Exp $ */
/* $NetBSD: in_gif.c,v 1.82 2016/08/01 03:15:30 ozaki-r Exp $ */
/* $KAME: in_gif.c,v 1.66 2001/07/29 04:46:09 itojun Exp $ */
/*
@ -31,7 +31,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: in_gif.c,v 1.81 2016/07/06 08:42:34 ozaki-r Exp $");
__KERNEL_RCSID(0, "$NetBSD: in_gif.c,v 1.82 2016/08/01 03:15:30 ozaki-r Exp $");
#ifdef _KERNEL_OPT
#include "opt_inet.h"
@ -289,6 +289,7 @@ gif_validate4(const struct ip *ip, struct gif_softc *sc, struct ifnet *ifp)
{
struct sockaddr_in *src, *dst;
struct in_ifaddr *ia4;
int s;
src = satosin(sc->gif_psrc);
dst = satosin(sc->gif_pdst);
@ -306,12 +307,16 @@ gif_validate4(const struct ip *ip, struct gif_softc *sc, struct ifnet *ifp)
return 0;
}
/* reject packets with broadcast on source */
s = pserialize_read_enter();
IN_ADDRLIST_READER_FOREACH(ia4) {
if ((ia4->ia_ifa.ifa_ifp->if_flags & IFF_BROADCAST) == 0)
continue;
if (ip->ip_src.s_addr == ia4->ia_broadaddr.sin_addr.s_addr)
if (ip->ip_src.s_addr == ia4->ia_broadaddr.sin_addr.s_addr) {
pserialize_read_exit(s);
return 0;
}
}
pserialize_read_exit(s);
/* ingress filters on outer source */
if ((sc->gif_if.if_flags & IFF_LINK2) == 0 && ifp) {

View File

@ -1,4 +1,4 @@
/* $NetBSD: in_pcb.c,v 1.167 2016/07/20 03:38:09 ozaki-r Exp $ */
/* $NetBSD: in_pcb.c,v 1.168 2016/08/01 03:15:30 ozaki-r Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@ -93,7 +93,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: in_pcb.c,v 1.167 2016/07/20 03:38:09 ozaki-r Exp $");
__KERNEL_RCSID(0, "$NetBSD: in_pcb.c,v 1.168 2016/08/01 03:15:30 ozaki-r Exp $");
#ifdef _KERNEL_OPT
#include "opt_inet.h"
@ -275,27 +275,39 @@ in_pcbsetport(struct sockaddr_in *sin, struct inpcb *inp, kauth_cred_t cred)
static int
in_pcbbind_addr(struct inpcb *inp, struct sockaddr_in *sin, kauth_cred_t cred)
{
int error = EADDRNOTAVAIL;
struct ifaddr *ifa = NULL;
int s;
if (sin->sin_family != AF_INET)
return (EAFNOSUPPORT);
s = pserialize_read_enter();
if (IN_MULTICAST(sin->sin_addr.s_addr)) {
/* Always succeed; port reuse handled in in_pcbbind_port(). */
} else if (!in_nullhost(sin->sin_addr)) {
struct in_ifaddr *ia = NULL;
struct in_ifaddr *ia;
ia = in_get_ia(sin->sin_addr);
/* check for broadcast addresses */
if (ia == NULL) {
ifa = ifa_ifwithaddr(sintosa(sin));
if (ifa != NULL)
ia = ifatoia(ifa);
}
if (ia == NULL)
ia = ifatoia(ifa_ifwithaddr(sintosa(sin)));
if (ia == NULL)
return (EADDRNOTAVAIL);
goto error;
if (ia->ia4_flags & (IN_IFF_NOTREADY | IN_IFF_DETACHED))
return (EADDRNOTAVAIL);
goto error;
}
pserialize_read_exit(s);
inp->inp_laddr = sin->sin_addr;
return (0);
error:
pserialize_read_exit(s);
return error;
}
static int
@ -484,6 +496,7 @@ in_pcbconnect(void *v, struct sockaddr_in *sin, struct lwp *l)
IN_ADDRLIST_READER_FIRST()->ia_addr.sin_addr;
} else if (sin->sin_addr.s_addr == INADDR_BROADCAST) {
struct in_ifaddr *ia;
int s = pserialize_read_enter();
IN_ADDRLIST_READER_FOREACH(ia) {
if (ia->ia_ifp->if_flags & IFF_BROADCAST) {
sin->sin_addr =
@ -491,6 +504,7 @@ in_pcbconnect(void *v, struct sockaddr_in *sin, struct lwp *l)
break;
}
}
pserialize_read_exit(s);
}
}
/*
@ -507,26 +521,40 @@ in_pcbconnect(void *v, struct sockaddr_in *sin, struct lwp *l)
*/
if (in_nullhost(inp->inp_laddr)) {
int xerror;
struct sockaddr_in *ifaddr;
struct in_ifaddr *ia;
struct in_ifaddr *ia, *_ia;
int s;
struct psref psref;
int bound;
ifaddr = in_selectsrc(sin, &inp->inp_route,
inp->inp_socket->so_options, inp->inp_moptions, &xerror);
if (ifaddr == NULL) {
bound = curlwp_bind();
ia = in_selectsrc(sin, &inp->inp_route,
inp->inp_socket->so_options, inp->inp_moptions, &xerror,
&psref);
if (ia == NULL) {
curlwp_bindx(bound);
if (xerror == 0)
xerror = EADDRNOTAVAIL;
return xerror;
}
ia = in_get_ia(ifaddr->sin_addr);
if (ia == NULL)
s = pserialize_read_enter();
_ia = in_get_ia(IA_SIN(ia)->sin_addr);
if (_ia == NULL) {
pserialize_read_exit(s);
ia4_release(ia, &psref);
curlwp_bindx(bound);
return (EADDRNOTAVAIL);
laddr = ifaddr->sin_addr;
}
pserialize_read_exit(s);
laddr = IA_SIN(ia)->sin_addr;
ia4_release(ia, &psref);
curlwp_bindx(bound);
} else
laddr = inp->inp_laddr;
if (in_pcblookup_connect(inp->inp_table, sin->sin_addr, sin->sin_port,
laddr, inp->inp_lport, &vestige) != 0
|| vestige.valid)
laddr, inp->inp_lport, &vestige) != NULL ||
vestige.valid) {
return (EADDRINUSE);
}
if (in_nullhost(inp->inp_laddr)) {
if (inp->inp_lport == 0) {
error = in_pcbbind(inp, NULL, l);

View File

@ -1,4 +1,4 @@
/* $NetBSD: in_var.h,v 1.78 2016/07/08 04:33:30 ozaki-r Exp $ */
/* $NetBSD: in_var.h,v 1.79 2016/08/01 03:15:30 ozaki-r Exp $ */
/*-
* Copyright (c) 1998 The NetBSD Foundation, Inc.
@ -111,6 +111,25 @@ struct in_ifaddr {
#endif
};
#ifdef _KERNEL
static inline void
ia4_acquire(struct in_ifaddr *ia, struct psref *psref)
{
KASSERT(ia != NULL);
ifa_acquire(&ia->ia_ifa, psref);
}
static inline void
ia4_release(struct in_ifaddr *ia, struct psref *psref)
{
if (ia == NULL)
return;
ifa_release(&ia->ia_ifa, psref);
}
#endif
struct in_aliasreq {
char ifra_name[IFNAMSIZ]; /* if name, e.g. "en0" */
struct sockaddr_in ifra_addr;
@ -125,6 +144,8 @@ struct in_aliasreq {
*/
#define IA_SIN(ia) (&(((struct in_ifaddr *)(ia))->ia_addr))
#define iatoifa(ia) (struct ifaddr *)(ia)
#ifdef _KERNEL
/* Note: 61, 127, 251, 509, 1021, 2039 are good. */
@ -238,6 +259,21 @@ in_get_ia(struct in_addr addr)
return ia;
}
static inline struct in_ifaddr *
in_get_ia_psref(struct in_addr addr, struct psref *psref)
{
struct in_ifaddr *ia;
int s;
s = pserialize_read_enter();
ia = in_get_ia(addr);
if (ia != NULL)
ia4_acquire(ia, psref);
pserialize_read_exit(s);
return ia;
}
/*
* Find whether an internet address (in_addr) belongs to a specified
* interface. NULL if the address isn't ours.
@ -256,6 +292,21 @@ in_get_ia_on_iface(struct in_addr addr, struct ifnet *ifp)
return ia;
}
static inline struct in_ifaddr *
in_get_ia_on_iface_psref(struct in_addr addr, struct ifnet *ifp, struct psref *psref)
{
struct in_ifaddr *ia;
int s;
s = pserialize_read_enter();
ia = in_get_ia_on_iface(addr, ifp);
if (ia != NULL)
ia4_acquire(ia, psref);
pserialize_read_exit(s);
return ia;
}
/*
* Find an internet address structure (in_ifaddr) corresponding
* to a given interface (ifnet structure).
@ -273,6 +324,21 @@ in_get_ia_from_ifp(struct ifnet *ifp)
return ifatoia(ifa);
}
static inline struct in_ifaddr *
in_get_ia_from_ifp_psref(struct ifnet *ifp, struct psref *psref)
{
struct in_ifaddr *ia;
int s;
s = pserialize_read_enter();
ia = in_get_ia_from_ifp(ifp);
if (ia != NULL)
ia4_acquire(ia, psref);
pserialize_read_exit(s);
return ia;
}
#include <netinet/in_selsrc.h>
/*
* IPv4 per-interface state.

View File

@ -1,4 +1,4 @@
/* $NetBSD: ip_carp.c,v 1.76 2016/07/23 13:37:10 is Exp $ */
/* $NetBSD: ip_carp.c,v 1.77 2016/08/01 03:15:30 ozaki-r Exp $ */
/* $OpenBSD: ip_carp.c,v 1.113 2005/11/04 08:11:54 mcbride Exp $ */
/*
@ -33,7 +33,7 @@
#endif
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: ip_carp.c,v 1.76 2016/07/23 13:37:10 is Exp $");
__KERNEL_RCSID(0, "$NetBSD: ip_carp.c,v 1.77 2016/08/01 03:15:30 ozaki-r Exp $");
/*
* TODO:
@ -635,15 +635,18 @@ carp_proto_input_c(struct mbuf *m, struct carp_header *ch, sa_family_t af)
if ((sc->sc_carpdev->if_flags & IFF_SIMPLEX) == 0) {
struct sockaddr sa;
struct ifaddr *ifa;
int s;
memset(&sa, 0, sizeof(sa));
sa.sa_family = af;
s = pserialize_read_enter();
ifa = ifaof_ifpforaddr(&sa, sc->sc_carpdev);
if (ifa && af == AF_INET) {
struct ip *ip = mtod(m, struct ip *);
if (ip->ip_src.s_addr ==
ifatoia(ifa)->ia_addr.sin_addr.s_addr) {
pserialize_read_exit(s);
m_freem(m);
return;
}
@ -660,11 +663,13 @@ carp_proto_input_c(struct mbuf *m, struct carp_header *ch, sa_family_t af)
if (IN6_IS_ADDR_LINKLOCAL(&in6_found))
in6_found.s6_addr16[1] = 0;
if (IN6_ARE_ADDR_EQUAL(&in6_src, &in6_found)) {
pserialize_read_exit(s);
m_freem(m);
return;
}
}
#endif /* INET6 */
pserialize_read_exit(s);
}
nanotime(&sc->sc_if.if_lastchange);
@ -989,7 +994,6 @@ carp_send_ad(void *v)
struct carp_header *ch_ptr;
struct mbuf *m;
int error, len, advbase, advskew, s;
struct ifaddr *ifa;
struct sockaddr sa;
KERNEL_LOCK(1, NULL);
@ -1029,6 +1033,8 @@ carp_send_ad(void *v)
#ifdef INET
if (sc->sc_naddrs) {
struct ip *ip;
struct ifaddr *ifa;
int _s;
MGETHDR(m, M_DONTWAIT, MT_HEADER);
if (m == NULL) {
@ -1057,12 +1063,14 @@ carp_send_ad(void *v)
memset(&sa, 0, sizeof(sa));
sa.sa_family = AF_INET;
_s = pserialize_read_enter();
ifa = ifaof_ifpforaddr(&sa, sc->sc_carpdev);
if (ifa == NULL)
ip->ip_src.s_addr = 0;
else
ip->ip_src.s_addr =
ifatoia(ifa)->ia_addr.sin_addr.s_addr;
pserialize_read_exit(_s);
ip->ip_dst.s_addr = INADDR_CARP_GROUP;
ch_ptr = (struct carp_header *)(&ip[1]);
@ -1110,6 +1118,8 @@ carp_send_ad(void *v)
#ifdef INET6_notyet
if (sc->sc_naddrs6) {
struct ip6_hdr *ip6;
struct ifaddr *ifa;
int _s;
MGETHDR(m, M_DONTWAIT, MT_HEADER);
if (m == NULL) {
@ -1134,12 +1144,14 @@ carp_send_ad(void *v)
/* set the source address */
memset(&sa, 0, sizeof(sa));
sa.sa_family = AF_INET6;
_s = pserialize_read_enter();
ifa = ifaof_ifpforaddr(&sa, sc->sc_carpdev);
if (ifa == NULL) /* This should never happen with IPv6 */
memset(&ip6->ip6_src, 0, sizeof(struct in6_addr));
else
bcopy(ifatoia6(ifa)->ia_addr.sin6_addr.s6_addr,
&ip6->ip6_src, sizeof(struct in6_addr));
pserialize_read_exit(_s);
/* set the multicast destination */
ip6->ip6_dst.s6_addr16[0] = htons(0xff02);
@ -1746,6 +1758,7 @@ carp_set_addr(struct carp_softc *sc, struct sockaddr_in *sin)
struct ifnet *ifp = sc->sc_carpdev;
struct in_ifaddr *ia, *ia_if;
int error = 0;
int s;
if (sin->sin_addr.s_addr == 0) {
if (!(sc->sc_if.if_flags & IFF_UP))
@ -1758,6 +1771,7 @@ carp_set_addr(struct carp_softc *sc, struct sockaddr_in *sin)
/* we have to do this by hand to ensure we don't match on ourselves */
ia_if = NULL;
s = pserialize_read_enter();
IN_ADDRLIST_READER_FOREACH(ia) {
/* and, yeah, we need a multicast-capable iface too */
if (ia->ia_ifp != &sc->sc_if &&
@ -1776,9 +1790,11 @@ carp_set_addr(struct carp_softc *sc, struct sockaddr_in *sin)
if (ifp != ia->ia_ifp)
return (EADDRNOTAVAIL);
} else {
/* FIXME NOMPSAFE */
ifp = ia->ia_ifp;
}
}
pserialize_read_exit(s);
if ((error = carp_set_ifp(sc, ifp)))
return (error);
@ -1836,6 +1852,7 @@ carp_set_addr6(struct carp_softc *sc, struct sockaddr_in6 *sin6)
struct ifnet *ifp = sc->sc_carpdev;
struct in6_ifaddr *ia, *ia_if;
int error = 0;
int s;
if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
if (!(sc->sc_if.if_flags & IFF_UP))
@ -1848,6 +1865,7 @@ carp_set_addr6(struct carp_softc *sc, struct sockaddr_in6 *sin6)
/* we have to do this by hand to ensure we don't match on ourselves */
ia_if = NULL;
s = pserialize_read_enter();
IN6_ADDRLIST_READER_FOREACH(ia) {
int i;
@ -1867,6 +1885,7 @@ carp_set_addr6(struct carp_softc *sc, struct sockaddr_in6 *sin6)
ia_if = ia;
}
}
pserialize_read_exit(s);
if (ia_if) {
ia = ia_if;

View File

@ -1,4 +1,4 @@
/* $NetBSD: ip_icmp.c,v 1.150 2016/07/08 04:33:30 ozaki-r Exp $ */
/* $NetBSD: ip_icmp.c,v 1.151 2016/08/01 03:15:30 ozaki-r Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@ -94,7 +94,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: ip_icmp.c,v 1.150 2016/07/08 04:33:30 ozaki-r Exp $");
__KERNEL_RCSID(0, "$NetBSD: ip_icmp.c,v 1.151 2016/08/01 03:15:30 ozaki-r Exp $");
#ifdef _KERNEL_OPT
#include "opt_ipsec.h"
@ -562,7 +562,8 @@ icmp_input(struct mbuf *m, ...)
case ICMP_MASKREQ: {
struct ifnet *rcvif;
int s;
int s, ss;
struct ifaddr *ifa;
if (icmpmaskrepl == 0)
break;
@ -579,12 +580,15 @@ icmp_input(struct mbuf *m, ...)
icmpdst.sin_addr = ip->ip_src;
else
icmpdst.sin_addr = ip->ip_dst;
ss = pserialize_read_enter();
rcvif = m_get_rcvif(m, &s);
ia = ifatoia(ifaof_ifpforaddr(sintosa(&icmpdst),
rcvif));
ifa = ifaof_ifpforaddr(sintosa(&icmpdst), rcvif);
m_put_rcvif(rcvif, &s);
if (ia == 0)
if (ifa == NULL) {
pserialize_read_exit(ss);
break;
}
ia = ifatoia(ifa);
icp->icmp_type = ICMP_MASKREPLY;
icp->icmp_mask = ia->ia_sockmask.sin_addr.s_addr;
if (in_nullhost(ip->ip_src)) {
@ -593,6 +597,7 @@ icmp_input(struct mbuf *m, ...)
else if (ia->ia_ifp->if_flags & IFF_POINTOPOINT)
ip->ip_src = ia->ia_dstaddr.sin_addr;
}
pserialize_read_exit(ss);
reflect:
{
uint64_t *icps = percpu_getref(icmpstat_percpu);
@ -693,7 +698,11 @@ icmp_reflect(struct mbuf *m)
struct mbuf *opts = NULL;
int optlen = (ip->ip_hl << 2) - sizeof(struct ip);
struct ifnet *rcvif;
struct psref psref;
struct psref psref, psref_ia;
int s;
int bound;
bound = curlwp_bind();
if (!in_canforward(ip->ip_src) &&
((ip->ip_src.s_addr & IN_CLASSA_NET) !=
@ -712,15 +721,18 @@ icmp_reflect(struct mbuf *m)
*/
/* Look for packet addressed to us */
ia = in_get_ia(t);
if (ia && (ia->ia4_flags & IN_IFF_NOTREADY))
ia = in_get_ia_psref(t, &psref_ia);
if (ia && (ia->ia4_flags & IN_IFF_NOTREADY)) {
ia4_release(ia, &psref_ia);
ia = NULL;
}
rcvif = m_get_rcvif_psref(m, &psref);
/* look for packet sent to broadcast address */
if (ia == NULL && rcvif &&
(rcvif->if_flags & IFF_BROADCAST)) {
s = pserialize_read_enter();
IFADDR_READER_FOREACH(ifa, rcvif) {
if (ifa->ifa_addr->sa_family != AF_INET)
continue;
@ -731,6 +743,9 @@ icmp_reflect(struct mbuf *m)
ia = NULL;
}
}
if (ia != NULL)
ia4_acquire(ia, &psref_ia);
pserialize_read_exit(s);
}
sin = ia ? &ia->ia_addr : NULL;
@ -751,14 +766,17 @@ icmp_reflect(struct mbuf *m)
sockaddr_in_init(&sin_dst, &ip->ip_dst, 0);
memset(&icmproute, 0, sizeof(icmproute));
errornum = 0;
sin = in_selectsrc(&sin_dst, &icmproute, 0, NULL, &errornum);
ia = in_selectsrc(&sin_dst, &icmproute, 0, NULL, &errornum,
&psref_ia);
/* errornum is never used */
rtcache_free(&icmproute);
/* check to make sure sin is a source address on rcvif */
if (sin) {
if (ia != NULL) {
sin = &ia->ia_addr;
t = sin->sin_addr;
sin = NULL;
ia = in_get_ia_on_iface(t, rcvif);
ia4_release(ia, &psref_ia);
ia = in_get_ia_on_iface_psref(t, rcvif, &psref_ia);
if (ia != NULL)
sin = &ia->ia_addr;
}
@ -771,12 +789,16 @@ icmp_reflect(struct mbuf *m)
* when the incoming packet was encapsulated
*/
if (sin == NULL && rcvif) {
KASSERT(ia == NULL);
s = pserialize_read_enter();
IFADDR_READER_FOREACH(ifa, rcvif) {
if (ifa->ifa_addr->sa_family != AF_INET)
continue;
sin = &(ifatoia(ifa)->ia_addr);
ia4_acquire(ifatoia(ifa), &psref_ia);
break;
}
pserialize_read_exit(s);
}
m_put_rcvif_psref(rcvif, &psref);
@ -787,19 +809,25 @@ icmp_reflect(struct mbuf *m)
* We find the first AF_INET address on the first non-loopback
* interface.
*/
if (sin == NULL)
if (sin == NULL) {
KASSERT(ia == NULL);
s = pserialize_read_enter();
IN_ADDRLIST_READER_FOREACH(ia) {
if (ia->ia_ifp->if_flags & IFF_LOOPBACK)
continue;
sin = &ia->ia_addr;
ia4_acquire(ia, &psref_ia);
break;
}
pserialize_read_exit(s);
}
/*
* If we still didn't find an address, punt. We could have an
* interface up (and receiving packets) with no address.
*/
if (sin == NULL) {
KASSERT(ia == NULL);
m_freem(m);
goto done;
}
@ -807,6 +835,9 @@ icmp_reflect(struct mbuf *m)
ip->ip_src = sin->sin_addr;
ip->ip_ttl = MAXTTL;
if (ia != NULL)
ia4_release(ia, &psref_ia);
if (optlen > 0) {
u_char *cp;
int opt, cnt;
@ -890,6 +921,7 @@ icmp_reflect(struct mbuf *m)
icmp_send(m, opts);
done:
curlwp_bindx(bound);
if (opts)
(void)m_free(opts);
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: ip_input.c,v 1.338 2016/07/26 08:34:55 ozaki-r Exp $ */
/* $NetBSD: ip_input.c,v 1.339 2016/08/01 03:15:30 ozaki-r Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@ -91,7 +91,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: ip_input.c,v 1.338 2016/07/26 08:34:55 ozaki-r Exp $");
__KERNEL_RCSID(0, "$NetBSD: ip_input.c,v 1.339 2016/08/01 03:15:30 ozaki-r Exp $");
#ifdef _KERNEL_OPT
#include "opt_inet.h"
@ -447,12 +447,13 @@ static void
ip_input(struct mbuf *m)
{
struct ip *ip = NULL;
struct in_ifaddr *ia;
struct in_ifaddr *ia = NULL;
int hlen = 0, len;
int downmatch;
int srcrt = 0;
ifnet_t *ifp;
struct psref psref;
int s;
KASSERTMSG(cpu_softintr_p(), "ip_input: not in the software "
"interrupt handler; synchronization assumptions violated");
@ -665,15 +666,21 @@ ip_input(struct mbuf *m)
* or IN_IFF_NOTREADY addresses as not mine.
*/
downmatch = 0;
s = pserialize_read_enter();
ia = ip_match_our_address(ifp, ip, &downmatch);
if (ia != NULL)
if (ia != NULL) {
pserialize_read_exit(s);
goto ours;
}
if (ifp->if_flags & IFF_BROADCAST) {
ia = ip_match_our_address_broadcast(ifp, ip);
if (ia != NULL)
if (ia != NULL) {
pserialize_read_exit(s);
goto ours;
}
}
pserialize_read_exit(s);
if (IN_MULTICAST(ip->ip_dst.s_addr)) {
#ifdef MROUTING
@ -810,8 +817,17 @@ ours:
* Switch out to protocol's input routine.
*/
#if IFA_STATS
if (ia && ip)
ia->ia_ifa.ifa_data.ifad_inbytes += ntohs(ip->ip_len);
if (ia && ip) {
struct in_ifaddr *_ia;
/*
* Keep a reference from ip_match_our_address with psref
* is expensive, so explore ia here again.
*/
s = pserialize_read_enter();
_ia = in_get_ia(ip->ip_dst.s_addr);
_ia->ia_ifa.ifa_data.ifad_inbytes += ntohs(ip->ip_len);
pserialize_read_exit(s);
}
#endif
IP_STATINC(IP_STAT_DELIVERED);
@ -873,6 +889,8 @@ ip_dooptions(struct mbuf *m)
int opt, optlen, cnt, off, code, type = ICMP_PARAMPROB, forward = 0;
struct in_addr dst;
n_time ntime;
struct ifaddr *ifa;
int s;
dst = ip->ip_dst;
cp = (u_char *)(ip + 1);
@ -924,8 +942,11 @@ ip_dooptions(struct mbuf *m)
goto bad;
}
ipaddr.sin_addr = ip->ip_dst;
ia = ifatoia(ifa_ifwithaddr(sintosa(&ipaddr)));
if (ia == 0) {
s = pserialize_read_enter();
ifa = ifa_ifwithaddr(sintosa(&ipaddr));
if (ifa == NULL) {
pserialize_read_exit(s);
if (opt == IPOPT_SSRR) {
type = ICMP_UNREACH;
code = ICMP_UNREACH_SRCFAIL;
@ -937,6 +958,8 @@ ip_dooptions(struct mbuf *m)
*/
break;
}
pserialize_read_exit(s);
off--; /* 0 origin */
if ((off + sizeof(struct in_addr)) > optlen) {
/*
@ -950,18 +973,26 @@ ip_dooptions(struct mbuf *m)
*/
memcpy((void *)&ipaddr.sin_addr, (void *)(cp + off),
sizeof(ipaddr.sin_addr));
if (opt == IPOPT_SSRR)
ia = ifatoia(ifa_ifwithladdr(sintosa(&ipaddr)));
else
s = pserialize_read_enter();
if (opt == IPOPT_SSRR) {
ifa = ifa_ifwithladdr(sintosa(&ipaddr));
if (ifa != NULL)
ia = ifatoia(ifa);
else
ia = NULL;
} else {
ia = ip_rtaddr(ipaddr.sin_addr);
if (ia == 0) {
}
if (ia == NULL) {
type = ICMP_UNREACH;
code = ICMP_UNREACH_SRCFAIL;
pserialize_read_exit(s);
goto bad;
}
ip->ip_dst = ipaddr.sin_addr;
bcopy((void *)&ia->ia_addr.sin_addr,
(void *)(cp + off), sizeof(struct in_addr));
pserialize_read_exit(s);
cp[IPOPT_OFFSET] += sizeof(struct in_addr);
/*
* Let ip_intr's mcast routing check handle mcast pkts
@ -990,15 +1021,22 @@ ip_dooptions(struct mbuf *m)
* locate outgoing interface; if we're the destination,
* use the incoming interface (should be same).
*/
if ((ia = ifatoia(ifa_ifwithaddr(sintosa(&ipaddr))))
== NULL &&
(ia = ip_rtaddr(ipaddr.sin_addr)) == NULL) {
type = ICMP_UNREACH;
code = ICMP_UNREACH_HOST;
goto bad;
s = pserialize_read_enter();
ifa = ifa_ifwithaddr(sintosa(&ipaddr));
if (ifa == NULL) {
ia = ip_rtaddr(ipaddr.sin_addr);
if (ia == NULL) {
pserialize_read_exit(s);
type = ICMP_UNREACH;
code = ICMP_UNREACH_HOST;
goto bad;
}
} else {
ia = ifatoia(ifa);
}
bcopy((void *)&ia->ia_addr.sin_addr,
(void *)(cp + off), sizeof(struct in_addr));
pserialize_read_exit(s);
cp[IPOPT_OFFSET] += sizeof(struct in_addr);
break;
@ -1029,7 +1067,7 @@ ip_dooptions(struct mbuf *m)
case IPOPT_TS_TSANDADDR: {
struct ifnet *rcvif;
int s;
int _s, _ss;
if (ipt->ipt_ptr - 1 + sizeof(n_time) +
sizeof(struct in_addr) > ipt->ipt_len) {
@ -1038,14 +1076,18 @@ ip_dooptions(struct mbuf *m)
goto bad;
}
ipaddr.sin_addr = dst;
rcvif = m_get_rcvif(m, &s);
ia = ifatoia(ifaof_ifpforaddr(sintosa(&ipaddr),
rcvif));
m_put_rcvif(rcvif, &s);
if (ia == 0)
continue;
_ss = pserialize_read_enter();
rcvif = m_get_rcvif(m, &_s);
ifa = ifaof_ifpforaddr(sintosa(&ipaddr), rcvif);
m_put_rcvif(rcvif, &_s);
if (ifa == NULL) {
pserialize_read_exit(_ss);
break;
}
ia = ifatoia(ifa);
bcopy(&ia->ia_addr.sin_addr,
cp0, sizeof(struct in_addr));
pserialize_read_exit(_ss);
ipt->ipt_ptr += sizeof(struct in_addr);
break;
}
@ -1059,9 +1101,13 @@ ip_dooptions(struct mbuf *m)
}
memcpy(&ipaddr.sin_addr, cp0,
sizeof(struct in_addr));
if (ifatoia(ifa_ifwithaddr(sintosa(&ipaddr)))
== NULL)
s = pserialize_read_enter();
ifa = ifa_ifwithaddr(sintosa(&ipaddr));
if (ifa == NULL) {
pserialize_read_exit(s);
continue;
}
pserialize_read_exit(s);
ipt->ipt_ptr += sizeof(struct in_addr);
break;
@ -1080,7 +1126,7 @@ ip_dooptions(struct mbuf *m)
}
if (forward) {
struct ifnet *rcvif;
struct psref psref;
struct psref _psref;
if (ip_forwsrcrt == 0) {
type = ICMP_UNREACH;
@ -1088,14 +1134,14 @@ ip_dooptions(struct mbuf *m)
goto bad;
}
rcvif = m_get_rcvif_psref(m, &psref);
rcvif = m_get_rcvif_psref(m, &_psref);
if (__predict_false(rcvif == NULL)) {
type = ICMP_UNREACH;
code = ICMP_UNREACH_HOST;
goto bad;
}
ip_forward(m, 1, rcvif);
m_put_rcvif_psref(rcvif, &psref);
m_put_rcvif_psref(rcvif, &_psref);
return true;
}
return false;

View File

@ -1,4 +1,4 @@
/* $NetBSD: ip_mroute.c,v 1.143 2016/07/04 04:35:09 knakahara Exp $ */
/* $NetBSD: ip_mroute.c,v 1.144 2016/08/01 03:15:30 ozaki-r Exp $ */
/*
* Copyright (c) 1992, 1993
@ -93,7 +93,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: ip_mroute.c,v 1.143 2016/07/04 04:35:09 knakahara Exp $");
__KERNEL_RCSID(0, "$NetBSD: ip_mroute.c,v 1.144 2016/08/01 03:15:30 ozaki-r Exp $");
#ifdef _KERNEL_OPT
#include "opt_inet.h"
@ -785,7 +785,6 @@ static int
add_vif(struct vifctl *vifcp)
{
struct vif *vifp;
struct ifaddr *ifa;
struct ifnet *ifp;
int error, s;
struct sockaddr_in sin;
@ -811,11 +810,18 @@ add_vif(struct vifctl *vifcp)
} else
#endif
{
struct ifaddr *ifa;
sockaddr_in_init(&sin, &vifcp->vifc_lcl_addr, 0);
s = pserialize_read_enter();
ifa = ifa_ifwithaddr(sintosa(&sin));
if (ifa == NULL)
return (EADDRNOTAVAIL);
if (ifa == NULL) {
pserialize_read_exit(s);
return EADDRNOTAVAIL;
}
ifp = ifa->ifa_ifp;
/* FIXME NOMPSAFE */
pserialize_read_exit(s);
}
if (vifcp->vifc_flags & VIFF_TUNNEL) {

View File

@ -1,4 +1,4 @@
/* $NetBSD: ip_output.c,v 1.259 2016/07/08 04:33:30 ozaki-r Exp $ */
/* $NetBSD: ip_output.c,v 1.260 2016/08/01 03:15:30 ozaki-r Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@ -91,7 +91,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: ip_output.c,v 1.259 2016/07/08 04:33:30 ozaki-r Exp $");
__KERNEL_RCSID(0, "$NetBSD: ip_output.c,v 1.260 2016/08/01 03:15:30 ozaki-r Exp $");
#ifdef _KERNEL_OPT
#include "opt_inet.h"
@ -112,6 +112,7 @@ __KERNEL_RCSID(0, "$NetBSD: ip_output.c,v 1.259 2016/07/08 04:33:30 ozaki-r Exp
#include <sys/domain.h>
#endif
#include <sys/systm.h>
#include <sys/syslog.h>
#include <net/if.h>
#include <net/if_types.h>
@ -235,7 +236,7 @@ ip_output(struct mbuf *m0, struct mbuf *opt, struct route *ro, int flags,
int len, error = 0;
struct route iproute;
const struct sockaddr_in *dst;
struct in_ifaddr *ia;
struct in_ifaddr *ia = NULL;
int isbroadcast;
int sw_csum;
u_long mtu;
@ -251,8 +252,9 @@ ip_output(struct mbuf *m0, struct mbuf *opt, struct route *ro, int flags,
struct sockaddr *rdst = &u.dst; /* real IP destination, as opposed
* to the nexthop
*/
struct psref psref;
struct psref psref, psref_ia;
int bound;
bool bind_need_restore = false;
len = 0;
@ -311,15 +313,23 @@ ip_output(struct mbuf *m0, struct mbuf *opt, struct route *ro, int flags,
goto bad;
}
bound = curlwp_bind();
bind_need_restore = true;
/*
* If routing to interface only, short circuit routing lookup.
*/
if (flags & IP_ROUTETOIF) {
if ((ia = ifatoia(ifa_ifwithladdr(sintocsa(dst)))) == NULL) {
struct ifaddr *ifa;
ifa = ifa_ifwithladdr_psref(sintocsa(dst), &psref_ia);
if (ifa == NULL) {
IP_STATINC(IP_STAT_NOROUTE);
error = ENETUNREACH;
goto bad;
}
/* ia is already referenced by psref_ia */
ia = ifatoia(ifa);
ifp = ia->ia_ifp;
mtu = ifp->if_mtu;
ip->ip_ttl = 1;
@ -327,16 +337,18 @@ ip_output(struct mbuf *m0, struct mbuf *opt, struct route *ro, int flags,
} else if ((IN_MULTICAST(ip->ip_dst.s_addr) ||
ip->ip_dst.s_addr == INADDR_BROADCAST) &&
imo != NULL && imo->imo_multicast_if_index != 0) {
bound = curlwp_bind();
ifp = mifp = if_get_byindex(imo->imo_multicast_if_index, &psref);
if (ifp == NULL) {
curlwp_bindx(bound);
IP_STATINC(IP_STAT_NOROUTE);
error = ENETUNREACH;
goto bad;
}
mtu = ifp->if_mtu;
ia = in_get_ia_from_ifp(ifp);
ia = in_get_ia_from_ifp_psref(ifp, &psref_ia);
if (ia == NULL) {
error = EADDRNOTAVAIL;
goto bad;
}
isbroadcast = 0;
} else {
if (rt == NULL)
@ -346,6 +358,11 @@ ip_output(struct mbuf *m0, struct mbuf *opt, struct route *ro, int flags,
error = EHOSTUNREACH;
goto bad;
}
/*
* XXX NOMPSAFE: depends on accessing rt->rt_ifa isn't racy.
* Revisit when working on rtentry MP-ification.
*/
ifa_acquire(rt->rt_ifa, &psref_ia);
ia = ifatoia(rt->rt_ifa);
ifp = rt->rt_ifp;
if ((mtu = rt->rt_rmx.rmx_mtu) == 0)
@ -403,21 +420,26 @@ ip_output(struct mbuf *m0, struct mbuf *opt, struct route *ro, int flags,
if (in_nullhost(ip->ip_src)) {
struct in_ifaddr *xia;
struct ifaddr *xifa;
struct psref _psref;
xia = in_get_ia_from_ifp(ifp);
xia = in_get_ia_from_ifp_psref(ifp, &_psref);
if (!xia) {
error = EADDRNOTAVAIL;
goto bad;
}
xifa = &xia->ia_ifa;
if (xifa->ifa_getifa != NULL) {
ia4_release(xia, &_psref);
/* FIXME NOMPSAFE */
xia = ifatoia((*xifa->ifa_getifa)(xifa, rdst));
if (xia == NULL) {
error = EADDRNOTAVAIL;
goto bad;
}
ia4_acquire(xia, &_psref);
}
ip->ip_src = xia->ia_addr.sin_addr;
ia4_release(xia, &_psref);
}
inmgroup = in_multi_group(ip->ip_dst, ifp, flags);
@ -477,11 +499,14 @@ ip_output(struct mbuf *m0, struct mbuf *opt, struct route *ro, int flags,
xifa = &ia->ia_ifa;
if (xifa->ifa_getifa != NULL) {
ia4_release(ia, &psref_ia);
/* FIXME NOMPSAFE */
ia = ifatoia((*xifa->ifa_getifa)(xifa, rdst));
if (ia == NULL) {
error = EADDRNOTAVAIL;
goto bad;
}
ia4_acquire(ia, &psref_ia);
}
ip->ip_src = ia->ia_addr.sin_addr;
}
@ -543,6 +568,10 @@ sendit:
ip->ip_id = ip_newid_range(ia, num);
}
}
if (ia != NULL) {
ia4_release(ia, &psref_ia);
ia = NULL;
}
/*
* If we're doing Path MTU Discovery, we need to set DF unless
@ -583,7 +612,8 @@ sendit:
* search for the source address structure to
* maintain output statistics.
*/
ia = in_get_ia(ip->ip_src);
KASSERT(ia == NULL);
ia = in_get_ia_psref(ip->ip_src, &psref_ia);
#endif
/* Maybe skip checksums on loopback interfaces. */
@ -713,6 +743,7 @@ sendit:
IP_STATINC(IP_STAT_FRAGMENTED);
}
done:
ia4_release(ia, &psref_ia);
if (ro == &iproute) {
rtcache_free(&iproute);
}
@ -723,8 +754,9 @@ done:
#endif
if (mifp != NULL) {
if_put(mifp, &psref);
curlwp_bindx(bound);
}
if (bind_need_restore)
curlwp_bindx(bound);
return error;
bad:
m_freem(m);

View File

@ -1,4 +1,4 @@
/* $NetBSD: raw_ip.c,v 1.158 2016/05/12 02:24:17 ozaki-r Exp $ */
/* $NetBSD: raw_ip.c,v 1.159 2016/08/01 03:15:31 ozaki-r Exp $ */
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
@ -65,7 +65,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: raw_ip.c,v 1.158 2016/05/12 02:24:17 ozaki-r Exp $");
__KERNEL_RCSID(0, "$NetBSD: raw_ip.c,v 1.159 2016/08/01 03:15:31 ozaki-r Exp $");
#ifdef _KERNEL_OPT
#include "opt_inet.h"
@ -554,8 +554,8 @@ rip_bind(struct socket *so, struct sockaddr *nam, struct lwp *l)
struct inpcb *inp = sotoinpcb(so);
struct sockaddr_in *addr = (struct sockaddr_in *)nam;
int error = 0;
int s;
struct ifaddr *ia;
int s, ss;
struct ifaddr *ifa;
KASSERT(solocked(so));
KASSERT(inp != NULL);
@ -573,18 +573,22 @@ rip_bind(struct socket *so, struct sockaddr *nam, struct lwp *l)
error = EAFNOSUPPORT;
goto release;
}
if ((ia = ifa_ifwithaddr(sintosa(addr))) == 0 &&
ss = pserialize_read_enter();
if ((ifa = ifa_ifwithaddr(sintosa(addr))) == NULL &&
!in_nullhost(addr->sin_addr))
{
pserialize_read_exit(ss);
error = EADDRNOTAVAIL;
goto release;
}
if (ia && ((struct in_ifaddr *)ia)->ia4_flags &
if (ifa && (ifatoia(ifa))->ia4_flags &
(IN6_IFF_NOTREADY | IN_IFF_DETACHED))
{
pserialize_read_exit(ss);
error = EADDRNOTAVAIL;
goto release;
}
pserialize_read_exit(ss);
inp->inp_laddr = addr->sin_addr;

View File

@ -1,4 +1,4 @@
/* $NetBSD: icmp6.c,v 1.194 2016/07/15 07:40:09 ozaki-r Exp $ */
/* $NetBSD: icmp6.c,v 1.195 2016/08/01 03:15:31 ozaki-r Exp $ */
/* $KAME: icmp6.c,v 1.217 2001/06/20 15:03:29 jinmei Exp $ */
/*
@ -62,7 +62,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: icmp6.c,v 1.194 2016/07/15 07:40:09 ozaki-r Exp $");
__KERNEL_RCSID(0, "$NetBSD: icmp6.c,v 1.195 2016/08/01 03:15:31 ozaki-r Exp $");
#ifdef _KERNEL_OPT
#include "opt_inet.h"
@ -160,7 +160,7 @@ static struct mbuf *ni6_input(struct mbuf *, int);
static struct mbuf *ni6_nametodns(const char *, int, int);
static int ni6_dnsmatch(const char *, int, const char *, int);
static int ni6_addrs(struct icmp6_nodeinfo *, struct mbuf *,
struct ifnet **, char *);
struct ifnet **, char *, struct psref *);
static int ni6_store_addrs(struct icmp6_nodeinfo *, struct icmp6_nodeinfo *,
struct ifnet *, int);
static int icmp6_notify_error(struct mbuf *, int, int, int);
@ -1200,8 +1200,10 @@ ni6_input(struct mbuf *m, int off)
struct ip6_hdr *ip6;
int oldfqdn = 0; /* if 1, return pascal string (03 draft) */
char *subj = NULL;
int s;
struct ifnet *rcvif;
int s, ss;
struct ifaddr *ifa;
struct psref psref;
ip6 = mtod(m, struct ip6_hdr *);
IP6_EXTHDR_GET(ni6, struct icmp6_nodeinfo *, m, off, sizeof(*ni6));
@ -1220,12 +1222,17 @@ ni6_input(struct mbuf *m, int off)
*/
sockaddr_in6_init(&sin6, &ip6->ip6_dst, 0, 0, 0);
/* XXX scopeid */
if (ifa_ifwithaddr(sin6tosa(&sin6)))
ss = pserialize_read_enter();
ifa = ifa_ifwithaddr(sin6tosa(&sin6));
if (ifa != NULL)
; /* unicast/anycast, fine */
else if (IN6_IS_ADDR_MC_LINKLOCAL(&sin6.sin6_addr))
; /* link-local multicast, fine */
else
else {
pserialize_read_exit(ss);
goto bad;
}
pserialize_read_exit(ss);
/* validate query Subject field. */
qtype = ntohs(ni6->ni_qtype);
@ -1359,7 +1366,7 @@ ni6_input(struct mbuf *m, int off)
replylen += offsetof(struct ni_reply_fqdn, ni_fqdn_namelen);
break;
case NI_QTYPE_NODEADDR:
addrs = ni6_addrs(ni6, m, &ifp, subj);
addrs = ni6_addrs(ni6, m, &ifp, subj, &psref);
if ((replylen += addrs * (sizeof(struct in6_addr) +
sizeof(u_int32_t))) > MCLBYTES)
replylen = MCLBYTES; /* XXX: will truncate pkt later */
@ -1387,6 +1394,7 @@ ni6_input(struct mbuf *m, int off)
/* allocate an mbuf to reply. */
MGETHDR(n, M_DONTWAIT, m->m_type);
if (n == NULL) {
if_put(ifp, &psref);
m_freem(m);
return (NULL);
}
@ -1454,6 +1462,8 @@ ni6_input(struct mbuf *m, int off)
sizeof(struct ip6_hdr) + sizeof(struct icmp6_nodeinfo);
lenlim = M_TRAILINGSPACE(n);
copied = ni6_store_addrs(ni6, nni6, ifp, lenlim);
if_put(ifp, &psref);
ifp = NULL;
/* XXX: reset mbuf length */
n->m_pkthdr.len = n->m_len = sizeof(struct ip6_hdr) +
sizeof(struct icmp6_nodeinfo) + copied;
@ -1468,6 +1478,7 @@ ni6_input(struct mbuf *m, int off)
return (n);
bad:
if_put(ifp, &psref);
m_freem(m);
if (n)
m_freem(n);
@ -1657,7 +1668,7 @@ ni6_dnsmatch(const char *a, int alen, const char *b, int blen)
*/
static int
ni6_addrs(struct icmp6_nodeinfo *ni6, struct mbuf *m,
struct ifnet **ifpp, char *subj)
struct ifnet **ifpp, char *subj, struct psref *psref)
{
struct ifnet *ifp;
struct in6_ifaddr *ia6;
@ -1665,6 +1676,7 @@ ni6_addrs(struct icmp6_nodeinfo *ni6, struct mbuf *m,
struct sockaddr_in6 *subj_ip6 = NULL; /* XXX pedant */
int addrs = 0, addrsofif, iffound = 0;
int niflags = ni6->ni_flags;
int s;
if ((niflags & NI_NODEADDR_FLAG_ALL) == 0) {
switch (ni6->ni_code) {
@ -1682,6 +1694,7 @@ ni6_addrs(struct icmp6_nodeinfo *ni6, struct mbuf *m,
}
}
s = pserialize_read_enter();
IFNET_READER_FOREACH(ifp) {
addrsofif = 0;
IFADDR_READER_FOREACH(ifa, ifp) {
@ -1733,12 +1746,15 @@ ni6_addrs(struct icmp6_nodeinfo *ni6, struct mbuf *m,
addrsofif++; /* count the address */
}
if (iffound) {
if_acquire_NOMPSAFE(ifp, psref);
pserialize_read_exit(s);
*ifpp = ifp;
return (addrsofif);
}
addrs += addrsofif;
}
pserialize_read_exit(s);
return (addrs);
}
@ -1748,7 +1764,7 @@ ni6_store_addrs(struct icmp6_nodeinfo *ni6,
struct icmp6_nodeinfo *nni6, struct ifnet *ifp0,
int resid)
{
struct ifnet *ifp = ifp0 ? ifp0 : IFNET_READER_FIRST();
struct ifnet *ifp;
struct in6_ifaddr *ia6;
struct ifaddr *ifa;
struct ifnet *ifp_dep = NULL;
@ -1756,10 +1772,13 @@ ni6_store_addrs(struct icmp6_nodeinfo *ni6,
u_char *cp = (u_char *)(nni6 + 1);
int niflags = ni6->ni_flags;
u_int32_t ltime;
int s;
if (ifp0 == NULL && !(niflags & NI_NODEADDR_FLAG_ALL))
return (0); /* needless to copy */
s = pserialize_read_enter();
ifp = ifp0 ? ifp0 : IFNET_READER_FIRST();
again:
for (; ifp; ifp = IFNET_READER_NEXT(ifp))
@ -1820,7 +1839,7 @@ ni6_store_addrs(struct icmp6_nodeinfo *ni6,
* Set the truncate flag and return.
*/
nni6->ni_flags |= NI_NODEADDR_FLAG_TRUNCATE;
return (copied);
goto out;
}
/*
@ -1876,7 +1895,8 @@ ni6_store_addrs(struct icmp6_nodeinfo *ni6,
goto again;
}
out:
pserialize_read_exit(s);
return (copied);
}
@ -2067,16 +2087,21 @@ icmp6_reflect(struct mbuf *m, size_t off)
struct sockaddr_in6 sin6;
struct sockaddr sa;
} u;
int _s;
struct ifaddr *ifa;
sockaddr_in6_init(&u.sin6, &origdst, 0, 0, 0);
ia = ifatoia6(ifa_ifwithaddr(&u.sa));
_s = pserialize_read_enter();
ifa = ifa_ifwithaddr(&u.sa);
if (ia == NULL)
;
else if ((ia->ia6_flags &
(IN6_IFF_ANYCAST|IN6_IFF_NOTREADY)) == 0)
src = &ia->ia_addr.sin6_addr;
if (ifa != NULL) {
ia = ifatoia6(ifa);
if ((ia->ia6_flags &
(IN6_IFF_ANYCAST|IN6_IFF_NOTREADY)) == 0)
src = &ia->ia_addr.sin6_addr;
}
pserialize_read_exit(_s);
}
if (src == NULL) {
@ -2438,11 +2463,15 @@ icmp6_redirect_output(struct mbuf *m0, struct rtentry *rt)
{
/* get ip6 linklocal address for ifp(my outgoing interface). */
struct in6_ifaddr *ia;
int s = pserialize_read_enter();
if ((ia = in6ifa_ifpforlinklocal(ifp,
IN6_IFF_NOTREADY|
IN6_IFF_ANYCAST)) == NULL)
IN6_IFF_ANYCAST)) == NULL) {
pserialize_read_exit(s);
goto fail;
}
ifp_ll6 = &ia->ia_addr.sin6_addr;
pserialize_read_exit(s);
}
/* get ip6 linklocal address for the router. */

View File

@ -1,4 +1,4 @@
/* $NetBSD: in6.c,v 1.212 2016/07/28 09:03:50 ozaki-r Exp $ */
/* $NetBSD: in6.c,v 1.213 2016/08/01 03:15:31 ozaki-r Exp $ */
/* $KAME: in6.c,v 1.198 2001/07/18 09:12:38 itojun Exp $ */
/*
@ -62,7 +62,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: in6.c,v 1.212 2016/07/28 09:03:50 ozaki-r Exp $");
__KERNEL_RCSID(0, "$NetBSD: in6.c,v 1.213 2016/08/01 03:15:31 ozaki-r Exp $");
#ifdef _KERNEL_OPT
#include "opt_inet.h"
@ -143,6 +143,7 @@ const struct sockaddr_in6 sa6_any = {sizeof(sa6_any), AF_INET6,
0, 0, IN6ADDR_ANY_INIT, 0};
struct pslist_head in6_ifaddr_list;
kmutex_t in6_ifaddr_lock;
static int in6_lifaddr_ioctl(struct socket *, u_long, void *,
struct ifnet *);
@ -155,6 +156,7 @@ in6_init(void)
{
PSLIST_INIT(&in6_ifaddr_list);
mutex_init(&in6_ifaddr_lock, MUTEX_DEFAULT, IPL_NONE);
}
/*
@ -189,6 +191,8 @@ in6_ifremlocal(struct ifaddr *ifa)
struct in6_ifaddr *ia;
struct ifaddr *alt_ifa = NULL;
int ia_count = 0;
struct psref psref;
int s;
/*
* Some of BSD variants do not remove cloned routes
@ -218,6 +222,7 @@ in6_ifremlocal(struct ifaddr *ifa)
* XXX agree, especially now that I have fixed the dangling
* XXX ifp-pointers bug.
*/
s = pserialize_read_enter();
IN6_ADDRLIST_READER_FOREACH(ia) {
if (!IN6_ARE_ADDR_EQUAL(IFA_IN6(ifa), &ia->ia_addr.sin6_addr))
continue;
@ -226,11 +231,17 @@ in6_ifremlocal(struct ifaddr *ifa)
if (++ia_count > 1 && alt_ifa != NULL)
break;
}
if (ia_count > 1 && alt_ifa != NULL)
ifa_acquire(alt_ifa, &psref);
pserialize_read_exit(s);
if (ia_count == 0)
return;
rt_ifa_remlocal(ifa, ia_count == 1 ? NULL : alt_ifa);
if (ia_count > 1 && alt_ifa != NULL)
ifa_release(alt_ifa, &psref);
}
int
@ -279,7 +290,9 @@ in6_control1(struct socket *so, u_long cmd, void *data, struct ifnet *ifp)
struct in6_ifaddr *ia = NULL;
struct in6_aliasreq *ifra = (struct in6_aliasreq *)data;
struct sockaddr_in6 *sa6;
int error;
int error, bound;
struct psref psref;
bool run_hooks = false;
switch (cmd) {
case SIOCAADDRCTL_POLICY:
@ -395,14 +408,17 @@ in6_control1(struct socket *so, u_long cmd, void *data, struct ifnet *ifp)
sa6 = NULL;
break;
}
error = 0;
bound = curlwp_bind();
if (sa6 && sa6->sin6_family == AF_INET6) {
if (sa6->sin6_scope_id != 0)
error = sa6_embedscope(sa6, 0);
else
error = in6_setscope(&sa6->sin6_addr, ifp, NULL);
if (error != 0)
return error;
ia = in6ifa_ifpwithaddr(ifp, &sa6->sin6_addr);
goto out;
ia = in6ifa_ifpwithaddr_psref(ifp, &sa6->sin6_addr, &psref);
} else
ia = NULL;
@ -414,7 +430,8 @@ in6_control1(struct socket *so, u_long cmd, void *data, struct ifnet *ifp)
* Since IPv6 allows a node to assign multiple addresses
* on a single interface, SIOCSIFxxx ioctls are deprecated.
*/
return EINVAL;
error = EINVAL;
goto release;
case SIOCDIFADDR_IN6:
/*
@ -424,8 +441,10 @@ in6_control1(struct socket *so, u_long cmd, void *data, struct ifnet *ifp)
* interface address from the day one, we consider "remove the
* first one" semantics to be not preferable.
*/
if (ia == NULL)
return EADDRNOTAVAIL;
if (ia == NULL) {
error = EADDRNOTAVAIL;
goto out;
}
/* FALLTHROUGH */
#ifdef OSIOCAIFADDR_IN6
case OSIOCAIFADDR_IN6:
@ -436,8 +455,10 @@ in6_control1(struct socket *so, u_long cmd, void *data, struct ifnet *ifp)
* the corresponding operation.
*/
if (ifra->ifra_addr.sin6_family != AF_INET6 ||
ifra->ifra_addr.sin6_len != sizeof(struct sockaddr_in6))
return EAFNOSUPPORT;
ifra->ifra_addr.sin6_len != sizeof(struct sockaddr_in6)) {
error = EAFNOSUPPORT;
goto release;
}
/* Privileged. */
break;
@ -453,8 +474,10 @@ in6_control1(struct socket *so, u_long cmd, void *data, struct ifnet *ifp)
case OSIOCGIFALIFETIME_IN6:
#endif
/* must think again about its semantics */
if (ia == NULL)
return EADDRNOTAVAIL;
if (ia == NULL) {
error = EADDRNOTAVAIL;
goto out;
}
break;
}
@ -463,19 +486,21 @@ in6_control1(struct socket *so, u_long cmd, void *data, struct ifnet *ifp)
case SIOCGIFADDR_IN6:
ifr->ifr_addr = ia->ia_addr;
if ((error = sa6_recoverscope(&ifr->ifr_addr)) != 0)
return error;
break;
break;
case SIOCGIFDSTADDR_IN6:
if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
return EINVAL;
if ((ifp->if_flags & IFF_POINTOPOINT) == 0) {
error = EINVAL;
break;
}
/*
* XXX: should we check if ifa_dstaddr is NULL and return
* an error?
*/
ifr->ifr_dstaddr = ia->ia_dstaddr;
if ((error = sa6_recoverscope(&ifr->ifr_dstaddr)) != 0)
return error;
break;
break;
case SIOCGIFNETMASK_IN6:
@ -487,8 +512,10 @@ in6_control1(struct socket *so, u_long cmd, void *data, struct ifnet *ifp)
break;
case SIOCGIFSTAT_IN6:
if (ifp == NULL)
return EINVAL;
if (ifp == NULL) {
error = EINVAL;
break;
}
memset(&ifr->ifr_ifru.ifru_stat, 0,
sizeof(ifr->ifr_ifru.ifru_stat));
ifr->ifr_ifru.ifru_stat =
@ -496,8 +523,10 @@ in6_control1(struct socket *so, u_long cmd, void *data, struct ifnet *ifp)
break;
case SIOCGIFSTAT_ICMP6:
if (ifp == NULL)
return EINVAL;
if (ifp == NULL) {
error = EINVAL;
break;
}
memset(&ifr->ifr_ifru.ifru_icmp6stat, 0,
sizeof(ifr->ifr_ifru.ifru_icmp6stat));
ifr->ifr_ifru.ifru_icmp6stat =
@ -569,6 +598,8 @@ in6_control1(struct socket *so, u_long cmd, void *data, struct ifnet *ifp)
struct nd_prefixctl prc0;
struct nd_prefix *pr;
struct in6_addrlifetime *lt;
struct in6_ifaddr *_ia;
int s;
/* reject read-only flags */
if ((ifra->ifra_flags & IN6_IFF_DUPLICATED) != 0 ||
@ -576,7 +607,8 @@ in6_control1(struct socket *so, u_long cmd, void *data, struct ifnet *ifp)
(ifra->ifra_flags & IN6_IFF_TENTATIVE) != 0 ||
(ifra->ifra_flags & IN6_IFF_NODAD) != 0 ||
(ifra->ifra_flags & IN6_IFF_AUTOCONF) != 0) {
return EINVAL;
error = EINVAL;
break;
}
/*
* ia6t_expire and ia6t_preferred won't be used for now,
@ -589,19 +621,31 @@ in6_control1(struct socket *so, u_long cmd, void *data, struct ifnet *ifp)
lt->ia6t_preferred =
time_wall_to_mono(lt->ia6t_preferred);
/*
* first, make or update the interface address structure,
* and link it to the list.
* first, make (ia == NULL) or update (ia != NULL) the interface
* address structure, and link it to the list.
*/
if ((error = in6_update_ifa(ifp, ifra, ia, 0)) != 0)
return error;
if ((ia = in6ifa_ifpwithaddr(ifp, &ifra->ifra_addr.sin6_addr))
== NULL) {
break;
s = pserialize_read_enter();
_ia = in6ifa_ifpwithaddr(ifp, &ifra->ifra_addr.sin6_addr);
if (_ia == NULL) {
pserialize_read_exit(s);
/*
* this can happen when the user specify the 0 valid
* lifetime.
*/
break;
}
/*
* If ia == NULL, _ia has been created and we need to acquire
* a reference. Otherwise, a reference is already taken.
*/
if (ia == NULL) {
ia6_acquire(_ia, &psref);
ia = _ia;
} else
KASSERT(_ia == ia);
pserialize_read_exit(s);
/*
* then, make the prefix on-link on the interface.
@ -647,11 +691,12 @@ in6_control1(struct socket *so, u_long cmd, void *data, struct ifnet *ifp)
* interface route.
*/
if ((error = nd6_prelist_add(&prc0, NULL, &pr)) != 0)
return error;
break;
if (pr == NULL) {
log(LOG_ERR, "nd6_prelist_add succeeded but "
"no prefix\n");
return EINVAL; /* XXX panic here? */
error = EINVAL; /* XXX panic here? */
break;
}
}
@ -682,8 +727,7 @@ in6_control1(struct socket *so, u_long cmd, void *data, struct ifnet *ifp)
*/
pfxlist_onlink_check();
(void)pfil_run_hooks(if_pfil, (struct mbuf **)SIOCAIFADDR_IN6,
ifp, PFIL_IFADDR);
run_hooks = true;
break;
}
@ -702,19 +746,26 @@ in6_control1(struct socket *so, u_long cmd, void *data, struct ifnet *ifp)
* Note that in6_purgeaddr() will decrement ndpr_refcnt.
*/
pr = ia->ia6_ndpr;
ia6_release(ia, &psref);
in6_purgeaddr(&ia->ia_ifa);
ia = NULL;
if (pr && pr->ndpr_refcnt == 0)
prelist_remove(pr);
(void)pfil_run_hooks(if_pfil, (struct mbuf **)SIOCDIFADDR_IN6,
ifp, PFIL_IFADDR);
run_hooks = true;
break;
}
default:
return ENOTTY;
error = ENOTTY;
}
release:
ia6_release(ia, &psref);
return 0;
if (run_hooks)
pfil_run_hooks(if_pfil, (struct mbuf **)cmd, ifp, PFIL_IFADDR);
out:
curlwp_bindx(bound);
return error;
}
int
@ -930,6 +981,7 @@ in6_update_ifa1(struct ifnet *ifp, struct in6_aliasreq *ifra,
ia->ia_ifp = ifp;
IN6_ADDRLIST_ENTRY_INIT(ia);
ifa_psref_init(&ia->ia_ifa);
}
/* update timestamp */
@ -1036,7 +1088,9 @@ in6_update_ifa1(struct ifnet *ifp, struct in6_aliasreq *ifra,
/*
* Insert ia to the global list and ifa to the interface's list.
*/
mutex_enter(&in6_ifaddr_lock);
IN6_ADDRLIST_WRITER_INSERT_TAIL(ia);
mutex_exit(&in6_ifaddr_lock);
/* gain a refcnt for the link from in6_ifaddr */
ifaref(&ia->ia_ifa);
@ -1345,11 +1399,10 @@ in6_unlink_ifa(struct in6_ifaddr *ia, struct ifnet *ifp)
{
int s = splnet();
ifa_remove(ifp, &ia->ia_ifa);
mutex_enter(&in6_ifaddr_lock);
IN6_ADDRLIST_WRITER_REMOVE(ia);
/* TODO psref_target_destroy */
IN6_ADDRLIST_ENTRY_DESTROY(ia);
ifa_remove(ifp, &ia->ia_ifa);
mutex_exit(&in6_ifaddr_lock);
/*
* XXX thorpej@NetBSD.org -- if the interface is going
@ -1388,6 +1441,8 @@ in6_unlink_ifa(struct in6_ifaddr *ia, struct ifnet *ifp)
if ((ia->ia6_flags & IN6_IFF_AUTOCONF) != 0)
pfxlist_onlink_check();
IN6_ADDRLIST_ENTRY_DESTROY(ia);
/*
* release another refcnt for the link from in6_ifaddr.
* Note that we should decrement the refcnt at least once for all *BSD.
@ -1480,6 +1535,8 @@ in6_lifaddr_ioctl(struct socket *so, u_long cmd, void *data,
struct in6_aliasreq ifra;
struct in6_addr *xhostid = NULL;
int prefixlen;
int bound = curlwp_bind();
struct psref psref;
if ((iflr->flags & IFLR_PREFIX) != 0) {
struct sockaddr_in6 *sin6;
@ -1489,20 +1546,27 @@ in6_lifaddr_ioctl(struct socket *so, u_long cmd, void *data,
* address. xhostid points to the first link-local
* address attached to the interface.
*/
ia = in6ifa_ifpforlinklocal(ifp, 0);
if (ia == NULL)
ia = in6ifa_ifpforlinklocal_psref(ifp, 0, &psref);
if (ia == NULL) {
curlwp_bindx(bound);
return EADDRNOTAVAIL;
}
xhostid = IFA_IN6(&ia->ia_ifa);
/* prefixlen must be <= 64. */
if (64 < iflr->prefixlen)
if (64 < iflr->prefixlen) {
ia6_release(ia, &psref);
curlwp_bindx(bound);
return EINVAL;
}
prefixlen = iflr->prefixlen;
/* hostid part must be zero. */
sin6 = (struct sockaddr_in6 *)&iflr->addr;
if (sin6->sin6_addr.s6_addr32[2] != 0
|| sin6->sin6_addr.s6_addr32[3] != 0) {
ia6_release(ia, &psref);
curlwp_bindx(bound);
return EINVAL;
}
} else
@ -1532,6 +1596,11 @@ in6_lifaddr_ioctl(struct socket *so, u_long cmd, void *data,
xhostid->s6_addr32[3];
}
}
if (xhostid) {
ia6_release(ia, &psref);
ia = NULL;
}
curlwp_bindx(bound);
ifra.ifra_prefixmask.sin6_len = sizeof(struct sockaddr_in6);
in6_prefixlen2mask(&ifra.ifra_prefixmask.sin6_addr, prefixlen);
@ -1547,6 +1616,7 @@ in6_lifaddr_ioctl(struct socket *so, u_long cmd, void *data,
struct in6_addr mask, candidate, match;
struct sockaddr_in6 *sin6;
int cmp;
int error, s;
memset(&mask, 0, sizeof(mask));
if (iflr->flags & IFLR_PREFIX) {
@ -1579,6 +1649,7 @@ in6_lifaddr_ioctl(struct socket *so, u_long cmd, void *data,
}
}
s = pserialize_read_enter();
IFADDR_READER_FOREACH(ifa, ifp) {
if (ifa->ifa_addr->sa_family != AF_INET6)
continue;
@ -1599,19 +1670,19 @@ in6_lifaddr_ioctl(struct socket *so, u_long cmd, void *data,
if (IN6_ARE_ADDR_EQUAL(&candidate, &match))
break;
}
if (!ifa)
return EADDRNOTAVAIL;
if (!ifa) {
error = EADDRNOTAVAIL;
goto error;
}
ia = ifa2ia6(ifa);
if (cmd == SIOCGLIFADDR) {
int error;
/* fill in the if_laddrreq structure */
memcpy(&iflr->addr, &ia->ia_addr, ia->ia_addr.sin6_len);
error = sa6_recoverscope(
(struct sockaddr_in6 *)&iflr->addr);
if (error != 0)
return error;
goto error;
if ((ifp->if_flags & IFF_POINTOPOINT) != 0) {
memcpy(&iflr->dstaddr, &ia->ia_dstaddr,
@ -1619,7 +1690,7 @@ in6_lifaddr_ioctl(struct socket *so, u_long cmd, void *data,
error = sa6_recoverscope(
(struct sockaddr_in6 *)&iflr->dstaddr);
if (error != 0)
return error;
goto error;
} else
memset(&iflr->dstaddr, 0, sizeof(iflr->dstaddr));
@ -1628,7 +1699,7 @@ in6_lifaddr_ioctl(struct socket *so, u_long cmd, void *data,
iflr->flags = ia->ia6_flags; /* XXX */
return 0;
error = 0;
} else {
struct in6_aliasreq ifra;
@ -1650,8 +1721,13 @@ in6_lifaddr_ioctl(struct socket *so, u_long cmd, void *data,
ia->ia_prefixmask.sin6_len);
ifra.ifra_flags = ia->ia6_flags;
pserialize_read_exit(s);
return in6_control(so, SIOCDIFADDR_IN6, &ifra, ifp);
}
error:
pserialize_read_exit(s);
return error;
}
}
@ -1756,6 +1832,21 @@ in6ifa_ifpforlinklocal(const struct ifnet *ifp, const int ignoreflags)
return (struct in6_ifaddr *)best_ifa;
}
struct in6_ifaddr *
in6ifa_ifpforlinklocal_psref(const struct ifnet *ifp, const int ignoreflags,
struct psref *psref)
{
struct in6_ifaddr *ia;
int s = pserialize_read_enter();
ia = in6ifa_ifpforlinklocal(ifp, ignoreflags);
if (ia != NULL)
ia6_acquire(ia, psref);
pserialize_read_exit(s);
return ia;
}
/*
* find the internet address corresponding to a given address.
* ifaddr is returned referenced.
@ -1764,13 +1855,10 @@ struct in6_ifaddr *
in6ifa_ifwithaddr(const struct in6_addr *addr, uint32_t zoneid)
{
struct in6_ifaddr *ia;
int s;
#ifdef __FreeBSD__
IN6_IFADDR_RLOCK();
LIST_FOREACH(ia, IN6ADDR_HASH(addr), ia6_hash) {
#else
s = pserialize_read_enter();
IN6_ADDRLIST_READER_FOREACH(ia) {
#endif
if (IN6_ARE_ADDR_EQUAL(IA6_IN6(ia), addr)) {
if (zoneid != 0 &&
zoneid != ia->ia_addr.sin6_scope_id)
@ -1779,9 +1867,8 @@ in6ifa_ifwithaddr(const struct in6_addr *addr, uint32_t zoneid)
break;
}
}
#ifdef __FreeBSD__
IN6_IFADDR_RUNLOCK();
#endif
pserialize_read_exit(s);
return ia;
}
@ -1804,6 +1891,21 @@ in6ifa_ifpwithaddr(const struct ifnet *ifp, const struct in6_addr *addr)
return (struct in6_ifaddr *)best_ifa;
}
struct in6_ifaddr *
in6ifa_ifpwithaddr_psref(const struct ifnet *ifp, const struct in6_addr *addr,
struct psref *psref)
{
struct in6_ifaddr *ia;
int s = pserialize_read_enter();
ia = in6ifa_ifpwithaddr(ifp, addr);
if (ia != NULL)
ia6_acquire(ia, psref);
pserialize_read_exit(s);
return ia;
}
static struct in6_ifaddr *
bestia(struct in6_ifaddr *best_ia, struct in6_ifaddr *ia)
{
@ -2043,6 +2145,7 @@ in6_if_link_up(struct ifnet *ifp)
{
struct ifaddr *ifa;
struct in6_ifaddr *ia;
int s, bound;
/* Ensure it's sane to run DAD */
if (ifp->if_link_state == LINK_STATE_DOWN)
@ -2050,9 +2153,16 @@ in6_if_link_up(struct ifnet *ifp)
if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING))
return;
bound = curlwp_bind();
s = pserialize_read_enter();
IFADDR_READER_FOREACH(ifa, ifp) {
struct psref psref;
if (ifa->ifa_addr->sa_family != AF_INET6)
continue;
ifa_acquire(ifa, &psref);
pserialize_read_exit(s);
ia = (struct in6_ifaddr *)ifa;
/* If detached then mark as tentative */
@ -2083,7 +2193,12 @@ in6_if_link_up(struct ifnet *ifp)
/* +1 ensures callout is always used */
nd6_dad_start(ifa, rand_delay + 1);
}
s = pserialize_read_enter();
ifa_release(ifa, &psref);
}
pserialize_read_exit(s);
curlwp_bindx(bound);
/* Restore any detached prefixes */
pfxlist_onlink_check();
@ -2110,13 +2225,21 @@ in6_if_link_down(struct ifnet *ifp)
{
struct ifaddr *ifa;
struct in6_ifaddr *ia;
int s, bound;
/* Any prefixes on this interface should be detached as well */
pfxlist_onlink_check();
bound = curlwp_bind();
s = pserialize_read_enter();
IFADDR_READER_FOREACH(ifa, ifp) {
struct psref psref;
if (ifa->ifa_addr->sa_family != AF_INET6)
continue;
ifa_acquire(ifa, &psref);
pserialize_read_exit(s);
ia = (struct in6_ifaddr *)ifa;
/* Stop DAD processing */
@ -2138,7 +2261,12 @@ in6_if_link_down(struct ifnet *ifp)
~(IN6_IFF_TENTATIVE | IN6_IFF_DUPLICATED);
rt_newaddrmsg(RTM_NEWADDR, ifa, 0, NULL);
}
s = pserialize_read_enter();
ifa_release(ifa, &psref);
}
pserialize_read_exit(s);
curlwp_bindx(bound);
}
void
@ -2319,18 +2447,22 @@ in6_lltable_rtcheck(struct ifnet *ifp,
rt = rtalloc1(l3addr, 0);
if (rt == NULL || (rt->rt_flags & RTF_GATEWAY) || rt->rt_ifp != ifp) {
int s;
struct ifaddr *ifa;
/*
* Create an ND6 cache for an IPv6 neighbor
* that is not covered by our own prefix.
*/
/* XXX ifaof_ifpforaddr should take a const param */
s = pserialize_read_enter();
ifa = ifaof_ifpforaddr(l3addr, ifp);
if (ifa != NULL) {
pserialize_read_exit(s);
if (rt != NULL)
rtfree(rt);
return 0;
}
pserialize_read_exit(s);
log(LOG_INFO, "IPv6 address: \"%s\" is not on the network\n",
ip6_sprintf(&((const struct sockaddr_in6 *)l3addr)->sin6_addr));
if (rt != NULL)

View File

@ -1,4 +1,4 @@
/* $NetBSD: in6_ifattach.c,v 1.102 2016/07/20 07:37:51 ozaki-r Exp $ */
/* $NetBSD: in6_ifattach.c,v 1.103 2016/08/01 03:15:31 ozaki-r Exp $ */
/* $KAME: in6_ifattach.c,v 1.124 2001/07/18 08:32:51 jinmei Exp $ */
/*
@ -31,7 +31,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: in6_ifattach.c,v 1.102 2016/07/20 07:37:51 ozaki-r Exp $");
__KERNEL_RCSID(0, "$NetBSD: in6_ifattach.c,v 1.103 2016/08/01 03:15:31 ozaki-r Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@ -320,31 +320,35 @@ int
in6_get_hw_ifid(struct ifnet *ifp, struct in6_addr *in6)
{
struct ifaddr *ifa;
const struct sockaddr_dl *sdl = NULL, *tsdl;
const struct sockaddr_dl *sdl = NULL;
const char *addr;
size_t addrlen;
static u_int8_t allzero[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
static u_int8_t allone[8] =
{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
int s;
s = pserialize_read_enter();
IFADDR_READER_FOREACH(ifa, ifp) {
const struct sockaddr_dl *tsdl;
if (ifa->ifa_addr->sa_family != AF_LINK)
continue;
tsdl = satocsdl(ifa->ifa_addr);
if (tsdl == NULL || tsdl->sdl_alen == 0)
continue;
if (sdl == NULL || ifa == ifp->if_dl || ifa == ifp->if_hwdl)
if (sdl == NULL || ifa == ifp->if_dl || ifa == ifp->if_hwdl) {
sdl = tsdl;
addr = CLLADDR(sdl);
addrlen = sdl->sdl_alen;
}
if (ifa == ifp->if_hwdl)
break;
}
pserialize_read_exit(s);
if (sdl == NULL)
return -1;
addr = CLLADDR(sdl);
addrlen = sdl->sdl_alen;
switch (ifp->if_type) {
case IFT_IEEE1394:
case IFT_IEEE80211:
@ -532,7 +536,7 @@ in6_ifattach_linklocal(struct ifnet *ifp, struct ifnet *altifp)
struct in6_ifaddr *ia __diagused;
struct in6_aliasreq ifra;
struct nd_prefixctl prc0;
int i, error;
int i, error, s;
/*
* configure link-local address.
@ -589,8 +593,10 @@ in6_ifattach_linklocal(struct ifnet *ifp, struct ifnet *altifp)
return -1;
}
s = pserialize_read_enter();
ia = in6ifa_ifpforlinklocal(ifp, 0); /* ia must not be NULL */
KASSERTMSG(ia, "ia == NULL in in6_ifattach_linklocal");
pserialize_read_exit(s);
/*
* Make the link-local prefix (fe80::/64%link) as on-link.
@ -811,24 +817,29 @@ in6_ifattach(struct ifnet *ifp, struct ifnet *altifp)
* XXX multiple loopback interface case.
*/
if ((ifp->if_flags & IFF_LOOPBACK) != 0) {
int s = pserialize_read_enter();
in6 = in6addr_loopback;
if (in6ifa_ifpwithaddr(ifp, &in6) == NULL) {
if (in6_ifattach_loopback(ifp) != 0)
if (in6_ifattach_loopback(ifp) != 0) {
pserialize_read_exit(s);
return;
}
}
pserialize_read_exit(s);
}
/*
* assign a link-local address, if there's none.
*/
if (!(ND_IFINFO(ifp)->flags & ND6_IFF_IFDISABLED) &&
ND_IFINFO(ifp)->flags & ND6_IFF_AUTO_LINKLOCAL)
{
ND_IFINFO(ifp)->flags & ND6_IFF_AUTO_LINKLOCAL) {
int s = pserialize_read_enter();
ia = in6ifa_ifpforlinklocal(ifp, 0);
if (ia == NULL && in6_ifattach_linklocal(ifp, altifp) != 0) {
printf("%s: cannot assign link-local address\n",
ifp->if_xname);
}
pserialize_read_exit(s);
}
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: in6_pcb.c,v 1.147 2016/07/15 07:40:09 ozaki-r Exp $ */
/* $NetBSD: in6_pcb.c,v 1.148 2016/08/01 03:15:31 ozaki-r Exp $ */
/* $KAME: in6_pcb.c,v 1.84 2001/02/08 18:02:08 itojun Exp $ */
/*
@ -62,7 +62,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: in6_pcb.c,v 1.147 2016/07/15 07:40:09 ozaki-r Exp $");
__KERNEL_RCSID(0, "$NetBSD: in6_pcb.c,v 1.148 2016/08/01 03:15:31 ozaki-r Exp $");
#ifdef _KERNEL_OPT
#include "opt_inet.h"
@ -203,6 +203,7 @@ static int
in6_pcbbind_addr(struct in6pcb *in6p, struct sockaddr_in6 *sin6, struct lwp *l)
{
int error;
int s;
/*
* We should check the family, but old programs
@ -219,9 +220,12 @@ in6_pcbbind_addr(struct in6pcb *in6p, struct sockaddr_in6 *sin6, struct lwp *l)
if ((error = sa6_embedscope(sin6, ip6_use_defzone)) != 0)
return (error);
s = pserialize_read_enter();
if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
if ((in6p->in6p_flags & IN6P_IPV6_V6ONLY) != 0)
return (EINVAL);
if ((in6p->in6p_flags & IN6P_IPV6_V6ONLY) != 0) {
error = EINVAL;
goto out;
}
if (sin6->sin6_addr.s6_addr32[3]) {
struct sockaddr_in sin;
@ -230,18 +234,27 @@ in6_pcbbind_addr(struct in6pcb *in6p, struct sockaddr_in6 *sin6, struct lwp *l)
sin.sin_family = AF_INET;
bcopy(&sin6->sin6_addr.s6_addr32[3],
&sin.sin_addr, sizeof(sin.sin_addr));
if (!IN_MULTICAST(sin.sin_addr.s_addr) &&
ifa_ifwithaddr((struct sockaddr *)&sin) == NULL)
return EADDRNOTAVAIL;
if (!IN_MULTICAST(sin.sin_addr.s_addr)) {
struct ifaddr *ifa;
ifa = ifa_ifwithaddr((struct sockaddr *)&sin);
if (ifa == NULL) {
error = EADDRNOTAVAIL;
goto out;
}
}
}
} else if (IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) {
// succeed
} else if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
struct ifaddr *ia = NULL;
struct ifaddr *ifa = NULL;
if ((in6p->in6p_flags & IN6P_FAITH) == 0 &&
(ia = ifa_ifwithaddr(sin6tosa(sin6))) == NULL)
return (EADDRNOTAVAIL);
if ((in6p->in6p_flags & IN6P_FAITH) == 0) {
ifa = ifa_ifwithaddr(sin6tosa(sin6));
if (ifa == NULL) {
error = EADDRNOTAVAIL;
goto out;
}
}
/*
* bind to an anycast address might accidentally
@ -256,17 +269,18 @@ in6_pcbbind_addr(struct in6pcb *in6p, struct sockaddr_in6 *sin6, struct lwp *l)
* flag to control the bind(2) behavior against
* deprecated addresses (default: forbid bind(2)).
*/
if (ia &&
ifatoia6(ia)->ia6_flags &
(IN6_IFF_ANYCAST|IN6_IFF_NOTREADY|IN6_IFF_DETACHED))
return (EADDRNOTAVAIL);
if (ifa &&
ifatoia6(ifa)->ia6_flags &
(IN6_IFF_ANYCAST|IN6_IFF_NOTREADY|IN6_IFF_DETACHED)) {
error = EADDRNOTAVAIL;
goto out;
}
}
in6p->in6p_laddr = sin6->sin6_addr;
return (0);
error = 0;
out:
pserialize_read_exit(s);
return error;
}
/*
@ -485,23 +499,27 @@ in6_pcbconnect(void *v, struct sockaddr_in6 *sin6, struct lwp *l)
if (IN6_IS_ADDR_V4MAPPED(&in6p->in6p_laddr) &&
in6p->in6p_laddr.s6_addr32[3] == 0) {
#ifdef INET
struct sockaddr_in sin, *sinp;
struct sockaddr_in sin;
struct in_ifaddr *ia4;
struct psref _psref;
memset(&sin, 0, sizeof(sin));
sin.sin_len = sizeof(sin);
sin.sin_family = AF_INET;
memcpy(&sin.sin_addr, &sin6->sin6_addr.s6_addr32[3],
sizeof(sin.sin_addr));
sinp = in_selectsrc(&sin, &in6p->in6p_route,
in6p->in6p_socket->so_options, NULL, &error);
if (sinp == NULL) {
ia4 = in_selectsrc(&sin, &in6p->in6p_route,
in6p->in6p_socket->so_options, NULL, &error, &_psref);
if (ia4 == NULL) {
if (error == 0)
error = EADDRNOTAVAIL;
return (error);
}
memset(&mapped, 0, sizeof(mapped));
mapped.s6_addr16[5] = htons(0xffff);
memcpy(&mapped.s6_addr32[3], &sinp->sin_addr, sizeof(sinp->sin_addr));
memcpy(&mapped.s6_addr32[3], &IA_SIN(ia4)->sin_addr,
sizeof(IA_SIN(ia4)->sin_addr));
ia4_release(ia4, &_psref);
in6a = &mapped;
#else
return EADDRNOTAVAIL;

View File

@ -1,4 +1,4 @@
/* $NetBSD: in6_src.c,v 1.65 2016/07/15 07:40:09 ozaki-r Exp $ */
/* $NetBSD: in6_src.c,v 1.66 2016/08/01 03:15:31 ozaki-r Exp $ */
/* $KAME: in6_src.c,v 1.159 2005/10/19 01:40:32 t-momose Exp $ */
/*
@ -66,7 +66,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: in6_src.c,v 1.65 2016/07/15 07:40:09 ozaki-r Exp $");
__KERNEL_RCSID(0, "$NetBSD: in6_src.c,v 1.66 2016/08/01 03:15:31 ozaki-r Exp $");
#ifdef _KERNEL_OPT
#include "opt_inet.h"
@ -192,6 +192,7 @@ in6_selectsrc(struct sockaddr_in6 *dstsock, struct ip6_pktopts *opts,
struct in6_addr *ret_ia = NULL;
int bound = curlwp_bind();
#define PSREF (psref == NULL) ? &local_psref : psref
int s;
KASSERT((ifpp != NULL && psref != NULL) ||
(ifpp == NULL && psref == NULL));
@ -222,6 +223,8 @@ in6_selectsrc(struct sockaddr_in6 *dstsock, struct ip6_pktopts *opts,
!IN6_IS_ADDR_UNSPECIFIED(&pi->ipi6_addr)) {
struct sockaddr_in6 srcsock;
struct in6_ifaddr *ia6;
int _s;
struct ifaddr *ifa;
/*
* Determine the appropriate zone id of the source based on
@ -240,9 +243,16 @@ in6_selectsrc(struct sockaddr_in6 *dstsock, struct ip6_pktopts *opts,
goto exit;
}
ia6 = ifatoia6(ifa_ifwithaddr(sin6tosa(&srcsock)));
if (ia6 == NULL ||
(ia6->ia6_flags & (IN6_IFF_ANYCAST | IN6_IFF_NOTREADY))) {
_s = pserialize_read_enter();
ifa = ifa_ifwithaddr(sin6tosa(&srcsock));
if (ifa == NULL) {
pserialize_read_exit(_s);
*errorp = EADDRNOTAVAIL;
goto exit;
}
ia6 = ifatoia6(ifa);
if (ia6->ia6_flags & (IN6_IFF_ANYCAST | IN6_IFF_NOTREADY)) {
pserialize_read_exit(_s);
*errorp = EADDRNOTAVAIL;
goto exit;
}
@ -250,6 +260,8 @@ in6_selectsrc(struct sockaddr_in6 *dstsock, struct ip6_pktopts *opts,
if (ifpp)
*ifpp = ifp;
ret_ia = &ia6->ia_addr.sin6_addr;
pserialize_read_exit(_s);
/* XXX don't return pointer */
goto exit;
}
@ -293,6 +305,7 @@ in6_selectsrc(struct sockaddr_in6 *dstsock, struct ip6_pktopts *opts,
if (*errorp != 0)
goto exit;
s = pserialize_read_enter();
IN6_ADDRLIST_READER_FOREACH(ia) {
int new_scope = -1, new_matchlen = -1;
struct in6_addrpolicy *new_policy = NULL;
@ -551,6 +564,7 @@ in6_selectsrc(struct sockaddr_in6 *dstsock, struct ip6_pktopts *opts,
out:
break;
}
pserialize_read_exit(s);
if ((ia = ia_best) == NULL) {
*errorp = EADDRNOTAVAIL;
@ -659,8 +673,12 @@ selectroute(struct sockaddr_in6 *dstsock, struct ip6_pktopts *opts,
goto done;
}
ifp = rt->rt_ifp;
if (ifp != NULL)
if_acquire_NOMPSAFE(ifp, PSREF);
if (ifp != NULL) {
if (!if_is_deactivated(ifp))
if_acquire_NOMPSAFE(ifp, PSREF);
else
ifp = NULL;
}
/*
* When cloning is required, try to allocate a route to the
@ -699,8 +717,12 @@ selectroute(struct sockaddr_in6 *dstsock, struct ip6_pktopts *opts,
else {
if_put(ifp, PSREF);
ifp = rt->rt_ifp;
if (ifp != NULL)
if_acquire_NOMPSAFE(ifp, PSREF);
if (ifp != NULL) {
if (!if_is_deactivated(ifp))
if_acquire_NOMPSAFE(ifp, PSREF);
else
ifp = NULL;
}
}
/*
@ -788,7 +810,8 @@ in6_selectif(struct sockaddr_in6 *dstsock, struct ip6_pktopts *opts,
* addresses.)
*/
if (rt && rt->rt_ifa && rt->rt_ifa->ifa_ifp &&
rt->rt_ifa->ifa_ifp != *retifp) {
rt->rt_ifa->ifa_ifp != *retifp &&
!if_is_deactivated(rt->rt_ifa->ifa_ifp)) {
if_put(*retifp, psref);
*retifp = rt->rt_ifa->ifa_ifp;
if_acquire_NOMPSAFE(*retifp, psref);

View File

@ -1,4 +1,4 @@
/* $NetBSD: in6_var.h,v 1.83 2016/07/08 04:33:30 ozaki-r Exp $ */
/* $NetBSD: in6_var.h,v 1.84 2016/08/01 03:15:31 ozaki-r Exp $ */
/* $KAME: in6_var.h,v 1.81 2002/06/08 11:16:51 itojun Exp $ */
/*
@ -134,6 +134,25 @@ struct in6_ifaddr {
#endif
};
#ifdef _KERNEL
static inline void
ia6_acquire(struct in6_ifaddr *ia, struct psref *psref)
{
KASSERT(ia != NULL);
ifa_acquire(&ia->ia_ifa, psref);
}
static inline void
ia6_release(struct in6_ifaddr *ia, struct psref *psref)
{
if (ia == NULL)
return;
ifa_release(&ia->ia_ifa, psref);
}
#endif
/* control structure to manage address selection policy */
struct in6_addrpolicy {
struct sockaddr_in6 addr; /* prefix address */
@ -489,13 +508,17 @@ struct in6_rrenumreq {
#ifdef _KERNEL
#include <sys/mutex.h>
#include <sys/pserialize.h>
#include <net/pktqueue.h>
extern pktqueue_t *ip6_pktq;
MALLOC_DECLARE(M_IP6OPT);
extern struct pslist_head in6_ifaddr_list;
extern struct pslist_head in6_ifaddr_list;
extern kmutex_t in6_ifaddr_lock;
#define IN6_ADDRLIST_ENTRY_INIT(__ia) \
PSLIST_ENTRY_INIT((__ia), ia6_pslist_entry)
@ -573,6 +596,20 @@ in6_get_ia_from_ifp(struct ifnet *ifp)
return (struct in6_ifaddr *)ifa;
}
static inline struct in6_ifaddr *
in6_get_ia_from_ifp_psref(struct ifnet *ifp, struct psref *psref)
{
struct in6_ifaddr *ia;
int s;
s = pserialize_read_enter();
ia = in6_get_ia_from_ifp(ifp);
if (ia != NULL)
ia6_acquire(ia, psref);
pserialize_read_exit(s);
return ia;
}
#endif /* _KERNEL */
/*
@ -623,13 +660,18 @@ in6_lookup_multi(struct in6_addr *addr, struct ifnet *ifp)
{
struct in6_multi *in6m;
struct in6_ifaddr *ia;
int s;
if ((ia = in6_get_ia_from_ifp(ifp)) == NULL)
s = pserialize_read_enter();
if ((ia = in6_get_ia_from_ifp(ifp)) == NULL) {
pserialize_read_exit(s);
return NULL;
}
LIST_FOREACH(in6m, &ia->ia6_multiaddrs, in6m_entry) {
if (IN6_ARE_ADDR_EQUAL(&in6m->in6m_addr, addr))
break;
}
pserialize_read_exit(s);
return in6m;
}
@ -659,6 +701,7 @@ in6_next_multi(struct in6_multistep *step)
}
while (step->i_ia != NULL) {
in6m = LIST_FIRST(&step->i_ia->ia6_multiaddrs);
/* FIXME NOMPSAFE */
step->i_ia = IN6_ADDRLIST_READER_NEXT(step->i_ia);
if (in6m != NULL) {
step->i_in6m = LIST_NEXT(in6m, in6m_entry);
@ -672,6 +715,7 @@ static inline struct in6_multi *
in6_first_multi(struct in6_multistep *step)
{
/* FIXME NOMPSAFE */
step->i_ia = IN6_ADDRLIST_READER_FIRST();
step->i_in6m = NULL;
return in6_next_multi(step);
@ -748,9 +792,15 @@ void in6_ifremlocal(struct ifaddr *);
void in6_ifaddlocal(struct ifaddr *);
void in6_createmkludge(struct ifnet *);
void in6_purgemkludge(struct ifnet *);
struct in6_ifaddr *in6ifa_ifpforlinklocal(const struct ifnet *, int);
struct in6_ifaddr *in6ifa_ifpwithaddr(const struct ifnet *,
const struct in6_addr *);
struct in6_ifaddr *
in6ifa_ifpforlinklocal(const struct ifnet *, int);
struct in6_ifaddr *
in6ifa_ifpforlinklocal_psref(const struct ifnet *, int, struct psref *);
struct in6_ifaddr *
in6ifa_ifpwithaddr(const struct ifnet *, const struct in6_addr *);
struct in6_ifaddr *
in6ifa_ifpwithaddr_psref(const struct ifnet *, const struct in6_addr *,
struct psref *);
struct in6_ifaddr *in6ifa_ifwithaddr(const struct in6_addr *, uint32_t);
char *ip6_sprintf(const struct in6_addr *);
int in6_matchlen(struct in6_addr *, struct in6_addr *);

View File

@ -1,4 +1,4 @@
/* $NetBSD: ip6_input.c,v 1.164 2016/07/07 09:32:03 ozaki-r Exp $ */
/* $NetBSD: ip6_input.c,v 1.165 2016/08/01 03:15:31 ozaki-r Exp $ */
/* $KAME: ip6_input.c,v 1.188 2001/03/29 05:34:31 itojun Exp $ */
/*
@ -62,7 +62,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: ip6_input.c,v 1.164 2016/07/07 09:32:03 ozaki-r Exp $");
__KERNEL_RCSID(0, "$NetBSD: ip6_input.c,v 1.165 2016/08/01 03:15:31 ozaki-r Exp $");
#ifdef _KERNEL_OPT
#include "opt_gateway.h"
@ -565,8 +565,10 @@ ip6_input(struct mbuf *m, struct ifnet *rcvif)
*/
if (deliverifp && ip6_getdstifaddr(m) == NULL) {
struct in6_ifaddr *ia6;
int s = pserialize_read_enter();
ia6 = in6_ifawithifp(deliverifp, &ip6->ip6_dst);
/* Depends on ip6_setdstifaddr never sleep */
if (ia6 != NULL && ip6_setdstifaddr(m, ia6) == NULL) {
/*
* XXX maybe we should drop the packet here,
@ -574,6 +576,7 @@ ip6_input(struct mbuf *m, struct ifnet *rcvif)
* to the upper layers.
*/
}
pserialize_read_exit(s);
}
/*
@ -701,9 +704,11 @@ ip6_input(struct mbuf *m, struct ifnet *rcvif)
#ifdef IFA_STATS
if (deliverifp != NULL) {
struct in6_ifaddr *ia6;
int s = pserialize_read_enter();
ia6 = in6_ifawithifp(deliverifp, &ip6->ip6_dst);
if (ia6)
ia6->ia_ifa.ifa_data.ifad_inbytes += m->m_pkthdr.len;
pserialize_read_exit(s);
}
#endif
IP6_STATINC(IP6_STAT_DELIVERED);

View File

@ -1,4 +1,4 @@
/* $NetBSD: ip6_output.c,v 1.172 2016/07/29 06:02:03 ozaki-r Exp $ */
/* $NetBSD: ip6_output.c,v 1.173 2016/08/01 03:15:31 ozaki-r Exp $ */
/* $KAME: ip6_output.c,v 1.172 2001/03/25 09:55:56 itojun Exp $ */
/*
@ -62,7 +62,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: ip6_output.c,v 1.172 2016/07/29 06:02:03 ozaki-r Exp $");
__KERNEL_RCSID(0, "$NetBSD: ip6_output.c,v 1.173 2016/08/01 03:15:31 ozaki-r Exp $");
#ifdef _KERNEL_OPT
#include "opt_inet.h"
@ -526,6 +526,8 @@ ip6_output(
*/
if (ia != NULL && ia->ia_ifp) {
origifp = ia->ia_ifp;
if (if_is_deactivated(origifp))
goto bad;
if_acquire_NOMPSAFE(origifp, &psref_ia);
release_psref_ia = true;
} else
@ -761,13 +763,16 @@ ip6_output(
/* case 1-a and 2-a */
struct in6_ifaddr *ia6;
int sw_csum;
int s;
ip6 = mtod(m, struct ip6_hdr *);
s = pserialize_read_enter();
ia6 = in6_ifawithifp(ifp, &ip6->ip6_src);
if (ia6) {
/* Record statistics for this interface address. */
ia6->ia_ifa.ifa_data.ifad_outbytes += m->m_pkthdr.len;
}
pserialize_read_exit(s);
sw_csum = m->m_pkthdr.csum_flags & ~ifp->if_csum_flags_tx;
if ((sw_csum & (M_CSUM_UDPv6|M_CSUM_TCPv6)) != 0) {
@ -953,7 +958,9 @@ sendorfree:
m->m_nextpkt = 0;
if (error == 0) {
struct in6_ifaddr *ia6;
int s;
ip6 = mtod(m, struct ip6_hdr *);
s = pserialize_read_enter();
ia6 = in6_ifawithifp(ifp, &ip6->ip6_src);
if (ia6) {
/*
@ -963,6 +970,7 @@ sendorfree:
ia6->ia_ifa.ifa_data.ifad_outbytes +=
m->m_pkthdr.len;
}
pserialize_read_exit(s);
KASSERT(dst != NULL);
error = nd6_output(ifp, origifp, m, dst, rt);
} else

View File

@ -1,4 +1,4 @@
/* $NetBSD: mld6.c,v 1.73 2016/07/20 07:37:51 ozaki-r Exp $ */
/* $NetBSD: mld6.c,v 1.74 2016/08/01 03:15:31 ozaki-r Exp $ */
/* $KAME: mld6.c,v 1.25 2001/01/16 14:14:18 itojun Exp $ */
/*
@ -102,7 +102,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: mld6.c,v 1.73 2016/07/20 07:37:51 ozaki-r Exp $");
__KERNEL_RCSID(0, "$NetBSD: mld6.c,v 1.74 2016/08/01 03:15:31 ozaki-r Exp $");
#ifdef _KERNEL_OPT
#include "opt_inet.h"
@ -402,7 +402,9 @@ mld_input(struct mbuf *m, int off)
* if we sent the last report.
*/
switch (mldh->mld_type) {
case MLD_LISTENER_QUERY:
case MLD_LISTENER_QUERY: {
struct psref psref;
if (ifp->if_flags & IFF_LOOPBACK)
break;
@ -428,10 +430,14 @@ mld_input(struct mbuf *m, int off)
*/
timer = ntohs(mldh->mld_maxdelay);
ia = in6_get_ia_from_ifp(ifp);
ia = in6_get_ia_from_ifp_psref(ifp, &psref);
if (ia == NULL)
break;
/* The following operations may sleep */
m_put_rcvif(ifp, &s);
ifp = NULL;
LIST_FOREACH(in6m, &ia->ia6_multiaddrs, in6m_entry) {
if (IN6_ARE_ADDR_EQUAL(&in6m->in6m_addr, &all_in6) ||
IPV6_ADDR_MC_SCOPE(&in6m->in6m_addr) <
@ -457,7 +463,9 @@ mld_input(struct mbuf *m, int off)
mld_starttimer(in6m);
}
}
ia6_release(ia, &psref);
break;
}
case MLD_LISTENER_REPORT:
/*
@ -514,6 +522,8 @@ mld_sendpkt(struct in6_multi *in6m, int type,
struct in6_ifaddr *ia = NULL;
struct ifnet *ifp = in6m->in6m_ifp;
int ignflags;
struct psref psref;
int bound;
/*
* At first, find a link local address on the outgoing interface
@ -522,20 +532,31 @@ mld_sendpkt(struct in6_multi *in6m, int type,
* the case where we first join a link-local address.
*/
ignflags = (IN6_IFF_NOTREADY|IN6_IFF_ANYCAST) & ~IN6_IFF_TENTATIVE;
if ((ia = in6ifa_ifpforlinklocal(ifp, ignflags)) == NULL)
bound = curlwp_bind();
ia = in6ifa_ifpforlinklocal_psref(ifp, ignflags, &psref);
if (ia == NULL) {
curlwp_bindx(bound);
return;
if ((ia->ia6_flags & IN6_IFF_TENTATIVE))
}
if ((ia->ia6_flags & IN6_IFF_TENTATIVE)) {
ia6_release(ia, &psref);
ia = NULL;
}
/* Allocate two mbufs to store IPv6 header and MLD header */
mldh = mld_allocbuf(&mh, sizeof(struct mld_hdr), in6m, type);
if (mldh == NULL)
if (mldh == NULL) {
ia6_release(ia, &psref);
curlwp_bindx(bound);
return;
}
/* fill src/dst here */
ip6 = mtod(mh, struct ip6_hdr *);
ip6->ip6_src = ia ? ia->ia_addr.sin6_addr : in6addr_any;
ip6->ip6_dst = dst ? *dst : in6m->in6m_addr;
ia6_release(ia, &psref);
curlwp_bindx(bound);
mldh->mld_addr = in6m->in6m_addr;
in6_clearscope(&mldh->mld_addr); /* XXX */
@ -645,6 +666,7 @@ in6_addmulti(struct in6_addr *maddr6, struct ifnet *ifp,
*/
in6m->in6m_refcount++;
} else {
int _s;
/*
* New address; allocate a new multicast record
* and link it into the interface's multicast list.
@ -664,8 +686,10 @@ in6_addmulti(struct in6_addr *maddr6, struct ifnet *ifp,
callout_init(&in6m->in6m_timer_ch, CALLOUT_MPSAFE);
callout_setfunc(&in6m->in6m_timer_ch, mld_timeo, in6m);
_s = pserialize_read_enter();
ia = in6_get_ia_from_ifp(ifp);
if (ia == NULL) {
pserialize_read_exit(_s);
callout_destroy(&in6m->in6m_timer_ch);
free(in6m, M_IPMADDR);
splx(s);
@ -674,7 +698,9 @@ in6_addmulti(struct in6_addr *maddr6, struct ifnet *ifp,
}
in6m->in6m_ia = ia;
ifaref(&ia->ia_ifa); /* gain a reference */
/* FIXME NOMPSAFE: need to lock */
LIST_INSERT_HEAD(&ia->ia6_multiaddrs, in6m, in6m_entry);
pserialize_read_exit(_s);
/*
* Ask the network driver to update its multicast reception
@ -816,7 +842,9 @@ in6_savemkludge(struct in6_ifaddr *oia)
{
struct in6_ifaddr *ia;
struct in6_multi *in6m;
int s;
s = pserialize_read_enter();
ia = in6_get_ia_from_ifp(oia->ia_ifp);
if (ia) { /* there is another address */
KASSERT(ia != oia);
@ -825,6 +853,7 @@ in6_savemkludge(struct in6_ifaddr *oia)
ifaref(&ia->ia_ifa);
ifafree(&in6m->in6m_ia->ia_ifa);
in6m->in6m_ia = ia;
/* FIXME NOMPSAFE: need to lock */
LIST_INSERT_HEAD(&ia->ia6_multiaddrs, in6m, in6m_entry);
}
} else { /* last address on this if deleted, save */
@ -844,6 +873,7 @@ in6_savemkludge(struct in6_ifaddr *oia)
LIST_INSERT_HEAD(&mk->mk_head, in6m, in6m_entry);
}
}
pserialize_read_exit(s);
}
/*
@ -986,8 +1016,8 @@ in6_multicast_sysctl(SYSCTLFN_ARGS)
uint32_t tmp;
int error;
size_t written;
struct psref psref;
int bound;
struct psref psref, psref_ia;
int bound, s;
if (namelen != 1)
return EINVAL;
@ -1001,6 +1031,7 @@ in6_multicast_sysctl(SYSCTLFN_ARGS)
if (oldp == NULL) {
*oldlenp = 0;
s = pserialize_read_enter();
IFADDR_READER_FOREACH(ifa, ifp) {
if (ifa->ifa_addr->sa_family != AF_INET6)
continue;
@ -1010,6 +1041,7 @@ in6_multicast_sysctl(SYSCTLFN_ARGS)
sizeof(uint32_t);
}
}
pserialize_read_exit(s);
if_put(ifp, &psref);
curlwp_bindx(bound);
return 0;
@ -1017,9 +1049,14 @@ in6_multicast_sysctl(SYSCTLFN_ARGS)
error = 0;
written = 0;
s = pserialize_read_enter();
IFADDR_READER_FOREACH(ifa, ifp) {
if (ifa->ifa_addr->sa_family != AF_INET6)
continue;
ifa_acquire(ifa, &psref_ia);
pserialize_read_exit(s);
ifa6 = (struct in6_ifaddr *)ifa;
LIST_FOREACH(in6m, &ifa6->ia6_multiaddrs, in6m_entry) {
if (written + 2 * sizeof(struct in6_addr) +
@ -1044,8 +1081,13 @@ in6_multicast_sysctl(SYSCTLFN_ARGS)
oldp = (char *)oldp + sizeof(tmp);
written += sizeof(tmp);
}
s = pserialize_read_enter();
ifa_release(ifa, &psref_ia);
}
pserialize_read_exit(s);
done:
ifa_release(ifa, &psref_ia);
if_put(ifp, &psref);
curlwp_bindx(bound);
*oldlenp = written;

View File

@ -1,4 +1,4 @@
/* $NetBSD: nd6.c,v 1.204 2016/07/15 07:40:09 ozaki-r Exp $ */
/* $NetBSD: nd6.c,v 1.205 2016/08/01 03:15:31 ozaki-r Exp $ */
/* $KAME: nd6.c,v 1.279 2002/06/08 11:16:51 itojun Exp $ */
/*
@ -31,7 +31,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.204 2016/07/15 07:40:09 ozaki-r Exp $");
__KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.205 2016/08/01 03:15:31 ozaki-r Exp $");
#ifdef _KERNEL_OPT
#include "opt_net_mpsafe.h"
@ -571,6 +571,8 @@ nd6_timer_work(struct work *wk, void *arg)
struct nd_defrouter *next_dr, *dr;
struct nd_prefix *next_pr, *pr;
struct in6_ifaddr *ia6, *nia6;
int s, bound;
struct psref psref;
callout_reset(&nd6_timer_ch, nd6_prune * hz,
nd6_timer, NULL);
@ -592,9 +594,15 @@ nd6_timer_work(struct work *wk, void *arg)
* However, from a stricter speci-confrmance standpoint, we should
* rather separate address lifetimes and prefix lifetimes.
*/
bound = curlwp_bind();
addrloop:
for (ia6 = IN6_ADDRLIST_WRITER_FIRST(); ia6; ia6 = nia6) {
nia6 = IN6_ADDRLIST_WRITER_NEXT(ia6);
s = pserialize_read_enter();
for (ia6 = IN6_ADDRLIST_READER_FIRST(); ia6; ia6 = nia6) {
nia6 = IN6_ADDRLIST_READER_NEXT(ia6);
ia6_acquire(ia6, &psref);
pserialize_read_exit(s);
/* check address lifetime */
if (IFA6_IS_INVALID(ia6)) {
int regen = 0;
@ -615,7 +623,9 @@ nd6_timer_work(struct work *wk, void *arg)
regen = 1;
}
ia6_release(ia6, &psref);
in6_purgeaddr(&ia6->ia_ifa);
ia6 = NULL;
if (regen)
goto addrloop; /* XXX: see below */
@ -649,6 +659,7 @@ nd6_timer_work(struct work *wk, void *arg)
* loop just for safety. Or does this
* significantly reduce performance??
*/
ia6_release(ia6, &psref);
goto addrloop;
}
}
@ -663,7 +674,11 @@ nd6_timer_work(struct work *wk, void *arg)
(struct ifaddr *)ia6, 0, NULL);
}
}
s = pserialize_read_enter();
ia6_release(ia6, &psref);
}
pserialize_read_exit(s);
curlwp_bindx(bound);
/* expire prefix list */
LIST_FOREACH_SAFE(pr, &nd_prefix, ndpr_entry, next_pr) {
@ -702,8 +717,10 @@ regen_tmpaddr(const struct in6_ifaddr *ia6)
struct ifaddr *ifa;
struct ifnet *ifp;
struct in6_ifaddr *public_ifa6 = NULL;
int s;
ifp = ia6->ia_ifa.ifa_ifp;
s = pserialize_read_enter();
IFADDR_READER_FOREACH(ifa, ifp) {
struct in6_ifaddr *it6;
@ -745,18 +762,24 @@ regen_tmpaddr(const struct in6_ifaddr *ia6)
if (public_ifa6 != NULL) {
int e;
struct psref psref;
ia6_acquire(public_ifa6, &psref);
pserialize_read_exit(s);
/*
* Random factor is introduced in the preferred lifetime, so
* we do not need additional delay (3rd arg to in6_tmpifadd).
*/
if ((e = in6_tmpifadd(public_ifa6, 0, 0)) != 0) {
ia6_release(public_ifa6, &psref);
log(LOG_NOTICE, "regen_tmpaddr: failed to create a new"
" tmp addr, errno=%d\n", e);
return -1;
}
ia6_release(public_ifa6, &psref);
return 0;
}
pserialize_read_exit(s);
return -1;
}
@ -914,6 +937,7 @@ nd6_is_new_addr_neighbor(const struct sockaddr_in6 *addr, struct ifnet *ifp)
{
struct nd_prefix *pr;
struct ifaddr *dstaddr;
int s;
/*
* A link-local address is always a neighbor.
@ -979,20 +1003,15 @@ nd6_is_new_addr_neighbor(const struct sockaddr_in6 *addr, struct ifnet *ifp)
* If the address is assigned on the node of the other side of
* a p2p interface, the address should be a neighbor.
*/
s = pserialize_read_enter();
dstaddr = ifa_ifwithdstaddr(sin6tocsa(addr));
if (dstaddr != NULL) {
if (dstaddr->ifa_ifp == ifp) {
#ifdef __FreeBSD__
/* XXX we need to ifaref in ifa_ifwithdstaddr as well */
ifafree(dstaddr);
#endif
pserialize_read_exit(s);
return 1;
}
#ifdef __FreeBSD__
/* XXX we need to ifaref in ifa_ifwithdstaddr as well */
ifafree(dstaddr);
#endif
}
pserialize_read_exit(s);
/*
* If the default router list is empty, all addresses are regarded
@ -1374,7 +1393,9 @@ nd6_rtrequest(int req, struct rtentry *rt, const struct rt_addrinfo *info)
}
switch (req) {
case RTM_ADD:
case RTM_ADD: {
int s;
RT_DPRINTF("rt_getkey(rt) = %p\n", rt_getkey(rt));
/*
* There is no backward compatibility :)
@ -1481,6 +1502,7 @@ nd6_rtrequest(int req, struct rtentry *rt, const struct rt_addrinfo *info)
* check if rt_getkey(rt) is an address assigned
* to the interface.
*/
s = pserialize_read_enter();
ifa = (struct ifaddr *)in6ifa_ifpwithaddr(ifp,
&satocsin6(rt_getkey(rt))->sin6_addr);
if (ifa != NULL) {
@ -1517,8 +1539,8 @@ nd6_rtrequest(int req, struct rtentry *rt, const struct rt_addrinfo *info)
}
}
}
out:
pserialize_read_exit(s);
/*
* If we have too many cache entries, initiate immediate
* purging for some entries.
@ -1526,6 +1548,7 @@ nd6_rtrequest(int req, struct rtentry *rt, const struct rt_addrinfo *info)
if (rt->rt_ifp != NULL)
nd6_gc_neighbors(LLTABLE6(rt->rt_ifp));
break;
}
case RTM_DELETE:
/* leave from solicited node multicast for proxy ND */
@ -1709,6 +1732,7 @@ nd6_ioctl(u_long cmd, void *data, struct ifnet *ifp)
*/
int duplicated_linklocal = 0;
s = pserialize_read_enter();
IFADDR_READER_FOREACH(ifa, ifp) {
if (ifa->ifa_addr->sa_family != AF_INET6)
continue;
@ -1720,6 +1744,7 @@ nd6_ioctl(u_long cmd, void *data, struct ifnet *ifp)
break;
}
}
pserialize_read_exit(s);
if (duplicated_linklocal) {
ND.flags |= ND6_IFF_IFDISABLED;
@ -1732,18 +1757,29 @@ nd6_ioctl(u_long cmd, void *data, struct ifnet *ifp)
in6_if_up(ifp);
}
} else if (!(ND_IFINFO(ifp)->flags & ND6_IFF_IFDISABLED) &&
(ND.flags & ND6_IFF_IFDISABLED))
{
(ND.flags & ND6_IFF_IFDISABLED)) {
int bound = curlwp_bind();
/* Mark all IPv6 addresses as tentative. */
ND_IFINFO(ifp)->flags |= ND6_IFF_IFDISABLED;
s = pserialize_read_enter();
IFADDR_READER_FOREACH(ifa, ifp) {
struct psref psref;
if (ifa->ifa_addr->sa_family != AF_INET6)
continue;
ifa_acquire(ifa, &psref);
pserialize_read_exit(s);
nd6_dad_stop(ifa);
ia = (struct in6_ifaddr *)ifa;
ia->ia6_flags |= IN6_IFF_TENTATIVE;
s = pserialize_read_enter();
ifa_release(ifa, &psref);
}
pserialize_read_exit(s);
curlwp_bindx(bound);
}
if (ND.flags & ND6_IFF_AUTO_LINKLOCAL) {
@ -1761,9 +1797,10 @@ nd6_ioctl(u_long cmd, void *data, struct ifnet *ifp)
* address is assigned, and IFF_UP, try to
* assign one.
*/
int haslinklocal = 0;
int haslinklocal = 0;
IFADDR_READER_FOREACH(ifa, ifp) {
s = pserialize_read_enter();
IFADDR_READER_FOREACH(ifa, ifp) {
if (ifa->ifa_addr->sa_family !=AF_INET6)
continue;
ia = (struct in6_ifaddr *)ifa;
@ -1771,8 +1808,9 @@ nd6_ioctl(u_long cmd, void *data, struct ifnet *ifp)
haslinklocal = 1;
break;
}
}
if (!haslinklocal)
}
pserialize_read_exit(s);
if (!haslinklocal)
in6_ifattach(ifp, NULL);
}
}
@ -1793,22 +1831,30 @@ nd6_ioctl(u_long cmd, void *data, struct ifnet *ifp)
s = splsoftnet();
LIST_FOREACH_SAFE(pfx, &nd_prefix, ndpr_entry, next) {
struct in6_ifaddr *ia, *ia_next;
int _s;
if (IN6_IS_ADDR_LINKLOCAL(&pfx->ndpr_prefix.sin6_addr))
continue; /* XXX */
/* do we really have to remove addresses as well? */
for (ia = IN6_ADDRLIST_WRITER_FIRST(); ia;
restart:
_s = pserialize_read_enter();
for (ia = IN6_ADDRLIST_READER_FIRST(); ia;
ia = ia_next) {
/* ia might be removed. keep the next ptr. */
ia_next = IN6_ADDRLIST_WRITER_NEXT(ia);
ia_next = IN6_ADDRLIST_READER_NEXT(ia);
if ((ia->ia6_flags & IN6_IFF_AUTOCONF) == 0)
continue;
if (ia->ia6_ndpr == pfx)
if (ia->ia6_ndpr == pfx) {
pserialize_read_exit(_s);
/* XXX NOMPSAFE? */
in6_purgeaddr(&ia->ia_ifa);
goto restart;
}
}
pserialize_read_exit(_s);
prelist_remove(pfx);
}
splx(s);
@ -2172,6 +2218,7 @@ nd6_output(struct ifnet *ifp, struct ifnet *origifp, struct mbuf *m,
if (rt != NULL && (rt->rt_flags & RTF_GATEWAY) != 0) {
struct sockaddr_in6 *gw6 = satosin6(rt->rt_gateway);
int s;
/* XXX remain the check to keep the original behavior. */
/*
@ -2182,6 +2229,7 @@ nd6_output(struct ifnet *ifp, struct ifnet *origifp, struct mbuf *m,
* if the gateway is our own address, which is
* sometimes used to install a route to a p2p link.
*/
s = pserialize_read_enter();
if (!nd6_is_addr_neighbor(gw6, ifp) ||
in6ifa_ifpwithaddr(ifp, &gw6->sin6_addr)) {
/*
@ -2192,8 +2240,10 @@ nd6_output(struct ifnet *ifp, struct ifnet *origifp, struct mbuf *m,
if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
senderr(EHOSTUNREACH);
pserialize_read_exit(s);
goto sendpkt;
}
pserialize_read_exit(s);
}
/*

View File

@ -1,4 +1,4 @@
/* $NetBSD: nd6_nbr.c,v 1.126 2016/07/28 09:03:50 ozaki-r Exp $ */
/* $NetBSD: nd6_nbr.c,v 1.127 2016/08/01 03:15:31 ozaki-r Exp $ */
/* $KAME: nd6_nbr.c,v 1.61 2001/02/10 16:06:14 jinmei Exp $ */
/*
@ -31,7 +31,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: nd6_nbr.c,v 1.126 2016/07/28 09:03:50 ozaki-r Exp $");
__KERNEL_RCSID(0, "$NetBSD: nd6_nbr.c,v 1.127 2016/08/01 03:15:31 ozaki-r Exp $");
#ifdef _KERNEL_OPT
#include "opt_inet.h"
@ -104,7 +104,7 @@ nd6_ns_input(struct mbuf *m, int off, int icmp6len)
struct in6_addr taddr6;
struct in6_addr myaddr6;
char *lladdr = NULL;
struct ifaddr *ifa;
struct ifaddr *ifa = NULL;
int lladdrlen = 0;
int anycast = 0, proxy = 0, tentative = 0;
int router = ip6_forwarding;
@ -112,6 +112,7 @@ nd6_ns_input(struct mbuf *m, int off, int icmp6len)
union nd_opts ndopts;
const struct sockaddr_dl *proxydl = NULL;
struct psref psref;
struct psref psref_ia;
ifp = m_get_rcvif_psref(m, &psref);
if (ifp == NULL)
@ -216,14 +217,20 @@ nd6_ns_input(struct mbuf *m, int off, int icmp6len)
*/
/* (1) and (3) check. */
#if NCARP > 0
if (ifp->if_carp && ifp->if_type != IFT_CARP)
if (ifp->if_carp && ifp->if_type != IFT_CARP) {
int s = pserialize_read_enter();
ifa = carp_iamatch6(ifp->if_carp, &taddr6);
else
if (ifa != NULL)
ifa_acquire(ifa, &psref_ia);
pserialize_read_exit(s);
} else
ifa = NULL;
if (!ifa)
ifa = (struct ifaddr *)in6ifa_ifpwithaddr(ifp, &taddr6);
ifa = (struct ifaddr *)in6ifa_ifpwithaddr_psref(ifp, &taddr6,
&psref_ia);
#else
ifa = (struct ifaddr *)in6ifa_ifpwithaddr(ifp, &taddr6);
ifa = (struct ifaddr *)in6ifa_ifpwithaddr_psref(ifp, &taddr6,
&psref_ia);
#endif
/* (2) check. */
@ -239,8 +246,8 @@ nd6_ns_input(struct mbuf *m, int off, int icmp6len)
/*
* proxy NDP for single entry
*/
ifa = (struct ifaddr *)in6ifa_ifpforlinklocal(ifp,
IN6_IFF_NOTREADY|IN6_IFF_ANYCAST);
ifa = (struct ifaddr *)in6ifa_ifpforlinklocal_psref(ifp,
IN6_IFF_NOTREADY|IN6_IFF_ANYCAST, &psref_ia);
if (ifa) {
proxy = 1;
proxydl = satocsdl(rt->rt_gateway);
@ -299,9 +306,13 @@ nd6_ns_input(struct mbuf *m, int off, int icmp6len)
*/
if (IN6_IS_ADDR_UNSPECIFIED(&saddr6))
nd6_dad_ns_input(ifa);
ifa_release(ifa, &psref_ia);
ifa = NULL;
goto freeit;
}
ifa_release(ifa, &psref_ia);
ifa = NULL;
/*
* If the source address is unspecified address, entries must not
@ -331,6 +342,7 @@ nd6_ns_input(struct mbuf *m, int off, int icmp6len)
(router ? ND_NA_FLAG_ROUTER : 0) | ND_NA_FLAG_SOLICITED,
tlladdr, (const struct sockaddr *)proxydl);
freeit:
ifa_release(ifa, &psref_ia);
m_put_rcvif_psref(ifp, &psref);
m_freem(m);
return;
@ -340,6 +352,7 @@ nd6_ns_input(struct mbuf *m, int off, int icmp6len)
nd6log(LOG_ERR, "dst=%s\n", ip6_sprintf(&daddr6));
nd6log(LOG_ERR, "tgt=%s\n", ip6_sprintf(&taddr6));
ICMP6_STATINC(ICMP6_STAT_BADNS);
ifa_release(ifa, &psref_ia);
m_put_rcvif_psref(ifp, &psref);
m_freem(m);
}
@ -430,6 +443,7 @@ nd6_ns_output(struct ifnet *ifp, const struct in6_addr *daddr6,
goto bad;
}
if (!dad) {
int s;
/*
* RFC2461 7.2.2:
* "If the source address of the packet prompting the
@ -445,6 +459,7 @@ nd6_ns_output(struct ifnet *ifp, const struct in6_addr *daddr6,
* - hsrc belongs to the outgoing interface.
* Otherwise, we perform the source address selection as usual.
*/
s = pserialize_read_enter();
if (hsrc && in6ifa_ifpwithaddr(ifp, hsrc))
src = hsrc;
else {
@ -459,9 +474,11 @@ nd6_ns_output(struct ifnet *ifp, const struct in6_addr *daddr6,
nd6log(LOG_DEBUG, "source can't be "
"determined: dst=%s, error=%d\n",
ip6_sprintf(&dst_sa.sin6_addr), error);
pserialize_read_exit(s);
goto bad;
}
}
pserialize_read_exit(s);
} else {
/*
* Source address for DAD packet must always be IPv6
@ -559,6 +576,7 @@ nd6_na_input(struct mbuf *m, int off, int icmp6len)
int rt_announce;
bool checklink = false;
struct psref psref;
struct psref psref_ia;
ifp = m_get_rcvif_psref(m, &psref);
if (ifp == NULL)
@ -613,7 +631,7 @@ nd6_na_input(struct mbuf *m, int off, int icmp6len)
lladdrlen = ndopts.nd_opts_tgt_lladdr->nd_opt_len << 3;
}
ifa = (struct ifaddr *)in6ifa_ifpwithaddr(ifp, &taddr6);
ifa = (struct ifaddr *)in6ifa_ifpwithaddr_psref(ifp, &taddr6, &psref_ia);
/*
* Target address matches one of my interface address.
@ -627,6 +645,8 @@ nd6_na_input(struct mbuf *m, int off, int icmp6len)
if (ifa
&& (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_TENTATIVE)) {
nd6_dad_na_input(ifa);
ifa_release(ifa, &psref_ia);
ifa = NULL;
goto freeit;
}
@ -635,6 +655,8 @@ nd6_na_input(struct mbuf *m, int off, int icmp6len)
log(LOG_ERR,
"nd6_na_input: duplicate IP6 address %s\n",
ip6_sprintf(&taddr6));
ifa_release(ifa, &psref_ia);
ifa = NULL;
goto freeit;
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: nd6_rtr.c,v 1.117 2016/07/20 07:37:51 ozaki-r Exp $ */
/* $NetBSD: nd6_rtr.c,v 1.118 2016/08/01 03:15:31 ozaki-r Exp $ */
/* $KAME: nd6_rtr.c,v 1.95 2001/02/07 08:09:47 itojun Exp $ */
/*
@ -31,7 +31,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: nd6_rtr.c,v 1.117 2016/07/20 07:37:51 ozaki-r Exp $");
__KERNEL_RCSID(0, "$NetBSD: nd6_rtr.c,v 1.118 2016/08/01 03:15:31 ozaki-r Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@ -66,7 +66,7 @@ static int rtpref(struct nd_defrouter *);
static struct nd_defrouter *defrtrlist_update(struct nd_defrouter *);
static int prelist_update(struct nd_prefixctl *, struct nd_defrouter *,
struct mbuf *, int);
static struct in6_ifaddr *in6_ifadd(struct nd_prefixctl *, int);
static struct in6_ifaddr *in6_ifadd(struct nd_prefixctl *, int, struct psref *);
static struct nd_pfxrouter *pfxrtr_lookup(struct nd_prefix *,
struct nd_defrouter *);
static void pfxrtr_add(struct nd_prefix *, struct nd_defrouter *);
@ -898,6 +898,7 @@ purge_detached(struct ifnet *ifp)
struct ifaddr *ifa, *ifa_next;
for (pr = nd_prefix.lh_first; pr; pr = pr_next) {
int s;
pr_next = pr->ndpr_next;
/*
@ -913,6 +914,8 @@ purge_detached(struct ifnet *ifp)
!LIST_EMPTY(&pr->ndpr_advrtrs)))
continue;
restart:
s = pserialize_read_enter();
for (ifa = IFADDR_READER_FIRST(ifp); ifa; ifa = ifa_next) {
ifa_next = IFADDR_READER_NEXT(ifa);
if (ifa->ifa_addr->sa_family != AF_INET6)
@ -920,9 +923,13 @@ purge_detached(struct ifnet *ifp)
ia = (struct in6_ifaddr *)ifa;
if ((ia->ia6_flags & IN6_IFF_AUTOCONF) ==
IN6_IFF_AUTOCONF && ia->ia6_ndpr == pr) {
pserialize_read_exit(s);
in6_purgeaddr(ifa);
goto restart;
}
}
pserialize_read_exit(s);
if (pr->ndpr_refcnt == 0)
prelist_remove(pr);
}
@ -1065,6 +1072,7 @@ prelist_update(struct nd_prefixctl *newprc,
int error = 0;
int auth;
struct in6_addrlifetime lt6_tmp;
int ss;
auth = 0;
if (m) {
@ -1187,6 +1195,7 @@ prelist_update(struct nd_prefixctl *newprc,
* consider autoconfigured addresses while RFC2462 simply said
* "address".
*/
ss = pserialize_read_enter();
IFADDR_READER_FOREACH(ifa, ifp) {
struct in6_ifaddr *ia6;
u_int32_t remaininglifetime;
@ -1308,9 +1317,12 @@ prelist_update(struct nd_prefixctl *newprc,
ia6->ia6_lifetime = lt6_tmp;
ia6->ia6_updatetime = time_uptime;
}
pserialize_read_exit(ss);
if (ia6_match == NULL && newprc->ndprc_vltime) {
int ifidlen;
struct in6_ifaddr *ia6;
struct psref psref;
/*
* 5.5.3 (d) (continued)
@ -1340,7 +1352,7 @@ prelist_update(struct nd_prefixctl *newprc,
goto end;
}
if ((ia6 = in6_ifadd(newprc, mcast)) != NULL) {
if ((ia6 = in6_ifadd(newprc, mcast, &psref)) != NULL) {
/*
* note that we should use pr (not newprc) for reference.
*/
@ -1367,6 +1379,7 @@ prelist_update(struct nd_prefixctl *newprc,
"address, errno=%d\n", e);
}
}
ia6_release(ia6, &psref);
/*
* A newly added address might affect the status
@ -1426,6 +1439,7 @@ pfxlist_onlink_check(void)
struct in6_ifaddr *ia;
struct nd_defrouter *dr;
struct nd_pfxrouter *pfxrtr = NULL;
int s;
/*
* Check if there is a prefix that has a reachable advertising
@ -1540,6 +1554,7 @@ pfxlist_onlink_check(void)
* always be attached.
* The precise detection logic is same as the one for prefixes.
*/
s = pserialize_read_enter();
IN6_ADDRLIST_READER_FOREACH(ia) {
if (!(ia->ia6_flags & IN6_IFF_AUTOCONF))
continue;
@ -1556,20 +1571,30 @@ pfxlist_onlink_check(void)
if (find_pfxlist_reachable_router(ia->ia6_ndpr))
break;
}
pserialize_read_exit(s);
if (ia) {
int bound = curlwp_bind();
s = pserialize_read_enter();
IN6_ADDRLIST_READER_FOREACH(ia) {
struct ifaddr *ifa = (struct ifaddr *)ia;
struct psref psref;
if ((ia->ia6_flags & IN6_IFF_AUTOCONF) == 0)
continue;
if (ia->ia6_ndpr == NULL) /* XXX: see above. */
continue;
ia6_acquire(ia, &psref);
pserialize_read_exit(s);
if (find_pfxlist_reachable_router(ia->ia6_ndpr)) {
if (ia->ia6_flags & IN6_IFF_DETACHED) {
ia->ia6_flags &= ~IN6_IFF_DETACHED;
ia->ia6_flags |= IN6_IFF_TENTATIVE;
nd6_dad_start((struct ifaddr *)ia,
nd6_dad_start(ifa,
0);
/* We will notify the routing socket
* of the DAD result, so no need to
@ -1579,23 +1604,43 @@ pfxlist_onlink_check(void)
if ((ia->ia6_flags & IN6_IFF_DETACHED) == 0) {
ia->ia6_flags |= IN6_IFF_DETACHED;
rt_newaddrmsg(RTM_NEWADDR,
(struct ifaddr *)ia, 0, NULL);
ifa, 0, NULL);
}
}
s = pserialize_read_enter();
ia6_release(ia, &psref);
}
pserialize_read_exit(s);
curlwp_bindx(bound);
}
else {
int bound = curlwp_bind();
s = pserialize_read_enter();
IN6_ADDRLIST_READER_FOREACH(ia) {
if ((ia->ia6_flags & IN6_IFF_AUTOCONF) == 0)
continue;
if (ia->ia6_flags & IN6_IFF_DETACHED) {
struct ifaddr *ifa = (struct ifaddr *)ia;
struct psref psref;
ia->ia6_flags &= ~IN6_IFF_DETACHED;
ia->ia6_flags |= IN6_IFF_TENTATIVE;
ia6_acquire(ia, &psref);
pserialize_read_exit(s);
/* Do we need a delay in this case? */
nd6_dad_start((struct ifaddr *)ia, 0);
nd6_dad_start(ifa, 0);
s = pserialize_read_enter();
ia6_release(ia, &psref);
}
}
pserialize_read_exit(s);
curlwp_bindx(bound);
}
}
@ -1608,6 +1653,8 @@ nd6_prefix_onlink(struct nd_prefix *pr)
struct nd_prefix *opr;
u_long rtflags;
int error = 0;
struct psref psref;
int bound;
/* sanity check */
if ((pr->ndpr_stateflags & NDPRF_ONLINK) != 0) {
@ -1640,14 +1687,18 @@ nd6_prefix_onlink(struct nd_prefix *pr)
* We prefer link-local addresses as the associated interface address.
*/
/* search for a link-local addr */
ifa = (struct ifaddr *)in6ifa_ifpforlinklocal(ifp,
IN6_IFF_NOTREADY | IN6_IFF_ANYCAST);
bound = curlwp_bind();
ifa = (struct ifaddr *)in6ifa_ifpforlinklocal_psref(ifp,
IN6_IFF_NOTREADY | IN6_IFF_ANYCAST, &psref);
if (ifa == NULL) {
/* XXX: freebsd does not have ifa_ifwithaf */
int s = pserialize_read_enter();
IFADDR_READER_FOREACH(ifa, ifp) {
if (ifa->ifa_addr->sa_family == AF_INET6)
break;
}
if (ifa != NULL)
ifa_acquire(ifa, &psref);
pserialize_read_exit(s);
/* should we care about ia6_flags? */
}
if (ifa == NULL) {
@ -1661,6 +1712,7 @@ nd6_prefix_onlink(struct nd_prefix *pr)
" to add route for a prefix(%s/%d) on %s\n",
ip6_sprintf(&pr->ndpr_prefix.sin6_addr),
pr->ndpr_plen, if_name(ifp));
curlwp_bindx(bound);
return (0);
}
@ -1697,6 +1749,8 @@ nd6_prefix_onlink(struct nd_prefix *pr)
ip6_sprintf(&((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr),
ip6_sprintf(&mask6.sin6_addr), rtflags, error);
}
ifa_release(ifa, &psref);
curlwp_bindx(bound);
return (error);
}
@ -1772,7 +1826,7 @@ nd6_prefix_offlink(struct nd_prefix *pr)
}
static struct in6_ifaddr *
in6_ifadd(struct nd_prefixctl *prc, int mcast)
in6_ifadd(struct nd_prefixctl *prc, int mcast, struct psref *psref)
{
struct ifnet *ifp = prc->ndprc_ifp;
struct ifaddr *ifa;
@ -1782,6 +1836,7 @@ in6_ifadd(struct nd_prefixctl *prc, int mcast)
struct in6_addr mask;
int prefixlen = prc->ndprc_plen;
int updateflags;
int s;
in6_prefixlen2mask(&mask, prefixlen);
@ -1805,11 +1860,14 @@ in6_ifadd(struct nd_prefixctl *prc, int mcast)
* with the same interface identifier, than to have multiple addresses
* with different interface identifiers.
*/
s = pserialize_read_enter();
ifa = (struct ifaddr *)in6ifa_ifpforlinklocal(ifp, 0); /* 0 is OK? */
if (ifa)
ib = (struct in6_ifaddr *)ifa;
else
else {
pserialize_read_exit(s);
return NULL;
}
#if 0 /* don't care link local addr state, and always do DAD */
/* if link-local address is not eligible, do not autoconfigure. */
@ -1825,6 +1883,7 @@ in6_ifadd(struct nd_prefixctl *prc, int mcast)
nd6log(LOG_INFO, "wrong prefixlen for %s "
"(prefix=%d ifid=%d)\n",
if_name(ifp), prefixlen, 128 - plen0);
pserialize_read_exit(s);
return NULL;
}
@ -1852,6 +1911,7 @@ in6_ifadd(struct nd_prefixctl *prc, int mcast)
(ib->ia_addr.sin6_addr.s6_addr32[2] & ~mask.s6_addr32[2]);
ifra.ifra_addr.sin6_addr.s6_addr32[3] |=
(ib->ia_addr.sin6_addr.s6_addr32[3] & ~mask.s6_addr32[3]);
pserialize_read_exit(s);
/* new prefix mask. */
sockaddr_in6_init(&ifra.ifra_prefixmask, &mask, 0, 0, 0);
@ -1869,12 +1929,15 @@ in6_ifadd(struct nd_prefixctl *prc, int mcast)
* usually not happen, but we can still see this case, e.g., if we
* have manually configured the exact address to be configured.
*/
s = pserialize_read_enter();
if (in6ifa_ifpwithaddr(ifp, &ifra.ifra_addr.sin6_addr) != NULL) {
/* this should be rare enough to make an explicit log */
log(LOG_INFO, "in6_ifadd: %s is already configured\n",
ip6_sprintf(&ifra.ifra_addr.sin6_addr));
pserialize_read_exit(s);
return (NULL);
}
pserialize_read_exit(s);
/*
* Allocate ifaddr structure, link into chain, etc.
@ -1892,7 +1955,7 @@ in6_ifadd(struct nd_prefixctl *prc, int mcast)
return (NULL); /* ifaddr must not have been allocated. */
}
ia = in6ifa_ifpwithaddr(ifp, &ifra.ifra_addr.sin6_addr);
ia = in6ifa_ifpwithaddr_psref(ifp, &ifra.ifra_addr.sin6_addr, psref);
return (ia); /* this is always non-NULL */
}
@ -2007,14 +2070,17 @@ in6_tmpifadd(
if ((error = in6_update_ifa(ifp, &ifra, NULL, updateflags)) != 0)
return (error);
s = pserialize_read_enter();
newia = in6ifa_ifpwithaddr(ifp, &ifra.ifra_addr.sin6_addr);
if (newia == NULL) { /* XXX: can it happen? */
pserialize_read_exit(s);
nd6log(LOG_ERR,
"ifa update succeeded, but we got no ifaddr\n");
return (EINVAL); /* XXX */
}
newia->ia6_ndpr = ia0->ia6_ndpr;
newia->ia6_ndpr->ndpr_refcnt++;
pserialize_read_exit(s);
/*
* A newly added address might affect the status of other addresses.

View File

@ -1,4 +1,4 @@
/* $NetBSD: raw_ip6.c,v 1.148 2016/07/15 07:40:09 ozaki-r Exp $ */
/* $NetBSD: raw_ip6.c,v 1.149 2016/08/01 03:15:31 ozaki-r Exp $ */
/* $KAME: raw_ip6.c,v 1.82 2001/07/23 18:57:56 jinmei Exp $ */
/*
@ -62,7 +62,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: raw_ip6.c,v 1.148 2016/07/15 07:40:09 ozaki-r Exp $");
__KERNEL_RCSID(0, "$NetBSD: raw_ip6.c,v 1.149 2016/08/01 03:15:31 ozaki-r Exp $");
#ifdef _KERNEL_OPT
#include "opt_ipsec.h"
@ -671,8 +671,9 @@ rip6_bind(struct socket *so, struct sockaddr *nam, struct lwp *l)
{
struct in6pcb *in6p = sotoin6pcb(so);
struct sockaddr_in6 *addr = (struct sockaddr_in6 *)nam;
struct ifaddr *ia = NULL;
struct ifaddr *ifa = NULL;
int error = 0;
int s;
KASSERT(solocked(so));
KASSERT(in6p != NULL);
@ -692,15 +693,24 @@ rip6_bind(struct socket *so, struct sockaddr *nam, struct lwp *l)
*/
if (IN6_IS_ADDR_V4MAPPED(&addr->sin6_addr))
return EADDRNOTAVAIL;
s = pserialize_read_enter();
if (!IN6_IS_ADDR_UNSPECIFIED(&addr->sin6_addr) &&
(ia = ifa_ifwithaddr(sin6tosa(addr))) == 0)
return EADDRNOTAVAIL;
if (ia && ifatoia6(ia)->ia6_flags &
(ifa = ifa_ifwithaddr(sin6tosa(addr))) == NULL) {
error = EADDRNOTAVAIL;
goto out;
}
if (ifa && (ifatoia6(ifa))->ia6_flags &
(IN6_IFF_ANYCAST|IN6_IFF_NOTREADY|
IN6_IFF_DETACHED|IN6_IFF_DEPRECATED))
return EADDRNOTAVAIL;
IN6_IFF_DETACHED|IN6_IFF_DEPRECATED)) {
error = EADDRNOTAVAIL;
goto out;
}
in6p->in6p_laddr = addr->sin6_addr;
return 0;
error = 0;
out:
pserialize_read_exit(s);
return error;
}
static int

View File

@ -1,5 +1,5 @@
/* $KAME: sctp6_usrreq.c,v 1.38 2005/08/24 08:08:56 suz Exp $ */
/* $NetBSD: sctp6_usrreq.c,v 1.7 2016/07/15 07:40:09 ozaki-r Exp $ */
/* $NetBSD: sctp6_usrreq.c,v 1.8 2016/08/01 03:15:31 ozaki-r Exp $ */
/*
* Copyright (c) 2001, 2002, 2003, 2004 Cisco Systems, Inc.
@ -33,7 +33,7 @@
* SUCH DAMAGE.
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: sctp6_usrreq.c,v 1.7 2016/07/15 07:40:09 ozaki-r Exp $");
__KERNEL_RCSID(0, "$NetBSD: sctp6_usrreq.c,v 1.8 2016/08/01 03:15:31 ozaki-r Exp $");
#ifdef _KERNEL_OPT
#include "opt_inet.h"
@ -1294,6 +1294,7 @@ static int
sctp6_purgeif(struct socket *so, struct ifnet *ifp)
{
struct ifaddr *ifa;
/* FIXME NOMPSAFE */
IFADDR_READER_FOREACH(ifa, ifp) {
if (ifa->ifa_addr->sa_family == PF_INET6) {
sctp_delete_ip_address(ifa);

View File

@ -1,4 +1,4 @@
/* $NetBSD: udp6_output.c,v 1.52 2016/06/21 10:25:27 ozaki-r Exp $ */
/* $NetBSD: udp6_output.c,v 1.53 2016/08/01 03:15:31 ozaki-r Exp $ */
/* $KAME: udp6_output.c,v 1.43 2001/10/15 09:19:52 itojun Exp $ */
/*
@ -62,7 +62,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: udp6_output.c,v 1.52 2016/06/21 10:25:27 ozaki-r Exp $");
__KERNEL_RCSID(0, "$NetBSD: udp6_output.c,v 1.53 2016/08/01 03:15:31 ozaki-r Exp $");
#ifdef _KERNEL_OPT
#include "opt_inet.h"
@ -227,6 +227,7 @@ udp6_output(struct in6pcb * const in6p, struct mbuf *m,
if (!IN6_IS_ADDR_V4MAPPED(faddr)) {
struct psref psref;
int bound = curlwp_bind();
laddr = in6_selectsrc(sin6, optp,
in6p->in6p_moptions,
@ -236,9 +237,11 @@ udp6_output(struct in6pcb * const in6p, struct mbuf *m,
(error = in6_setscope(&sin6->sin6_addr,
oifp, NULL))) {
if_put(oifp, &psref);
curlwp_bindx(bound);
goto release;
}
if_put(oifp, &psref);
curlwp_bindx(bound);
} else {
/*
* XXX: freebsd[34] does not have in_selectsrc, but
@ -247,15 +250,20 @@ udp6_output(struct in6pcb * const in6p, struct mbuf *m,
* never see this path.
*/
if (IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_laddr)) {
struct sockaddr_in *sinp, sin_dst;
struct sockaddr_in sin_dst;
struct in_addr ina;
struct in_ifaddr *ia4;
struct psref _psref;
int bound;
memcpy(&ina, &faddr->s6_addr[12], sizeof(ina));
sockaddr_in_init(&sin_dst, &ina, 0);
sinp = in_selectsrc(&sin_dst, &in6p->in6p_route,
bound = curlwp_bind();
ia4 = in_selectsrc(&sin_dst, &in6p->in6p_route,
in6p->in6p_socket->so_options, NULL,
&error);
if (sinp == NULL) {
&error, &_psref);
if (ia4 == NULL) {
curlwp_bindx(bound);
if (error == 0)
error = EADDRNOTAVAIL;
goto release;
@ -263,8 +271,10 @@ udp6_output(struct in6pcb * const in6p, struct mbuf *m,
memset(&laddr_mapped, 0, sizeof(laddr_mapped));
laddr_mapped.s6_addr16[5] = 0xffff; /* ugly */
memcpy(&laddr_mapped.s6_addr[12],
&sinp->sin_addr,
sizeof(sinp->sin_addr));
&IA_SIN(ia4)->sin_addr,
sizeof(IA_SIN(ia4)->sin_addr));
ia4_release(ia4, &_psref);
curlwp_bindx(bound);
laddr = &laddr_mapped;
} else
{