1 /* $OpenBSD: ip_mroute.c,v 1.143 2024/07/02 18:33:47 bluhm Exp $ */
2 /* $NetBSD: ip_mroute.c,v 1.85 2004/04/26 01:31:57 matt Exp $ */
3
4 /*
5 * Copyright (c) 1989 Stephen Deering
6 * Copyright (c) 1992, 1993
7 * The Regents of the University of California. All rights reserved.
8 *
9 * This code is derived from software contributed to Berkeley by
10 * Stephen Deering of Stanford University.
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
20 * 3. Neither the name of the University nor the names of its contributors
21 * may be used to endorse or promote products derived from this software
22 * without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 *
36 * @(#)ip_mroute.c 8.2 (Berkeley) 11/15/93
37 */
38
39 /*
40 * IP multicast forwarding procedures
41 *
42 * Written by David Waitzman, BBN Labs, August 1988.
43 * Modified by Steve Deering, Stanford, February 1989.
44 * Modified by Mark J. Steiglitz, Stanford, May, 1991
45 * Modified by Van Jacobson, LBL, January 1993
46 * Modified by Ajit Thyagarajan, PARC, August 1993
47 * Modified by Bill Fenner, PARC, April 1994
48 * Modified by Charles M. Hannum, NetBSD, May 1995.
49 * Modified by Ahmed Helmy, SGI, June 1996
50 * Modified by George Edmond Eddy (Rusty), ISI, February 1998
51 * Modified by Pavlin Radoslavov, USC/ISI, May 1998, August 1999, October 2000
52 * Modified by Hitoshi Asaeda, WIDE, August 2000
53 * Modified by Pavlin Radoslavov, ICSI, October 2002
54 *
55 * MROUTING Revision: 1.2
56 * advanced API support, bandwidth metering and signaling
57 */
58
59 #include <sys/param.h>
60 #include <sys/systm.h>
61 #include <sys/mbuf.h>
62 #include <sys/socket.h>
63 #include <sys/socketvar.h>
64 #include <sys/protosw.h>
65 #include <sys/ioctl.h>
66 #include <sys/syslog.h>
67
68 #include <net/if.h>
69 #include <net/if_var.h>
70 #include <net/route.h>
71
72 #include <netinet/in.h>
73 #include <netinet/ip.h>
74 #include <netinet/ip_var.h>
75 #include <netinet/in_pcb.h>
76 #include <netinet/igmp.h>
77 #include <netinet/ip_mroute.h>
78
79 /* #define MCAST_DEBUG */
80
81 #ifdef MCAST_DEBUG
82 int mcast_debug = 1;
83 #define DPRINTF(fmt, args...) \
84 do { \
85 if (mcast_debug) \
86 printf("%s:%d " fmt "\n", \
87 __func__, __LINE__, ## args); \
88 } while (0)
89 #else
90 #define DPRINTF(fmt, args...) \
91 do { } while (0)
92 #endif
93
94 /*
95 * Globals. All but ip_mrouter and ip_mrtproto could be static,
96 * except for netstat or debugging purposes.
97 */
98 struct socket *ip_mrouter[RT_TABLEID_MAX + 1];
99 struct rttimer_queue ip_mrouterq;
100 uint64_t mrt_count[RT_TABLEID_MAX + 1];
101 int ip_mrtproto = IGMP_DVMRP; /* for netstat only */
102
103 struct mrtstat mrtstat;
104
105 struct rtentry *mfc_find(struct ifnet *, struct in_addr *,
106 struct in_addr *, unsigned int);
107 int get_sg_cnt(unsigned int, struct sioc_sg_req *);
108 int get_vif_cnt(unsigned int, struct sioc_vif_req *);
109 int mrt_rtwalk_mfcsysctl(struct rtentry *, void *, unsigned int);
110 int ip_mrouter_init(struct socket *, struct mbuf *);
111 int mrouter_rtwalk_delete(struct rtentry *, void *, unsigned int);
112 int get_version(struct mbuf *);
113 int add_vif(struct socket *, struct mbuf *);
114 int del_vif(struct socket *, struct mbuf *);
115 void update_mfc_params(struct mfcctl2 *, int, unsigned int);
116 int mfc_add(struct mfcctl2 *, struct in_addr *, struct in_addr *,
117 int, unsigned int, int);
118 int add_mfc(struct socket *, struct mbuf *);
119 int del_mfc(struct socket *, struct mbuf *);
120 int set_api_config(struct socket *, struct mbuf *); /* chose API capabilities */
121 int get_api_support(struct mbuf *);
122 int get_api_config(struct mbuf *);
123 int socket_send(struct socket *, struct mbuf *,
124 struct sockaddr_in *);
125 int ip_mdq(struct mbuf *, struct ifnet *, struct rtentry *, int);
126 struct ifnet *if_lookupbyvif(vifi_t, unsigned int);
127 struct rtentry *rt_mcast_add(struct ifnet *, struct sockaddr *,
128 struct sockaddr *);
129 void mrt_mcast_del(struct rtentry *, unsigned int);
130
131 /*
132 * Kernel multicast routing API capabilities and setup.
133 * If more API capabilities are added to the kernel, they should be
134 * recorded in `mrt_api_support'.
135 */
136 static const u_int32_t mrt_api_support = (MRT_MFC_FLAGS_DISABLE_WRONGVIF |
137 MRT_MFC_RP);
138 static u_int32_t mrt_api_config = 0;
139
140 /*
141 * Find a route for a given origin IP address and Multicast group address
142 * Type of service parameter to be added in the future!!!
143 * Statistics are updated by the caller if needed
144 * (mrtstat.mrts_mfc_lookups and mrtstat.mrts_mfc_misses)
145 */
146 struct rtentry *
mfc_find(struct ifnet * ifp,struct in_addr * origin,struct in_addr * group,unsigned int rtableid)147 mfc_find(struct ifnet *ifp, struct in_addr *origin, struct in_addr *group,
148 unsigned int rtableid)
149 {
150 struct rtentry *rt;
151 struct sockaddr_in msin;
152
153 memset(&msin, 0, sizeof(msin));
154 msin.sin_len = sizeof(msin);
155 msin.sin_family = AF_INET;
156 msin.sin_addr = *group;
157
158 rt = rtalloc(sintosa(&msin), 0, rtableid);
159 do {
160 if (!rtisvalid(rt)) {
161 rtfree(rt);
162 return NULL;
163 }
164 /* Don't consider non multicast routes. */
165 if (ISSET(rt->rt_flags, RTF_HOST | RTF_MULTICAST) !=
166 (RTF_HOST | RTF_MULTICAST))
167 continue;
168 /* Return first occurrence if interface is not specified. */
169 if (ifp == NULL)
170 return (rt);
171 if (rt->rt_ifidx == ifp->if_index)
172 return (rt);
173 } while ((rt = rtable_iterate(rt)) != NULL);
174
175 return (NULL);
176 }
177
178 /*
179 * Handle MRT setsockopt commands to modify the multicast routing tables.
180 */
181 int
ip_mrouter_set(struct socket * so,int optname,struct mbuf * m)182 ip_mrouter_set(struct socket *so, int optname, struct mbuf *m)
183 {
184 struct inpcb *inp = sotoinpcb(so);
185 int error;
186
187 if (optname != MRT_INIT &&
188 so != ip_mrouter[inp->inp_rtableid])
189 error = ENOPROTOOPT;
190 else
191 switch (optname) {
192 case MRT_INIT:
193 error = ip_mrouter_init(so, m);
194 break;
195 case MRT_DONE:
196 error = ip_mrouter_done(so);
197 break;
198 case MRT_ADD_VIF:
199 error = add_vif(so, m);
200 break;
201 case MRT_DEL_VIF:
202 error = del_vif(so, m);
203 break;
204 case MRT_ADD_MFC:
205 error = add_mfc(so, m);
206 break;
207 case MRT_DEL_MFC:
208 error = del_mfc(so, m);
209 break;
210 case MRT_API_CONFIG:
211 error = set_api_config(so, m);
212 break;
213 default:
214 error = ENOPROTOOPT;
215 break;
216 }
217
218 return (error);
219 }
220
221 /*
222 * Handle MRT getsockopt commands
223 */
224 int
ip_mrouter_get(struct socket * so,int optname,struct mbuf * m)225 ip_mrouter_get(struct socket *so, int optname, struct mbuf *m)
226 {
227 struct inpcb *inp = sotoinpcb(so);
228 int error;
229
230 if (so != ip_mrouter[inp->inp_rtableid])
231 error = ENOPROTOOPT;
232 else {
233 switch (optname) {
234 case MRT_VERSION:
235 error = get_version(m);
236 break;
237 case MRT_API_SUPPORT:
238 error = get_api_support(m);
239 break;
240 case MRT_API_CONFIG:
241 error = get_api_config(m);
242 break;
243 default:
244 error = ENOPROTOOPT;
245 break;
246 }
247 }
248
249 return (error);
250 }
251
252 /*
253 * Handle ioctl commands to obtain information from the cache
254 */
255 int
mrt_ioctl(struct socket * so,u_long cmd,caddr_t data)256 mrt_ioctl(struct socket *so, u_long cmd, caddr_t data)
257 {
258 struct inpcb *inp = sotoinpcb(so);
259 int error;
260
261 if (inp == NULL)
262 return (ENOTCONN);
263
264 KERNEL_LOCK();
265
266 if (so != ip_mrouter[inp->inp_rtableid])
267 error = EINVAL;
268 else
269 switch (cmd) {
270 case SIOCGETVIFCNT:
271 NET_LOCK_SHARED();
272 error = get_vif_cnt(inp->inp_rtableid,
273 (struct sioc_vif_req *)data);
274 NET_UNLOCK_SHARED();
275 break;
276 case SIOCGETSGCNT:
277 NET_LOCK_SHARED();
278 error = get_sg_cnt(inp->inp_rtableid,
279 (struct sioc_sg_req *)data);
280 NET_UNLOCK_SHARED();
281 break;
282 default:
283 error = ENOTTY;
284 break;
285 }
286
287 KERNEL_UNLOCK();
288 return (error);
289 }
290
291 /*
292 * returns the packet, byte, rpf-failure count for the source group provided
293 */
294 int
get_sg_cnt(unsigned int rtableid,struct sioc_sg_req * req)295 get_sg_cnt(unsigned int rtableid, struct sioc_sg_req *req)
296 {
297 struct rtentry *rt;
298 struct mfc *mfc;
299
300 rt = mfc_find(NULL, &req->src, &req->grp, rtableid);
301 if (rt == NULL) {
302 req->pktcnt = req->bytecnt = req->wrong_if = 0xffffffff;
303 return (EADDRNOTAVAIL);
304 }
305
306 req->pktcnt = req->bytecnt = req->wrong_if = 0;
307 do {
308 /* Don't consider non multicast routes. */
309 if (ISSET(rt->rt_flags, RTF_HOST | RTF_MULTICAST) !=
310 (RTF_HOST | RTF_MULTICAST))
311 continue;
312
313 mfc = (struct mfc *)rt->rt_llinfo;
314 if (mfc == NULL)
315 continue;
316
317 req->pktcnt += mfc->mfc_pkt_cnt;
318 req->bytecnt += mfc->mfc_byte_cnt;
319 req->wrong_if += mfc->mfc_wrong_if;
320 } while ((rt = rtable_iterate(rt)) != NULL);
321
322 return (0);
323 }
324
325 /*
326 * returns the input and output packet and byte counts on the vif provided
327 */
328 int
get_vif_cnt(unsigned int rtableid,struct sioc_vif_req * req)329 get_vif_cnt(unsigned int rtableid, struct sioc_vif_req *req)
330 {
331 struct ifnet *ifp;
332 struct vif *v;
333 vifi_t vifi = req->vifi;
334
335 if ((ifp = if_lookupbyvif(vifi, rtableid)) == NULL)
336 return (EINVAL);
337
338 v = (struct vif *)ifp->if_mcast;
339 req->icount = v->v_pkt_in;
340 req->ocount = v->v_pkt_out;
341 req->ibytes = v->v_bytes_in;
342 req->obytes = v->v_bytes_out;
343
344 return (0);
345 }
346
347 int
mrt_sysctl_vif(void * oldp,size_t * oldlenp)348 mrt_sysctl_vif(void *oldp, size_t *oldlenp)
349 {
350 caddr_t where = oldp;
351 size_t needed, given;
352 struct ifnet *ifp;
353 struct vif *vifp;
354 struct vifinfo vinfo;
355
356 given = *oldlenp;
357 needed = 0;
358 memset(&vinfo, 0, sizeof vinfo);
359 TAILQ_FOREACH(ifp, &ifnetlist, if_list) {
360 if ((vifp = (struct vif *)ifp->if_mcast) == NULL)
361 continue;
362
363 vinfo.v_vifi = vifp->v_id;
364 vinfo.v_flags = vifp->v_flags;
365 vinfo.v_threshold = vifp->v_threshold;
366 vinfo.v_lcl_addr = vifp->v_lcl_addr;
367 vinfo.v_rmt_addr = vifp->v_rmt_addr;
368 vinfo.v_pkt_in = vifp->v_pkt_in;
369 vinfo.v_pkt_out = vifp->v_pkt_out;
370 vinfo.v_bytes_in = vifp->v_bytes_in;
371 vinfo.v_bytes_out = vifp->v_bytes_out;
372
373 needed += sizeof(vinfo);
374 if (where && needed <= given) {
375 int error;
376
377 error = copyout(&vinfo, where, sizeof(vinfo));
378 if (error)
379 return (error);
380 where += sizeof(vinfo);
381 }
382 }
383 if (where) {
384 *oldlenp = needed;
385 if (given < needed)
386 return (ENOMEM);
387 } else
388 *oldlenp = (11 * needed) / 10;
389
390 return (0);
391 }
392
393 struct mfcsysctlarg {
394 struct mfcinfo *msa_minfos;
395 size_t msa_len;
396 size_t msa_needed;
397 };
398
399 int
mrt_rtwalk_mfcsysctl(struct rtentry * rt,void * arg,unsigned int rtableid)400 mrt_rtwalk_mfcsysctl(struct rtentry *rt, void *arg, unsigned int rtableid)
401 {
402 struct mfc *mfc = (struct mfc *)rt->rt_llinfo;
403 struct mfcsysctlarg *msa = (struct mfcsysctlarg *)arg;
404 struct ifnet *ifp;
405 struct vif *v;
406 struct mfcinfo *minfo;
407 int new = 0;
408
409 /* Skip entries being removed. */
410 if (mfc == NULL)
411 return (0);
412
413 /* Skip non-multicast routes. */
414 if (ISSET(rt->rt_flags, RTF_HOST | RTF_MULTICAST) !=
415 (RTF_HOST | RTF_MULTICAST))
416 return (0);
417
418 /* User just asked for the output size. */
419 if (msa->msa_minfos == NULL) {
420 msa->msa_needed += sizeof(*minfo);
421 return (0);
422 }
423
424 /* Skip route with invalid interfaces. */
425 if ((ifp = if_get(rt->rt_ifidx)) == NULL)
426 return (0);
427 if ((v = (struct vif *)ifp->if_mcast) == NULL) {
428 if_put(ifp);
429 return (0);
430 }
431
432 for (minfo = msa->msa_minfos;
433 (uint8_t *)(minfo + 1) <=
434 (uint8_t *)msa->msa_minfos + msa->msa_len;
435 minfo++) {
436 /* Find a new entry or update old entry. */
437 if (minfo->mfc_origin.s_addr !=
438 satosin(rt->rt_gateway)->sin_addr.s_addr ||
439 minfo->mfc_mcastgrp.s_addr !=
440 satosin(rt_key(rt))->sin_addr.s_addr) {
441 if (minfo->mfc_origin.s_addr != 0 ||
442 minfo->mfc_mcastgrp.s_addr != 0)
443 continue;
444
445 new = 1;
446 }
447
448 minfo->mfc_origin = satosin(rt->rt_gateway)->sin_addr;
449 minfo->mfc_mcastgrp = satosin(rt_key(rt))->sin_addr;
450 minfo->mfc_parent = mfc->mfc_parent;
451 minfo->mfc_pkt_cnt += mfc->mfc_pkt_cnt;
452 minfo->mfc_byte_cnt += mfc->mfc_byte_cnt;
453 minfo->mfc_ttls[v->v_id] = mfc->mfc_ttl;
454 break;
455 }
456
457 if (new != 0)
458 msa->msa_needed += sizeof(*minfo);
459
460 if_put(ifp);
461
462 return (0);
463 }
464
465 int
mrt_sysctl_mfc(void * oldp,size_t * oldlenp)466 mrt_sysctl_mfc(void *oldp, size_t *oldlenp)
467 {
468 unsigned int rtableid;
469 int error;
470 struct mfcsysctlarg msa;
471
472 if (oldp != NULL && *oldlenp > MAXPHYS)
473 return (EINVAL);
474
475 memset(&msa, 0, sizeof(msa));
476 if (oldp != NULL && *oldlenp > 0) {
477 msa.msa_minfos = malloc(*oldlenp, M_TEMP, M_WAITOK | M_ZERO);
478 msa.msa_len = *oldlenp;
479 }
480
481 for (rtableid = 0; rtableid <= RT_TABLEID_MAX; rtableid++) {
482 rtable_walk(rtableid, AF_INET, NULL, mrt_rtwalk_mfcsysctl,
483 &msa);
484 }
485
486 if (msa.msa_minfos != NULL && msa.msa_needed > 0 &&
487 (error = copyout(msa.msa_minfos, oldp, msa.msa_needed)) != 0) {
488 free(msa.msa_minfos, M_TEMP, msa.msa_len);
489 return (error);
490 }
491
492 free(msa.msa_minfos, M_TEMP, msa.msa_len);
493 *oldlenp = msa.msa_needed;
494
495 return (0);
496 }
497
498 /*
499 * Enable multicast routing
500 */
501 int
ip_mrouter_init(struct socket * so,struct mbuf * m)502 ip_mrouter_init(struct socket *so, struct mbuf *m)
503 {
504 struct inpcb *inp = sotoinpcb(so);
505 unsigned int rtableid = inp->inp_rtableid;
506 int *v;
507
508 if (so->so_type != SOCK_RAW ||
509 so->so_proto->pr_protocol != IPPROTO_IGMP)
510 return (EOPNOTSUPP);
511
512 if (m == NULL || m->m_len < sizeof(int))
513 return (EINVAL);
514
515 v = mtod(m, int *);
516 if (*v != 1)
517 return (EINVAL);
518
519 if (ip_mrouter[rtableid] != NULL)
520 return (EADDRINUSE);
521
522 ip_mrouter[rtableid] = so;
523
524 return (0);
525 }
526
527 int
mrouter_rtwalk_delete(struct rtentry * rt,void * arg,unsigned int rtableid)528 mrouter_rtwalk_delete(struct rtentry *rt, void *arg, unsigned int rtableid)
529 {
530 /* Skip non-multicast routes. */
531 if (ISSET(rt->rt_flags, RTF_HOST | RTF_MULTICAST) !=
532 (RTF_HOST | RTF_MULTICAST))
533 return (0);
534
535 return EEXIST;
536 }
537
538 /*
539 * Disable multicast routing
540 */
541 int
ip_mrouter_done(struct socket * so)542 ip_mrouter_done(struct socket *so)
543 {
544 struct inpcb *inp = sotoinpcb(so);
545 struct ifnet *ifp;
546 unsigned int rtableid = inp->inp_rtableid;
547 int error;
548
549 NET_ASSERT_LOCKED();
550
551 /* Delete all remaining installed multicast routes. */
552 do {
553 struct rtentry *rt = NULL;
554
555 error = rtable_walk(rtableid, AF_INET, &rt,
556 mrouter_rtwalk_delete, NULL);
557 if (rt != NULL && error == EEXIST) {
558 mrt_mcast_del(rt, rtableid);
559 error = EAGAIN;
560 }
561 rtfree(rt);
562 } while (error == EAGAIN);
563
564 /* Unregister all interfaces in the domain. */
565 TAILQ_FOREACH(ifp, &ifnetlist, if_list) {
566 if (ifp->if_rdomain != rtableid)
567 continue;
568
569 vif_delete(ifp);
570 }
571
572 mrt_api_config = 0;
573
574 ip_mrouter[rtableid] = NULL;
575 mrt_count[rtableid] = 0;
576
577 return (0);
578 }
579
580 int
get_version(struct mbuf * m)581 get_version(struct mbuf *m)
582 {
583 int *v = mtod(m, int *);
584
585 *v = 0x0305; /* XXX !!!! */
586 m->m_len = sizeof(int);
587 return (0);
588 }
589
590 /*
591 * Configure API capabilities
592 */
593 int
set_api_config(struct socket * so,struct mbuf * m)594 set_api_config(struct socket *so, struct mbuf *m)
595 {
596 struct inpcb *inp = sotoinpcb(so);
597 struct ifnet *ifp;
598 u_int32_t *apival;
599 unsigned int rtableid = inp->inp_rtableid;
600
601 if (m == NULL || m->m_len < sizeof(u_int32_t))
602 return (EINVAL);
603
604 apival = mtod(m, u_int32_t *);
605
606 /*
607 * We can set the API capabilities only if it is the first operation
608 * after MRT_INIT. I.e.:
609 * - there are no vifs installed
610 * - the MFC table is empty
611 */
612 TAILQ_FOREACH(ifp, &ifnetlist, if_list) {
613 if (ifp->if_rdomain != rtableid)
614 continue;
615 if (ifp->if_mcast == NULL)
616 continue;
617
618 *apival = 0;
619 return (EPERM);
620 }
621 if (mrt_count[rtableid] > 0) {
622 *apival = 0;
623 return (EPERM);
624 }
625
626 mrt_api_config = *apival & mrt_api_support;
627 *apival = mrt_api_config;
628
629 return (0);
630 }
631
632 /*
633 * Get API capabilities
634 */
635 int
get_api_support(struct mbuf * m)636 get_api_support(struct mbuf *m)
637 {
638 u_int32_t *apival;
639
640 if (m == NULL || m->m_len < sizeof(u_int32_t))
641 return (EINVAL);
642
643 apival = mtod(m, u_int32_t *);
644
645 *apival = mrt_api_support;
646
647 return (0);
648 }
649
650 /*
651 * Get API configured capabilities
652 */
653 int
get_api_config(struct mbuf * m)654 get_api_config(struct mbuf *m)
655 {
656 u_int32_t *apival;
657
658 if (m == NULL || m->m_len < sizeof(u_int32_t))
659 return (EINVAL);
660
661 apival = mtod(m, u_int32_t *);
662
663 *apival = mrt_api_config;
664
665 return (0);
666 }
667
668 static struct sockaddr_in sin = { sizeof(sin), AF_INET };
669
670 int
add_vif(struct socket * so,struct mbuf * m)671 add_vif(struct socket *so, struct mbuf *m)
672 {
673 struct inpcb *inp = sotoinpcb(so);
674 struct vifctl *vifcp;
675 struct vif *vifp;
676 struct ifaddr *ifa;
677 struct ifnet *ifp;
678 struct ifreq ifr;
679 int error;
680 unsigned int rtableid = inp->inp_rtableid;
681
682 NET_ASSERT_LOCKED();
683
684 if (m == NULL || m->m_len < sizeof(struct vifctl))
685 return (EINVAL);
686
687 vifcp = mtod(m, struct vifctl *);
688 if (vifcp->vifc_vifi >= MAXVIFS)
689 return (EINVAL);
690 if (in_nullhost(vifcp->vifc_lcl_addr))
691 return (EADDRNOTAVAIL);
692 if (if_lookupbyvif(vifcp->vifc_vifi, rtableid) != NULL)
693 return (EADDRINUSE);
694
695 /* Tunnels are no longer supported use gif(4) instead. */
696 if (vifcp->vifc_flags & VIFF_TUNNEL)
697 return (EOPNOTSUPP);
698 {
699 sin.sin_addr = vifcp->vifc_lcl_addr;
700 ifa = ifa_ifwithaddr(sintosa(&sin), rtableid);
701 if (ifa == NULL)
702 return (EADDRNOTAVAIL);
703 }
704
705 /* Use the physical interface associated with the address. */
706 ifp = ifa->ifa_ifp;
707 if (ifp->if_mcast != NULL)
708 return (EADDRINUSE);
709
710 {
711 /* Make sure the interface supports multicast. */
712 if ((ifp->if_flags & IFF_MULTICAST) == 0)
713 return (EOPNOTSUPP);
714
715 /* Enable promiscuous reception of all IP multicasts. */
716 memset(&ifr, 0, sizeof(ifr));
717 satosin(&ifr.ifr_addr)->sin_len = sizeof(struct sockaddr_in);
718 satosin(&ifr.ifr_addr)->sin_family = AF_INET;
719 satosin(&ifr.ifr_addr)->sin_addr = zeroin_addr;
720 KERNEL_LOCK();
721 error = (*ifp->if_ioctl)(ifp, SIOCADDMULTI, (caddr_t)&ifr);
722 KERNEL_UNLOCK();
723 if (error)
724 return (error);
725 }
726
727 vifp = malloc(sizeof(*vifp), M_MRTABLE, M_WAITOK | M_ZERO);
728 ifp->if_mcast = (caddr_t)vifp;
729
730 vifp->v_id = vifcp->vifc_vifi;
731 vifp->v_flags = vifcp->vifc_flags;
732 vifp->v_threshold = vifcp->vifc_threshold;
733 vifp->v_lcl_addr = vifcp->vifc_lcl_addr;
734 vifp->v_rmt_addr = vifcp->vifc_rmt_addr;
735
736 return (0);
737 }
738
739 int
del_vif(struct socket * so,struct mbuf * m)740 del_vif(struct socket *so, struct mbuf *m)
741 {
742 struct inpcb *inp = sotoinpcb(so);
743 struct ifnet *ifp;
744 vifi_t *vifip;
745 unsigned int rtableid = inp->inp_rtableid;
746
747 NET_ASSERT_LOCKED();
748
749 if (m == NULL || m->m_len < sizeof(vifi_t))
750 return (EINVAL);
751
752 vifip = mtod(m, vifi_t *);
753 if ((ifp = if_lookupbyvif(*vifip, rtableid)) == NULL)
754 return (EADDRNOTAVAIL);
755
756 vif_delete(ifp);
757 return (0);
758 }
759
760 void
vif_delete(struct ifnet * ifp)761 vif_delete(struct ifnet *ifp)
762 {
763 struct vif *v;
764 struct ifreq ifr;
765
766 if ((v = (struct vif *)ifp->if_mcast) == NULL)
767 return;
768
769 ifp->if_mcast = NULL;
770
771 memset(&ifr, 0, sizeof(ifr));
772 satosin(&ifr.ifr_addr)->sin_len = sizeof(struct sockaddr_in);
773 satosin(&ifr.ifr_addr)->sin_family = AF_INET;
774 satosin(&ifr.ifr_addr)->sin_addr = zeroin_addr;
775 KERNEL_LOCK();
776 (*ifp->if_ioctl)(ifp, SIOCDELMULTI, (caddr_t)&ifr);
777 KERNEL_UNLOCK();
778
779 free(v, M_MRTABLE, sizeof(*v));
780 }
781
782 void
mfc_expire_route(struct rtentry * rt,u_int rtableid)783 mfc_expire_route(struct rtentry *rt, u_int rtableid)
784 {
785 struct mfc *mfc = (struct mfc *)rt->rt_llinfo;
786
787 /* Skip entry being deleted. */
788 if (mfc == NULL)
789 return;
790
791 DPRINTF("Route domain %d origin %#08X group %#08x interface %d "
792 "expire %s", rtableid, satosin(rt->rt_gateway)->sin_addr.s_addr,
793 satosin(rt_key(rt))->sin_addr.s_addr,
794 rt->rt_ifidx, mfc->mfc_expire ? "yes" : "no");
795
796 /* Not expired, add it back to the queue. */
797 if (mfc->mfc_expire == 0) {
798 mfc->mfc_expire = 1;
799 rt_timer_add(rt, &ip_mrouterq, rtableid);
800 return;
801 }
802
803 mrt_mcast_del(rt, rtableid);
804 }
805
806 int
mfc_add_route(struct ifnet * ifp,struct sockaddr * origin,struct sockaddr * group,struct mfcctl2 * mfccp,int wait)807 mfc_add_route(struct ifnet *ifp, struct sockaddr *origin,
808 struct sockaddr *group, struct mfcctl2 *mfccp, int wait)
809 {
810 struct vif *v = (struct vif *)ifp->if_mcast;
811 struct rtentry *rt;
812 struct mfc *mfc;
813 unsigned int rtableid = ifp->if_rdomain;
814
815 rt = rt_mcast_add(ifp, origin, group);
816 if (rt == NULL)
817 return (EHOSTUNREACH);
818
819 mfc = malloc(sizeof(*mfc), M_MRTABLE, wait | M_ZERO);
820 if (mfc == NULL) {
821 DPRINTF("origin %#08X group %#08X parent %d (%s) "
822 "malloc failed",
823 satosin(origin)->sin_addr.s_addr,
824 satosin(group)->sin_addr.s_addr,
825 mfccp->mfcc_parent, ifp->if_xname);
826 mrt_mcast_del(rt, rtableid);
827 rtfree(rt);
828 return (ENOMEM);
829 }
830
831 rt->rt_llinfo = (caddr_t)mfc;
832
833 rt_timer_add(rt, &ip_mrouterq, rtableid);
834
835 mfc->mfc_parent = mfccp->mfcc_parent;
836 mfc->mfc_pkt_cnt = 0;
837 mfc->mfc_byte_cnt = 0;
838 mfc->mfc_wrong_if = 0;
839 mfc->mfc_ttl = mfccp->mfcc_ttls[v->v_id];
840 mfc->mfc_flags = mfccp->mfcc_flags[v->v_id] & mrt_api_config &
841 MRT_MFC_FLAGS_ALL;
842 mfc->mfc_expire = 0;
843
844 /* set the RP address */
845 if (mrt_api_config & MRT_MFC_RP)
846 mfc->mfc_rp = mfccp->mfcc_rp;
847 else
848 mfc->mfc_rp = zeroin_addr;
849
850 rtfree(rt);
851
852 return (0);
853 }
854
855 void
update_mfc_params(struct mfcctl2 * mfccp,int wait,unsigned int rtableid)856 update_mfc_params(struct mfcctl2 *mfccp, int wait, unsigned int rtableid)
857 {
858 struct rtentry *rt;
859 struct mfc *mfc;
860 struct ifnet *ifp;
861 int i;
862 struct sockaddr_in osin, msin;
863
864 memset(&osin, 0, sizeof(osin));
865 osin.sin_len = sizeof(osin);
866 osin.sin_family = AF_INET;
867 osin.sin_addr = mfccp->mfcc_origin;
868
869 memset(&msin, 0, sizeof(msin));
870 msin.sin_len = sizeof(msin);
871 msin.sin_family = AF_INET;
872 msin.sin_addr = mfccp->mfcc_mcastgrp;
873
874 for (i = 0; i < MAXVIFS; i++) {
875 /* Don't add/del upstream routes here. */
876 if (i == mfccp->mfcc_parent)
877 continue;
878
879 /* Test for vif existence and then update the entry. */
880 if ((ifp = if_lookupbyvif(i, rtableid)) == NULL)
881 continue;
882
883 rt = mfc_find(ifp, &mfccp->mfcc_origin,
884 &mfccp->mfcc_mcastgrp, rtableid);
885
886 /* vif not configured or removed. */
887 if (mfccp->mfcc_ttls[i] == 0) {
888 /* Route doesn't exist, nothing to do. */
889 if (rt == NULL)
890 continue;
891
892 DPRINTF("del route (group %#08X) for vif %d (%s)",
893 mfccp->mfcc_mcastgrp.s_addr, i, ifp->if_xname);
894 mrt_mcast_del(rt, rtableid);
895 rtfree(rt);
896 continue;
897 }
898
899 /* Route exists, look for changes. */
900 if (rt != NULL) {
901 mfc = (struct mfc *)rt->rt_llinfo;
902 /* Skip route being deleted. */
903 if (mfc == NULL) {
904 rtfree(rt);
905 continue;
906 }
907
908 /* No new changes to apply. */
909 if (mfccp->mfcc_ttls[i] == mfc->mfc_ttl &&
910 mfccp->mfcc_parent == mfc->mfc_parent) {
911 rtfree(rt);
912 continue;
913 }
914
915 DPRINTF("update route (group %#08X) for vif %d (%s)",
916 mfccp->mfcc_mcastgrp.s_addr, i, ifp->if_xname);
917 mfc->mfc_ttl = mfccp->mfcc_ttls[i];
918 mfc->mfc_parent = mfccp->mfcc_parent;
919 rtfree(rt);
920 continue;
921 }
922
923 DPRINTF("add route (group %#08X) for vif %d (%s)",
924 mfccp->mfcc_mcastgrp.s_addr, i, ifp->if_xname);
925
926 mfc_add_route(ifp, sintosa(&osin), sintosa(&msin),
927 mfccp, wait);
928 }
929
930 /* Create route for the parent interface. */
931 if ((ifp = if_lookupbyvif(mfccp->mfcc_parent, rtableid)) == NULL) {
932 DPRINTF("failed to find upstream interface %d",
933 mfccp->mfcc_parent);
934 return;
935 }
936
937 /* We already have a route, nothing to do here. */
938 if ((rt = mfc_find(ifp, &mfccp->mfcc_origin,
939 &mfccp->mfcc_mcastgrp, rtableid)) != NULL) {
940 rtfree(rt);
941 return;
942 }
943
944 DPRINTF("add upstream route (group %#08X) for if %s",
945 mfccp->mfcc_mcastgrp.s_addr, ifp->if_xname);
946 mfc_add_route(ifp, sintosa(&osin), sintosa(&msin), mfccp, wait);
947 }
948
949 int
mfc_add(struct mfcctl2 * mfcctl2,struct in_addr * origin,struct in_addr * group,int vidx,unsigned int rtableid,int wait)950 mfc_add(struct mfcctl2 *mfcctl2, struct in_addr *origin,
951 struct in_addr *group, int vidx, unsigned int rtableid, int wait)
952 {
953 struct ifnet *ifp;
954 struct vif *v;
955 struct mfcctl2 mfcctl;
956
957 ifp = if_lookupbyvif(vidx, rtableid);
958 if (ifp == NULL ||
959 (v = (struct vif *)ifp->if_mcast) == NULL)
960 return (EHOSTUNREACH);
961
962 memset(&mfcctl, 0, sizeof(mfcctl));
963 if (mfcctl2 == NULL) {
964 mfcctl.mfcc_origin = *origin;
965 mfcctl.mfcc_mcastgrp = *group;
966 mfcctl.mfcc_parent = vidx;
967 } else
968 memcpy(&mfcctl, mfcctl2, sizeof(mfcctl));
969
970 update_mfc_params(&mfcctl, wait, rtableid);
971
972 return (0);
973 }
974
975 int
add_mfc(struct socket * so,struct mbuf * m)976 add_mfc(struct socket *so, struct mbuf *m)
977 {
978 struct inpcb *inp = sotoinpcb(so);
979 struct mfcctl2 mfcctl2;
980 int mfcctl_size = sizeof(struct mfcctl);
981 unsigned int rtableid = inp->inp_rtableid;
982
983 NET_ASSERT_LOCKED();
984
985 if (mrt_api_config & MRT_API_FLAGS_ALL)
986 mfcctl_size = sizeof(struct mfcctl2);
987
988 if (m == NULL || m->m_len < mfcctl_size)
989 return (EINVAL);
990
991 /*
992 * select data size depending on API version.
993 */
994 if (mrt_api_config & MRT_API_FLAGS_ALL) {
995 struct mfcctl2 *mp2 = mtod(m, struct mfcctl2 *);
996 memcpy((caddr_t)&mfcctl2, mp2, sizeof(*mp2));
997 } else {
998 struct mfcctl *mp = mtod(m, struct mfcctl *);
999 memcpy((caddr_t)&mfcctl2, mp, sizeof(*mp));
1000 memset((caddr_t)&mfcctl2 + sizeof(struct mfcctl), 0,
1001 sizeof(mfcctl2) - sizeof(struct mfcctl));
1002 }
1003
1004 if (mfc_add(&mfcctl2, &mfcctl2.mfcc_origin, &mfcctl2.mfcc_mcastgrp,
1005 mfcctl2.mfcc_parent, rtableid, M_WAITOK) == -1)
1006 return (EINVAL);
1007
1008 return (0);
1009 }
1010
1011 int
del_mfc(struct socket * so,struct mbuf * m)1012 del_mfc(struct socket *so, struct mbuf *m)
1013 {
1014 struct inpcb *inp = sotoinpcb(so);
1015 struct rtentry *rt;
1016 struct mfcctl2 mfcctl2;
1017 int mfcctl_size = sizeof(struct mfcctl);
1018 struct mfcctl *mp;
1019 unsigned int rtableid = inp->inp_rtableid;
1020
1021 NET_ASSERT_LOCKED();
1022
1023 /*
1024 * XXX: for deleting MFC entries the information in entries
1025 * of size "struct mfcctl" is sufficient.
1026 */
1027
1028 if (m == NULL || m->m_len < mfcctl_size)
1029 return (EINVAL);
1030
1031 mp = mtod(m, struct mfcctl *);
1032
1033 memcpy((caddr_t)&mfcctl2, mp, sizeof(*mp));
1034 memset((caddr_t)&mfcctl2 + sizeof(struct mfcctl), 0,
1035 sizeof(mfcctl2) - sizeof(struct mfcctl));
1036
1037 DPRINTF("origin %#08X group %#08X rtableid %d",
1038 mfcctl2.mfcc_origin.s_addr, mfcctl2.mfcc_mcastgrp.s_addr, rtableid);
1039
1040 while ((rt = mfc_find(NULL, &mfcctl2.mfcc_origin,
1041 &mfcctl2.mfcc_mcastgrp, rtableid)) != NULL) {
1042 mrt_mcast_del(rt, rtableid);
1043 rtfree(rt);
1044 }
1045
1046 return (0);
1047 }
1048
1049 int
socket_send(struct socket * so,struct mbuf * mm,struct sockaddr_in * src)1050 socket_send(struct socket *so, struct mbuf *mm, struct sockaddr_in *src)
1051 {
1052 if (so != NULL) {
1053 int ret;
1054
1055 mtx_enter(&so->so_rcv.sb_mtx);
1056 ret = sbappendaddr(so, &so->so_rcv, sintosa(src), mm, NULL);
1057 mtx_leave(&so->so_rcv.sb_mtx);
1058
1059 if (ret != 0) {
1060 sorwakeup(so);
1061 return (0);
1062 }
1063 }
1064 m_freem(mm);
1065 return (-1);
1066 }
1067
1068 /*
1069 * IP multicast forwarding function. This function assumes that the packet
1070 * pointed to by "ip" has arrived on (or is about to be sent to) the interface
1071 * pointed to by "ifp", and the packet is to be relayed to other networks
1072 * that have members of the packet's destination IP multicast group.
1073 *
1074 * The packet is returned unscathed to the caller, unless it is
1075 * erroneous, in which case a non-zero return value tells the caller to
1076 * discard it.
1077 */
1078
1079 #define IP_HDR_LEN 20 /* # bytes of fixed IP header (excluding options) */
1080 #define TUNNEL_LEN 12 /* # bytes of IP option for tunnel encapsulation */
1081
1082 int
ip_mforward(struct mbuf * m,struct ifnet * ifp,int flags)1083 ip_mforward(struct mbuf *m, struct ifnet *ifp, int flags)
1084 {
1085 struct ip *ip = mtod(m, struct ip *);
1086 struct vif *v;
1087 struct rtentry *rt;
1088 static int srctun = 0;
1089 struct mbuf *mm;
1090 unsigned int rtableid = ifp->if_rdomain;
1091
1092 if (ip->ip_hl < (IP_HDR_LEN + TUNNEL_LEN) >> 2 ||
1093 ((u_char *)(ip + 1))[1] != IPOPT_LSRR) {
1094 /*
1095 * Packet arrived via a physical interface or
1096 * an encapsulated tunnel or a register_vif.
1097 */
1098 } else {
1099 /*
1100 * Packet arrived through a source-route tunnel.
1101 * Source-route tunnels are no longer supported.
1102 */
1103 if ((srctun++ % 1000) == 0)
1104 log(LOG_ERR, "ip_mforward: received source-routed "
1105 "packet from %x\n", ntohl(ip->ip_src.s_addr));
1106 return (EOPNOTSUPP);
1107 }
1108
1109 /*
1110 * Don't forward a packet with time-to-live of zero or one,
1111 * or a packet destined to a local-only group.
1112 */
1113 if (ip->ip_ttl <= 1 || IN_LOCAL_GROUP(ip->ip_dst.s_addr))
1114 return (0);
1115
1116 /*
1117 * Determine forwarding vifs from the forwarding cache table
1118 */
1119 ++mrtstat.mrts_mfc_lookups;
1120 rt = mfc_find(NULL, &ip->ip_src, &ip->ip_dst, rtableid);
1121
1122 /* Entry exists, so forward if necessary */
1123 if (rt != NULL) {
1124 return (ip_mdq(m, ifp, rt, flags));
1125 } else {
1126 /*
1127 * If we don't have a route for packet's origin,
1128 * Make a copy of the packet & send message to routing daemon
1129 */
1130 int hlen = ip->ip_hl << 2;
1131
1132 ++mrtstat.mrts_mfc_misses;
1133 mrtstat.mrts_no_route++;
1134
1135 {
1136 struct igmpmsg *im;
1137
1138 /*
1139 * Locate the vifi for the incoming interface for
1140 * this packet.
1141 * If none found, drop packet.
1142 */
1143 if ((v = (struct vif *)ifp->if_mcast) == NULL)
1144 return (EHOSTUNREACH);
1145 /*
1146 * Make a copy of the header to send to the user level
1147 * process
1148 */
1149 mm = m_copym(m, 0, hlen, M_NOWAIT);
1150 if (mm == NULL ||
1151 (mm = m_pullup(mm, hlen)) == NULL)
1152 return (ENOBUFS);
1153
1154 /*
1155 * Send message to routing daemon to install
1156 * a route into the kernel table
1157 */
1158
1159 im = mtod(mm, struct igmpmsg *);
1160 im->im_msgtype = IGMPMSG_NOCACHE;
1161 im->im_mbz = 0;
1162 im->im_vif = v->v_id;
1163
1164 mrtstat.mrts_upcalls++;
1165
1166 sin.sin_addr = ip->ip_src;
1167 if (socket_send(ip_mrouter[rtableid], mm, &sin) < 0) {
1168 log(LOG_WARNING, "ip_mforward: ip_mrouter "
1169 "socket queue full\n");
1170 ++mrtstat.mrts_upq_sockfull;
1171 return (ENOBUFS);
1172 }
1173
1174 mfc_add(NULL, &ip->ip_src, &ip->ip_dst, v->v_id,
1175 rtableid, M_NOWAIT);
1176 }
1177
1178 return (0);
1179 }
1180 }
1181
1182 /*
1183 * Packet forwarding routine once entry in the cache is made
1184 */
1185 int
ip_mdq(struct mbuf * m,struct ifnet * ifp0,struct rtentry * rt,int flags)1186 ip_mdq(struct mbuf *m, struct ifnet *ifp0, struct rtentry *rt, int flags)
1187 {
1188 struct ip *ip = mtod(m, struct ip *);
1189 struct mfc *mfc = (struct mfc *)rt->rt_llinfo;
1190 struct vif *v = (struct vif *)ifp0->if_mcast;
1191 struct ifnet *ifp;
1192 struct mbuf *mc;
1193 struct ip_moptions imo;
1194
1195 /* Sanity check: we have all promised pointers. */
1196 if (v == NULL || mfc == NULL) {
1197 rtfree(rt);
1198 return (EHOSTUNREACH);
1199 }
1200
1201 /*
1202 * Don't forward if it didn't arrive from the parent vif for its origin.
1203 */
1204 if (mfc->mfc_parent != v->v_id) {
1205 /* came in the wrong interface */
1206 ++mrtstat.mrts_wrong_if;
1207 mfc->mfc_wrong_if++;
1208 rtfree(rt);
1209 return (0);
1210 }
1211
1212 /* If I sourced this packet, it counts as output, else it was input. */
1213 if (in_hosteq(ip->ip_src, v->v_lcl_addr)) {
1214 v->v_pkt_out++;
1215 v->v_bytes_out += m->m_pkthdr.len;
1216 } else {
1217 v->v_pkt_in++;
1218 v->v_bytes_in += m->m_pkthdr.len;
1219 }
1220
1221 /*
1222 * For each vif, decide if a copy of the packet should be forwarded.
1223 * Forward if:
1224 * - the ttl exceeds the vif's threshold
1225 * - there are group members downstream on interface
1226 */
1227 do {
1228 /* Don't consider non multicast routes. */
1229 if (ISSET(rt->rt_flags, RTF_HOST | RTF_MULTICAST) !=
1230 (RTF_HOST | RTF_MULTICAST))
1231 continue;
1232
1233 mfc = (struct mfc *)rt->rt_llinfo;
1234 if (mfc == NULL)
1235 continue;
1236
1237 mfc->mfc_pkt_cnt++;
1238 mfc->mfc_byte_cnt += m->m_pkthdr.len;
1239
1240 /* Don't let this route expire. */
1241 mfc->mfc_expire = 0;
1242
1243 if (ip->ip_ttl <= mfc->mfc_ttl)
1244 continue;
1245 if ((ifp = if_get(rt->rt_ifidx)) == NULL)
1246 continue;
1247
1248 /* Sanity check: did we configure this? */
1249 if ((v = (struct vif *)ifp->if_mcast) == NULL) {
1250 if_put(ifp);
1251 continue;
1252 }
1253
1254 /* Don't send in the upstream interface. */
1255 if (mfc->mfc_parent == v->v_id) {
1256 if_put(ifp);
1257 continue;
1258 }
1259
1260 v->v_pkt_out++;
1261 v->v_bytes_out += m->m_pkthdr.len;
1262
1263 /*
1264 * Make a new reference to the packet; make sure
1265 * that the IP header is actually copied, not
1266 * just referenced, so that ip_output() only
1267 * scribbles on the copy.
1268 */
1269 mc = m_dup_pkt(m, max_linkhdr, M_NOWAIT);
1270 if (mc == NULL) {
1271 if_put(ifp);
1272 rtfree(rt);
1273 return (ENOBUFS);
1274 }
1275
1276 /*
1277 * if physical interface option, extract the options
1278 * and then send
1279 */
1280 imo.imo_ifidx = rt->rt_ifidx;
1281 imo.imo_ttl = ip->ip_ttl - IPTTLDEC;
1282 imo.imo_loop = 1;
1283
1284 ip_output(mc, NULL, NULL, flags | IP_FORWARDING, &imo, NULL, 0);
1285 if_put(ifp);
1286 } while ((rt = rtable_iterate(rt)) != NULL);
1287
1288 return (0);
1289 }
1290
1291 struct ifnet *
if_lookupbyvif(vifi_t vifi,unsigned int rtableid)1292 if_lookupbyvif(vifi_t vifi, unsigned int rtableid)
1293 {
1294 struct vif *v;
1295 struct ifnet *ifp;
1296
1297 TAILQ_FOREACH(ifp, &ifnetlist, if_list) {
1298 if (ifp->if_rdomain != rtableid)
1299 continue;
1300 if ((v = (struct vif *)ifp->if_mcast) == NULL)
1301 continue;
1302 if (v->v_id != vifi)
1303 continue;
1304
1305 return (ifp);
1306 }
1307
1308 return (NULL);
1309 }
1310
1311 struct rtentry *
rt_mcast_add(struct ifnet * ifp,struct sockaddr * origin,struct sockaddr * group)1312 rt_mcast_add(struct ifnet *ifp, struct sockaddr *origin, struct sockaddr *group)
1313 {
1314 struct ifaddr *ifa;
1315 int rv;
1316 unsigned int rtableid = ifp->if_rdomain;
1317
1318 TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) {
1319 if (ifa->ifa_addr->sa_family == AF_INET)
1320 break;
1321 }
1322 if (ifa == NULL) {
1323 DPRINTF("ifa == NULL");
1324 return (NULL);
1325 }
1326
1327 rv = rt_ifa_add(ifa, RTF_HOST | RTF_MULTICAST | RTF_MPATH,
1328 group, ifp->if_rdomain);
1329 if (rv != 0) {
1330 DPRINTF("rt_ifa_add failed (%d)", rv);
1331 return (NULL);
1332 }
1333
1334 mrt_count[rtableid]++;
1335
1336 return (mfc_find(ifp, NULL, &satosin(group)->sin_addr, rtableid));
1337 }
1338
1339 void
mrt_mcast_del(struct rtentry * rt,unsigned int rtableid)1340 mrt_mcast_del(struct rtentry *rt, unsigned int rtableid)
1341 {
1342 struct ifnet *ifp;
1343 int error;
1344
1345 /* Remove all timers related to this route. */
1346 rt_timer_remove_all(rt);
1347
1348 free(rt->rt_llinfo, M_MRTABLE, sizeof(struct mfc));
1349 rt->rt_llinfo = NULL;
1350
1351 ifp = if_get(rt->rt_ifidx);
1352 if (ifp == NULL)
1353 return;
1354 error = rtdeletemsg(rt, ifp, rtableid);
1355 if_put(ifp);
1356
1357 if (error)
1358 DPRINTF("delete route error %d\n", error);
1359
1360 mrt_count[rtableid]--;
1361 }
1362