1 /* $NetBSD: mld6.c,v 1.32 2006/03/06 20:33:52 rpaulo Exp $ */ 2 /* $KAME: mld6.c,v 1.25 2001/01/16 14:14:18 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) 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. 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. 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 */ 103 104 #include <sys/cdefs.h> 105 __KERNEL_RCSID(0, "$NetBSD: mld6.c,v 1.32 2006/03/06 20:33:52 rpaulo Exp $"); 106 107 #include "opt_inet.h" 108 109 #include <sys/param.h> 110 #include <sys/systm.h> 111 #include <sys/mbuf.h> 112 #include <sys/socket.h> 113 #include <sys/protosw.h> 114 #include <sys/syslog.h> 115 #include <sys/sysctl.h> 116 #include <sys/kernel.h> 117 #include <sys/callout.h> 118 119 #include <net/if.h> 120 121 #include <netinet/in.h> 122 #include <netinet/in_var.h> 123 #include <netinet6/in6_var.h> 124 #include <netinet/ip6.h> 125 #include <netinet6/ip6_var.h> 126 #include <netinet6/scope6_var.h> 127 #include <netinet/icmp6.h> 128 #include <netinet6/mld6_var.h> 129 130 #include <net/net_osdep.h> 131 132 133 /* 134 * This structure is used to keep track of in6_multi chains which belong to 135 * deleted interface addresses. 136 */ 137 static LIST_HEAD(, multi6_kludge) in6_mk; /* XXX BSS initialization */ 138 139 struct multi6_kludge { 140 LIST_ENTRY(multi6_kludge) mk_entry; 141 struct ifnet *mk_ifp; 142 struct in6_multihead mk_head; 143 }; 144 145 146 /* 147 * Protocol constants 148 */ 149 150 /* 151 * time between repetitions of a node's initial report of interest in a 152 * multicast address(in seconds) 153 */ 154 #define MLD_UNSOLICITED_REPORT_INTERVAL 10 155 156 static struct ip6_pktopts ip6_opts; 157 158 static void mld_start_listening(struct in6_multi *); 159 static void mld_stop_listening(struct in6_multi *); 160 161 static struct mld_hdr * mld_allocbuf(struct mbuf **, int, struct in6_multi *, 162 int); 163 static void mld_sendpkt(struct in6_multi *, int, const struct in6_addr *); 164 static void mld_starttimer(struct in6_multi *); 165 static void mld_stoptimer(struct in6_multi *); 166 static void mld_timeo(struct in6_multi *); 167 static u_long mld_timerresid(struct in6_multi *); 168 169 void 170 mld_init() 171 { 172 static u_int8_t hbh_buf[8]; 173 struct ip6_hbh *hbh = (struct ip6_hbh *)hbh_buf; 174 u_int16_t rtalert_code = htons((u_int16_t)IP6OPT_RTALERT_MLD); 175 176 /* ip6h_nxt will be fill in later */ 177 hbh->ip6h_len = 0; /* (8 >> 3) - 1 */ 178 179 /* XXX: grotty hard coding... */ 180 hbh_buf[2] = IP6OPT_PADN; /* 2 byte padding */ 181 hbh_buf[3] = 0; 182 hbh_buf[4] = IP6OPT_RTALERT; 183 hbh_buf[5] = IP6OPT_RTALERT_LEN - 2; 184 bcopy((caddr_t)&rtalert_code, &hbh_buf[6], sizeof(u_int16_t)); 185 186 ip6_opts.ip6po_hbh = hbh; 187 /* We will specify the hoplimit by a multicast option. */ 188 ip6_opts.ip6po_hlim = -1; 189 } 190 191 static void 192 mld_starttimer(in6m) 193 struct in6_multi *in6m; 194 { 195 struct timeval now; 196 197 microtime(&now); 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; 204 } 205 206 /* start or restart the timer */ 207 callout_reset(in6m->in6m_timer_ch, in6m->in6m_timer, 208 (void (*) __P((void *)))mld_timeo, in6m); 209 } 210 211 static void 212 mld_stoptimer(in6m) 213 struct in6_multi *in6m; 214 { 215 if (in6m->in6m_timer == IN6M_TIMER_UNDEF) 216 return; 217 218 callout_stop(in6m->in6m_timer_ch); 219 220 in6m->in6m_timer = IN6M_TIMER_UNDEF; 221 } 222 223 static void 224 mld_timeo(in6m) 225 struct in6_multi *in6m; 226 { 227 int s = splsoftnet(); 228 229 in6m->in6m_timer = IN6M_TIMER_UNDEF; 230 231 callout_stop(in6m->in6m_timer_ch); 232 233 switch (in6m->in6m_state) { 234 case MLD_REPORTPENDING: 235 mld_start_listening(in6m); 236 break; 237 default: 238 mld_sendpkt(in6m, MLD_LISTENER_REPORT, NULL); 239 break; 240 } 241 242 splx(s); 243 } 244 245 static u_long 246 mld_timerresid(in6m) 247 struct in6_multi *in6m; 248 { 249 struct timeval now, diff; 250 251 microtime(&now); 252 253 if (now.tv_sec > in6m->in6m_timer_expire.tv_sec || 254 (now.tv_sec == in6m->in6m_timer_expire.tv_sec && 255 now.tv_usec > in6m->in6m_timer_expire.tv_usec)) { 256 return (0); 257 } 258 diff = in6m->in6m_timer_expire; 259 diff.tv_sec -= now.tv_sec; 260 diff.tv_usec -= now.tv_usec; 261 if (diff.tv_usec < 0) { 262 diff.tv_sec--; 263 diff.tv_usec += 1000000; 264 } 265 266 /* return the remaining time in milliseconds */ 267 return (((u_long)(diff.tv_sec * 1000000 + diff.tv_usec)) / 1000); 268 } 269 270 static void 271 mld_start_listening(in6m) 272 struct in6_multi *in6m; 273 { 274 struct in6_addr all_in6; 275 276 /* 277 * RFC2710 page 10: 278 * The node never sends a Report or Done for the link-scope all-nodes 279 * address. 280 * MLD messages are never sent for multicast addresses whose scope is 0 281 * (reserved) or 1 (node-local). 282 */ 283 all_in6 = in6addr_linklocal_allnodes; 284 if (in6_setscope(&all_in6, in6m->in6m_ifp, NULL)) { 285 /* XXX: this should not happen! */ 286 in6m->in6m_timer = 0; 287 in6m->in6m_state = MLD_OTHERLISTENER; 288 } 289 if (IN6_ARE_ADDR_EQUAL(&in6m->in6m_addr, &all_in6) || 290 IPV6_ADDR_MC_SCOPE(&in6m->in6m_addr) < IPV6_ADDR_SCOPE_LINKLOCAL) { 291 in6m->in6m_timer = IN6M_TIMER_UNDEF; 292 in6m->in6m_state = MLD_OTHERLISTENER; 293 } else { 294 mld_sendpkt(in6m, MLD_LISTENER_REPORT, NULL); 295 in6m->in6m_timer = arc4random() % 296 (MLD_UNSOLICITED_REPORT_INTERVAL * hz); 297 in6m->in6m_state = MLD_IREPORTEDLAST; 298 299 mld_starttimer(in6m); 300 } 301 } 302 303 static void 304 mld_stop_listening(in6m) 305 struct in6_multi *in6m; 306 { 307 struct in6_addr allnode, allrouter; 308 309 allnode = in6addr_linklocal_allnodes; 310 if (in6_setscope(&allnode, in6m->in6m_ifp, NULL)) { 311 /* XXX: this should not happen! */ 312 return; 313 } 314 allrouter = in6addr_linklocal_allrouters; 315 if (in6_setscope(&allrouter, in6m->in6m_ifp, NULL)) { 316 /* XXX impossible */ 317 return; 318 } 319 320 if (in6m->in6m_state == MLD_IREPORTEDLAST && 321 (!IN6_ARE_ADDR_EQUAL(&in6m->in6m_addr, &allnode)) && 322 IPV6_ADDR_MC_SCOPE(&in6m->in6m_addr) > 323 IPV6_ADDR_SCOPE_INTFACELOCAL) { 324 mld_sendpkt(in6m, MLD_LISTENER_DONE, &allrouter); 325 } 326 } 327 328 void 329 mld_input(m, off) 330 struct mbuf *m; 331 int off; 332 { 333 struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); 334 struct mld_hdr *mldh; 335 struct ifnet *ifp = m->m_pkthdr.rcvif; 336 struct in6_multi *in6m = NULL; 337 struct in6_addr mld_addr, all_in6; 338 struct in6_ifaddr *ia; 339 int timer = 0; /* timer value in the MLD query header */ 340 341 IP6_EXTHDR_GET(mldh, struct mld_hdr *, m, off, sizeof(*mldh)); 342 if (mldh == NULL) { 343 icmp6stat.icp6s_tooshort++; 344 return; 345 } 346 347 /* source address validation */ 348 ip6 = mtod(m, struct ip6_hdr *);/* in case mpullup */ 349 if (!IN6_IS_ADDR_LINKLOCAL(&ip6->ip6_src)) { 350 /* 351 * RFC3590 allows the IPv6 unspecified address as the source 352 * address of MLD report and done messages. However, as this 353 * same document says, this special rule is for snooping 354 * switches and the RFC requires routers to discard MLD packets 355 * with the unspecified source address. The RFC only talks 356 * about hosts receiving an MLD query or report in Security 357 * Considerations, but this is probably the correct intention. 358 * RFC3590 does not talk about other cases than link-local and 359 * the unspecified source addresses, but we believe the same 360 * rule should be applied. 361 * As a result, we only allow link-local addresses as the 362 * source address; otherwise, simply discard the packet. 363 */ 364 #if 0 365 /* 366 * XXX: do not log in an input path to avoid log flooding, 367 * though RFC3590 says "SHOULD log" if the source of a query 368 * is the unspecified address. 369 */ 370 log(LOG_INFO, 371 "mld_input: src %s is not link-local (grp=%s)\n", 372 ip6_sprintf(&ip6->ip6_src), ip6_sprintf(&mldh->mld_addr)); 373 #endif 374 m_freem(m); 375 return; 376 } 377 378 /* 379 * make a copy for local work (in6_setscope() may modify the 1st arg) 380 */ 381 mld_addr = mldh->mld_addr; 382 if (in6_setscope(&mld_addr, ifp, NULL)) { 383 /* XXX: this should not happen! */ 384 m_free(m); 385 return; 386 } 387 388 /* 389 * In the MLD specification, there are 3 states and a flag. 390 * 391 * In Non-Listener state, we simply don't have a membership record. 392 * In Delaying Listener state, our timer is running (in6m->in6m_timer) 393 * In Idle Listener state, our timer is not running 394 * (in6m->in6m_timer==IN6M_TIMER_UNDEF) 395 * 396 * The flag is in6m->in6m_state, it is set to MLD_OTHERLISTENER if 397 * we have heard a report from another member, or MLD_IREPORTEDLAST 398 * if we sent the last report. 399 */ 400 switch (mldh->mld_type) { 401 case MLD_LISTENER_QUERY: 402 if (ifp->if_flags & IFF_LOOPBACK) 403 break; 404 405 if (!IN6_IS_ADDR_UNSPECIFIED(&mld_addr) && 406 !IN6_IS_ADDR_MULTICAST(&mld_addr)) 407 break; /* print error or log stat? */ 408 409 all_in6 = in6addr_linklocal_allnodes; 410 if (in6_setscope(&all_in6, ifp, NULL)) { 411 /* XXX: this should not happen! */ 412 break; 413 } 414 415 /* 416 * - Start the timers in all of our membership records 417 * that the query applies to for the interface on 418 * which the query arrived excl. those that belong 419 * to the "all-nodes" group (ff02::1). 420 * - Restart any timer that is already running but has 421 * a value longer than the requested timeout. 422 * - Use the value specified in the query message as 423 * the maximum timeout. 424 */ 425 timer = ntohs(mldh->mld_maxdelay); 426 427 IFP_TO_IA6(ifp, ia); 428 if (ia == NULL) 429 break; 430 431 for (in6m = ia->ia6_multiaddrs.lh_first; 432 in6m; 433 in6m = in6m->in6m_entry.le_next) 434 { 435 if (IN6_ARE_ADDR_EQUAL(&in6m->in6m_addr, &all_in6) || 436 IPV6_ADDR_MC_SCOPE(&in6m->in6m_addr) < 437 IPV6_ADDR_SCOPE_LINKLOCAL) 438 continue; 439 440 if (in6m->in6m_state == MLD_REPORTPENDING) 441 continue; /* we are not yet ready */ 442 443 if (!IN6_IS_ADDR_UNSPECIFIED(&mld_addr) && 444 !IN6_ARE_ADDR_EQUAL(&mld_addr, &in6m->in6m_addr)) 445 continue; 446 447 if (timer == 0) { 448 /* send a report immediately */ 449 mld_stoptimer(in6m); 450 mld_sendpkt(in6m, MLD_LISTENER_REPORT, NULL); 451 in6m->in6m_state = MLD_IREPORTEDLAST; 452 } else if (in6m->in6m_timer == IN6M_TIMER_UNDEF || 453 mld_timerresid(in6m) > (u_long)timer) { 454 in6m->in6m_timer = arc4random() % 455 (int)(((long)timer * hz) / 1000); 456 mld_starttimer(in6m); 457 } 458 } 459 break; 460 461 case MLD_LISTENER_REPORT: 462 /* 463 * For fast leave to work, we have to know that we are the 464 * last person to send a report for this group. Reports 465 * can potentially get looped back if we are a multicast 466 * router, so discard reports sourced by me. 467 * Note that it is impossible to check IFF_LOOPBACK flag of 468 * ifp for this purpose, since ip6_mloopback pass the physical 469 * interface to looutput. 470 */ 471 if (m->m_flags & M_LOOP) /* XXX: grotty flag, but efficient */ 472 break; 473 474 if (!IN6_IS_ADDR_MULTICAST(&mldh->mld_addr)) 475 break; 476 477 /* 478 * If we belong to the group being reported, stop 479 * our timer for that group. 480 */ 481 IN6_LOOKUP_MULTI(mld_addr, ifp, in6m); 482 if (in6m) { 483 mld_stoptimer(in6m); /* transit to idle state */ 484 in6m->in6m_state = MLD_OTHERLISTENER; /* clear flag */ 485 } 486 break; 487 default: /* this is impossible */ 488 #if 0 489 /* 490 * this case should be impossible because of filtering in 491 * icmp6_input(). But we explicitly disabled this part 492 * just in case. 493 */ 494 log(LOG_ERR, "mld_input: illegal type(%d)", mldh->mld_type); 495 #endif 496 break; 497 } 498 499 m_freem(m); 500 } 501 502 static void 503 mld_sendpkt(in6m, type, dst) 504 struct in6_multi *in6m; 505 int type; 506 const struct in6_addr *dst; 507 { 508 struct mbuf *mh; 509 struct mld_hdr *mldh; 510 struct ip6_hdr *ip6 = NULL; 511 struct ip6_moptions im6o; 512 struct in6_ifaddr *ia = NULL; 513 struct ifnet *ifp = in6m->in6m_ifp; 514 int ignflags; 515 516 /* 517 * At first, find a link local address on the outgoing interface 518 * to use as the source address of the MLD packet. 519 * We do not reject tentative addresses for MLD report to deal with 520 * the case where we first join a link-local address. 521 */ 522 ignflags = (IN6_IFF_NOTREADY|IN6_IFF_ANYCAST) & ~IN6_IFF_TENTATIVE; 523 if ((ia = in6ifa_ifpforlinklocal(ifp, ignflags)) == NULL) 524 return; 525 if ((ia->ia6_flags & IN6_IFF_TENTATIVE)) 526 ia = NULL; 527 528 /* Allocate two mbufs to store IPv6 header and MLD header */ 529 mldh = mld_allocbuf(&mh, sizeof(struct mld_hdr), in6m, type); 530 if (mldh == NULL) 531 return; 532 533 /* fill src/dst here */ 534 ip6 = mtod(mh, struct ip6_hdr *); 535 ip6->ip6_src = ia ? ia->ia_addr.sin6_addr : in6addr_any; 536 ip6->ip6_dst = dst ? *dst : in6m->in6m_addr; 537 538 mldh->mld_addr = in6m->in6m_addr; 539 in6_clearscope(&mldh->mld_addr); /* XXX */ 540 mldh->mld_cksum = in6_cksum(mh, IPPROTO_ICMPV6, sizeof(struct ip6_hdr), 541 sizeof(struct mld_hdr)); 542 543 /* construct multicast option */ 544 memset(&im6o, 0, sizeof(im6o)); 545 im6o.im6o_multicast_ifp = ifp; 546 im6o.im6o_multicast_hlim = 1; 547 548 /* 549 * Request loopback of the report if we are acting as a multicast 550 * router, so that the process-level routing daemon can hear it. 551 */ 552 im6o.im6o_multicast_loop = (ip6_mrouter != NULL); 553 554 /* increment output statictics */ 555 icmp6stat.icp6s_outhist[type]++; 556 icmp6_ifstat_inc(ifp, ifs6_out_msg); 557 switch (type) { 558 case MLD_LISTENER_QUERY: 559 icmp6_ifstat_inc(ifp, ifs6_out_mldquery); 560 break; 561 case MLD_LISTENER_REPORT: 562 icmp6_ifstat_inc(ifp, ifs6_out_mldreport); 563 break; 564 case MLD_LISTENER_DONE: 565 icmp6_ifstat_inc(ifp, ifs6_out_mlddone); 566 break; 567 } 568 569 ip6_output(mh, &ip6_opts, NULL, ia ? 0 : IPV6_UNSPECSRC, 570 &im6o, (struct socket *)NULL, NULL); 571 } 572 573 static struct mld_hdr * 574 mld_allocbuf(mh, len, in6m, type) 575 struct mbuf **mh; 576 int len; 577 struct in6_multi *in6m; 578 int type; 579 { 580 struct mbuf *md; 581 struct mld_hdr *mldh; 582 struct ip6_hdr *ip6; 583 584 /* 585 * Allocate mbufs to store ip6 header and MLD header. 586 * We allocate 2 mbufs and make chain in advance because 587 * it is more convenient when inserting the hop-by-hop option later. 588 */ 589 MGETHDR(*mh, M_DONTWAIT, MT_HEADER); 590 if (*mh == NULL) 591 return NULL; 592 MGET(md, M_DONTWAIT, MT_DATA); 593 if (md == NULL) { 594 m_free(*mh); 595 *mh = NULL; 596 return NULL; 597 } 598 (*mh)->m_next = md; 599 md->m_next = NULL; 600 601 (*mh)->m_pkthdr.rcvif = NULL; 602 (*mh)->m_pkthdr.len = sizeof(struct ip6_hdr) + len; 603 (*mh)->m_len = sizeof(struct ip6_hdr); 604 MH_ALIGN(*mh, sizeof(struct ip6_hdr)); 605 606 /* fill in the ip6 header */ 607 ip6 = mtod(*mh, struct ip6_hdr *); 608 memset(ip6, 0, sizeof(*ip6)); 609 ip6->ip6_flow = 0; 610 ip6->ip6_vfc &= ~IPV6_VERSION_MASK; 611 ip6->ip6_vfc |= IPV6_VERSION; 612 /* ip6_plen will be set later */ 613 ip6->ip6_nxt = IPPROTO_ICMPV6; 614 /* ip6_hlim will be set by im6o.im6o_multicast_hlim */ 615 /* ip6_src/dst will be set by mld_sendpkt() or mld_sendbuf() */ 616 617 /* fill in the MLD header as much as possible */ 618 md->m_len = len; 619 mldh = mtod(md, struct mld_hdr *); 620 memset(mldh, 0, len); 621 mldh->mld_type = type; 622 return mldh; 623 } 624 625 /* 626 * Add an address to the list of IP6 multicast addresses for a given interface. 627 */ 628 struct in6_multi * 629 in6_addmulti(maddr6, ifp, errorp, timer) 630 struct in6_addr *maddr6; 631 struct ifnet *ifp; 632 int *errorp, timer; 633 { 634 struct in6_ifaddr *ia; 635 struct in6_ifreq ifr; 636 struct in6_multi *in6m; 637 int s = splsoftnet(); 638 639 *errorp = 0; 640 641 /* 642 * See if address already in list. 643 */ 644 IN6_LOOKUP_MULTI(*maddr6, ifp, in6m); 645 if (in6m != NULL) { 646 /* 647 * Found it; just increment the refrence count. 648 */ 649 in6m->in6m_refcount++; 650 } else { 651 /* 652 * New address; allocate a new multicast record 653 * and link it into the interface's multicast list. 654 */ 655 in6m = (struct in6_multi *) 656 malloc(sizeof(*in6m), M_IPMADDR, M_NOWAIT); 657 if (in6m == NULL) { 658 splx(s); 659 *errorp = ENOBUFS; 660 return (NULL); 661 } 662 663 memset(in6m, 0, sizeof(*in6m)); 664 in6m->in6m_addr = *maddr6; 665 in6m->in6m_ifp = ifp; 666 in6m->in6m_refcount = 1; 667 in6m->in6m_timer = IN6M_TIMER_UNDEF; 668 in6m->in6m_timer_ch = 669 malloc(sizeof(*in6m->in6m_timer_ch), M_IPMADDR, M_NOWAIT); 670 if (in6m->in6m_timer_ch == NULL) { 671 free(in6m, M_IPMADDR); 672 splx(s); 673 return (NULL); 674 } 675 IFP_TO_IA6(ifp, ia); 676 if (ia == NULL) { 677 free(in6m, M_IPMADDR); 678 splx(s); 679 *errorp = EADDRNOTAVAIL; /* appropriate? */ 680 return (NULL); 681 } 682 in6m->in6m_ia = ia; 683 IFAREF(&ia->ia_ifa); /* gain a reference */ 684 LIST_INSERT_HEAD(&ia->ia6_multiaddrs, in6m, in6m_entry); 685 686 /* 687 * Ask the network driver to update its multicast reception 688 * filter appropriately for the new address. 689 */ 690 memset(&ifr.ifr_addr, 0, sizeof(struct sockaddr_in6)); 691 ifr.ifr_addr.sin6_family = AF_INET6; 692 ifr.ifr_addr.sin6_len = sizeof(struct sockaddr_in6); 693 ifr.ifr_addr.sin6_addr = *maddr6; 694 if (ifp->if_ioctl == NULL) 695 *errorp = ENXIO; /* XXX: appropriate? */ 696 else 697 *errorp = (*ifp->if_ioctl)(ifp, SIOCADDMULTI, 698 (caddr_t)&ifr); 699 if (*errorp) { 700 LIST_REMOVE(in6m, in6m_entry); 701 free(in6m, M_IPMADDR); 702 IFAFREE(&ia->ia_ifa); 703 splx(s); 704 return (NULL); 705 } 706 707 callout_init(in6m->in6m_timer_ch); 708 in6m->in6m_timer = timer; 709 if (in6m->in6m_timer > 0) { 710 in6m->in6m_state = MLD_REPORTPENDING; 711 mld_starttimer(in6m); 712 713 splx(s); 714 return (in6m); 715 } 716 717 /* 718 * Let MLD6 know that we have joined a new IP6 multicast 719 * group. 720 */ 721 mld_start_listening(in6m); 722 } 723 splx(s); 724 return (in6m); 725 } 726 727 /* 728 * Delete a multicast address record. 729 */ 730 void 731 in6_delmulti(in6m) 732 struct in6_multi *in6m; 733 { 734 struct in6_ifreq ifr; 735 struct in6_ifaddr *ia; 736 int s = splsoftnet(); 737 738 mld_stoptimer(in6m); 739 740 if (--in6m->in6m_refcount == 0) { 741 /* 742 * No remaining claims to this record; let MLD6 know 743 * that we are leaving the multicast group. 744 */ 745 mld_stop_listening(in6m); 746 747 /* 748 * Unlink from list. 749 */ 750 LIST_REMOVE(in6m, in6m_entry); 751 if (in6m->in6m_ia) { 752 IFAFREE(&in6m->in6m_ia->ia_ifa); /* release reference */ 753 } 754 755 /* 756 * Delete all references of this multicasting group from 757 * the membership arrays 758 */ 759 for (ia = in6_ifaddr; ia; ia = ia->ia_next) { 760 struct in6_multi_mship *imm; 761 LIST_FOREACH(imm, &ia->ia6_memberships, 762 i6mm_chain) { 763 if (imm->i6mm_maddr == in6m) 764 imm->i6mm_maddr = NULL; 765 } 766 } 767 768 /* 769 * Notify the network driver to update its multicast 770 * reception filter. 771 */ 772 memset(&ifr.ifr_addr, 0, sizeof(struct sockaddr_in6)); 773 ifr.ifr_addr.sin6_family = AF_INET6; 774 ifr.ifr_addr.sin6_len = sizeof(struct sockaddr_in6); 775 ifr.ifr_addr.sin6_addr = in6m->in6m_addr; 776 (*in6m->in6m_ifp->if_ioctl)(in6m->in6m_ifp, 777 SIOCDELMULTI, (caddr_t)&ifr); 778 free(in6m->in6m_timer_ch, M_IPMADDR); 779 free(in6m, M_IPMADDR); 780 } 781 splx(s); 782 } 783 784 785 struct in6_multi_mship * 786 in6_joingroup(ifp, addr, errorp, timer) 787 struct ifnet *ifp; 788 struct in6_addr *addr; 789 int *errorp, timer; 790 { 791 struct in6_multi_mship *imm; 792 793 imm = malloc(sizeof(*imm), M_IPMADDR, M_NOWAIT); 794 if (!imm) { 795 *errorp = ENOBUFS; 796 return NULL; 797 } 798 799 memset(imm, 0, sizeof(*imm)); 800 imm->i6mm_maddr = in6_addmulti(addr, ifp, errorp, timer); 801 if (!imm->i6mm_maddr) { 802 /* *errorp is alrady set */ 803 free(imm, M_IPMADDR); 804 return NULL; 805 } 806 return imm; 807 } 808 809 int 810 in6_leavegroup(imm) 811 struct in6_multi_mship *imm; 812 { 813 814 if (imm->i6mm_maddr) { 815 in6_delmulti(imm->i6mm_maddr); 816 } 817 free(imm, M_IPMADDR); 818 return 0; 819 } 820 821 822 /* 823 * Multicast address kludge: 824 * If there were any multicast addresses attached to this interface address, 825 * either move them to another address on this interface, or save them until 826 * such time as this interface is reconfigured for IPv6. 827 */ 828 void 829 in6_savemkludge(oia) 830 struct in6_ifaddr *oia; 831 { 832 struct in6_ifaddr *ia; 833 struct in6_multi *in6m, *next; 834 835 IFP_TO_IA6(oia->ia_ifp, ia); 836 if (ia) { /* there is another address */ 837 for (in6m = oia->ia6_multiaddrs.lh_first; in6m; in6m = next) { 838 next = in6m->in6m_entry.le_next; 839 IFAFREE(&in6m->in6m_ia->ia_ifa); 840 IFAREF(&ia->ia_ifa); 841 in6m->in6m_ia = ia; 842 LIST_INSERT_HEAD(&ia->ia6_multiaddrs, in6m, in6m_entry); 843 } 844 } else { /* last address on this if deleted, save */ 845 struct multi6_kludge *mk; 846 847 for (mk = in6_mk.lh_first; mk; mk = mk->mk_entry.le_next) { 848 if (mk->mk_ifp == oia->ia_ifp) 849 break; 850 } 851 if (mk == NULL) /* this should not happen! */ 852 panic("in6_savemkludge: no kludge space"); 853 854 for (in6m = oia->ia6_multiaddrs.lh_first; in6m; in6m = next) { 855 next = in6m->in6m_entry.le_next; 856 IFAFREE(&in6m->in6m_ia->ia_ifa); /* release reference */ 857 in6m->in6m_ia = NULL; 858 LIST_INSERT_HEAD(&mk->mk_head, in6m, in6m_entry); 859 } 860 } 861 } 862 863 /* 864 * Continuation of multicast address hack: 865 * If there was a multicast group list previously saved for this interface, 866 * then we re-attach it to the first address configured on the i/f. 867 */ 868 void 869 in6_restoremkludge(ia, ifp) 870 struct in6_ifaddr *ia; 871 struct ifnet *ifp; 872 { 873 struct multi6_kludge *mk; 874 875 for (mk = in6_mk.lh_first; mk; mk = mk->mk_entry.le_next) { 876 if (mk->mk_ifp == ifp) { 877 struct in6_multi *in6m, *next; 878 879 for (in6m = mk->mk_head.lh_first; in6m; in6m = next) { 880 next = in6m->in6m_entry.le_next; 881 in6m->in6m_ia = ia; 882 IFAREF(&ia->ia_ifa); 883 LIST_INSERT_HEAD(&ia->ia6_multiaddrs, 884 in6m, in6m_entry); 885 } 886 LIST_INIT(&mk->mk_head); 887 break; 888 } 889 } 890 } 891 892 /* 893 * Allocate space for the kludge at interface initialization time. 894 * Formerly, we dynamically allocated the space in in6_savemkludge() with 895 * malloc(M_WAITOK). However, it was wrong since the function could be called 896 * under an interrupt context (software timer on address lifetime expiration). 897 * Also, we cannot just give up allocating the strucutre, since the group 898 * membership structure is very complex and we need to keep it anyway. 899 * Of course, this function MUST NOT be called under an interrupt context. 900 * Specifically, it is expected to be called only from in6_ifattach(), though 901 * it is a global function. 902 */ 903 void 904 in6_createmkludge(ifp) 905 struct ifnet *ifp; 906 { 907 struct multi6_kludge *mk; 908 909 for (mk = in6_mk.lh_first; mk; mk = mk->mk_entry.le_next) { 910 /* If we've already had one, do not allocate. */ 911 if (mk->mk_ifp == ifp) 912 return; 913 } 914 915 mk = malloc(sizeof(*mk), M_IPMADDR, M_WAITOK); 916 917 memset(mk, 0, sizeof(*mk)); 918 LIST_INIT(&mk->mk_head); 919 mk->mk_ifp = ifp; 920 LIST_INSERT_HEAD(&in6_mk, mk, mk_entry); 921 } 922 923 void 924 in6_purgemkludge(ifp) 925 struct ifnet *ifp; 926 { 927 struct multi6_kludge *mk; 928 struct in6_multi *in6m; 929 930 for (mk = in6_mk.lh_first; mk; mk = mk->mk_entry.le_next) { 931 if (mk->mk_ifp != ifp) 932 continue; 933 934 /* leave from all multicast groups joined */ 935 while ((in6m = LIST_FIRST(&mk->mk_head)) != NULL) { 936 in6_delmulti(in6m); 937 } 938 LIST_REMOVE(mk, mk_entry); 939 free(mk, M_IPMADDR); 940 break; 941 } 942 } 943