]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/netinet6/mld6.c
This commit was generated by cvs2svn to compensate for changes in r168463,
[FreeBSD/FreeBSD.git] / sys / netinet6 / mld6.c
1 /*      $FreeBSD$       */
2 /*      $KAME: mld6.c,v 1.27 2001/04/04 05:17:30 itojun Exp $   */
3
4 /*-
5  * Copyright (C) 1998 WIDE Project.
6  * All rights reserved.
7  *
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.
19  *
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  * 4. Neither the name of the University nor the names of its contributors
50  *    may be used to endorse or promote products derived from this software
51  *    without specific prior written permission.
52  *
53  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
54  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
55  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
56  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
57  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
58  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
59  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
60  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
61  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
62  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
63  * SUCH DAMAGE.
64  *
65  *      @(#)igmp.c      8.1 (Berkeley) 7/19/93
66  */
67
68 #include "opt_inet.h"
69 #include "opt_inet6.h"
70
71 #include <sys/param.h>
72 #include <sys/systm.h>
73 #include <sys/mbuf.h>
74 #include <sys/socket.h>
75 #include <sys/protosw.h>
76 #include <sys/syslog.h>
77 #include <sys/kernel.h>
78 #include <sys/callout.h>
79 #include <sys/malloc.h>
80
81 #include <net/if.h>
82
83 #include <netinet/in.h>
84 #include <netinet/in_var.h>
85 #include <netinet6/in6_var.h>
86 #include <netinet/ip6.h>
87 #include <netinet6/ip6_var.h>
88 #include <netinet6/scope6_var.h>
89 #include <netinet/icmp6.h>
90 #include <netinet6/mld6_var.h>
91
92 /*
93  * Protocol constants
94  */
95
96 /* denotes that the MLD max response delay field specifies time in milliseconds */
97 #define MLD_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 MLD_UNSOLICITED_REPORT_INTERVAL 10
103
104 static struct ip6_pktopts ip6_opts;
105
106 static void mld6_sendpkt(struct in6_multi *, int, const struct in6_addr *);
107 static void mld_starttimer(struct in6_multi *);
108 static void mld_stoptimer(struct in6_multi *);
109 static void mld_timeo(struct in6_multi *);
110 static u_long mld_timerresid(struct in6_multi *);
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         /* ip6h_nxt will be fill in later */
120         hbh->ip6h_len = 0;      /* (8 >> 3) - 1 */
121
122         /* XXX: grotty hard coding... */
123         hbh_buf[2] = IP6OPT_PADN;       /* 2 byte padding */
124         hbh_buf[3] = 0;
125         hbh_buf[4] = IP6OPT_ROUTER_ALERT;
126         hbh_buf[5] = IP6OPT_RTALERT_LEN - 2;
127         bcopy((caddr_t)&rtalert_code, &hbh_buf[6], sizeof(u_int16_t));
128
129         ip6_initpktopts(&ip6_opts);
130         ip6_opts.ip6po_hbh = hbh;
131 }
132
133 static void
134 mld_starttimer(in6m)
135         struct in6_multi *in6m;
136 {
137         struct timeval now;
138
139         microtime(&now);
140         in6m->in6m_timer_expire.tv_sec = now.tv_sec + in6m->in6m_timer / hz;
141         in6m->in6m_timer_expire.tv_usec = now.tv_usec +
142             (in6m->in6m_timer % hz) * (1000000 / hz);
143         if (in6m->in6m_timer_expire.tv_usec > 1000000) {
144                 in6m->in6m_timer_expire.tv_sec++;
145                 in6m->in6m_timer_expire.tv_usec -= 1000000;
146         }
147
148         /* start or restart the timer */
149         callout_reset(in6m->in6m_timer_ch, in6m->in6m_timer,
150             (void (*) __P((void *)))mld_timeo, in6m);
151 }
152
153 static void
154 mld_stoptimer(in6m)
155         struct in6_multi *in6m;
156 {
157         if (in6m->in6m_timer == IN6M_TIMER_UNDEF)
158                 return;
159
160         callout_stop(in6m->in6m_timer_ch);
161         in6m->in6m_timer = IN6M_TIMER_UNDEF;
162 }
163
164 static void
165 mld_timeo(in6m)
166         struct in6_multi *in6m;
167 {
168         int s = splnet();
169
170         in6m->in6m_timer = IN6M_TIMER_UNDEF;
171
172         callout_stop(in6m->in6m_timer_ch);
173
174         switch (in6m->in6m_state) {
175         case MLD_REPORTPENDING:
176                 mld6_start_listening(in6m);
177                 break;
178         default:
179                 mld6_sendpkt(in6m, MLD_LISTENER_REPORT, NULL);
180                 break;
181         }
182
183         splx(s);
184 }
185
186 static u_long
187 mld_timerresid(in6m)
188         struct in6_multi *in6m;
189 {
190         struct timeval now, diff;
191
192         microtime(&now);
193
194         if (now.tv_sec > in6m->in6m_timer_expire.tv_sec ||
195             (now.tv_sec == in6m->in6m_timer_expire.tv_sec &&
196             now.tv_usec > in6m->in6m_timer_expire.tv_usec)) {
197                 return (0);
198         }
199         diff = in6m->in6m_timer_expire;
200         diff.tv_sec -= now.tv_sec;
201         diff.tv_usec -= now.tv_usec;
202         if (diff.tv_usec < 0) {
203                 diff.tv_sec--;
204                 diff.tv_usec += 1000000;
205         }
206
207         /* return the remaining time in milliseconds */
208         return (((u_long)(diff.tv_sec * 1000000 + diff.tv_usec)) / 1000);
209 }
210
211 void
212 mld6_start_listening(in6m)
213         struct in6_multi *in6m;
214 {
215         struct in6_addr all_in6;
216         int s = splnet();
217
218         /*
219          * RFC2710 page 10:
220          * The node never sends a Report or Done for the link-scope all-nodes
221          * address.
222          * MLD messages are never sent for multicast addresses whose scope is 0
223          * (reserved) or 1 (node-local).
224          */
225         all_in6 = in6addr_linklocal_allnodes;
226         if (in6_setscope(&all_in6, in6m->in6m_ifp, NULL)) {
227                 /* XXX: this should not happen! */
228                 in6m->in6m_timer = 0;
229                 in6m->in6m_state = MLD_OTHERLISTENER;
230         }
231         if (IN6_ARE_ADDR_EQUAL(&in6m->in6m_addr, &all_in6) ||
232             IPV6_ADDR_MC_SCOPE(&in6m->in6m_addr) <
233             IPV6_ADDR_SCOPE_LINKLOCAL) {
234                 in6m->in6m_timer = 0;
235                 in6m->in6m_state = MLD_OTHERLISTENER;
236         } else {
237                 mld6_sendpkt(in6m, MLD_LISTENER_REPORT, NULL);
238                 in6m->in6m_timer = arc4random() %
239                         MLD_UNSOLICITED_REPORT_INTERVAL * hz;
240                 in6m->in6m_state = MLD_IREPORTEDLAST;
241
242                 mld_starttimer(in6m);
243         }
244         splx(s);
245 }
246
247 void
248 mld6_stop_listening(in6m)
249         struct in6_multi *in6m;
250 {
251         struct in6_addr allnode, allrouter;
252
253         allnode = in6addr_linklocal_allnodes;
254         if (in6_setscope(&allnode, in6m->in6m_ifp, NULL)) {
255                 /* XXX: this should not happen! */
256                 return;
257         }
258         allrouter = in6addr_linklocal_allrouters;
259         if (in6_setscope(&allrouter, in6m->in6m_ifp, NULL)) {
260                 /* XXX impossible */
261                 return;
262         }
263         if (in6m->in6m_state == MLD_IREPORTEDLAST &&
264             !IN6_ARE_ADDR_EQUAL(&in6m->in6m_addr, &allnode) &&
265             IPV6_ADDR_MC_SCOPE(&in6m->in6m_addr) >
266             IPV6_ADDR_SCOPE_INTFACELOCAL) {
267                 mld6_sendpkt(in6m, MLD_LISTENER_DONE, &allrouter);
268         }
269 }
270
271 void
272 mld6_input(m, off)
273         struct mbuf *m;
274         int off;
275 {
276         struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
277         struct mld_hdr *mldh;
278         struct ifnet *ifp = m->m_pkthdr.rcvif;
279         struct in6_multi *in6m;
280         struct in6_addr mld_addr, all_in6;
281         struct in6_ifaddr *ia;
282         struct ifmultiaddr *ifma;
283         int timer;              /* timer value in the MLD query header */
284
285 #ifndef PULLDOWN_TEST
286         IP6_EXTHDR_CHECK(m, off, sizeof(*mldh),);
287         mldh = (struct mld_hdr *)(mtod(m, caddr_t) + off);
288 #else
289         IP6_EXTHDR_GET(mldh, struct mld_hdr *, m, off, sizeof(*mldh));
290         if (mldh == NULL) {
291                 icmp6stat.icp6s_tooshort++;
292                 return;
293         }
294 #endif
295
296         /* source address validation */
297         ip6 = mtod(m, struct ip6_hdr *); /* in case mpullup */
298         if (!IN6_IS_ADDR_LINKLOCAL(&ip6->ip6_src)) {
299                 char ip6bufs[INET6_ADDRSTRLEN], ip6bufg[INET6_ADDRSTRLEN];
300                 log(LOG_ERR,
301                     "mld6_input: src %s is not link-local (grp=%s)\n",
302                     ip6_sprintf(ip6bufs, &ip6->ip6_src),
303                     ip6_sprintf(ip6bufg, &mldh->mld_addr));
304                 /*
305                  * spec (RFC2710) does not explicitly
306                  * specify to discard the packet from a non link-local
307                  * source address. But we believe it's expected to do so.
308                  * XXX: do we have to allow :: as source?
309                  */
310                 m_freem(m);
311                 return;
312         }
313
314         /*
315          * make a copy for local work (in6_setscope() may modify the 1st arg)
316          */
317         mld_addr = mldh->mld_addr;
318         if (in6_setscope(&mld_addr, ifp, NULL)) {
319                 /* XXX: this should not happen! */
320                 m_free(m);
321                 return;
322         }
323
324         /*
325          * In the MLD6 specification, there are 3 states and a flag.
326          *
327          * In Non-Listener state, we simply don't have a membership record.
328          * In Delaying Listener state, our timer is running (in6m->in6m_timer)
329          * In Idle Listener state, our timer is not running 
330          * (in6m->in6m_timer==IN6M_TIMER_UNDEF)
331          *
332          * The flag is in6m->in6m_state, it is set to MLD_OTHERLISTENER if
333          * we have heard a report from another member, or MLD_IREPORTEDLAST
334          * if we sent the last report.
335          */
336         switch(mldh->mld_type) {
337         case MLD_LISTENER_QUERY:
338                 if (ifp->if_flags & IFF_LOOPBACK)
339                         break;
340
341                 if (!IN6_IS_ADDR_UNSPECIFIED(&mld_addr) &&
342                     !IN6_IS_ADDR_MULTICAST(&mld_addr))
343                         break;  /* print error or log stat? */
344
345                 all_in6 = in6addr_linklocal_allnodes;
346                 if (in6_setscope(&all_in6, ifp, NULL)) {
347                         /* XXX: this should not happen! */
348                         break;
349                 }
350
351                 /*
352                  * - Start the timers in all of our membership records
353                  *   that the query applies to for the interface on
354                  *   which the query arrived excl. those that belong
355                  *   to the "all-nodes" group (ff02::1).
356                  * - Restart any timer that is already running but has
357                  *   A value longer than the requested timeout.
358                  * - Use the value specified in the query message as
359                  *   the maximum timeout.
360                  */
361                 timer = ntohs(mldh->mld_maxdelay);
362
363                 IFP_TO_IA6(ifp, ia);
364                 if (ia == NULL)
365                         break;
366
367                 /*
368                  * XXX: System timer resolution is too low to handle Max
369                  * Response Delay, so set 1 to the internal timer even if
370                  * the calculated value equals to zero when Max Response
371                  * Delay is positive.
372                  */
373                 timer = ntohs(mldh->mld_maxdelay) * PR_FASTHZ / MLD_TIMER_SCALE;
374                 if (timer == 0 && mldh->mld_maxdelay)
375                         timer = 1;
376
377                 IF_ADDR_LOCK(ifp);
378                 TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
379                         if (ifma->ifma_addr->sa_family != AF_INET6)
380                                 continue;
381                         in6m = (struct in6_multi *)ifma->ifma_protospec;
382
383                         if (IN6_ARE_ADDR_EQUAL(&in6m->in6m_addr, &all_in6) ||
384                             IPV6_ADDR_MC_SCOPE(&in6m->in6m_addr) <
385                             IPV6_ADDR_SCOPE_LINKLOCAL)
386                                 continue;
387
388                         if (IN6_IS_ADDR_UNSPECIFIED(&mld_addr) ||
389                             IN6_ARE_ADDR_EQUAL(&mld_addr, &in6m->in6m_addr)) {
390                                 if (timer == 0) {
391                                         /* send a report immediately */
392                                         mld_stoptimer(in6m);
393                                         mld6_sendpkt(in6m, MLD_LISTENER_REPORT,
394                                                 NULL);
395                                         in6m->in6m_timer = 0; /* reset timer */
396                                         in6m->in6m_state = MLD_IREPORTEDLAST;
397                                 }
398                                 else if (in6m->in6m_timer == IN6M_TIMER_UNDEF ||
399                                     mld_timerresid(in6m) > (u_long)timer) {
400                                         in6m->in6m_timer = arc4random() %
401                                             (int)((long)(timer * hz) / 1000);
402                                         mld_starttimer(in6m);
403                                 }
404                         }
405                 }
406                 IF_ADDR_UNLOCK(ifp);
407                 break;
408
409         case MLD_LISTENER_REPORT:
410                 /*
411                  * For fast leave to work, we have to know that we are the
412                  * last person to send a report for this group.  Reports
413                  * can potentially get looped back if we are a multicast
414                  * router, so discard reports sourced by me.
415                  * Note that it is impossible to check IFF_LOOPBACK flag of
416                  * ifp for this purpose, since ip6_mloopback pass the physical
417                  * interface to looutput.
418                  */
419                 if (m->m_flags & M_LOOP) /* XXX: grotty flag, but efficient */
420                         break;
421
422                 if (!IN6_IS_ADDR_MULTICAST(&mld_addr))
423                         break;
424
425                 /*
426                  * If we belong to the group being reported, stop
427                  * our timer for that group.
428                  */
429                 IN6_LOOKUP_MULTI(mld_addr, ifp, in6m);
430                 if (in6m) {
431                         in6m->in6m_timer = 0; /* transit to idle state */
432                         in6m->in6m_state = MLD_OTHERLISTENER; /* clear flag */
433                 }
434                 break;
435         default:                /* this is impossible */
436                 log(LOG_ERR, "mld6_input: illegal type(%d)", mldh->mld_type);
437                 break;
438         }
439
440         m_freem(m);
441 }
442
443 static void
444 mld6_sendpkt(in6m, type, dst)
445         struct in6_multi *in6m;
446         int type;
447         const struct in6_addr *dst;
448 {
449         struct mbuf *mh, *md;
450         struct mld_hdr *mldh;
451         struct ip6_hdr *ip6;
452         struct ip6_moptions im6o;
453         struct in6_ifaddr *ia;
454         struct ifnet *ifp = in6m->in6m_ifp;
455         struct ifnet *outif = NULL;
456
457         /*
458          * At first, find a link local address on the outgoing interface
459          * to use as the source address of the MLD packet.
460          */
461         if ((ia = in6ifa_ifpforlinklocal(ifp, IN6_IFF_NOTREADY|IN6_IFF_ANYCAST))
462             == NULL)
463                 return;
464
465         /*
466          * Allocate mbufs to store ip6 header and MLD header.
467          * We allocate 2 mbufs and make chain in advance because
468          * it is more convenient when inserting the hop-by-hop option later.
469          */
470         MGETHDR(mh, M_DONTWAIT, MT_HEADER);
471         if (mh == NULL)
472                 return;
473         MGET(md, M_DONTWAIT, MT_DATA);
474         if (md == NULL) {
475                 m_free(mh);
476                 return;
477         }
478         mh->m_next = md;
479
480         mh->m_pkthdr.rcvif = NULL;
481         mh->m_pkthdr.len = sizeof(struct ip6_hdr) + sizeof(struct mld_hdr);
482         mh->m_len = sizeof(struct ip6_hdr);
483         MH_ALIGN(mh, sizeof(struct ip6_hdr));
484
485         /* fill in the ip6 header */
486         ip6 = mtod(mh, struct ip6_hdr *);
487         ip6->ip6_flow = 0;
488         ip6->ip6_vfc &= ~IPV6_VERSION_MASK;
489         ip6->ip6_vfc |= IPV6_VERSION;
490         /* ip6_plen will be set later */
491         ip6->ip6_nxt = IPPROTO_ICMPV6;
492         /* ip6_hlim will be set by im6o.im6o_multicast_hlim */
493         ip6->ip6_src = ia->ia_addr.sin6_addr;
494         ip6->ip6_dst = dst ? *dst : in6m->in6m_addr;
495
496         /* fill in the MLD header */
497         md->m_len = sizeof(struct mld_hdr);
498         mldh = mtod(md, struct mld_hdr *);
499         mldh->mld_type = type;
500         mldh->mld_code = 0;
501         mldh->mld_cksum = 0;
502         /* XXX: we assume the function will not be called for query messages */
503         mldh->mld_maxdelay = 0;
504         mldh->mld_reserved = 0;
505         mldh->mld_addr = in6m->in6m_addr;
506         in6_clearscope(&mldh->mld_addr); /* XXX */
507         mldh->mld_cksum = in6_cksum(mh, IPPROTO_ICMPV6, sizeof(struct ip6_hdr),
508                                     sizeof(struct mld_hdr));
509
510         /* construct multicast option */
511         bzero(&im6o, sizeof(im6o));
512         im6o.im6o_multicast_ifp = ifp;
513         im6o.im6o_multicast_hlim = 1;
514
515         /*
516          * Request loopback of the report if we are acting as a multicast
517          * router, so that the process-level routing daemon can hear it.
518          */
519         im6o.im6o_multicast_loop = (ip6_mrouter != NULL);
520
521         /* increment output statictics */
522         icmp6stat.icp6s_outhist[type]++;
523
524         ip6_output(mh, &ip6_opts, NULL, 0, &im6o, &outif, NULL);
525         if (outif) {
526                 icmp6_ifstat_inc(outif, ifs6_out_msg);
527                 switch (type) {
528                 case MLD_LISTENER_QUERY:
529                         icmp6_ifstat_inc(outif, ifs6_out_mldquery);
530                         break;
531                 case MLD_LISTENER_REPORT:
532                         icmp6_ifstat_inc(outif, ifs6_out_mldreport);
533                         break;
534                 case MLD_LISTENER_DONE:
535                         icmp6_ifstat_inc(outif, ifs6_out_mlddone);
536                         break;
537                 }
538         }
539 }
540
541 /*
542  * Add an address to the list of IP6 multicast addresses for a given interface.
543  * Add source addresses to the list also, if upstream router is MLDv2 capable
544  * and the number of source is not 0.
545  */
546 struct  in6_multi *
547 in6_addmulti(maddr6, ifp, errorp, delay)
548         struct in6_addr *maddr6;
549         struct ifnet *ifp;
550         int *errorp, delay;
551 {
552         struct in6_multi *in6m;
553
554         *errorp = 0;
555         in6m = NULL;
556
557         IFF_LOCKGIANT(ifp);
558         /*IN6_MULTI_LOCK();*/
559
560         IN6_LOOKUP_MULTI(*maddr6, ifp, in6m);
561         if (in6m != NULL) {
562                 /*
563                  * If we already joined this group, just bump the
564                  * refcount and return it.
565                  */
566                 KASSERT(in6m->in6m_refcount >= 1,
567                     ("%s: bad refcount %d", __func__, in6m->in6m_refcount));
568                 ++in6m->in6m_refcount;
569         } else do {
570                 struct in6_multi *nin6m;
571                 struct ifmultiaddr *ifma;
572                 struct sockaddr_in6 sa6;
573
574                 bzero(&sa6, sizeof(sa6));
575                 sa6.sin6_family = AF_INET6;
576                 sa6.sin6_len = sizeof(struct sockaddr_in6);
577                 sa6.sin6_addr = *maddr6;
578
579                 *errorp = if_addmulti(ifp, (struct sockaddr *)&sa6, &ifma);
580                 if (*errorp)
581                         break;
582
583                 /*
584                  * If ifma->ifma_protospec is null, then if_addmulti() created
585                  * a new record.  Otherwise, bump refcount, and we are done.
586                  */
587                 if (ifma->ifma_protospec != NULL) {
588                         in6m = ifma->ifma_protospec;
589                         ++in6m->in6m_refcount;
590                         break;
591                 }
592
593                 nin6m = malloc(sizeof(*nin6m), M_IP6MADDR, M_NOWAIT | M_ZERO);
594                 if (nin6m == NULL) {
595                         if_delmulti_ifma(ifma);
596                         break;
597                 }
598
599                 nin6m->in6m_addr = *maddr6;
600                 nin6m->in6m_ifp = ifp;
601                 nin6m->in6m_refcount = 1;
602                 nin6m->in6m_ifma = ifma;
603                 ifma->ifma_protospec = nin6m;
604
605                 nin6m->in6m_timer_ch = malloc(sizeof(*nin6m->in6m_timer_ch),
606                     M_IP6MADDR, M_NOWAIT);
607                 if (nin6m->in6m_timer_ch == NULL) {
608                         free(nin6m, M_IP6MADDR);
609                         if_delmulti_ifma(ifma);
610                         break;
611                 }
612
613                 LIST_INSERT_HEAD(&in6_multihead, nin6m, in6m_entry);
614
615                 callout_init(nin6m->in6m_timer_ch, 0);
616                 nin6m->in6m_timer = delay;
617                 if (nin6m->in6m_timer > 0) {
618                         nin6m->in6m_state = MLD_REPORTPENDING;
619                         mld_starttimer(nin6m);
620                 }
621
622                 mld6_start_listening(nin6m);
623
624                 in6m = nin6m;
625
626         } while (0);
627
628         /*IN6_MULTI_UNLOCK();*/
629         IFF_UNLOCKGIANT(ifp);
630
631         return (in6m);
632 }
633
634 /*
635  * Delete a multicast address record.
636  *
637  * TODO: Locking, as per netinet.
638  */
639 void
640 in6_delmulti(struct in6_multi *in6m)
641 {
642         struct ifmultiaddr *ifma;
643
644         KASSERT(in6m->in6m_refcount >= 1, ("%s: freeing freed in6m", __func__));
645
646         if (--in6m->in6m_refcount == 0) {
647                 mld_stoptimer(in6m);
648                 mld6_stop_listening(in6m);
649
650                 ifma = in6m->in6m_ifma;
651                 KASSERT(ifma->ifma_protospec == in6m,
652                     ("%s: ifma_protospec != in6m", __func__));
653                 ifma->ifma_protospec = NULL;
654
655                 LIST_REMOVE(in6m, in6m_entry);
656                 free(in6m->in6m_timer_ch, M_IP6MADDR);
657                 free(in6m, M_IP6MADDR);
658
659                 if_delmulti_ifma(ifma);
660         }
661 }