fixed memory leak for IPv6 multicast membership information associated
with interface addresses.

Approved by:    gnn (mentor)

src/sys/netinet6/in6.c:			1.71
src/sys/netinet6/in6_ifattach.c:	1.36
src/sys/netinet6/in6_var.h:		1.31
This commit is contained in:
jinmei 2007-06-10 17:17:55 +00:00
parent 2903a43579
commit f3d7053114
3 changed files with 31 additions and 21 deletions

View File

@ -901,6 +901,7 @@ in6_update_ifa(ifp, ifra, ia, flags)
if (ia == NULL)
return (ENOBUFS);
bzero((caddr_t)ia, sizeof(*ia));
LIST_INIT(&ia->ia6_memberships);
/* Initialize the address and masks, and put time stamp */
IFA_LOCK_INIT(&ia->ia_ifa);
ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr;
@ -1058,7 +1059,7 @@ in6_update_ifa(ifp, ifra, ia, flags)
(MAX_RTR_SOLICITATION_DELAY * hz);
}
imm = in6_joingroup(ifp, &llsol, &error, delay);
if (error != 0) {
if (imm == NULL) {
nd6log((LOG_WARNING,
"in6_update_ifa: addmulti failed for "
"%s on %s (errno=%d)\n",
@ -1067,6 +1068,8 @@ in6_update_ifa(ifp, ifra, ia, flags)
in6_purgeaddr((struct ifaddr *)ia);
return (error);
}
LIST_INSERT_HEAD(&ia->ia6_memberships,
imm, i6mm_chain);
in6m_sol = imm->i6mm_maddr;
bzero(&mltmask, sizeof(mltmask));
@ -1148,6 +1151,7 @@ in6_update_ifa(ifp, ifra, ia, flags)
if_name(ifp), error));
goto cleanup;
}
LIST_INSERT_HEAD(&ia->ia6_memberships, imm, i6mm_chain);
/*
* join node information group address
@ -1173,6 +1177,9 @@ in6_update_ifa(ifp, ifra, ia, flags)
ip6_sprintf(&mltaddr.sin6_addr),
if_name(ifp), error));
/* XXX not very fatal, go on... */
} else {
LIST_INSERT_HEAD(&ia->ia6_memberships,
imm, i6mm_chain);
}
}
#undef hostnamelen
@ -1235,6 +1242,7 @@ in6_update_ifa(ifp, ifra, ia, flags)
if_name(ifp), error));
goto cleanup;
}
LIST_INSERT_HEAD(&ia->ia6_memberships, imm, i6mm_chain);
#undef MLTMASK_LEN
}
@ -1298,6 +1306,7 @@ in6_purgeaddr(ifa)
{
struct ifnet *ifp = ifa->ifa_ifp;
struct in6_ifaddr *ia = (struct in6_ifaddr *) ifa;
struct in6_multi_mship *imm;
/* stop DAD processing */
nd6_dad_stop(ifa);
@ -1324,24 +1333,12 @@ in6_purgeaddr(ifa)
/* Remove ownaddr's loopback rtentry, if it exists. */
in6_ifremloop(&(ia->ia_ifa));
if (ifp->if_flags & IFF_MULTICAST) {
/*
* delete solicited multicast addr for deleting host id
*/
struct in6_multi *in6m;
struct in6_addr llsol;
bzero(&llsol, sizeof(struct in6_addr));
llsol.s6_addr32[0] = IPV6_ADDR_INT32_MLL;
llsol.s6_addr32[1] = 0;
llsol.s6_addr32[2] = htonl(1);
llsol.s6_addr32[3] =
ia->ia_addr.sin6_addr.s6_addr32[3];
llsol.s6_addr8[12] = 0xff;
(void)in6_setscope(&llsol, ifp, NULL); /* XXX proceed anyway */
IN6_LOOKUP_MULTI(llsol, ifp, in6m);
if (in6m)
in6_delmulti(in6m);
/*
* leave from multicast groups we have joined for the interface
*/
while ((imm = ia->ia6_memberships.lh_first) != NULL) {
LIST_REMOVE(imm, i6mm_chain);
in6_leavegroup(imm);
}
in6_unlink_ifa(ia, ifp);

View File

@ -733,8 +733,8 @@ in6_ifdetach(ifp)
struct rtentry *rt;
short rtflags;
struct sockaddr_in6 sin6;
struct in6_multi *in6m;
struct in6_multi *in6m_next;
struct in6_multi *in6m, *in6m_next;
struct in6_multi_mship *imm;
/* remove neighbor management table */
nd6_purge(ifp);
@ -758,6 +758,14 @@ in6_ifdetach(ifp)
ia = (struct in6_ifaddr *)ifa;
/*
* leave from multicast groups we have joined for the interface
*/
while ((imm = ia->ia6_memberships.lh_first) != NULL) {
LIST_REMOVE(imm, i6mm_chain);
in6_leavegroup(imm);
}
/* remove from the routing table */
if ((ia->ia_flags & IFA_ROUTE) &&
(rt = rtalloc1((struct sockaddr *)&ia->ia_addr, 0, 0UL))) {
@ -803,6 +811,8 @@ in6_ifdetach(ifp)
in6m_next = LIST_NEXT(in6m, in6m_entry);
if (in6m->in6m_ifp != ifp)
continue;
printf("in6_ifdetach: in6m=%p (ref=%d), ifp=%p\n", in6m,
in6m->in6m_ifma->ifma_refcount, ifp);
in6_delmulti(in6m);
in6m = NULL;
}

View File

@ -115,6 +115,9 @@ struct in6_ifaddr {
/* back pointer to the ND prefix (for autoconfigured addresses only) */
struct nd_prefix *ia6_ndpr;
/* multicast addresses joined from the kernel */
LIST_HEAD(, in6_multi_mship) ia6_memberships;
};
/* control structure to manage address selection policy */