1 /* $OpenBSD: ip6_mroute.c,v 1.143 2024/07/04 12:50:08 bluhm Exp $ */ 2 /* $NetBSD: ip6_mroute.c,v 1.59 2003/12/10 09:28:38 itojun Exp $ */ 3 /* $KAME: ip6_mroute.c,v 1.45 2001/03/25 08:38:51 itojun Exp $ */ 4 5 /* 6 * Copyright (C) 1998 WIDE Project. 7 * All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. Neither the name of the project nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34 /* BSDI ip_mroute.c,v 2.10 1996/11/14 00:29:52 jch Exp */ 35 36 /* 37 * Copyright (c) 1989 Stephen Deering 38 * Copyright (c) 1992, 1993 39 * The Regents of the University of California. All rights reserved. 40 * 41 * This code is derived from software contributed to Berkeley by 42 * Stephen Deering of Stanford University. 43 * 44 * Redistribution and use in source and binary forms, with or without 45 * modification, are permitted provided that the following conditions 46 * are met: 47 * 1. Redistributions of source code must retain the above copyright 48 * notice, this list of conditions and the following disclaimer. 49 * 2. Redistributions in binary form must reproduce the above copyright 50 * notice, this list of conditions and the following disclaimer in the 51 * documentation and/or other materials provided with the distribution. 52 * 3. Neither the name of the University nor the names of its contributors 53 * may be used to endorse or promote products derived from this software 54 * without specific prior written permission. 55 * 56 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 57 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 58 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 59 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 60 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 61 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 62 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 63 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 64 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 65 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 66 * SUCH DAMAGE. 67 * 68 * @(#)ip_mroute.c 8.2 (Berkeley) 11/15/93 69 */ 70 71 /* 72 * IP multicast forwarding procedures 73 * 74 * Written by David Waitzman, BBN Labs, August 1988. 75 * Modified by Steve Deering, Stanford, February 1989. 76 * Modified by Mark J. Steiglitz, Stanford, May, 1991 77 * Modified by Van Jacobson, LBL, January 1993 78 * Modified by Ajit Thyagarajan, PARC, August 1993 79 * Modified by Bill Fenner, PARC, April 1994 80 * 81 * MROUTING Revision: 3.5.1.2 82 */ 83 84 #include <sys/param.h> 85 #include <sys/malloc.h> 86 #include <sys/systm.h> 87 #include <sys/timeout.h> 88 #include <sys/mbuf.h> 89 #include <sys/socket.h> 90 #include <sys/socketvar.h> 91 #include <sys/protosw.h> 92 #include <sys/kernel.h> 93 #include <sys/ioctl.h> 94 #include <sys/syslog.h> 95 #include <sys/sysctl.h> 96 97 #include <net/if.h> 98 #include <net/if_var.h> 99 #include <net/route.h> 100 101 #include <netinet/in.h> 102 #include <netinet6/in6_var.h> 103 #include <netinet/ip.h> 104 #include <netinet/ip6.h> 105 #include <netinet/icmp6.h> 106 #include <netinet6/ip6_var.h> 107 #include <netinet6/ip6_mroute.h> 108 #include <netinet/in_pcb.h> 109 110 /* #define MCAST_DEBUG */ 111 112 #ifdef MCAST_DEBUG 113 int mcast6_debug = 1; 114 #define DPRINTF(fmt, args...) \ 115 do { \ 116 if (mcast6_debug) \ 117 printf("%s:%d " fmt "\n", \ 118 __func__, __LINE__, ## args); \ 119 } while (0) 120 #else 121 #define DPRINTF(fmt, args...) \ 122 do { } while (0) 123 #endif 124 125 int ip6_mdq(struct mbuf *, struct ifnet *, struct rtentry *, int); 126 void phyint_send6(struct ifnet *, struct ip6_hdr *, struct mbuf *, int); 127 128 /* 129 * Globals. All but ip6_mrouter, ip6_mrtproto and mrt6stat could be static, 130 * except for netstat or debugging purposes. 131 */ 132 struct socket *ip6_mrouter[RT_TABLEID_MAX + 1]; 133 struct rttimer_queue ip6_mrouterq; 134 int ip6_mrouter_ver = 0; 135 int ip6_mrtproto; /* for netstat only */ 136 struct mrt6stat mrt6stat; 137 138 int get_sg6_cnt(struct sioc_sg_req6 *, unsigned int); 139 int get_mif6_cnt(struct sioc_mif_req6 *, unsigned int); 140 int ip6_mrouter_init(struct socket *, int, int); 141 int add_m6if(struct socket *, struct mif6ctl *); 142 int del_m6if(struct socket *, mifi_t *); 143 int add_m6fc(struct socket *, struct mf6cctl *); 144 int del_m6fc(struct socket *, struct mf6cctl *); 145 struct ifnet *mrt6_iflookupbymif(mifi_t, unsigned int); 146 struct rtentry *mf6c_find(struct ifnet *, struct in6_addr *, 147 struct in6_addr *, unsigned int); 148 struct rtentry *mrt6_mcast_add(struct ifnet *, struct sockaddr *, 149 struct sockaddr *); 150 void mrt6_mcast_del(struct rtentry *, unsigned int); 151 152 /* 153 * Handle MRT setsockopt commands to modify the multicast routing tables. 154 */ 155 int 156 ip6_mrouter_set(int cmd, struct socket *so, struct mbuf *m) 157 { 158 struct inpcb *inp = sotoinpcb(so); 159 160 if (cmd != MRT6_INIT && so != ip6_mrouter[inp->inp_rtableid]) 161 return (EPERM); 162 163 switch (cmd) { 164 case MRT6_INIT: 165 if (m == NULL || m->m_len < sizeof(int)) 166 return (EINVAL); 167 return (ip6_mrouter_init(so, *mtod(m, int *), cmd)); 168 case MRT6_DONE: 169 return (ip6_mrouter_done(so)); 170 case MRT6_ADD_MIF: 171 if (m == NULL || m->m_len < sizeof(struct mif6ctl)) 172 return (EINVAL); 173 return (add_m6if(so, mtod(m, struct mif6ctl *))); 174 case MRT6_DEL_MIF: 175 if (m == NULL || m->m_len < sizeof(mifi_t)) 176 return (EINVAL); 177 return (del_m6if(so, mtod(m, mifi_t *))); 178 case MRT6_ADD_MFC: 179 if (m == NULL || m->m_len < sizeof(struct mf6cctl)) 180 return (EINVAL); 181 return (add_m6fc(so, mtod(m, struct mf6cctl *))); 182 case MRT6_DEL_MFC: 183 if (m == NULL || m->m_len < sizeof(struct mf6cctl)) 184 return (EINVAL); 185 return (del_m6fc(so, mtod(m, struct mf6cctl *))); 186 default: 187 return (EOPNOTSUPP); 188 } 189 } 190 191 /* 192 * Handle MRT getsockopt commands 193 */ 194 int 195 ip6_mrouter_get(int cmd, struct socket *so, struct mbuf *m) 196 { 197 struct inpcb *inp = sotoinpcb(so); 198 199 if (so != ip6_mrouter[inp->inp_rtableid]) 200 return (EPERM); 201 202 switch (cmd) { 203 default: 204 return EOPNOTSUPP; 205 } 206 } 207 208 /* 209 * Handle ioctl commands to obtain information from the cache 210 */ 211 int 212 mrt6_ioctl(struct socket *so, u_long cmd, caddr_t data) 213 { 214 struct inpcb *inp = sotoinpcb(so); 215 int error; 216 217 if (inp == NULL) 218 return (ENOTCONN); 219 220 KERNEL_LOCK(); 221 222 switch (cmd) { 223 case SIOCGETSGCNT_IN6: 224 NET_LOCK_SHARED(); 225 error = get_sg6_cnt((struct sioc_sg_req6 *)data, 226 inp->inp_rtableid); 227 NET_UNLOCK_SHARED(); 228 break; 229 case SIOCGETMIFCNT_IN6: 230 NET_LOCK_SHARED(); 231 error = get_mif6_cnt((struct sioc_mif_req6 *)data, 232 inp->inp_rtableid); 233 NET_UNLOCK_SHARED(); 234 break; 235 default: 236 error = ENOTTY; 237 break; 238 } 239 240 KERNEL_UNLOCK(); 241 return error; 242 } 243 244 /* 245 * returns the packet, byte, rpf-failure count for the source group provided 246 */ 247 int 248 get_sg6_cnt(struct sioc_sg_req6 *req, unsigned int rtableid) 249 { 250 struct rtentry *rt; 251 struct mf6c *mf6c; 252 253 rt = mf6c_find(NULL, &req->src.sin6_addr, &req->grp.sin6_addr, 254 rtableid); 255 if (rt == NULL) { 256 req->pktcnt = req->bytecnt = req->wrong_if = 0xffffffff; 257 return EADDRNOTAVAIL; 258 } 259 260 req->pktcnt = req->bytecnt = req->wrong_if = 0; 261 do { 262 mf6c = (struct mf6c *)rt->rt_llinfo; 263 if (mf6c == NULL) 264 continue; 265 266 req->pktcnt += mf6c->mf6c_pkt_cnt; 267 req->bytecnt += mf6c->mf6c_byte_cnt; 268 req->wrong_if += mf6c->mf6c_wrong_if; 269 } while ((rt = rtable_iterate(rt)) != NULL); 270 271 return 0; 272 } 273 274 /* 275 * returns the input and output packet and byte counts on the mif provided 276 */ 277 int 278 get_mif6_cnt(struct sioc_mif_req6 *req, unsigned int rtableid) 279 { 280 struct ifnet *ifp; 281 struct mif6 *m6; 282 283 if ((ifp = mrt6_iflookupbymif(req->mifi, rtableid)) == NULL) 284 return EINVAL; 285 286 m6 = (struct mif6 *)ifp->if_mcast6; 287 req->icount = m6->m6_pkt_in; 288 req->ocount = m6->m6_pkt_out; 289 req->ibytes = m6->m6_bytes_in; 290 req->obytes = m6->m6_bytes_out; 291 292 return 0; 293 } 294 295 int 296 mrt6_sysctl_mif(void *oldp, size_t *oldlenp) 297 { 298 struct ifnet *ifp; 299 caddr_t where = oldp; 300 size_t needed, given; 301 struct mif6 *mifp; 302 struct mif6info minfo; 303 304 given = *oldlenp; 305 needed = 0; 306 memset(&minfo, 0, sizeof minfo); 307 TAILQ_FOREACH(ifp, &ifnetlist, if_list) { 308 if ((mifp = (struct mif6 *)ifp->if_mcast6) == NULL) 309 continue; 310 311 minfo.m6_mifi = mifp->m6_mifi; 312 minfo.m6_flags = mifp->m6_flags; 313 minfo.m6_lcl_addr = mifp->m6_lcl_addr; 314 minfo.m6_ifindex = ifp->if_index; 315 minfo.m6_pkt_in = mifp->m6_pkt_in; 316 minfo.m6_pkt_out = mifp->m6_pkt_out; 317 minfo.m6_bytes_in = mifp->m6_bytes_in; 318 minfo.m6_bytes_out = mifp->m6_bytes_out; 319 minfo.m6_rate_limit = mifp->m6_rate_limit; 320 321 needed += sizeof(minfo); 322 if (where && needed <= given) { 323 int error; 324 325 error = copyout(&minfo, where, sizeof(minfo)); 326 if (error) 327 return (error); 328 where += sizeof(minfo); 329 } 330 } 331 if (where) { 332 *oldlenp = needed; 333 if (given < needed) 334 return (ENOMEM); 335 } else 336 *oldlenp = (11 * needed) / 10; 337 338 return (0); 339 } 340 341 struct mf6csysctlarg { 342 struct mf6cinfo *ms6a_minfos; 343 size_t ms6a_len; 344 size_t ms6a_needed; 345 }; 346 347 int 348 mrt6_rtwalk_mf6csysctl(struct rtentry *rt, void *arg, unsigned int rtableid) 349 { 350 struct mf6c *mf6c = (struct mf6c *)rt->rt_llinfo; 351 struct mf6csysctlarg *msa = arg; 352 struct ifnet *ifp; 353 struct mif6 *m6; 354 struct mf6cinfo *minfo; 355 int new = 0; 356 357 /* Skip entries being removed. */ 358 if (mf6c == NULL) 359 return 0; 360 361 /* Skip non-multicast routes. */ 362 if (ISSET(rt->rt_flags, RTF_HOST | RTF_MULTICAST) != 363 (RTF_HOST | RTF_MULTICAST)) 364 return 0; 365 366 /* User just asked for the output size. */ 367 if (msa->ms6a_minfos == NULL) { 368 msa->ms6a_needed += sizeof(*minfo); 369 return 0; 370 } 371 372 /* Skip route with invalid interfaces. */ 373 if ((ifp = if_get(rt->rt_ifidx)) == NULL) 374 return 0; 375 if ((m6 = (struct mif6 *)ifp->if_mcast6) == NULL) { 376 if_put(ifp); 377 return 0; 378 } 379 380 for (minfo = msa->ms6a_minfos; 381 (uint8_t *)(minfo + 1) <= 382 (uint8_t *)msa->ms6a_minfos + msa->ms6a_len; 383 minfo++) { 384 /* Find a new entry or update old entry. */ 385 if (!IN6_ARE_ADDR_EQUAL(&minfo->mf6c_origin.sin6_addr, 386 &satosin6(rt->rt_gateway)->sin6_addr) || 387 !IN6_ARE_ADDR_EQUAL(&minfo->mf6c_mcastgrp.sin6_addr, 388 &satosin6(rt_key(rt))->sin6_addr)) { 389 if (!IN6_IS_ADDR_UNSPECIFIED( 390 &minfo->mf6c_origin.sin6_addr) || 391 !IN6_IS_ADDR_UNSPECIFIED( 392 &minfo->mf6c_mcastgrp.sin6_addr)) 393 continue; 394 395 new = 1; 396 } 397 398 minfo->mf6c_origin = *satosin6(rt->rt_gateway); 399 minfo->mf6c_mcastgrp = *satosin6(rt_key(rt)); 400 minfo->mf6c_parent = mf6c->mf6c_parent; 401 minfo->mf6c_pkt_cnt += mf6c->mf6c_pkt_cnt; 402 minfo->mf6c_byte_cnt += mf6c->mf6c_byte_cnt; 403 IF_SET(m6->m6_mifi, &minfo->mf6c_ifset); 404 break; 405 } 406 407 if (new != 0) 408 msa->ms6a_needed += sizeof(*minfo); 409 410 if_put(ifp); 411 412 return 0; 413 } 414 415 int 416 mrt6_sysctl_mfc(void *oldp, size_t *oldlenp) 417 { 418 unsigned int rtableid; 419 int error; 420 struct mf6csysctlarg msa; 421 422 if (oldp != NULL && *oldlenp > MAXPHYS) 423 return EINVAL; 424 425 memset(&msa, 0, sizeof(msa)); 426 if (oldp != NULL && *oldlenp > 0) { 427 msa.ms6a_minfos = malloc(*oldlenp, M_TEMP, M_WAITOK | M_ZERO); 428 msa.ms6a_len = *oldlenp; 429 } 430 431 for (rtableid = 0; rtableid <= RT_TABLEID_MAX; rtableid++) { 432 rtable_walk(rtableid, AF_INET6, NULL, mrt6_rtwalk_mf6csysctl, 433 &msa); 434 } 435 436 if (msa.ms6a_minfos != NULL && msa.ms6a_needed > 0 && 437 (error = copyout(msa.ms6a_minfos, oldp, msa.ms6a_needed)) != 0) { 438 free(msa.ms6a_minfos, M_TEMP, msa.ms6a_len); 439 return error; 440 } 441 442 free(msa.ms6a_minfos, M_TEMP, msa.ms6a_len); 443 *oldlenp = msa.ms6a_needed; 444 445 return 0; 446 } 447 448 /* 449 * Enable multicast routing 450 */ 451 int 452 ip6_mrouter_init(struct socket *so, int v, int cmd) 453 { 454 struct inpcb *inp = sotoinpcb(so); 455 unsigned int rtableid = inp->inp_rtableid; 456 457 if (so->so_type != SOCK_RAW || 458 so->so_proto->pr_protocol != IPPROTO_ICMPV6) 459 return (EOPNOTSUPP); 460 461 if (v != 1) 462 return (ENOPROTOOPT); 463 464 if (ip6_mrouter[rtableid] != NULL) 465 return (EADDRINUSE); 466 467 ip6_mrouter[rtableid] = so; 468 ip6_mrouter_ver = cmd; 469 470 return (0); 471 } 472 473 int 474 mrouter6_rtwalk_delete(struct rtentry *rt, void *arg, unsigned int rtableid) 475 { 476 /* Skip non-multicast routes. */ 477 if (ISSET(rt->rt_flags, RTF_HOST | RTF_MULTICAST) != 478 (RTF_HOST | RTF_MULTICAST)) 479 return 0; 480 481 return EEXIST; 482 } 483 484 /* 485 * Disable multicast routing 486 */ 487 int 488 ip6_mrouter_done(struct socket *so) 489 { 490 struct inpcb *inp = sotoinpcb(so); 491 struct ifnet *ifp; 492 unsigned int rtableid = inp->inp_rtableid; 493 int error; 494 495 NET_ASSERT_LOCKED(); 496 497 /* Delete all remaining installed multicast routes. */ 498 do { 499 struct rtentry *rt = NULL; 500 501 error = rtable_walk(rtableid, AF_INET6, &rt, 502 mrouter6_rtwalk_delete, NULL); 503 if (rt != NULL && error == EEXIST) { 504 mrt6_mcast_del(rt, rtableid); 505 error = EAGAIN; 506 } 507 rtfree(rt); 508 } while (error == EAGAIN); 509 510 /* Unregister all interfaces in the domain. */ 511 TAILQ_FOREACH(ifp, &ifnetlist, if_list) { 512 if (ifp->if_rdomain != rtableid) 513 continue; 514 515 ip6_mrouter_detach(ifp); 516 } 517 518 ip6_mrouter[inp->inp_rtableid] = NULL; 519 ip6_mrouter_ver = 0; 520 521 return 0; 522 } 523 524 void 525 ip6_mrouter_detach(struct ifnet *ifp) 526 { 527 struct mif6 *m6 = (struct mif6 *)ifp->if_mcast6; 528 struct in6_ifreq ifr; 529 530 if (m6 == NULL) 531 return; 532 533 ifp->if_mcast6 = NULL; 534 535 memset(&ifr, 0, sizeof(ifr)); 536 ifr.ifr_addr.sin6_family = AF_INET6; 537 ifr.ifr_addr.sin6_addr = in6addr_any; 538 KERNEL_LOCK(); 539 (*ifp->if_ioctl)(ifp, SIOCDELMULTI, (caddr_t)&ifr); 540 KERNEL_UNLOCK(); 541 542 free(m6, M_MRTABLE, sizeof(*m6)); 543 } 544 545 /* 546 * Add a mif to the mif table 547 */ 548 int 549 add_m6if(struct socket *so, struct mif6ctl *mifcp) 550 { 551 struct inpcb *inp = sotoinpcb(so); 552 struct mif6 *mifp; 553 struct ifnet *ifp; 554 struct in6_ifreq ifr; 555 int error; 556 unsigned int rtableid = inp->inp_rtableid; 557 558 NET_ASSERT_LOCKED(); 559 560 if (mifcp->mif6c_mifi >= MAXMIFS) 561 return EINVAL; 562 563 if (mrt6_iflookupbymif(mifcp->mif6c_mifi, rtableid) != NULL) 564 return EADDRINUSE; /* XXX: is it appropriate? */ 565 566 { 567 ifp = if_get(mifcp->mif6c_pifi); 568 if (ifp == NULL) 569 return ENXIO; 570 571 /* Make sure the interface supports multicast */ 572 if ((ifp->if_flags & IFF_MULTICAST) == 0) { 573 if_put(ifp); 574 return EOPNOTSUPP; 575 } 576 577 /* 578 * Enable promiscuous reception of all IPv6 multicasts 579 * from the interface. 580 */ 581 memset(&ifr, 0, sizeof(ifr)); 582 ifr.ifr_addr.sin6_family = AF_INET6; 583 ifr.ifr_addr.sin6_addr = in6addr_any; 584 KERNEL_LOCK(); 585 error = (*ifp->if_ioctl)(ifp, SIOCADDMULTI, (caddr_t)&ifr); 586 KERNEL_UNLOCK(); 587 588 if (error) { 589 if_put(ifp); 590 return error; 591 } 592 } 593 594 mifp = malloc(sizeof(*mifp), M_MRTABLE, M_WAITOK | M_ZERO); 595 ifp->if_mcast6 = (caddr_t)mifp; 596 mifp->m6_mifi = mifcp->mif6c_mifi; 597 mifp->m6_flags = mifcp->mif6c_flags; 598 #ifdef notyet 599 /* scaling up here allows division by 1024 in critical code */ 600 mifp->m6_rate_limit = mifcp->mif6c_rate_limit * 1024 / 1000; 601 #endif 602 603 if_put(ifp); 604 605 return 0; 606 } 607 608 /* 609 * Delete a mif from the mif table 610 */ 611 int 612 del_m6if(struct socket *so, mifi_t *mifip) 613 { 614 struct inpcb *inp = sotoinpcb(so); 615 struct ifnet *ifp; 616 617 NET_ASSERT_LOCKED(); 618 619 if (*mifip >= MAXMIFS) 620 return EINVAL; 621 if ((ifp = mrt6_iflookupbymif(*mifip, inp->inp_rtableid)) == NULL) 622 return EINVAL; 623 624 ip6_mrouter_detach(ifp); 625 626 return 0; 627 } 628 629 int 630 mf6c_add_route(struct ifnet *ifp, struct sockaddr *origin, 631 struct sockaddr *group, struct mf6cctl *mf6cc, int wait) 632 { 633 struct rtentry *rt; 634 struct mf6c *mf6c; 635 unsigned int rtableid = ifp->if_rdomain; 636 #ifdef MCAST_DEBUG 637 char bsrc[INET6_ADDRSTRLEN], bdst[INET6_ADDRSTRLEN]; 638 #endif /* MCAST_DEBUG */ 639 640 rt = mrt6_mcast_add(ifp, origin, group); 641 if (rt == NULL) 642 return ENOENT; 643 644 mf6c = malloc(sizeof(*mf6c), M_MRTABLE, wait | M_ZERO); 645 if (mf6c == NULL) { 646 DPRINTF("origin %s group %s parent %d (%s) malloc failed", 647 inet_ntop(AF_INET6, origin, bsrc, sizeof(bsrc)), 648 inet_ntop(AF_INET6, group, bdst, sizeof(bdst)), 649 mf6cc->mf6cc_parent, ifp->if_xname); 650 mrt6_mcast_del(rt, rtableid); 651 rtfree(rt); 652 return ENOMEM; 653 } 654 655 rt->rt_llinfo = (caddr_t)mf6c; 656 rt_timer_add(rt, &ip6_mrouterq, rtableid); 657 mf6c->mf6c_parent = mf6cc->mf6cc_parent; 658 rtfree(rt); 659 660 return 0; 661 } 662 663 void 664 mf6c_update(struct mf6cctl *mf6cc, int wait, unsigned int rtableid) 665 { 666 struct rtentry *rt; 667 struct mf6c *mf6c; 668 struct ifnet *ifp; 669 struct sockaddr_in6 osin6, gsin6; 670 mifi_t mifi; 671 #ifdef MCAST_DEBUG 672 char bdst[INET6_ADDRSTRLEN]; 673 #endif /* MCAST_DEBUG */ 674 675 memset(&osin6, 0, sizeof(osin6)); 676 osin6.sin6_family = AF_INET6; 677 osin6.sin6_len = sizeof(osin6); 678 osin6.sin6_addr = mf6cc->mf6cc_origin.sin6_addr; 679 680 memset(&gsin6, 0, sizeof(gsin6)); 681 gsin6.sin6_family = AF_INET6; 682 gsin6.sin6_len = sizeof(gsin6); 683 gsin6.sin6_addr = mf6cc->mf6cc_mcastgrp.sin6_addr; 684 685 for (mifi = 0; mifi < MAXMIFS; mifi++) { 686 if (mifi == mf6cc->mf6cc_parent) 687 continue; 688 689 /* Test for mif existence and then update the entry. */ 690 if ((ifp = mrt6_iflookupbymif(mifi, rtableid)) == NULL) 691 continue; 692 693 rt = mf6c_find(ifp, &mf6cc->mf6cc_origin.sin6_addr, 694 &mf6cc->mf6cc_mcastgrp.sin6_addr, rtableid); 695 696 /* mif not configured or removed. */ 697 if (!IF_ISSET(mifi, &mf6cc->mf6cc_ifset)) { 698 /* Route doesn't exist, nothing to do. */ 699 if (rt == NULL) 700 continue; 701 702 DPRINTF("del route (group %s) for mif %d (%s)", 703 inet_ntop(AF_INET6, 704 &mf6cc->mf6cc_mcastgrp.sin6_addr, bdst, 705 sizeof(bdst)), mifi, ifp->if_xname); 706 mrt6_mcast_del(rt, rtableid); 707 rtfree(rt); 708 continue; 709 } 710 711 /* Route exists, look for changes. */ 712 if (rt != NULL) { 713 mf6c = (struct mf6c *)rt->rt_llinfo; 714 /* Skip route being deleted. */ 715 if (mf6c == NULL) { 716 rtfree(rt); 717 continue; 718 } 719 720 /* No new changes to apply. */ 721 if (mf6cc->mf6cc_parent == mf6c->mf6c_parent) { 722 rtfree(rt); 723 continue; 724 } 725 726 DPRINTF("update route (group %s) for mif %d (%s)", 727 inet_ntop(AF_INET6, 728 &mf6cc->mf6cc_mcastgrp.sin6_addr, bdst, 729 sizeof(bdst)), mifi, ifp->if_xname); 730 731 mf6c->mf6c_parent = mf6cc->mf6cc_parent; 732 rtfree(rt); 733 continue; 734 } 735 736 DPRINTF("add route (group %s) for mif %d (%s)", 737 inet_ntop(AF_INET6, &mf6cc->mf6cc_mcastgrp.sin6_addr, 738 bdst, sizeof(bdst)), mifi, ifp->if_xname); 739 740 mf6c_add_route(ifp, sin6tosa(&osin6), sin6tosa(&gsin6), 741 mf6cc, wait); 742 } 743 744 /* Create route for the parent interface. */ 745 if ((ifp = mrt6_iflookupbymif(mf6cc->mf6cc_parent, 746 rtableid)) == NULL) { 747 DPRINTF("failed to find upstream interface %d", 748 mf6cc->mf6cc_parent); 749 return; 750 } 751 752 /* We already have a route, nothing to do here. */ 753 if ((rt = mf6c_find(ifp, &mf6cc->mf6cc_origin.sin6_addr, 754 &mf6cc->mf6cc_mcastgrp.sin6_addr, rtableid)) != NULL) { 755 rtfree(rt); 756 return; 757 } 758 759 DPRINTF("add upstream route (group %s) for if %s", 760 inet_ntop(AF_INET6, &mf6cc->mf6cc_mcastgrp.sin6_addr, 761 bdst, sizeof(bdst)), ifp->if_xname); 762 mf6c_add_route(ifp, sin6tosa(&osin6), sin6tosa(&gsin6), mf6cc, wait); 763 } 764 765 int 766 mf6c_add(struct mf6cctl *mfccp, struct in6_addr *origin, 767 struct in6_addr *group, int vidx, unsigned int rtableid, int wait) 768 { 769 struct ifnet *ifp; 770 struct mif6 *m6; 771 struct mf6cctl mf6cc; 772 773 ifp = mrt6_iflookupbymif(vidx, rtableid); 774 if (ifp == NULL || 775 (m6 = (struct mif6 *)ifp->if_mcast6) == NULL) 776 return ENOENT; 777 778 memset(&mf6cc, 0, sizeof(mf6cc)); 779 if (mfccp == NULL) { 780 mf6cc.mf6cc_origin.sin6_family = AF_INET6; 781 mf6cc.mf6cc_origin.sin6_len = sizeof(mf6cc.mf6cc_origin); 782 mf6cc.mf6cc_origin.sin6_addr = *origin; 783 mf6cc.mf6cc_mcastgrp.sin6_family = AF_INET6; 784 mf6cc.mf6cc_mcastgrp.sin6_len = sizeof(mf6cc.mf6cc_mcastgrp); 785 mf6cc.mf6cc_mcastgrp.sin6_addr = *group; 786 mf6cc.mf6cc_parent = vidx; 787 } else 788 memcpy(&mf6cc, mfccp, sizeof(mf6cc)); 789 790 mf6c_update(&mf6cc, wait, rtableid); 791 792 return 0; 793 } 794 795 int 796 add_m6fc(struct socket *so, struct mf6cctl *mfccp) 797 { 798 struct inpcb *inp = sotoinpcb(so); 799 unsigned int rtableid = inp->inp_rtableid; 800 801 NET_ASSERT_LOCKED(); 802 803 return mf6c_add(mfccp, &mfccp->mf6cc_origin.sin6_addr, 804 &mfccp->mf6cc_mcastgrp.sin6_addr, mfccp->mf6cc_parent, 805 rtableid, M_WAITOK); 806 } 807 808 int 809 del_m6fc(struct socket *so, struct mf6cctl *mfccp) 810 { 811 struct inpcb *inp = sotoinpcb(so); 812 struct rtentry *rt; 813 unsigned int rtableid = inp->inp_rtableid; 814 815 NET_ASSERT_LOCKED(); 816 817 while ((rt = mf6c_find(NULL, &mfccp->mf6cc_origin.sin6_addr, 818 &mfccp->mf6cc_mcastgrp.sin6_addr, rtableid)) != NULL) { 819 mrt6_mcast_del(rt, rtableid); 820 rtfree(rt); 821 } 822 823 return 0; 824 } 825 826 int 827 socket6_send(struct socket *so, struct mbuf *mm, struct sockaddr_in6 *src) 828 { 829 if (so != NULL) { 830 int ret; 831 832 mtx_enter(&so->so_rcv.sb_mtx); 833 ret = sbappendaddr(so, &so->so_rcv, sin6tosa(src), mm, NULL); 834 mtx_leave(&so->so_rcv.sb_mtx); 835 836 if (ret != 0) { 837 sorwakeup(so); 838 return 0; 839 } 840 } 841 m_freem(mm); 842 return -1; 843 } 844 845 /* 846 * IPv6 multicast forwarding function. This function assumes that the packet 847 * pointed to by "ip6" has arrived on (or is about to be sent to) the interface 848 * pointed to by "ifp", and the packet is to be relayed to other networks 849 * that have members of the packet's destination IPv6 multicast group. 850 * 851 * The packet is returned unscathed to the caller, unless it is 852 * erroneous, in which case a non-zero return value tells the caller to 853 * discard it. 854 */ 855 int 856 ip6_mforward(struct ip6_hdr *ip6, struct ifnet *ifp, struct mbuf *m, int flags) 857 { 858 struct rtentry *rt; 859 struct mif6 *mifp; 860 struct mbuf *mm; 861 struct sockaddr_in6 sin6; 862 unsigned int rtableid = ifp->if_rdomain; 863 864 NET_ASSERT_LOCKED(); 865 866 /* 867 * Don't forward a packet with Hop limit of zero or one, 868 * or a packet destined to a local-only group. 869 */ 870 if (ip6->ip6_hlim <= 1 || IN6_IS_ADDR_MC_INTFACELOCAL(&ip6->ip6_dst) || 871 IN6_IS_ADDR_MC_LINKLOCAL(&ip6->ip6_dst)) 872 return 0; 873 ip6->ip6_hlim--; 874 875 /* 876 * Source address check: do not forward packets with unspecified 877 * source. It was discussed in July 2000, on ipngwg mailing list. 878 * This is rather more serious than unicast cases, because some 879 * MLD packets can be sent with the unspecified source address 880 * (although such packets must normally set 1 to the hop limit field). 881 */ 882 if (IN6_IS_ADDR_UNSPECIFIED(&ip6->ip6_src)) { 883 ip6stat_inc(ip6s_cantforward); 884 if (ip6_log_time + ip6_log_interval < getuptime()) { 885 char src[INET6_ADDRSTRLEN], dst[INET6_ADDRSTRLEN]; 886 887 ip6_log_time = getuptime(); 888 889 inet_ntop(AF_INET6, &ip6->ip6_src, src, sizeof(src)); 890 inet_ntop(AF_INET6, &ip6->ip6_dst, dst, sizeof(dst)); 891 log(LOG_DEBUG, "cannot forward " 892 "from %s to %s nxt %d received on interface %u\n", 893 src, dst, ip6->ip6_nxt, m->m_pkthdr.ph_ifidx); 894 } 895 return 0; 896 } 897 898 /* 899 * Determine forwarding mifs from the forwarding cache table 900 */ 901 rt = mf6c_find(NULL, &ip6->ip6_src, &ip6->ip6_dst, rtableid); 902 903 /* Entry exists, so forward if necessary */ 904 if (rt) { 905 return (ip6_mdq(m, ifp, rt, flags)); 906 } else { 907 /* 908 * If we don't have a route for packet's origin, 909 * Make a copy of the packet & 910 * send message to routing daemon 911 */ 912 913 mrt6stat.mrt6s_no_route++; 914 915 { 916 struct mrt6msg *im; 917 918 if ((mifp = (struct mif6 *)ifp->if_mcast6) == NULL) 919 return EHOSTUNREACH; 920 921 /* 922 * Make a copy of the header to send to the user 923 * level process 924 */ 925 mm = m_copym(m, 0, sizeof(struct ip6_hdr), M_NOWAIT); 926 if (mm == NULL) 927 return ENOBUFS; 928 929 /* 930 * Send message to routing daemon 931 */ 932 (void)memset(&sin6, 0, sizeof(sin6)); 933 sin6.sin6_len = sizeof(sin6); 934 sin6.sin6_family = AF_INET6; 935 sin6.sin6_addr = ip6->ip6_src; 936 937 im = NULL; 938 switch (ip6_mrouter_ver) { 939 case MRT6_INIT: 940 im = mtod(mm, struct mrt6msg *); 941 im->im6_msgtype = MRT6MSG_NOCACHE; 942 im->im6_mbz = 0; 943 im->im6_mif = mifp->m6_mifi; 944 break; 945 default: 946 m_freem(mm); 947 return EINVAL; 948 } 949 950 if (socket6_send(ip6_mrouter[rtableid], mm, 951 &sin6) < 0) { 952 log(LOG_WARNING, "ip6_mforward: ip6_mrouter " 953 "socket queue full\n"); 954 mrt6stat.mrt6s_upq_sockfull++; 955 return ENOBUFS; 956 } 957 958 mrt6stat.mrt6s_upcalls++; 959 960 mf6c_add(NULL, &ip6->ip6_src, &ip6->ip6_dst, 961 mifp->m6_mifi, rtableid, M_NOWAIT); 962 } 963 964 return 0; 965 } 966 } 967 968 void 969 mf6c_expire_route(struct rtentry *rt, u_int rtableid) 970 { 971 struct mf6c *mf6c = (struct mf6c *)rt->rt_llinfo; 972 #ifdef MCAST_DEBUG 973 char bsrc[INET6_ADDRSTRLEN], bdst[INET6_ADDRSTRLEN]; 974 #endif /* MCAST_DEBUG */ 975 976 /* Skip entry being deleted. */ 977 if (mf6c == NULL) 978 return; 979 980 DPRINTF("origin %s group %s interface %d expire %s", 981 inet_ntop(AF_INET6, &satosin6(rt->rt_gateway)->sin6_addr, 982 bsrc, sizeof(bsrc)), 983 inet_ntop(AF_INET6, &satosin6(rt_key(rt))->sin6_addr, 984 bdst, sizeof(bdst)), rt->rt_ifidx, 985 mf6c->mf6c_expire ? "yes" : "no"); 986 987 if (mf6c->mf6c_expire == 0) { 988 mf6c->mf6c_expire = 1; 989 rt_timer_add(rt, &ip6_mrouterq, rtableid); 990 return; 991 } 992 993 mrt6_mcast_del(rt, rtableid); 994 } 995 996 /* 997 * Packet forwarding routine once entry in the cache is made 998 */ 999 int 1000 ip6_mdq(struct mbuf *m, struct ifnet *ifp, struct rtentry *rt, int flags) 1001 { 1002 struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); 1003 struct mif6 *m6, *mifp = (struct mif6 *)ifp->if_mcast6; 1004 struct mf6c *mf6c = (struct mf6c *)rt->rt_llinfo; 1005 struct ifnet *ifn; 1006 int plen = m->m_pkthdr.len; 1007 1008 if (mifp == NULL || mf6c == NULL) { 1009 rtfree(rt); 1010 return EHOSTUNREACH; 1011 } 1012 1013 /* 1014 * Don't forward if it didn't arrive from the parent mif 1015 * for its origin. 1016 */ 1017 if (mifp->m6_mifi != mf6c->mf6c_parent) { 1018 /* came in the wrong interface */ 1019 mrt6stat.mrt6s_wrong_if++; 1020 mf6c->mf6c_wrong_if++; 1021 rtfree(rt); 1022 return 0; 1023 } /* if wrong iif */ 1024 1025 /* If I sourced this packet, it counts as output, else it was input. */ 1026 if (m->m_pkthdr.ph_ifidx == 0) { 1027 /* XXX: is ph_ifidx really 0 when output?? */ 1028 mifp->m6_pkt_out++; 1029 mifp->m6_bytes_out += plen; 1030 } else { 1031 mifp->m6_pkt_in++; 1032 mifp->m6_bytes_in += plen; 1033 } 1034 1035 /* 1036 * For each mif, forward a copy of the packet if there are group 1037 * members downstream on the interface. 1038 */ 1039 do { 1040 /* Don't consider non multicast routes. */ 1041 if (ISSET(rt->rt_flags, RTF_HOST | RTF_MULTICAST) != 1042 (RTF_HOST | RTF_MULTICAST)) 1043 continue; 1044 1045 mf6c = (struct mf6c *)rt->rt_llinfo; 1046 if (mf6c == NULL) 1047 continue; 1048 1049 mf6c->mf6c_pkt_cnt++; 1050 mf6c->mf6c_byte_cnt += m->m_pkthdr.len; 1051 1052 /* Don't let this route expire. */ 1053 mf6c->mf6c_expire = 0; 1054 1055 if ((ifn = if_get(rt->rt_ifidx)) == NULL) 1056 continue; 1057 1058 /* Sanity check: did we configure this? */ 1059 if ((m6 = (struct mif6 *)ifn->if_mcast6) == NULL) { 1060 if_put(ifn); 1061 continue; 1062 } 1063 1064 /* Don't send in the upstream interface. */ 1065 if (mf6c->mf6c_parent == m6->m6_mifi) { 1066 if_put(ifn); 1067 continue; 1068 } 1069 1070 /* 1071 * check if the outgoing packet is going to break 1072 * a scope boundary. 1073 */ 1074 if ((mifp->m6_flags & MIFF_REGISTER) == 0 && 1075 (m6->m6_flags & MIFF_REGISTER) == 0 && 1076 (in6_addr2scopeid(ifp->if_index, &ip6->ip6_dst) != 1077 in6_addr2scopeid(ifn->if_index, &ip6->ip6_dst) || 1078 in6_addr2scopeid(ifp->if_index, &ip6->ip6_src) != 1079 in6_addr2scopeid(ifn->if_index, &ip6->ip6_src))) { 1080 if_put(ifn); 1081 ip6stat_inc(ip6s_badscope); 1082 continue; 1083 } 1084 1085 m6->m6_pkt_out++; 1086 m6->m6_bytes_out += plen; 1087 1088 phyint_send6(ifn, ip6, m, flags); 1089 if_put(ifn); 1090 } while ((rt = rtable_iterate(rt)) != NULL); 1091 1092 return 0; 1093 } 1094 1095 void 1096 phyint_send6(struct ifnet *ifp, struct ip6_hdr *ip6, struct mbuf *m, int flags) 1097 { 1098 struct mbuf *mb_copy; 1099 struct sockaddr_in6 *dst6, sin6; 1100 int error = 0; 1101 1102 NET_ASSERT_LOCKED(); 1103 1104 /* 1105 * Make a new reference to the packet; make sure that 1106 * the IPv6 header is actually copied, not just referenced, 1107 * so that ip6_output() only scribbles on the copy. 1108 */ 1109 mb_copy = m_dup_pkt(m, max_linkhdr, M_NOWAIT); 1110 if (mb_copy == NULL) 1111 return; 1112 /* set MCAST flag to the outgoing packet */ 1113 mb_copy->m_flags |= M_MCAST; 1114 1115 /* 1116 * If we sourced the packet, call ip6_output since we may divide 1117 * the packet into fragments when the packet is too big for the 1118 * outgoing interface. 1119 * Otherwise, we can simply send the packet to the interface 1120 * sending queue. 1121 */ 1122 if (m->m_pkthdr.ph_ifidx == 0) { 1123 struct ip6_moptions im6o; 1124 1125 im6o.im6o_ifidx = ifp->if_index; 1126 /* XXX: ip6_output will override ip6->ip6_hlim */ 1127 im6o.im6o_hlim = ip6->ip6_hlim; 1128 im6o.im6o_loop = 1; 1129 error = ip6_output(mb_copy, NULL, NULL, flags | IPV6_FORWARDING, 1130 &im6o, NULL); 1131 return; 1132 } 1133 1134 /* 1135 * If we belong to the destination multicast group 1136 * on the outgoing interface, loop back a copy. 1137 */ 1138 dst6 = &sin6; 1139 memset(&sin6, 0, sizeof(sin6)); 1140 if (in6_hasmulti(&ip6->ip6_dst, ifp)) { 1141 dst6->sin6_len = sizeof(struct sockaddr_in6); 1142 dst6->sin6_family = AF_INET6; 1143 dst6->sin6_addr = ip6->ip6_dst; 1144 ip6_mloopback(ifp, m, dst6); 1145 } 1146 /* 1147 * Put the packet into the sending queue of the outgoing interface 1148 * if it would fit in the MTU of the interface. 1149 */ 1150 if (mb_copy->m_pkthdr.len <= ifp->if_mtu || ifp->if_mtu < IPV6_MMTU) { 1151 dst6->sin6_len = sizeof(struct sockaddr_in6); 1152 dst6->sin6_family = AF_INET6; 1153 dst6->sin6_addr = ip6->ip6_dst; 1154 error = ifp->if_output(ifp, mb_copy, sin6tosa(dst6), NULL); 1155 } else { 1156 if (ip6_mcast_pmtu) 1157 icmp6_error(mb_copy, ICMP6_PACKET_TOO_BIG, 0, 1158 ifp->if_mtu); 1159 else { 1160 m_freem(mb_copy); /* simply discard the packet */ 1161 } 1162 } 1163 } 1164 1165 struct ifnet * 1166 mrt6_iflookupbymif(mifi_t mifi, unsigned int rtableid) 1167 { 1168 struct mif6 *m6; 1169 struct ifnet *ifp; 1170 1171 TAILQ_FOREACH(ifp, &ifnetlist, if_list) { 1172 if (ifp->if_rdomain != rtableid) 1173 continue; 1174 if ((m6 = (struct mif6 *)ifp->if_mcast6) == NULL) 1175 continue; 1176 if (m6->m6_mifi != mifi) 1177 continue; 1178 1179 return ifp; 1180 } 1181 1182 return NULL; 1183 } 1184 1185 struct rtentry * 1186 mf6c_find(struct ifnet *ifp, struct in6_addr *origin, struct in6_addr *group, 1187 unsigned int rtableid) 1188 { 1189 struct rtentry *rt; 1190 struct sockaddr_in6 msin6; 1191 1192 memset(&msin6, 0, sizeof(msin6)); 1193 msin6.sin6_family = AF_INET6; 1194 msin6.sin6_len = sizeof(msin6); 1195 msin6.sin6_addr = *group; 1196 1197 rt = rtalloc(sin6tosa(&msin6), 0, rtableid); 1198 do { 1199 if (!rtisvalid(rt)) { 1200 rtfree(rt); 1201 return NULL; 1202 } 1203 if (ISSET(rt->rt_flags, RTF_HOST | RTF_MULTICAST) != 1204 (RTF_HOST | RTF_MULTICAST)) 1205 continue; 1206 /* Return first occurrence if interface is not specified. */ 1207 if (ifp == NULL) 1208 return rt; 1209 if (rt->rt_ifidx == ifp->if_index) 1210 return rt; 1211 } while ((rt = rtable_iterate(rt)) != NULL); 1212 1213 return NULL; 1214 } 1215 1216 struct rtentry * 1217 mrt6_mcast_add(struct ifnet *ifp, struct sockaddr *origin, 1218 struct sockaddr *group) 1219 { 1220 struct ifaddr *ifa; 1221 int rv; 1222 unsigned int rtableid = ifp->if_rdomain; 1223 1224 TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) { 1225 if (ifa->ifa_addr->sa_family == AF_INET6) 1226 break; 1227 } 1228 if (ifa == NULL) { 1229 DPRINTF("ifa == NULL"); 1230 return NULL; 1231 } 1232 1233 rv = rt_ifa_add(ifa, RTF_HOST | RTF_MULTICAST | RTF_MPATH, group, 1234 ifp->if_rdomain); 1235 if (rv != 0) { 1236 DPRINTF("rt_ifa_add failed %d", rv); 1237 return NULL; 1238 } 1239 1240 return mf6c_find(ifp, NULL, &satosin6(group)->sin6_addr, rtableid); 1241 } 1242 1243 void 1244 mrt6_mcast_del(struct rtentry *rt, unsigned int rtableid) 1245 { 1246 struct ifnet *ifp; 1247 int error; 1248 1249 /* Remove all timers related to this route. */ 1250 rt_timer_remove_all(rt); 1251 1252 free(rt->rt_llinfo, M_MRTABLE, sizeof(struct mf6c)); 1253 rt->rt_llinfo = NULL; 1254 1255 ifp = if_get(rt->rt_ifidx); 1256 if (ifp == NULL) 1257 return; 1258 error = rtdeletemsg(rt, ifp, rtableid); 1259 if_put(ifp); 1260 1261 if (error) 1262 DPRINTF("delete route error %d\n", error); 1263 } 1264