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