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