Annotation of src/sys/netinet6/mld6.c, Revision 1.95
1.95 ! ozaki-r 1: /* $NetBSD: mld6.c,v 1.94 2018/05/29 04:36:15 ozaki-r 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) 1992, 1993
35: * The Regents of the University of California. All rights reserved.
36: *
37: * This code is derived from software contributed to Berkeley by
38: * Stephen Deering of Stanford University.
39: *
40: * Redistribution and use in source and binary forms, with or without
41: * modification, are permitted provided that the following conditions
42: * are met:
43: * 1. Redistributions of source code must retain the above copyright
44: * notice, this list of conditions and the following disclaimer.
45: * 2. Redistributions in binary form must reproduce the above copyright
46: * notice, this list of conditions and the following disclaimer in the
47: * documentation and/or other materials provided with the distribution.
1.23 agc 48: * 3. Neither the name of the University nor the names of its contributors
49: * may be used to endorse or promote products derived from this software
50: * without specific prior written permission.
51: *
52: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
53: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
54: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
55: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
56: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
57: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
58: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
59: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
60: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
61: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
62: * SUCH DAMAGE.
63: *
64: * @(#)igmp.c 8.1 (Berkeley) 7/19/93
65: */
66:
67: /*
68: * Copyright (c) 1988 Stephen Deering.
69: *
70: * This code is derived from software contributed to Berkeley by
71: * Stephen Deering of Stanford University.
72: *
73: * Redistribution and use in source and binary forms, with or without
74: * modification, are permitted provided that the following conditions
75: * are met:
76: * 1. Redistributions of source code must retain the above copyright
77: * notice, this list of conditions and the following disclaimer.
78: * 2. Redistributions in binary form must reproduce the above copyright
79: * notice, this list of conditions and the following disclaimer in the
80: * documentation and/or other materials provided with the distribution.
1.2 itojun 81: * 3. All advertising materials mentioning features or use of this software
82: * must display the following acknowledgement:
83: * This product includes software developed by the University of
84: * California, Berkeley and its contributors.
85: * 4. Neither the name of the University nor the names of its contributors
86: * may be used to endorse or promote products derived from this software
87: * without specific prior written permission.
88: *
89: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
90: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
91: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
92: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
93: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
94: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
95: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
96: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
97: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
98: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
99: * SUCH DAMAGE.
100: *
101: * @(#)igmp.c 8.1 (Berkeley) 7/19/93
102: */
1.16 lukem 103:
104: #include <sys/cdefs.h>
1.95 ! ozaki-r 105: __KERNEL_RCSID(0, "$NetBSD: mld6.c,v 1.94 2018/05/29 04:36:15 ozaki-r Exp $");
1.2 itojun 106:
1.63 pooka 107: #ifdef _KERNEL_OPT
1.2 itojun 108: #include "opt_inet.h"
1.75 knakahar 109: #include "opt_net_mpsafe.h"
1.63 pooka 110: #endif
1.2 itojun 111:
112: #include <sys/param.h>
113: #include <sys/systm.h>
114: #include <sys/mbuf.h>
115: #include <sys/socket.h>
1.45 ad 116: #include <sys/socketvar.h>
1.2 itojun 117: #include <sys/syslog.h>
1.31 rpaulo 118: #include <sys/sysctl.h>
119: #include <sys/kernel.h>
120: #include <sys/callout.h>
1.55 tls 121: #include <sys/cprng.h>
1.85 ozaki-r 122: #include <sys/rwlock.h>
1.2 itojun 123:
124: #include <net/if.h>
125:
126: #include <netinet/in.h>
127: #include <netinet/in_var.h>
1.31 rpaulo 128: #include <netinet6/in6_var.h>
1.10 itojun 129: #include <netinet/ip6.h>
1.2 itojun 130: #include <netinet6/ip6_var.h>
1.29 rpaulo 131: #include <netinet6/scope6_var.h>
1.10 itojun 132: #include <netinet/icmp6.h>
1.44 thorpej 133: #include <netinet6/icmp6_private.h>
1.2 itojun 134: #include <netinet6/mld6_var.h>
135:
1.85 ozaki-r 136: static krwlock_t in6_multilock __cacheline_aligned;
137:
1.31 rpaulo 138: /*
1.2 itojun 139: * Protocol constants
140: */
141:
142: /*
143: * time between repetitions of a node's initial report of interest in a
144: * multicast address(in seconds)
145: */
1.22 itojun 146: #define MLD_UNSOLICITED_REPORT_INTERVAL 10
1.2 itojun 147:
148: static struct ip6_pktopts ip6_opts;
149:
1.31 rpaulo 150: static void mld_start_listening(struct in6_multi *);
151: static void mld_stop_listening(struct in6_multi *);
152:
1.91 maxv 153: static struct mld_hdr *mld_allocbuf(struct mbuf **, struct in6_multi *, int);
1.31 rpaulo 154: static void mld_sendpkt(struct in6_multi *, int, const struct in6_addr *);
155: static void mld_starttimer(struct in6_multi *);
156: static void mld_stoptimer(struct in6_multi *);
157: static u_long mld_timerresid(struct in6_multi *);
1.2 itojun 158:
1.85 ozaki-r 159: static void in6m_ref(struct in6_multi *);
160: static void in6m_unref(struct in6_multi *);
161: static void in6m_destroy(struct in6_multi *);
162:
1.2 itojun 163: void
1.42 matt 164: mld_init(void)
1.2 itojun 165: {
166: static u_int8_t hbh_buf[8];
167: struct ip6_hbh *hbh = (struct ip6_hbh *)hbh_buf;
168: u_int16_t rtalert_code = htons((u_int16_t)IP6OPT_RTALERT_MLD);
169:
170: /* ip6h_nxt will be fill in later */
1.11 itojun 171: hbh->ip6h_len = 0; /* (8 >> 3) - 1 */
1.2 itojun 172:
173: /* XXX: grotty hard coding... */
174: hbh_buf[2] = IP6OPT_PADN; /* 2 byte padding */
175: hbh_buf[3] = 0;
176: hbh_buf[4] = IP6OPT_RTALERT;
177: hbh_buf[5] = IP6OPT_RTALERT_LEN - 2;
1.50 tsutsui 178: memcpy(&hbh_buf[6], (void *)&rtalert_code, sizeof(u_int16_t));
1.2 itojun 179:
180: ip6_opts.ip6po_hbh = hbh;
181: /* We will specify the hoplimit by a multicast option. */
182: ip6_opts.ip6po_hlim = -1;
1.62 roy 183: ip6_opts.ip6po_prefer_tempaddr = IP6PO_TEMPADDR_NOTPREFER;
1.85 ozaki-r 184:
185: rw_init(&in6_multilock);
1.2 itojun 186: }
187:
1.31 rpaulo 188: static void
1.38 christos 189: mld_starttimer(struct in6_multi *in6m)
1.31 rpaulo 190: {
191: struct timeval now;
192:
1.85 ozaki-r 193: KASSERT(rw_write_held(&in6_multilock));
1.61 ozaki-r 194: KASSERT(in6m->in6m_timer != IN6M_TIMER_UNDEF);
195:
1.31 rpaulo 196: microtime(&now);
197: in6m->in6m_timer_expire.tv_sec = now.tv_sec + in6m->in6m_timer / hz;
198: in6m->in6m_timer_expire.tv_usec = now.tv_usec +
199: (in6m->in6m_timer % hz) * (1000000 / hz);
200: if (in6m->in6m_timer_expire.tv_usec > 1000000) {
201: in6m->in6m_timer_expire.tv_sec++;
202: in6m->in6m_timer_expire.tv_usec -= 1000000;
203: }
204:
205: /* start or restart the timer */
1.41 joerg 206: callout_schedule(&in6m->in6m_timer_ch, in6m->in6m_timer);
1.31 rpaulo 207: }
208:
1.85 ozaki-r 209: /*
210: * mld_stoptimer releases in6_multilock when calling callout_halt.
211: * The caller must ensure in6m won't be freed while releasing the lock.
212: */
1.31 rpaulo 213: static void
1.38 christos 214: mld_stoptimer(struct in6_multi *in6m)
1.31 rpaulo 215: {
1.85 ozaki-r 216:
217: KASSERT(rw_write_held(&in6_multilock));
218:
1.31 rpaulo 219: if (in6m->in6m_timer == IN6M_TIMER_UNDEF)
220: return;
221:
1.85 ozaki-r 222: rw_exit(&in6_multilock);
223:
1.93 ozaki-r 224: callout_halt(&in6m->in6m_timer_ch, NULL);
1.85 ozaki-r 225:
226: rw_enter(&in6_multilock, RW_WRITER);
1.31 rpaulo 227:
228: in6m->in6m_timer = IN6M_TIMER_UNDEF;
229: }
230:
231: static void
1.41 joerg 232: mld_timeo(void *arg)
1.31 rpaulo 233: {
1.41 joerg 234: struct in6_multi *in6m = arg;
1.45 ad 235:
1.85 ozaki-r 236: KASSERT(in6m->in6m_refcount > 0);
237:
1.93 ozaki-r 238: KERNEL_LOCK_UNLESS_NET_MPSAFE();
1.85 ozaki-r 239: rw_enter(&in6_multilock, RW_WRITER);
1.61 ozaki-r 240: if (in6m->in6m_timer == IN6M_TIMER_UNDEF)
241: goto out;
242:
1.31 rpaulo 243: in6m->in6m_timer = IN6M_TIMER_UNDEF;
244:
245: switch (in6m->in6m_state) {
246: case MLD_REPORTPENDING:
247: mld_start_listening(in6m);
248: break;
249: default:
250: mld_sendpkt(in6m, MLD_LISTENER_REPORT, NULL);
251: break;
252: }
253:
1.61 ozaki-r 254: out:
1.85 ozaki-r 255: rw_exit(&in6_multilock);
1.93 ozaki-r 256: KERNEL_UNLOCK_UNLESS_NET_MPSAFE();
1.31 rpaulo 257: }
258:
259: static u_long
1.38 christos 260: mld_timerresid(struct in6_multi *in6m)
1.31 rpaulo 261: {
262: struct timeval now, diff;
263:
264: microtime(&now);
265:
266: if (now.tv_sec > in6m->in6m_timer_expire.tv_sec ||
267: (now.tv_sec == in6m->in6m_timer_expire.tv_sec &&
268: now.tv_usec > in6m->in6m_timer_expire.tv_usec)) {
269: return (0);
270: }
271: diff = in6m->in6m_timer_expire;
272: diff.tv_sec -= now.tv_sec;
273: diff.tv_usec -= now.tv_usec;
274: if (diff.tv_usec < 0) {
275: diff.tv_sec--;
276: diff.tv_usec += 1000000;
277: }
278:
279: /* return the remaining time in milliseconds */
1.47 adrianp 280: return diff.tv_sec * 1000 + diff.tv_usec / 1000;
1.31 rpaulo 281: }
282:
283: static void
1.38 christos 284: mld_start_listening(struct in6_multi *in6m)
1.2 itojun 285: {
1.29 rpaulo 286: struct in6_addr all_in6;
287:
1.85 ozaki-r 288: KASSERT(rw_write_held(&in6_multilock));
289:
1.2 itojun 290: /*
1.11 itojun 291: * RFC2710 page 10:
1.2 itojun 292: * The node never sends a Report or Done for the link-scope all-nodes
293: * address.
294: * MLD messages are never sent for multicast addresses whose scope is 0
295: * (reserved) or 1 (node-local).
296: */
1.29 rpaulo 297: all_in6 = in6addr_linklocal_allnodes;
298: if (in6_setscope(&all_in6, in6m->in6m_ifp, NULL)) {
299: /* XXX: this should not happen! */
300: in6m->in6m_timer = 0;
301: in6m->in6m_state = MLD_OTHERLISTENER;
302: }
303: if (IN6_ARE_ADDR_EQUAL(&in6m->in6m_addr, &all_in6) ||
1.2 itojun 304: IPV6_ADDR_MC_SCOPE(&in6m->in6m_addr) < IPV6_ADDR_SCOPE_LINKLOCAL) {
1.31 rpaulo 305: in6m->in6m_timer = IN6M_TIMER_UNDEF;
1.22 itojun 306: in6m->in6m_state = MLD_OTHERLISTENER;
1.2 itojun 307: } else {
1.31 rpaulo 308: mld_sendpkt(in6m, MLD_LISTENER_REPORT, NULL);
1.55 tls 309: in6m->in6m_timer = cprng_fast32() %
1.31 rpaulo 310: (MLD_UNSOLICITED_REPORT_INTERVAL * hz);
1.22 itojun 311: in6m->in6m_state = MLD_IREPORTEDLAST;
1.31 rpaulo 312:
313: mld_starttimer(in6m);
1.2 itojun 314: }
315: }
316:
1.31 rpaulo 317: static void
1.38 christos 318: mld_stop_listening(struct in6_multi *in6m)
1.2 itojun 319: {
1.29 rpaulo 320: struct in6_addr allnode, allrouter;
321:
1.85 ozaki-r 322: KASSERT(rw_lock_held(&in6_multilock));
323:
1.29 rpaulo 324: allnode = in6addr_linklocal_allnodes;
325: if (in6_setscope(&allnode, in6m->in6m_ifp, NULL)) {
326: /* XXX: this should not happen! */
327: return;
328: }
329: allrouter = in6addr_linklocal_allrouters;
330: if (in6_setscope(&allrouter, in6m->in6m_ifp, NULL)) {
331: /* XXX impossible */
332: return;
333: }
1.2 itojun 334:
1.22 itojun 335: if (in6m->in6m_state == MLD_IREPORTEDLAST &&
1.29 rpaulo 336: (!IN6_ARE_ADDR_EQUAL(&in6m->in6m_addr, &allnode)) &&
337: IPV6_ADDR_MC_SCOPE(&in6m->in6m_addr) >
338: IPV6_ADDR_SCOPE_INTFACELOCAL) {
1.31 rpaulo 339: mld_sendpkt(in6m, MLD_LISTENER_DONE, &allrouter);
1.29 rpaulo 340: }
1.2 itojun 341: }
342:
343: void
1.38 christos 344: mld_input(struct mbuf *m, int off)
1.2 itojun 345: {
1.52 dholland 346: struct ip6_hdr *ip6;
1.22 itojun 347: struct mld_hdr *mldh;
1.66 ozaki-r 348: struct ifnet *ifp;
1.31 rpaulo 349: struct in6_multi *in6m = NULL;
1.29 rpaulo 350: struct in6_addr mld_addr, all_in6;
1.47 adrianp 351: u_long timer = 0; /* timer value in the MLD query header */
1.83 ozaki-r 352: struct psref psref;
1.2 itojun 353:
1.83 ozaki-r 354: ifp = m_get_rcvif_psref(m, &psref);
1.81 ozaki-r 355: if (__predict_false(ifp == NULL))
356: goto out;
1.22 itojun 357: IP6_EXTHDR_GET(mldh, struct mld_hdr *, m, off, sizeof(*mldh));
1.13 itojun 358: if (mldh == NULL) {
1.44 thorpej 359: ICMP6_STATINC(ICMP6_STAT_TOOSHORT);
1.66 ozaki-r 360: goto out_nodrop;
1.13 itojun 361: }
362:
1.91 maxv 363: ip6 = mtod(m, struct ip6_hdr *);
364:
1.2 itojun 365: /* source address validation */
366: if (!IN6_IS_ADDR_LINKLOCAL(&ip6->ip6_src)) {
1.31 rpaulo 367: /*
368: * RFC3590 allows the IPv6 unspecified address as the source
369: * address of MLD report and done messages. However, as this
370: * same document says, this special rule is for snooping
371: * switches and the RFC requires routers to discard MLD packets
372: * with the unspecified source address. The RFC only talks
373: * about hosts receiving an MLD query or report in Security
374: * Considerations, but this is probably the correct intention.
375: * RFC3590 does not talk about other cases than link-local and
376: * the unspecified source addresses, but we believe the same
377: * rule should be applied.
378: * As a result, we only allow link-local addresses as the
379: * source address; otherwise, simply discard the packet.
380: */
1.18 itojun 381: #if 0
1.31 rpaulo 382: /*
383: * XXX: do not log in an input path to avoid log flooding,
384: * though RFC3590 says "SHOULD log" if the source of a query
385: * is the unspecified address.
386: */
1.78 ryo 387: char ip6bufs[INET6_ADDRSTRLEN];
388: char ip6bufm[INET6_ADDRSTRLEN];
1.31 rpaulo 389: log(LOG_INFO,
1.22 itojun 390: "mld_input: src %s is not link-local (grp=%s)\n",
1.79 christos 391: IN6_PRINT(ip6bufs,&ip6->ip6_src),
392: IN6_PRINT(ip6bufm, &mldh->mld_addr));
1.18 itojun 393: #endif
1.66 ozaki-r 394: goto out;
1.2 itojun 395: }
396:
397: /*
1.29 rpaulo 398: * make a copy for local work (in6_setscope() may modify the 1st arg)
399: */
400: mld_addr = mldh->mld_addr;
401: if (in6_setscope(&mld_addr, ifp, NULL)) {
402: /* XXX: this should not happen! */
1.66 ozaki-r 403: goto out;
1.29 rpaulo 404: }
405:
406: /*
1.31 rpaulo 407: * In the MLD specification, there are 3 states and a flag.
1.2 itojun 408: *
409: * In Non-Listener state, we simply don't have a membership record.
410: * In Delaying Listener state, our timer is running (in6m->in6m_timer)
1.91 maxv 411: * In Idle Listener state, our timer is not running
1.31 rpaulo 412: * (in6m->in6m_timer==IN6M_TIMER_UNDEF)
1.2 itojun 413: *
1.22 itojun 414: * The flag is in6m->in6m_state, it is set to MLD_OTHERLISTENER if
415: * we have heard a report from another member, or MLD_IREPORTEDLAST
1.2 itojun 416: * if we sent the last report.
417: */
1.22 itojun 418: switch (mldh->mld_type) {
1.74 ozaki-r 419: case MLD_LISTENER_QUERY: {
1.85 ozaki-r 420: struct in6_multi *next;
421:
1.7 itojun 422: if (ifp->if_flags & IFF_LOOPBACK)
423: break;
424:
1.29 rpaulo 425: if (!IN6_IS_ADDR_UNSPECIFIED(&mld_addr) &&
426: !IN6_IS_ADDR_MULTICAST(&mld_addr))
1.7 itojun 427: break; /* print error or log stat? */
1.29 rpaulo 428:
429: all_in6 = in6addr_linklocal_allnodes;
430: if (in6_setscope(&all_in6, ifp, NULL)) {
431: /* XXX: this should not happen! */
432: break;
433: }
1.2 itojun 434:
1.7 itojun 435: /*
1.11 itojun 436: * - Start the timers in all of our membership records
437: * that the query applies to for the interface on
438: * which the query arrived excl. those that belong
439: * to the "all-nodes" group (ff02::1).
440: * - Restart any timer that is already running but has
1.30 rpaulo 441: * a value longer than the requested timeout.
1.11 itojun 442: * - Use the value specified in the query message as
443: * the maximum timeout.
444: */
1.31 rpaulo 445: timer = ntohs(mldh->mld_maxdelay);
446:
1.85 ozaki-r 447: rw_enter(&in6_multilock, RW_WRITER);
448: /*
449: * mld_stoptimer and mld_sendpkt release in6_multilock
450: * temporarily, so we have to prevent in6m from being freed
451: * while releasing the lock by having an extra reference to it.
452: *
453: * Also in6_purge_multi might remove items from the list of the
454: * ifp while releasing the lock. Fortunately in6_purge_multi is
455: * never executed as long as we have a psref of the ifp.
456: */
457: LIST_FOREACH_SAFE(in6m, &ifp->if_multiaddrs, in6m_entry, next) {
1.29 rpaulo 458: if (IN6_ARE_ADDR_EQUAL(&in6m->in6m_addr, &all_in6) ||
1.7 itojun 459: IPV6_ADDR_MC_SCOPE(&in6m->in6m_addr) <
460: IPV6_ADDR_SCOPE_LINKLOCAL)
461: continue;
1.2 itojun 462:
1.31 rpaulo 463: if (in6m->in6m_state == MLD_REPORTPENDING)
464: continue; /* we are not yet ready */
465:
466: if (!IN6_IS_ADDR_UNSPECIFIED(&mld_addr) &&
467: !IN6_ARE_ADDR_EQUAL(&mld_addr, &in6m->in6m_addr))
468: continue;
469:
470: if (timer == 0) {
1.85 ozaki-r 471: in6m_ref(in6m);
472:
1.31 rpaulo 473: /* send a report immediately */
474: mld_stoptimer(in6m);
475: mld_sendpkt(in6m, MLD_LISTENER_REPORT, NULL);
476: in6m->in6m_state = MLD_IREPORTEDLAST;
1.85 ozaki-r 477:
478: in6m_unref(in6m); /* May free in6m */
1.31 rpaulo 479: } else if (in6m->in6m_timer == IN6M_TIMER_UNDEF ||
1.47 adrianp 480: mld_timerresid(in6m) > timer) {
481: in6m->in6m_timer =
1.55 tls 482: 1 + (cprng_fast32() % timer) * hz / 1000;
1.31 rpaulo 483: mld_starttimer(in6m);
1.7 itojun 484: }
485: }
1.85 ozaki-r 486: rw_exit(&in6_multilock);
1.29 rpaulo 487: break;
1.74 ozaki-r 488: }
1.2 itojun 489:
1.22 itojun 490: case MLD_LISTENER_REPORT:
1.2 itojun 491: /*
1.11 itojun 492: * For fast leave to work, we have to know that we are the
493: * last person to send a report for this group. Reports
494: * can potentially get looped back if we are a multicast
495: * router, so discard reports sourced by me.
496: * Note that it is impossible to check IFF_LOOPBACK flag of
497: * ifp for this purpose, since ip6_mloopback pass the physical
498: * interface to looutput.
499: */
1.7 itojun 500: if (m->m_flags & M_LOOP) /* XXX: grotty flag, but efficient */
501: break;
502:
1.22 itojun 503: if (!IN6_IS_ADDR_MULTICAST(&mldh->mld_addr))
1.7 itojun 504: break;
505:
506: /*
1.11 itojun 507: * If we belong to the group being reported, stop
508: * our timer for that group.
509: */
1.85 ozaki-r 510: rw_enter(&in6_multilock, RW_WRITER);
1.82 ozaki-r 511: in6m = in6_lookup_multi(&mld_addr, ifp);
1.7 itojun 512: if (in6m) {
1.85 ozaki-r 513: in6m_ref(in6m);
1.31 rpaulo 514: mld_stoptimer(in6m); /* transit to idle state */
1.22 itojun 515: in6m->in6m_state = MLD_OTHERLISTENER; /* clear flag */
1.85 ozaki-r 516: in6m_unref(in6m);
517: in6m = NULL; /* in6m might be freed */
1.7 itojun 518: }
1.85 ozaki-r 519: rw_exit(&in6_multilock);
1.7 itojun 520: break;
521: default: /* this is impossible */
1.18 itojun 522: #if 0
1.19 itojun 523: /*
524: * this case should be impossible because of filtering in
525: * icmp6_input(). But we explicitly disabled this part
526: * just in case.
527: */
1.31 rpaulo 528: log(LOG_ERR, "mld_input: illegal type(%d)", mldh->mld_type);
1.18 itojun 529: #endif
1.7 itojun 530: break;
1.2 itojun 531: }
1.11 itojun 532:
1.66 ozaki-r 533: out:
1.11 itojun 534: m_freem(m);
1.66 ozaki-r 535: out_nodrop:
1.83 ozaki-r 536: m_put_rcvif_psref(ifp, &psref);
1.2 itojun 537: }
538:
1.85 ozaki-r 539: /*
540: * XXX mld_sendpkt must be called with in6_multilock held and
541: * will release in6_multilock before calling ip6_output and
542: * returning to avoid locking against myself in ip6_output.
543: */
1.2 itojun 544: static void
1.91 maxv 545: mld_sendpkt(struct in6_multi *in6m, int type, const struct in6_addr *dst)
1.2 itojun 546: {
1.31 rpaulo 547: struct mbuf *mh;
1.22 itojun 548: struct mld_hdr *mldh;
1.31 rpaulo 549: struct ip6_hdr *ip6 = NULL;
1.2 itojun 550: struct ip6_moptions im6o;
1.31 rpaulo 551: struct in6_ifaddr *ia = NULL;
1.2 itojun 552: struct ifnet *ifp = in6m->in6m_ifp;
1.19 itojun 553: int ignflags;
1.74 ozaki-r 554: struct psref psref;
555: int bound;
1.2 itojun 556:
1.85 ozaki-r 557: KASSERT(rw_write_held(&in6_multilock));
558:
1.2 itojun 559: /*
560: * At first, find a link local address on the outgoing interface
561: * to use as the source address of the MLD packet.
1.19 itojun 562: * We do not reject tentative addresses for MLD report to deal with
563: * the case where we first join a link-local address.
1.2 itojun 564: */
1.19 itojun 565: ignflags = (IN6_IFF_NOTREADY|IN6_IFF_ANYCAST) & ~IN6_IFF_TENTATIVE;
1.74 ozaki-r 566: bound = curlwp_bind();
567: ia = in6ifa_ifpforlinklocal_psref(ifp, ignflags, &psref);
568: if (ia == NULL) {
569: curlwp_bindx(bound);
1.2 itojun 570: return;
1.74 ozaki-r 571: }
572: if ((ia->ia6_flags & IN6_IFF_TENTATIVE)) {
573: ia6_release(ia, &psref);
1.19 itojun 574: ia = NULL;
1.74 ozaki-r 575: }
1.2 itojun 576:
1.31 rpaulo 577: /* Allocate two mbufs to store IPv6 header and MLD header */
1.91 maxv 578: mldh = mld_allocbuf(&mh, in6m, type);
1.74 ozaki-r 579: if (mldh == NULL) {
580: ia6_release(ia, &psref);
581: curlwp_bindx(bound);
1.2 itojun 582: return;
1.74 ozaki-r 583: }
1.2 itojun 584:
1.31 rpaulo 585: /* fill src/dst here */
1.91 maxv 586: ip6 = mtod(mh, struct ip6_hdr *);
587: ip6->ip6_src = ia ? ia->ia_addr.sin6_addr : in6addr_any;
588: ip6->ip6_dst = dst ? *dst : in6m->in6m_addr;
1.74 ozaki-r 589: ia6_release(ia, &psref);
590: curlwp_bindx(bound);
1.2 itojun 591:
1.22 itojun 592: mldh->mld_addr = in6m->in6m_addr;
1.29 rpaulo 593: in6_clearscope(&mldh->mld_addr); /* XXX */
1.22 itojun 594: mldh->mld_cksum = in6_cksum(mh, IPPROTO_ICMPV6, sizeof(struct ip6_hdr),
595: sizeof(struct mld_hdr));
1.2 itojun 596:
597: /* construct multicast option */
1.31 rpaulo 598: memset(&im6o, 0, sizeof(im6o));
1.68 ozaki-r 599: im6o.im6o_multicast_if_index = if_get_index(ifp);
1.2 itojun 600: im6o.im6o_multicast_hlim = 1;
601:
602: /*
603: * Request loopback of the report if we are acting as a multicast
604: * router, so that the process-level routing daemon can hear it.
605: */
606: im6o.im6o_multicast_loop = (ip6_mrouter != NULL);
607:
1.91 maxv 608: /* increment output statistics */
1.44 thorpej 609: ICMP6_STATINC(ICMP6_STAT_OUTHIST + type);
1.15 itojun 610: icmp6_ifstat_inc(ifp, ifs6_out_msg);
1.17 itojun 611: switch (type) {
1.22 itojun 612: case MLD_LISTENER_QUERY:
1.15 itojun 613: icmp6_ifstat_inc(ifp, ifs6_out_mldquery);
614: break;
1.22 itojun 615: case MLD_LISTENER_REPORT:
1.15 itojun 616: icmp6_ifstat_inc(ifp, ifs6_out_mldreport);
617: break;
1.22 itojun 618: case MLD_LISTENER_DONE:
1.15 itojun 619: icmp6_ifstat_inc(ifp, ifs6_out_mlddone);
620: break;
1.7 itojun 621: }
1.19 itojun 622:
1.85 ozaki-r 623: /* XXX we cannot call ip6_output with holding in6_multilock */
624: rw_exit(&in6_multilock);
625:
1.27 perry 626: ip6_output(mh, &ip6_opts, NULL, ia ? 0 : IPV6_UNSPECSRC,
1.53 plunky 627: &im6o, NULL, NULL);
1.85 ozaki-r 628:
629: rw_enter(&in6_multilock, RW_WRITER);
1.2 itojun 630: }
1.31 rpaulo 631:
632: static struct mld_hdr *
1.91 maxv 633: mld_allocbuf(struct mbuf **mh, struct in6_multi *in6m, int type)
1.31 rpaulo 634: {
635: struct mbuf *md;
636: struct mld_hdr *mldh;
637: struct ip6_hdr *ip6;
638:
639: /*
640: * Allocate mbufs to store ip6 header and MLD header.
641: * We allocate 2 mbufs and make chain in advance because
642: * it is more convenient when inserting the hop-by-hop option later.
643: */
644: MGETHDR(*mh, M_DONTWAIT, MT_HEADER);
645: if (*mh == NULL)
646: return NULL;
647: MGET(md, M_DONTWAIT, MT_DATA);
648: if (md == NULL) {
649: m_free(*mh);
650: *mh = NULL;
651: return NULL;
652: }
653: (*mh)->m_next = md;
654: md->m_next = NULL;
655:
1.65 ozaki-r 656: m_reset_rcvif((*mh));
1.91 maxv 657: (*mh)->m_pkthdr.len = sizeof(struct ip6_hdr) + sizeof(struct mld_hdr);
1.31 rpaulo 658: (*mh)->m_len = sizeof(struct ip6_hdr);
659: MH_ALIGN(*mh, sizeof(struct ip6_hdr));
660:
661: /* fill in the ip6 header */
662: ip6 = mtod(*mh, struct ip6_hdr *);
663: memset(ip6, 0, sizeof(*ip6));
664: ip6->ip6_flow = 0;
665: ip6->ip6_vfc &= ~IPV6_VERSION_MASK;
666: ip6->ip6_vfc |= IPV6_VERSION;
667: /* ip6_plen will be set later */
668: ip6->ip6_nxt = IPPROTO_ICMPV6;
669: /* ip6_hlim will be set by im6o.im6o_multicast_hlim */
670: /* ip6_src/dst will be set by mld_sendpkt() or mld_sendbuf() */
671:
672: /* fill in the MLD header as much as possible */
1.91 maxv 673: md->m_len = sizeof(struct mld_hdr);
1.31 rpaulo 674: mldh = mtod(md, struct mld_hdr *);
1.91 maxv 675: memset(mldh, 0, sizeof(struct mld_hdr));
1.31 rpaulo 676: mldh->mld_type = type;
677: return mldh;
678: }
679:
1.85 ozaki-r 680: static void
681: in6m_ref(struct in6_multi *in6m)
682: {
683:
684: KASSERT(rw_write_held(&in6_multilock));
685: in6m->in6m_refcount++;
686: }
687:
688: static void
689: in6m_unref(struct in6_multi *in6m)
690: {
691:
692: KASSERT(rw_write_held(&in6_multilock));
693: if (--in6m->in6m_refcount == 0)
694: in6m_destroy(in6m);
695: }
696:
1.31 rpaulo 697: /*
698: * Add an address to the list of IP6 multicast addresses for a given interface.
699: */
700: struct in6_multi *
1.91 maxv 701: in6_addmulti(struct in6_addr *maddr6, struct ifnet *ifp, int *errorp,
702: int timer)
1.31 rpaulo 703: {
1.54 dyoung 704: struct sockaddr_in6 sin6;
1.31 rpaulo 705: struct in6_multi *in6m;
706:
707: *errorp = 0;
708:
1.85 ozaki-r 709: rw_enter(&in6_multilock, RW_WRITER);
1.31 rpaulo 710: /*
711: * See if address already in list.
712: */
1.82 ozaki-r 713: in6m = in6_lookup_multi(maddr6, ifp);
1.31 rpaulo 714: if (in6m != NULL) {
715: /*
1.91 maxv 716: * Found it; just increment the reference count.
1.31 rpaulo 717: */
718: in6m->in6m_refcount++;
719: } else {
720: /*
721: * New address; allocate a new multicast record
722: * and link it into the interface's multicast list.
723: */
1.91 maxv 724: in6m = malloc(sizeof(*in6m), M_IPMADDR, M_NOWAIT|M_ZERO);
1.31 rpaulo 725: if (in6m == NULL) {
726: *errorp = ENOBUFS;
1.85 ozaki-r 727: goto out;
1.31 rpaulo 728: }
729:
730: in6m->in6m_addr = *maddr6;
731: in6m->in6m_ifp = ifp;
732: in6m->in6m_refcount = 1;
733: in6m->in6m_timer = IN6M_TIMER_UNDEF;
1.64 joerg 734: callout_init(&in6m->in6m_timer_ch, CALLOUT_MPSAFE);
735: callout_setfunc(&in6m->in6m_timer_ch, mld_timeo, in6m);
736:
1.83 ozaki-r 737: LIST_INSERT_HEAD(&ifp->if_multiaddrs, in6m, in6m_entry);
1.31 rpaulo 738:
739: /*
740: * Ask the network driver to update its multicast reception
741: * filter appropriately for the new address.
742: */
1.54 dyoung 743: sockaddr_in6_init(&sin6, maddr6, 0, 0, 0);
744: *errorp = if_mcast_op(ifp, SIOCADDMULTI, sin6tosa(&sin6));
1.31 rpaulo 745: if (*errorp) {
1.64 joerg 746: callout_destroy(&in6m->in6m_timer_ch);
1.31 rpaulo 747: LIST_REMOVE(in6m, in6m_entry);
748: free(in6m, M_IPMADDR);
1.85 ozaki-r 749: in6m = NULL;
750: goto out;
1.31 rpaulo 751: }
752:
1.32 rpaulo 753: in6m->in6m_timer = timer;
1.31 rpaulo 754: if (in6m->in6m_timer > 0) {
755: in6m->in6m_state = MLD_REPORTPENDING;
756: mld_starttimer(in6m);
1.85 ozaki-r 757: goto out;
1.31 rpaulo 758: }
759:
760: /*
761: * Let MLD6 know that we have joined a new IP6 multicast
762: * group.
763: */
764: mld_start_listening(in6m);
765: }
1.85 ozaki-r 766: out:
767: rw_exit(&in6_multilock);
768: return in6m;
1.31 rpaulo 769: }
770:
1.85 ozaki-r 771: static void
772: in6m_destroy(struct in6_multi *in6m)
1.31 rpaulo 773: {
1.85 ozaki-r 774: struct sockaddr_in6 sin6;
775:
776: KASSERT(rw_write_held(&in6_multilock));
777: KASSERT(in6m->in6m_refcount == 0);
1.31 rpaulo 778:
1.85 ozaki-r 779: /*
780: * No remaining claims to this record; let MLD6 know
781: * that we are leaving the multicast group.
782: */
783: mld_stop_listening(in6m);
1.31 rpaulo 784:
1.85 ozaki-r 785: /*
786: * Unlink from list.
787: */
788: LIST_REMOVE(in6m, in6m_entry);
1.73 ozaki-r 789:
1.85 ozaki-r 790: /*
791: * Delete all references of this multicasting group from
792: * the membership arrays
793: */
1.86 ozaki-r 794: in6_purge_mcast_references(in6m);
1.85 ozaki-r 795:
796: /*
797: * Notify the network driver to update its multicast
798: * reception filter.
799: */
800: sockaddr_in6_init(&sin6, &in6m->in6m_addr, 0, 0, 0);
801: if_mcast_op(in6m->in6m_ifp, SIOCDELMULTI, sin6tosa(&sin6));
1.31 rpaulo 802:
1.85 ozaki-r 803: /* Tell mld_timeo we're halting the timer */
804: in6m->in6m_timer = IN6M_TIMER_UNDEF;
1.93 ozaki-r 805:
1.94 ozaki-r 806: rw_exit(&in6_multilock);
1.93 ozaki-r 807: callout_halt(&in6m->in6m_timer_ch, NULL);
1.85 ozaki-r 808: callout_destroy(&in6m->in6m_timer_ch);
1.31 rpaulo 809:
1.85 ozaki-r 810: free(in6m, M_IPMADDR);
1.94 ozaki-r 811: rw_enter(&in6_multilock, RW_WRITER);
1.85 ozaki-r 812: }
1.31 rpaulo 813:
1.85 ozaki-r 814: /*
815: * Delete a multicast address record.
816: */
817: void
1.95 ! ozaki-r 818: in6_delmulti_locked(struct in6_multi *in6m)
1.85 ozaki-r 819: {
1.61 ozaki-r 820:
1.95 ! ozaki-r 821: KASSERT(rw_write_held(&in6_multilock));
1.85 ozaki-r 822: KASSERT(in6m->in6m_refcount > 0);
1.61 ozaki-r 823:
1.85 ozaki-r 824: /*
825: * The caller should have a reference to in6m. So we don't need to care
826: * of releasing the lock in mld_stoptimer.
827: */
828: mld_stoptimer(in6m);
829: if (--in6m->in6m_refcount == 0)
830: in6m_destroy(in6m);
1.95 ! ozaki-r 831: }
! 832:
! 833: void
! 834: in6_delmulti(struct in6_multi *in6m)
! 835: {
! 836:
! 837: rw_enter(&in6_multilock, RW_WRITER);
! 838: in6_delmulti_locked(in6m);
1.85 ozaki-r 839: rw_exit(&in6_multilock);
1.31 rpaulo 840: }
841:
1.83 ozaki-r 842: /*
843: * Look up the in6_multi record for a given IP6 multicast address
844: * on a given interface. If no matching record is found, "in6m"
845: * returns NULL.
846: */
847: struct in6_multi *
848: in6_lookup_multi(const struct in6_addr *addr, const struct ifnet *ifp)
849: {
850: struct in6_multi *in6m;
851:
1.85 ozaki-r 852: KASSERT(rw_lock_held(&in6_multilock));
853:
1.83 ozaki-r 854: LIST_FOREACH(in6m, &ifp->if_multiaddrs, in6m_entry) {
855: if (IN6_ARE_ADDR_EQUAL(&in6m->in6m_addr, addr))
856: break;
857: }
858: return in6m;
859: }
860:
1.84 ozaki-r 861: bool
862: in6_multi_group(const struct in6_addr *addr, const struct ifnet *ifp)
863: {
864: bool ingroup;
865:
1.85 ozaki-r 866: rw_enter(&in6_multilock, RW_READER);
1.84 ozaki-r 867: ingroup = in6_lookup_multi(addr, ifp) != NULL;
1.85 ozaki-r 868: rw_exit(&in6_multilock);
1.84 ozaki-r 869:
870: return ingroup;
871: }
872:
1.83 ozaki-r 873: /*
874: * Purge in6_multi records associated to the interface.
875: */
876: void
877: in6_purge_multi(struct ifnet *ifp)
878: {
879: struct in6_multi *in6m, *next;
880:
1.85 ozaki-r 881: rw_enter(&in6_multilock, RW_WRITER);
1.83 ozaki-r 882: LIST_FOREACH_SAFE(in6m, &ifp->if_multiaddrs, in6m_entry, next) {
1.85 ozaki-r 883: /*
884: * Normally multicast addresses are already purged at this
885: * point. Remaining references aren't accessible via ifp,
886: * so what we can do here is to prevent ifp from being
887: * accessed via in6m by removing it from the list of ifp.
888: */
889: mld_stoptimer(in6m);
890: LIST_REMOVE(in6m, in6m_entry);
1.83 ozaki-r 891: }
1.85 ozaki-r 892: rw_exit(&in6_multilock);
1.83 ozaki-r 893: }
1.31 rpaulo 894:
1.87 ozaki-r 895: void
896: in6_multi_lock(int op)
897: {
898:
899: rw_enter(&in6_multilock, op);
900: }
901:
902: void
903: in6_multi_unlock(void)
904: {
905:
906: rw_exit(&in6_multilock);
907: }
908:
1.88 ozaki-r 909: bool
910: in6_multi_locked(int op)
911: {
912:
913: switch (op) {
914: case RW_READER:
915: return rw_read_held(&in6_multilock);
916: case RW_WRITER:
917: return rw_write_held(&in6_multilock);
918: default:
919: return rw_lock_held(&in6_multilock);
920: }
921: }
922:
1.31 rpaulo 923: struct in6_multi_mship *
1.91 maxv 924: in6_joingroup(struct ifnet *ifp, struct in6_addr *addr, int *errorp, int timer)
1.31 rpaulo 925: {
926: struct in6_multi_mship *imm;
927:
1.51 dyoung 928: imm = malloc(sizeof(*imm), M_IPMADDR, M_NOWAIT|M_ZERO);
929: if (imm == NULL) {
1.31 rpaulo 930: *errorp = ENOBUFS;
931: return NULL;
932: }
933:
1.32 rpaulo 934: imm->i6mm_maddr = in6_addmulti(addr, ifp, errorp, timer);
1.31 rpaulo 935: if (!imm->i6mm_maddr) {
1.36 dyoung 936: /* *errorp is already set */
1.31 rpaulo 937: free(imm, M_IPMADDR);
938: return NULL;
939: }
940: return imm;
941: }
942:
943: int
1.38 christos 944: in6_leavegroup(struct in6_multi_mship *imm)
1.31 rpaulo 945: {
1.88 ozaki-r 946: struct in6_multi *in6m;
1.31 rpaulo 947:
1.95 ! ozaki-r 948: rw_enter(&in6_multilock, RW_WRITER);
1.88 ozaki-r 949: in6m = imm->i6mm_maddr;
1.95 ! ozaki-r 950: imm->i6mm_maddr = NULL;
1.88 ozaki-r 951: if (in6m != NULL) {
1.95 ! ozaki-r 952: in6_delmulti_locked(in6m);
1.31 rpaulo 953: }
1.95 ! ozaki-r 954: rw_exit(&in6_multilock);
1.31 rpaulo 955: free(imm, M_IPMADDR);
956: return 0;
957: }
958:
959: /*
1.83 ozaki-r 960: * DEPRECATED: keep it just to avoid breaking old sysctl users.
1.31 rpaulo 961: */
1.57 joerg 962: static int
963: in6_mkludge_sysctl(SYSCTLFN_ARGS)
964: {
965:
966: if (namelen != 1)
967: return EINVAL;
1.83 ozaki-r 968: *oldlenp = 0;
969: return 0;
1.57 joerg 970: }
971:
972: static int
973: in6_multicast_sysctl(SYSCTLFN_ARGS)
974: {
975: struct ifnet *ifp;
976: struct ifaddr *ifa;
1.83 ozaki-r 977: struct in6_ifaddr *ia6;
1.57 joerg 978: struct in6_multi *in6m;
979: uint32_t tmp;
980: int error;
981: size_t written;
1.74 ozaki-r 982: struct psref psref, psref_ia;
983: int bound, s;
1.57 joerg 984:
985: if (namelen != 1)
986: return EINVAL;
987:
1.85 ozaki-r 988: rw_enter(&in6_multilock, RW_READER);
989:
1.67 ozaki-r 990: bound = curlwp_bind();
991: ifp = if_get_byindex(name[0], &psref);
992: if (ifp == NULL) {
993: curlwp_bindx(bound);
1.85 ozaki-r 994: rw_exit(&in6_multilock);
1.57 joerg 995: return ENODEV;
1.67 ozaki-r 996: }
1.57 joerg 997:
998: if (oldp == NULL) {
999: *oldlenp = 0;
1.74 ozaki-r 1000: s = pserialize_read_enter();
1.71 ozaki-r 1001: IFADDR_READER_FOREACH(ifa, ifp) {
1.83 ozaki-r 1002: LIST_FOREACH(in6m, &ifp->if_multiaddrs, in6m_entry) {
1.57 joerg 1003: *oldlenp += 2 * sizeof(struct in6_addr) +
1004: sizeof(uint32_t);
1005: }
1006: }
1.74 ozaki-r 1007: pserialize_read_exit(s);
1.67 ozaki-r 1008: if_put(ifp, &psref);
1009: curlwp_bindx(bound);
1.85 ozaki-r 1010: rw_exit(&in6_multilock);
1.57 joerg 1011: return 0;
1012: }
1013:
1014: error = 0;
1015: written = 0;
1.74 ozaki-r 1016: s = pserialize_read_enter();
1.71 ozaki-r 1017: IFADDR_READER_FOREACH(ifa, ifp) {
1.57 joerg 1018: if (ifa->ifa_addr->sa_family != AF_INET6)
1019: continue;
1.74 ozaki-r 1020:
1021: ifa_acquire(ifa, &psref_ia);
1022: pserialize_read_exit(s);
1023:
1.83 ozaki-r 1024: ia6 = ifatoia6(ifa);
1025: LIST_FOREACH(in6m, &ifp->if_multiaddrs, in6m_entry) {
1.57 joerg 1026: if (written + 2 * sizeof(struct in6_addr) +
1027: sizeof(uint32_t) > *oldlenp)
1028: goto done;
1.83 ozaki-r 1029: /*
1030: * XXX return the first IPv6 address to keep backward
1031: * compatibility, however now multicast addresses
1032: * don't belong to any IPv6 addresses so it should be
1033: * unnecessary.
1034: */
1035: error = sysctl_copyout(l, &ia6->ia_addr.sin6_addr,
1.57 joerg 1036: oldp, sizeof(struct in6_addr));
1037: if (error)
1038: goto done;
1039: oldp = (char *)oldp + sizeof(struct in6_addr);
1040: written += sizeof(struct in6_addr);
1041: error = sysctl_copyout(l, &in6m->in6m_addr,
1042: oldp, sizeof(struct in6_addr));
1043: if (error)
1044: goto done;
1045: oldp = (char *)oldp + sizeof(struct in6_addr);
1046: written += sizeof(struct in6_addr);
1047: tmp = in6m->in6m_refcount;
1048: error = sysctl_copyout(l, &tmp, oldp, sizeof(tmp));
1049: if (error)
1050: goto done;
1051: oldp = (char *)oldp + sizeof(tmp);
1052: written += sizeof(tmp);
1053: }
1.74 ozaki-r 1054:
1055: s = pserialize_read_enter();
1.83 ozaki-r 1056:
1057: break;
1.57 joerg 1058: }
1.74 ozaki-r 1059: pserialize_read_exit(s);
1.57 joerg 1060: done:
1.74 ozaki-r 1061: ifa_release(ifa, &psref_ia);
1.67 ozaki-r 1062: if_put(ifp, &psref);
1063: curlwp_bindx(bound);
1.85 ozaki-r 1064: rw_exit(&in6_multilock);
1.57 joerg 1065: *oldlenp = written;
1066: return error;
1067: }
1068:
1.76 ozaki-r 1069: void
1070: in6_sysctl_multicast_setup(struct sysctllog **clog)
1.57 joerg 1071: {
1072:
1073: sysctl_createv(clog, 0, NULL, NULL,
1074: CTLFLAG_PERMANENT,
1.59 joerg 1075: CTLTYPE_NODE, "inet6", NULL,
1076: NULL, 0, NULL, 0,
1077: CTL_NET, PF_INET6, CTL_EOL);
1078:
1079: sysctl_createv(clog, 0, NULL, NULL,
1080: CTLFLAG_PERMANENT,
1.57 joerg 1081: CTLTYPE_NODE, "multicast",
1082: SYSCTL_DESCR("Multicast information"),
1083: in6_multicast_sysctl, 0, NULL, 0,
1084: CTL_NET, PF_INET6, CTL_CREATE, CTL_EOL);
1085:
1086: sysctl_createv(clog, 0, NULL, NULL,
1087: CTLFLAG_PERMANENT,
1088: CTLTYPE_NODE, "multicast_kludge",
1089: SYSCTL_DESCR("multicast kludge information"),
1090: in6_mkludge_sysctl, 0, NULL, 0,
1091: CTL_NET, PF_INET6, CTL_CREATE, CTL_EOL);
1092: }
CVSweb <webmaster@jp.NetBSD.org>