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
ip6_mrouter_set(int cmd,struct socket * so,struct mbuf * m)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
ip6_mrouter_get(int cmd,struct socket * so,struct mbuf * m)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
mrt6_ioctl(struct socket * so,u_long cmd,caddr_t data)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
get_sg6_cnt(struct sioc_sg_req6 * req,unsigned int rtableid)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
get_mif6_cnt(struct sioc_mif_req6 * req,unsigned int rtableid)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
mrt6_sysctl_mif(void * oldp,size_t * oldlenp)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
mrt6_rtwalk_mf6csysctl(struct rtentry * rt,void * arg,unsigned int rtableid)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
mrt6_sysctl_mfc(void * oldp,size_t * oldlenp)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
ip6_mrouter_init(struct socket * so,int v,int cmd)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
mrouter6_rtwalk_delete(struct rtentry * rt,void * arg,unsigned int rtableid)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
ip6_mrouter_done(struct socket * so)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
ip6_mrouter_detach(struct ifnet * ifp)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
add_m6if(struct socket * so,struct mif6ctl * mifcp)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
del_m6if(struct socket * so,mifi_t * mifip)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
mf6c_add_route(struct ifnet * ifp,struct sockaddr * origin,struct sockaddr * group,struct mf6cctl * mf6cc,int wait)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
mf6c_update(struct mf6cctl * mf6cc,int wait,unsigned int rtableid)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
mf6c_add(struct mf6cctl * mfccp,struct in6_addr * origin,struct in6_addr * group,int vidx,unsigned int rtableid,int wait)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
add_m6fc(struct socket * so,struct mf6cctl * mfccp)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
del_m6fc(struct socket * so,struct mf6cctl * mfccp)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
socket6_send(struct socket * so,struct mbuf * mm,struct sockaddr_in6 * src)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
ip6_mforward(struct ip6_hdr * ip6,struct ifnet * ifp,struct mbuf * m,int flags)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
mf6c_expire_route(struct rtentry * rt,u_int rtableid)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
ip6_mdq(struct mbuf * m,struct ifnet * ifp,struct rtentry * rt,int flags)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
phyint_send6(struct ifnet * ifp,struct ip6_hdr * ip6,struct mbuf * m,int flags)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 *
mrt6_iflookupbymif(mifi_t mifi,unsigned int rtableid)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 *
mf6c_find(struct ifnet * ifp,struct in6_addr * origin,struct in6_addr * group,unsigned int rtableid)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 *
mrt6_mcast_add(struct ifnet * ifp,struct sockaddr * origin,struct sockaddr * group)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
mrt6_mcast_del(struct rtentry * rt,unsigned int rtableid)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