version 1.26.10.1, 2005/03/19 08:36:41 |
version 1.28.2.1, 2006/02/01 14:52:42 |
Line 119 __KERNEL_RCSID(0, "$NetBSD$"); |
|
Line 119 __KERNEL_RCSID(0, "$NetBSD$"); |
|
#include <netinet/in_var.h> |
#include <netinet/in_var.h> |
#include <netinet/ip6.h> |
#include <netinet/ip6.h> |
#include <netinet6/ip6_var.h> |
#include <netinet6/ip6_var.h> |
|
#include <netinet6/scope6_var.h> |
#include <netinet/icmp6.h> |
#include <netinet/icmp6.h> |
#include <netinet6/mld6_var.h> |
#include <netinet6/mld6_var.h> |
|
|
Line 138 __KERNEL_RCSID(0, "$NetBSD$"); |
|
Line 139 __KERNEL_RCSID(0, "$NetBSD$"); |
|
|
|
static struct ip6_pktopts ip6_opts; |
static struct ip6_pktopts ip6_opts; |
static int mld_timers_are_running; |
static int mld_timers_are_running; |
/* XXX: These are necessary for KAME's link-local hack */ |
|
static struct in6_addr mld_all_nodes_linklocal = IN6ADDR_LINKLOCAL_ALLNODES_INIT; |
|
static struct in6_addr mld_all_routers_linklocal = IN6ADDR_LINKLOCAL_ALLROUTERS_INIT; |
|
|
|
static void mld6_sendpkt __P((struct in6_multi *, int, const struct in6_addr *)); |
static void mld6_sendpkt __P((struct in6_multi *, int, const struct in6_addr *)); |
|
|
|
|
mld6_start_listening(in6m) |
mld6_start_listening(in6m) |
struct in6_multi *in6m; |
struct in6_multi *in6m; |
{ |
{ |
|
struct in6_addr all_in6; |
|
|
/* |
/* |
* RFC2710 page 10: |
* RFC2710 page 10: |
* The node never sends a Report or Done for the link-scope all-nodes |
* The node never sends a Report or Done for the link-scope all-nodes |
Line 179 mld6_start_listening(in6m) |
|
Line 179 mld6_start_listening(in6m) |
|
* MLD messages are never sent for multicast addresses whose scope is 0 |
* MLD messages are never sent for multicast addresses whose scope is 0 |
* (reserved) or 1 (node-local). |
* (reserved) or 1 (node-local). |
*/ |
*/ |
mld_all_nodes_linklocal.s6_addr16[1] = |
all_in6 = in6addr_linklocal_allnodes; |
htons(in6m->in6m_ifp->if_index); /* XXX */ |
if (in6_setscope(&all_in6, in6m->in6m_ifp, NULL)) { |
if (IN6_ARE_ADDR_EQUAL(&in6m->in6m_addr, &mld_all_nodes_linklocal) || |
/* XXX: this should not happen! */ |
|
in6m->in6m_timer = 0; |
|
in6m->in6m_state = MLD_OTHERLISTENER; |
|
} |
|
if (IN6_ARE_ADDR_EQUAL(&in6m->in6m_addr, &all_in6) || |
IPV6_ADDR_MC_SCOPE(&in6m->in6m_addr) < IPV6_ADDR_SCOPE_LINKLOCAL) { |
IPV6_ADDR_MC_SCOPE(&in6m->in6m_addr) < IPV6_ADDR_SCOPE_LINKLOCAL) { |
in6m->in6m_timer = 0; |
in6m->in6m_timer = 0; |
in6m->in6m_state = MLD_OTHERLISTENER; |
in6m->in6m_state = MLD_OTHERLISTENER; |
|
|
mld6_stop_listening(in6m) |
mld6_stop_listening(in6m) |
struct in6_multi *in6m; |
struct in6_multi *in6m; |
{ |
{ |
mld_all_nodes_linklocal.s6_addr16[1] = |
struct in6_addr allnode, allrouter; |
htons(in6m->in6m_ifp->if_index); /* XXX */ |
|
mld_all_routers_linklocal.s6_addr16[1] = |
allnode = in6addr_linklocal_allnodes; |
htons(in6m->in6m_ifp->if_index); /* XXX: necessary when mrouting */ |
if (in6_setscope(&allnode, in6m->in6m_ifp, NULL)) { |
|
/* XXX: this should not happen! */ |
|
return; |
|
} |
|
allrouter = in6addr_linklocal_allrouters; |
|
if (in6_setscope(&allrouter, in6m->in6m_ifp, NULL)) { |
|
/* XXX impossible */ |
|
return; |
|
} |
|
|
if (in6m->in6m_state == MLD_IREPORTEDLAST && |
if (in6m->in6m_state == MLD_IREPORTEDLAST && |
(!IN6_ARE_ADDR_EQUAL(&in6m->in6m_addr, &mld_all_nodes_linklocal)) && |
(!IN6_ARE_ADDR_EQUAL(&in6m->in6m_addr, &allnode)) && |
IPV6_ADDR_MC_SCOPE(&in6m->in6m_addr) > IPV6_ADDR_SCOPE_NODELOCAL) |
IPV6_ADDR_MC_SCOPE(&in6m->in6m_addr) > |
mld6_sendpkt(in6m, MLD_LISTENER_DONE, |
IPV6_ADDR_SCOPE_INTFACELOCAL) { |
&mld_all_routers_linklocal); |
mld6_sendpkt(in6m, MLD_LISTENER_DONE, &allrouter); |
|
} |
} |
} |
|
|
void |
void |
Line 220 mld6_input(m, off) |
|
Line 233 mld6_input(m, off) |
|
struct mld_hdr *mldh; |
struct mld_hdr *mldh; |
struct ifnet *ifp = m->m_pkthdr.rcvif; |
struct ifnet *ifp = m->m_pkthdr.rcvif; |
struct in6_multi *in6m; |
struct in6_multi *in6m; |
|
struct in6_addr mld_addr, all_in6; |
struct in6_ifaddr *ia; |
struct in6_ifaddr *ia; |
int timer; /* timer value in the MLD query header */ |
int timer; /* timer value in the MLD query header */ |
|
|
Line 249 mld6_input(m, off) |
|
Line 263 mld6_input(m, off) |
|
} |
} |
|
|
/* |
/* |
|
* make a copy for local work (in6_setscope() may modify the 1st arg) |
|
*/ |
|
mld_addr = mldh->mld_addr; |
|
if (in6_setscope(&mld_addr, ifp, NULL)) { |
|
/* XXX: this should not happen! */ |
|
m_free(m); |
|
return; |
|
} |
|
|
|
/* |
* In the MLD6 specification, there are 3 states and a flag. |
* In the MLD6 specification, there are 3 states and a flag. |
* |
* |
* In Non-Listener state, we simply don't have a membership record. |
* In Non-Listener state, we simply don't have a membership record. |
Line 264 mld6_input(m, off) |
|
Line 288 mld6_input(m, off) |
|
if (ifp->if_flags & IFF_LOOPBACK) |
if (ifp->if_flags & IFF_LOOPBACK) |
break; |
break; |
|
|
if (!IN6_IS_ADDR_UNSPECIFIED(&mldh->mld_addr) && |
if (!IN6_IS_ADDR_UNSPECIFIED(&mld_addr) && |
!IN6_IS_ADDR_MULTICAST(&mldh->mld_addr)) |
!IN6_IS_ADDR_MULTICAST(&mld_addr)) |
break; /* print error or log stat? */ |
break; /* print error or log stat? */ |
if (IN6_IS_ADDR_MC_LINKLOCAL(&mldh->mld_addr)) |
|
mldh->mld_addr.s6_addr16[1] = |
all_in6 = in6addr_linklocal_allnodes; |
htons(ifp->if_index); /* XXX */ |
if (in6_setscope(&all_in6, ifp, NULL)) { |
|
/* XXX: this should not happen! */ |
|
break; |
|
} |
|
|
/* |
/* |
* - Start the timers in all of our membership records |
* - Start the timers in all of our membership records |
Line 294 mld6_input(m, off) |
|
Line 321 mld6_input(m, off) |
|
timer = ntohs(mldh->mld_maxdelay)*PR_FASTHZ/MLD_TIMER_SCALE; |
timer = ntohs(mldh->mld_maxdelay)*PR_FASTHZ/MLD_TIMER_SCALE; |
if (timer == 0 && mldh->mld_maxdelay) |
if (timer == 0 && mldh->mld_maxdelay) |
timer = 1; |
timer = 1; |
mld_all_nodes_linklocal.s6_addr16[1] = |
|
htons(ifp->if_index); /* XXX */ |
|
|
|
for (in6m = ia->ia6_multiaddrs.lh_first; |
for (in6m = ia->ia6_multiaddrs.lh_first; |
in6m; |
in6m; |
in6m = in6m->in6m_entry.le_next) |
in6m = in6m->in6m_entry.le_next) |
{ |
{ |
if (IN6_ARE_ADDR_EQUAL(&in6m->in6m_addr, |
if (IN6_ARE_ADDR_EQUAL(&in6m->in6m_addr, &all_in6) || |
&mld_all_nodes_linklocal) || |
|
IPV6_ADDR_MC_SCOPE(&in6m->in6m_addr) < |
IPV6_ADDR_MC_SCOPE(&in6m->in6m_addr) < |
IPV6_ADDR_SCOPE_LINKLOCAL) |
IPV6_ADDR_SCOPE_LINKLOCAL) |
continue; |
continue; |
|
|
if (IN6_IS_ADDR_UNSPECIFIED(&mldh->mld_addr) || |
if (IN6_IS_ADDR_UNSPECIFIED(&mld_addr) || |
IN6_ARE_ADDR_EQUAL(&mldh->mld_addr, |
IN6_ARE_ADDR_EQUAL(&mld_addr, &in6m->in6m_addr)) { |
&in6m->in6m_addr)) |
|
{ |
|
if (timer == 0) { |
if (timer == 0) { |
/* send a report immediately */ |
/* send a report immediately */ |
mld6_sendpkt(in6m, MLD_LISTENER_REPORT, |
mld6_sendpkt(in6m, MLD_LISTENER_REPORT, |
Line 326 mld6_input(m, off) |
|
Line 348 mld6_input(m, off) |
|
} |
} |
} |
} |
} |
} |
|
|
if (IN6_IS_ADDR_MC_LINKLOCAL(&mldh->mld_addr)) |
|
mldh->mld_addr.s6_addr16[1] = 0; /* XXX */ |
|
break; |
break; |
|
|
case MLD_LISTENER_REPORT: |
case MLD_LISTENER_REPORT: |
/* |
/* |
* For fast leave to work, we have to know that we are the |
* For fast leave to work, we have to know that we are the |
Line 346 mld6_input(m, off) |
|
Line 366 mld6_input(m, off) |
|
if (!IN6_IS_ADDR_MULTICAST(&mldh->mld_addr)) |
if (!IN6_IS_ADDR_MULTICAST(&mldh->mld_addr)) |
break; |
break; |
|
|
if (IN6_IS_ADDR_MC_LINKLOCAL(&mldh->mld_addr)) |
|
mldh->mld_addr.s6_addr16[1] = |
|
htons(ifp->if_index); /* XXX */ |
|
/* |
/* |
* If we belong to the group being reported, stop |
* If we belong to the group being reported, stop |
* our timer for that group. |
* our timer for that group. |
*/ |
*/ |
IN6_LOOKUP_MULTI(mldh->mld_addr, ifp, in6m); |
IN6_LOOKUP_MULTI(mld_addr, ifp, in6m); |
if (in6m) { |
if (in6m) { |
in6m->in6m_timer = 0; /* transit to idle state */ |
in6m->in6m_timer = 0; /* transit to idle state */ |
in6m->in6m_state = MLD_OTHERLISTENER; /* clear flag */ |
in6m->in6m_state = MLD_OTHERLISTENER; /* clear flag */ |
} |
} |
|
|
if (IN6_IS_ADDR_MC_LINKLOCAL(&mldh->mld_addr)) |
|
mldh->mld_addr.s6_addr16[1] = 0; /* XXX */ |
|
break; |
break; |
default: /* this is impossible */ |
default: /* this is impossible */ |
#if 0 |
#if 0 |
Line 474 mld6_sendpkt(in6m, type, dst) |
|
Line 488 mld6_sendpkt(in6m, type, dst) |
|
mldh->mld_maxdelay = 0; |
mldh->mld_maxdelay = 0; |
mldh->mld_reserved = 0; |
mldh->mld_reserved = 0; |
mldh->mld_addr = in6m->in6m_addr; |
mldh->mld_addr = in6m->in6m_addr; |
if (IN6_IS_ADDR_MC_LINKLOCAL(&mldh->mld_addr)) |
in6_clearscope(&mldh->mld_addr); /* XXX */ |
mldh->mld_addr.s6_addr16[1] = 0; /* XXX */ |
|
mldh->mld_cksum = in6_cksum(mh, IPPROTO_ICMPV6, sizeof(struct ip6_hdr), |
mldh->mld_cksum = in6_cksum(mh, IPPROTO_ICMPV6, sizeof(struct ip6_hdr), |
sizeof(struct mld_hdr)); |
sizeof(struct mld_hdr)); |
|
|