1 /* $NetBSD: mld6.c,v 1.50 2009/04/18 14:58:05 tsutsui Exp $ */
2 /* $KAME: mld6.c,v 1.25 2001/01/16 14:14:18 itojun Exp $ */
5 * Copyright (C) 1998 WIDE Project.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
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.
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
34 * Copyright (c) 1992, 1993
35 * The Regents of the University of California. All rights reserved.
37 * This code is derived from software contributed to Berkeley by
38 * Stephen Deering of Stanford University.
40 * Redistribution and use in source and binary forms, with or without
41 * modification, are permitted provided that the following conditions
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.
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.
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
64 * @(#)igmp.c 8.1 (Berkeley) 7/19/93
68 * Copyright (c) 1988 Stephen Deering.
70 * This code is derived from software contributed to Berkeley by
71 * Stephen Deering of Stanford University.
73 * Redistribution and use in source and binary forms, with or without
74 * modification, are permitted provided that the following conditions
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.
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.
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
101 * @(#)igmp.c 8.1 (Berkeley) 7/19/93
104 #include <sys/cdefs.h>
105 __KERNEL_RCSID(0, "$NetBSD: mld6.c,v 1.50 2009/04/18 14:58:05 tsutsui Exp $");
107 #include "opt_inet.h"
109 #include <sys/param.h>
110 #include <sys/systm.h>
111 #include <sys/mbuf.h>
112 #include <sys/socket.h>
113 #include <sys/socketvar.h>
114 #include <sys/protosw.h>
115 #include <sys/syslog.h>
116 #include <sys/sysctl.h>
117 #include <sys/kernel.h>
118 #include <sys/callout.h>
122 #include <netinet/in.h>
123 #include <netinet/in_var.h>
124 #include <netinet6/in6_var.h>
125 #include <netinet/ip6.h>
126 #include <netinet6/ip6_var.h>
127 #include <netinet6/scope6_var.h>
128 #include <netinet/icmp6.h>
129 #include <netinet6/icmp6_private.h>
130 #include <netinet6/mld6_var.h>
132 #include <net/net_osdep.h>
136 * This structure is used to keep track of in6_multi chains which belong to
137 * deleted interface addresses.
139 static LIST_HEAD(, multi6_kludge
) in6_mk
; /* XXX BSS initialization */
141 struct multi6_kludge
{
142 LIST_ENTRY(multi6_kludge
) mk_entry
;
143 struct ifnet
*mk_ifp
;
144 struct in6_multihead mk_head
;
153 * time between repetitions of a node's initial report of interest in a
154 * multicast address(in seconds)
156 #define MLD_UNSOLICITED_REPORT_INTERVAL 10
158 static struct ip6_pktopts ip6_opts
;
160 static void mld_start_listening(struct in6_multi
*);
161 static void mld_stop_listening(struct in6_multi
*);
163 static struct mld_hdr
* mld_allocbuf(struct mbuf
**, int, struct in6_multi
*,
165 static void mld_sendpkt(struct in6_multi
*, int, const struct in6_addr
*);
166 static void mld_starttimer(struct in6_multi
*);
167 static void mld_stoptimer(struct in6_multi
*);
168 static u_long
mld_timerresid(struct in6_multi
*);
173 static u_int8_t hbh_buf
[8];
174 struct ip6_hbh
*hbh
= (struct ip6_hbh
*)hbh_buf
;
175 u_int16_t rtalert_code
= htons((u_int16_t
)IP6OPT_RTALERT_MLD
);
177 /* ip6h_nxt will be fill in later */
178 hbh
->ip6h_len
= 0; /* (8 >> 3) - 1 */
180 /* XXX: grotty hard coding... */
181 hbh_buf
[2] = IP6OPT_PADN
; /* 2 byte padding */
183 hbh_buf
[4] = IP6OPT_RTALERT
;
184 hbh_buf
[5] = IP6OPT_RTALERT_LEN
- 2;
185 memcpy(&hbh_buf
[6], (void *)&rtalert_code
, sizeof(u_int16_t
));
187 ip6_opts
.ip6po_hbh
= hbh
;
188 /* We will specify the hoplimit by a multicast option. */
189 ip6_opts
.ip6po_hlim
= -1;
193 mld_starttimer(struct in6_multi
*in6m
)
198 in6m
->in6m_timer_expire
.tv_sec
= now
.tv_sec
+ in6m
->in6m_timer
/ hz
;
199 in6m
->in6m_timer_expire
.tv_usec
= now
.tv_usec
+
200 (in6m
->in6m_timer
% hz
) * (1000000 / hz
);
201 if (in6m
->in6m_timer_expire
.tv_usec
> 1000000) {
202 in6m
->in6m_timer_expire
.tv_sec
++;
203 in6m
->in6m_timer_expire
.tv_usec
-= 1000000;
206 /* start or restart the timer */
207 callout_schedule(&in6m
->in6m_timer_ch
, in6m
->in6m_timer
);
211 mld_stoptimer(struct in6_multi
*in6m
)
213 if (in6m
->in6m_timer
== IN6M_TIMER_UNDEF
)
216 callout_stop(&in6m
->in6m_timer_ch
);
218 in6m
->in6m_timer
= IN6M_TIMER_UNDEF
;
224 struct in6_multi
*in6m
= arg
;
226 mutex_enter(softnet_lock
);
227 KERNEL_LOCK(1, NULL
);
229 in6m
->in6m_timer
= IN6M_TIMER_UNDEF
;
231 switch (in6m
->in6m_state
) {
232 case MLD_REPORTPENDING
:
233 mld_start_listening(in6m
);
236 mld_sendpkt(in6m
, MLD_LISTENER_REPORT
, NULL
);
240 KERNEL_UNLOCK_ONE(NULL
);
241 mutex_exit(softnet_lock
);
245 mld_timerresid(struct in6_multi
*in6m
)
247 struct timeval now
, diff
;
251 if (now
.tv_sec
> in6m
->in6m_timer_expire
.tv_sec
||
252 (now
.tv_sec
== in6m
->in6m_timer_expire
.tv_sec
&&
253 now
.tv_usec
> in6m
->in6m_timer_expire
.tv_usec
)) {
256 diff
= in6m
->in6m_timer_expire
;
257 diff
.tv_sec
-= now
.tv_sec
;
258 diff
.tv_usec
-= now
.tv_usec
;
259 if (diff
.tv_usec
< 0) {
261 diff
.tv_usec
+= 1000000;
264 /* return the remaining time in milliseconds */
265 return diff
.tv_sec
* 1000 + diff
.tv_usec
/ 1000;
269 mld_start_listening(struct in6_multi
*in6m
)
271 struct in6_addr all_in6
;
275 * The node never sends a Report or Done for the link-scope all-nodes
277 * MLD messages are never sent for multicast addresses whose scope is 0
278 * (reserved) or 1 (node-local).
280 all_in6
= in6addr_linklocal_allnodes
;
281 if (in6_setscope(&all_in6
, in6m
->in6m_ifp
, NULL
)) {
282 /* XXX: this should not happen! */
283 in6m
->in6m_timer
= 0;
284 in6m
->in6m_state
= MLD_OTHERLISTENER
;
286 if (IN6_ARE_ADDR_EQUAL(&in6m
->in6m_addr
, &all_in6
) ||
287 IPV6_ADDR_MC_SCOPE(&in6m
->in6m_addr
) < IPV6_ADDR_SCOPE_LINKLOCAL
) {
288 in6m
->in6m_timer
= IN6M_TIMER_UNDEF
;
289 in6m
->in6m_state
= MLD_OTHERLISTENER
;
291 mld_sendpkt(in6m
, MLD_LISTENER_REPORT
, NULL
);
292 in6m
->in6m_timer
= arc4random() %
293 (MLD_UNSOLICITED_REPORT_INTERVAL
* hz
);
294 in6m
->in6m_state
= MLD_IREPORTEDLAST
;
296 mld_starttimer(in6m
);
301 mld_stop_listening(struct in6_multi
*in6m
)
303 struct in6_addr allnode
, allrouter
;
305 allnode
= in6addr_linklocal_allnodes
;
306 if (in6_setscope(&allnode
, in6m
->in6m_ifp
, NULL
)) {
307 /* XXX: this should not happen! */
310 allrouter
= in6addr_linklocal_allrouters
;
311 if (in6_setscope(&allrouter
, in6m
->in6m_ifp
, NULL
)) {
316 if (in6m
->in6m_state
== MLD_IREPORTEDLAST
&&
317 (!IN6_ARE_ADDR_EQUAL(&in6m
->in6m_addr
, &allnode
)) &&
318 IPV6_ADDR_MC_SCOPE(&in6m
->in6m_addr
) >
319 IPV6_ADDR_SCOPE_INTFACELOCAL
) {
320 mld_sendpkt(in6m
, MLD_LISTENER_DONE
, &allrouter
);
325 mld_input(struct mbuf
*m
, int off
)
327 struct ip6_hdr
*ip6
= mtod(m
, struct ip6_hdr
*);
328 struct mld_hdr
*mldh
;
329 struct ifnet
*ifp
= m
->m_pkthdr
.rcvif
;
330 struct in6_multi
*in6m
= NULL
;
331 struct in6_addr mld_addr
, all_in6
;
332 struct in6_ifaddr
*ia
;
333 u_long timer
= 0; /* timer value in the MLD query header */
335 IP6_EXTHDR_GET(mldh
, struct mld_hdr
*, m
, off
, sizeof(*mldh
));
337 ICMP6_STATINC(ICMP6_STAT_TOOSHORT
);
341 /* source address validation */
342 ip6
= mtod(m
, struct ip6_hdr
*);/* in case mpullup */
343 if (!IN6_IS_ADDR_LINKLOCAL(&ip6
->ip6_src
)) {
345 * RFC3590 allows the IPv6 unspecified address as the source
346 * address of MLD report and done messages. However, as this
347 * same document says, this special rule is for snooping
348 * switches and the RFC requires routers to discard MLD packets
349 * with the unspecified source address. The RFC only talks
350 * about hosts receiving an MLD query or report in Security
351 * Considerations, but this is probably the correct intention.
352 * RFC3590 does not talk about other cases than link-local and
353 * the unspecified source addresses, but we believe the same
354 * rule should be applied.
355 * As a result, we only allow link-local addresses as the
356 * source address; otherwise, simply discard the packet.
360 * XXX: do not log in an input path to avoid log flooding,
361 * though RFC3590 says "SHOULD log" if the source of a query
362 * is the unspecified address.
365 "mld_input: src %s is not link-local (grp=%s)\n",
366 ip6_sprintf(&ip6
->ip6_src
), ip6_sprintf(&mldh
->mld_addr
));
373 * make a copy for local work (in6_setscope() may modify the 1st arg)
375 mld_addr
= mldh
->mld_addr
;
376 if (in6_setscope(&mld_addr
, ifp
, NULL
)) {
377 /* XXX: this should not happen! */
383 * In the MLD specification, there are 3 states and a flag.
385 * In Non-Listener state, we simply don't have a membership record.
386 * In Delaying Listener state, our timer is running (in6m->in6m_timer)
387 * In Idle Listener state, our timer is not running
388 * (in6m->in6m_timer==IN6M_TIMER_UNDEF)
390 * The flag is in6m->in6m_state, it is set to MLD_OTHERLISTENER if
391 * we have heard a report from another member, or MLD_IREPORTEDLAST
392 * if we sent the last report.
394 switch (mldh
->mld_type
) {
395 case MLD_LISTENER_QUERY
:
396 if (ifp
->if_flags
& IFF_LOOPBACK
)
399 if (!IN6_IS_ADDR_UNSPECIFIED(&mld_addr
) &&
400 !IN6_IS_ADDR_MULTICAST(&mld_addr
))
401 break; /* print error or log stat? */
403 all_in6
= in6addr_linklocal_allnodes
;
404 if (in6_setscope(&all_in6
, ifp
, NULL
)) {
405 /* XXX: this should not happen! */
410 * - Start the timers in all of our membership records
411 * that the query applies to for the interface on
412 * which the query arrived excl. those that belong
413 * to the "all-nodes" group (ff02::1).
414 * - Restart any timer that is already running but has
415 * a value longer than the requested timeout.
416 * - Use the value specified in the query message as
417 * the maximum timeout.
419 timer
= ntohs(mldh
->mld_maxdelay
);
425 LIST_FOREACH(in6m
, &ia
->ia6_multiaddrs
, in6m_entry
) {
426 if (IN6_ARE_ADDR_EQUAL(&in6m
->in6m_addr
, &all_in6
) ||
427 IPV6_ADDR_MC_SCOPE(&in6m
->in6m_addr
) <
428 IPV6_ADDR_SCOPE_LINKLOCAL
)
431 if (in6m
->in6m_state
== MLD_REPORTPENDING
)
432 continue; /* we are not yet ready */
434 if (!IN6_IS_ADDR_UNSPECIFIED(&mld_addr
) &&
435 !IN6_ARE_ADDR_EQUAL(&mld_addr
, &in6m
->in6m_addr
))
439 /* send a report immediately */
441 mld_sendpkt(in6m
, MLD_LISTENER_REPORT
, NULL
);
442 in6m
->in6m_state
= MLD_IREPORTEDLAST
;
443 } else if (in6m
->in6m_timer
== IN6M_TIMER_UNDEF
||
444 mld_timerresid(in6m
) > timer
) {
446 1 + (arc4random() % timer
) * hz
/ 1000;
447 mld_starttimer(in6m
);
452 case MLD_LISTENER_REPORT
:
454 * For fast leave to work, we have to know that we are the
455 * last person to send a report for this group. Reports
456 * can potentially get looped back if we are a multicast
457 * router, so discard reports sourced by me.
458 * Note that it is impossible to check IFF_LOOPBACK flag of
459 * ifp for this purpose, since ip6_mloopback pass the physical
460 * interface to looutput.
462 if (m
->m_flags
& M_LOOP
) /* XXX: grotty flag, but efficient */
465 if (!IN6_IS_ADDR_MULTICAST(&mldh
->mld_addr
))
469 * If we belong to the group being reported, stop
470 * our timer for that group.
472 IN6_LOOKUP_MULTI(mld_addr
, ifp
, in6m
);
474 mld_stoptimer(in6m
); /* transit to idle state */
475 in6m
->in6m_state
= MLD_OTHERLISTENER
; /* clear flag */
478 default: /* this is impossible */
481 * this case should be impossible because of filtering in
482 * icmp6_input(). But we explicitly disabled this part
485 log(LOG_ERR
, "mld_input: illegal type(%d)", mldh
->mld_type
);
494 mld_sendpkt(struct in6_multi
*in6m
, int type
,
495 const struct in6_addr
*dst
)
498 struct mld_hdr
*mldh
;
499 struct ip6_hdr
*ip6
= NULL
;
500 struct ip6_moptions im6o
;
501 struct in6_ifaddr
*ia
= NULL
;
502 struct ifnet
*ifp
= in6m
->in6m_ifp
;
506 * At first, find a link local address on the outgoing interface
507 * to use as the source address of the MLD packet.
508 * We do not reject tentative addresses for MLD report to deal with
509 * the case where we first join a link-local address.
511 ignflags
= (IN6_IFF_NOTREADY
|IN6_IFF_ANYCAST
) & ~IN6_IFF_TENTATIVE
;
512 if ((ia
= in6ifa_ifpforlinklocal(ifp
, ignflags
)) == NULL
)
514 if ((ia
->ia6_flags
& IN6_IFF_TENTATIVE
))
517 /* Allocate two mbufs to store IPv6 header and MLD header */
518 mldh
= mld_allocbuf(&mh
, sizeof(struct mld_hdr
), in6m
, type
);
522 /* fill src/dst here */
523 ip6
= mtod(mh
, struct ip6_hdr
*);
524 ip6
->ip6_src
= ia
? ia
->ia_addr
.sin6_addr
: in6addr_any
;
525 ip6
->ip6_dst
= dst
? *dst
: in6m
->in6m_addr
;
527 mldh
->mld_addr
= in6m
->in6m_addr
;
528 in6_clearscope(&mldh
->mld_addr
); /* XXX */
529 mldh
->mld_cksum
= in6_cksum(mh
, IPPROTO_ICMPV6
, sizeof(struct ip6_hdr
),
530 sizeof(struct mld_hdr
));
532 /* construct multicast option */
533 memset(&im6o
, 0, sizeof(im6o
));
534 im6o
.im6o_multicast_ifp
= ifp
;
535 im6o
.im6o_multicast_hlim
= 1;
538 * Request loopback of the report if we are acting as a multicast
539 * router, so that the process-level routing daemon can hear it.
541 im6o
.im6o_multicast_loop
= (ip6_mrouter
!= NULL
);
543 /* increment output statictics */
544 ICMP6_STATINC(ICMP6_STAT_OUTHIST
+ type
);
545 icmp6_ifstat_inc(ifp
, ifs6_out_msg
);
547 case MLD_LISTENER_QUERY
:
548 icmp6_ifstat_inc(ifp
, ifs6_out_mldquery
);
550 case MLD_LISTENER_REPORT
:
551 icmp6_ifstat_inc(ifp
, ifs6_out_mldreport
);
553 case MLD_LISTENER_DONE
:
554 icmp6_ifstat_inc(ifp
, ifs6_out_mlddone
);
558 ip6_output(mh
, &ip6_opts
, NULL
, ia
? 0 : IPV6_UNSPECSRC
,
559 &im6o
, (struct socket
*)NULL
, NULL
);
562 static struct mld_hdr
*
563 mld_allocbuf(struct mbuf
**mh
, int len
, struct in6_multi
*in6m
,
567 struct mld_hdr
*mldh
;
571 * Allocate mbufs to store ip6 header and MLD header.
572 * We allocate 2 mbufs and make chain in advance because
573 * it is more convenient when inserting the hop-by-hop option later.
575 MGETHDR(*mh
, M_DONTWAIT
, MT_HEADER
);
578 MGET(md
, M_DONTWAIT
, MT_DATA
);
587 (*mh
)->m_pkthdr
.rcvif
= NULL
;
588 (*mh
)->m_pkthdr
.len
= sizeof(struct ip6_hdr
) + len
;
589 (*mh
)->m_len
= sizeof(struct ip6_hdr
);
590 MH_ALIGN(*mh
, sizeof(struct ip6_hdr
));
592 /* fill in the ip6 header */
593 ip6
= mtod(*mh
, struct ip6_hdr
*);
594 memset(ip6
, 0, sizeof(*ip6
));
596 ip6
->ip6_vfc
&= ~IPV6_VERSION_MASK
;
597 ip6
->ip6_vfc
|= IPV6_VERSION
;
598 /* ip6_plen will be set later */
599 ip6
->ip6_nxt
= IPPROTO_ICMPV6
;
600 /* ip6_hlim will be set by im6o.im6o_multicast_hlim */
601 /* ip6_src/dst will be set by mld_sendpkt() or mld_sendbuf() */
603 /* fill in the MLD header as much as possible */
605 mldh
= mtod(md
, struct mld_hdr
*);
606 memset(mldh
, 0, len
);
607 mldh
->mld_type
= type
;
612 * Add an address to the list of IP6 multicast addresses for a given interface.
615 in6_addmulti(struct in6_addr
*maddr6
, struct ifnet
*ifp
,
616 int *errorp
, int timer
)
618 struct in6_ifaddr
*ia
;
619 struct in6_ifreq ifr
;
620 struct in6_multi
*in6m
;
621 int s
= splsoftnet();
626 * See if address already in list.
628 IN6_LOOKUP_MULTI(*maddr6
, ifp
, in6m
);
631 * Found it; just increment the refrence count.
633 in6m
->in6m_refcount
++;
636 * New address; allocate a new multicast record
637 * and link it into the interface's multicast list.
639 in6m
= (struct in6_multi
*)
640 malloc(sizeof(*in6m
), M_IPMADDR
, M_NOWAIT
|M_ZERO
);
647 in6m
->in6m_addr
= *maddr6
;
648 in6m
->in6m_ifp
= ifp
;
649 in6m
->in6m_refcount
= 1;
650 in6m
->in6m_timer
= IN6M_TIMER_UNDEF
;
653 free(in6m
, M_IPMADDR
);
655 *errorp
= EADDRNOTAVAIL
; /* appropriate? */
659 IFAREF(&ia
->ia_ifa
); /* gain a reference */
660 LIST_INSERT_HEAD(&ia
->ia6_multiaddrs
, in6m
, in6m_entry
);
663 * Ask the network driver to update its multicast reception
664 * filter appropriately for the new address.
666 sockaddr_in6_init(&ifr
.ifr_addr
, maddr6
, 0, 0, 0);
667 *errorp
= (*ifp
->if_ioctl
)(ifp
, SIOCADDMULTI
, &ifr
);
669 LIST_REMOVE(in6m
, in6m_entry
);
670 free(in6m
, M_IPMADDR
);
671 IFAFREE(&ia
->ia_ifa
);
676 callout_init(&in6m
->in6m_timer_ch
, CALLOUT_MPSAFE
);
677 callout_setfunc(&in6m
->in6m_timer_ch
, mld_timeo
, in6m
);
678 in6m
->in6m_timer
= timer
;
679 if (in6m
->in6m_timer
> 0) {
680 in6m
->in6m_state
= MLD_REPORTPENDING
;
681 mld_starttimer(in6m
);
688 * Let MLD6 know that we have joined a new IP6 multicast
691 mld_start_listening(in6m
);
698 * Delete a multicast address record.
701 in6_delmulti(struct in6_multi
*in6m
)
703 struct in6_ifreq ifr
;
704 struct in6_ifaddr
*ia
;
705 int s
= splsoftnet();
709 if (--in6m
->in6m_refcount
== 0) {
711 * No remaining claims to this record; let MLD6 know
712 * that we are leaving the multicast group.
714 mld_stop_listening(in6m
);
719 LIST_REMOVE(in6m
, in6m_entry
);
720 if (in6m
->in6m_ia
!= NULL
) {
721 IFAFREE(&in6m
->in6m_ia
->ia_ifa
); /* release reference */
722 in6m
->in6m_ia
= NULL
;
726 * Delete all references of this multicasting group from
727 * the membership arrays
729 for (ia
= in6_ifaddr
; ia
; ia
= ia
->ia_next
) {
730 struct in6_multi_mship
*imm
;
731 LIST_FOREACH(imm
, &ia
->ia6_memberships
, i6mm_chain
) {
732 if (imm
->i6mm_maddr
== in6m
)
733 imm
->i6mm_maddr
= NULL
;
738 * Notify the network driver to update its multicast
741 sockaddr_in6_init(&ifr
.ifr_addr
, &in6m
->in6m_addr
, 0, 0, 0);
742 (*in6m
->in6m_ifp
->if_ioctl
)(in6m
->in6m_ifp
, SIOCDELMULTI
, &ifr
);
743 callout_destroy(&in6m
->in6m_timer_ch
);
744 free(in6m
, M_IPMADDR
);
750 struct in6_multi_mship
*
751 in6_joingroup(struct ifnet
*ifp
, struct in6_addr
*addr
,
752 int *errorp
, int timer
)
754 struct in6_multi_mship
*imm
;
756 imm
= malloc(sizeof(*imm
), M_IPMADDR
, M_NOWAIT
|M_ZERO
);
762 imm
->i6mm_maddr
= in6_addmulti(addr
, ifp
, errorp
, timer
);
763 if (!imm
->i6mm_maddr
) {
764 /* *errorp is already set */
765 free(imm
, M_IPMADDR
);
772 in6_leavegroup(struct in6_multi_mship
*imm
)
775 if (imm
->i6mm_maddr
) {
776 in6_delmulti(imm
->i6mm_maddr
);
778 free(imm
, M_IPMADDR
);
784 * Multicast address kludge:
785 * If there were any multicast addresses attached to this interface address,
786 * either move them to another address on this interface, or save them until
787 * such time as this interface is reconfigured for IPv6.
790 in6_savemkludge(struct in6_ifaddr
*oia
)
792 struct in6_ifaddr
*ia
;
793 struct in6_multi
*in6m
;
795 IFP_TO_IA6(oia
->ia_ifp
, ia
);
796 if (ia
) { /* there is another address */
798 while ((in6m
= LIST_FIRST(&oia
->ia6_multiaddrs
)) != NULL
) {
799 LIST_REMOVE(in6m
, in6m_entry
);
801 IFAFREE(&in6m
->in6m_ia
->ia_ifa
);
803 LIST_INSERT_HEAD(&ia
->ia6_multiaddrs
, in6m
, in6m_entry
);
805 } else { /* last address on this if deleted, save */
806 struct multi6_kludge
*mk
;
808 LIST_FOREACH(mk
, &in6_mk
, mk_entry
) {
809 if (mk
->mk_ifp
== oia
->ia_ifp
)
812 if (mk
== NULL
) /* this should not happen! */
813 panic("in6_savemkludge: no kludge space");
815 while ((in6m
= LIST_FIRST(&oia
->ia6_multiaddrs
)) != NULL
) {
816 LIST_REMOVE(in6m
, in6m_entry
);
817 IFAFREE(&in6m
->in6m_ia
->ia_ifa
); /* release reference */
818 in6m
->in6m_ia
= NULL
;
819 LIST_INSERT_HEAD(&mk
->mk_head
, in6m
, in6m_entry
);
825 * Continuation of multicast address hack:
826 * If there was a multicast group list previously saved for this interface,
827 * then we re-attach it to the first address configured on the i/f.
830 in6_restoremkludge(struct in6_ifaddr
*ia
, struct ifnet
*ifp
)
832 struct multi6_kludge
*mk
;
833 struct in6_multi
*in6m
;
835 LIST_FOREACH(mk
, &in6_mk
, mk_entry
) {
836 if (mk
->mk_ifp
== ifp
)
841 while ((in6m
= LIST_FIRST(&mk
->mk_head
)) != NULL
) {
842 LIST_REMOVE(in6m
, in6m_entry
);
845 LIST_INSERT_HEAD(&ia
->ia6_multiaddrs
, in6m
, in6m_entry
);
850 * Allocate space for the kludge at interface initialization time.
851 * Formerly, we dynamically allocated the space in in6_savemkludge() with
852 * malloc(M_WAITOK). However, it was wrong since the function could be called
853 * under an interrupt context (software timer on address lifetime expiration).
854 * Also, we cannot just give up allocating the strucutre, since the group
855 * membership structure is very complex and we need to keep it anyway.
856 * Of course, this function MUST NOT be called under an interrupt context.
857 * Specifically, it is expected to be called only from in6_ifattach(), though
858 * it is a global function.
861 in6_createmkludge(struct ifnet
*ifp
)
863 struct multi6_kludge
*mk
;
865 LIST_FOREACH(mk
, &in6_mk
, mk_entry
) {
866 /* If we've already had one, do not allocate. */
867 if (mk
->mk_ifp
== ifp
)
871 mk
= malloc(sizeof(*mk
), M_IPMADDR
, M_ZERO
|M_WAITOK
);
873 LIST_INIT(&mk
->mk_head
);
875 LIST_INSERT_HEAD(&in6_mk
, mk
, mk_entry
);
879 in6_purgemkludge(struct ifnet
*ifp
)
881 struct multi6_kludge
*mk
;
882 struct in6_multi
*in6m
, *next
;
884 LIST_FOREACH(mk
, &in6_mk
, mk_entry
) {
885 if (mk
->mk_ifp
== ifp
)
891 /* leave from all multicast groups joined */
892 for (in6m
= LIST_FIRST(&mk
->mk_head
); in6m
!= NULL
; in6m
= next
) {
893 next
= LIST_NEXT(in6m
, in6m_entry
);
896 LIST_REMOVE(mk
, mk_entry
);