Annotation of src/sys/netinet6/mld6.c, Revision 1.15
1.15 ! itojun 1: /* $NetBSD: mld6.c,v 1.14 2001/10/16 06:24:45 itojun Exp $ */
1.13 itojun 2: /* $KAME: mld6.c,v 1.25 2001/01/16 14:14:18 itojun Exp $ */
1.3 thorpej 3:
1.2 itojun 4: /*
5: * Copyright (C) 1998 WIDE Project.
6: * All rights reserved.
1.13 itojun 7: *
1.2 itojun 8: * Redistribution and use in source and binary forms, with or without
9: * modification, are permitted provided that the following conditions
10: * are met:
11: * 1. Redistributions of source code must retain the above copyright
12: * notice, this list of conditions and the following disclaimer.
13: * 2. Redistributions in binary form must reproduce the above copyright
14: * notice, this list of conditions and the following disclaimer in the
15: * documentation and/or other materials provided with the distribution.
16: * 3. Neither the name of the project nor the names of its contributors
17: * may be used to endorse or promote products derived from this software
18: * without specific prior written permission.
1.13 itojun 19: *
1.2 itojun 20: * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
21: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23: * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
24: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30: * SUCH DAMAGE.
31: */
32:
33: /*
34: * Copyright (c) 1988 Stephen Deering.
35: * Copyright (c) 1992, 1993
36: * The Regents of the University of California. All rights reserved.
37: *
38: * This code is derived from software contributed to Berkeley by
39: * Stephen Deering of Stanford University.
40: *
41: * Redistribution and use in source and binary forms, with or without
42: * modification, are permitted provided that the following conditions
43: * are met:
44: * 1. Redistributions of source code must retain the above copyright
45: * notice, this list of conditions and the following disclaimer.
46: * 2. Redistributions in binary form must reproduce the above copyright
47: * notice, this list of conditions and the following disclaimer in the
48: * documentation and/or other materials provided with the distribution.
49: * 3. All advertising materials mentioning features or use of this software
50: * must display the following acknowledgement:
51: * This product includes software developed by the University of
52: * California, Berkeley and its contributors.
53: * 4. Neither the name of the University nor the names of its contributors
54: * may be used to endorse or promote products derived from this software
55: * without specific prior written permission.
56: *
57: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
58: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
59: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
60: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
61: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
62: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
63: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
64: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
65: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
66: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
67: * SUCH DAMAGE.
68: *
69: * @(#)igmp.c 8.1 (Berkeley) 7/19/93
70: */
71:
72: #include "opt_inet.h"
73:
74: #include <sys/param.h>
75: #include <sys/systm.h>
76: #include <sys/mbuf.h>
77: #include <sys/socket.h>
78: #include <sys/protosw.h>
79: #include <sys/syslog.h>
80:
81: #include <net/if.h>
82:
83: #include <netinet/in.h>
84: #include <netinet/in_var.h>
1.10 itojun 85: #include <netinet/ip6.h>
1.2 itojun 86: #include <netinet6/ip6_var.h>
1.10 itojun 87: #include <netinet/icmp6.h>
1.2 itojun 88: #include <netinet6/mld6_var.h>
89:
1.7 itojun 90: #include <net/net_osdep.h>
91:
1.2 itojun 92: /*
93: * Protocol constants
94: */
95:
96: /* denotes that the MLD max response delay field specifies time in milliseconds */
97: #define MLD6_TIMER_SCALE 1000
98: /*
99: * time between repetitions of a node's initial report of interest in a
100: * multicast address(in seconds)
101: */
102: #define MLD6_UNSOLICITED_REPORT_INTERVAL 10
103:
104: static struct ip6_pktopts ip6_opts;
105: static int mld6_timers_are_running;
106: /* XXX: These are necessary for KAME's link-local hack */
107: static struct in6_addr mld6_all_nodes_linklocal = IN6ADDR_LINKLOCAL_ALLNODES_INIT;
108: static struct in6_addr mld6_all_routers_linklocal = IN6ADDR_LINKLOCAL_ALLROUTERS_INIT;
109:
110: static void mld6_sendpkt __P((struct in6_multi *, int, const struct in6_addr *));
111:
112: void
113: mld6_init()
114: {
115: static u_int8_t hbh_buf[8];
116: struct ip6_hbh *hbh = (struct ip6_hbh *)hbh_buf;
117: u_int16_t rtalert_code = htons((u_int16_t)IP6OPT_RTALERT_MLD);
118:
119: mld6_timers_are_running = 0;
120:
121: /* ip6h_nxt will be fill in later */
1.11 itojun 122: hbh->ip6h_len = 0; /* (8 >> 3) - 1 */
1.2 itojun 123:
124: /* XXX: grotty hard coding... */
125: hbh_buf[2] = IP6OPT_PADN; /* 2 byte padding */
126: hbh_buf[3] = 0;
127: hbh_buf[4] = IP6OPT_RTALERT;
128: hbh_buf[5] = IP6OPT_RTALERT_LEN - 2;
129: bcopy((caddr_t)&rtalert_code, &hbh_buf[6], sizeof(u_int16_t));
130:
131: ip6_opts.ip6po_hbh = hbh;
132: /* We will specify the hoplimit by a multicast option. */
133: ip6_opts.ip6po_hlim = -1;
134: }
135:
136: void
137: mld6_start_listening(in6m)
138: struct in6_multi *in6m;
139: {
1.4 itojun 140: int s = splsoftnet();
1.2 itojun 141:
142: /*
1.11 itojun 143: * RFC2710 page 10:
1.2 itojun 144: * The node never sends a Report or Done for the link-scope all-nodes
145: * address.
146: * MLD messages are never sent for multicast addresses whose scope is 0
147: * (reserved) or 1 (node-local).
148: */
149: mld6_all_nodes_linklocal.s6_addr16[1] =
150: htons(in6m->in6m_ifp->if_index); /* XXX */
151: if (IN6_ARE_ADDR_EQUAL(&in6m->in6m_addr, &mld6_all_nodes_linklocal) ||
152: IPV6_ADDR_MC_SCOPE(&in6m->in6m_addr) < IPV6_ADDR_SCOPE_LINKLOCAL) {
153: in6m->in6m_timer = 0;
154: in6m->in6m_state = MLD6_OTHERLISTENER;
155: } else {
156: mld6_sendpkt(in6m, MLD6_LISTENER_REPORT, NULL);
157: in6m->in6m_timer = MLD6_RANDOM_DELAY(
158: MLD6_UNSOLICITED_REPORT_INTERVAL * PR_FASTHZ);
159: in6m->in6m_state = MLD6_IREPORTEDLAST;
160: mld6_timers_are_running = 1;
161: }
162: splx(s);
163: }
164:
165: void
166: mld6_stop_listening(in6m)
167: struct in6_multi *in6m;
168: {
169: mld6_all_nodes_linklocal.s6_addr16[1] =
170: htons(in6m->in6m_ifp->if_index); /* XXX */
171: mld6_all_routers_linklocal.s6_addr16[1] =
172: htons(in6m->in6m_ifp->if_index); /* XXX: necessary when mrouting */
173:
174: if (in6m->in6m_state == MLD6_IREPORTEDLAST &&
175: (!IN6_ARE_ADDR_EQUAL(&in6m->in6m_addr, &mld6_all_nodes_linklocal)) &&
176: IPV6_ADDR_MC_SCOPE(&in6m->in6m_addr) > IPV6_ADDR_SCOPE_NODELOCAL)
177: mld6_sendpkt(in6m, MLD6_LISTENER_DONE,
178: &mld6_all_routers_linklocal);
179: }
180:
181: void
182: mld6_input(m, off)
183: struct mbuf *m;
184: int off;
185: {
186: struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
1.11 itojun 187: struct mld6_hdr *mldh;
1.2 itojun 188: struct ifnet *ifp = m->m_pkthdr.rcvif;
189: struct in6_multi *in6m;
190: struct in6_ifaddr *ia;
191: int timer; /* timer value in the MLD query header */
192:
1.13 itojun 193: #ifndef PULLDOWN_TEST
194: IP6_EXTHDR_CHECK(m, off, sizeof(*mldh),);
195: mldh = (struct mld6_hdr *)(mtod(m, caddr_t) + off);
196: #else
197: IP6_EXTHDR_GET(mldh, struct mld6_hdr *, m, off, sizeof(*mldh));
198: if (mldh == NULL) {
199: icmp6stat.icp6s_tooshort++;
200: return;
201: }
202: #endif
203:
1.2 itojun 204: /* source address validation */
1.13 itojun 205: ip6 = mtod(m, struct ip6_hdr *);/* in case mpullup */
1.2 itojun 206: if (!IN6_IS_ADDR_LINKLOCAL(&ip6->ip6_src)) {
207: log(LOG_ERR,
1.13 itojun 208: "mld6_input: src %s is not link-local (grp=%s)\n",
209: ip6_sprintf(&ip6->ip6_src),
210: ip6_sprintf(&mldh->mld6_addr));
1.2 itojun 211: /*
1.11 itojun 212: * spec (RFC2710) does not explicitly
1.2 itojun 213: * specify to discard the packet from a non link-local
214: * source address. But we believe it's expected to do so.
1.13 itojun 215: * XXX: do we have to allow :: as source?
1.2 itojun 216: */
1.11 itojun 217: m_freem(m);
1.2 itojun 218: return;
219: }
220:
221: /*
222: * In the MLD6 specification, there are 3 states and a flag.
223: *
224: * In Non-Listener state, we simply don't have a membership record.
225: * In Delaying Listener state, our timer is running (in6m->in6m_timer)
226: * In Idle Listener state, our timer is not running (in6m->in6m_timer==0)
227: *
228: * The flag is in6m->in6m_state, it is set to MLD6_OTHERLISTENER if
229: * we have heard a report from another member, or MLD6_IREPORTEDLAST
230: * if we sent the last report.
231: */
232: switch(mldh->mld6_type) {
1.7 itojun 233: case MLD6_LISTENER_QUERY:
234: if (ifp->if_flags & IFF_LOOPBACK)
235: break;
236:
237: if (!IN6_IS_ADDR_UNSPECIFIED(&mldh->mld6_addr) &&
1.13 itojun 238: !IN6_IS_ADDR_MULTICAST(&mldh->mld6_addr))
1.7 itojun 239: break; /* print error or log stat? */
240: if (IN6_IS_ADDR_MC_LINKLOCAL(&mldh->mld6_addr))
241: mldh->mld6_addr.s6_addr16[1] =
242: htons(ifp->if_index); /* XXX */
1.2 itojun 243:
1.7 itojun 244: /*
1.11 itojun 245: * - Start the timers in all of our membership records
246: * that the query applies to for the interface on
247: * which the query arrived excl. those that belong
248: * to the "all-nodes" group (ff02::1).
249: * - Restart any timer that is already running but has
250: * A value longer than the requested timeout.
251: * - Use the value specified in the query message as
252: * the maximum timeout.
253: */
1.7 itojun 254: IFP_TO_IA6(ifp, ia);
255: if (ia == NULL)
256: break;
1.2 itojun 257:
258: /*
1.11 itojun 259: * XXX: System timer resolution is too low to handle Max
260: * Response Delay, so set 1 to the internal timer even if
261: * the calculated value equals to zero when Max Response
262: * Delay is positive.
263: */
1.7 itojun 264: timer = ntohs(mldh->mld6_maxdelay)*PR_FASTHZ/MLD6_TIMER_SCALE;
265: if (timer == 0 && mldh->mld6_maxdelay)
266: timer = 1;
267: mld6_all_nodes_linklocal.s6_addr16[1] =
268: htons(ifp->if_index); /* XXX */
269:
270: for (in6m = ia->ia6_multiaddrs.lh_first;
271: in6m;
272: in6m = in6m->in6m_entry.le_next)
273: {
274: if (IN6_ARE_ADDR_EQUAL(&in6m->in6m_addr,
1.2 itojun 275: &mld6_all_nodes_linklocal) ||
1.7 itojun 276: IPV6_ADDR_MC_SCOPE(&in6m->in6m_addr) <
277: IPV6_ADDR_SCOPE_LINKLOCAL)
278: continue;
1.2 itojun 279:
1.7 itojun 280: if (IN6_IS_ADDR_UNSPECIFIED(&mldh->mld6_addr) ||
281: IN6_ARE_ADDR_EQUAL(&mldh->mld6_addr,
282: &in6m->in6m_addr))
283: {
284: if (timer == 0) {
285: /* send a report immediately */
286: mld6_sendpkt(in6m, MLD6_LISTENER_REPORT,
287: NULL);
288: in6m->in6m_timer = 0; /* reset timer */
289: in6m->in6m_state = MLD6_IREPORTEDLAST;
290: }
291: else if (in6m->in6m_timer == 0 || /*idle state*/
292: in6m->in6m_timer > timer) {
293: in6m->in6m_timer =
294: MLD6_RANDOM_DELAY(timer);
295: mld6_timers_are_running = 1;
296: }
297: }
298: }
1.2 itojun 299:
1.7 itojun 300: if (IN6_IS_ADDR_MC_LINKLOCAL(&mldh->mld6_addr))
301: mldh->mld6_addr.s6_addr16[1] = 0; /* XXX */
302: break;
303: case MLD6_LISTENER_REPORT:
1.2 itojun 304: /*
1.11 itojun 305: * For fast leave to work, we have to know that we are the
306: * last person to send a report for this group. Reports
307: * can potentially get looped back if we are a multicast
308: * router, so discard reports sourced by me.
309: * Note that it is impossible to check IFF_LOOPBACK flag of
310: * ifp for this purpose, since ip6_mloopback pass the physical
311: * interface to looutput.
312: */
1.7 itojun 313: if (m->m_flags & M_LOOP) /* XXX: grotty flag, but efficient */
314: break;
315:
316: if (!IN6_IS_ADDR_MULTICAST(&mldh->mld6_addr))
317: break;
318:
319: if (IN6_IS_ADDR_MC_LINKLOCAL(&mldh->mld6_addr))
320: mldh->mld6_addr.s6_addr16[1] =
321: htons(ifp->if_index); /* XXX */
322: /*
1.11 itojun 323: * If we belong to the group being reported, stop
324: * our timer for that group.
325: */
1.7 itojun 326: IN6_LOOKUP_MULTI(mldh->mld6_addr, ifp, in6m);
327: if (in6m) {
328: in6m->in6m_timer = 0; /* transit to idle state */
329: in6m->in6m_state = MLD6_OTHERLISTENER; /* clear flag */
330: }
331:
332: if (IN6_IS_ADDR_MC_LINKLOCAL(&mldh->mld6_addr))
333: mldh->mld6_addr.s6_addr16[1] = 0; /* XXX */
334: break;
335: default: /* this is impossible */
336: log(LOG_ERR, "mld6_input: illegal type(%d)", mldh->mld6_type);
337: break;
1.2 itojun 338: }
1.11 itojun 339:
340: m_freem(m);
1.2 itojun 341: }
342:
343: void
344: mld6_fasttimeo()
345: {
1.13 itojun 346: struct in6_multi *in6m;
1.2 itojun 347: struct in6_multistep step;
348: int s;
349:
350: /*
351: * Quick check to see if any work needs to be done, in order
352: * to minimize the overhead of fasttimo processing.
353: */
354: if (!mld6_timers_are_running)
355: return;
356:
1.4 itojun 357: s = splsoftnet();
1.2 itojun 358: mld6_timers_are_running = 0;
359: IN6_FIRST_MULTI(step, in6m);
360: while (in6m != NULL) {
361: if (in6m->in6m_timer == 0) {
362: /* do nothing */
363: } else if (--in6m->in6m_timer == 0) {
364: mld6_sendpkt(in6m, MLD6_LISTENER_REPORT, NULL);
365: in6m->in6m_state = MLD6_IREPORTEDLAST;
366: } else {
367: mld6_timers_are_running = 1;
368: }
369: IN6_NEXT_MULTI(step, in6m);
370: }
371: splx(s);
372: }
373:
374: static void
375: mld6_sendpkt(in6m, type, dst)
376: struct in6_multi *in6m;
377: int type;
378: const struct in6_addr *dst;
379: {
380: struct mbuf *mh, *md;
381: struct mld6_hdr *mldh;
382: struct ip6_hdr *ip6;
383: struct ip6_moptions im6o;
384: struct in6_ifaddr *ia;
385: struct ifnet *ifp = in6m->in6m_ifp;
386:
387: /*
388: * At first, find a link local address on the outgoing interface
389: * to use as the source address of the MLD packet.
390: */
1.11 itojun 391: if ((ia = in6ifa_ifpforlinklocal(ifp, IN6_IFF_NOTREADY|IN6_IFF_ANYCAST))
392: == NULL)
1.2 itojun 393: return;
394:
395: /*
396: * Allocate mbufs to store ip6 header and MLD header.
397: * We allocate 2 mbufs and make chain in advance because
398: * it is more convenient when inserting the hop-by-hop option later.
399: */
400: MGETHDR(mh, M_DONTWAIT, MT_HEADER);
401: if (mh == NULL)
402: return;
403: MGET(md, M_DONTWAIT, MT_DATA);
404: if (md == NULL) {
405: m_free(mh);
406: return;
407: }
408: mh->m_next = md;
409:
410: mh->m_pkthdr.len = sizeof(struct ip6_hdr) + sizeof(struct mld6_hdr);
411: mh->m_len = sizeof(struct ip6_hdr);
412: MH_ALIGN(mh, sizeof(struct ip6_hdr));
413:
414: /* fill in the ip6 header */
415: ip6 = mtod(mh, struct ip6_hdr *);
416: ip6->ip6_flow = 0;
1.8 itojun 417: ip6->ip6_vfc &= ~IPV6_VERSION_MASK;
418: ip6->ip6_vfc |= IPV6_VERSION;
1.2 itojun 419: /* ip6_plen will be set later */
420: ip6->ip6_nxt = IPPROTO_ICMPV6;
421: /* ip6_hlim will be set by im6o.im6o_multicast_hlim */
422: ip6->ip6_src = ia->ia_addr.sin6_addr;
423: ip6->ip6_dst = dst ? *dst : in6m->in6m_addr;
424:
425: /* fill in the MLD header */
426: md->m_len = sizeof(struct mld6_hdr);
427: mldh = mtod(md, struct mld6_hdr *);
428: mldh->mld6_type = type;
429: mldh->mld6_code = 0;
430: mldh->mld6_cksum = 0;
431: /* XXX: we assume the function will not be called for query messages */
432: mldh->mld6_maxdelay = 0;
433: mldh->mld6_reserved = 0;
434: mldh->mld6_addr = in6m->in6m_addr;
435: if (IN6_IS_ADDR_MC_LINKLOCAL(&mldh->mld6_addr))
436: mldh->mld6_addr.s6_addr16[1] = 0; /* XXX */
1.14 itojun 437: mldh->mld6_cksum = in6_cksum(mh, IPPROTO_ICMPV6,
438: sizeof(struct ip6_hdr),
1.2 itojun 439: sizeof(struct mld6_hdr));
440:
441: /* construct multicast option */
442: bzero(&im6o, sizeof(im6o));
443: im6o.im6o_multicast_ifp = ifp;
444: im6o.im6o_multicast_hlim = 1;
445:
446: /*
447: * Request loopback of the report if we are acting as a multicast
448: * router, so that the process-level routing daemon can hear it.
449: */
450: im6o.im6o_multicast_loop = (ip6_mrouter != NULL);
451:
452: /* increment output statictics */
453: icmp6stat.icp6s_outhist[type]++;
454:
1.15 ! itojun 455: ip6_output(mh, &ip6_opts, NULL, 0, &im6o, NULL);
! 456: icmp6_ifstat_inc(ifp, ifs6_out_msg);
! 457: switch(type) {
! 458: case MLD6_LISTENER_QUERY:
! 459: icmp6_ifstat_inc(ifp, ifs6_out_mldquery);
! 460: break;
! 461: case MLD6_LISTENER_REPORT:
! 462: icmp6_ifstat_inc(ifp, ifs6_out_mldreport);
! 463: break;
! 464: case MLD6_LISTENER_DONE:
! 465: icmp6_ifstat_inc(ifp, ifs6_out_mlddone);
! 466: break;
1.7 itojun 467: }
1.2 itojun 468: }
CVSweb <webmaster@jp.NetBSD.org>