1 /* $OpenBSD: ip_mroute.c,v 1.137 2022/09/08 10:22:06 kn 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 *);
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 *
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
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
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
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 if (so != ip_mrouter[inp->inp_rtableid])
265 error = EINVAL;
266 else
267 switch (cmd) {
268 case SIOCGETVIFCNT:
269 NET_LOCK_SHARED();
270 error = get_vif_cnt(inp->inp_rtableid,
271 (struct sioc_vif_req *)data);
272 NET_UNLOCK_SHARED();
273 break;
274 case SIOCGETSGCNT:
275 NET_LOCK_SHARED();
276 error = get_sg_cnt(inp->inp_rtableid,
277 (struct sioc_sg_req *)data);
278 NET_UNLOCK_SHARED();
279 break;
280 default:
281 error = ENOTTY;
282 break;
283 }
284
285 return (error);
286 }
287
288 /*
289 * returns the packet, byte, rpf-failure count for the source group provided
290 */
291 int
292 get_sg_cnt(unsigned int rtableid, struct sioc_sg_req *req)
293 {
294 struct rtentry *rt;
295 struct mfc *mfc;
296
297 rt = mfc_find(NULL, &req->src, &req->grp, rtableid);
298 if (rt == NULL) {
299 req->pktcnt = req->bytecnt = req->wrong_if = 0xffffffff;
300 return (EADDRNOTAVAIL);
301 }
302
303 req->pktcnt = req->bytecnt = req->wrong_if = 0;
304 do {
305 /* Don't consider non multicast routes. */
306 if (ISSET(rt->rt_flags, RTF_HOST | RTF_MULTICAST) !=
307 (RTF_HOST | RTF_MULTICAST))
308 continue;
309
310 mfc = (struct mfc *)rt->rt_llinfo;
311 if (mfc == NULL)
312 continue;
313
314 req->pktcnt += mfc->mfc_pkt_cnt;
315 req->bytecnt += mfc->mfc_byte_cnt;
316 req->wrong_if += mfc->mfc_wrong_if;
317 } while ((rt = rtable_iterate(rt)) != NULL);
318
319 return (0);
320 }
321
322 /*
323 * returns the input and output packet and byte counts on the vif provided
324 */
325 int
326 get_vif_cnt(unsigned int rtableid, struct sioc_vif_req *req)
327 {
328 struct ifnet *ifp;
329 struct vif *v;
330 vifi_t vifi = req->vifi;
331
332 if ((ifp = if_lookupbyvif(vifi, rtableid)) == NULL)
333 return (EINVAL);
334
335 v = (struct vif *)ifp->if_mcast;
336 req->icount = v->v_pkt_in;
337 req->ocount = v->v_pkt_out;
338 req->ibytes = v->v_bytes_in;
339 req->obytes = v->v_bytes_out;
340
341 return (0);
342 }
343
344 int
345 mrt_sysctl_vif(void *oldp, size_t *oldlenp)
346 {
347 caddr_t where = oldp;
348 size_t needed, given;
349 struct ifnet *ifp;
350 struct vif *vifp;
351 struct vifinfo vinfo;
352
353 given = *oldlenp;
354 needed = 0;
355 memset(&vinfo, 0, sizeof vinfo);
356 TAILQ_FOREACH(ifp, &ifnetlist, if_list) {
357 if ((vifp = (struct vif *)ifp->if_mcast) == NULL)
358 continue;
359
360 vinfo.v_vifi = vifp->v_id;
361 vinfo.v_flags = vifp->v_flags;
362 vinfo.v_threshold = vifp->v_threshold;
363 vinfo.v_lcl_addr = vifp->v_lcl_addr;
364 vinfo.v_rmt_addr = vifp->v_rmt_addr;
365 vinfo.v_pkt_in = vifp->v_pkt_in;
366 vinfo.v_pkt_out = vifp->v_pkt_out;
367 vinfo.v_bytes_in = vifp->v_bytes_in;
368 vinfo.v_bytes_out = vifp->v_bytes_out;
369
370 needed += sizeof(vinfo);
371 if (where && needed <= given) {
372 int error;
373
374 error = copyout(&vinfo, where, sizeof(vinfo));
375 if (error)
376 return (error);
377 where += sizeof(vinfo);
378 }
379 }
380 if (where) {
381 *oldlenp = needed;
382 if (given < needed)
383 return (ENOMEM);
384 } else
385 *oldlenp = (11 * needed) / 10;
386
387 return (0);
388 }
389
390 struct mfcsysctlarg {
391 struct mfcinfo *msa_minfos;
392 size_t msa_len;
393 size_t msa_needed;
394 };
395
396 int
397 mrt_rtwalk_mfcsysctl(struct rtentry *rt, void *arg, unsigned int rtableid)
398 {
399 struct mfc *mfc = (struct mfc *)rt->rt_llinfo;
400 struct mfcsysctlarg *msa = (struct mfcsysctlarg *)arg;
401 struct ifnet *ifp;
402 struct vif *v;
403 struct mfcinfo *minfo;
404 int new = 0;
405
406 /* Skip entries being removed. */
407 if (mfc == NULL)
408 return (0);
409
410 /* Skip non-multicast routes. */
411 if (ISSET(rt->rt_flags, RTF_HOST | RTF_MULTICAST) !=
412 (RTF_HOST | RTF_MULTICAST))
413 return (0);
414
415 /* User just asked for the output size. */
416 if (msa->msa_minfos == NULL) {
417 msa->msa_needed += sizeof(*minfo);
418 return (0);
419 }
420
421 /* Skip route with invalid interfaces. */
422 if ((ifp = if_get(rt->rt_ifidx)) == NULL)
423 return (0);
424 if ((v = (struct vif *)ifp->if_mcast) == NULL) {
425 if_put(ifp);
426 return (0);
427 }
428
429 for (minfo = msa->msa_minfos;
430 (uint8_t *)minfo < ((uint8_t *)msa->msa_minfos + msa->msa_len);
431 minfo++) {
432 /* Find a new entry or update old entry. */
433 if (minfo->mfc_origin.s_addr !=
434 satosin(rt->rt_gateway)->sin_addr.s_addr ||
435 minfo->mfc_mcastgrp.s_addr !=
436 satosin(rt_key(rt))->sin_addr.s_addr) {
437 if (minfo->mfc_origin.s_addr != 0 ||
438 minfo->mfc_mcastgrp.s_addr != 0)
439 continue;
440
441 new = 1;
442 }
443
444 minfo->mfc_origin = satosin(rt->rt_gateway)->sin_addr;
445 minfo->mfc_mcastgrp = satosin(rt_key(rt))->sin_addr;
446 minfo->mfc_parent = mfc->mfc_parent;
447 minfo->mfc_pkt_cnt += mfc->mfc_pkt_cnt;
448 minfo->mfc_byte_cnt += mfc->mfc_byte_cnt;
449 minfo->mfc_ttls[v->v_id] = mfc->mfc_ttl;
450 break;
451 }
452
453 if (new != 0)
454 msa->msa_needed += sizeof(*minfo);
455
456 if_put(ifp);
457
458 return (0);
459 }
460
461 int
462 mrt_sysctl_mfc(void *oldp, size_t *oldlenp)
463 {
464 unsigned int rtableid;
465 int error;
466 struct mfcsysctlarg msa;
467
468 if (oldp != NULL && *oldlenp > MAXPHYS)
469 return (EINVAL);
470
471 if (oldp != NULL)
472 msa.msa_minfos = malloc(*oldlenp, M_TEMP, M_WAITOK | M_ZERO);
473 else
474 msa.msa_minfos = NULL;
475
476 msa.msa_len = *oldlenp;
477 msa.msa_needed = 0;
478
479 for (rtableid = 0; rtableid <= RT_TABLEID_MAX; rtableid++) {
480 rtable_walk(rtableid, AF_INET, NULL, mrt_rtwalk_mfcsysctl,
481 &msa);
482 }
483
484 if (msa.msa_minfos != NULL && msa.msa_needed > 0 &&
485 (error = copyout(msa.msa_minfos, oldp, msa.msa_needed)) != 0) {
486 free(msa.msa_minfos, M_TEMP, *oldlenp);
487 return (error);
488 }
489
490 free(msa.msa_minfos, M_TEMP, *oldlenp);
491 *oldlenp = msa.msa_needed;
492
493 return (0);
494 }
495
496 /*
497 * Enable multicast routing
498 */
499 int
500 ip_mrouter_init(struct socket *so, struct mbuf *m)
501 {
502 struct inpcb *inp = sotoinpcb(so);
503 unsigned int rtableid = inp->inp_rtableid;
504 int *v;
505
506 if (so->so_type != SOCK_RAW ||
507 so->so_proto->pr_protocol != IPPROTO_IGMP)
508 return (EOPNOTSUPP);
509
510 if (m == NULL || m->m_len < sizeof(int))
511 return (EINVAL);
512
513 v = mtod(m, int *);
514 if (*v != 1)
515 return (EINVAL);
516
517 if (ip_mrouter[rtableid] != NULL)
518 return (EADDRINUSE);
519
520 ip_mrouter[rtableid] = so;
521
522 return (0);
523 }
524
525 int
526 mrouter_rtwalk_delete(struct rtentry *rt, void *arg, unsigned int rtableid)
527 {
528 /* Skip non-multicast routes. */
529 if (ISSET(rt->rt_flags, RTF_HOST | RTF_MULTICAST) !=
530 (RTF_HOST | RTF_MULTICAST))
531 return (0);
532
533 return EEXIST;
534 }
535
536 /*
537 * Disable multicast routing
538 */
539 int
540 ip_mrouter_done(struct socket *so)
541 {
542 struct inpcb *inp = sotoinpcb(so);
543 struct ifnet *ifp;
544 unsigned int rtableid = inp->inp_rtableid;
545 int error;
546
547 NET_ASSERT_LOCKED();
548
549 /* Delete all remaining installed multicast routes. */
550 do {
551 struct rtentry *rt = NULL;
552
553 error = rtable_walk(rtableid, AF_INET, &rt,
554 mrouter_rtwalk_delete, NULL);
555 if (rt != NULL && error == EEXIST) {
556 mrt_mcast_del(rt, rtableid);
557 error = EAGAIN;
558 }
559 rtfree(rt);
560 } while (error == EAGAIN);
561
562 /* Unregister all interfaces in the domain. */
563 TAILQ_FOREACH(ifp, &ifnetlist, if_list) {
564 if (ifp->if_rdomain != rtableid)
565 continue;
566
567 vif_delete(ifp);
568 }
569
570 mrt_api_config = 0;
571
572 ip_mrouter[rtableid] = NULL;
573 mrt_count[rtableid] = 0;
574
575 return (0);
576 }
577
578 int
579 get_version(struct mbuf *m)
580 {
581 int *v = mtod(m, int *);
582
583 *v = 0x0305; /* XXX !!!! */
584 m->m_len = sizeof(int);
585 return (0);
586 }
587
588 /*
589 * Configure API capabilities
590 */
591 int
592 set_api_config(struct socket *so, struct mbuf *m)
593 {
594 struct inpcb *inp = sotoinpcb(so);
595 struct ifnet *ifp;
596 u_int32_t *apival;
597 unsigned int rtableid = inp->inp_rtableid;
598
599 if (m == NULL || m->m_len < sizeof(u_int32_t))
600 return (EINVAL);
601
602 apival = mtod(m, u_int32_t *);
603
604 /*
605 * We can set the API capabilities only if it is the first operation
606 * after MRT_INIT. I.e.:
607 * - there are no vifs installed
608 * - the MFC table is empty
609 */
610 TAILQ_FOREACH(ifp, &ifnetlist, if_list) {
611 if (ifp->if_rdomain != rtableid)
612 continue;
613 if (ifp->if_mcast == NULL)
614 continue;
615
616 *apival = 0;
617 return (EPERM);
618 }
619 if (mrt_count[rtableid] > 0) {
620 *apival = 0;
621 return (EPERM);
622 }
623
624 mrt_api_config = *apival & mrt_api_support;
625 *apival = mrt_api_config;
626
627 return (0);
628 }
629
630 /*
631 * Get API capabilities
632 */
633 int
634 get_api_support(struct mbuf *m)
635 {
636 u_int32_t *apival;
637
638 if (m == NULL || m->m_len < sizeof(u_int32_t))
639 return (EINVAL);
640
641 apival = mtod(m, u_int32_t *);
642
643 *apival = mrt_api_support;
644
645 return (0);
646 }
647
648 /*
649 * Get API configured capabilities
650 */
651 int
652 get_api_config(struct mbuf *m)
653 {
654 u_int32_t *apival;
655
656 if (m == NULL || m->m_len < sizeof(u_int32_t))
657 return (EINVAL);
658
659 apival = mtod(m, u_int32_t *);
660
661 *apival = mrt_api_config;
662
663 return (0);
664 }
665
666 static struct sockaddr_in sin = { sizeof(sin), AF_INET };
667
668 int
669 add_vif(struct socket *so, struct mbuf *m)
670 {
671 struct inpcb *inp = sotoinpcb(so);
672 struct vifctl *vifcp;
673 struct vif *vifp;
674 struct ifaddr *ifa;
675 struct ifnet *ifp;
676 struct ifreq ifr;
677 int error;
678 unsigned int rtableid = inp->inp_rtableid;
679
680 NET_ASSERT_LOCKED();
681
682 if (m == NULL || m->m_len < sizeof(struct vifctl))
683 return (EINVAL);
684
685 vifcp = mtod(m, struct vifctl *);
686 if (vifcp->vifc_vifi >= MAXVIFS)
687 return (EINVAL);
688 if (in_nullhost(vifcp->vifc_lcl_addr))
689 return (EADDRNOTAVAIL);
690 if (if_lookupbyvif(vifcp->vifc_vifi, rtableid) != NULL)
691 return (EADDRINUSE);
692
693 /* Tunnels are no longer supported use gif(4) instead. */
694 if (vifcp->vifc_flags & VIFF_TUNNEL)
695 return (EOPNOTSUPP);
696 {
697 sin.sin_addr = vifcp->vifc_lcl_addr;
698 ifa = ifa_ifwithaddr(sintosa(&sin), rtableid);
699 if (ifa == NULL)
700 return (EADDRNOTAVAIL);
701 }
702
703 /* Use the physical interface associated with the address. */
704 ifp = ifa->ifa_ifp;
705 if (ifp->if_mcast != NULL)
706 return (EADDRINUSE);
707
708 {
709 /* Make sure the interface supports multicast. */
710 if ((ifp->if_flags & IFF_MULTICAST) == 0)
711 return (EOPNOTSUPP);
712
713 /* Enable promiscuous reception of all IP multicasts. */
714 memset(&ifr, 0, sizeof(ifr));
715 satosin(&ifr.ifr_addr)->sin_len = sizeof(struct sockaddr_in);
716 satosin(&ifr.ifr_addr)->sin_family = AF_INET;
717 satosin(&ifr.ifr_addr)->sin_addr = zeroin_addr;
718 error = (*ifp->if_ioctl)(ifp, SIOCADDMULTI, (caddr_t)&ifr);
719 if (error)
720 return (error);
721 }
722
723 vifp = malloc(sizeof(*vifp), M_MRTABLE, M_WAITOK | M_ZERO);
724 ifp->if_mcast = (caddr_t)vifp;
725
726 vifp->v_id = vifcp->vifc_vifi;
727 vifp->v_flags = vifcp->vifc_flags;
728 vifp->v_threshold = vifcp->vifc_threshold;
729 vifp->v_lcl_addr = vifcp->vifc_lcl_addr;
730 vifp->v_rmt_addr = vifcp->vifc_rmt_addr;
731
732 return (0);
733 }
734
735 int
736 del_vif(struct socket *so, struct mbuf *m)
737 {
738 struct inpcb *inp = sotoinpcb(so);
739 struct ifnet *ifp;
740 vifi_t *vifip;
741 unsigned int rtableid = inp->inp_rtableid;
742
743 NET_ASSERT_LOCKED();
744
745 if (m == NULL || m->m_len < sizeof(vifi_t))
746 return (EINVAL);
747
748 vifip = mtod(m, vifi_t *);
749 if ((ifp = if_lookupbyvif(*vifip, rtableid)) == NULL)
750 return (EADDRNOTAVAIL);
751
752 vif_delete(ifp);
753 return (0);
754 }
755
756 void
757 vif_delete(struct ifnet *ifp)
758 {
759 struct vif *v;
760 struct ifreq ifr;
761
762 if ((v = (struct vif *)ifp->if_mcast) == NULL)
763 return;
764
765 ifp->if_mcast = NULL;
766
767 memset(&ifr, 0, sizeof(ifr));
768 satosin(&ifr.ifr_addr)->sin_len = sizeof(struct sockaddr_in);
769 satosin(&ifr.ifr_addr)->sin_family = AF_INET;
770 satosin(&ifr.ifr_addr)->sin_addr = zeroin_addr;
771 KERNEL_LOCK();
772 (*ifp->if_ioctl)(ifp, SIOCDELMULTI, (caddr_t)&ifr);
773 KERNEL_UNLOCK();
774
775 free(v, M_MRTABLE, sizeof(*v));
776 }
777
778 void
779 mfc_expire_route(struct rtentry *rt, u_int rtableid)
780 {
781 struct mfc *mfc = (struct mfc *)rt->rt_llinfo;
782
783 /* Skip entry being deleted. */
784 if (mfc == NULL)
785 return;
786
787 DPRINTF("Route domain %d origin %#08X group %#08x interface %d "
788 "expire %s", rtableid, satosin(rt->rt_gateway)->sin_addr.s_addr,
789 satosin(rt_key(rt))->sin_addr.s_addr,
790 rt->rt_ifidx, mfc->mfc_expire ? "yes" : "no");
791
792 /* Not expired, add it back to the queue. */
793 if (mfc->mfc_expire == 0) {
794 mfc->mfc_expire = 1;
795 rt_timer_add(rt, &ip_mrouterq, rtableid);
796 return;
797 }
798
799 mrt_mcast_del(rt, rtableid);
800 }
801
802 int
803 mfc_add_route(struct ifnet *ifp, struct sockaddr *origin,
804 struct sockaddr *group, struct mfcctl2 *mfccp, int wait)
805 {
806 struct vif *v = (struct vif *)ifp->if_mcast;
807 struct rtentry *rt;
808 struct mfc *mfc;
809 unsigned int rtableid = ifp->if_rdomain;
810
811 rt = rt_mcast_add(ifp, origin, group);
812 if (rt == NULL)
813 return (EHOSTUNREACH);
814
815 mfc = malloc(sizeof(*mfc), M_MRTABLE, wait | M_ZERO);
816 if (mfc == NULL) {
817 DPRINTF("origin %#08X group %#08X parent %d (%s) "
818 "malloc failed",
819 satosin(origin)->sin_addr.s_addr,
820 satosin(group)->sin_addr.s_addr,
821 mfccp->mfcc_parent, ifp->if_xname);
822 mrt_mcast_del(rt, rtableid);
823 rtfree(rt);
824 return (ENOMEM);
825 }
826
827 rt->rt_llinfo = (caddr_t)mfc;
828
829 rt_timer_add(rt, &ip_mrouterq, rtableid);
830
831 mfc->mfc_parent = mfccp->mfcc_parent;
832 mfc->mfc_pkt_cnt = 0;
833 mfc->mfc_byte_cnt = 0;
834 mfc->mfc_wrong_if = 0;
835 mfc->mfc_ttl = mfccp->mfcc_ttls[v->v_id];
836 mfc->mfc_flags = mfccp->mfcc_flags[v->v_id] & mrt_api_config &
837 MRT_MFC_FLAGS_ALL;
838 mfc->mfc_expire = 0;
839
840 /* set the RP address */
841 if (mrt_api_config & MRT_MFC_RP)
842 mfc->mfc_rp = mfccp->mfcc_rp;
843 else
844 mfc->mfc_rp = zeroin_addr;
845
846 rtfree(rt);
847
848 return (0);
849 }
850
851 void
852 update_mfc_params(struct mfcctl2 *mfccp, int wait, unsigned int rtableid)
853 {
854 struct rtentry *rt;
855 struct mfc *mfc;
856 struct ifnet *ifp;
857 int i;
858 struct sockaddr_in osin, msin;
859
860 memset(&osin, 0, sizeof(osin));
861 osin.sin_len = sizeof(osin);
862 osin.sin_family = AF_INET;
863 osin.sin_addr = mfccp->mfcc_origin;
864
865 memset(&msin, 0, sizeof(msin));
866 msin.sin_len = sizeof(msin);
867 msin.sin_family = AF_INET;
868 msin.sin_addr = mfccp->mfcc_mcastgrp;
869
870 for (i = 0; i < MAXVIFS; i++) {
871 /* Don't add/del upstream routes here. */
872 if (i == mfccp->mfcc_parent)
873 continue;
874
875 /* Test for vif existence and then update the entry. */
876 if ((ifp = if_lookupbyvif(i, rtableid)) == NULL)
877 continue;
878
879 rt = mfc_find(ifp, &mfccp->mfcc_origin,
880 &mfccp->mfcc_mcastgrp, rtableid);
881
882 /* vif not configured or removed. */
883 if (mfccp->mfcc_ttls[i] == 0) {
884 /* Route doesn't exist, nothing to do. */
885 if (rt == NULL)
886 continue;
887
888 DPRINTF("del route (group %#08X) for vif %d (%s)",
889 mfccp->mfcc_mcastgrp.s_addr, i, ifp->if_xname);
890 mrt_mcast_del(rt, rtableid);
891 rtfree(rt);
892 continue;
893 }
894
895 /* Route exists, look for changes. */
896 if (rt != NULL) {
897 mfc = (struct mfc *)rt->rt_llinfo;
898 /* Skip route being deleted. */
899 if (mfc == NULL) {
900 rtfree(rt);
901 continue;
902 }
903
904 /* No new changes to apply. */
905 if (mfccp->mfcc_ttls[i] == mfc->mfc_ttl &&
906 mfccp->mfcc_parent == mfc->mfc_parent) {
907 rtfree(rt);
908 continue;
909 }
910
911 DPRINTF("update route (group %#08X) for vif %d (%s)",
912 mfccp->mfcc_mcastgrp.s_addr, i, ifp->if_xname);
913 mfc->mfc_ttl = mfccp->mfcc_ttls[i];
914 mfc->mfc_parent = mfccp->mfcc_parent;
915 rtfree(rt);
916 continue;
917 }
918
919 DPRINTF("add route (group %#08X) for vif %d (%s)",
920 mfccp->mfcc_mcastgrp.s_addr, i, ifp->if_xname);
921
922 mfc_add_route(ifp, sintosa(&osin), sintosa(&msin),
923 mfccp, wait);
924 }
925
926 /* Create route for the parent interface. */
927 if ((ifp = if_lookupbyvif(mfccp->mfcc_parent, rtableid)) == NULL) {
928 DPRINTF("failed to find upstream interface %d",
929 mfccp->mfcc_parent);
930 return;
931 }
932
933 /* We already have a route, nothing to do here. */
934 if ((rt = mfc_find(ifp, &mfccp->mfcc_origin,
935 &mfccp->mfcc_mcastgrp, rtableid)) != NULL) {
936 rtfree(rt);
937 return;
938 }
939
940 DPRINTF("add upstream route (group %#08X) for if %s",
941 mfccp->mfcc_mcastgrp.s_addr, ifp->if_xname);
942 mfc_add_route(ifp, sintosa(&osin), sintosa(&msin), mfccp, wait);
943 }
944
945 int
946 mfc_add(struct mfcctl2 *mfcctl2, struct in_addr *origin,
947 struct in_addr *group, int vidx, unsigned int rtableid, int wait)
948 {
949 struct ifnet *ifp;
950 struct vif *v;
951 struct mfcctl2 mfcctl;
952
953 ifp = if_lookupbyvif(vidx, rtableid);
954 if (ifp == NULL ||
955 (v = (struct vif *)ifp->if_mcast) == NULL)
956 return (EHOSTUNREACH);
957
958 memset(&mfcctl, 0, sizeof(mfcctl));
959 if (mfcctl2 == NULL) {
960 mfcctl.mfcc_origin = *origin;
961 mfcctl.mfcc_mcastgrp = *group;
962 mfcctl.mfcc_parent = vidx;
963 } else
964 memcpy(&mfcctl, mfcctl2, sizeof(mfcctl));
965
966 update_mfc_params(&mfcctl, wait, rtableid);
967
968 return (0);
969 }
970
971 int
972 add_mfc(struct socket *so, struct mbuf *m)
973 {
974 struct inpcb *inp = sotoinpcb(so);
975 struct mfcctl2 mfcctl2;
976 int mfcctl_size = sizeof(struct mfcctl);
977 unsigned int rtableid = inp->inp_rtableid;
978
979 NET_ASSERT_LOCKED();
980
981 if (mrt_api_config & MRT_API_FLAGS_ALL)
982 mfcctl_size = sizeof(struct mfcctl2);
983
984 if (m == NULL || m->m_len < mfcctl_size)
985 return (EINVAL);
986
987 /*
988 * select data size depending on API version.
989 */
990 if (mrt_api_config & MRT_API_FLAGS_ALL) {
991 struct mfcctl2 *mp2 = mtod(m, struct mfcctl2 *);
992 memcpy((caddr_t)&mfcctl2, mp2, sizeof(*mp2));
993 } else {
994 struct mfcctl *mp = mtod(m, struct mfcctl *);
995 memcpy((caddr_t)&mfcctl2, mp, sizeof(*mp));
996 memset((caddr_t)&mfcctl2 + sizeof(struct mfcctl), 0,
997 sizeof(mfcctl2) - sizeof(struct mfcctl));
998 }
999
1000 if (mfc_add(&mfcctl2, &mfcctl2.mfcc_origin, &mfcctl2.mfcc_mcastgrp,
1001 mfcctl2.mfcc_parent, rtableid, M_WAITOK) == -1)
1002 return (EINVAL);
1003
1004 return (0);
1005 }
1006
1007 int
1008 del_mfc(struct socket *so, struct mbuf *m)
1009 {
1010 struct inpcb *inp = sotoinpcb(so);
1011 struct rtentry *rt;
1012 struct mfcctl2 mfcctl2;
1013 int mfcctl_size = sizeof(struct mfcctl);
1014 struct mfcctl *mp;
1015 unsigned int rtableid = inp->inp_rtableid;
1016
1017 NET_ASSERT_LOCKED();
1018
1019 /*
1020 * XXX: for deleting MFC entries the information in entries
1021 * of size "struct mfcctl" is sufficient.
1022 */
1023
1024 if (m == NULL || m->m_len < mfcctl_size)
1025 return (EINVAL);
1026
1027 mp = mtod(m, struct mfcctl *);
1028
1029 memcpy((caddr_t)&mfcctl2, mp, sizeof(*mp));
1030 memset((caddr_t)&mfcctl2 + sizeof(struct mfcctl), 0,
1031 sizeof(mfcctl2) - sizeof(struct mfcctl));
1032
1033 DPRINTF("origin %#08X group %#08X rtableid %d",
1034 mfcctl2.mfcc_origin.s_addr, mfcctl2.mfcc_mcastgrp.s_addr, rtableid);
1035
1036 while ((rt = mfc_find(NULL, &mfcctl2.mfcc_origin,
1037 &mfcctl2.mfcc_mcastgrp, rtableid)) != NULL) {
1038 mrt_mcast_del(rt, rtableid);
1039 rtfree(rt);
1040 }
1041
1042 return (0);
1043 }
1044
1045 int
1046 socket_send(struct socket *s, struct mbuf *mm, struct sockaddr_in *src)
1047 {
1048 if (s != NULL) {
1049 if (sbappendaddr(s, &s->so_rcv, sintosa(src), mm, NULL) != 0) {
1050 sorwakeup(s);
1051 return (0);
1052 }
1053 }
1054 m_freem(mm);
1055 return (-1);
1056 }
1057
1058 /*
1059 * IP multicast forwarding function. This function assumes that the packet
1060 * pointed to by "ip" has arrived on (or is about to be sent to) the interface
1061 * pointed to by "ifp", and the packet is to be relayed to other networks
1062 * that have members of the packet's destination IP multicast group.
1063 *
1064 * The packet is returned unscathed to the caller, unless it is
1065 * erroneous, in which case a non-zero return value tells the caller to
1066 * discard it.
1067 */
1068
1069 #define IP_HDR_LEN 20 /* # bytes of fixed IP header (excluding options) */
1070 #define TUNNEL_LEN 12 /* # bytes of IP option for tunnel encapsulation */
1071
1072 int
1073 ip_mforward(struct mbuf *m, struct ifnet *ifp)
1074 {
1075 struct ip *ip = mtod(m, struct ip *);
1076 struct vif *v;
1077 struct rtentry *rt;
1078 static int srctun = 0;
1079 struct mbuf *mm;
1080 unsigned int rtableid = ifp->if_rdomain;
1081
1082 if (ip->ip_hl < (IP_HDR_LEN + TUNNEL_LEN) >> 2 ||
1083 ((u_char *)(ip + 1))[1] != IPOPT_LSRR) {
1084 /*
1085 * Packet arrived via a physical interface or
1086 * an encapsulated tunnel or a register_vif.
1087 */
1088 } else {
1089 /*
1090 * Packet arrived through a source-route tunnel.
1091 * Source-route tunnels are no longer supported.
1092 */
1093 if ((srctun++ % 1000) == 0)
1094 log(LOG_ERR, "ip_mforward: received source-routed "
1095 "packet from %x\n", ntohl(ip->ip_src.s_addr));
1096 return (EOPNOTSUPP);
1097 }
1098
1099 /*
1100 * Don't forward a packet with time-to-live of zero or one,
1101 * or a packet destined to a local-only group.
1102 */
1103 if (ip->ip_ttl <= 1 || IN_LOCAL_GROUP(ip->ip_dst.s_addr))
1104 return (0);
1105
1106 /*
1107 * Determine forwarding vifs from the forwarding cache table
1108 */
1109 ++mrtstat.mrts_mfc_lookups;
1110 rt = mfc_find(NULL, &ip->ip_src, &ip->ip_dst, rtableid);
1111
1112 /* Entry exists, so forward if necessary */
1113 if (rt != NULL) {
1114 return (ip_mdq(m, ifp, rt));
1115 } else {
1116 /*
1117 * If we don't have a route for packet's origin,
1118 * Make a copy of the packet & send message to routing daemon
1119 */
1120 int hlen = ip->ip_hl << 2;
1121
1122 ++mrtstat.mrts_mfc_misses;
1123 mrtstat.mrts_no_route++;
1124
1125 {
1126 struct igmpmsg *im;
1127
1128 /*
1129 * Locate the vifi for the incoming interface for
1130 * this packet.
1131 * If none found, drop packet.
1132 */
1133 if ((v = (struct vif *)ifp->if_mcast) == NULL)
1134 return (EHOSTUNREACH);
1135 /*
1136 * Make a copy of the header to send to the user level
1137 * process
1138 */
1139 mm = m_copym(m, 0, hlen, M_NOWAIT);
1140 if (mm == NULL ||
1141 (mm = m_pullup(mm, hlen)) == NULL)
1142 return (ENOBUFS);
1143
1144 /*
1145 * Send message to routing daemon to install
1146 * a route into the kernel table
1147 */
1148
1149 im = mtod(mm, struct igmpmsg *);
1150 im->im_msgtype = IGMPMSG_NOCACHE;
1151 im->im_mbz = 0;
1152 im->im_vif = v->v_id;
1153
1154 mrtstat.mrts_upcalls++;
1155
1156 sin.sin_addr = ip->ip_src;
1157 if (socket_send(ip_mrouter[rtableid], mm, &sin) < 0) {
1158 log(LOG_WARNING, "ip_mforward: ip_mrouter "
1159 "socket queue full\n");
1160 ++mrtstat.mrts_upq_sockfull;
1161 return (ENOBUFS);
1162 }
1163
1164 mfc_add(NULL, &ip->ip_src, &ip->ip_dst, v->v_id,
1165 rtableid, M_NOWAIT);
1166 }
1167
1168 return (0);
1169 }
1170 }
1171
1172 /*
1173 * Packet forwarding routine once entry in the cache is made
1174 */
1175 int
1176 ip_mdq(struct mbuf *m, struct ifnet *ifp0, struct rtentry *rt)
1177 {
1178 struct ip *ip = mtod(m, struct ip *);
1179 struct mfc *mfc = (struct mfc *)rt->rt_llinfo;
1180 struct vif *v = (struct vif *)ifp0->if_mcast;
1181 struct ifnet *ifp;
1182 struct mbuf *mc;
1183 struct ip_moptions imo;
1184
1185 /* Sanity check: we have all promised pointers. */
1186 if (v == NULL || mfc == NULL) {
1187 rtfree(rt);
1188 return (EHOSTUNREACH);
1189 }
1190
1191 /*
1192 * Don't forward if it didn't arrive from the parent vif for its origin.
1193 */
1194 if (mfc->mfc_parent != v->v_id) {
1195 /* came in the wrong interface */
1196 ++mrtstat.mrts_wrong_if;
1197 mfc->mfc_wrong_if++;
1198 rtfree(rt);
1199 return (0);
1200 }
1201
1202 /* If I sourced this packet, it counts as output, else it was input. */
1203 if (in_hosteq(ip->ip_src, v->v_lcl_addr)) {
1204 v->v_pkt_out++;
1205 v->v_bytes_out += m->m_pkthdr.len;
1206 } else {
1207 v->v_pkt_in++;
1208 v->v_bytes_in += m->m_pkthdr.len;
1209 }
1210
1211 /*
1212 * For each vif, decide if a copy of the packet should be forwarded.
1213 * Forward if:
1214 * - the ttl exceeds the vif's threshold
1215 * - there are group members downstream on interface
1216 */
1217 do {
1218 /* Don't consider non multicast routes. */
1219 if (ISSET(rt->rt_flags, RTF_HOST | RTF_MULTICAST) !=
1220 (RTF_HOST | RTF_MULTICAST))
1221 continue;
1222
1223 mfc = (struct mfc *)rt->rt_llinfo;
1224 if (mfc == NULL)
1225 continue;
1226
1227 mfc->mfc_pkt_cnt++;
1228 mfc->mfc_byte_cnt += m->m_pkthdr.len;
1229
1230 /* Don't let this route expire. */
1231 mfc->mfc_expire = 0;
1232
1233 if (ip->ip_ttl <= mfc->mfc_ttl)
1234 continue;
1235 if ((ifp = if_get(rt->rt_ifidx)) == NULL)
1236 continue;
1237
1238 /* Sanity check: did we configure this? */
1239 if ((v = (struct vif *)ifp->if_mcast) == NULL) {
1240 if_put(ifp);
1241 continue;
1242 }
1243
1244 /* Don't send in the upstream interface. */
1245 if (mfc->mfc_parent == v->v_id) {
1246 if_put(ifp);
1247 continue;
1248 }
1249
1250 v->v_pkt_out++;
1251 v->v_bytes_out += m->m_pkthdr.len;
1252
1253 /*
1254 * Make a new reference to the packet; make sure
1255 * that the IP header is actually copied, not
1256 * just referenced, so that ip_output() only
1257 * scribbles on the copy.
1258 */
1259 mc = m_dup_pkt(m, max_linkhdr, M_NOWAIT);
1260 if (mc == NULL) {
1261 if_put(ifp);
1262 rtfree(rt);
1263 return (ENOBUFS);
1264 }
1265
1266 /*
1267 * if physical interface option, extract the options
1268 * and then send
1269 */
1270 imo.imo_ifidx = rt->rt_ifidx;
1271 imo.imo_ttl = ip->ip_ttl - IPTTLDEC;
1272 imo.imo_loop = 1;
1273
1274 ip_output(mc, NULL, NULL, IP_FORWARDING, &imo, NULL, 0);
1275 if_put(ifp);
1276 } while ((rt = rtable_iterate(rt)) != NULL);
1277
1278 return (0);
1279 }
1280
1281 struct ifnet *
1282 if_lookupbyvif(vifi_t vifi, unsigned int rtableid)
1283 {
1284 struct vif *v;
1285 struct ifnet *ifp;
1286
1287 TAILQ_FOREACH(ifp, &ifnetlist, if_list) {
1288 if (ifp->if_rdomain != rtableid)
1289 continue;
1290 if ((v = (struct vif *)ifp->if_mcast) == NULL)
1291 continue;
1292 if (v->v_id != vifi)
1293 continue;
1294
1295 return (ifp);
1296 }
1297
1298 return (NULL);
1299 }
1300
1301 struct rtentry *
1302 rt_mcast_add(struct ifnet *ifp, struct sockaddr *origin, struct sockaddr *group)
1303 {
1304 struct ifaddr *ifa;
1305 int rv;
1306 unsigned int rtableid = ifp->if_rdomain;
1307
1308 TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) {
1309 if (ifa->ifa_addr->sa_family == AF_INET)
1310 break;
1311 }
1312 if (ifa == NULL) {
1313 DPRINTF("ifa == NULL");
1314 return (NULL);
1315 }
1316
1317 rv = rt_ifa_add(ifa, RTF_HOST | RTF_MULTICAST | RTF_MPATH,
1318 group, ifp->if_rdomain);
1319 if (rv != 0) {
1320 DPRINTF("rt_ifa_add failed (%d)", rv);
1321 return (NULL);
1322 }
1323
1324 mrt_count[rtableid]++;
1325
1326 return (mfc_find(ifp, NULL, &satosin(group)->sin_addr, rtableid));
1327 }
1328
1329 void
1330 mrt_mcast_del(struct rtentry *rt, unsigned int rtableid)
1331 {
1332 struct ifnet *ifp;
1333 int error;
1334
1335 /* Remove all timers related to this route. */
1336 rt_timer_remove_all(rt);
1337
1338 free(rt->rt_llinfo, M_MRTABLE, sizeof(struct mfc));
1339 rt->rt_llinfo = NULL;
1340
1341 ifp = if_get(rt->rt_ifidx);
1342 if (ifp == NULL)
1343 return;
1344 error = rtdeletemsg(rt, ifp, rtableid);
1345 if_put(ifp);
1346
1347 if (error)
1348 DPRINTF("delete route error %d\n", error);
1349
1350 mrt_count[rtableid]--;
1351 }
Cache object: 77aa143c9dc41654eb2d5b4830e31142
|