In preparation for multi-FIB IPv6 support, factor the code for joining
and leaving multicast groups out from in6_update_ifa() and in6_purgeaddr(). Sponsored by: Cisco Systems, Inc.
This commit is contained in:
parent
1616ed91c2
commit
5490110cf5
@ -820,6 +820,169 @@ in6_control(struct socket *so, u_long cmd, caddr_t data,
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* Join necessary multicast groups. Factored out from in6_update_ifa().
|
||||
* This entire work should only be done once, for the default FIB.
|
||||
*/
|
||||
static int
|
||||
in6_update_ifa_join_mc(struct ifnet *ifp, struct in6_aliasreq *ifra,
|
||||
struct in6_ifaddr *ia, int flags, struct in6_multi **in6m_sol)
|
||||
{
|
||||
char ip6buf[INET6_ADDRSTRLEN];
|
||||
struct sockaddr_in6 mltaddr, mltmask;
|
||||
struct in6_addr llsol;
|
||||
struct in6_multi_mship *imm;
|
||||
struct rtentry *rt;
|
||||
int delay, error;
|
||||
|
||||
KASSERT(in6m_sol != NULL, ("%s: in6m_sol is NULL", __func__));
|
||||
|
||||
/* Join solicited multicast addr for new host id. */
|
||||
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] = ifra->ifra_addr.sin6_addr.s6_addr32[3];
|
||||
llsol.s6_addr8[12] = 0xff;
|
||||
if ((error = in6_setscope(&llsol, ifp, NULL)) != 0) {
|
||||
/* XXX: should not happen */
|
||||
log(LOG_ERR, "%s: in6_setscope failed\n", __func__);
|
||||
goto cleanup;
|
||||
}
|
||||
delay = 0;
|
||||
if ((flags & IN6_IFAUPDATE_DADDELAY)) {
|
||||
/*
|
||||
* We need a random delay for DAD on the address being
|
||||
* configured. It also means delaying transmission of the
|
||||
* corresponding MLD report to avoid report collision.
|
||||
* [RFC 4861, Section 6.3.7]
|
||||
*/
|
||||
delay = arc4random() % (MAX_RTR_SOLICITATION_DELAY * hz);
|
||||
}
|
||||
imm = in6_joingroup(ifp, &llsol, &error, delay);
|
||||
if (imm == NULL) {
|
||||
nd6log((LOG_WARNING, "%s: addmulti failed for %s on %s "
|
||||
"(errno=%d)\n", __func__, ip6_sprintf(ip6buf, &llsol),
|
||||
if_name(ifp), error));
|
||||
goto cleanup;
|
||||
}
|
||||
LIST_INSERT_HEAD(&ia->ia6_memberships, imm, i6mm_chain);
|
||||
*in6m_sol = imm->i6mm_maddr;
|
||||
|
||||
bzero(&mltmask, sizeof(mltmask));
|
||||
mltmask.sin6_len = sizeof(struct sockaddr_in6);
|
||||
mltmask.sin6_family = AF_INET6;
|
||||
mltmask.sin6_addr = in6mask32;
|
||||
#define MLTMASK_LEN 4 /* mltmask's masklen (=32bit=4octet) */
|
||||
|
||||
/*
|
||||
* Join link-local all-nodes address.
|
||||
*/
|
||||
bzero(&mltaddr, sizeof(mltaddr));
|
||||
mltaddr.sin6_len = sizeof(struct sockaddr_in6);
|
||||
mltaddr.sin6_family = AF_INET6;
|
||||
mltaddr.sin6_addr = in6addr_linklocal_allnodes;
|
||||
if ((error = in6_setscope(&mltaddr.sin6_addr, ifp, NULL)) != 0)
|
||||
goto cleanup; /* XXX: should not fail */
|
||||
|
||||
/*
|
||||
* XXX: do we really need this automatic routes? We should probably
|
||||
* reconsider this stuff. Most applications actually do not need the
|
||||
* routes, since they usually specify the outgoing interface.
|
||||
*/
|
||||
rt = rtalloc1((struct sockaddr *)&mltaddr, 0, 0UL);
|
||||
if (rt != NULL) {
|
||||
/* XXX: only works in !SCOPEDROUTING case. */
|
||||
if (memcmp(&mltaddr.sin6_addr,
|
||||
&((struct sockaddr_in6 *)rt_key(rt))->sin6_addr,
|
||||
MLTMASK_LEN)) {
|
||||
RTFREE_LOCKED(rt);
|
||||
rt = NULL;
|
||||
}
|
||||
}
|
||||
if (rt == NULL) {
|
||||
error = rtrequest(RTM_ADD, (struct sockaddr *)&mltaddr,
|
||||
(struct sockaddr *)&ia->ia_addr,
|
||||
(struct sockaddr *)&mltmask, RTF_UP,
|
||||
(struct rtentry **)0);
|
||||
if (error)
|
||||
goto cleanup;
|
||||
} else
|
||||
RTFREE_LOCKED(rt);
|
||||
|
||||
imm = in6_joingroup(ifp, &mltaddr.sin6_addr, &error, 0);
|
||||
if (imm == NULL) {
|
||||
nd6log((LOG_WARNING, "%s: addmulti failed for %s on %s "
|
||||
"(errno=%d)\n", __func__, ip6_sprintf(ip6buf,
|
||||
&mltaddr.sin6_addr), if_name(ifp), error));
|
||||
goto cleanup;
|
||||
}
|
||||
LIST_INSERT_HEAD(&ia->ia6_memberships, imm, i6mm_chain);
|
||||
|
||||
/*
|
||||
* Join node information group address.
|
||||
*/
|
||||
delay = 0;
|
||||
if ((flags & IN6_IFAUPDATE_DADDELAY)) {
|
||||
/*
|
||||
* The spec does not say anything about delay for this group,
|
||||
* but the same logic should apply.
|
||||
*/
|
||||
delay = arc4random() % (MAX_RTR_SOLICITATION_DELAY * hz);
|
||||
}
|
||||
if (in6_nigroup(ifp, NULL, -1, &mltaddr.sin6_addr) == 0) {
|
||||
/* XXX jinmei */
|
||||
imm = in6_joingroup(ifp, &mltaddr.sin6_addr, &error, delay);
|
||||
if (imm == NULL)
|
||||
nd6log((LOG_WARNING, "%s: addmulti failed for %s on %s "
|
||||
"(errno=%d)\n", __func__, ip6_sprintf(ip6buf,
|
||||
&mltaddr.sin6_addr), if_name(ifp), error));
|
||||
/* XXX not very fatal, go on... */
|
||||
else
|
||||
LIST_INSERT_HEAD(&ia->ia6_memberships, imm, i6mm_chain);
|
||||
}
|
||||
|
||||
/*
|
||||
* Join interface-local all-nodes address.
|
||||
* (ff01::1%ifN, and ff01::%ifN/32)
|
||||
*/
|
||||
mltaddr.sin6_addr = in6addr_nodelocal_allnodes;
|
||||
if ((error = in6_setscope(&mltaddr.sin6_addr, ifp, NULL)) != 0)
|
||||
goto cleanup; /* XXX: should not fail */
|
||||
/* XXX: again, do we really need the route? */
|
||||
rt = rtalloc1((struct sockaddr *)&mltaddr, 0, 0UL);
|
||||
if (rt != NULL) {
|
||||
if (memcmp(&mltaddr.sin6_addr,
|
||||
&((struct sockaddr_in6 *)rt_key(rt))->sin6_addr,
|
||||
MLTMASK_LEN)) {
|
||||
RTFREE_LOCKED(rt);
|
||||
rt = NULL;
|
||||
}
|
||||
}
|
||||
if (rt == NULL) {
|
||||
error = rtrequest(RTM_ADD, (struct sockaddr *)&mltaddr,
|
||||
(struct sockaddr *)&ia->ia_addr,
|
||||
(struct sockaddr *)&mltmask, RTF_UP,
|
||||
(struct rtentry **)0);
|
||||
if (error)
|
||||
goto cleanup;
|
||||
} else
|
||||
RTFREE_LOCKED(rt);
|
||||
|
||||
imm = in6_joingroup(ifp, &mltaddr.sin6_addr, &error, 0);
|
||||
if (imm == NULL) {
|
||||
nd6log((LOG_WARNING, "%s: addmulti failed for %s on %s "
|
||||
"(errno=%d)\n", __func__, ip6_sprintf(ip6buf,
|
||||
&mltaddr.sin6_addr), if_name(ifp), error));
|
||||
goto cleanup;
|
||||
}
|
||||
LIST_INSERT_HEAD(&ia->ia6_memberships, imm, i6mm_chain);
|
||||
#undef MLTMASK_LEN
|
||||
|
||||
cleanup:
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* Update parameters of an IPv6 interface address.
|
||||
* If necessary, a new entry is created and linked into address chains.
|
||||
@ -833,9 +996,7 @@ in6_update_ifa(struct ifnet *ifp, struct in6_aliasreq *ifra,
|
||||
int error = 0, hostIsNew = 0, plen = -1;
|
||||
struct sockaddr_in6 dst6;
|
||||
struct in6_addrlifetime *lt;
|
||||
struct in6_multi_mship *imm;
|
||||
struct in6_multi *in6m_sol;
|
||||
struct rtentry *rt;
|
||||
int delay;
|
||||
char ip6buf[INET6_ADDRSTRLEN];
|
||||
|
||||
@ -1083,172 +1244,12 @@ in6_update_ifa(struct ifnet *ifp, struct in6_aliasreq *ifra,
|
||||
* not just go to unlink.
|
||||
*/
|
||||
|
||||
/* Join necessary multicast groups */
|
||||
/* Join necessary multicast groups. */
|
||||
in6m_sol = NULL;
|
||||
if ((ifp->if_flags & IFF_MULTICAST) != 0) {
|
||||
struct sockaddr_in6 mltaddr, mltmask;
|
||||
struct in6_addr llsol;
|
||||
|
||||
/* join solicited multicast addr for new host id */
|
||||
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] = ifra->ifra_addr.sin6_addr.s6_addr32[3];
|
||||
llsol.s6_addr8[12] = 0xff;
|
||||
if ((error = in6_setscope(&llsol, ifp, NULL)) != 0) {
|
||||
/* XXX: should not happen */
|
||||
log(LOG_ERR, "in6_update_ifa: "
|
||||
"in6_setscope failed\n");
|
||||
error = in6_update_ifa_join_mc(ifp, ifra, ia, flags, &in6m_sol);
|
||||
if (error)
|
||||
goto cleanup;
|
||||
}
|
||||
delay = 0;
|
||||
if ((flags & IN6_IFAUPDATE_DADDELAY)) {
|
||||
/*
|
||||
* We need a random delay for DAD on the address
|
||||
* being configured. It also means delaying
|
||||
* transmission of the corresponding MLD report to
|
||||
* avoid report collision.
|
||||
* [RFC 4861, Section 6.3.7]
|
||||
*/
|
||||
delay = arc4random() %
|
||||
(MAX_RTR_SOLICITATION_DELAY * hz);
|
||||
}
|
||||
imm = in6_joingroup(ifp, &llsol, &error, delay);
|
||||
if (imm == NULL) {
|
||||
nd6log((LOG_WARNING,
|
||||
"in6_update_ifa: addmulti failed for "
|
||||
"%s on %s (errno=%d)\n",
|
||||
ip6_sprintf(ip6buf, &llsol), if_name(ifp),
|
||||
error));
|
||||
goto cleanup;
|
||||
}
|
||||
LIST_INSERT_HEAD(&ia->ia6_memberships,
|
||||
imm, i6mm_chain);
|
||||
in6m_sol = imm->i6mm_maddr;
|
||||
|
||||
bzero(&mltmask, sizeof(mltmask));
|
||||
mltmask.sin6_len = sizeof(struct sockaddr_in6);
|
||||
mltmask.sin6_family = AF_INET6;
|
||||
mltmask.sin6_addr = in6mask32;
|
||||
#define MLTMASK_LEN 4 /* mltmask's masklen (=32bit=4octet) */
|
||||
|
||||
/*
|
||||
* join link-local all-nodes address
|
||||
*/
|
||||
bzero(&mltaddr, sizeof(mltaddr));
|
||||
mltaddr.sin6_len = sizeof(struct sockaddr_in6);
|
||||
mltaddr.sin6_family = AF_INET6;
|
||||
mltaddr.sin6_addr = in6addr_linklocal_allnodes;
|
||||
if ((error = in6_setscope(&mltaddr.sin6_addr, ifp, NULL)) !=
|
||||
0)
|
||||
goto cleanup; /* XXX: should not fail */
|
||||
|
||||
/*
|
||||
* XXX: do we really need this automatic routes?
|
||||
* We should probably reconsider this stuff. Most applications
|
||||
* actually do not need the routes, since they usually specify
|
||||
* the outgoing interface.
|
||||
*/
|
||||
rt = rtalloc1((struct sockaddr *)&mltaddr, 0, 0UL);
|
||||
if (rt) {
|
||||
/* XXX: only works in !SCOPEDROUTING case. */
|
||||
if (memcmp(&mltaddr.sin6_addr,
|
||||
&((struct sockaddr_in6 *)rt_key(rt))->sin6_addr,
|
||||
MLTMASK_LEN)) {
|
||||
RTFREE_LOCKED(rt);
|
||||
rt = NULL;
|
||||
}
|
||||
}
|
||||
if (!rt) {
|
||||
error = rtrequest(RTM_ADD, (struct sockaddr *)&mltaddr,
|
||||
(struct sockaddr *)&ia->ia_addr,
|
||||
(struct sockaddr *)&mltmask, RTF_UP,
|
||||
(struct rtentry **)0);
|
||||
if (error)
|
||||
goto cleanup;
|
||||
} else {
|
||||
RTFREE_LOCKED(rt);
|
||||
}
|
||||
|
||||
imm = in6_joingroup(ifp, &mltaddr.sin6_addr, &error, 0);
|
||||
if (!imm) {
|
||||
nd6log((LOG_WARNING,
|
||||
"in6_update_ifa: addmulti failed for "
|
||||
"%s on %s (errno=%d)\n",
|
||||
ip6_sprintf(ip6buf, &mltaddr.sin6_addr),
|
||||
if_name(ifp), error));
|
||||
goto cleanup;
|
||||
}
|
||||
LIST_INSERT_HEAD(&ia->ia6_memberships, imm, i6mm_chain);
|
||||
|
||||
/*
|
||||
* join node information group address
|
||||
*/
|
||||
delay = 0;
|
||||
if ((flags & IN6_IFAUPDATE_DADDELAY)) {
|
||||
/*
|
||||
* The spec doesn't say anything about delay for this
|
||||
* group, but the same logic should apply.
|
||||
*/
|
||||
delay = arc4random() %
|
||||
(MAX_RTR_SOLICITATION_DELAY * hz);
|
||||
}
|
||||
if (in6_nigroup(ifp, NULL, -1, &mltaddr.sin6_addr) == 0) {
|
||||
imm = in6_joingroup(ifp, &mltaddr.sin6_addr, &error,
|
||||
delay); /* XXX jinmei */
|
||||
if (!imm) {
|
||||
nd6log((LOG_WARNING, "in6_update_ifa: "
|
||||
"addmulti failed for %s on %s "
|
||||
"(errno=%d)\n",
|
||||
ip6_sprintf(ip6buf, &mltaddr.sin6_addr),
|
||||
if_name(ifp), error));
|
||||
/* XXX not very fatal, go on... */
|
||||
} else {
|
||||
LIST_INSERT_HEAD(&ia->ia6_memberships,
|
||||
imm, i6mm_chain);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* join interface-local all-nodes address.
|
||||
* (ff01::1%ifN, and ff01::%ifN/32)
|
||||
*/
|
||||
mltaddr.sin6_addr = in6addr_nodelocal_allnodes;
|
||||
if ((error = in6_setscope(&mltaddr.sin6_addr, ifp, NULL))
|
||||
!= 0)
|
||||
goto cleanup; /* XXX: should not fail */
|
||||
/* XXX: again, do we really need the route? */
|
||||
rt = rtalloc1((struct sockaddr *)&mltaddr, 0, 0UL);
|
||||
if (rt) {
|
||||
if (memcmp(&mltaddr.sin6_addr,
|
||||
&((struct sockaddr_in6 *)rt_key(rt))->sin6_addr,
|
||||
MLTMASK_LEN)) {
|
||||
RTFREE_LOCKED(rt);
|
||||
rt = NULL;
|
||||
}
|
||||
}
|
||||
if (!rt) {
|
||||
error = rtrequest(RTM_ADD, (struct sockaddr *)&mltaddr,
|
||||
(struct sockaddr *)&ia->ia_addr,
|
||||
(struct sockaddr *)&mltmask, RTF_UP,
|
||||
(struct rtentry **)0);
|
||||
if (error)
|
||||
goto cleanup;
|
||||
} else
|
||||
RTFREE_LOCKED(rt);
|
||||
|
||||
imm = in6_joingroup(ifp, &mltaddr.sin6_addr, &error, 0);
|
||||
if (!imm) {
|
||||
nd6log((LOG_WARNING, "in6_update_ifa: "
|
||||
"addmulti failed for %s on %s "
|
||||
"(errno=%d)\n",
|
||||
ip6_sprintf(ip6buf, &mltaddr.sin6_addr),
|
||||
if_name(ifp), error));
|
||||
goto cleanup;
|
||||
}
|
||||
LIST_INSERT_HEAD(&ia->ia6_memberships, imm, i6mm_chain);
|
||||
#undef MLTMASK_LEN
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1312,15 +1313,143 @@ in6_update_ifa(struct ifnet *ifp, struct in6_aliasreq *ifra,
|
||||
return error;
|
||||
}
|
||||
|
||||
/*
|
||||
* Leave multicast groups. Factored out from in6_purgeaddr().
|
||||
* This entire work should only be done once, for the default FIB.
|
||||
*/
|
||||
static int
|
||||
in6_purgeaddr_mc(struct ifnet *ifp, struct in6_ifaddr *ia, struct ifaddr *ifa0)
|
||||
{
|
||||
struct sockaddr_in6 mltaddr, mltmask;
|
||||
struct in6_multi_mship *imm;
|
||||
struct rtentry *rt;
|
||||
int error;
|
||||
|
||||
/*
|
||||
* Leave from multicast groups we have joined for the interface.
|
||||
*/
|
||||
while ((imm = LIST_FIRST(&ia->ia6_memberships)) != NULL) {
|
||||
LIST_REMOVE(imm, i6mm_chain);
|
||||
in6_leavegroup(imm);
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove the link-local all-nodes address.
|
||||
*/
|
||||
bzero(&mltmask, sizeof(mltmask));
|
||||
mltmask.sin6_len = sizeof(struct sockaddr_in6);
|
||||
mltmask.sin6_family = AF_INET6;
|
||||
mltmask.sin6_addr = in6mask32;
|
||||
|
||||
bzero(&mltaddr, sizeof(mltaddr));
|
||||
mltaddr.sin6_len = sizeof(struct sockaddr_in6);
|
||||
mltaddr.sin6_family = AF_INET6;
|
||||
mltaddr.sin6_addr = in6addr_linklocal_allnodes;
|
||||
|
||||
if ((error = in6_setscope(&mltaddr.sin6_addr, ifp, NULL)) != 0)
|
||||
return (error);
|
||||
|
||||
rt = rtalloc1((struct sockaddr *)&mltaddr, 0, 0UL);
|
||||
if (rt != NULL && rt->rt_gateway != NULL &&
|
||||
(memcmp(&satosin6(rt->rt_gateway)->sin6_addr,
|
||||
&ia->ia_addr.sin6_addr,
|
||||
sizeof(ia->ia_addr.sin6_addr)) == 0)) {
|
||||
/*
|
||||
* If no more IPv6 address exists on this interface then
|
||||
* remove the multicast address route.
|
||||
*/
|
||||
if (ifa0 == NULL) {
|
||||
memcpy(&mltaddr.sin6_addr, &satosin6(rt_key(rt))->sin6_addr,
|
||||
sizeof(mltaddr.sin6_addr));
|
||||
RTFREE_LOCKED(rt);
|
||||
error = rtrequest(RTM_DELETE,
|
||||
(struct sockaddr *)&mltaddr,
|
||||
(struct sockaddr *)&ia->ia_addr,
|
||||
(struct sockaddr *)&mltmask, RTF_UP,
|
||||
(struct rtentry **)0);
|
||||
if (error)
|
||||
log(LOG_INFO, "%s: link-local all-nodes "
|
||||
"multicast address deletion error\n",
|
||||
__func__);
|
||||
} else {
|
||||
/*
|
||||
* Replace the gateway of the route.
|
||||
*/
|
||||
struct sockaddr_in6 sa;
|
||||
|
||||
bzero(&sa, sizeof(sa));
|
||||
sa.sin6_len = sizeof(struct sockaddr_in6);
|
||||
sa.sin6_family = AF_INET6;
|
||||
memcpy(&sa.sin6_addr, &satosin6(ifa0->ifa_addr)->sin6_addr,
|
||||
sizeof(sa.sin6_addr));
|
||||
in6_setscope(&sa.sin6_addr, ifa0->ifa_ifp, NULL);
|
||||
memcpy(rt->rt_gateway, &sa, sizeof(sa));
|
||||
RTFREE_LOCKED(rt);
|
||||
}
|
||||
} else {
|
||||
if (rt != NULL)
|
||||
RTFREE_LOCKED(rt);
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove the node-local all-nodes address.
|
||||
*/
|
||||
mltaddr.sin6_addr = in6addr_nodelocal_allnodes;
|
||||
if ((error = in6_setscope(&mltaddr.sin6_addr, ifp, NULL)) != 0)
|
||||
return (error);
|
||||
|
||||
rt = rtalloc1((struct sockaddr *)&mltaddr, 0, 0UL);
|
||||
if (rt != NULL && rt->rt_gateway != NULL &&
|
||||
(memcmp(&satosin6(rt->rt_gateway)->sin6_addr,
|
||||
&ia->ia_addr.sin6_addr,
|
||||
sizeof(ia->ia_addr.sin6_addr)) == 0)) {
|
||||
/*
|
||||
* If no more IPv6 address exists on this interface then
|
||||
* remove the multicast address route.
|
||||
*/
|
||||
if (ifa0 == NULL) {
|
||||
memcpy(&mltaddr.sin6_addr, &satosin6(rt_key(rt))->sin6_addr,
|
||||
sizeof(mltaddr.sin6_addr));
|
||||
|
||||
RTFREE_LOCKED(rt);
|
||||
error = rtrequest(RTM_DELETE,
|
||||
(struct sockaddr *)&mltaddr,
|
||||
(struct sockaddr *)&ia->ia_addr,
|
||||
(struct sockaddr *)&mltmask, RTF_UP,
|
||||
(struct rtentry **)0);
|
||||
if (error)
|
||||
log(LOG_INFO, "%s: node-local all-nodes"
|
||||
"multicast address deletion error\n",
|
||||
__func__);
|
||||
} else {
|
||||
/*
|
||||
* Replace the gateway of the route.
|
||||
*/
|
||||
struct sockaddr_in6 sa;
|
||||
|
||||
bzero(&sa, sizeof(sa));
|
||||
sa.sin6_len = sizeof(struct sockaddr_in6);
|
||||
sa.sin6_family = AF_INET6;
|
||||
memcpy(&sa.sin6_addr, &satosin6(ifa0->ifa_addr)->sin6_addr,
|
||||
sizeof(sa.sin6_addr));
|
||||
in6_setscope(&sa.sin6_addr, ifa0->ifa_ifp, NULL);
|
||||
memcpy(rt->rt_gateway, &sa, sizeof(sa));
|
||||
RTFREE_LOCKED(rt);
|
||||
}
|
||||
} else {
|
||||
if (rt != NULL)
|
||||
RTFREE_LOCKED(rt);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
in6_purgeaddr(struct ifaddr *ifa)
|
||||
{
|
||||
struct ifnet *ifp = ifa->ifa_ifp;
|
||||
struct in6_ifaddr *ia = (struct in6_ifaddr *) ifa;
|
||||
struct in6_multi_mship *imm;
|
||||
struct sockaddr_in6 mltaddr, mltmask;
|
||||
int plen, error;
|
||||
struct rtentry *rt;
|
||||
struct ifaddr *ifa0;
|
||||
|
||||
if (ifa->ifa_carp)
|
||||
@ -1362,121 +1491,9 @@ in6_purgeaddr(struct ifaddr *ifa)
|
||||
|
||||
in6_ifremloop(ifa);
|
||||
|
||||
/*
|
||||
* leave from multicast groups we have joined for the interface
|
||||
*/
|
||||
while ((imm = LIST_FIRST(&ia->ia6_memberships)) != NULL) {
|
||||
LIST_REMOVE(imm, i6mm_chain);
|
||||
in6_leavegroup(imm);
|
||||
}
|
||||
/* Leave multicast groups. */
|
||||
error = in6_purgeaddr_mc(ifp, ia, ifa0);
|
||||
|
||||
/*
|
||||
* remove the link-local all-nodes address
|
||||
*/
|
||||
bzero(&mltmask, sizeof(mltmask));
|
||||
mltmask.sin6_len = sizeof(struct sockaddr_in6);
|
||||
mltmask.sin6_family = AF_INET6;
|
||||
mltmask.sin6_addr = in6mask32;
|
||||
|
||||
bzero(&mltaddr, sizeof(mltaddr));
|
||||
mltaddr.sin6_len = sizeof(struct sockaddr_in6);
|
||||
mltaddr.sin6_family = AF_INET6;
|
||||
mltaddr.sin6_addr = in6addr_linklocal_allnodes;
|
||||
|
||||
if ((error = in6_setscope(&mltaddr.sin6_addr, ifp, NULL)) != 0)
|
||||
goto cleanup;
|
||||
|
||||
rt = rtalloc1((struct sockaddr *)&mltaddr, 0, 0UL);
|
||||
if (rt != NULL && rt->rt_gateway != NULL &&
|
||||
(memcmp(&satosin6(rt->rt_gateway)->sin6_addr,
|
||||
&ia->ia_addr.sin6_addr,
|
||||
sizeof(ia->ia_addr.sin6_addr)) == 0)) {
|
||||
/*
|
||||
* if no more IPv6 address exists on this interface
|
||||
* then remove the multicast address route
|
||||
*/
|
||||
if (ifa0 == NULL) {
|
||||
memcpy(&mltaddr.sin6_addr, &satosin6(rt_key(rt))->sin6_addr,
|
||||
sizeof(mltaddr.sin6_addr));
|
||||
RTFREE_LOCKED(rt);
|
||||
error = rtrequest(RTM_DELETE, (struct sockaddr *)&mltaddr,
|
||||
(struct sockaddr *)&ia->ia_addr,
|
||||
(struct sockaddr *)&mltmask, RTF_UP,
|
||||
(struct rtentry **)0);
|
||||
if (error)
|
||||
log(LOG_INFO, "in6_purgeaddr: link-local all-nodes"
|
||||
"multicast address deletion error\n");
|
||||
} else {
|
||||
/*
|
||||
* replace the gateway of the route
|
||||
*/
|
||||
struct sockaddr_in6 sa;
|
||||
|
||||
bzero(&sa, sizeof(sa));
|
||||
sa.sin6_len = sizeof(struct sockaddr_in6);
|
||||
sa.sin6_family = AF_INET6;
|
||||
memcpy(&sa.sin6_addr, &satosin6(ifa0->ifa_addr)->sin6_addr,
|
||||
sizeof(sa.sin6_addr));
|
||||
in6_setscope(&sa.sin6_addr, ifa0->ifa_ifp, NULL);
|
||||
memcpy(rt->rt_gateway, &sa, sizeof(sa));
|
||||
RTFREE_LOCKED(rt);
|
||||
}
|
||||
} else {
|
||||
if (rt != NULL)
|
||||
RTFREE_LOCKED(rt);
|
||||
}
|
||||
|
||||
/*
|
||||
* remove the node-local all-nodes address
|
||||
*/
|
||||
mltaddr.sin6_addr = in6addr_nodelocal_allnodes;
|
||||
if ((error = in6_setscope(&mltaddr.sin6_addr, ifp, NULL)) !=
|
||||
0)
|
||||
goto cleanup;
|
||||
|
||||
rt = rtalloc1((struct sockaddr *)&mltaddr, 0, 0UL);
|
||||
if (rt != NULL && rt->rt_gateway != NULL &&
|
||||
(memcmp(&satosin6(rt->rt_gateway)->sin6_addr,
|
||||
&ia->ia_addr.sin6_addr,
|
||||
sizeof(ia->ia_addr.sin6_addr)) == 0)) {
|
||||
/*
|
||||
* if no more IPv6 address exists on this interface
|
||||
* then remove the multicast address route
|
||||
*/
|
||||
if (ifa0 == NULL) {
|
||||
memcpy(&mltaddr.sin6_addr, &satosin6(rt_key(rt))->sin6_addr,
|
||||
sizeof(mltaddr.sin6_addr));
|
||||
|
||||
RTFREE_LOCKED(rt);
|
||||
error = rtrequest(RTM_DELETE, (struct sockaddr *)&mltaddr,
|
||||
(struct sockaddr *)&ia->ia_addr,
|
||||
(struct sockaddr *)&mltmask, RTF_UP,
|
||||
(struct rtentry **)0);
|
||||
|
||||
if (error)
|
||||
log(LOG_INFO, "in6_purgeaddr: node-local all-nodes"
|
||||
"multicast address deletion error\n");
|
||||
} else {
|
||||
/*
|
||||
* replace the gateway of the route
|
||||
*/
|
||||
struct sockaddr_in6 sa;
|
||||
|
||||
bzero(&sa, sizeof(sa));
|
||||
sa.sin6_len = sizeof(struct sockaddr_in6);
|
||||
sa.sin6_family = AF_INET6;
|
||||
memcpy(&sa.sin6_addr, &satosin6(ifa0->ifa_addr)->sin6_addr,
|
||||
sizeof(sa.sin6_addr));
|
||||
in6_setscope(&sa.sin6_addr, ifa0->ifa_ifp, NULL);
|
||||
memcpy(rt->rt_gateway, &sa, sizeof(sa));
|
||||
RTFREE_LOCKED(rt);
|
||||
}
|
||||
} else {
|
||||
if (rt != NULL)
|
||||
RTFREE_LOCKED(rt);
|
||||
}
|
||||
|
||||
cleanup:
|
||||
if (ifa0 != NULL)
|
||||
ifa_free(ifa0);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user