Modify most routines returning 'struct ifaddr *' to return references
rather than pointers, requiring callers to properly dispose of those references. The following routines now return references: ifaddr_byindex ifa_ifwithaddr ifa_ifwithbroadaddr ifa_ifwithdstaddr ifa_ifwithnet ifaof_ifpforaddr ifa_ifwithroute ifa_ifwithroute_fib rt_getifa rt_getifa_fib IFP_TO_IA ip_rtaddr in6_ifawithifp in6ifa_ifpforlinklocal in6ifa_ifpwithaddr in6_ifadd carp_iamatch6 ip6_getdstifaddr Remove unused macro which didn't have required referencing: IFP_TO_IA6 This closes many small races in which changes to interface or address lists while an ifaddr was in use could lead to use of freed memory (etc). In a few cases, add missing if_addr_list locking required to safely acquire references. Because of a lack of deep copying support, we accept a race in which an in6_ifaddr pointed to by mbuf tags and extracted with ip6_getdstifaddr() doesn't hold a reference while in transmit. Once we have mbuf tag deep copy support, this can be fixed. Reviewed by: bz Obtained from: Apple, Inc. (portions) MFC after: 6 weeks (portions)
This commit is contained in:
parent
abcd328be6
commit
8c0fec805f
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=194760
@ -129,13 +129,16 @@ int rdma_translate_ip(struct sockaddr *addr, struct rdma_dev_addr *dev_addr)
|
||||
struct ifaddr *ifa;
|
||||
struct sockaddr_in *sin = (struct sockaddr_in *)addr;
|
||||
uint16_t port = sin->sin_port;
|
||||
int ret;
|
||||
|
||||
sin->sin_port = 0;
|
||||
ifa = ifa_ifwithaddr(addr);
|
||||
sin->sin_port = port;
|
||||
if (!ifa)
|
||||
return (EADDRNOTAVAIL);
|
||||
return rdma_copy_addr(dev_addr, ifa->ifa_ifp, NULL);
|
||||
ret = rdma_copy_addr(dev_addr, ifa->ifa_ifp, NULL);
|
||||
ifa_free(ifa);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
static void queue_req(struct addr_req *req)
|
||||
|
@ -1337,6 +1337,7 @@ static int iw_conn_req_handler(struct iw_cm_id *cm_id,
|
||||
}
|
||||
dev = ifa->ifa_ifp;
|
||||
ret = rdma_copy_addr(&conn_id->id.route.addr.dev_addr, dev, NULL);
|
||||
ifa_free(ifa);
|
||||
if (ret) {
|
||||
cma_enable_remove(conn_id);
|
||||
rdma_destroy_id(new_cm_id);
|
||||
|
43
sys/net/if.c
43
sys/net/if.c
@ -48,6 +48,7 @@
|
||||
#include <sys/socket.h>
|
||||
#include <sys/socketvar.h>
|
||||
#include <sys/protosw.h>
|
||||
#include <sys/kdb.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/lock.h>
|
||||
#include <sys/refcount.h>
|
||||
@ -261,6 +262,8 @@ ifaddr_byindex(u_short idx)
|
||||
|
||||
IFNET_RLOCK();
|
||||
ifa = ifnet_byindex_locked(idx)->if_addr;
|
||||
if (ifa != NULL)
|
||||
ifa_ref(ifa);
|
||||
IFNET_RUNLOCK();
|
||||
return (ifa);
|
||||
}
|
||||
@ -1464,7 +1467,7 @@ ifa_free(struct ifaddr *ifa)
|
||||
*/
|
||||
/*ARGSUSED*/
|
||||
static struct ifaddr *
|
||||
ifa_ifwithaddr_internal(struct sockaddr *addr)
|
||||
ifa_ifwithaddr_internal(struct sockaddr *addr, int getref)
|
||||
{
|
||||
INIT_VNET_NET(curvnet);
|
||||
struct ifnet *ifp;
|
||||
@ -1477,6 +1480,8 @@ ifa_ifwithaddr_internal(struct sockaddr *addr)
|
||||
if (ifa->ifa_addr->sa_family != addr->sa_family)
|
||||
continue;
|
||||
if (sa_equal(addr, ifa->ifa_addr)) {
|
||||
if (getref)
|
||||
ifa_ref(ifa);
|
||||
IF_ADDR_UNLOCK(ifp);
|
||||
goto done;
|
||||
}
|
||||
@ -1485,6 +1490,8 @@ ifa_ifwithaddr_internal(struct sockaddr *addr)
|
||||
ifa->ifa_broadaddr &&
|
||||
ifa->ifa_broadaddr->sa_len != 0 &&
|
||||
sa_equal(ifa->ifa_broadaddr, addr)) {
|
||||
if (getref)
|
||||
ifa_ref(ifa);
|
||||
IF_ADDR_UNLOCK(ifp);
|
||||
goto done;
|
||||
}
|
||||
@ -1501,14 +1508,14 @@ struct ifaddr *
|
||||
ifa_ifwithaddr(struct sockaddr *addr)
|
||||
{
|
||||
|
||||
return (ifa_ifwithaddr_internal(addr));
|
||||
return (ifa_ifwithaddr_internal(addr, 1));
|
||||
}
|
||||
|
||||
int
|
||||
ifa_ifwithaddr_check(struct sockaddr *addr)
|
||||
{
|
||||
|
||||
return (ifa_ifwithaddr_internal(addr) != NULL);
|
||||
return (ifa_ifwithaddr_internal(addr, 0) != NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1532,6 +1539,7 @@ ifa_ifwithbroadaddr(struct sockaddr *addr)
|
||||
ifa->ifa_broadaddr &&
|
||||
ifa->ifa_broadaddr->sa_len != 0 &&
|
||||
sa_equal(ifa->ifa_broadaddr, addr)) {
|
||||
ifa_ref(ifa);
|
||||
IF_ADDR_UNLOCK(ifp);
|
||||
goto done;
|
||||
}
|
||||
@ -1565,6 +1573,7 @@ ifa_ifwithdstaddr(struct sockaddr *addr)
|
||||
continue;
|
||||
if (ifa->ifa_dstaddr != NULL &&
|
||||
sa_equal(addr, ifa->ifa_dstaddr)) {
|
||||
ifa_ref(ifa);
|
||||
IF_ADDR_UNLOCK(ifp);
|
||||
goto done;
|
||||
}
|
||||
@ -1587,7 +1596,7 @@ ifa_ifwithnet(struct sockaddr *addr)
|
||||
INIT_VNET_NET(curvnet);
|
||||
struct ifnet *ifp;
|
||||
struct ifaddr *ifa;
|
||||
struct ifaddr *ifa_maybe = (struct ifaddr *) 0;
|
||||
struct ifaddr *ifa_maybe = NULL;
|
||||
u_int af = addr->sa_family;
|
||||
char *addr_data = addr->sa_data, *cplim;
|
||||
|
||||
@ -1602,8 +1611,10 @@ ifa_ifwithnet(struct sockaddr *addr)
|
||||
}
|
||||
|
||||
/*
|
||||
* Scan though each interface, looking for ones that have
|
||||
* addresses in this address family.
|
||||
* Scan though each interface, looking for ones that have addresses
|
||||
* in this address family. Maintain a reference on ifa_maybe once
|
||||
* we find one, as we release the IF_ADDR_LOCK() that kept it stable
|
||||
* when we move onto the next interface.
|
||||
*/
|
||||
IFNET_RLOCK();
|
||||
TAILQ_FOREACH(ifp, &V_ifnet, if_link) {
|
||||
@ -1624,6 +1635,7 @@ next: continue;
|
||||
*/
|
||||
if (ifa->ifa_dstaddr != NULL &&
|
||||
sa_equal(addr, ifa->ifa_dstaddr)) {
|
||||
ifa_ref(ifa);
|
||||
IF_ADDR_UNLOCK(ifp);
|
||||
goto done;
|
||||
}
|
||||
@ -1634,6 +1646,7 @@ next: continue;
|
||||
*/
|
||||
if (ifa->ifa_claim_addr) {
|
||||
if ((*ifa->ifa_claim_addr)(ifa, addr)) {
|
||||
ifa_ref(ifa);
|
||||
IF_ADDR_UNLOCK(ifp);
|
||||
goto done;
|
||||
}
|
||||
@ -1664,17 +1677,24 @@ next: continue;
|
||||
* before continuing to search
|
||||
* for an even better one.
|
||||
*/
|
||||
if (ifa_maybe == 0 ||
|
||||
if (ifa_maybe == NULL ||
|
||||
rn_refines((caddr_t)ifa->ifa_netmask,
|
||||
(caddr_t)ifa_maybe->ifa_netmask))
|
||||
(caddr_t)ifa_maybe->ifa_netmask)) {
|
||||
if (ifa_maybe != NULL)
|
||||
ifa_free(ifa_maybe);
|
||||
ifa_maybe = ifa;
|
||||
ifa_ref(ifa_maybe);
|
||||
}
|
||||
}
|
||||
}
|
||||
IF_ADDR_UNLOCK(ifp);
|
||||
}
|
||||
ifa = ifa_maybe;
|
||||
ifa_maybe = NULL;
|
||||
done:
|
||||
IFNET_RUNLOCK();
|
||||
if (ifa_maybe != NULL)
|
||||
ifa_free(ifa_maybe);
|
||||
return (ifa);
|
||||
}
|
||||
|
||||
@ -1688,7 +1708,7 @@ ifaof_ifpforaddr(struct sockaddr *addr, struct ifnet *ifp)
|
||||
struct ifaddr *ifa;
|
||||
char *cp, *cp2, *cp3;
|
||||
char *cplim;
|
||||
struct ifaddr *ifa_maybe = 0;
|
||||
struct ifaddr *ifa_maybe = NULL;
|
||||
u_int af = addr->sa_family;
|
||||
|
||||
if (af >= AF_MAX)
|
||||
@ -1697,7 +1717,7 @@ ifaof_ifpforaddr(struct sockaddr *addr, struct ifnet *ifp)
|
||||
TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
|
||||
if (ifa->ifa_addr->sa_family != af)
|
||||
continue;
|
||||
if (ifa_maybe == 0)
|
||||
if (ifa_maybe == NULL)
|
||||
ifa_maybe = ifa;
|
||||
if (ifa->ifa_netmask == 0) {
|
||||
if (sa_equal(addr, ifa->ifa_addr) ||
|
||||
@ -1723,6 +1743,8 @@ ifaof_ifpforaddr(struct sockaddr *addr, struct ifnet *ifp)
|
||||
}
|
||||
ifa = ifa_maybe;
|
||||
done:
|
||||
if (ifa != NULL)
|
||||
ifa_ref(ifa);
|
||||
IF_ADDR_UNLOCK(ifp);
|
||||
return (ifa);
|
||||
}
|
||||
@ -1748,7 +1770,6 @@ link_rtrequest(int cmd, struct rtentry *rt, struct rt_addrinfo *info)
|
||||
return;
|
||||
ifa = ifaof_ifpforaddr(dst, ifp);
|
||||
if (ifa) {
|
||||
ifa_ref(ifa); /* XXX */
|
||||
oifa = rt->rt_ifa;
|
||||
rt->rt_ifa = ifa;
|
||||
ifa_free(oifa);
|
||||
|
@ -559,6 +559,7 @@ rtredirect_fib(struct sockaddr *dst,
|
||||
struct ifaddr *ifa;
|
||||
struct radix_node_head *rnh;
|
||||
|
||||
ifa = NULL;
|
||||
rnh = rt_tables_get_rnh(fibnum, dst->sa_family);
|
||||
if (rnh == NULL) {
|
||||
error = EAFNOSUPPORT;
|
||||
@ -664,6 +665,8 @@ rtredirect_fib(struct sockaddr *dst,
|
||||
info.rti_info[RTAX_NETMASK] = netmask;
|
||||
info.rti_info[RTAX_AUTHOR] = src;
|
||||
rt_missmsg(RTM_REDIRECT, &info, flags, error);
|
||||
if (ifa != NULL)
|
||||
ifa_free(ifa);
|
||||
}
|
||||
|
||||
int
|
||||
@ -693,6 +696,9 @@ rtioctl_fib(u_long req, caddr_t data, u_int fibnum)
|
||||
#endif /* INET */
|
||||
}
|
||||
|
||||
/*
|
||||
* For both ifa_ifwithroute() routines, 'ifa' is returned referenced.
|
||||
*/
|
||||
struct ifaddr *
|
||||
ifa_ifwithroute(int flags, struct sockaddr *dst, struct sockaddr *gateway)
|
||||
{
|
||||
@ -749,11 +755,13 @@ ifa_ifwithroute_fib(int flags, struct sockaddr *dst, struct sockaddr *gateway,
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (!not_found && rt->rt_ifa != NULL) {
|
||||
ifa = rt->rt_ifa;
|
||||
ifa_ref(ifa);
|
||||
}
|
||||
RT_REMREF(rt);
|
||||
RT_UNLOCK(rt);
|
||||
if (not_found)
|
||||
return (NULL);
|
||||
if ((ifa = rt->rt_ifa) == NULL)
|
||||
if (not_found || ifa == NULL)
|
||||
return (NULL);
|
||||
}
|
||||
if (ifa->ifa_addr->sa_family != dst->sa_family) {
|
||||
@ -761,6 +769,8 @@ ifa_ifwithroute_fib(int flags, struct sockaddr *dst, struct sockaddr *gateway,
|
||||
ifa = ifaof_ifpforaddr(dst, ifa->ifa_ifp);
|
||||
if (ifa == NULL)
|
||||
ifa = oifa;
|
||||
else
|
||||
ifa_free(oifa);
|
||||
}
|
||||
return (ifa);
|
||||
}
|
||||
@ -819,6 +829,10 @@ rt_getifa(struct rt_addrinfo *info)
|
||||
return (rt_getifa_fib(info, 0));
|
||||
}
|
||||
|
||||
/*
|
||||
* Look up rt_addrinfo for a specific fib. Note that if rti_ifa is defined,
|
||||
* it will be referenced so the caller must free it.
|
||||
*/
|
||||
int
|
||||
rt_getifa_fib(struct rt_addrinfo *info, u_int fibnum)
|
||||
{
|
||||
@ -831,8 +845,10 @@ rt_getifa_fib(struct rt_addrinfo *info, u_int fibnum)
|
||||
*/
|
||||
if (info->rti_ifp == NULL && ifpaddr != NULL &&
|
||||
ifpaddr->sa_family == AF_LINK &&
|
||||
(ifa = ifa_ifwithnet(ifpaddr)) != NULL)
|
||||
(ifa = ifa_ifwithnet(ifpaddr)) != NULL) {
|
||||
info->rti_ifp = ifa->ifa_ifp;
|
||||
ifa_free(ifa);
|
||||
}
|
||||
if (info->rti_ifa == NULL && ifaaddr != NULL)
|
||||
info->rti_ifa = ifa_ifwithaddr(ifaaddr);
|
||||
if (info->rti_ifa == NULL) {
|
||||
@ -1123,12 +1139,19 @@ rtrequest1_fib(int req, struct rt_addrinfo *info, struct rtentry **ret_nrt,
|
||||
(gateway->sa_family != AF_UNSPEC) && (gateway->sa_family != AF_LINK))
|
||||
senderr(EINVAL);
|
||||
|
||||
if (info->rti_ifa == NULL && (error = rt_getifa_fib(info, fibnum)))
|
||||
senderr(error);
|
||||
if (info->rti_ifa == NULL) {
|
||||
error = rt_getifa_fib(info, fibnum);
|
||||
if (error)
|
||||
senderr(error);
|
||||
} else
|
||||
ifa_ref(info->rti_ifa);
|
||||
ifa = info->rti_ifa;
|
||||
rt = uma_zalloc(V_rtzone, M_NOWAIT | M_ZERO);
|
||||
if (rt == NULL)
|
||||
if (rt == NULL) {
|
||||
if (ifa != NULL)
|
||||
ifa_free(ifa);
|
||||
senderr(ENOBUFS);
|
||||
}
|
||||
RT_LOCK_INIT(rt);
|
||||
rt->rt_flags = RTF_UP | flags;
|
||||
rt->rt_fibnum = fibnum;
|
||||
@ -1139,6 +1162,8 @@ rtrequest1_fib(int req, struct rt_addrinfo *info, struct rtentry **ret_nrt,
|
||||
RT_LOCK(rt);
|
||||
if ((error = rt_setgate(rt, dst, gateway)) != 0) {
|
||||
RT_LOCK_DESTROY(rt);
|
||||
if (ifa != NULL)
|
||||
ifa_free(ifa);
|
||||
uma_zfree(V_rtzone, rt);
|
||||
senderr(error);
|
||||
}
|
||||
@ -1157,11 +1182,10 @@ rtrequest1_fib(int req, struct rt_addrinfo *info, struct rtentry **ret_nrt,
|
||||
bcopy(dst, ndst, dst->sa_len);
|
||||
|
||||
/*
|
||||
* Note that we now have a reference to the ifa.
|
||||
* We use the ifa reference returned by rt_getifa_fib().
|
||||
* This moved from below so that rnh->rnh_addaddr() can
|
||||
* examine the ifa and ifa->ifa_ifp if it so desires.
|
||||
*/
|
||||
ifa_ref(ifa);
|
||||
rt->rt_ifa = ifa;
|
||||
rt->rt_ifp = ifa->ifa_ifp;
|
||||
rt->rt_rmx.rmx_weight = 1;
|
||||
|
@ -683,6 +683,13 @@ route_output(struct mbuf *m, struct socket *so)
|
||||
RT_UNLOCK(rt);
|
||||
RADIX_NODE_HEAD_LOCK(rnh);
|
||||
error = rt_getifa_fib(&info, rt->rt_fibnum);
|
||||
/*
|
||||
* XXXRW: Really we should release this
|
||||
* reference later, but this maintains
|
||||
* historical behavior.
|
||||
*/
|
||||
if (info.rti_ifa != NULL)
|
||||
ifa_free(info.rti_ifa);
|
||||
RADIX_NODE_HEAD_UNLOCK(rnh);
|
||||
if (error != 0)
|
||||
senderr(error);
|
||||
|
@ -301,6 +301,7 @@ ieee80211_ifattach(struct ieee80211com *ic,
|
||||
sdl->sdl_type = IFT_ETHER; /* XXX IFT_IEEE80211? */
|
||||
sdl->sdl_alen = IEEE80211_ADDR_LEN;
|
||||
IEEE80211_ADDR_COPY(LLADDR(sdl), macaddr);
|
||||
ifa_free(ifa);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1233,8 +1233,10 @@ igmp_input_v1_report(struct ifnet *ifp, /*const*/ struct ip *ip,
|
||||
*/
|
||||
if (V_igmp_recvifkludge && in_nullhost(ip->ip_src)) {
|
||||
IFP_TO_IA(ifp, ia);
|
||||
if (ia != NULL)
|
||||
if (ia != NULL) {
|
||||
ip->ip_src.s_addr = htonl(ia->ia_subnet);
|
||||
ifa_free(&ia->ia_ifa);
|
||||
}
|
||||
}
|
||||
|
||||
CTR3(KTR_IGMPV3, "process v1 report %s on ifp %p(%s)",
|
||||
@ -1326,16 +1328,23 @@ igmp_input_v2_report(struct ifnet *ifp, /*const*/ struct ip *ip,
|
||||
* group.
|
||||
*/
|
||||
IFP_TO_IA(ifp, ia);
|
||||
if (ia != NULL && in_hosteq(ip->ip_src, IA_SIN(ia)->sin_addr))
|
||||
if (ia != NULL && in_hosteq(ip->ip_src, IA_SIN(ia)->sin_addr)) {
|
||||
ifa_free(&ia->ia_ifa);
|
||||
return (0);
|
||||
}
|
||||
|
||||
IGMPSTAT_INC(igps_rcv_reports);
|
||||
|
||||
if (ifp->if_flags & IFF_LOOPBACK)
|
||||
if (ifp->if_flags & IFF_LOOPBACK) {
|
||||
if (ia != NULL)
|
||||
ifa_free(&ia->ia_ifa);
|
||||
return (0);
|
||||
}
|
||||
|
||||
if (!IN_MULTICAST(ntohl(igmp->igmp_group.s_addr)) ||
|
||||
!in_hosteq(igmp->igmp_group, ip->ip_dst)) {
|
||||
if (ia != NULL)
|
||||
ifa_free(&ia->ia_ifa);
|
||||
IGMPSTAT_INC(igps_rcv_badreports);
|
||||
return (EINVAL);
|
||||
}
|
||||
@ -1351,6 +1360,8 @@ igmp_input_v2_report(struct ifnet *ifp, /*const*/ struct ip *ip,
|
||||
if (ia != NULL)
|
||||
ip->ip_src.s_addr = htonl(ia->ia_subnet);
|
||||
}
|
||||
if (ia != NULL)
|
||||
ifa_free(&ia->ia_ifa);
|
||||
|
||||
CTR3(KTR_IGMPV3, "process v2 report %s on ifp %p(%s)",
|
||||
inet_ntoa(igmp->igmp_group), ifp, ifp->if_xname);
|
||||
@ -3534,8 +3545,10 @@ igmp_v3_encap_report(struct ifnet *ifp, struct mbuf *m)
|
||||
struct in_ifaddr *ia;
|
||||
|
||||
IFP_TO_IA(ifp, ia);
|
||||
if (ia != NULL)
|
||||
if (ia != NULL) {
|
||||
ip->ip_src = ia->ia_addr.sin_addr;
|
||||
ifa_free(&ia->ia_ifa);
|
||||
}
|
||||
}
|
||||
|
||||
ip->ip_dst.s_addr = htonl(INADDR_ALLRPTS_GROUP);
|
||||
|
115
sys/netinet/in.c
115
sys/netinet/in.c
@ -219,7 +219,6 @@ in_control(struct socket *so, u_long cmd, caddr_t data, struct ifnet *ifp,
|
||||
register struct ifaddr *ifa;
|
||||
struct in_addr allhosts_addr;
|
||||
struct in_addr dst;
|
||||
struct in_ifaddr *oia;
|
||||
struct in_ifinfo *ii;
|
||||
struct in_aliasreq *ifra = (struct in_aliasreq *)data;
|
||||
struct sockaddr_in oldaddr;
|
||||
@ -323,8 +322,10 @@ in_control(struct socket *so, u_long cmd, caddr_t data, struct ifnet *ifp,
|
||||
break;
|
||||
}
|
||||
}
|
||||
IF_ADDR_LOCK(ifp);
|
||||
if (ia != NULL)
|
||||
ifa_ref(&ia->ia_ifa);
|
||||
if (ia == NULL) {
|
||||
IF_ADDR_LOCK(ifp);
|
||||
TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
|
||||
iap = ifatoia(ifa);
|
||||
if (iap->ia_addr.sin_family == AF_INET) {
|
||||
@ -336,6 +337,9 @@ in_control(struct socket *so, u_long cmd, caddr_t data, struct ifnet *ifp,
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (ia != NULL)
|
||||
ifa_ref(&ia->ia_ifa);
|
||||
IF_ADDR_UNLOCK(ifp);
|
||||
}
|
||||
if (ia == NULL)
|
||||
iaIsFirst = 1;
|
||||
@ -345,23 +349,29 @@ in_control(struct socket *so, u_long cmd, caddr_t data, struct ifnet *ifp,
|
||||
case SIOCAIFADDR:
|
||||
case SIOCDIFADDR:
|
||||
if (ifra->ifra_addr.sin_family == AF_INET) {
|
||||
struct in_ifaddr *oia;
|
||||
|
||||
for (oia = ia; ia; ia = TAILQ_NEXT(ia, ia_link)) {
|
||||
if (ia->ia_ifp == ifp &&
|
||||
ia->ia_addr.sin_addr.s_addr ==
|
||||
ifra->ifra_addr.sin_addr.s_addr)
|
||||
break;
|
||||
}
|
||||
if (ia != NULL && ia != oia)
|
||||
ifa_ref(&ia->ia_ifa);
|
||||
if (oia != NULL && ia != oia)
|
||||
ifa_free(&oia->ia_ifa);
|
||||
if ((ifp->if_flags & IFF_POINTOPOINT)
|
||||
&& (cmd == SIOCAIFADDR)
|
||||
&& (ifra->ifra_dstaddr.sin_addr.s_addr
|
||||
== INADDR_ANY)) {
|
||||
error = EDESTADDRREQ;
|
||||
goto out_unlock;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
if (cmd == SIOCDIFADDR && ia == NULL) {
|
||||
error = EADDRNOTAVAIL;
|
||||
goto out_unlock;
|
||||
goto out;
|
||||
}
|
||||
/* FALLTHROUGH */
|
||||
case SIOCSIFADDR:
|
||||
@ -373,7 +383,7 @@ in_control(struct socket *so, u_long cmd, caddr_t data, struct ifnet *ifp,
|
||||
M_ZERO);
|
||||
if (ia == NULL) {
|
||||
error = ENOBUFS;
|
||||
goto out_unlock;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ifa = &ia->ia_ifa;
|
||||
@ -390,7 +400,11 @@ in_control(struct socket *so, u_long cmd, caddr_t data, struct ifnet *ifp,
|
||||
}
|
||||
ia->ia_ifp = ifp;
|
||||
|
||||
ifa_ref(ifa); /* if_addrhead */
|
||||
IF_ADDR_LOCK(ifp);
|
||||
TAILQ_INSERT_TAIL(&ifp->if_addrhead, ifa, ifa_link);
|
||||
IF_ADDR_UNLOCK(ifp);
|
||||
ifa_ref(ifa); /* in_ifaddrhead */
|
||||
s = splnet();
|
||||
TAILQ_INSERT_TAIL(&V_in_ifaddrhead, ia, ia_link);
|
||||
splx(s);
|
||||
@ -405,64 +419,53 @@ in_control(struct socket *so, u_long cmd, caddr_t data, struct ifnet *ifp,
|
||||
case SIOCGIFBRDADDR:
|
||||
if (ia == NULL) {
|
||||
error = EADDRNOTAVAIL;
|
||||
goto out_unlock;
|
||||
goto out;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Most paths in this switch return directly or via out_unlock. Only
|
||||
* paths that remove the address break in order to hit common removal
|
||||
* code.
|
||||
*
|
||||
* XXXRW: We enter the switch with IF_ADDR_LOCK() held, but leave
|
||||
* without it. This is a bug.
|
||||
* Most paths in this switch return directly or via out. Only paths
|
||||
* that remove the address break in order to hit common removal code.
|
||||
*/
|
||||
IF_ADDR_LOCK_ASSERT(ifp);
|
||||
switch (cmd) {
|
||||
case SIOCGIFADDR:
|
||||
*((struct sockaddr_in *)&ifr->ifr_addr) = ia->ia_addr;
|
||||
goto out_unlock;
|
||||
goto out;
|
||||
|
||||
case SIOCGIFBRDADDR:
|
||||
if ((ifp->if_flags & IFF_BROADCAST) == 0) {
|
||||
error = EINVAL;
|
||||
goto out_unlock;
|
||||
goto out;
|
||||
}
|
||||
*((struct sockaddr_in *)&ifr->ifr_dstaddr) = ia->ia_broadaddr;
|
||||
goto out_unlock;
|
||||
goto out;
|
||||
|
||||
case SIOCGIFDSTADDR:
|
||||
if ((ifp->if_flags & IFF_POINTOPOINT) == 0) {
|
||||
error = EINVAL;
|
||||
goto out_unlock;
|
||||
goto out;
|
||||
}
|
||||
*((struct sockaddr_in *)&ifr->ifr_dstaddr) = ia->ia_dstaddr;
|
||||
goto out_unlock;
|
||||
goto out;
|
||||
|
||||
case SIOCGIFNETMASK:
|
||||
*((struct sockaddr_in *)&ifr->ifr_addr) = ia->ia_sockmask;
|
||||
goto out_unlock;
|
||||
goto out;
|
||||
|
||||
case SIOCSIFDSTADDR:
|
||||
if ((ifp->if_flags & IFF_POINTOPOINT) == 0) {
|
||||
error = EINVAL;
|
||||
goto out_unlock;
|
||||
goto out;
|
||||
}
|
||||
oldaddr = ia->ia_dstaddr;
|
||||
ia->ia_dstaddr = *(struct sockaddr_in *)&ifr->ifr_dstaddr;
|
||||
IF_ADDR_UNLOCK(ifp);
|
||||
|
||||
/*
|
||||
* XXXRW: Locks dropped for if_ioctl and rtinit, but ia is
|
||||
* still being used.
|
||||
*/
|
||||
if (ifp->if_ioctl != NULL) {
|
||||
error = (*ifp->if_ioctl)(ifp, SIOCSIFDSTADDR,
|
||||
(caddr_t)ia);
|
||||
if (error) {
|
||||
ia->ia_dstaddr = oldaddr;
|
||||
return (error);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
if (ia->ia_flags & IFA_ROUTE) {
|
||||
@ -472,23 +475,17 @@ in_control(struct socket *so, u_long cmd, caddr_t data, struct ifnet *ifp,
|
||||
(struct sockaddr *)&ia->ia_dstaddr;
|
||||
rtinit(&(ia->ia_ifa), (int)RTM_ADD, RTF_HOST|RTF_UP);
|
||||
}
|
||||
return (0);
|
||||
goto out;
|
||||
|
||||
case SIOCSIFBRDADDR:
|
||||
if ((ifp->if_flags & IFF_BROADCAST) == 0) {
|
||||
error = EINVAL;
|
||||
goto out_unlock;
|
||||
goto out;
|
||||
}
|
||||
ia->ia_broadaddr = *(struct sockaddr_in *)&ifr->ifr_broadaddr;
|
||||
goto out_unlock;
|
||||
goto out;
|
||||
|
||||
case SIOCSIFADDR:
|
||||
IF_ADDR_UNLOCK(ifp);
|
||||
|
||||
/*
|
||||
* XXXRW: Locks dropped for in_ifinit and in_joingroup, but ia
|
||||
* is still being used.
|
||||
*/
|
||||
error = in_ifinit(ifp, ia,
|
||||
(struct sockaddr_in *) &ifr->ifr_addr, 1);
|
||||
if (error != 0 && iaIsNew)
|
||||
@ -502,12 +499,13 @@ in_control(struct socket *so, u_long cmd, caddr_t data, struct ifnet *ifp,
|
||||
}
|
||||
EVENTHANDLER_INVOKE(ifaddr_event, ifp);
|
||||
}
|
||||
return (0);
|
||||
error = 0;
|
||||
goto out;
|
||||
|
||||
case SIOCSIFNETMASK:
|
||||
ia->ia_sockmask.sin_addr = ifra->ifra_addr.sin_addr;
|
||||
ia->ia_subnetmask = ntohl(ia->ia_sockmask.sin_addr.s_addr);
|
||||
goto out_unlock;
|
||||
goto out;
|
||||
|
||||
case SIOCAIFADDR:
|
||||
maskIsNew = 0;
|
||||
@ -521,12 +519,6 @@ in_control(struct socket *so, u_long cmd, caddr_t data, struct ifnet *ifp,
|
||||
ia->ia_addr.sin_addr.s_addr)
|
||||
hostIsNew = 0;
|
||||
}
|
||||
IF_ADDR_UNLOCK(ifp);
|
||||
|
||||
/*
|
||||
* XXXRW: Locks dropped for in_ifscrub and in_ifinit, but ia
|
||||
* is still being used.
|
||||
*/
|
||||
if (ifra->ifra_mask.sin_len) {
|
||||
in_ifscrub(ifp, ia);
|
||||
ia->ia_sockmask = ifra->ifra_mask;
|
||||
@ -545,7 +537,7 @@ in_control(struct socket *so, u_long cmd, caddr_t data, struct ifnet *ifp,
|
||||
(hostIsNew || maskIsNew))
|
||||
error = in_ifinit(ifp, ia, &ifra->ifra_addr, 0);
|
||||
if (error != 0 && iaIsNew)
|
||||
break;
|
||||
goto out;
|
||||
|
||||
if ((ifp->if_flags & IFF_BROADCAST) &&
|
||||
(ifra->ifra_broadaddr.sin_family == AF_INET))
|
||||
@ -559,15 +551,10 @@ in_control(struct socket *so, u_long cmd, caddr_t data, struct ifnet *ifp,
|
||||
}
|
||||
EVENTHANDLER_INVOKE(ifaddr_event, ifp);
|
||||
}
|
||||
return (error);
|
||||
goto out;
|
||||
|
||||
case SIOCDIFADDR:
|
||||
IF_ADDR_UNLOCK(ifp);
|
||||
|
||||
/*
|
||||
* XXXRW: Locks dropped for in_ifscrub and in_ifadown, but ia
|
||||
* is still being used.
|
||||
*
|
||||
* in_ifscrub kills the interface route.
|
||||
*/
|
||||
in_ifscrub(ifp, ia);
|
||||
@ -587,25 +574,25 @@ in_control(struct socket *so, u_long cmd, caddr_t data, struct ifnet *ifp,
|
||||
panic("in_control: unsupported ioctl");
|
||||
}
|
||||
|
||||
/*
|
||||
* XXXRW: In a more ideal world, we would still be holding
|
||||
* IF_ADDR_LOCK here.
|
||||
*/
|
||||
IF_ADDR_LOCK(ifp);
|
||||
TAILQ_REMOVE(&ifp->if_addrhead, &ia->ia_ifa, ifa_link);
|
||||
IF_ADDR_UNLOCK(ifp);
|
||||
ifa_free(&ia->ia_ifa); /* if_addrhead */
|
||||
s = splnet();
|
||||
TAILQ_REMOVE(&V_in_ifaddrhead, ia, ia_link);
|
||||
ifa_free(&ia->ia_ifa); /* in_ifaddrhead */
|
||||
if (ia->ia_addr.sin_family == AF_INET) {
|
||||
struct in_ifaddr *if_ia;
|
||||
|
||||
LIST_REMOVE(ia, ia_hash);
|
||||
/*
|
||||
* If this is the last IPv4 address configured on this
|
||||
* interface, leave the all-hosts group.
|
||||
* No state-change report need be transmitted.
|
||||
*/
|
||||
oia = NULL;
|
||||
IFP_TO_IA(ifp, oia);
|
||||
if (oia == NULL) {
|
||||
if_ia = NULL;
|
||||
IFP_TO_IA(ifp, if_ia);
|
||||
if (if_ia == NULL) {
|
||||
ii = ((struct in_ifinfo *)ifp->if_afdata[AF_INET]);
|
||||
IN_MULTI_LOCK();
|
||||
if (ii->ii_allhosts) {
|
||||
@ -614,15 +601,13 @@ in_control(struct socket *so, u_long cmd, caddr_t data, struct ifnet *ifp,
|
||||
ii->ii_allhosts = NULL;
|
||||
}
|
||||
IN_MULTI_UNLOCK();
|
||||
}
|
||||
} else
|
||||
ifa_free(&if_ia->ia_ifa);
|
||||
}
|
||||
ifa_free(&ia->ia_ifa);
|
||||
splx(s);
|
||||
|
||||
return (error);
|
||||
|
||||
out_unlock:
|
||||
IF_ADDR_UNLOCK(ifp);
|
||||
out:
|
||||
if (ia != NULL)
|
||||
ifa_free(&ia->ia_ifa);
|
||||
return (error);
|
||||
}
|
||||
|
||||
|
@ -1722,6 +1722,7 @@ inp_getmoptions(struct inpcb *inp, struct sockopt *sopt)
|
||||
if (ia != NULL) {
|
||||
mreqn.imr_address =
|
||||
IA_SIN(ia)->sin_addr;
|
||||
ifa_free(&ia->ia_ifa);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -549,7 +549,6 @@ static int
|
||||
in_pcbladdr(struct inpcb *inp, struct in_addr *faddr, struct in_addr *laddr,
|
||||
struct ucred *cred)
|
||||
{
|
||||
struct in_ifaddr *ia;
|
||||
struct ifaddr *ifa;
|
||||
struct sockaddr *sa;
|
||||
struct sockaddr_in *sin;
|
||||
@ -559,7 +558,6 @@ in_pcbladdr(struct inpcb *inp, struct in_addr *faddr, struct in_addr *laddr,
|
||||
KASSERT(laddr != NULL, ("%s: laddr NULL", __func__));
|
||||
|
||||
error = 0;
|
||||
ia = NULL;
|
||||
bzero(&sro, sizeof(sro));
|
||||
|
||||
sin = (struct sockaddr_in *)&sro.ro_dst;
|
||||
@ -585,6 +583,7 @@ in_pcbladdr(struct inpcb *inp, struct in_addr *faddr, struct in_addr *laddr,
|
||||
* the source address from.
|
||||
*/
|
||||
if (sro.ro_rt == NULL || sro.ro_rt->rt_ifp == NULL) {
|
||||
struct in_ifaddr *ia;
|
||||
struct ifnet *ifp;
|
||||
|
||||
ia = ifatoia(ifa_ifwithdstaddr((struct sockaddr *)sin));
|
||||
@ -597,10 +596,12 @@ in_pcbladdr(struct inpcb *inp, struct in_addr *faddr, struct in_addr *laddr,
|
||||
|
||||
if (cred == NULL || !prison_flag(cred, PR_IP4)) {
|
||||
laddr->s_addr = ia->ia_addr.sin_addr.s_addr;
|
||||
ifa_free(&ia->ia_ifa);
|
||||
goto done;
|
||||
}
|
||||
|
||||
ifp = ia->ia_ifp;
|
||||
ifa_free(&ia->ia_ifa);
|
||||
ia = NULL;
|
||||
IF_ADDR_LOCK(ifp);
|
||||
TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
|
||||
@ -636,6 +637,7 @@ in_pcbladdr(struct inpcb *inp, struct in_addr *faddr, struct in_addr *laddr,
|
||||
* 3. as a last resort return the 'default' jail address.
|
||||
*/
|
||||
if ((sro.ro_rt->rt_ifp->if_flags & IFF_LOOPBACK) == 0) {
|
||||
struct in_ifaddr *ia;
|
||||
struct ifnet *ifp;
|
||||
|
||||
/* If not jailed, use the default returned. */
|
||||
@ -658,10 +660,10 @@ in_pcbladdr(struct inpcb *inp, struct in_addr *faddr, struct in_addr *laddr,
|
||||
* 2. Check if we have any address on the outgoing interface
|
||||
* belonging to this jail.
|
||||
*/
|
||||
ia = NULL;
|
||||
ifp = sro.ro_rt->rt_ifp;
|
||||
IF_ADDR_LOCK(ifp);
|
||||
TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
|
||||
|
||||
sa = ifa->ifa_addr;
|
||||
if (sa->sa_family != AF_INET)
|
||||
continue;
|
||||
@ -694,6 +696,7 @@ in_pcbladdr(struct inpcb *inp, struct in_addr *faddr, struct in_addr *laddr,
|
||||
*/
|
||||
if ((sro.ro_rt->rt_ifp->if_flags & IFF_LOOPBACK) != 0) {
|
||||
struct sockaddr_in sain;
|
||||
struct in_ifaddr *ia;
|
||||
|
||||
bzero(&sain, sizeof(struct sockaddr_in));
|
||||
sain.sin_family = AF_INET;
|
||||
@ -710,6 +713,7 @@ in_pcbladdr(struct inpcb *inp, struct in_addr *faddr, struct in_addr *laddr,
|
||||
goto done;
|
||||
}
|
||||
laddr->s_addr = ia->ia_addr.sin_addr.s_addr;
|
||||
ifa_free(&ia->ia_ifa);
|
||||
goto done;
|
||||
}
|
||||
|
||||
@ -718,6 +722,7 @@ in_pcbladdr(struct inpcb *inp, struct in_addr *faddr, struct in_addr *laddr,
|
||||
struct ifnet *ifp;
|
||||
|
||||
ifp = ia->ia_ifp;
|
||||
ifa_free(&ia->ia_ifa);
|
||||
ia = NULL;
|
||||
IF_ADDR_LOCK(ifp);
|
||||
TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
|
||||
|
@ -146,14 +146,16 @@ do { \
|
||||
* Macro for finding the internet address structure (in_ifaddr) corresponding
|
||||
* to a given interface (ifnet structure).
|
||||
*/
|
||||
#define IFP_TO_IA(ifp, ia) \
|
||||
/* struct ifnet *ifp; */ \
|
||||
/* struct in_ifaddr *ia; */ \
|
||||
{ \
|
||||
for ((ia) = TAILQ_FIRST(&V_in_ifaddrhead); \
|
||||
(ia) != NULL && (ia)->ia_ifp != (ifp); \
|
||||
(ia) = TAILQ_NEXT((ia), ia_link)) \
|
||||
continue; \
|
||||
#define IFP_TO_IA(ifp, ia) \
|
||||
/* struct ifnet *ifp; */ \
|
||||
/* struct in_ifaddr *ia; */ \
|
||||
{ \
|
||||
for ((ia) = TAILQ_FIRST(&V_in_ifaddrhead); \
|
||||
(ia) != NULL && (ia)->ia_ifp != (ifp); \
|
||||
(ia) = TAILQ_NEXT((ia), ia_link)) \
|
||||
continue; \
|
||||
if ((ia) != NULL) \
|
||||
ifa_ref(&(ia)->ia_ifa); \
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -1239,6 +1239,7 @@ carp_iamatch6(void *v, struct in6_addr *taddr)
|
||||
(SC2IFP(vh)->if_flags & IFF_UP) &&
|
||||
(SC2IFP(vh)->if_drv_flags & IFF_DRV_RUNNING) &&
|
||||
vh->sc_state == MASTER) {
|
||||
ifa_ref(ifa);
|
||||
IF_ADDR_UNLOCK(SC2IFP(vh));
|
||||
CARP_UNLOCK(cif);
|
||||
return (ifa);
|
||||
|
@ -464,6 +464,7 @@ div_output(struct socket *so, struct mbuf *m, struct sockaddr_in *sin,
|
||||
goto cantsend;
|
||||
}
|
||||
m->m_pkthdr.rcvif = ifa->ifa_ifp;
|
||||
ifa_free(ifa);
|
||||
}
|
||||
#ifdef MAC
|
||||
mac_socket_create_mbuf(so, m);
|
||||
|
@ -536,10 +536,12 @@ icmp_input(struct mbuf *m, int off)
|
||||
}
|
||||
ia = (struct in_ifaddr *)ifaof_ifpforaddr(
|
||||
(struct sockaddr *)&icmpdst, m->m_pkthdr.rcvif);
|
||||
if (ia == 0)
|
||||
if (ia == NULL)
|
||||
break;
|
||||
if (ia->ia_ifp == 0)
|
||||
if (ia->ia_ifp == NULL) {
|
||||
ifa_free(&ia->ia_ifa);
|
||||
break;
|
||||
}
|
||||
icp->icmp_type = ICMP_MASKREPLY;
|
||||
if (V_icmpmaskfake == 0)
|
||||
icp->icmp_mask = ia->ia_sockmask.sin_addr.s_addr;
|
||||
@ -551,6 +553,7 @@ icmp_input(struct mbuf *m, int off)
|
||||
else if (ia->ia_ifp->if_flags & IFF_POINTOPOINT)
|
||||
ip->ip_src = satosin(&ia->ia_dstaddr)->sin_addr;
|
||||
}
|
||||
ifa_free(&ia->ia_ifa);
|
||||
reflect:
|
||||
ip->ip_len += hlen; /* since ip_input deducts this */
|
||||
ICMPSTAT_INC(icps_reflect);
|
||||
@ -748,6 +751,7 @@ icmp_reflect(struct mbuf *m)
|
||||
goto done;
|
||||
}
|
||||
t = IA_SIN(ia)->sin_addr;
|
||||
ifa_free(&ia->ia_ifa);
|
||||
match:
|
||||
#ifdef MAC
|
||||
mac_netinet_icmp_replyinplace(m);
|
||||
|
@ -622,8 +622,10 @@ ip_input(struct mbuf *m)
|
||||
* enabled.
|
||||
*/
|
||||
if (IA_SIN(ia)->sin_addr.s_addr == ip->ip_dst.s_addr &&
|
||||
(!checkif || ia->ia_ifp == ifp))
|
||||
(!checkif || ia->ia_ifp == ifp)) {
|
||||
ifa_ref(&ia->ia_ifa);
|
||||
goto ours;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Check for broadcast addresses.
|
||||
@ -641,15 +643,18 @@ ip_input(struct mbuf *m)
|
||||
ia = ifatoia(ifa);
|
||||
if (satosin(&ia->ia_broadaddr)->sin_addr.s_addr ==
|
||||
ip->ip_dst.s_addr) {
|
||||
ifa_ref(ifa);
|
||||
IF_ADDR_UNLOCK(ifp);
|
||||
goto ours;
|
||||
}
|
||||
if (ia->ia_netbroadcast.s_addr == ip->ip_dst.s_addr) {
|
||||
ifa_ref(ifa);
|
||||
IF_ADDR_UNLOCK(ifp);
|
||||
goto ours;
|
||||
}
|
||||
#ifdef BOOTP_COMPAT
|
||||
if (IA_SIN(ia)->sin_addr.s_addr == INADDR_ANY) {
|
||||
ifa_ref(ifa);
|
||||
IF_ADDR_UNLOCK(ifp);
|
||||
goto ours;
|
||||
}
|
||||
@ -742,6 +747,7 @@ ip_input(struct mbuf *m)
|
||||
if (ia != NULL) {
|
||||
ia->ia_ifa.if_ipackets++;
|
||||
ia->ia_ifa.if_ibytes += m->m_pkthdr.len;
|
||||
ifa_free(&ia->ia_ifa);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1335,8 +1341,8 @@ ipproto_unregister(u_char ipproto)
|
||||
}
|
||||
|
||||
/*
|
||||
* Given address of next destination (final or next hop),
|
||||
* return internet address info of interface to be used to get there.
|
||||
* Given address of next destination (final or next hop), return (referenced)
|
||||
* internet address info of interface to be used to get there.
|
||||
*/
|
||||
struct in_ifaddr *
|
||||
ip_rtaddr(struct in_addr dst, u_int fibnum)
|
||||
@ -1356,6 +1362,7 @@ ip_rtaddr(struct in_addr dst, u_int fibnum)
|
||||
return (NULL);
|
||||
|
||||
ifa = ifatoia(sro.ro_rt->rt_ifa);
|
||||
ifa_ref(&ifa->ia_ifa);
|
||||
RTFREE(sro.ro_rt);
|
||||
return (ifa);
|
||||
}
|
||||
@ -1530,11 +1537,16 @@ ip_forward(struct mbuf *m, int srcrt)
|
||||
else {
|
||||
if (mcopy)
|
||||
m_freem(mcopy);
|
||||
if (ia != NULL)
|
||||
ifa_free(&ia->ia_ifa);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (mcopy == NULL)
|
||||
if (mcopy == NULL) {
|
||||
if (ia != NULL)
|
||||
ifa_free(&ia->ia_ifa);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (error) {
|
||||
|
||||
@ -1592,6 +1604,8 @@ ip_forward(struct mbuf *m, int srcrt)
|
||||
*/
|
||||
if (V_ip_sendsourcequench == 0) {
|
||||
m_freem(mcopy);
|
||||
if (ia != NULL)
|
||||
ifa_free(&ia->ia_ifa);
|
||||
return;
|
||||
} else {
|
||||
type = ICMP_SOURCEQUENCH;
|
||||
@ -1601,8 +1615,12 @@ ip_forward(struct mbuf *m, int srcrt)
|
||||
|
||||
case EACCES: /* ipfw denied packet */
|
||||
m_freem(mcopy);
|
||||
if (ia != NULL)
|
||||
ifa_free(&ia->ia_ifa);
|
||||
return;
|
||||
}
|
||||
if (ia != NULL)
|
||||
ifa_free(&ia->ia_ifa);
|
||||
icmp_error(mcopy, type, code, dest.s_addr, mtu);
|
||||
}
|
||||
|
||||
|
@ -883,6 +883,7 @@ add_vif(struct vifctl *vifcp)
|
||||
return EADDRNOTAVAIL;
|
||||
}
|
||||
ifp = ifa->ifa_ifp;
|
||||
ifa_free(ifa);
|
||||
}
|
||||
|
||||
if ((vifcp->vifc_flags & VIFF_TUNNEL) != 0) {
|
||||
|
@ -164,9 +164,8 @@ ip_dooptions(struct mbuf *m, int pass)
|
||||
goto bad;
|
||||
}
|
||||
ipaddr.sin_addr = ip->ip_dst;
|
||||
ia = (struct in_ifaddr *)
|
||||
ifa_ifwithaddr((struct sockaddr *)&ipaddr);
|
||||
if (ia == NULL) {
|
||||
if (ifa_ifwithaddr_check((struct sockaddr *)&ipaddr)
|
||||
== 0) {
|
||||
if (opt == IPOPT_SSRR) {
|
||||
type = ICMP_UNREACH;
|
||||
code = ICMP_UNREACH_SRCFAIL;
|
||||
@ -245,6 +244,7 @@ ip_dooptions(struct mbuf *m, int pass)
|
||||
ip->ip_dst = ipaddr.sin_addr;
|
||||
(void)memcpy(cp + off, &(IA_SIN(ia)->sin_addr),
|
||||
sizeof(struct in_addr));
|
||||
ifa_free(&ia->ia_ifa);
|
||||
cp[IPOPT_OFFSET] += sizeof(struct in_addr);
|
||||
/*
|
||||
* Let ip_intr's mcast routing check handle mcast pkts
|
||||
@ -286,6 +286,7 @@ ip_dooptions(struct mbuf *m, int pass)
|
||||
}
|
||||
(void)memcpy(cp + off, &(IA_SIN(ia)->sin_addr),
|
||||
sizeof(struct in_addr));
|
||||
ifa_free(&ia->ia_ifa);
|
||||
cp[IPOPT_OFFSET] += sizeof(struct in_addr);
|
||||
break;
|
||||
|
||||
@ -331,6 +332,7 @@ ip_dooptions(struct mbuf *m, int pass)
|
||||
continue;
|
||||
(void)memcpy(sin, &IA_SIN(ia)->sin_addr,
|
||||
sizeof(struct in_addr));
|
||||
ifa_free(&ia->ia_ifa);
|
||||
cp[IPOPT_OFFSET] += sizeof(struct in_addr);
|
||||
off += sizeof(struct in_addr);
|
||||
break;
|
||||
|
@ -288,6 +288,7 @@ ip_output(struct mbuf *m, struct mbuf *opt, struct route *ro, int flags,
|
||||
goto bad;
|
||||
}
|
||||
ia = ifatoia(ro->ro_rt->rt_ifa);
|
||||
ifa_ref(&ia->ia_ifa);
|
||||
ifp = ro->ro_rt->rt_ifp;
|
||||
ro->ro_rt->rt_rmx.rmx_pksent++;
|
||||
if (ro->ro_rt->rt_flags & RTF_GATEWAY)
|
||||
@ -667,6 +668,8 @@ ip_output(struct mbuf *m, struct mbuf *opt, struct route *ro, int flags,
|
||||
if (ro == &iproute && ro->ro_rt && !nortfree) {
|
||||
RTFREE(ro->ro_rt);
|
||||
}
|
||||
if (ia != NULL)
|
||||
ifa_free(&ia->ia_ifa);
|
||||
return (error);
|
||||
bad:
|
||||
m_freem(m);
|
||||
|
@ -285,6 +285,7 @@ tcp6_input(struct mbuf **mp, int *offp, int proto)
|
||||
if (ia6 && (ia6->ia6_flags & IN6_IFF_ANYCAST)) {
|
||||
struct ip6_hdr *ip6;
|
||||
|
||||
ifa_free(&ia6->ia_ifa);
|
||||
ip6 = mtod(m, struct ip6_hdr *);
|
||||
icmp6_error(m, ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_ADDR,
|
||||
(caddr_t)&ip6->ip6_dst - (caddr_t)ip6);
|
||||
@ -939,8 +940,10 @@ tcp_input(struct mbuf *m, int off0)
|
||||
if (isipv6 && !V_ip6_use_deprecated) {
|
||||
struct in6_ifaddr *ia6;
|
||||
|
||||
if ((ia6 = ip6_getdstifaddr(m)) &&
|
||||
ia6 = ip6_getdstifaddr(m);
|
||||
if (ia6 != NULL &&
|
||||
(ia6->ia6_flags & IN6_IFF_DEPRECATED)) {
|
||||
ifa_free(&ia6->ia_ifa);
|
||||
if ((s = tcp_log_addrs(&inc, th, NULL, NULL)))
|
||||
log(LOG_DEBUG, "%s; %s: Listen socket: "
|
||||
"Connection attempt to deprecated "
|
||||
@ -949,6 +952,7 @@ tcp_input(struct mbuf *m, int off0)
|
||||
rstreason = BANDLIM_RST_OPENPORT;
|
||||
goto dropwithreset;
|
||||
}
|
||||
ifa_free(&ia6->ia_ifa);
|
||||
}
|
||||
#endif
|
||||
/*
|
||||
|
@ -185,8 +185,10 @@ frag6_input(struct mbuf **mp, int *offp, int proto)
|
||||
dstifp = NULL;
|
||||
#ifdef IN6_IFSTAT_STRICT
|
||||
/* find the destination interface of the packet. */
|
||||
if ((ia = ip6_getdstifaddr(m)) != NULL)
|
||||
if ((ia = ip6_getdstifaddr(m)) != NULL) {
|
||||
dstifp = ia->ia_ifp;
|
||||
ifa_free(&ia->ia_ifa);
|
||||
}
|
||||
#else
|
||||
/* we are violating the spec, this is not the destination interface */
|
||||
if ((m->m_flags & M_PKTHDR) != 0)
|
||||
|
@ -1244,11 +1244,13 @@ ni6_input(struct mbuf *m, int off)
|
||||
|
||||
if ((ia6->ia6_flags & IN6_IFF_TEMPORARY) &&
|
||||
!(V_icmp6_nodeinfo & ICMP6_NODEINFO_TMPADDROK)) {
|
||||
ifa_free(&ia6->ia_ifa);
|
||||
nd6log((LOG_DEBUG, "ni6_input: ignore node info to "
|
||||
"a temporary address in %s:%d",
|
||||
__FILE__, __LINE__));
|
||||
goto bad;
|
||||
}
|
||||
ifa_free(&ia6->ia_ifa);
|
||||
}
|
||||
|
||||
/* validate query Subject field. */
|
||||
@ -2074,7 +2076,7 @@ icmp6_reflect(struct mbuf *m, size_t off)
|
||||
INIT_VNET_INET6(curvnet);
|
||||
struct ip6_hdr *ip6;
|
||||
struct icmp6_hdr *icmp6;
|
||||
struct in6_ifaddr *ia;
|
||||
struct in6_ifaddr *ia = NULL;
|
||||
int plen;
|
||||
int type, code;
|
||||
struct ifnet *outif = NULL;
|
||||
@ -2220,9 +2222,13 @@ icmp6_reflect(struct mbuf *m, size_t off)
|
||||
if (outif)
|
||||
icmp6_ifoutstat_inc(outif, type, code);
|
||||
|
||||
if (ia != NULL)
|
||||
ifa_free(&ia->ia_ifa);
|
||||
return;
|
||||
|
||||
bad:
|
||||
if (ia != NULL)
|
||||
ifa_free(&ia->ia_ifa);
|
||||
m_freem(m);
|
||||
return;
|
||||
}
|
||||
@ -2541,6 +2547,8 @@ icmp6_redirect_output(struct mbuf *m0, struct rtentry *rt)
|
||||
IN6_IFF_ANYCAST)) == NULL)
|
||||
goto fail;
|
||||
ifp_ll6 = &ia->ia_addr.sin6_addr;
|
||||
/* XXXRW: reference released prematurely. */
|
||||
ifa_free(&ia->ia_ifa);
|
||||
}
|
||||
|
||||
/* get ip6 linklocal address for the router. */
|
||||
|
@ -321,8 +321,6 @@ in6_control(struct socket *so, u_long cmd, caddr_t data,
|
||||
break;
|
||||
}
|
||||
if (sa6 && sa6->sin6_family == AF_INET6) {
|
||||
int error = 0;
|
||||
|
||||
if (sa6->sin6_scope_id != 0)
|
||||
error = sa6_embedscope(sa6, 0);
|
||||
else
|
||||
@ -345,7 +343,8 @@ in6_control(struct socket *so, u_long cmd, caddr_t data,
|
||||
* on a single interface, SIOCSIFxxx ioctls are deprecated.
|
||||
*/
|
||||
/* we decided to obsolete this command (20000704) */
|
||||
return (EINVAL);
|
||||
error = EINVAL;
|
||||
goto out;
|
||||
|
||||
case SIOCDIFADDR_IN6:
|
||||
/*
|
||||
@ -355,8 +354,10 @@ in6_control(struct socket *so, u_long cmd, caddr_t data,
|
||||
* 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 */
|
||||
case SIOCAIFADDR_IN6:
|
||||
/*
|
||||
@ -364,16 +365,17 @@ in6_control(struct socket *so, u_long cmd, caddr_t data,
|
||||
* 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 out;
|
||||
}
|
||||
|
||||
if (td != NULL) {
|
||||
error = priv_check(td, (cmd == SIOCDIFADDR_IN6) ?
|
||||
PRIV_NET_DELIFADDR : PRIV_NET_ADDIFADDR);
|
||||
if (error)
|
||||
return (error);
|
||||
goto out;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case SIOCGIFADDR_IN6:
|
||||
@ -384,9 +386,12 @@ in6_control(struct socket *so, u_long cmd, caddr_t data,
|
||||
case SIOCGIFDSTADDR_IN6:
|
||||
case SIOCGIFALIFETIME_IN6:
|
||||
/* must think again about its semantics */
|
||||
if (ia == NULL)
|
||||
return (EADDRNOTAVAIL);
|
||||
if (ia == NULL) {
|
||||
error = EADDRNOTAVAIL;
|
||||
goto out;
|
||||
}
|
||||
break;
|
||||
|
||||
case SIOCSIFALIFETIME_IN6:
|
||||
{
|
||||
struct in6_addrlifetime *lt;
|
||||
@ -394,42 +399,47 @@ in6_control(struct socket *so, u_long cmd, caddr_t data,
|
||||
if (td != NULL) {
|
||||
error = priv_check(td, PRIV_NETINET_ALIFETIME6);
|
||||
if (error)
|
||||
return (error);
|
||||
goto out;
|
||||
}
|
||||
if (ia == NULL) {
|
||||
error = EADDRNOTAVAIL;
|
||||
goto out;
|
||||
}
|
||||
if (ia == NULL)
|
||||
return (EADDRNOTAVAIL);
|
||||
/* sanity for overflow - beware unsigned */
|
||||
lt = &ifr->ifr_ifru.ifru_lifetime;
|
||||
if (lt->ia6t_vltime != ND6_INFINITE_LIFETIME &&
|
||||
lt->ia6t_vltime + time_second < time_second) {
|
||||
return EINVAL;
|
||||
error = EINVAL;
|
||||
goto out;
|
||||
}
|
||||
if (lt->ia6t_pltime != ND6_INFINITE_LIFETIME &&
|
||||
lt->ia6t_pltime + time_second < time_second) {
|
||||
return EINVAL;
|
||||
error = EINVAL;
|
||||
goto out;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
switch (cmd) {
|
||||
|
||||
case SIOCGIFADDR_IN6:
|
||||
ifr->ifr_addr = ia->ia_addr;
|
||||
if ((error = sa6_recoverscope(&ifr->ifr_addr)) != 0)
|
||||
return (error);
|
||||
goto out;
|
||||
break;
|
||||
|
||||
case SIOCGIFDSTADDR_IN6:
|
||||
if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
|
||||
return (EINVAL);
|
||||
if ((ifp->if_flags & IFF_POINTOPOINT) == 0) {
|
||||
error = EINVAL;
|
||||
goto out;
|
||||
}
|
||||
/*
|
||||
* 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);
|
||||
goto out;
|
||||
break;
|
||||
|
||||
case SIOCGIFNETMASK_IN6:
|
||||
@ -441,8 +451,10 @@ in6_control(struct socket *so, u_long cmd, caddr_t data,
|
||||
break;
|
||||
|
||||
case SIOCGIFSTAT_IN6:
|
||||
if (ifp == NULL)
|
||||
return EINVAL;
|
||||
if (ifp == NULL) {
|
||||
error = EINVAL;
|
||||
goto out;
|
||||
}
|
||||
bzero(&ifr->ifr_ifru.ifru_stat,
|
||||
sizeof(ifr->ifr_ifru.ifru_stat));
|
||||
ifr->ifr_ifru.ifru_stat =
|
||||
@ -450,8 +462,10 @@ in6_control(struct socket *so, u_long cmd, caddr_t data,
|
||||
break;
|
||||
|
||||
case SIOCGIFSTAT_ICMP6:
|
||||
if (ifp == NULL)
|
||||
return EINVAL;
|
||||
if (ifp == NULL) {
|
||||
error = EINVAL;
|
||||
goto out;
|
||||
}
|
||||
bzero(&ifr->ifr_ifru.ifru_icmp6stat,
|
||||
sizeof(ifr->ifr_ifru.ifru_icmp6stat));
|
||||
ifr->ifr_ifru.ifru_icmp6stat =
|
||||
@ -515,7 +529,7 @@ in6_control(struct socket *so, u_long cmd, caddr_t data,
|
||||
|
||||
case SIOCAIFADDR_IN6:
|
||||
{
|
||||
int i, error = 0;
|
||||
int i;
|
||||
struct nd_prefixctl pr0;
|
||||
struct nd_prefix *pr;
|
||||
|
||||
@ -524,7 +538,9 @@ in6_control(struct socket *so, u_long cmd, caddr_t data,
|
||||
* and link it to the list.
|
||||
*/
|
||||
if ((error = in6_update_ifa(ifp, ifra, ia, 0)) != 0)
|
||||
return (error);
|
||||
goto out;
|
||||
if (ia != NULL)
|
||||
ifa_free(&ia->ia_ifa);
|
||||
if ((ia = in6ifa_ifpwithaddr(ifp, &ifra->ifra_addr.sin6_addr))
|
||||
== NULL) {
|
||||
/*
|
||||
@ -578,11 +594,12 @@ in6_control(struct socket *so, u_long cmd, caddr_t data,
|
||||
* interface route.
|
||||
*/
|
||||
if ((error = nd6_prelist_add(&pr0, NULL, &pr)) != 0)
|
||||
return (error);
|
||||
goto out;
|
||||
if (pr == NULL) {
|
||||
log(LOG_ERR, "nd6_prelist_add succeeded but "
|
||||
"no prefix\n");
|
||||
return (EINVAL); /* XXX panic here? */
|
||||
error = EINVAL;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
@ -640,12 +657,19 @@ in6_control(struct socket *so, u_long cmd, caddr_t data,
|
||||
}
|
||||
|
||||
default:
|
||||
if (ifp == NULL || ifp->if_ioctl == 0)
|
||||
return (EOPNOTSUPP);
|
||||
return ((*ifp->if_ioctl)(ifp, cmd, data));
|
||||
if (ifp == NULL || ifp->if_ioctl == 0) {
|
||||
error = EOPNOTSUPP;
|
||||
goto out;
|
||||
}
|
||||
error = (*ifp->if_ioctl)(ifp, cmd, data);
|
||||
goto out;
|
||||
}
|
||||
|
||||
return (0);
|
||||
error = 0;
|
||||
out:
|
||||
if (ia != NULL)
|
||||
ifa_free(&ia->ia_ifa);
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -811,6 +835,7 @@ in6_update_ifa(struct ifnet *ifp, struct in6_aliasreq *ifra,
|
||||
} else
|
||||
V_in6_ifaddr = ia;
|
||||
|
||||
ifa_ref(&ia->ia_ifa); /* if_addrhead */
|
||||
IF_ADDR_LOCK(ifp);
|
||||
TAILQ_INSERT_TAIL(&ifp->if_addrhead, &ia->ia_ifa, ifa_link);
|
||||
IF_ADDR_UNLOCK(ifp);
|
||||
@ -1085,8 +1110,7 @@ in6_update_ifa(struct ifnet *ifp, struct in6_aliasreq *ifra,
|
||||
* XXX It may be of use, if we can administratively
|
||||
* disable DAD.
|
||||
*/
|
||||
if (hostIsNew && in6if_do_dad(ifp) &&
|
||||
((ifra->ifra_flags & IN6_IFF_NODAD) == 0) &&
|
||||
if (in6if_do_dad(ifp) && ((ifra->ifra_flags & IN6_IFF_NODAD) == 0) &&
|
||||
(ia->ia6_flags & IN6_IFF_TENTATIVE))
|
||||
{
|
||||
int mindelay, maxdelay;
|
||||
@ -1120,6 +1144,8 @@ in6_update_ifa(struct ifnet *ifp, struct in6_aliasreq *ifra,
|
||||
nd6_dad_start((struct ifaddr *)ia, delay);
|
||||
}
|
||||
|
||||
KASSERT(hostIsNew, ("in6_update_ifa: !hostIsNew"));
|
||||
ifa_free(&ia->ia_ifa);
|
||||
return (error);
|
||||
|
||||
unlink:
|
||||
@ -1127,11 +1153,15 @@ in6_update_ifa(struct ifnet *ifp, struct in6_aliasreq *ifra,
|
||||
* XXX: if a change of an existing address failed, keep the entry
|
||||
* anyway.
|
||||
*/
|
||||
if (hostIsNew)
|
||||
if (hostIsNew) {
|
||||
ifa_free(&ia->ia_ifa);
|
||||
in6_unlink_ifa(ia, ifp);
|
||||
}
|
||||
return (error);
|
||||
|
||||
cleanup:
|
||||
KASSERT(hostIsNew, ("in6_update_ifa: cleanup: !hostIsNew"));
|
||||
ifa_free(&ia->ia_ifa);
|
||||
in6_purgeaddr(&ia->ia_ifa);
|
||||
return error;
|
||||
}
|
||||
@ -1155,6 +1185,7 @@ in6_purgeaddr(struct ifaddr *ifa)
|
||||
* link-local and node-local all-nodes multicast
|
||||
* address routes
|
||||
*/
|
||||
IF_ADDR_LOCK(ifp);
|
||||
TAILQ_FOREACH_SAFE(ifa0, &ifp->if_addrhead, ifa_link, nifa) {
|
||||
if ((ifa0->ifa_addr->sa_family != AF_INET6) ||
|
||||
memcmp(&satosin6(ifa0->ifa_addr)->sin6_addr,
|
||||
@ -1164,6 +1195,9 @@ in6_purgeaddr(struct ifaddr *ifa)
|
||||
else
|
||||
break;
|
||||
}
|
||||
if (ifa0 != NULL)
|
||||
ifa_ref(ifa0);
|
||||
IF_ADDR_UNLOCK(ifp);
|
||||
|
||||
/* stop DAD processing */
|
||||
nd6_dad_stop(ifa);
|
||||
@ -1331,6 +1365,8 @@ in6_purgeaddr(struct ifaddr *ifa)
|
||||
return;
|
||||
ia->ia_flags &= ~IFA_ROUTE;
|
||||
}
|
||||
if (ifa0 != NULL)
|
||||
ifa_free(ifa0);
|
||||
|
||||
in6_unlink_ifa(ia, ifp);
|
||||
}
|
||||
@ -1345,6 +1381,7 @@ in6_unlink_ifa(struct in6_ifaddr *ia, struct ifnet *ifp)
|
||||
IF_ADDR_LOCK(ifp);
|
||||
TAILQ_REMOVE(&ifp->if_addrhead, &ia->ia_ifa, ifa_link);
|
||||
IF_ADDR_UNLOCK(ifp);
|
||||
ifa_free(&ia->ia_ifa); /* if_addrhead */
|
||||
|
||||
oia = ia;
|
||||
if (oia == (ia = V_in6_ifaddr))
|
||||
@ -1481,6 +1518,7 @@ in6_lifaddr_ioctl(struct socket *so, u_long cmd, caddr_t data,
|
||||
struct in6_addr *hostid = NULL;
|
||||
int prefixlen;
|
||||
|
||||
ifa = NULL;
|
||||
if ((iflr->flags & IFLR_PREFIX) != 0) {
|
||||
struct sockaddr_in6 *sin6;
|
||||
|
||||
@ -1532,6 +1570,8 @@ in6_lifaddr_ioctl(struct socket *so, u_long cmd, caddr_t data,
|
||||
hostid->s6_addr32[3];
|
||||
}
|
||||
}
|
||||
if (ifa != NULL)
|
||||
ifa_free(ifa);
|
||||
|
||||
ifra.ifra_prefixmask.sin6_len = sizeof(struct sockaddr_in6);
|
||||
in6_prefixlen2mask(&ifra.ifra_prefixmask.sin6_addr, prefixlen);
|
||||
@ -1779,6 +1819,7 @@ in6_ifinit(struct ifnet *ifp, struct in6_ifaddr *ia,
|
||||
|
||||
/*
|
||||
* Find an IPv6 interface link-local address specific to an interface.
|
||||
* ifaddr is returned referenced.
|
||||
*/
|
||||
struct in6_ifaddr *
|
||||
in6ifa_ifpforlinklocal(struct ifnet *ifp, int ignoreflags)
|
||||
@ -1793,6 +1834,7 @@ in6ifa_ifpforlinklocal(struct ifnet *ifp, int ignoreflags)
|
||||
if ((((struct in6_ifaddr *)ifa)->ia6_flags &
|
||||
ignoreflags) != 0)
|
||||
continue;
|
||||
ifa_ref(ifa);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -1804,6 +1846,7 @@ in6ifa_ifpforlinklocal(struct ifnet *ifp, int ignoreflags)
|
||||
|
||||
/*
|
||||
* find the internet address corresponding to a given interface and address.
|
||||
* ifaddr is returned referenced.
|
||||
*/
|
||||
struct in6_ifaddr *
|
||||
in6ifa_ifpwithaddr(struct ifnet *ifp, struct in6_addr *addr)
|
||||
@ -1814,8 +1857,10 @@ in6ifa_ifpwithaddr(struct ifnet *ifp, struct in6_addr *addr)
|
||||
TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
|
||||
if (ifa->ifa_addr->sa_family != AF_INET6)
|
||||
continue;
|
||||
if (IN6_ARE_ADDR_EQUAL(addr, IFA_IN6(ifa)))
|
||||
if (IN6_ARE_ADDR_EQUAL(addr, IFA_IN6(ifa))) {
|
||||
ifa_ref(ifa);
|
||||
break;
|
||||
}
|
||||
}
|
||||
IF_ADDR_UNLOCK(ifp);
|
||||
|
||||
@ -2049,6 +2094,7 @@ in6_ifawithifp(struct ifnet *ifp, struct in6_addr *dst)
|
||||
}
|
||||
}
|
||||
if (besta) {
|
||||
ifa_ref(&besta->ia_ifa);
|
||||
IF_ADDR_UNLOCK(ifp);
|
||||
return (besta);
|
||||
}
|
||||
@ -2068,6 +2114,8 @@ in6_ifawithifp(struct ifnet *ifp, struct in6_addr *dst)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ifa != NULL)
|
||||
ifa_ref(ifa);
|
||||
IF_ADDR_UNLOCK(ifp);
|
||||
return (struct in6_ifaddr *)ifa;
|
||||
}
|
||||
@ -2319,6 +2367,7 @@ in6_lltable_rtcheck(struct ifnet *ifp, const struct sockaddr *l3addr)
|
||||
/* XXX ifaof_ifpforaddr should take a const param */
|
||||
ifa = ifaof_ifpforaddr(__DECONST(struct sockaddr *, l3addr), ifp);
|
||||
if (ifa != NULL) {
|
||||
ifa_free(ifa);
|
||||
if (rt != NULL)
|
||||
RTFREE_LOCKED(rt);
|
||||
return 0;
|
||||
|
@ -253,6 +253,7 @@ in6_get_hw_ifid(struct ifnet *ifp, struct in6_addr *in6)
|
||||
return -1;
|
||||
|
||||
found:
|
||||
IF_ADDR_LOCK_ASSERT(ifp);
|
||||
addr = LLADDR(sdl);
|
||||
addrlen = sdl->sdl_alen;
|
||||
|
||||
@ -513,6 +514,7 @@ in6_ifattach_linklocal(struct ifnet *ifp, struct ifnet *altifp)
|
||||
/* NOTREACHED */
|
||||
}
|
||||
#endif
|
||||
ifa_free(&ia->ia_ifa);
|
||||
|
||||
/*
|
||||
* Make the link-local prefix (fe80::%link/64) as on-link.
|
||||
@ -737,11 +739,15 @@ in6_ifattach(struct ifnet *ifp, struct ifnet *altifp)
|
||||
* XXX multiple loopback interface case.
|
||||
*/
|
||||
if ((ifp->if_flags & IFF_LOOPBACK) != 0) {
|
||||
struct ifaddr *ifa;
|
||||
|
||||
in6 = in6addr_loopback;
|
||||
if (in6ifa_ifpwithaddr(ifp, &in6) == NULL) {
|
||||
ifa = (struct ifaddr *)in6ifa_ifpwithaddr(ifp, &in6);
|
||||
if (ifa == NULL) {
|
||||
if (in6_ifattach_loopback(ifp) != 0)
|
||||
return;
|
||||
}
|
||||
} else
|
||||
ifa_free(ifa);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -755,7 +761,8 @@ in6_ifattach(struct ifnet *ifp, struct ifnet *altifp)
|
||||
} else {
|
||||
/* failed to assign linklocal address. bark? */
|
||||
}
|
||||
}
|
||||
} else
|
||||
ifa_free(&ia->ia_ifa);
|
||||
}
|
||||
|
||||
#ifdef IFT_STF /* XXX */
|
||||
|
@ -162,10 +162,11 @@ in6_pcbbind(register struct inpcb *inp, struct sockaddr *nam,
|
||||
if (so->so_options & SO_REUSEADDR)
|
||||
reuseport = SO_REUSEADDR|SO_REUSEPORT;
|
||||
} else if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
|
||||
struct ifaddr *ia;
|
||||
struct ifaddr *ifa;
|
||||
|
||||
sin6->sin6_port = 0; /* yech... */
|
||||
if ((ia = ifa_ifwithaddr((struct sockaddr *)sin6)) == NULL &&
|
||||
if ((ifa = ifa_ifwithaddr((struct sockaddr *)sin6)) ==
|
||||
NULL &&
|
||||
(inp->inp_flags & INP_BINDANY) == 0) {
|
||||
return (EADDRNOTAVAIL);
|
||||
}
|
||||
@ -176,11 +177,14 @@ in6_pcbbind(register struct inpcb *inp, struct sockaddr *nam,
|
||||
* We should allow to bind to a deprecated address, since
|
||||
* the application dares to use it.
|
||||
*/
|
||||
if (ia &&
|
||||
((struct in6_ifaddr *)ia)->ia6_flags &
|
||||
if (ifa != NULL &&
|
||||
((struct in6_ifaddr *)ifa)->ia6_flags &
|
||||
(IN6_IFF_ANYCAST|IN6_IFF_NOTREADY|IN6_IFF_DETACHED)) {
|
||||
ifa_free(ifa);
|
||||
return (EADDRNOTAVAIL);
|
||||
}
|
||||
if (ifa != NULL)
|
||||
ifa_free(ifa);
|
||||
}
|
||||
if (lport) {
|
||||
struct inpcb *t;
|
||||
|
@ -245,15 +245,26 @@ in6_selectsrc(struct sockaddr_in6 *dstsock, struct ip6_pktopts *opts,
|
||||
(inp->inp_flags & IN6P_IPV6_V6ONLY) != 0))) != 0)
|
||||
return (NULL);
|
||||
|
||||
ia6 = (struct in6_ifaddr *)ifa_ifwithaddr((struct sockaddr *)(&srcsock));
|
||||
ia6 = (struct in6_ifaddr *)ifa_ifwithaddr(
|
||||
(struct sockaddr *)&srcsock);
|
||||
if (ia6 == NULL ||
|
||||
(ia6->ia6_flags & (IN6_IFF_ANYCAST | IN6_IFF_NOTREADY))) {
|
||||
if (ia6 != NULL)
|
||||
ifa_free(&ia6->ia_ifa);
|
||||
*errorp = EADDRNOTAVAIL;
|
||||
return (NULL);
|
||||
}
|
||||
pi->ipi6_addr = srcsock.sin6_addr; /* XXX: this overrides pi */
|
||||
if (ifpp)
|
||||
*ifpp = ifp;
|
||||
|
||||
/*
|
||||
* XXXRW: This returns a pointer into a structure with no
|
||||
* refcount. in6_selectsrc() should return it to caller-
|
||||
* provided memory using call-by-reference rather than
|
||||
* returning pointers into other memory.
|
||||
*/
|
||||
ifa_free(&ia6->ia_ifa);
|
||||
return (&ia6->ia_addr.sin6_addr);
|
||||
}
|
||||
|
||||
|
@ -498,25 +498,6 @@ do { \
|
||||
|
||||
extern struct in6_addr zeroin6_addr;
|
||||
extern u_char inet6ctlerrmap[];
|
||||
|
||||
/*
|
||||
* Macro for finding the internet address structure (in6_ifaddr) corresponding
|
||||
* to a given interface (ifnet structure).
|
||||
*/
|
||||
|
||||
#define IFP_TO_IA6(ifp, ia) \
|
||||
/* struct ifnet *ifp; */ \
|
||||
/* struct in6_ifaddr *ia; */ \
|
||||
do { \
|
||||
struct ifaddr *ifa; \
|
||||
IF_ADDR_LOCK_ASSERT(ifp); \
|
||||
TAILQ_FOREACH(ifa, &(ifp)->if_addrhead, ifa_link) { \
|
||||
if (ifa->ifa_addr->sa_family == AF_INET6) \
|
||||
break; \
|
||||
} \
|
||||
(ia) = (struct in6_ifaddr *)ifa; \
|
||||
} while (/*CONSTCOND*/ 0)
|
||||
|
||||
#endif /* _KERNEL */
|
||||
|
||||
/*
|
||||
|
@ -724,6 +724,7 @@ ip6_input(struct mbuf *m)
|
||||
* to the upper layers.
|
||||
*/
|
||||
}
|
||||
ifa_free(&ia6->ia_ifa);
|
||||
}
|
||||
}
|
||||
|
||||
@ -919,6 +920,11 @@ ip6_input(struct mbuf *m)
|
||||
/*
|
||||
* set/grab in6_ifaddr correspond to IPv6 destination address.
|
||||
* XXX backward compatibility wrapper
|
||||
*
|
||||
* XXXRW: We should bump the refcount on ia6 before sticking it in the m_tag,
|
||||
* and then bump it when the tag is copied, and release it when the tag is
|
||||
* freed. Unfortunately, m_tags don't support deep copies (yet), so instead
|
||||
* we just bump the ia refcount when we receive it. This should be fixed.
|
||||
*/
|
||||
static struct ip6aux *
|
||||
ip6_setdstifaddr(struct mbuf *m, struct in6_ifaddr *ia6)
|
||||
@ -935,11 +941,14 @@ struct in6_ifaddr *
|
||||
ip6_getdstifaddr(struct mbuf *m)
|
||||
{
|
||||
struct ip6aux *ip6a;
|
||||
struct in6_ifaddr *ia;
|
||||
|
||||
ip6a = ip6_findaux(m);
|
||||
if (ip6a)
|
||||
return ip6a->ip6a_dstia6;
|
||||
else
|
||||
if (ip6a) {
|
||||
ia = ip6a->ip6a_dstia6;
|
||||
ifa_ref(&ia->ia_ifa);
|
||||
return ia;
|
||||
} else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -904,6 +904,7 @@ skip_ipsec2:;
|
||||
/* Record statistics for this interface address. */
|
||||
ia6->ia_ifa.if_opackets++;
|
||||
ia6->ia_ifa.if_obytes += m->m_pkthdr.len;
|
||||
ifa_free(&ia6->ia_ifa);
|
||||
}
|
||||
error = nd6_output(ifp, origifp, m, dst, ro->ro_rt);
|
||||
goto done;
|
||||
|
@ -1152,8 +1152,13 @@ mld_v1_input_report(struct ifnet *ifp, const struct ip6_hdr *ip6,
|
||||
*/
|
||||
ia = in6ifa_ifpforlinklocal(ifp, IN6_IFF_NOTREADY|IN6_IFF_ANYCAST);
|
||||
if ((ia && IN6_ARE_ADDR_EQUAL(&ip6->ip6_src, IA6_IN6(ia))) ||
|
||||
(ia == NULL && IN6_IS_ADDR_UNSPECIFIED(&src)))
|
||||
(ia == NULL && IN6_IS_ADDR_UNSPECIFIED(&src))) {
|
||||
if (ia != NULL)
|
||||
ifa_free(&ia->ia_ifa);
|
||||
return (0);
|
||||
}
|
||||
if (ia != NULL)
|
||||
ifa_free(&ia->ia_ifa);
|
||||
|
||||
CTR3(KTR_MLD, "process v1 report %s on ifp %p(%s)",
|
||||
ip6_sprintf(ip6tbuf, &mld->mld_addr), ifp, ifp->if_xname);
|
||||
@ -1796,11 +1801,16 @@ mld_v1_transmit_report(struct in6_multi *in6m, const int type)
|
||||
/* ia may be NULL if link-local address is tentative. */
|
||||
|
||||
MGETHDR(mh, M_DONTWAIT, MT_HEADER);
|
||||
if (mh == NULL)
|
||||
if (mh == NULL) {
|
||||
if (ia != NULL)
|
||||
ifa_free(&ia->ia_ifa);
|
||||
return (ENOMEM);
|
||||
}
|
||||
MGET(md, M_DONTWAIT, MT_DATA);
|
||||
if (md == NULL) {
|
||||
m_free(mh);
|
||||
if (ia != NULL)
|
||||
ifa_free(&ia->ia_ifa);
|
||||
return (ENOMEM);
|
||||
}
|
||||
mh->m_next = md;
|
||||
@ -1839,6 +1849,8 @@ mld_v1_transmit_report(struct in6_multi *in6m, const int type)
|
||||
|
||||
mld_dispatch_packet(mh);
|
||||
|
||||
if (ia != NULL)
|
||||
ifa_free(&ia->ia_ifa);
|
||||
return (0);
|
||||
}
|
||||
|
||||
@ -3136,6 +3148,8 @@ mld_v2_encap_report(struct ifnet *ifp, struct mbuf *m)
|
||||
|
||||
MGETHDR(mh, M_DONTWAIT, MT_HEADER);
|
||||
if (mh == NULL) {
|
||||
if (ia != NULL)
|
||||
ifa_free(&ia->ia_ifa);
|
||||
m_freem(m);
|
||||
return (NULL);
|
||||
}
|
||||
@ -3154,6 +3168,8 @@ mld_v2_encap_report(struct ifnet *ifp, struct mbuf *m)
|
||||
ip6->ip6_vfc |= IPV6_VERSION;
|
||||
ip6->ip6_nxt = IPPROTO_ICMPV6;
|
||||
ip6->ip6_src = ia ? ia->ia_addr.sin6_addr : in6addr_any;
|
||||
if (ia != NULL)
|
||||
ifa_free(&ia->ia_ifa);
|
||||
ip6->ip6_dst = in6addr_linklocal_allv2routers;
|
||||
/* scope ID will be set in netisr */
|
||||
|
||||
@ -3168,7 +3184,6 @@ mld_v2_encap_report(struct ifnet *ifp, struct mbuf *m)
|
||||
mh->m_next = m;
|
||||
mld->mld_cksum = in6_cksum(mh, IPPROTO_ICMPV6,
|
||||
sizeof(struct ip6_hdr), sizeof(struct mldv2_report) + mldreclen);
|
||||
|
||||
return (mh);
|
||||
}
|
||||
|
||||
|
@ -957,8 +957,13 @@ nd6_is_new_addr_neighbor(struct sockaddr_in6 *addr, struct ifnet *ifp)
|
||||
* a p2p interface, the address should be a neighbor.
|
||||
*/
|
||||
dstaddr = ifa_ifwithdstaddr((struct sockaddr *)addr);
|
||||
if ((dstaddr != NULL) && (dstaddr->ifa_ifp == ifp))
|
||||
return (1);
|
||||
if (dstaddr != NULL) {
|
||||
if (dstaddr->ifa_ifp == ifp) {
|
||||
ifa_free(dstaddr);
|
||||
return (1);
|
||||
}
|
||||
ifa_free(dstaddr);
|
||||
}
|
||||
|
||||
/*
|
||||
* If the default router list is empty, all addresses are regarded
|
||||
|
@ -355,6 +355,8 @@ nd6_ns_input(struct mbuf *m, int off, int icmp6len)
|
||||
(V_ip6_forwarding ? ND_NA_FLAG_ROUTER : 0) | ND_NA_FLAG_SOLICITED,
|
||||
tlladdr, (struct sockaddr *)proxydl);
|
||||
freeit:
|
||||
if (ifa != NULL)
|
||||
ifa_free(ifa);
|
||||
m_freem(m);
|
||||
return;
|
||||
|
||||
@ -366,6 +368,8 @@ nd6_ns_input(struct mbuf *m, int off, int icmp6len)
|
||||
nd6log((LOG_ERR, "nd6_ns_input: tgt=%s\n",
|
||||
ip6_sprintf(ip6bufs, &taddr6)));
|
||||
ICMP6STAT_INC(icp6s_badns);
|
||||
if (ifa != NULL)
|
||||
ifa_free(ifa);
|
||||
m_freem(m);
|
||||
}
|
||||
|
||||
@ -456,6 +460,8 @@ nd6_ns_output(struct ifnet *ifp, const struct in6_addr *daddr6,
|
||||
goto bad;
|
||||
}
|
||||
if (!dad) {
|
||||
struct ifaddr *ifa;
|
||||
|
||||
/*
|
||||
* RFC2461 7.2.2:
|
||||
* "If the source address of the packet prompting the
|
||||
@ -486,9 +492,11 @@ nd6_ns_output(struct ifnet *ifp, const struct in6_addr *daddr6,
|
||||
else
|
||||
hsrc = NULL;
|
||||
}
|
||||
if (hsrc && in6ifa_ifpwithaddr(ifp, hsrc))
|
||||
if (hsrc && (ifa = (struct ifaddr *)in6ifa_ifpwithaddr(ifp,
|
||||
hsrc)) != NULL) {
|
||||
src = hsrc;
|
||||
else {
|
||||
ifa_free(ifa);
|
||||
} else {
|
||||
int error;
|
||||
struct sockaddr_in6 dst_sa;
|
||||
|
||||
@ -679,12 +687,14 @@ nd6_na_input(struct mbuf *m, int off, int icmp6len)
|
||||
*/
|
||||
if (ifa
|
||||
&& (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_TENTATIVE)) {
|
||||
ifa_free(ifa);
|
||||
nd6_dad_na_input(ifa);
|
||||
goto freeit;
|
||||
}
|
||||
|
||||
/* Just for safety, maybe unnecessary. */
|
||||
if (ifa) {
|
||||
ifa_free(ifa);
|
||||
log(LOG_ERR,
|
||||
"nd6_na_input: duplicate IP6 address %s\n",
|
||||
ip6_sprintf(ip6bufs, &taddr6));
|
||||
|
@ -435,6 +435,7 @@ nd6_rtmsg(int cmd, struct rtentry *rt)
|
||||
{
|
||||
struct rt_addrinfo info;
|
||||
struct ifnet *ifp;
|
||||
struct ifaddr *ifa;
|
||||
|
||||
bzero((caddr_t)&info, sizeof(info));
|
||||
info.rti_info[RTAX_DST] = rt_key(rt);
|
||||
@ -443,13 +444,17 @@ nd6_rtmsg(int cmd, struct rtentry *rt)
|
||||
ifp = rt->rt_ifp;
|
||||
if (ifp != NULL) {
|
||||
IF_ADDR_LOCK(ifp);
|
||||
info.rti_info[RTAX_IFP] =
|
||||
TAILQ_FIRST(&ifp->if_addrhead)->ifa_addr;
|
||||
ifa = TAILQ_FIRST(&ifp->if_addrhead);
|
||||
info.rti_info[RTAX_IFP] = ifa->ifa_addr;
|
||||
ifa_ref(ifa);
|
||||
IF_ADDR_UNLOCK(ifp);
|
||||
info.rti_info[RTAX_IFA] = rt->rt_ifa->ifa_addr;
|
||||
}
|
||||
} else
|
||||
ifa = NULL;
|
||||
|
||||
rt_missmsg(cmd, &info, rt->rt_flags, 0);
|
||||
if (ifa != NULL)
|
||||
ifa_free(ifa);
|
||||
}
|
||||
|
||||
void
|
||||
@ -1307,6 +1312,7 @@ prelist_update(struct nd_prefixctl *new, struct nd_defrouter *dr,
|
||||
e));
|
||||
}
|
||||
}
|
||||
ifa_free(&ia6->ia_ifa);
|
||||
|
||||
/*
|
||||
* A newly added address might affect the status
|
||||
@ -1597,10 +1603,14 @@ nd6_prefix_onlink(struct nd_prefix *pr)
|
||||
IN6_IFF_NOTREADY | IN6_IFF_ANYCAST);
|
||||
if (ifa == NULL) {
|
||||
/* XXX: freebsd does not have ifa_ifwithaf */
|
||||
IF_ADDR_LOCK(ifp);
|
||||
TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
|
||||
if (ifa->ifa_addr->sa_family == AF_INET6)
|
||||
break;
|
||||
}
|
||||
if (ifa != NULL)
|
||||
ifa_ref(ifa);
|
||||
IF_ADDR_UNLOCK(ifp);
|
||||
/* should we care about ia6_flags? */
|
||||
}
|
||||
if (ifa == NULL) {
|
||||
@ -1661,6 +1671,8 @@ nd6_prefix_onlink(struct nd_prefix *pr)
|
||||
RT_REMREF(rt);
|
||||
RT_UNLOCK(rt);
|
||||
}
|
||||
if (ifa != NULL)
|
||||
ifa_free(ifa);
|
||||
|
||||
return (error);
|
||||
}
|
||||
@ -1802,6 +1814,7 @@ in6_ifadd(struct nd_prefixctl *pr, int mcast)
|
||||
/* prefixlen + ifidlen must be equal to 128 */
|
||||
plen0 = in6_mask2len(&ib->ia_prefixmask.sin6_addr, NULL);
|
||||
if (prefixlen != plen0) {
|
||||
ifa_free(ifa);
|
||||
nd6log((LOG_INFO, "in6_ifadd: wrong prefixlen for %s "
|
||||
"(prefix=%d ifid=%d)\n",
|
||||
if_name(ifp), prefixlen, 128 - plen0));
|
||||
@ -1834,6 +1847,7 @@ in6_ifadd(struct nd_prefixctl *pr, 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]);
|
||||
ifa_free(ifa);
|
||||
|
||||
/* new prefix mask. */
|
||||
ifra.ifra_prefixmask.sin6_len = sizeof(struct sockaddr_in6);
|
||||
@ -1854,7 +1868,10 @@ in6_ifadd(struct nd_prefixctl *pr, 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.
|
||||
*/
|
||||
if (in6ifa_ifpwithaddr(ifp, &ifra.ifra_addr.sin6_addr) != NULL) {
|
||||
ifa = (struct ifaddr *)in6ifa_ifpwithaddr(ifp,
|
||||
&ifra.ifra_addr.sin6_addr);
|
||||
if (ifa != NULL) {
|
||||
ifa_free(ifa);
|
||||
/* this should be rare enough to make an explicit log */
|
||||
log(LOG_INFO, "in6_ifadd: %s is already configured\n",
|
||||
ip6_sprintf(ip6buf, &ifra.ifra_addr.sin6_addr));
|
||||
@ -1879,8 +1896,12 @@ in6_ifadd(struct nd_prefixctl *pr, int mcast)
|
||||
}
|
||||
|
||||
ia = in6ifa_ifpwithaddr(ifp, &ifra.ifra_addr.sin6_addr);
|
||||
|
||||
return (ia); /* this is always non-NULL */
|
||||
/*
|
||||
* XXXRW: Assumption of non-NULLness here might not be true with
|
||||
* fine-grained locking -- should we validate it? Or just return
|
||||
* earlier ifa rather than looking it up again?
|
||||
*/
|
||||
return (ia); /* this is always non-NULL and referenced. */
|
||||
}
|
||||
|
||||
/*
|
||||
@ -2000,6 +2021,7 @@ in6_tmpifadd(const struct in6_ifaddr *ia0, int forcegen, int delay)
|
||||
}
|
||||
newia->ia6_ndpr = ia0->ia6_ndpr;
|
||||
newia->ia6_ndpr->ndpr_refcnt++;
|
||||
ifa_free(&newia->ia_ifa);
|
||||
|
||||
/*
|
||||
* A newly added address might affect the status of other addresses.
|
||||
|
@ -714,7 +714,7 @@ rip6_bind(struct socket *so, struct sockaddr *nam, struct thread *td)
|
||||
INIT_VNET_INET6(so->so_vnet);
|
||||
struct inpcb *inp;
|
||||
struct sockaddr_in6 *addr = (struct sockaddr_in6 *)nam;
|
||||
struct ifaddr *ia = NULL;
|
||||
struct ifaddr *ifa = NULL;
|
||||
int error = 0;
|
||||
|
||||
inp = sotoinpcb(so);
|
||||
@ -730,14 +730,17 @@ rip6_bind(struct socket *so, struct sockaddr *nam, struct thread *td)
|
||||
return (error);
|
||||
|
||||
if (!IN6_IS_ADDR_UNSPECIFIED(&addr->sin6_addr) &&
|
||||
(ia = ifa_ifwithaddr((struct sockaddr *)addr)) == 0)
|
||||
(ifa = ifa_ifwithaddr((struct sockaddr *)addr)) == NULL)
|
||||
return (EADDRNOTAVAIL);
|
||||
if (ia &&
|
||||
((struct in6_ifaddr *)ia)->ia6_flags &
|
||||
if (ifa != NULL &&
|
||||
((struct in6_ifaddr *)ifa)->ia6_flags &
|
||||
(IN6_IFF_ANYCAST|IN6_IFF_NOTREADY|
|
||||
IN6_IFF_DETACHED|IN6_IFF_DEPRECATED)) {
|
||||
ifa_free(ifa);
|
||||
return (EADDRNOTAVAIL);
|
||||
}
|
||||
if (ifa != NULL)
|
||||
ifa_free(ifa);
|
||||
INP_INFO_WLOCK(&V_ripcbinfo);
|
||||
INP_WLOCK(inp);
|
||||
inp->in6p_laddr = addr->sin6_addr;
|
||||
|
@ -158,7 +158,6 @@ ipx_pcbbind(struct ipxpcb *ipxp, struct sockaddr *nam, struct thread *td)
|
||||
int
|
||||
ipx_pcbconnect(struct ipxpcb *ipxp, struct sockaddr *nam, struct thread *td)
|
||||
{
|
||||
struct ipx_ifaddr *ia;
|
||||
struct sockaddr_ipx *sipx = (struct sockaddr_ipx *)nam;
|
||||
struct ipx_addr *dst;
|
||||
struct route *ro;
|
||||
@ -167,8 +166,6 @@ ipx_pcbconnect(struct ipxpcb *ipxp, struct sockaddr *nam, struct thread *td)
|
||||
IPX_LIST_LOCK_ASSERT();
|
||||
IPX_LOCK_ASSERT(ipxp);
|
||||
|
||||
ia = NULL;
|
||||
|
||||
if (sipx->sipx_family != AF_IPX)
|
||||
return (EAFNOSUPPORT);
|
||||
if (sipx->sipx_port == 0 || ipx_nullhost(sipx->sipx_addr))
|
||||
@ -213,6 +210,8 @@ ipx_pcbconnect(struct ipxpcb *ipxp, struct sockaddr *nam, struct thread *td)
|
||||
rtalloc_ign(ro, 0);
|
||||
}
|
||||
if (ipx_neteqnn(ipxp->ipxp_laddr.x_net, ipx_zeronet)) {
|
||||
struct ipx_ifaddr *ia = NULL;
|
||||
|
||||
/*
|
||||
* If route is known or can be allocated now,
|
||||
* our src addr is taken from the i/f, else punt.
|
||||
@ -225,40 +224,10 @@ ipx_pcbconnect(struct ipxpcb *ipxp, struct sockaddr *nam, struct thread *td)
|
||||
if (ro->ro_rt != NULL && (ifp = ro->ro_rt->rt_ifp) != NULL) {
|
||||
IPX_IFADDR_RLOCK();
|
||||
for (ia = ipx_ifaddr; ia != NULL; ia = ia->ia_next)
|
||||
if (ia->ia_ifp == ifp)
|
||||
break;
|
||||
IPX_IFADDR_RUNLOCK();
|
||||
}
|
||||
if (ia == NULL) {
|
||||
u_short fport = sipx->sipx_addr.x_port;
|
||||
sipx->sipx_addr.x_port = 0;
|
||||
ia = (struct ipx_ifaddr *)
|
||||
ifa_ifwithdstaddr((struct sockaddr *)sipx);
|
||||
sipx->sipx_addr.x_port = fport;
|
||||
if (ia == NULL)
|
||||
ia = ipx_iaonnetof(&sipx->sipx_addr);
|
||||
if (ia == NULL)
|
||||
ia = ipx_ifaddr;
|
||||
if (ia == NULL)
|
||||
return (EADDRNOTAVAIL);
|
||||
}
|
||||
ipxp->ipxp_laddr.x_net = satoipx_addr(ia->ia_addr).x_net;
|
||||
}
|
||||
if (ipx_nullhost(ipxp->ipxp_laddr)) {
|
||||
/*
|
||||
* If route is known or can be allocated now,
|
||||
* our src addr is taken from the i/f, else punt.
|
||||
*/
|
||||
|
||||
/*
|
||||
* If we found a route, use the address
|
||||
* corresponding to the outgoing interface
|
||||
*/
|
||||
if (ro->ro_rt != NULL && (ifp = ro->ro_rt->rt_ifp) != NULL) {
|
||||
IPX_IFADDR_RLOCK();
|
||||
for (ia = ipx_ifaddr; ia != NULL; ia = ia->ia_next)
|
||||
if (ia->ia_ifp == ifp)
|
||||
if (ia->ia_ifp == ifp) {
|
||||
ifa_ref(&ia->ia_ifa);
|
||||
break;
|
||||
}
|
||||
IPX_IFADDR_RUNLOCK();
|
||||
}
|
||||
if (ia == NULL) {
|
||||
@ -270,17 +239,68 @@ ipx_pcbconnect(struct ipxpcb *ipxp, struct sockaddr *nam, struct thread *td)
|
||||
if (ia == NULL) {
|
||||
IPX_IFADDR_RLOCK();
|
||||
ia = ipx_iaonnetof(&sipx->sipx_addr);
|
||||
if (ia != NULL)
|
||||
ifa_ref(&ia->ia_ifa);
|
||||
IPX_IFADDR_RUNLOCK();
|
||||
}
|
||||
if (ia == NULL) {
|
||||
IPX_IFADDR_RLOCK();
|
||||
ia = ipx_ifaddr;
|
||||
if (ia != NULL)
|
||||
ifa_ref(&ia->ia_ifa);
|
||||
IPX_IFADDR_RUNLOCK();
|
||||
}
|
||||
if (ia == NULL)
|
||||
return (EADDRNOTAVAIL);
|
||||
}
|
||||
ipxp->ipxp_laddr.x_net = satoipx_addr(ia->ia_addr).x_net;
|
||||
ifa_free(&ia->ia_ifa);
|
||||
}
|
||||
if (ipx_nullhost(ipxp->ipxp_laddr)) {
|
||||
struct ipx_ifaddr *ia = NULL;
|
||||
/*
|
||||
* If route is known or can be allocated now,
|
||||
* our src addr is taken from the i/f, else punt.
|
||||
*/
|
||||
|
||||
/*
|
||||
* If we found a route, use the address
|
||||
* corresponding to the outgoing interface
|
||||
*/
|
||||
if (ro->ro_rt != NULL && (ifp = ro->ro_rt->rt_ifp) != NULL) {
|
||||
IPX_IFADDR_RLOCK();
|
||||
for (ia = ipx_ifaddr; ia != NULL; ia = ia->ia_next)
|
||||
if (ia->ia_ifp == ifp) {
|
||||
ifa_ref(&ia->ia_ifa);
|
||||
break;
|
||||
}
|
||||
IPX_IFADDR_RUNLOCK();
|
||||
}
|
||||
if (ia == NULL) {
|
||||
u_short fport = sipx->sipx_addr.x_port;
|
||||
sipx->sipx_addr.x_port = 0;
|
||||
ia = (struct ipx_ifaddr *)
|
||||
ifa_ifwithdstaddr((struct sockaddr *)sipx);
|
||||
sipx->sipx_addr.x_port = fport;
|
||||
if (ia == NULL) {
|
||||
IPX_IFADDR_RLOCK();
|
||||
ia = ipx_iaonnetof(&sipx->sipx_addr);
|
||||
if (ia != NULL)
|
||||
ifa_ref(&ia->ia_ifa);
|
||||
IPX_IFADDR_RUNLOCK();
|
||||
}
|
||||
if (ia == NULL) {
|
||||
IPX_IFADDR_RLOCK();
|
||||
ia = ipx_ifaddr;
|
||||
if (ia != NULL)
|
||||
ifa_ref(&ia->ia_ifa);
|
||||
IPX_IFADDR_RUNLOCK();
|
||||
}
|
||||
if (ia == NULL)
|
||||
return (EADDRNOTAVAIL);
|
||||
}
|
||||
ipxp->ipxp_laddr.x_host = satoipx_addr(ia->ia_addr).x_host;
|
||||
ifa_free(&ia->ia_ifa);
|
||||
}
|
||||
if (ipx_pcblookup(&sipx->sipx_addr, ipxp->ipxp_lport, 0))
|
||||
return (EADDRINUSE);
|
||||
|
Loading…
Reference in New Issue
Block a user