summaryrefslogtreecommitdiffstats
path: root/sys/netinet
diff options
context:
space:
mode:
authorrwatson <rwatson@FreeBSD.org>2009-06-23 20:19:09 +0000
committerrwatson <rwatson@FreeBSD.org>2009-06-23 20:19:09 +0000
commitc9ef486fe1d7da6a2212a337eacc5ed5b40f85d9 (patch)
tree5ce1a7dad67026f119a839b3325454ebafa72c51 /sys/netinet
parentf75c2385c686d82292982283b5f0a9c9988beda8 (diff)
downloadFreeBSD-src-c9ef486fe1d7da6a2212a337eacc5ed5b40f85d9.zip
FreeBSD-src-c9ef486fe1d7da6a2212a337eacc5ed5b40f85d9.tar.gz
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)
Diffstat (limited to 'sys/netinet')
-rw-r--r--sys/netinet/igmp.c21
-rw-r--r--sys/netinet/in.c115
-rw-r--r--sys/netinet/in_mcast.c1
-rw-r--r--sys/netinet/in_pcb.c11
-rw-r--r--sys/netinet/in_var.h18
-rw-r--r--sys/netinet/ip_carp.c1
-rw-r--r--sys/netinet/ip_divert.c1
-rw-r--r--sys/netinet/ip_icmp.c8
-rw-r--r--sys/netinet/ip_input.c26
-rw-r--r--sys/netinet/ip_mroute.c1
-rw-r--r--sys/netinet/ip_options.c8
-rw-r--r--sys/netinet/ip_output.c3
-rw-r--r--sys/netinet/tcp_input.c6
13 files changed, 130 insertions, 90 deletions
diff --git a/sys/netinet/igmp.c b/sys/netinet/igmp.c
index 2761590..be102d4 100644
--- a/sys/netinet/igmp.c
+++ b/sys/netinet/igmp.c
@@ -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);
diff --git a/sys/netinet/in.c b/sys/netinet/in.c
index 1b9a79d..2b6fd18 100644
--- a/sys/netinet/in.c
+++ b/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);
}
diff --git a/sys/netinet/in_mcast.c b/sys/netinet/in_mcast.c
index d7cbd35..a856676 100644
--- a/sys/netinet/in_mcast.c
+++ b/sys/netinet/in_mcast.c
@@ -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);
}
}
}
diff --git a/sys/netinet/in_pcb.c b/sys/netinet/in_pcb.c
index 4e30572..574ce63 100644
--- a/sys/netinet/in_pcb.c
+++ b/sys/netinet/in_pcb.c
@@ -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) {
diff --git a/sys/netinet/in_var.h b/sys/netinet/in_var.h
index 2b59e92..dbacbfa 100644
--- a/sys/netinet/in_var.h
+++ b/sys/netinet/in_var.h
@@ -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
diff --git a/sys/netinet/ip_carp.c b/sys/netinet/ip_carp.c
index fa0726a..fcfe28a 100644
--- a/sys/netinet/ip_carp.c
+++ b/sys/netinet/ip_carp.c
@@ -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);
diff --git a/sys/netinet/ip_divert.c b/sys/netinet/ip_divert.c
index 0b72c65..680156b 100644
--- a/sys/netinet/ip_divert.c
+++ b/sys/netinet/ip_divert.c
@@ -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);
diff --git a/sys/netinet/ip_icmp.c b/sys/netinet/ip_icmp.c
index cfd27f0..3cd6530 100644
--- a/sys/netinet/ip_icmp.c
+++ b/sys/netinet/ip_icmp.c
@@ -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);
diff --git a/sys/netinet/ip_input.c b/sys/netinet/ip_input.c
index 8642e31..be4b084 100644
--- a/sys/netinet/ip_input.c
+++ b/sys/netinet/ip_input.c
@@ -622,8 +622,10 @@ passin:
* 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 @@ passin:
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 @@ ours:
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);
}
diff --git a/sys/netinet/ip_mroute.c b/sys/netinet/ip_mroute.c
index 091bd21..3c3c014 100644
--- a/sys/netinet/ip_mroute.c
+++ b/sys/netinet/ip_mroute.c
@@ -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) {
diff --git a/sys/netinet/ip_options.c b/sys/netinet/ip_options.c
index b59d708..09a1d62 100644
--- a/sys/netinet/ip_options.c
+++ b/sys/netinet/ip_options.c
@@ -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 @@ dropit:
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 @@ dropit:
}
(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 @@ dropit:
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;
diff --git a/sys/netinet/ip_output.c b/sys/netinet/ip_output.c
index c1e0d37..8ed63a5 100644
--- a/sys/netinet/ip_output.c
+++ b/sys/netinet/ip_output.c
@@ -288,6 +288,7 @@ again:
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 @@ done:
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);
diff --git a/sys/netinet/tcp_input.c b/sys/netinet/tcp_input.c
index 371dd1ef..cad7bbe 100644
--- a/sys/netinet/tcp_input.c
+++ b/sys/netinet/tcp_input.c
@@ -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 @@ findpcb:
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 @@ findpcb:
rstreason = BANDLIM_RST_OPENPORT;
goto dropwithreset;
}
+ ifa_free(&ia6->ia_ifa);
}
#endif
/*
OpenPOWER on IntegriCloud