Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files. =================================================================== RCS file: /ftp/cvs/cvsroot/src/sys/netinet6/mld6.c,v rcsdiff: /ftp/cvs/cvsroot/src/sys/netinet6/mld6.c,v: warning: Unknown phrases like `commitid ...;' are present. retrieving revision 1.10 retrieving revision 1.13.2.6 diff -u -p -r1.10 -r1.13.2.6 --- src/sys/netinet6/mld6.c 2000/02/06 12:49:47 1.10 +++ src/sys/netinet6/mld6.c 2002/06/20 03:49:27 1.13.2.6 @@ -1,9 +1,10 @@ -/* $NetBSD: mld6.c,v 1.10 2000/02/06 12:49:47 itojun Exp $ */ +/* $NetBSD: mld6.c,v 1.13.2.6 2002/06/20 03:49:27 nathanw Exp $ */ +/* $KAME: mld6.c,v 1.25 2001/01/16 14:14:18 itojun Exp $ */ /* * Copyright (C) 1998 WIDE Project. * All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -15,7 +16,7 @@ * 3. Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. - * + * * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE @@ -68,8 +69,10 @@ * @(#)igmp.c 8.1 (Berkeley) 7/19/93 */ +#include +__KERNEL_RCSID(0, "$NetBSD: mld6.c,v 1.13.2.6 2002/06/20 03:49:27 nathanw Exp $"); + #include "opt_inet.h" -#include "opt_ipsec.h" #include #include @@ -119,7 +122,7 @@ mld6_init() mld6_timers_are_running = 0; /* ip6h_nxt will be fill in later */ - hbh->ip6h_len = 0; /* (8 >> 3) - 1*/ + hbh->ip6h_len = 0; /* (8 >> 3) - 1 */ /* XXX: grotty hard coding... */ hbh_buf[2] = IP6OPT_PADN; /* 2 byte padding */ @@ -140,22 +143,23 @@ mld6_start_listening(in6m) int s = splsoftnet(); /* - * (draft-ietf-ipngwg-mld, page 10) + * RFC2710 page 10: * The node never sends a Report or Done for the link-scope all-nodes * address. * MLD messages are never sent for multicast addresses whose scope is 0 * (reserved) or 1 (node-local). */ mld6_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) || IPV6_ADDR_MC_SCOPE(&in6m->in6m_addr) < IPV6_ADDR_SCOPE_LINKLOCAL) { in6m->in6m_timer = 0; in6m->in6m_state = MLD6_OTHERLISTENER; } else { mld6_sendpkt(in6m, MLD6_LISTENER_REPORT, NULL); - in6m->in6m_timer = MLD6_RANDOM_DELAY( - MLD6_UNSOLICITED_REPORT_INTERVAL * PR_FASTHZ); + in6m->in6m_timer = + MLD6_RANDOM_DELAY(MLD6_UNSOLICITED_REPORT_INTERVAL * + PR_FASTHZ); in6m->in6m_state = MLD6_IREPORTEDLAST; mld6_timers_are_running = 1; } @@ -167,15 +171,15 @@ mld6_stop_listening(in6m) struct in6_multi *in6m; { mld6_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] = - 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 && (!IN6_ARE_ADDR_EQUAL(&in6m->in6m_addr, &mld6_all_nodes_linklocal)) && IPV6_ADDR_MC_SCOPE(&in6m->in6m_addr) > IPV6_ADDR_SCOPE_NODELOCAL) mld6_sendpkt(in6m, MLD6_LISTENER_DONE, - &mld6_all_routers_linklocal); + &mld6_all_routers_linklocal); } void @@ -184,22 +188,39 @@ mld6_input(m, off) int off; { struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); - struct mld6_hdr *mldh = (struct mld6_hdr *)(mtod(m, caddr_t) + off); + struct mld6_hdr *mldh; struct ifnet *ifp = m->m_pkthdr.rcvif; struct in6_multi *in6m; struct in6_ifaddr *ia; int timer; /* timer value in the MLD query header */ +#ifndef PULLDOWN_TEST + IP6_EXTHDR_CHECK(m, off, sizeof(*mldh),); + mldh = (struct mld6_hdr *)(mtod(m, caddr_t) + off); +#else + IP6_EXTHDR_GET(mldh, struct mld6_hdr *, m, off, sizeof(*mldh)); + if (mldh == NULL) { + icmp6stat.icp6s_tooshort++; + return; + } +#endif + /* source address validation */ + ip6 = mtod(m, struct ip6_hdr *);/* in case mpullup */ if (!IN6_IS_ADDR_LINKLOCAL(&ip6->ip6_src)) { +#if 0 log(LOG_ERR, - "mld6_input: src %s is not link-local\n", - ip6_sprintf(&ip6->ip6_src)); + "mld6_input: src %s is not link-local (grp=%s)\n", + ip6_sprintf(&ip6->ip6_src), + ip6_sprintf(&mldh->mld6_addr)); +#endif /* - * spec(draft-ietf-ipngwg-mld) does not explicitly + * spec (RFC2710) does not explicitly * specify to discard the packet from a non link-local * source address. But we believe it's expected to do so. + * XXX: do we have to allow :: as source? */ + m_freem(m); return; } @@ -214,44 +235,44 @@ mld6_input(m, off) * we have heard a report from another member, or MLD6_IREPORTEDLAST * if we sent the last report. */ - switch(mldh->mld6_type) { + switch (mldh->mld6_type) { case MLD6_LISTENER_QUERY: if (ifp->if_flags & IFF_LOOPBACK) break; if (!IN6_IS_ADDR_UNSPECIFIED(&mldh->mld6_addr) && - !IN6_IS_ADDR_MULTICAST(&mldh->mld6_addr)) + !IN6_IS_ADDR_MULTICAST(&mldh->mld6_addr)) break; /* print error or log stat? */ if (IN6_IS_ADDR_MC_LINKLOCAL(&mldh->mld6_addr)) mldh->mld6_addr.s6_addr16[1] = - htons(ifp->if_index); /* XXX */ + htons(ifp->if_index); /* XXX */ /* - * - Start the timers in all of our membership records - * that the query applies to for the interface on - * which the query arrived excl. those that belong - * to the "all-nodes" group (ff02::1). - * - Restart any timer that is already running but has - * A value longer than the requested timeout. - * - Use the value specified in the query message as - * the maximum timeout. - */ + * - Start the timers in all of our membership records + * that the query applies to for the interface on + * which the query arrived excl. those that belong + * to the "all-nodes" group (ff02::1). + * - Restart any timer that is already running but has + * A value longer than the requested timeout. + * - Use the value specified in the query message as + * the maximum timeout. + */ IFP_TO_IA6(ifp, ia); if (ia == NULL) break; /* - * XXX: System timer resolution is too low to handle Max - * Response Delay, so set 1 to the internal timer even if - * the calculated value equals to zero when Max Response - * Delay is positive. - */ + * XXX: System timer resolution is too low to handle Max + * Response Delay, so set 1 to the internal timer even if + * the calculated value equals to zero when Max Response + * Delay is positive. + */ timer = ntohs(mldh->mld6_maxdelay)*PR_FASTHZ/MLD6_TIMER_SCALE; if (timer == 0 && mldh->mld6_maxdelay) timer = 1; mld6_all_nodes_linklocal.s6_addr16[1] = htons(ifp->if_index); /* XXX */ - + for (in6m = ia->ia6_multiaddrs.lh_first; in6m; in6m = in6m->in6m_entry.le_next) @@ -269,14 +290,14 @@ mld6_input(m, off) if (timer == 0) { /* send a report immediately */ mld6_sendpkt(in6m, MLD6_LISTENER_REPORT, - NULL); + NULL); in6m->in6m_timer = 0; /* reset timer */ in6m->in6m_state = MLD6_IREPORTEDLAST; } else if (in6m->in6m_timer == 0 || /*idle state*/ - in6m->in6m_timer > timer) { + in6m->in6m_timer > timer) { in6m->in6m_timer = - MLD6_RANDOM_DELAY(timer); + MLD6_RANDOM_DELAY(timer); mld6_timers_are_running = 1; } } @@ -287,14 +308,14 @@ mld6_input(m, off) break; case MLD6_LISTENER_REPORT: /* - * For fast leave to work, we have to know that we are the - * last person to send a report for this group. Reports - * can potentially get looped back if we are a multicast - * router, so discard reports sourced by me. - * Note that it is impossible to check IFF_LOOPBACK flag of - * ifp for this purpose, since ip6_mloopback pass the physical - * interface to looutput. - */ + * For fast leave to work, we have to know that we are the + * last person to send a report for this group. Reports + * can potentially get looped back if we are a multicast + * router, so discard reports sourced by me. + * Note that it is impossible to check IFF_LOOPBACK flag of + * ifp for this purpose, since ip6_mloopback pass the physical + * interface to looutput. + */ if (m->m_flags & M_LOOP) /* XXX: grotty flag, but efficient */ break; @@ -305,9 +326,9 @@ mld6_input(m, off) mldh->mld6_addr.s6_addr16[1] = htons(ifp->if_index); /* XXX */ /* - * If we belong to the group being reported, stop - * our timer for that group. - */ + * If we belong to the group being reported, stop + * our timer for that group. + */ IN6_LOOKUP_MULTI(mldh->mld6_addr, ifp, in6m); if (in6m) { in6m->in6m_timer = 0; /* transit to idle state */ @@ -318,18 +339,26 @@ mld6_input(m, off) mldh->mld6_addr.s6_addr16[1] = 0; /* XXX */ break; default: /* this is impossible */ +#if 0 + /* + * this case should be impossible because of filtering in + * icmp6_input(). But we explicitly disabled this part + * just in case. + */ log(LOG_ERR, "mld6_input: illegal type(%d)", mldh->mld6_type); +#endif break; } + + m_freem(m); } void mld6_fasttimeo() { - register struct in6_multi *in6m; + struct in6_multi *in6m; struct in6_multistep step; int s; - /* * Quick check to see if any work needs to be done, in order * to minimize the overhead of fasttimo processing. @@ -366,14 +395,19 @@ mld6_sendpkt(in6m, type, dst) struct ip6_moptions im6o; struct in6_ifaddr *ia; struct ifnet *ifp = in6m->in6m_ifp; - struct ifnet *outif = NULL; + int ignflags; /* * At first, find a link local address on the outgoing interface * to use as the source address of the MLD packet. + * We do not reject tentative addresses for MLD report to deal with + * the case where we first join a link-local address. */ - if ((ia = in6ifa_ifpforlinklocal(ifp)) == NULL) + ignflags = (IN6_IFF_NOTREADY|IN6_IFF_ANYCAST) & ~IN6_IFF_TENTATIVE; + if ((ia = in6ifa_ifpforlinklocal(ifp, ignflags)) == NULL) return; + if ((ia->ia6_flags & IN6_IFF_TENTATIVE)) + ia = NULL; /* * Allocate mbufs to store ip6 header and MLD header. @@ -390,9 +424,7 @@ mld6_sendpkt(in6m, type, dst) } mh->m_next = md; -#ifdef IPSEC mh->m_pkthdr.rcvif = NULL; -#endif mh->m_pkthdr.len = sizeof(struct ip6_hdr) + sizeof(struct mld6_hdr); mh->m_len = sizeof(struct ip6_hdr); MH_ALIGN(mh, sizeof(struct ip6_hdr)); @@ -405,7 +437,7 @@ mld6_sendpkt(in6m, type, dst) /* ip6_plen will be set later */ ip6->ip6_nxt = IPPROTO_ICMPV6; /* ip6_hlim will be set by im6o.im6o_multicast_hlim */ - ip6->ip6_src = ia->ia_addr.sin6_addr; + ip6->ip6_src = ia ? ia->ia_addr.sin6_addr : in6addr_any; ip6->ip6_dst = dst ? *dst : in6m->in6m_addr; /* fill in the MLD header */ @@ -420,8 +452,9 @@ mld6_sendpkt(in6m, type, dst) mldh->mld6_addr = in6m->in6m_addr; if (IN6_IS_ADDR_MC_LINKLOCAL(&mldh->mld6_addr)) mldh->mld6_addr.s6_addr16[1] = 0; /* XXX */ - mldh->mld6_cksum = in6_cksum(mh, IPPROTO_ICMPV6, sizeof(struct ip6_hdr), - sizeof(struct mld6_hdr)); + mldh->mld6_cksum = in6_cksum(mh, IPPROTO_ICMPV6, + sizeof(struct ip6_hdr), + sizeof(struct mld6_hdr)); /* construct multicast option */ bzero(&im6o, sizeof(im6o)); @@ -436,20 +469,18 @@ mld6_sendpkt(in6m, type, dst) /* increment output statictics */ icmp6stat.icp6s_outhist[type]++; - - ip6_output(mh, &ip6_opts, NULL, 0, &im6o, &outif); - if (outif) { - icmp6_ifstat_inc(outif, ifs6_out_msg); - switch(type) { - case MLD6_LISTENER_QUERY: - icmp6_ifstat_inc(outif, ifs6_out_mldquery); - break; - case MLD6_LISTENER_REPORT: - icmp6_ifstat_inc(outif, ifs6_out_mldreport); - break; - case MLD6_LISTENER_DONE: - icmp6_ifstat_inc(outif, ifs6_out_mlddone); - break; - } + icmp6_ifstat_inc(ifp, ifs6_out_msg); + switch (type) { + case MLD6_LISTENER_QUERY: + icmp6_ifstat_inc(ifp, ifs6_out_mldquery); + break; + case MLD6_LISTENER_REPORT: + icmp6_ifstat_inc(ifp, ifs6_out_mldreport); + break; + case MLD6_LISTENER_DONE: + icmp6_ifstat_inc(ifp, ifs6_out_mlddone); + break; } + + ip6_output(mh, &ip6_opts, NULL, ia ? 0 : IPV6_UNSPECSRC, &im6o, NULL); }