Line data Source code
1 : /* $NetBSD: ip6_mroute.c,v 1.59 2003/12/10 09:28:38 itojun Exp $ */
2 : /* $KAME: ip6_mroute.c,v 1.45 2001/03/25 08:38:51 itojun Exp $ */
3 :
4 : /*
5 : * Copyright (C) 1998 WIDE Project.
6 : * All rights reserved.
7 : *
8 : * Redistribution and use in source and binary forms, with or without
9 : * modification, are permitted provided that the following conditions
10 : * are met:
11 : * 1. Redistributions of source code must retain the above copyright
12 : * notice, this list of conditions and the following disclaimer.
13 : * 2. Redistributions in binary form must reproduce the above copyright
14 : * notice, this list of conditions and the following disclaimer in the
15 : * documentation and/or other materials provided with the distribution.
16 : * 3. Neither the name of the project nor the names of its contributors
17 : * may be used to endorse or promote products derived from this software
18 : * without specific prior written permission.
19 : *
20 : * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
21 : * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 : * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 : * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
24 : * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 : * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 : * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 : * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 : * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 : * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 : * SUCH DAMAGE.
31 : */
32 :
33 : /* BSDI ip_mroute.c,v 2.10 1996/11/14 00:29:52 jch Exp */
34 :
35 : /*
36 : * Copyright (c) 1989 Stephen Deering
37 : * Copyright (c) 1992, 1993
38 : * The Regents of the University of California. All rights reserved.
39 : *
40 : * This code is derived from software contributed to Berkeley by
41 : * Stephen Deering of Stanford University.
42 : *
43 : * Redistribution and use in source and binary forms, with or without
44 : * modification, are permitted provided that the following conditions
45 : * are met:
46 : * 1. Redistributions of source code must retain the above copyright
47 : * notice, this list of conditions and the following disclaimer.
48 : * 2. Redistributions in binary form must reproduce the above copyright
49 : * notice, this list of conditions and the following disclaimer in the
50 : * documentation and/or other materials provided with the distribution.
51 : * 3. Neither the name of the University nor the names of its contributors
52 : * may be used to endorse or promote products derived from this software
53 : * without specific prior written permission.
54 : *
55 : * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
56 : * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
57 : * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
58 : * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
59 : * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
60 : * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
61 : * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
62 : * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
63 : * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
64 : * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
65 : * SUCH DAMAGE.
66 : *
67 : * @(#)ip_mroute.c 8.2 (Berkeley) 11/15/93
68 : */
69 :
70 : /*
71 : * IP multicast forwarding procedures
72 : *
73 : * Written by David Waitzman, BBN Labs, August 1988.
74 : * Modified by Steve Deering, Stanford, February 1989.
75 : * Modified by Mark J. Steiglitz, Stanford, May, 1991
76 : * Modified by Van Jacobson, LBL, January 1993
77 : * Modified by Ajit Thyagarajan, PARC, August 1993
78 : * Modified by Bill Fenner, PARC, April 1994
79 : *
80 : * MROUTING Revision: 3.5.1.2
81 : */
82 :
83 : #include <sys/param.h>
84 : #include <sys/malloc.h>
85 : #include <sys/systm.h>
86 : #include <sys/timeout.h>
87 : #include <sys/mbuf.h>
88 : #include <sys/socket.h>
89 : #include <sys/socketvar.h>
90 : #include <sys/protosw.h>
91 : #include <sys/kernel.h>
92 : #include <sys/ioctl.h>
93 : #include <sys/syslog.h>
94 : #include <sys/sysctl.h>
95 :
96 : #include <net/if.h>
97 : #include <net/if_var.h>
98 : #include <net/route.h>
99 :
100 : #include <netinet/in.h>
101 : #include <netinet6/in6_var.h>
102 : #include <netinet/ip.h>
103 : #include <netinet/ip6.h>
104 : #include <netinet/icmp6.h>
105 : #include <netinet6/ip6_var.h>
106 : #include <netinet6/ip6_mroute.h>
107 : #include <netinet/in_pcb.h>
108 :
109 : /* #define MCAST_DEBUG */
110 :
111 : #ifdef MCAST_DEBUG
112 : int mcast6_debug = 1;
113 : #define DPRINTF(fmt, args...) \
114 : do { \
115 : if (mcast6_debug) \
116 : printf("%s:%d " fmt "\n", \
117 : __func__, __LINE__, ## args); \
118 : } while (0)
119 : #else
120 : #define DPRINTF(fmt, args...) \
121 : do { } while (0)
122 : #endif
123 :
124 : int ip6_mdq(struct mbuf *, struct ifnet *, struct rtentry *);
125 : void phyint_send6(struct ifnet *, struct ip6_hdr *, struct mbuf *);
126 :
127 : /*
128 : * Globals. All but ip6_mrouter, ip6_mrtproto and mrt6stat could be static,
129 : * except for netstat or debugging purposes.
130 : */
131 : struct socket *ip6_mrouter[RT_TABLEID_MAX];
132 : struct rttimer_queue *mrouter6q[RT_TABLEID_MAX];
133 : int ip6_mrouter_ver = 0;
134 : int ip6_mrtproto; /* for netstat only */
135 : struct mrt6stat mrt6stat;
136 :
137 : #define NO_RTE_FOUND 0x1
138 : #define RTE_FOUND 0x2
139 :
140 : #define MCAST_EXPIRE_TIMEOUT 30 /* seconds */
141 :
142 : /*
143 : * Macros to compute elapsed time efficiently
144 : * Borrowed from Van Jacobson's scheduling code
145 : */
146 : #define TV_DELTA(a, b, delta) do { \
147 : int xxs; \
148 : \
149 : delta = (a).tv_usec - (b).tv_usec; \
150 : if ((xxs = (a).tv_sec - (b).tv_sec)) { \
151 : switch (xxs) { \
152 : case 2: \
153 : delta += 1000000; \
154 : /* FALLTHROUGH */ \
155 : case 1: \
156 : delta += 1000000; \
157 : break; \
158 : default: \
159 : delta += (1000000 * xxs); \
160 : } \
161 : } \
162 : } while (0)
163 :
164 : #define TV_LT(a, b) (((a).tv_usec < (b).tv_usec && \
165 : (a).tv_sec <= (b).tv_sec) || (a).tv_sec < (b).tv_sec)
166 :
167 : int get_sg6_cnt(struct sioc_sg_req6 *, unsigned int);
168 : int get_mif6_cnt(struct sioc_mif_req6 *, unsigned int);
169 : int ip6_mrouter_init(struct socket *, int, int);
170 : int add_m6if(struct socket *, struct mif6ctl *);
171 : int del_m6if(struct socket *, mifi_t *);
172 : int add_m6fc(struct socket *, struct mf6cctl *);
173 : int del_m6fc(struct socket *, struct mf6cctl *);
174 : struct ifnet *mrt6_iflookupbymif(mifi_t, unsigned int);
175 : struct rtentry *mf6c_find(struct ifnet *, struct in6_addr *,
176 : struct in6_addr *, unsigned int);
177 : struct rtentry *mrt6_mcast6_add(struct ifnet *, struct sockaddr *,
178 : struct sockaddr *);
179 : int mrt6_mcast6_del(struct rtentry *, unsigned int);
180 : void mf6c_expire_route(struct rtentry *, struct rttimer *);
181 :
182 : /*
183 : * Handle MRT setsockopt commands to modify the multicast routing tables.
184 : */
185 : int
186 0 : ip6_mrouter_set(int cmd, struct socket *so, struct mbuf *m)
187 : {
188 0 : struct inpcb *inp = sotoinpcb(so);
189 :
190 0 : if (cmd != MRT6_INIT && so != ip6_mrouter[inp->inp_rtableid])
191 0 : return (EPERM);
192 :
193 0 : switch (cmd) {
194 : case MRT6_INIT:
195 0 : if (m == NULL || m->m_len < sizeof(int))
196 0 : return (EINVAL);
197 0 : return (ip6_mrouter_init(so, *mtod(m, int *), cmd));
198 : case MRT6_DONE:
199 0 : return (ip6_mrouter_done(so));
200 : case MRT6_ADD_MIF:
201 0 : if (m == NULL || m->m_len < sizeof(struct mif6ctl))
202 0 : return (EINVAL);
203 0 : return (add_m6if(so, mtod(m, struct mif6ctl *)));
204 : case MRT6_DEL_MIF:
205 0 : if (m == NULL || m->m_len < sizeof(mifi_t))
206 0 : return (EINVAL);
207 0 : return (del_m6if(so, mtod(m, mifi_t *)));
208 : case MRT6_ADD_MFC:
209 0 : if (m == NULL || m->m_len < sizeof(struct mf6cctl))
210 0 : return (EINVAL);
211 0 : return (add_m6fc(so, mtod(m, struct mf6cctl *)));
212 : case MRT6_DEL_MFC:
213 0 : if (m == NULL || m->m_len < sizeof(struct mf6cctl))
214 0 : return (EINVAL);
215 0 : return (del_m6fc(so, mtod(m, struct mf6cctl *)));
216 : default:
217 0 : return (EOPNOTSUPP);
218 : }
219 0 : }
220 :
221 : /*
222 : * Handle MRT getsockopt commands
223 : */
224 : int
225 0 : ip6_mrouter_get(int cmd, struct socket *so, struct mbuf *m)
226 : {
227 0 : struct inpcb *inp = sotoinpcb(so);
228 :
229 0 : if (so != ip6_mrouter[inp->inp_rtableid])
230 0 : return (EPERM);
231 :
232 : switch (cmd) {
233 : default:
234 0 : return EOPNOTSUPP;
235 : }
236 0 : }
237 :
238 : /*
239 : * Handle ioctl commands to obtain information from the cache
240 : */
241 : int
242 0 : mrt6_ioctl(struct socket *so, u_long cmd, caddr_t data)
243 : {
244 0 : struct inpcb *inp = sotoinpcb(so);
245 : int error;
246 :
247 0 : switch (cmd) {
248 : case SIOCGETSGCNT_IN6:
249 0 : NET_RLOCK();
250 0 : error = get_sg6_cnt((struct sioc_sg_req6 *)data,
251 0 : inp->inp_rtableid);
252 0 : NET_RUNLOCK();
253 0 : break;
254 : case SIOCGETMIFCNT_IN6:
255 0 : NET_RLOCK();
256 0 : error = get_mif6_cnt((struct sioc_mif_req6 *)data,
257 0 : inp->inp_rtableid);
258 0 : NET_RUNLOCK();
259 0 : break;
260 : default:
261 : error = ENOTTY;
262 0 : break;
263 : }
264 0 : return error;
265 : }
266 :
267 : /*
268 : * returns the packet, byte, rpf-failure count for the source group provided
269 : */
270 : int
271 0 : get_sg6_cnt(struct sioc_sg_req6 *req, unsigned int rtableid)
272 : {
273 : struct rtentry *rt;
274 : struct mf6c *mf6c;
275 :
276 0 : rt = mf6c_find(NULL, &req->src.sin6_addr, &req->grp.sin6_addr,
277 : rtableid);
278 0 : if (rt == NULL) {
279 0 : req->pktcnt = req->bytecnt = req->wrong_if = 0xffffffff;
280 0 : return EADDRNOTAVAIL;
281 : }
282 :
283 0 : req->pktcnt = req->bytecnt = req->wrong_if = 0;
284 0 : do {
285 0 : mf6c = (struct mf6c *)rt->rt_llinfo;
286 0 : if (mf6c == NULL)
287 : continue;
288 :
289 0 : req->pktcnt += mf6c->mf6c_pkt_cnt;
290 0 : req->bytecnt += mf6c->mf6c_byte_cnt;
291 0 : req->wrong_if += mf6c->mf6c_wrong_if;
292 0 : } while ((rt = rtable_iterate(rt)) != NULL);
293 :
294 0 : return 0;
295 0 : }
296 :
297 : /*
298 : * returns the input and output packet and byte counts on the mif provided
299 : */
300 : int
301 0 : get_mif6_cnt(struct sioc_mif_req6 *req, unsigned int rtableid)
302 : {
303 : struct ifnet *ifp;
304 : struct mif6 *m6;
305 :
306 0 : if ((ifp = mrt6_iflookupbymif(req->mifi, rtableid)) == NULL)
307 0 : return EINVAL;
308 :
309 0 : m6 = (struct mif6 *)ifp->if_mcast6;
310 0 : req->icount = m6->m6_pkt_in;
311 0 : req->ocount = m6->m6_pkt_out;
312 0 : req->ibytes = m6->m6_bytes_in;
313 0 : req->obytes = m6->m6_bytes_out;
314 :
315 0 : return 0;
316 0 : }
317 :
318 : int
319 0 : mrt6_sysctl_mif(void *oldp, size_t *oldlenp)
320 : {
321 : struct ifnet *ifp;
322 : caddr_t where = oldp;
323 : size_t needed, given;
324 : struct mif6 *mifp;
325 0 : struct mif6info minfo;
326 :
327 0 : given = *oldlenp;
328 : needed = 0;
329 0 : TAILQ_FOREACH(ifp, &ifnet, if_list) {
330 0 : if ((mifp = (struct mif6 *)ifp->if_mcast6) == NULL)
331 : continue;
332 :
333 0 : minfo.m6_mifi = mifp->m6_mifi;
334 0 : minfo.m6_flags = mifp->m6_flags;
335 0 : minfo.m6_lcl_addr = mifp->m6_lcl_addr;
336 0 : minfo.m6_ifindex = ifp->if_index;
337 0 : minfo.m6_pkt_in = mifp->m6_pkt_in;
338 0 : minfo.m6_pkt_out = mifp->m6_pkt_out;
339 0 : minfo.m6_bytes_in = mifp->m6_bytes_in;
340 0 : minfo.m6_bytes_out = mifp->m6_bytes_out;
341 0 : minfo.m6_rate_limit = mifp->m6_rate_limit;
342 :
343 0 : needed += sizeof(minfo);
344 0 : if (where && needed <= given) {
345 : int error;
346 :
347 0 : error = copyout(&minfo, where, sizeof(minfo));
348 0 : if (error)
349 0 : return (error);
350 0 : where += sizeof(minfo);
351 0 : }
352 : }
353 0 : if (where) {
354 0 : *oldlenp = needed;
355 0 : if (given < needed)
356 0 : return (ENOMEM);
357 : } else
358 0 : *oldlenp = (11 * needed) / 10;
359 :
360 0 : return (0);
361 0 : }
362 :
363 : struct mf6csysctlarg {
364 : struct mf6cinfo *ms6a_minfos;
365 : size_t ms6a_len;
366 : size_t ms6a_needed;
367 : };
368 :
369 : int
370 0 : mrt6_rtwalk_mf6csysctl(struct rtentry *rt, void *arg, unsigned int rtableid)
371 : {
372 0 : struct mf6c *mf6c = (struct mf6c *)rt->rt_llinfo;
373 0 : struct mf6csysctlarg *msa = arg;
374 : struct ifnet *ifp;
375 : struct mif6 *m6;
376 : struct mf6cinfo *minfo;
377 : int new = 0;
378 :
379 : /* Skip entries being removed. */
380 0 : if (mf6c == NULL)
381 0 : return 0;
382 :
383 : /* Skip non-multicast routes. */
384 0 : if (ISSET(rt->rt_flags, RTF_HOST | RTF_MULTICAST) !=
385 : (RTF_HOST | RTF_MULTICAST))
386 0 : return 0;
387 :
388 : /* User just asked for the output size. */
389 0 : if (msa->ms6a_minfos == NULL) {
390 0 : msa->ms6a_needed += sizeof(*minfo);
391 0 : return 0;
392 : }
393 :
394 : /* Skip route with invalid interfaces. */
395 0 : if ((ifp = if_get(rt->rt_ifidx)) == NULL)
396 0 : return 0;
397 0 : if ((m6 = (struct mif6 *)ifp->if_mcast6) == NULL) {
398 0 : if_put(ifp);
399 0 : return 0;
400 : }
401 :
402 0 : for (minfo = msa->ms6a_minfos;
403 0 : (uint8_t *)minfo < ((uint8_t *)msa->ms6a_minfos + msa->ms6a_len);
404 0 : minfo++) {
405 : /* Find a new entry or update old entry. */
406 0 : if (!IN6_ARE_ADDR_EQUAL(&minfo->mf6c_origin.sin6_addr,
407 0 : &satosin6(rt->rt_gateway)->sin6_addr) ||
408 0 : !IN6_ARE_ADDR_EQUAL(&minfo->mf6c_mcastgrp.sin6_addr,
409 : &satosin6(rt_key(rt))->sin6_addr)) {
410 0 : if (!IN6_IS_ADDR_UNSPECIFIED(
411 0 : &minfo->mf6c_origin.sin6_addr) ||
412 0 : !IN6_IS_ADDR_UNSPECIFIED(
413 : &minfo->mf6c_mcastgrp.sin6_addr))
414 : continue;
415 :
416 : new = 1;
417 0 : }
418 :
419 0 : minfo->mf6c_origin = *satosin6(rt->rt_gateway);
420 0 : minfo->mf6c_mcastgrp = *satosin6(rt_key(rt));
421 0 : minfo->mf6c_parent = mf6c->mf6c_parent;
422 0 : minfo->mf6c_pkt_cnt += mf6c->mf6c_pkt_cnt;
423 0 : minfo->mf6c_byte_cnt += mf6c->mf6c_byte_cnt;
424 0 : IF_SET(m6->m6_mifi, &minfo->mf6c_ifset);
425 0 : break;
426 : }
427 :
428 0 : if (new != 0)
429 0 : msa->ms6a_needed += sizeof(*minfo);
430 :
431 0 : if_put(ifp);
432 :
433 0 : return 0;
434 0 : }
435 :
436 : int
437 0 : mrt6_sysctl_mfc(void *oldp, size_t *oldlenp)
438 : {
439 : unsigned int rtableid;
440 : int error;
441 0 : struct mf6csysctlarg msa;
442 :
443 0 : if (oldp != NULL && *oldlenp > MAXPHYS)
444 0 : return EINVAL;
445 :
446 0 : if (oldp != NULL)
447 0 : msa.ms6a_minfos = malloc(*oldlenp, M_TEMP, M_WAITOK | M_ZERO);
448 : else
449 0 : msa.ms6a_minfos = NULL;
450 :
451 0 : msa.ms6a_len = *oldlenp;
452 0 : msa.ms6a_needed = 0;
453 :
454 0 : for (rtableid = 0; rtableid < RT_TABLEID_MAX; rtableid++)
455 0 : rtable_walk(rtableid, AF_INET6, mrt6_rtwalk_mf6csysctl, &msa);
456 :
457 0 : if (msa.ms6a_minfos != NULL && msa.ms6a_needed > 0 &&
458 0 : (error = copyout(msa.ms6a_minfos, oldp, msa.ms6a_needed)) != 0) {
459 0 : free(msa.ms6a_minfos, M_TEMP, *oldlenp);
460 0 : return error;
461 : }
462 :
463 0 : free(msa.ms6a_minfos, M_TEMP, *oldlenp);
464 0 : *oldlenp = msa.ms6a_needed;
465 :
466 0 : return 0;
467 0 : }
468 :
469 : /*
470 : * Enable multicast routing
471 : */
472 : int
473 0 : ip6_mrouter_init(struct socket *so, int v, int cmd)
474 : {
475 0 : struct inpcb *inp = sotoinpcb(so);
476 0 : unsigned int rtableid = inp->inp_rtableid;
477 :
478 0 : if (so->so_type != SOCK_RAW ||
479 0 : so->so_proto->pr_protocol != IPPROTO_ICMPV6)
480 0 : return (EOPNOTSUPP);
481 :
482 0 : if (v != 1)
483 0 : return (ENOPROTOOPT);
484 :
485 0 : if (ip6_mrouter[rtableid] != NULL)
486 0 : return (EADDRINUSE);
487 :
488 0 : ip6_mrouter[rtableid] = so;
489 0 : ip6_mrouter_ver = cmd;
490 0 : mrouter6q[rtableid] = rt_timer_queue_create(MCAST_EXPIRE_TIMEOUT);
491 :
492 0 : return (0);
493 0 : }
494 :
495 : int
496 0 : mrouter6_rtwalk_delete(struct rtentry *rt, void *arg, unsigned int rtableid)
497 : {
498 : /* Skip non-multicast routes. */
499 0 : if (ISSET(rt->rt_flags, RTF_HOST | RTF_MULTICAST) !=
500 : (RTF_HOST | RTF_MULTICAST))
501 0 : return 0;
502 :
503 : /* Remove all timers related to this route. */
504 0 : rt_timer_remove_all(rt);
505 0 : mrt6_mcast6_del(rt, rtableid);
506 :
507 0 : return 0;
508 0 : }
509 :
510 : /*
511 : * Disable multicast routing
512 : */
513 : int
514 0 : ip6_mrouter_done(struct socket *so)
515 : {
516 0 : struct inpcb *inp = sotoinpcb(so);
517 : struct ifnet *ifp;
518 0 : unsigned int rtableid = inp->inp_rtableid;
519 :
520 0 : NET_ASSERT_LOCKED();
521 :
522 : /* Delete all remaining installed multicast routes. */
523 0 : rtable_walk(rtableid, AF_INET6, mrouter6_rtwalk_delete, NULL);
524 :
525 : /* Unregister all interfaces in the domain. */
526 0 : TAILQ_FOREACH(ifp, &ifnet, if_list) {
527 0 : if (ifp->if_rdomain != rtableid)
528 : continue;
529 :
530 0 : ip6_mrouter_detach(ifp);
531 0 : }
532 :
533 0 : rt_timer_queue_destroy(mrouter6q[rtableid]);
534 0 : ip6_mrouter[inp->inp_rtableid] = NULL;
535 0 : ip6_mrouter_ver = 0;
536 0 : mrouter6q[rtableid] = NULL;
537 :
538 0 : return 0;
539 : }
540 :
541 : void
542 0 : ip6_mrouter_detach(struct ifnet *ifp)
543 : {
544 0 : struct mif6 *m6 = (struct mif6 *)ifp->if_mcast6;
545 0 : struct in6_ifreq ifr;
546 :
547 0 : if (m6 == NULL)
548 0 : return;
549 :
550 0 : ifp->if_mcast6 = NULL;
551 :
552 0 : memset(&ifr, 0, sizeof(ifr));
553 0 : ifr.ifr_addr.sin6_family = AF_INET6;
554 0 : ifr.ifr_addr.sin6_addr = in6addr_any;
555 0 : (*ifp->if_ioctl)(ifp, SIOCDELMULTI, (caddr_t)&ifr);
556 :
557 0 : free(m6, M_MRTABLE, sizeof(*m6));
558 0 : }
559 :
560 : /*
561 : * Add a mif to the mif table
562 : */
563 : int
564 0 : add_m6if(struct socket *so, struct mif6ctl *mifcp)
565 : {
566 0 : struct inpcb *inp = sotoinpcb(so);
567 : struct mif6 *mifp;
568 : struct ifnet *ifp;
569 0 : struct in6_ifreq ifr;
570 : int error;
571 0 : unsigned int rtableid = inp->inp_rtableid;
572 :
573 0 : NET_ASSERT_LOCKED();
574 :
575 0 : if (mifcp->mif6c_mifi >= MAXMIFS)
576 0 : return EINVAL;
577 :
578 0 : if (mrt6_iflookupbymif(mifcp->mif6c_mifi, rtableid) != NULL)
579 0 : return EADDRINUSE; /* XXX: is it appropriate? */
580 :
581 : {
582 0 : ifp = if_get(mifcp->mif6c_pifi);
583 0 : if (ifp == NULL)
584 0 : return ENXIO;
585 :
586 : /* Make sure the interface supports multicast */
587 0 : if ((ifp->if_flags & IFF_MULTICAST) == 0) {
588 0 : if_put(ifp);
589 0 : return EOPNOTSUPP;
590 : }
591 :
592 : /*
593 : * Enable promiscuous reception of all IPv6 multicasts
594 : * from the interface.
595 : */
596 0 : memset(&ifr, 0, sizeof(ifr));
597 0 : ifr.ifr_addr.sin6_family = AF_INET6;
598 0 : ifr.ifr_addr.sin6_addr = in6addr_any;
599 0 : error = (*ifp->if_ioctl)(ifp, SIOCADDMULTI, (caddr_t)&ifr);
600 :
601 0 : if (error) {
602 0 : if_put(ifp);
603 0 : return error;
604 : }
605 : }
606 :
607 0 : mifp = malloc(sizeof(*mifp), M_MRTABLE, M_WAITOK | M_ZERO);
608 0 : ifp->if_mcast6 = (caddr_t)mifp;
609 0 : mifp->m6_mifi = mifcp->mif6c_mifi;
610 0 : mifp->m6_flags = mifcp->mif6c_flags;
611 : #ifdef notyet
612 : /* scaling up here allows division by 1024 in critical code */
613 : mifp->m6_rate_limit = mifcp->mif6c_rate_limit * 1024 / 1000;
614 : #endif
615 :
616 0 : if_put(ifp);
617 :
618 0 : return 0;
619 0 : }
620 :
621 : /*
622 : * Delete a mif from the mif table
623 : */
624 : int
625 0 : del_m6if(struct socket *so, mifi_t *mifip)
626 : {
627 0 : struct inpcb *inp = sotoinpcb(so);
628 : struct ifnet *ifp;
629 :
630 0 : NET_ASSERT_LOCKED();
631 :
632 0 : if (*mifip >= MAXMIFS)
633 0 : return EINVAL;
634 0 : if ((ifp = mrt6_iflookupbymif(*mifip, inp->inp_rtableid)) == NULL)
635 0 : return EINVAL;
636 :
637 0 : ip6_mrouter_detach(ifp);
638 :
639 0 : return 0;
640 0 : }
641 :
642 : int
643 0 : mf6c_add_route(struct ifnet *ifp, struct sockaddr *origin,
644 : struct sockaddr *group, struct mf6cctl *mf6cc, int wait)
645 : {
646 : struct rtentry *rt;
647 : struct mf6c *mf6c;
648 0 : unsigned int rtableid = ifp->if_rdomain;
649 : #ifdef MCAST_DEBUG
650 : char bsrc[INET6_ADDRSTRLEN], bdst[INET6_ADDRSTRLEN];
651 : #endif /* MCAST_DEBUG */
652 :
653 0 : rt = mrt6_mcast6_add(ifp, origin, group);
654 0 : if (rt == NULL)
655 0 : return ENOENT;
656 :
657 0 : mf6c = malloc(sizeof(*mf6c), M_MRTABLE, wait | M_ZERO);
658 0 : if (mf6c == NULL) {
659 : DPRINTF("origin %s group %s parent %d (%s) malloc failed",
660 : inet_ntop(AF_INET6, origin, bsrc, sizeof(bsrc)),
661 : inet_ntop(AF_INET6, group, bdst, sizeof(bdst)),
662 : mf6cc->mf6cc_parent, ifp->if_xname);
663 0 : mrt6_mcast6_del(rt, rtableid);
664 0 : return ENOMEM;
665 : }
666 :
667 0 : rt->rt_llinfo = (caddr_t)mf6c;
668 0 : rt_timer_add(rt, mf6c_expire_route, mrouter6q[rtableid], rtableid);
669 0 : mf6c->mf6c_parent = mf6cc->mf6cc_parent;
670 0 : rtfree(rt);
671 :
672 0 : return 0;
673 0 : }
674 :
675 : void
676 0 : mf6c_update(struct mf6cctl *mf6cc, int wait, unsigned int rtableid)
677 : {
678 : struct rtentry *rt;
679 : struct mf6c *mf6c;
680 : struct ifnet *ifp;
681 0 : struct sockaddr_in6 osin6, gsin6;
682 : mifi_t mifi;
683 : #ifdef MCAST_DEBUG
684 : char bdst[INET6_ADDRSTRLEN];
685 : #endif /* MCAST_DEBUG */
686 :
687 0 : memset(&osin6, 0, sizeof(osin6));
688 0 : osin6.sin6_family = AF_INET6;
689 0 : osin6.sin6_len = sizeof(osin6);
690 0 : osin6.sin6_addr = mf6cc->mf6cc_origin.sin6_addr;
691 :
692 0 : memset(&gsin6, 0, sizeof(gsin6));
693 0 : gsin6.sin6_family = AF_INET6;
694 0 : gsin6.sin6_len = sizeof(gsin6);
695 0 : gsin6.sin6_addr = mf6cc->mf6cc_mcastgrp.sin6_addr;
696 :
697 0 : for (mifi = 0; mifi < MAXMIFS; mifi++) {
698 0 : if (mifi == mf6cc->mf6cc_parent)
699 : continue;
700 :
701 : /* Test for mif existence and then update the entry. */
702 0 : if ((ifp = mrt6_iflookupbymif(mifi, rtableid)) == NULL)
703 : continue;
704 :
705 0 : rt = mf6c_find(ifp, &mf6cc->mf6cc_origin.sin6_addr,
706 : &mf6cc->mf6cc_mcastgrp.sin6_addr, rtableid);
707 :
708 : /* mif not configured or removed. */
709 0 : if (!IF_ISSET(mifi, &mf6cc->mf6cc_ifset)) {
710 : /* Route doesn't exist, nothing to do. */
711 0 : if (rt == NULL)
712 : continue;
713 :
714 : DPRINTF("del route (group %s) for mif %d (%s)",
715 : inet_ntop(AF_INET6,
716 : &mf6cc->mf6cc_mcastgrp.sin6_addr, bdst,
717 : sizeof(bdst)), mifi, ifp->if_xname);
718 :
719 0 : rt_timer_remove_all(rt);
720 0 : mrt6_mcast6_del(rt, rtableid);
721 0 : continue;
722 : }
723 :
724 : /* Route exists, look for changes. */
725 0 : if (rt != NULL) {
726 0 : mf6c = (struct mf6c *)rt->rt_llinfo;
727 : /* Skip route being deleted. */
728 0 : if (mf6c == NULL) {
729 0 : rtfree(rt);
730 0 : continue;
731 : }
732 :
733 : /* No new changes to apply. */
734 0 : if (mf6cc->mf6cc_parent == mf6c->mf6c_parent) {
735 0 : rtfree(rt);
736 0 : continue;
737 : }
738 :
739 : DPRINTF("update route (group %s) for mif %d (%s)",
740 : inet_ntop(AF_INET6,
741 : &mf6cc->mf6cc_mcastgrp.sin6_addr, bdst,
742 : sizeof(bdst)), mifi, ifp->if_xname);
743 :
744 0 : mf6c->mf6c_parent = mf6cc->mf6cc_parent;
745 0 : rtfree(rt);
746 0 : continue;
747 : }
748 :
749 : DPRINTF("add route (group %s) for mif %d (%s)",
750 : inet_ntop(AF_INET6, &mf6cc->mf6cc_mcastgrp.sin6_addr,
751 : bdst, sizeof(bdst)), mifi, ifp->if_xname);
752 :
753 0 : mf6c_add_route(ifp, sin6tosa(&osin6), sin6tosa(&gsin6),
754 : mf6cc, wait);
755 0 : }
756 :
757 : /* Create route for the parent interface. */
758 0 : if ((ifp = mrt6_iflookupbymif(mf6cc->mf6cc_parent,
759 0 : rtableid)) == NULL) {
760 : DPRINTF("failed to find upstream interface %d",
761 : mf6cc->mf6cc_parent);
762 0 : return;
763 : }
764 :
765 : /* We already have a route, nothing to do here. */
766 0 : if ((rt = mf6c_find(ifp, &mf6cc->mf6cc_origin.sin6_addr,
767 0 : &mf6cc->mf6cc_mcastgrp.sin6_addr, rtableid)) != NULL) {
768 0 : rtfree(rt);
769 0 : return;
770 : }
771 :
772 : DPRINTF("add upstream route (group %s) for if %s",
773 : inet_ntop(AF_INET6, &mf6cc->mf6cc_mcastgrp.sin6_addr,
774 : bdst, sizeof(bdst)), ifp->if_xname);
775 0 : mf6c_add_route(ifp, sin6tosa(&osin6), sin6tosa(&gsin6), mf6cc, wait);
776 0 : }
777 :
778 : int
779 0 : mf6c_add(struct mf6cctl *mfccp, struct in6_addr *origin,
780 : struct in6_addr *group, int vidx, unsigned int rtableid, int wait)
781 : {
782 : struct ifnet *ifp;
783 : struct mif6 *m6;
784 0 : struct mf6cctl mf6cc;
785 :
786 0 : ifp = mrt6_iflookupbymif(vidx, rtableid);
787 0 : if (ifp == NULL ||
788 0 : (m6 = (struct mif6 *)ifp->if_mcast6) == NULL)
789 0 : return ENOENT;
790 :
791 0 : memset(&mf6cc, 0, sizeof(mf6cc));
792 0 : if (mfccp == NULL) {
793 0 : mf6cc.mf6cc_origin.sin6_family = AF_INET6;
794 0 : mf6cc.mf6cc_origin.sin6_len = sizeof(mf6cc.mf6cc_origin);
795 0 : mf6cc.mf6cc_origin.sin6_addr = *origin;
796 0 : mf6cc.mf6cc_mcastgrp.sin6_family = AF_INET6;
797 0 : mf6cc.mf6cc_mcastgrp.sin6_len = sizeof(mf6cc.mf6cc_mcastgrp);
798 0 : mf6cc.mf6cc_mcastgrp.sin6_addr = *group;
799 0 : mf6cc.mf6cc_parent = vidx;
800 0 : } else
801 0 : memcpy(&mf6cc, mfccp, sizeof(mf6cc));
802 :
803 0 : mf6c_update(&mf6cc, wait, rtableid);
804 :
805 0 : return 0;
806 0 : }
807 :
808 : int
809 0 : add_m6fc(struct socket *so, struct mf6cctl *mfccp)
810 : {
811 0 : struct inpcb *inp = sotoinpcb(so);
812 0 : unsigned int rtableid = inp->inp_rtableid;
813 :
814 0 : NET_ASSERT_LOCKED();
815 :
816 0 : return mf6c_add(mfccp, &mfccp->mf6cc_origin.sin6_addr,
817 0 : &mfccp->mf6cc_mcastgrp.sin6_addr, mfccp->mf6cc_parent,
818 : rtableid, M_WAITOK);
819 : }
820 :
821 : int
822 0 : del_m6fc(struct socket *so, struct mf6cctl *mfccp)
823 : {
824 0 : struct inpcb *inp = sotoinpcb(so);
825 : struct rtentry *rt;
826 0 : unsigned int rtableid = inp->inp_rtableid;
827 :
828 0 : NET_ASSERT_LOCKED();
829 :
830 0 : while ((rt = mf6c_find(NULL, &mfccp->mf6cc_origin.sin6_addr,
831 0 : &mfccp->mf6cc_mcastgrp.sin6_addr, rtableid)) != NULL) {
832 : /* Remove all timers related to this route. */
833 0 : rt_timer_remove_all(rt);
834 0 : mrt6_mcast6_del(rt, rtableid);
835 : }
836 :
837 0 : return 0;
838 : }
839 :
840 : int
841 0 : socket6_send(struct socket *s, struct mbuf *mm, struct sockaddr_in6 *src)
842 : {
843 0 : if (s) {
844 0 : if (sbappendaddr(s, &s->so_rcv, sin6tosa(src), mm, NULL) != 0) {
845 0 : sorwakeup(s);
846 0 : return 0;
847 : }
848 : }
849 0 : m_freem(mm);
850 0 : return -1;
851 0 : }
852 :
853 : /*
854 : * IPv6 multicast forwarding function. This function assumes that the packet
855 : * pointed to by "ip6" has arrived on (or is about to be sent to) the interface
856 : * pointed to by "ifp", and the packet is to be relayed to other networks
857 : * that have members of the packet's destination IPv6 multicast group.
858 : *
859 : * The packet is returned unscathed to the caller, unless it is
860 : * erroneous, in which case a non-zero return value tells the caller to
861 : * discard it.
862 : */
863 : int
864 0 : ip6_mforward(struct ip6_hdr *ip6, struct ifnet *ifp, struct mbuf *m)
865 : {
866 : struct rtentry *rt;
867 : struct mif6 *mifp;
868 : struct mbuf *mm;
869 0 : struct sockaddr_in6 sin6;
870 0 : unsigned int rtableid = ifp->if_rdomain;
871 :
872 0 : NET_ASSERT_LOCKED();
873 :
874 : /*
875 : * Don't forward a packet with Hop limit of zero or one,
876 : * or a packet destined to a local-only group.
877 : */
878 0 : if (ip6->ip6_hlim <= 1 || IN6_IS_ADDR_MC_INTFACELOCAL(&ip6->ip6_dst) ||
879 0 : IN6_IS_ADDR_MC_LINKLOCAL(&ip6->ip6_dst))
880 0 : return 0;
881 0 : ip6->ip6_hlim--;
882 :
883 : /*
884 : * Source address check: do not forward packets with unspecified
885 : * source. It was discussed in July 2000, on ipngwg mailing list.
886 : * This is rather more serious than unicast cases, because some
887 : * MLD packets can be sent with the unspecified source address
888 : * (although such packets must normally set 1 to the hop limit field).
889 : */
890 0 : if (IN6_IS_ADDR_UNSPECIFIED(&ip6->ip6_src)) {
891 0 : ip6stat_inc(ip6s_cantforward);
892 0 : if (ip6_log_time + ip6_log_interval < time_uptime) {
893 0 : char src[INET6_ADDRSTRLEN], dst[INET6_ADDRSTRLEN];
894 :
895 0 : ip6_log_time = time_uptime;
896 :
897 0 : inet_ntop(AF_INET6, &ip6->ip6_src, src, sizeof(src));
898 0 : inet_ntop(AF_INET6, &ip6->ip6_dst, dst, sizeof(dst));
899 0 : log(LOG_DEBUG, "cannot forward "
900 : "from %s to %s nxt %d received on interface %u\n",
901 0 : src, dst, ip6->ip6_nxt, m->m_pkthdr.ph_ifidx);
902 0 : }
903 0 : return 0;
904 : }
905 :
906 : /*
907 : * Determine forwarding mifs from the forwarding cache table
908 : */
909 0 : rt = mf6c_find(NULL, &ip6->ip6_src, &ip6->ip6_dst, rtableid);
910 :
911 : /* Entry exists, so forward if necessary */
912 0 : if (rt) {
913 0 : return (ip6_mdq(m, ifp, rt));
914 : } else {
915 : /*
916 : * If we don't have a route for packet's origin,
917 : * Make a copy of the packet &
918 : * send message to routing daemon
919 : */
920 :
921 0 : mrt6stat.mrt6s_no_route++;
922 :
923 : {
924 : struct mrt6msg *im;
925 :
926 0 : if ((mifp = (struct mif6 *)ifp->if_mcast6) == NULL)
927 0 : return EHOSTUNREACH;
928 :
929 : /*
930 : * Make a copy of the header to send to the user
931 : * level process
932 : */
933 0 : mm = m_copym(m, 0, sizeof(struct ip6_hdr), M_NOWAIT);
934 0 : if (mm == NULL)
935 0 : return ENOBUFS;
936 :
937 : /*
938 : * Send message to routing daemon
939 : */
940 0 : (void)memset(&sin6, 0, sizeof(sin6));
941 0 : sin6.sin6_len = sizeof(sin6);
942 0 : sin6.sin6_family = AF_INET6;
943 0 : sin6.sin6_addr = ip6->ip6_src;
944 :
945 : im = NULL;
946 0 : switch (ip6_mrouter_ver) {
947 : case MRT6_INIT:
948 0 : im = mtod(mm, struct mrt6msg *);
949 0 : im->im6_msgtype = MRT6MSG_NOCACHE;
950 0 : im->im6_mbz = 0;
951 0 : im->im6_mif = mifp->m6_mifi;
952 : break;
953 : default:
954 0 : m_freem(mm);
955 0 : return EINVAL;
956 : }
957 :
958 0 : if (socket6_send(ip6_mrouter[rtableid], mm,
959 0 : &sin6) < 0) {
960 0 : log(LOG_WARNING, "ip6_mforward: ip6_mrouter "
961 : "socket queue full\n");
962 0 : mrt6stat.mrt6s_upq_sockfull++;
963 0 : return ENOBUFS;
964 : }
965 :
966 0 : mrt6stat.mrt6s_upcalls++;
967 :
968 0 : mf6c_add(NULL, &ip6->ip6_src, &ip6->ip6_dst,
969 0 : mifp->m6_mifi, rtableid, M_NOWAIT);
970 0 : }
971 :
972 0 : return 0;
973 : }
974 0 : }
975 :
976 : void
977 0 : mf6c_expire_route(struct rtentry *rt, struct rttimer *rtt)
978 : {
979 0 : struct mf6c *mf6c = (struct mf6c *)rt->rt_llinfo;
980 0 : unsigned int rtableid = rtt->rtt_tableid;
981 : #ifdef MCAST_DEBUG
982 : char bsrc[INET6_ADDRSTRLEN], bdst[INET6_ADDRSTRLEN];
983 : #endif /* MCAST_DEBUG */
984 :
985 : /* Skip entry being deleted. */
986 0 : if (mf6c == NULL)
987 0 : return;
988 :
989 : DPRINTF("origin %s group %s interface %d expire %s",
990 : inet_ntop(AF_INET6, &satosin6(rt->rt_gateway)->sin6_addr,
991 : bsrc, sizeof(bsrc)),
992 : inet_ntop(AF_INET6, &satosin6(rt_key(rt))->sin6_addr,
993 : bdst, sizeof(bdst)), rt->rt_ifidx,
994 : mf6c->mf6c_expire ? "yes" : "no");
995 :
996 0 : if (mf6c->mf6c_expire == 0) {
997 0 : mf6c->mf6c_expire = 1;
998 0 : rt_timer_add(rt, mf6c_expire_route, mrouter6q[rtableid],
999 : rtableid);
1000 0 : return;
1001 : }
1002 :
1003 0 : rt_timer_remove_all(rt);
1004 0 : mrt6_mcast6_del(rt, rtableid);
1005 0 : }
1006 :
1007 : /*
1008 : * Packet forwarding routine once entry in the cache is made
1009 : */
1010 : int
1011 0 : ip6_mdq(struct mbuf *m, struct ifnet *ifp, struct rtentry *rt)
1012 : {
1013 0 : struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
1014 0 : struct mif6 *m6, *mifp = (struct mif6 *)ifp->if_mcast6;
1015 0 : struct mf6c *mf6c = (struct mf6c *)rt->rt_llinfo;
1016 : struct ifnet *ifn;
1017 0 : int plen = m->m_pkthdr.len;
1018 :
1019 0 : if (mifp == NULL || mf6c == NULL) {
1020 0 : rtfree(rt);
1021 0 : return EHOSTUNREACH;
1022 : }
1023 :
1024 : /*
1025 : * Don't forward if it didn't arrive from the parent mif
1026 : * for its origin.
1027 : */
1028 0 : if (mifp->m6_mifi != mf6c->mf6c_parent) {
1029 : /* came in the wrong interface */
1030 0 : mrt6stat.mrt6s_wrong_if++;
1031 0 : mf6c->mf6c_wrong_if++;
1032 0 : rtfree(rt);
1033 0 : return 0;
1034 : } /* if wrong iif */
1035 :
1036 : /* If I sourced this packet, it counts as output, else it was input. */
1037 0 : if (m->m_pkthdr.ph_ifidx == 0) {
1038 : /* XXX: is ph_ifidx really 0 when output?? */
1039 0 : mifp->m6_pkt_out++;
1040 0 : mifp->m6_bytes_out += plen;
1041 0 : } else {
1042 0 : mifp->m6_pkt_in++;
1043 0 : mifp->m6_bytes_in += plen;
1044 : }
1045 :
1046 : /*
1047 : * For each mif, forward a copy of the packet if there are group
1048 : * members downstream on the interface.
1049 : */
1050 0 : do {
1051 : /* Don't consider non multicast routes. */
1052 0 : if (ISSET(rt->rt_flags, RTF_HOST | RTF_MULTICAST) !=
1053 : (RTF_HOST | RTF_MULTICAST))
1054 : continue;
1055 :
1056 0 : mf6c = (struct mf6c *)rt->rt_llinfo;
1057 0 : if (mf6c == NULL)
1058 : continue;
1059 :
1060 0 : mf6c->mf6c_pkt_cnt++;
1061 0 : mf6c->mf6c_byte_cnt += m->m_pkthdr.len;
1062 :
1063 : /* Don't let this route expire. */
1064 0 : mf6c->mf6c_expire = 0;
1065 :
1066 0 : if ((ifn = if_get(rt->rt_ifidx)) == NULL)
1067 : continue;
1068 :
1069 : /* Sanity check: did we configure this? */
1070 0 : if ((m6 = (struct mif6 *)ifn->if_mcast6) == NULL) {
1071 0 : if_put(ifn);
1072 0 : continue;
1073 : }
1074 :
1075 : /* Don't send in the upstream interface. */
1076 0 : if (mf6c->mf6c_parent == m6->m6_mifi) {
1077 0 : if_put(ifn);
1078 0 : continue;
1079 : }
1080 :
1081 : /*
1082 : * check if the outgoing packet is going to break
1083 : * a scope boundary.
1084 : */
1085 0 : if ((mifp->m6_flags & MIFF_REGISTER) == 0 &&
1086 0 : (m6->m6_flags & MIFF_REGISTER) == 0 &&
1087 0 : (in6_addr2scopeid(ifp->if_index, &ip6->ip6_dst) !=
1088 0 : in6_addr2scopeid(ifn->if_index, &ip6->ip6_dst) ||
1089 0 : in6_addr2scopeid(ifp->if_index, &ip6->ip6_src) !=
1090 0 : in6_addr2scopeid(ifn->if_index, &ip6->ip6_src))) {
1091 0 : if_put(ifn);
1092 0 : ip6stat_inc(ip6s_badscope);
1093 0 : continue;
1094 : }
1095 :
1096 0 : m6->m6_pkt_out++;
1097 0 : m6->m6_bytes_out += plen;
1098 :
1099 0 : phyint_send6(ifn, ip6, m);
1100 0 : if_put(ifn);
1101 0 : } while ((rt = rtable_iterate(rt)) != NULL);
1102 :
1103 0 : return 0;
1104 0 : }
1105 :
1106 : void
1107 0 : phyint_send6(struct ifnet *ifp, struct ip6_hdr *ip6, struct mbuf *m)
1108 : {
1109 : struct mbuf *mb_copy;
1110 0 : struct sockaddr_in6 *dst6, sin6;
1111 : int error = 0;
1112 :
1113 0 : NET_ASSERT_LOCKED();
1114 :
1115 : /*
1116 : * Make a new reference to the packet; make sure that
1117 : * the IPv6 header is actually copied, not just referenced,
1118 : * so that ip6_output() only scribbles on the copy.
1119 : */
1120 0 : mb_copy = m_dup_pkt(m, max_linkhdr, M_NOWAIT);
1121 0 : if (mb_copy == NULL)
1122 0 : return;
1123 : /* set MCAST flag to the outgoing packet */
1124 0 : mb_copy->m_flags |= M_MCAST;
1125 :
1126 : /*
1127 : * If we sourced the packet, call ip6_output since we may devide
1128 : * the packet into fragments when the packet is too big for the
1129 : * outgoing interface.
1130 : * Otherwise, we can simply send the packet to the interface
1131 : * sending queue.
1132 : */
1133 0 : if (m->m_pkthdr.ph_ifidx == 0) {
1134 0 : struct ip6_moptions im6o;
1135 :
1136 0 : im6o.im6o_ifidx = ifp->if_index;
1137 : /* XXX: ip6_output will override ip6->ip6_hlim */
1138 0 : im6o.im6o_hlim = ip6->ip6_hlim;
1139 0 : im6o.im6o_loop = 1;
1140 0 : error = ip6_output(mb_copy, NULL, NULL, IPV6_FORWARDING, &im6o,
1141 : NULL);
1142 : return;
1143 0 : }
1144 :
1145 : /*
1146 : * If we belong to the destination multicast group
1147 : * on the outgoing interface, loop back a copy.
1148 : */
1149 : dst6 = &sin6;
1150 0 : memset(&sin6, 0, sizeof(sin6));
1151 0 : if (in6_hasmulti(&ip6->ip6_dst, ifp)) {
1152 0 : dst6->sin6_len = sizeof(struct sockaddr_in6);
1153 0 : dst6->sin6_family = AF_INET6;
1154 0 : dst6->sin6_addr = ip6->ip6_dst;
1155 0 : ip6_mloopback(ifp, m, dst6);
1156 0 : }
1157 : /*
1158 : * Put the packet into the sending queue of the outgoing interface
1159 : * if it would fit in the MTU of the interface.
1160 : */
1161 0 : if (mb_copy->m_pkthdr.len <= ifp->if_mtu || ifp->if_mtu < IPV6_MMTU) {
1162 0 : dst6->sin6_len = sizeof(struct sockaddr_in6);
1163 0 : dst6->sin6_family = AF_INET6;
1164 0 : dst6->sin6_addr = ip6->ip6_dst;
1165 0 : error = ifp->if_output(ifp, mb_copy, sin6tosa(dst6), NULL);
1166 0 : } else {
1167 0 : if (ip6_mcast_pmtu)
1168 0 : icmp6_error(mb_copy, ICMP6_PACKET_TOO_BIG, 0,
1169 : ifp->if_mtu);
1170 : else {
1171 0 : m_freem(mb_copy); /* simply discard the packet */
1172 : }
1173 : }
1174 0 : }
1175 :
1176 : struct ifnet *
1177 0 : mrt6_iflookupbymif(mifi_t mifi, unsigned int rtableid)
1178 : {
1179 : struct mif6 *m6;
1180 : struct ifnet *ifp;
1181 :
1182 0 : TAILQ_FOREACH(ifp, &ifnet, if_list) {
1183 0 : if (ifp->if_rdomain != rtableid)
1184 : continue;
1185 0 : if ((m6 = (struct mif6 *)ifp->if_mcast6) == NULL)
1186 : continue;
1187 0 : if (m6->m6_mifi != mifi)
1188 : continue;
1189 :
1190 0 : return ifp;
1191 : }
1192 :
1193 0 : return NULL;
1194 0 : }
1195 :
1196 : struct rtentry *
1197 0 : mf6c_find(struct ifnet *ifp, struct in6_addr *origin, struct in6_addr *group,
1198 : unsigned int rtableid)
1199 : {
1200 : struct rtentry *rt;
1201 0 : struct sockaddr_in6 msin6;
1202 :
1203 0 : memset(&msin6, 0, sizeof(msin6));
1204 0 : msin6.sin6_family = AF_INET6;
1205 0 : msin6.sin6_len = sizeof(msin6);
1206 0 : msin6.sin6_addr = *group;
1207 :
1208 0 : rt = rtalloc(sin6tosa(&msin6), 0, rtableid);
1209 0 : do {
1210 0 : if (!rtisvalid(rt)) {
1211 0 : rtfree(rt);
1212 0 : return NULL;
1213 : }
1214 0 : if (ISSET(rt->rt_flags, RTF_HOST | RTF_MULTICAST) !=
1215 : (RTF_HOST | RTF_MULTICAST))
1216 : continue;
1217 : /* Return first occurrence if interface is not specified. */
1218 0 : if (ifp == NULL)
1219 0 : return rt;
1220 0 : if (rt->rt_ifidx == ifp->if_index)
1221 0 : return rt;
1222 0 : } while ((rt = rtable_iterate(rt)) != NULL);
1223 :
1224 0 : return NULL;
1225 0 : }
1226 :
1227 : struct rtentry *
1228 0 : mrt6_mcast6_add(struct ifnet *ifp, struct sockaddr *origin,
1229 : struct sockaddr *group)
1230 : {
1231 : struct ifaddr *ifa;
1232 : int rv;
1233 0 : unsigned int rtableid = ifp->if_rdomain;
1234 :
1235 0 : TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) {
1236 0 : if (ifa->ifa_addr->sa_family == AF_INET6)
1237 : break;
1238 : }
1239 0 : if (ifa == NULL) {
1240 : DPRINTF("ifa == NULL");
1241 0 : return NULL;
1242 : }
1243 :
1244 0 : rv = rt_ifa_add(ifa, RTF_HOST | RTF_MULTICAST, group);
1245 0 : if (rv != 0) {
1246 : DPRINTF("rt_ifa_add failed %d", rv);
1247 0 : return NULL;
1248 : }
1249 :
1250 0 : return mf6c_find(ifp, NULL, &satosin6(group)->sin6_addr, rtableid);
1251 0 : }
1252 :
1253 : int
1254 0 : mrt6_mcast6_del(struct rtentry *rt, unsigned int rtableid)
1255 : {
1256 : struct ifnet *ifp;
1257 : int rv;
1258 :
1259 0 : free(rt->rt_llinfo, M_MRTABLE, sizeof(struct mf6c));
1260 0 : rt->rt_llinfo = NULL;
1261 :
1262 0 : if ((ifp = if_get(rt->rt_ifidx)) == NULL) {
1263 : DPRINTF("if_get(%d) failed", rt->rt_ifidx);
1264 0 : rtfree(rt);
1265 0 : return ENOENT;
1266 : }
1267 :
1268 0 : rv = rtdeletemsg(rt, ifp, rtableid);
1269 0 : if_put(ifp);
1270 0 : if (rv != 0) {
1271 : DPRINTF("rtdeletemsg failed %d", rv);
1272 0 : rtfree(rt);
1273 0 : return rv;
1274 : }
1275 :
1276 0 : return 0;
1277 0 : }
|