version 1.21, 2003/05/14 06:47:43 |
version 1.22, 2003/06/06 08:13:44 |
Line 97 __KERNEL_RCSID(0, "$NetBSD$"); |
|
Line 97 __KERNEL_RCSID(0, "$NetBSD$"); |
|
*/ |
*/ |
|
|
/* denotes that the MLD max response delay field specifies time in milliseconds */ |
/* denotes that the MLD max response delay field specifies time in milliseconds */ |
#define MLD6_TIMER_SCALE 1000 |
#define MLD_TIMER_SCALE 1000 |
/* |
/* |
* time between repetitions of a node's initial report of interest in a |
* time between repetitions of a node's initial report of interest in a |
* multicast address(in seconds) |
* multicast address(in seconds) |
*/ |
*/ |
#define MLD6_UNSOLICITED_REPORT_INTERVAL 10 |
#define MLD_UNSOLICITED_REPORT_INTERVAL 10 |
|
|
static struct ip6_pktopts ip6_opts; |
static struct ip6_pktopts ip6_opts; |
static int mld6_timers_are_running; |
static int mld_timers_are_running; |
/* XXX: These are necessary for KAME's link-local hack */ |
/* XXX: These are necessary for KAME's link-local hack */ |
static struct in6_addr mld6_all_nodes_linklocal = IN6ADDR_LINKLOCAL_ALLNODES_INIT; |
static struct in6_addr mld_all_nodes_linklocal = IN6ADDR_LINKLOCAL_ALLNODES_INIT; |
static struct in6_addr mld6_all_routers_linklocal = IN6ADDR_LINKLOCAL_ALLROUTERS_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 *)); |
|
|
|
|
struct ip6_hbh *hbh = (struct ip6_hbh *)hbh_buf; |
struct ip6_hbh *hbh = (struct ip6_hbh *)hbh_buf; |
u_int16_t rtalert_code = htons((u_int16_t)IP6OPT_RTALERT_MLD); |
u_int16_t rtalert_code = htons((u_int16_t)IP6OPT_RTALERT_MLD); |
|
|
mld6_timers_are_running = 0; |
mld_timers_are_running = 0; |
|
|
/* ip6h_nxt will be fill in later */ |
/* ip6h_nxt will be fill in later */ |
hbh->ip6h_len = 0; /* (8 >> 3) - 1 */ |
hbh->ip6h_len = 0; /* (8 >> 3) - 1 */ |
Line 149 mld6_start_listening(in6m) |
|
Line 149 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). |
*/ |
*/ |
mld6_all_nodes_linklocal.s6_addr16[1] = |
mld_all_nodes_linklocal.s6_addr16[1] = |
htons(in6m->in6m_ifp->if_index); /* XXX */ |
htons(in6m->in6m_ifp->if_index); /* XXX */ |
if (IN6_ARE_ADDR_EQUAL(&in6m->in6m_addr, &mld6_all_nodes_linklocal) || |
if (IN6_ARE_ADDR_EQUAL(&in6m->in6m_addr, &mld_all_nodes_linklocal) || |
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 = MLD6_OTHERLISTENER; |
in6m->in6m_state = MLD_OTHERLISTENER; |
} else { |
} else { |
mld6_sendpkt(in6m, MLD6_LISTENER_REPORT, NULL); |
mld6_sendpkt(in6m, MLD_LISTENER_REPORT, NULL); |
in6m->in6m_timer = |
in6m->in6m_timer = |
MLD6_RANDOM_DELAY(MLD6_UNSOLICITED_REPORT_INTERVAL * |
MLD_RANDOM_DELAY(MLD_UNSOLICITED_REPORT_INTERVAL * |
PR_FASTHZ); |
PR_FASTHZ); |
in6m->in6m_state = MLD6_IREPORTEDLAST; |
in6m->in6m_state = MLD_IREPORTEDLAST; |
mld6_timers_are_running = 1; |
mld_timers_are_running = 1; |
} |
} |
splx(s); |
splx(s); |
} |
} |
|
|
mld6_stop_listening(in6m) |
mld6_stop_listening(in6m) |
struct in6_multi *in6m; |
struct in6_multi *in6m; |
{ |
{ |
mld6_all_nodes_linklocal.s6_addr16[1] = |
mld_all_nodes_linklocal.s6_addr16[1] = |
htons(in6m->in6m_ifp->if_index); /* XXX */ |
htons(in6m->in6m_ifp->if_index); /* XXX */ |
mld6_all_routers_linklocal.s6_addr16[1] = |
mld_all_routers_linklocal.s6_addr16[1] = |
htons(in6m->in6m_ifp->if_index); /* XXX: necessary when mrouting */ |
htons(in6m->in6m_ifp->if_index); /* XXX: necessary when mrouting */ |
|
|
if (in6m->in6m_state == MLD6_IREPORTEDLAST && |
if (in6m->in6m_state == MLD_IREPORTEDLAST && |
(!IN6_ARE_ADDR_EQUAL(&in6m->in6m_addr, &mld6_all_nodes_linklocal)) && |
(!IN6_ARE_ADDR_EQUAL(&in6m->in6m_addr, &mld_all_nodes_linklocal)) && |
IPV6_ADDR_MC_SCOPE(&in6m->in6m_addr) > IPV6_ADDR_SCOPE_NODELOCAL) |
IPV6_ADDR_MC_SCOPE(&in6m->in6m_addr) > IPV6_ADDR_SCOPE_NODELOCAL) |
mld6_sendpkt(in6m, MLD6_LISTENER_DONE, |
mld6_sendpkt(in6m, MLD_LISTENER_DONE, |
&mld6_all_routers_linklocal); |
&mld_all_routers_linklocal); |
} |
} |
|
|
void |
void |
Line 188 mld6_input(m, off) |
|
Line 188 mld6_input(m, off) |
|
int off; |
int off; |
{ |
{ |
struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); |
struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); |
struct mld6_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_ifaddr *ia; |
struct in6_ifaddr *ia; |
int timer; /* timer value in the MLD query header */ |
int timer; /* timer value in the MLD query header */ |
|
|
IP6_EXTHDR_GET(mldh, struct mld6_hdr *, m, off, sizeof(*mldh)); |
IP6_EXTHDR_GET(mldh, struct mld_hdr *, m, off, sizeof(*mldh)); |
if (mldh == NULL) { |
if (mldh == NULL) { |
icmp6stat.icp6s_tooshort++; |
icmp6stat.icp6s_tooshort++; |
return; |
return; |
Line 205 mld6_input(m, off) |
|
Line 205 mld6_input(m, off) |
|
if (!IN6_IS_ADDR_LINKLOCAL(&ip6->ip6_src)) { |
if (!IN6_IS_ADDR_LINKLOCAL(&ip6->ip6_src)) { |
#if 0 |
#if 0 |
log(LOG_ERR, |
log(LOG_ERR, |
"mld6_input: src %s is not link-local (grp=%s)\n", |
"mld_input: src %s is not link-local (grp=%s)\n", |
ip6_sprintf(&ip6->ip6_src), |
ip6_sprintf(&ip6->ip6_src), |
ip6_sprintf(&mldh->mld6_addr)); |
ip6_sprintf(&mldh->mld_addr)); |
#endif |
#endif |
/* |
/* |
* spec (RFC2710) does not explicitly |
* spec (RFC2710) does not explicitly |
Line 226 mld6_input(m, off) |
|
Line 226 mld6_input(m, off) |
|
* In Delaying Listener state, our timer is running (in6m->in6m_timer) |
* In Delaying Listener state, our timer is running (in6m->in6m_timer) |
* In Idle Listener state, our timer is not running (in6m->in6m_timer==0) |
* In Idle Listener state, our timer is not running (in6m->in6m_timer==0) |
* |
* |
* The flag is in6m->in6m_state, it is set to MLD6_OTHERLISTENER if |
* The flag is in6m->in6m_state, it is set to MLD_OTHERLISTENER if |
* we have heard a report from another member, or MLD6_IREPORTEDLAST |
* we have heard a report from another member, or MLD_IREPORTEDLAST |
* if we sent the last report. |
* if we sent the last report. |
*/ |
*/ |
switch (mldh->mld6_type) { |
switch (mldh->mld_type) { |
case MLD6_LISTENER_QUERY: |
case MLD_LISTENER_QUERY: |
if (ifp->if_flags & IFF_LOOPBACK) |
if (ifp->if_flags & IFF_LOOPBACK) |
break; |
break; |
|
|
if (!IN6_IS_ADDR_UNSPECIFIED(&mldh->mld6_addr) && |
if (!IN6_IS_ADDR_UNSPECIFIED(&mldh->mld_addr) && |
!IN6_IS_ADDR_MULTICAST(&mldh->mld6_addr)) |
!IN6_IS_ADDR_MULTICAST(&mldh->mld_addr)) |
break; /* print error or log stat? */ |
break; /* print error or log stat? */ |
if (IN6_IS_ADDR_MC_LINKLOCAL(&mldh->mld6_addr)) |
if (IN6_IS_ADDR_MC_LINKLOCAL(&mldh->mld_addr)) |
mldh->mld6_addr.s6_addr16[1] = |
mldh->mld_addr.s6_addr16[1] = |
htons(ifp->if_index); /* XXX */ |
htons(ifp->if_index); /* XXX */ |
|
|
/* |
/* |
Line 262 mld6_input(m, off) |
|
Line 262 mld6_input(m, off) |
|
* the calculated value equals to zero when Max Response |
* the calculated value equals to zero when Max Response |
* Delay is positive. |
* Delay is positive. |
*/ |
*/ |
timer = ntohs(mldh->mld6_maxdelay)*PR_FASTHZ/MLD6_TIMER_SCALE; |
timer = ntohs(mldh->mld_maxdelay)*PR_FASTHZ/MLD_TIMER_SCALE; |
if (timer == 0 && mldh->mld6_maxdelay) |
if (timer == 0 && mldh->mld_maxdelay) |
timer = 1; |
timer = 1; |
mld6_all_nodes_linklocal.s6_addr16[1] = |
mld_all_nodes_linklocal.s6_addr16[1] = |
htons(ifp->if_index); /* XXX */ |
htons(ifp->if_index); /* XXX */ |
|
|
for (in6m = ia->ia6_multiaddrs.lh_first; |
for (in6m = ia->ia6_multiaddrs.lh_first; |
Line 273 mld6_input(m, off) |
|
Line 273 mld6_input(m, off) |
|
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, |
&mld6_all_nodes_linklocal) || |
&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->mld6_addr) || |
if (IN6_IS_ADDR_UNSPECIFIED(&mldh->mld_addr) || |
IN6_ARE_ADDR_EQUAL(&mldh->mld6_addr, |
IN6_ARE_ADDR_EQUAL(&mldh->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, MLD6_LISTENER_REPORT, |
mld6_sendpkt(in6m, MLD_LISTENER_REPORT, |
NULL); |
NULL); |
in6m->in6m_timer = 0; /* reset timer */ |
in6m->in6m_timer = 0; /* reset timer */ |
in6m->in6m_state = MLD6_IREPORTEDLAST; |
in6m->in6m_state = MLD_IREPORTEDLAST; |
} |
} |
else if (in6m->in6m_timer == 0 || /*idle state*/ |
else if (in6m->in6m_timer == 0 || /*idle state*/ |
in6m->in6m_timer > timer) { |
in6m->in6m_timer > timer) { |
in6m->in6m_timer = |
in6m->in6m_timer = |
MLD6_RANDOM_DELAY(timer); |
MLD_RANDOM_DELAY(timer); |
mld6_timers_are_running = 1; |
mld_timers_are_running = 1; |
} |
} |
} |
} |
} |
} |
|
|
if (IN6_IS_ADDR_MC_LINKLOCAL(&mldh->mld6_addr)) |
if (IN6_IS_ADDR_MC_LINKLOCAL(&mldh->mld_addr)) |
mldh->mld6_addr.s6_addr16[1] = 0; /* XXX */ |
mldh->mld_addr.s6_addr16[1] = 0; /* XXX */ |
break; |
break; |
case MLD6_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 |
* last person to send a report for this group. Reports |
* last person to send a report for this group. Reports |
Line 314 mld6_input(m, off) |
|
Line 314 mld6_input(m, off) |
|
if (m->m_flags & M_LOOP) /* XXX: grotty flag, but efficient */ |
if (m->m_flags & M_LOOP) /* XXX: grotty flag, but efficient */ |
break; |
break; |
|
|
if (!IN6_IS_ADDR_MULTICAST(&mldh->mld6_addr)) |
if (!IN6_IS_ADDR_MULTICAST(&mldh->mld_addr)) |
break; |
break; |
|
|
if (IN6_IS_ADDR_MC_LINKLOCAL(&mldh->mld6_addr)) |
if (IN6_IS_ADDR_MC_LINKLOCAL(&mldh->mld_addr)) |
mldh->mld6_addr.s6_addr16[1] = |
mldh->mld_addr.s6_addr16[1] = |
htons(ifp->if_index); /* XXX */ |
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->mld6_addr, ifp, in6m); |
IN6_LOOKUP_MULTI(mldh->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 = MLD6_OTHERLISTENER; /* clear flag */ |
in6m->in6m_state = MLD_OTHERLISTENER; /* clear flag */ |
} |
} |
|
|
if (IN6_IS_ADDR_MC_LINKLOCAL(&mldh->mld6_addr)) |
if (IN6_IS_ADDR_MC_LINKLOCAL(&mldh->mld_addr)) |
mldh->mld6_addr.s6_addr16[1] = 0; /* XXX */ |
mldh->mld_addr.s6_addr16[1] = 0; /* XXX */ |
break; |
break; |
default: /* this is impossible */ |
default: /* this is impossible */ |
#if 0 |
#if 0 |
Line 340 mld6_input(m, off) |
|
Line 340 mld6_input(m, off) |
|
* icmp6_input(). But we explicitly disabled this part |
* icmp6_input(). But we explicitly disabled this part |
* just in case. |
* just in case. |
*/ |
*/ |
log(LOG_ERR, "mld6_input: illegal type(%d)", mldh->mld6_type); |
log(LOG_ERR, "mld_input: illegal type(%d)", mldh->mld6_type); |
#endif |
#endif |
break; |
break; |
} |
} |
Line 358 mld6_fasttimeo() |
|
Line 358 mld6_fasttimeo() |
|
* Quick check to see if any work needs to be done, in order |
* Quick check to see if any work needs to be done, in order |
* to minimize the overhead of fasttimo processing. |
* to minimize the overhead of fasttimo processing. |
*/ |
*/ |
if (!mld6_timers_are_running) |
if (!mld_timers_are_running) |
return; |
return; |
|
|
s = splsoftnet(); |
s = splsoftnet(); |
mld6_timers_are_running = 0; |
mld_timers_are_running = 0; |
IN6_FIRST_MULTI(step, in6m); |
IN6_FIRST_MULTI(step, in6m); |
while (in6m != NULL) { |
while (in6m != NULL) { |
if (in6m->in6m_timer == 0) { |
if (in6m->in6m_timer == 0) { |
/* do nothing */ |
/* do nothing */ |
} else if (--in6m->in6m_timer == 0) { |
} else if (--in6m->in6m_timer == 0) { |
mld6_sendpkt(in6m, MLD6_LISTENER_REPORT, NULL); |
mld6_sendpkt(in6m, MLD_LISTENER_REPORT, NULL); |
in6m->in6m_state = MLD6_IREPORTEDLAST; |
in6m->in6m_state = MLD_IREPORTEDLAST; |
} else { |
} else { |
mld6_timers_are_running = 1; |
mld_timers_are_running = 1; |
} |
} |
IN6_NEXT_MULTI(step, in6m); |
IN6_NEXT_MULTI(step, in6m); |
} |
} |
Line 385 mld6_sendpkt(in6m, type, dst) |
|
Line 385 mld6_sendpkt(in6m, type, dst) |
|
const struct in6_addr *dst; |
const struct in6_addr *dst; |
{ |
{ |
struct mbuf *mh, *md; |
struct mbuf *mh, *md; |
struct mld6_hdr *mldh; |
struct mld_hdr *mldh; |
struct ip6_hdr *ip6; |
struct ip6_hdr *ip6; |
struct ip6_moptions im6o; |
struct ip6_moptions im6o; |
struct in6_ifaddr *ia; |
struct in6_ifaddr *ia; |
Line 420 mld6_sendpkt(in6m, type, dst) |
|
Line 420 mld6_sendpkt(in6m, type, dst) |
|
mh->m_next = md; |
mh->m_next = md; |
|
|
mh->m_pkthdr.rcvif = NULL; |
mh->m_pkthdr.rcvif = NULL; |
mh->m_pkthdr.len = sizeof(struct ip6_hdr) + sizeof(struct mld6_hdr); |
mh->m_pkthdr.len = sizeof(struct ip6_hdr) + sizeof(struct mld_hdr); |
mh->m_len = sizeof(struct ip6_hdr); |
mh->m_len = sizeof(struct ip6_hdr); |
MH_ALIGN(mh, sizeof(struct ip6_hdr)); |
MH_ALIGN(mh, sizeof(struct ip6_hdr)); |
|
|
Line 436 mld6_sendpkt(in6m, type, dst) |
|
Line 436 mld6_sendpkt(in6m, type, dst) |
|
ip6->ip6_dst = dst ? *dst : in6m->in6m_addr; |
ip6->ip6_dst = dst ? *dst : in6m->in6m_addr; |
|
|
/* fill in the MLD header */ |
/* fill in the MLD header */ |
md->m_len = sizeof(struct mld6_hdr); |
md->m_len = sizeof(struct mld_hdr); |
mldh = mtod(md, struct mld6_hdr *); |
mldh = mtod(md, struct mld_hdr *); |
mldh->mld6_type = type; |
mldh->mld_type = type; |
mldh->mld6_code = 0; |
mldh->mld_code = 0; |
mldh->mld6_cksum = 0; |
mldh->mld_cksum = 0; |
/* XXX: we assume the function will not be called for query messages */ |
/* XXX: we assume the function will not be called for query messages */ |
mldh->mld6_maxdelay = 0; |
mldh->mld_maxdelay = 0; |
mldh->mld6_reserved = 0; |
mldh->mld_reserved = 0; |
mldh->mld6_addr = in6m->in6m_addr; |
mldh->mld_addr = in6m->in6m_addr; |
if (IN6_IS_ADDR_MC_LINKLOCAL(&mldh->mld6_addr)) |
if (IN6_IS_ADDR_MC_LINKLOCAL(&mldh->mld_addr)) |
mldh->mld6_addr.s6_addr16[1] = 0; /* XXX */ |
mldh->mld_addr.s6_addr16[1] = 0; /* XXX */ |
mldh->mld6_cksum = in6_cksum(mh, IPPROTO_ICMPV6, |
mldh->mld_cksum = in6_cksum(mh, IPPROTO_ICMPV6, sizeof(struct ip6_hdr), |
sizeof(struct ip6_hdr), |
sizeof(struct mld_hdr)); |
sizeof(struct mld6_hdr)); |
|
|
|
/* construct multicast option */ |
/* construct multicast option */ |
bzero(&im6o, sizeof(im6o)); |
bzero(&im6o, sizeof(im6o)); |
Line 466 mld6_sendpkt(in6m, type, dst) |
|
Line 465 mld6_sendpkt(in6m, type, dst) |
|
icmp6stat.icp6s_outhist[type]++; |
icmp6stat.icp6s_outhist[type]++; |
icmp6_ifstat_inc(ifp, ifs6_out_msg); |
icmp6_ifstat_inc(ifp, ifs6_out_msg); |
switch (type) { |
switch (type) { |
case MLD6_LISTENER_QUERY: |
case MLD_LISTENER_QUERY: |
icmp6_ifstat_inc(ifp, ifs6_out_mldquery); |
icmp6_ifstat_inc(ifp, ifs6_out_mldquery); |
break; |
break; |
case MLD6_LISTENER_REPORT: |
case MLD_LISTENER_REPORT: |
icmp6_ifstat_inc(ifp, ifs6_out_mldreport); |
icmp6_ifstat_inc(ifp, ifs6_out_mldreport); |
break; |
break; |
case MLD6_LISTENER_DONE: |
case MLD_LISTENER_DONE: |
icmp6_ifstat_inc(ifp, ifs6_out_mlddone); |
icmp6_ifstat_inc(ifp, ifs6_out_mlddone); |
break; |
break; |
} |
} |