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