Annotation of sys/netinet6/ip6_mroute.c, Revision 1.1.1.1
1.1 nbrk 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 + PIM-SMv2 (pimd) Support
81: */
82:
83: #ifndef _KERNEL
84: # ifdef KERNEL
85: # define _KERNEL
86: # endif
87: #endif
88:
89: #include <sys/param.h>
90: #include <sys/systm.h>
91: #include <sys/timeout.h>
92: #include <sys/mbuf.h>
93: #include <sys/socket.h>
94: #include <sys/socketvar.h>
95: #include <sys/sockio.h>
96: #include <sys/protosw.h>
97: #include <sys/errno.h>
98: #include <sys/time.h>
99: #include <sys/kernel.h>
100: #include <sys/ioctl.h>
101: #include <sys/syslog.h>
102:
103: #include <net/if.h>
104: #include <net/route.h>
105: #include <net/raw_cb.h>
106:
107: #include <netinet/in.h>
108: #include <netinet/in_var.h>
109: #include <netinet/icmp6.h>
110:
111: #include <netinet/ip6.h>
112: #include <netinet6/ip6_var.h>
113: #include <netinet6/ip6_mroute.h>
114: #include <netinet6/pim6.h>
115: #include <netinet6/pim6_var.h>
116: #include <netinet6/nd6.h>
117:
118: static int ip6_mdq(struct mbuf *, struct ifnet *, struct mf6c *);
119: static void phyint_send(struct ip6_hdr *, struct mif6 *, struct mbuf *);
120:
121: static int set_pim6(int *);
122: static int get_pim6(struct mbuf *);
123: static int socket_send(struct socket *, struct mbuf *,
124: struct sockaddr_in6 *);
125: static int register_send(struct ip6_hdr *, struct mif6 *,
126: struct mbuf *);
127:
128: /*
129: * Globals. All but ip6_mrouter, ip6_mrtproto and mrt6stat could be static,
130: * except for netstat or debugging purposes.
131: */
132: struct socket *ip6_mrouter = NULL;
133: int ip6_mrouter_ver = 0;
134: int ip6_mrtproto = IPPROTO_PIM; /* for netstat only */
135: struct mrt6stat mrt6stat;
136:
137: #define NO_RTE_FOUND 0x1
138: #define RTE_FOUND 0x2
139:
140: struct mf6c *mf6ctable[MF6CTBLSIZ];
141: u_char n6expire[MF6CTBLSIZ];
142: struct mif6 mif6table[MAXMIFS];
143: #ifdef MRT6DEBUG
144: u_int mrt6debug = 0; /* debug level */
145: #define DEBUG_MFC 0x02
146: #define DEBUG_FORWARD 0x04
147: #define DEBUG_EXPIRE 0x08
148: #define DEBUG_XMIT 0x10
149: #define DEBUG_REG 0x20
150: #define DEBUG_PIM 0x40
151: #endif
152:
153: static void expire_upcalls(void *);
154: #define EXPIRE_TIMEOUT (hz / 4) /* 4x / second */
155: #define UPCALL_EXPIRE 6 /* number of timeouts */
156:
157: #ifdef INET
158: #ifdef MROUTING
159: extern struct socket *ip_mrouter;
160: #endif
161: #endif
162:
163: /*
164: * 'Interfaces' associated with decapsulator (so we can tell
165: * packets that went through it from ones that get reflected
166: * by a broken gateway). These interfaces are never linked into
167: * the system ifnet list & no routes point to them. I.e., packets
168: * can't be sent this way. They only exist as a placeholder for
169: * multicast source verification.
170: */
171: struct ifnet multicast_register_if;
172:
173: #define ENCAP_HOPS 64
174:
175: /*
176: * Private variables.
177: */
178: static mifi_t nummifs = 0;
179: static mifi_t reg_mif_num = (mifi_t)-1;
180:
181: struct pim6stat pim6stat;
182: static int pim6;
183:
184: /*
185: * Hash function for a source, group entry
186: */
187: #define MF6CHASH(a, g) MF6CHASHMOD((a).s6_addr32[0] ^ (a).s6_addr32[1] ^ \
188: (a).s6_addr32[2] ^ (a).s6_addr32[3] ^ \
189: (g).s6_addr32[0] ^ (g).s6_addr32[1] ^ \
190: (g).s6_addr32[2] ^ (g).s6_addr32[3])
191:
192: /*
193: * Find a route for a given origin IPv6 address and Multicast group address.
194: * Quality of service parameter to be added in the future!!!
195: */
196:
197: #define MF6CFIND(o, g, rt) do { \
198: struct mf6c *_rt = mf6ctable[MF6CHASH(o,g)]; \
199: rt = NULL; \
200: mrt6stat.mrt6s_mfc_lookups++; \
201: while (_rt) { \
202: if (IN6_ARE_ADDR_EQUAL(&_rt->mf6c_origin.sin6_addr, &(o)) && \
203: IN6_ARE_ADDR_EQUAL(&_rt->mf6c_mcastgrp.sin6_addr, &(g)) && \
204: (_rt->mf6c_stall == NULL)) { \
205: rt = _rt; \
206: break; \
207: } \
208: _rt = _rt->mf6c_next; \
209: } \
210: if (rt == NULL) { \
211: mrt6stat.mrt6s_mfc_misses++; \
212: } \
213: } while (0)
214:
215: /*
216: * Macros to compute elapsed time efficiently
217: * Borrowed from Van Jacobson's scheduling code
218: */
219: #define TV_DELTA(a, b, delta) do { \
220: int xxs; \
221: \
222: delta = (a).tv_usec - (b).tv_usec; \
223: if ((xxs = (a).tv_sec - (b).tv_sec)) { \
224: switch (xxs) { \
225: case 2: \
226: delta += 1000000; \
227: /* FALLTHROUGH */ \
228: case 1: \
229: delta += 1000000; \
230: break; \
231: default: \
232: delta += (1000000 * xxs); \
233: } \
234: } \
235: } while (0)
236:
237: #define TV_LT(a, b) (((a).tv_usec < (b).tv_usec && \
238: (a).tv_sec <= (b).tv_sec) || (a).tv_sec < (b).tv_sec)
239:
240: #ifdef UPCALL_TIMING
241: #define UPCALL_MAX 50
242: u_long upcall_data[UPCALL_MAX + 1];
243: static void collate();
244: #endif /* UPCALL_TIMING */
245:
246: static int get_sg_cnt(struct sioc_sg_req6 *);
247: static int get_mif6_cnt(struct sioc_mif_req6 *);
248: static int ip6_mrouter_init(struct socket *, int, int);
249: static int add_m6if(struct mif6ctl *);
250: static int del_m6if(mifi_t *);
251: static int add_m6fc(struct mf6cctl *);
252: static int del_m6fc(struct mf6cctl *);
253:
254: static struct timeout expire_upcalls_ch;
255:
256: /*
257: * Handle MRT setsockopt commands to modify the multicast routing tables.
258: */
259: int
260: ip6_mrouter_set(cmd, so, m)
261: int cmd;
262: struct socket *so;
263: struct mbuf *m;
264: {
265: if (cmd != MRT6_INIT && so != ip6_mrouter)
266: return (EACCES);
267:
268: switch (cmd) {
269: #ifdef MRT6_OINIT
270: case MRT6_OINIT:
271: #endif
272: case MRT6_INIT:
273: if (m == NULL || m->m_len < sizeof(int))
274: return (EINVAL);
275: return (ip6_mrouter_init(so, *mtod(m, int *), cmd));
276: case MRT6_DONE:
277: return (ip6_mrouter_done());
278: case MRT6_ADD_MIF:
279: if (m == NULL || m->m_len < sizeof(struct mif6ctl))
280: return (EINVAL);
281: return (add_m6if(mtod(m, struct mif6ctl *)));
282: case MRT6_DEL_MIF:
283: if (m == NULL || m->m_len < sizeof(mifi_t))
284: return (EINVAL);
285: return (del_m6if(mtod(m, mifi_t *)));
286: case MRT6_ADD_MFC:
287: if (m == NULL || m->m_len < sizeof(struct mf6cctl))
288: return (EINVAL);
289: return (add_m6fc(mtod(m, struct mf6cctl *)));
290: case MRT6_DEL_MFC:
291: if (m == NULL || m->m_len < sizeof(struct mf6cctl))
292: return (EINVAL);
293: return (del_m6fc(mtod(m, struct mf6cctl *)));
294: case MRT6_PIM:
295: if (m == NULL || m->m_len < sizeof(int))
296: return (EINVAL);
297: return (set_pim6(mtod(m, int *)));
298: default:
299: return (EOPNOTSUPP);
300: }
301: }
302:
303: /*
304: * Handle MRT getsockopt commands
305: */
306: int
307: ip6_mrouter_get(cmd, so, m)
308: int cmd;
309: struct socket *so;
310: struct mbuf **m;
311: {
312: struct mbuf *mb;
313:
314: if (so != ip6_mrouter) return EACCES;
315:
316: *m = mb = m_get(M_WAIT, MT_SOOPTS);
317:
318: switch (cmd) {
319: case MRT6_PIM:
320: return get_pim6(mb);
321: default:
322: m_free(mb);
323: return EOPNOTSUPP;
324: }
325: }
326:
327: /*
328: * Handle ioctl commands to obtain information from the cache
329: */
330: int
331: mrt6_ioctl(cmd, data)
332: int cmd;
333: caddr_t data;
334: {
335:
336: switch (cmd) {
337: case SIOCGETSGCNT_IN6:
338: return (get_sg_cnt((struct sioc_sg_req6 *)data));
339: case SIOCGETMIFCNT_IN6:
340: return (get_mif6_cnt((struct sioc_mif_req6 *)data));
341: default:
342: return (EINVAL);
343: }
344: }
345:
346: /*
347: * returns the packet, byte, rpf-failure count for the source group provided
348: */
349: static int
350: get_sg_cnt(req)
351: struct sioc_sg_req6 *req;
352: {
353: struct mf6c *rt;
354: int s;
355:
356: s = splsoftnet();
357:
358: MF6CFIND(req->src.sin6_addr, req->grp.sin6_addr, rt);
359: splx(s);
360: if (rt != NULL) {
361: req->pktcnt = rt->mf6c_pkt_cnt;
362: req->bytecnt = rt->mf6c_byte_cnt;
363: req->wrong_if = rt->mf6c_wrong_if;
364: } else
365: return (ESRCH);
366: #if 0
367: req->pktcnt = req->bytecnt = req->wrong_if = 0xffffffff;
368: #endif
369:
370: return 0;
371: }
372:
373: /*
374: * returns the input and output packet and byte counts on the mif provided
375: */
376: static int
377: get_mif6_cnt(req)
378: struct sioc_mif_req6 *req;
379: {
380: mifi_t mifi = req->mifi;
381:
382: if (mifi >= nummifs)
383: return EINVAL;
384:
385: req->icount = mif6table[mifi].m6_pkt_in;
386: req->ocount = mif6table[mifi].m6_pkt_out;
387: req->ibytes = mif6table[mifi].m6_bytes_in;
388: req->obytes = mif6table[mifi].m6_bytes_out;
389:
390: return 0;
391: }
392:
393: /*
394: * Get PIM processiong global
395: */
396: static int
397: get_pim6(m)
398: struct mbuf *m;
399: {
400: int *i;
401:
402: i = mtod(m, int *);
403:
404: *i = pim6;
405:
406: return 0;
407: }
408:
409: static int
410: set_pim6(i)
411: int *i;
412: {
413: if ((*i != 1) && (*i != 0))
414: return EINVAL;
415:
416: pim6 = *i;
417:
418: return 0;
419: }
420:
421: /*
422: * Enable multicast routing
423: */
424: static int
425: ip6_mrouter_init(so, v, cmd)
426: struct socket *so;
427: int v;
428: int cmd;
429: {
430: #ifdef MRT6DEBUG
431: if (mrt6debug)
432: log(LOG_DEBUG,
433: "ip6_mrouter_init: so_type = %d, pr_protocol = %d\n",
434: so->so_type, so->so_proto->pr_protocol);
435: #endif
436:
437: if (so->so_type != SOCK_RAW ||
438: so->so_proto->pr_protocol != IPPROTO_ICMPV6)
439: return (EOPNOTSUPP);
440:
441: if (v != 1)
442: return (ENOPROTOOPT);
443:
444: if (ip6_mrouter != NULL)
445: return (EADDRINUSE);
446:
447: ip6_mrouter = so;
448: ip6_mrouter_ver = cmd;
449:
450: bzero((caddr_t)mf6ctable, sizeof(mf6ctable));
451: bzero((caddr_t)n6expire, sizeof(n6expire));
452:
453: pim6 = 0;/* used for stubbing out/in pim stuff */
454:
455: timeout_set(&expire_upcalls_ch, expire_upcalls, NULL);
456: timeout_add(&expire_upcalls_ch, EXPIRE_TIMEOUT);
457:
458: #ifdef MRT6DEBUG
459: if (mrt6debug)
460: log(LOG_DEBUG, "ip6_mrouter_init\n");
461: #endif
462:
463: return 0;
464: }
465:
466: /*
467: * Disable multicast routing
468: */
469: int
470: ip6_mrouter_done()
471: {
472: mifi_t mifi;
473: int i;
474: struct ifnet *ifp;
475: struct in6_ifreq ifr;
476: struct mf6c *rt;
477: struct rtdetq *rte;
478: int s;
479:
480: s = splsoftnet();
481:
482: /*
483: * For each phyint in use, disable promiscuous reception of all IPv6
484: * multicasts.
485: */
486: #ifdef INET
487: #ifdef MROUTING
488: /*
489: * If there is still IPv4 multicast routing daemon,
490: * we remain interfaces to receive all muliticasted packets.
491: * XXX: there may be an interface in which the IPv4 multicast
492: * daemon is not interested...
493: */
494: if (!ip_mrouter)
495: #endif
496: #endif
497: {
498: for (mifi = 0; mifi < nummifs; mifi++) {
499: if (mif6table[mifi].m6_ifp &&
500: !(mif6table[mifi].m6_flags & MIFF_REGISTER)) {
501: ifr.ifr_addr.sin6_family = AF_INET6;
502: ifr.ifr_addr.sin6_addr= in6addr_any;
503: ifp = mif6table[mifi].m6_ifp;
504: (*ifp->if_ioctl)(ifp, SIOCDELMULTI,
505: (caddr_t)&ifr);
506: }
507: }
508: }
509: #ifdef notyet
510: bzero((caddr_t)qtable, sizeof(qtable));
511: bzero((caddr_t)tbftable, sizeof(tbftable));
512: #endif
513: bzero((caddr_t)mif6table, sizeof(mif6table));
514: nummifs = 0;
515:
516: pim6 = 0; /* used to stub out/in pim specific code */
517:
518: timeout_del(&expire_upcalls_ch);
519:
520: /*
521: * Free all multicast forwarding cache entries.
522: */
523: for (i = 0; i < MF6CTBLSIZ; i++) {
524: rt = mf6ctable[i];
525: while (rt) {
526: struct mf6c *frt;
527:
528: for (rte = rt->mf6c_stall; rte != NULL; ) {
529: struct rtdetq *n = rte->next;
530:
531: m_free(rte->m);
532: free(rte, M_MRTABLE);
533: rte = n;
534: }
535: frt = rt;
536: rt = rt->mf6c_next;
537: free(frt, M_MRTABLE);
538: }
539: }
540:
541: bzero((caddr_t)mf6ctable, sizeof(mf6ctable));
542:
543: /*
544: * Reset de-encapsulation cache
545: */
546: reg_mif_num = -1;
547:
548: ip6_mrouter = NULL;
549: ip6_mrouter_ver = 0;
550:
551: splx(s);
552:
553: #ifdef MRT6DEBUG
554: if (mrt6debug)
555: log(LOG_DEBUG, "ip6_mrouter_done\n");
556: #endif
557:
558: return 0;
559: }
560:
561: void
562: ip6_mrouter_detach(ifp)
563: struct ifnet *ifp;
564: {
565: struct rtdetq *rte;
566: struct mf6c *mfc;
567: mifi_t mifi;
568: int i;
569:
570: /*
571: * Delete a mif which points to ifp.
572: */
573: for (mifi = 0; mifi < nummifs; mifi++)
574: if (mif6table[mifi].m6_ifp == ifp)
575: del_m6if(&mifi);
576:
577: /*
578: * Clear rte->ifp of cache entries received on ifp.
579: */
580: for (i = 0; i < MF6CTBLSIZ; i++) {
581: if (n6expire[i] == 0)
582: continue;
583:
584: for (mfc = mf6ctable[i]; mfc != NULL; mfc = mfc->mf6c_next) {
585: for (rte = mfc->mf6c_stall; rte != NULL; rte = rte->next) {
586: if (rte->ifp == ifp)
587: rte->ifp = NULL;
588: }
589: }
590: }
591: }
592:
593: /*
594: * Add a mif to the mif table
595: */
596: static int
597: add_m6if(mifcp)
598: struct mif6ctl *mifcp;
599: {
600: struct mif6 *mifp;
601: struct ifnet *ifp;
602: struct in6_ifreq ifr;
603: int error, s;
604: #ifdef notyet
605: struct tbf *m_tbf = tbftable + mifcp->mif6c_mifi;
606: #endif
607:
608: if (mifcp->mif6c_mifi >= MAXMIFS)
609: return EINVAL;
610: mifp = mif6table + mifcp->mif6c_mifi;
611: if (mifp->m6_ifp)
612: return EADDRINUSE; /* XXX: is it appropriate? */
613: if (mifcp->mif6c_pifi == 0 || mifcp->mif6c_pifi >= if_indexlim)
614: return ENXIO;
615: ifp = ifindex2ifnet[mifcp->mif6c_pifi];
616: if (!ifp)
617: return ENXIO;
618:
619: if (mifcp->mif6c_flags & MIFF_REGISTER) {
620: if (reg_mif_num == (mifi_t)-1) {
621: strlcpy(multicast_register_if.if_xname,
622: "register_mif",
623: sizeof multicast_register_if.if_xname); /* XXX */
624: multicast_register_if.if_flags |= IFF_LOOPBACK;
625: multicast_register_if.if_index = mifcp->mif6c_mifi;
626: reg_mif_num = mifcp->mif6c_mifi;
627: }
628:
629: ifp = &multicast_register_if;
630:
631: } /* if REGISTER */
632: else {
633: /* Make sure the interface supports multicast */
634: if ((ifp->if_flags & IFF_MULTICAST) == 0)
635: return EOPNOTSUPP;
636:
637: s = splsoftnet();
638:
639: /*
640: * Enable promiscuous reception of all IPv6 multicasts
641: * from the interface.
642: */
643: ifr.ifr_addr.sin6_family = AF_INET6;
644: ifr.ifr_addr.sin6_addr = in6addr_any;
645: error = (*ifp->if_ioctl)(ifp, SIOCADDMULTI, (caddr_t)&ifr);
646:
647: splx(s);
648: if (error)
649: return error;
650: }
651:
652: s = splsoftnet();
653:
654: mifp->m6_flags = mifcp->mif6c_flags;
655: mifp->m6_ifp = ifp;
656: #ifdef notyet
657: /* scaling up here allows division by 1024 in critical code */
658: mifp->m6_rate_limit = mifcp->mif6c_rate_limit * 1024 / 1000;
659: #endif
660: /* initialize per mif pkt counters */
661: mifp->m6_pkt_in = 0;
662: mifp->m6_pkt_out = 0;
663: mifp->m6_bytes_in = 0;
664: mifp->m6_bytes_out = 0;
665: splx(s);
666:
667: /* Adjust nummifs up if the mifi is higher than nummifs */
668: if (nummifs <= mifcp->mif6c_mifi)
669: nummifs = mifcp->mif6c_mifi + 1;
670:
671: #ifdef MRT6DEBUG
672: if (mrt6debug)
673: log(LOG_DEBUG,
674: "add_mif #%d, phyint %s%d\n",
675: mifcp->mif6c_mifi,
676: ifp->if_name, ifp->if_unit);
677: #endif
678:
679: return 0;
680: }
681:
682: /*
683: * Delete a mif from the mif table
684: */
685: static int
686: del_m6if(mifip)
687: mifi_t *mifip;
688: {
689: struct mif6 *mifp = mif6table + *mifip;
690: mifi_t mifi;
691: struct ifnet *ifp;
692: struct in6_ifreq ifr;
693: int s;
694:
695: if (*mifip >= nummifs)
696: return EINVAL;
697: if (mifp->m6_ifp == NULL)
698: return EINVAL;
699:
700: s = splsoftnet();
701:
702: if (!(mifp->m6_flags & MIFF_REGISTER)) {
703: /*
704: * XXX: what if there is yet IPv4 multicast daemon
705: * using the interface?
706: */
707: ifp = mifp->m6_ifp;
708:
709: ifr.ifr_addr.sin6_family = AF_INET6;
710: ifr.ifr_addr.sin6_addr = in6addr_any;
711: (*ifp->if_ioctl)(ifp, SIOCDELMULTI, (caddr_t)&ifr);
712: }
713:
714: #ifdef notyet
715: bzero((caddr_t)qtable[*mifip], sizeof(qtable[*mifip]));
716: bzero((caddr_t)mifp->m6_tbf, sizeof(*(mifp->m6_tbf)));
717: #endif
718: bzero((caddr_t)mifp, sizeof (*mifp));
719:
720: /* Adjust nummifs down */
721: for (mifi = nummifs; mifi > 0; mifi--)
722: if (mif6table[mifi - 1].m6_ifp)
723: break;
724: nummifs = mifi;
725:
726: splx(s);
727:
728: #ifdef MRT6DEBUG
729: if (mrt6debug)
730: log(LOG_DEBUG, "del_m6if %d, nummifs %d\n", *mifip, nummifs);
731: #endif
732:
733: return 0;
734: }
735:
736: /*
737: * Add an mfc entry
738: */
739: static int
740: add_m6fc(mfccp)
741: struct mf6cctl *mfccp;
742: {
743: struct mf6c *rt;
744: u_long hash;
745: struct rtdetq *rte;
746: u_short nstl;
747: int s;
748:
749: MF6CFIND(mfccp->mf6cc_origin.sin6_addr,
750: mfccp->mf6cc_mcastgrp.sin6_addr, rt);
751:
752: /* If an entry already exists, just update the fields */
753: if (rt) {
754: #ifdef MRT6DEBUG
755: if (mrt6debug & DEBUG_MFC)
756: log(LOG_DEBUG,"add_m6fc update o %s g %s p %x\n",
757: ip6_sprintf(&mfccp->mf6cc_origin.sin6_addr),
758: ip6_sprintf(&mfccp->mf6cc_mcastgrp.sin6_addr),
759: mfccp->mf6cc_parent);
760: #endif
761:
762: s = splsoftnet();
763:
764: rt->mf6c_parent = mfccp->mf6cc_parent;
765: rt->mf6c_ifset = mfccp->mf6cc_ifset;
766: splx(s);
767: return 0;
768: }
769:
770: /*
771: * Find the entry for which the upcall was made and update
772: */
773: s = splsoftnet();
774:
775: hash = MF6CHASH(mfccp->mf6cc_origin.sin6_addr,
776: mfccp->mf6cc_mcastgrp.sin6_addr);
777: for (rt = mf6ctable[hash], nstl = 0; rt; rt = rt->mf6c_next) {
778: if (IN6_ARE_ADDR_EQUAL(&rt->mf6c_origin.sin6_addr,
779: &mfccp->mf6cc_origin.sin6_addr) &&
780: IN6_ARE_ADDR_EQUAL(&rt->mf6c_mcastgrp.sin6_addr,
781: &mfccp->mf6cc_mcastgrp.sin6_addr) &&
782: (rt->mf6c_stall != NULL)) {
783:
784: if (nstl++)
785: log(LOG_ERR,
786: "add_m6fc: %s o %s g %s p %x dbx %p\n",
787: "multiple kernel entries",
788: ip6_sprintf(&mfccp->mf6cc_origin.sin6_addr),
789: ip6_sprintf(&mfccp->mf6cc_mcastgrp.sin6_addr),
790: mfccp->mf6cc_parent, rt->mf6c_stall);
791:
792: #ifdef MRT6DEBUG
793: if (mrt6debug & DEBUG_MFC)
794: log(LOG_DEBUG,
795: "add_m6fc o %s g %s p %x dbg %x\n",
796: ip6_sprintf(&mfccp->mf6cc_origin.sin6_addr),
797: ip6_sprintf(&mfccp->mf6cc_mcastgrp.sin6_addr),
798: mfccp->mf6cc_parent, rt->mf6c_stall);
799: #endif
800:
801: rt->mf6c_origin = mfccp->mf6cc_origin;
802: rt->mf6c_mcastgrp = mfccp->mf6cc_mcastgrp;
803: rt->mf6c_parent = mfccp->mf6cc_parent;
804: rt->mf6c_ifset = mfccp->mf6cc_ifset;
805: /* initialize pkt counters per src-grp */
806: rt->mf6c_pkt_cnt = 0;
807: rt->mf6c_byte_cnt = 0;
808: rt->mf6c_wrong_if = 0;
809:
810: rt->mf6c_expire = 0; /* Don't clean this guy up */
811: n6expire[hash]--;
812:
813: /* free packets Qed at the end of this entry */
814: for (rte = rt->mf6c_stall; rte != NULL; ) {
815: struct rtdetq *n = rte->next;
816: if (rte->ifp) {
817: ip6_mdq(rte->m, rte->ifp, rt);
818: }
819: m_freem(rte->m);
820: #ifdef UPCALL_TIMING
821: collate(&(rte->t));
822: #endif /* UPCALL_TIMING */
823: free(rte, M_MRTABLE);
824: rte = n;
825: }
826: rt->mf6c_stall = NULL;
827: }
828: }
829:
830: /*
831: * It is possible that an entry is being inserted without an upcall
832: */
833: if (nstl == 0) {
834: #ifdef MRT6DEBUG
835: if (mrt6debug & DEBUG_MFC)
836: log(LOG_DEBUG,
837: "add_m6fc no upcall h %d o %s g %s p %x\n",
838: hash,
839: ip6_sprintf(&mfccp->mf6cc_origin.sin6_addr),
840: ip6_sprintf(&mfccp->mf6cc_mcastgrp.sin6_addr),
841: mfccp->mf6cc_parent);
842: #endif
843:
844: for (rt = mf6ctable[hash]; rt; rt = rt->mf6c_next) {
845:
846: if (IN6_ARE_ADDR_EQUAL(&rt->mf6c_origin.sin6_addr,
847: &mfccp->mf6cc_origin.sin6_addr)&&
848: IN6_ARE_ADDR_EQUAL(&rt->mf6c_mcastgrp.sin6_addr,
849: &mfccp->mf6cc_mcastgrp.sin6_addr)) {
850:
851: rt->mf6c_origin = mfccp->mf6cc_origin;
852: rt->mf6c_mcastgrp = mfccp->mf6cc_mcastgrp;
853: rt->mf6c_parent = mfccp->mf6cc_parent;
854: rt->mf6c_ifset = mfccp->mf6cc_ifset;
855: /* initialize pkt counters per src-grp */
856: rt->mf6c_pkt_cnt = 0;
857: rt->mf6c_byte_cnt = 0;
858: rt->mf6c_wrong_if = 0;
859:
860: if (rt->mf6c_expire)
861: n6expire[hash]--;
862: rt->mf6c_expire = 0;
863: }
864: }
865: if (rt == NULL) {
866: /* no upcall, so make a new entry */
867: rt = (struct mf6c *)malloc(sizeof(*rt), M_MRTABLE,
868: M_NOWAIT);
869: if (rt == NULL) {
870: splx(s);
871: return ENOBUFS;
872: }
873:
874: /* insert new entry at head of hash chain */
875: rt->mf6c_origin = mfccp->mf6cc_origin;
876: rt->mf6c_mcastgrp = mfccp->mf6cc_mcastgrp;
877: rt->mf6c_parent = mfccp->mf6cc_parent;
878: rt->mf6c_ifset = mfccp->mf6cc_ifset;
879: /* initialize pkt counters per src-grp */
880: rt->mf6c_pkt_cnt = 0;
881: rt->mf6c_byte_cnt = 0;
882: rt->mf6c_wrong_if = 0;
883: rt->mf6c_expire = 0;
884: rt->mf6c_stall = NULL;
885:
886: /* link into table */
887: rt->mf6c_next = mf6ctable[hash];
888: mf6ctable[hash] = rt;
889: }
890: }
891: splx(s);
892: return 0;
893: }
894:
895: #ifdef UPCALL_TIMING
896: /*
897: * collect delay statistics on the upcalls
898: */
899: static void
900: collate(t)
901: struct timeval *t;
902: {
903: u_long d;
904: struct timeval tp;
905: u_long delta;
906:
907: GET_TIME(tp);
908:
909: if (TV_LT(*t, tp))
910: {
911: TV_DELTA(tp, *t, delta);
912:
913: d = delta >> 10;
914: if (d > UPCALL_MAX)
915: d = UPCALL_MAX;
916:
917: ++upcall_data[d];
918: }
919: }
920: #endif /* UPCALL_TIMING */
921:
922: /*
923: * Delete an mfc entry
924: */
925: static int
926: del_m6fc(mfccp)
927: struct mf6cctl *mfccp;
928: {
929: struct sockaddr_in6 origin;
930: struct sockaddr_in6 mcastgrp;
931: struct mf6c *rt;
932: struct mf6c **nptr;
933: u_long hash;
934: int s;
935:
936: origin = mfccp->mf6cc_origin;
937: mcastgrp = mfccp->mf6cc_mcastgrp;
938: hash = MF6CHASH(origin.sin6_addr, mcastgrp.sin6_addr);
939:
940: #ifdef MRT6DEBUG
941: if (mrt6debug & DEBUG_MFC)
942: log(LOG_DEBUG,"del_m6fc orig %s mcastgrp %s\n",
943: ip6_sprintf(&origin.sin6_addr),
944: ip6_sprintf(&mcastgrp.sin6_addr));
945: #endif
946:
947: s = splsoftnet();
948:
949: nptr = &mf6ctable[hash];
950: while ((rt = *nptr) != NULL) {
951: if (IN6_ARE_ADDR_EQUAL(&origin.sin6_addr,
952: &rt->mf6c_origin.sin6_addr) &&
953: IN6_ARE_ADDR_EQUAL(&mcastgrp.sin6_addr,
954: &rt->mf6c_mcastgrp.sin6_addr) &&
955: rt->mf6c_stall == NULL)
956: break;
957:
958: nptr = &rt->mf6c_next;
959: }
960: if (rt == NULL) {
961: splx(s);
962: return EADDRNOTAVAIL;
963: }
964:
965: *nptr = rt->mf6c_next;
966: free(rt, M_MRTABLE);
967:
968: splx(s);
969:
970: return 0;
971: }
972:
973: static int
974: socket_send(s, mm, src)
975: struct socket *s;
976: struct mbuf *mm;
977: struct sockaddr_in6 *src;
978: {
979: if (s) {
980: if (sbappendaddr(&s->so_rcv,
981: (struct sockaddr *)src,
982: mm, (struct mbuf *)0) != 0) {
983: sorwakeup(s);
984: return 0;
985: }
986: }
987: m_freem(mm);
988: return -1;
989: }
990:
991: /*
992: * IPv6 multicast forwarding function. This function assumes that the packet
993: * pointed to by "ip6" has arrived on (or is about to be sent to) the interface
994: * pointed to by "ifp", and the packet is to be relayed to other networks
995: * that have members of the packet's destination IPv6 multicast group.
996: *
997: * The packet is returned unscathed to the caller, unless it is
998: * erroneous, in which case a non-zero return value tells the caller to
999: * discard it.
1000: */
1001:
1002: int
1003: ip6_mforward(ip6, ifp, m)
1004: struct ip6_hdr *ip6;
1005: struct ifnet *ifp;
1006: struct mbuf *m;
1007: {
1008: struct mf6c *rt;
1009: struct mif6 *mifp;
1010: struct mbuf *mm;
1011: int s;
1012: mifi_t mifi;
1013: struct sockaddr_in6 sin6;
1014:
1015: #ifdef MRT6DEBUG
1016: if (mrt6debug & DEBUG_FORWARD)
1017: log(LOG_DEBUG, "ip6_mforward: src %s, dst %s, ifindex %d\n",
1018: ip6_sprintf(&ip6->ip6_src), ip6_sprintf(&ip6->ip6_dst),
1019: ifp->if_index);
1020: #endif
1021:
1022: /*
1023: * Don't forward a packet with Hop limit of zero or one,
1024: * or a packet destined to a local-only group.
1025: */
1026: if (ip6->ip6_hlim <= 1 || IN6_IS_ADDR_MC_INTFACELOCAL(&ip6->ip6_dst) ||
1027: IN6_IS_ADDR_MC_LINKLOCAL(&ip6->ip6_dst))
1028: return 0;
1029: ip6->ip6_hlim--;
1030:
1031: /*
1032: * Source address check: do not forward packets with unspecified
1033: * source. It was discussed in July 2000, on ipngwg mailing list.
1034: * This is rather more serious than unicast cases, because some
1035: * MLD packets can be sent with the unspecified source address
1036: * (although such packets must normally set 1 to the hop limit field).
1037: */
1038: if (IN6_IS_ADDR_UNSPECIFIED(&ip6->ip6_src)) {
1039: ip6stat.ip6s_cantforward++;
1040: if (ip6_log_time + ip6_log_interval < time_second) {
1041: ip6_log_time = time_second;
1042: log(LOG_DEBUG,
1043: "cannot forward "
1044: "from %s to %s nxt %d received on %s\n",
1045: ip6_sprintf(&ip6->ip6_src),
1046: ip6_sprintf(&ip6->ip6_dst),
1047: ip6->ip6_nxt,
1048: m->m_pkthdr.rcvif->if_xname);
1049: }
1050: return 0;
1051: }
1052:
1053: /*
1054: * Determine forwarding mifs from the forwarding cache table
1055: */
1056: s = splsoftnet();
1057: MF6CFIND(ip6->ip6_src, ip6->ip6_dst, rt);
1058:
1059: /* Entry exists, so forward if necessary */
1060: if (rt) {
1061: splx(s);
1062: return (ip6_mdq(m, ifp, rt));
1063: } else {
1064: /*
1065: * If we don't have a route for packet's origin,
1066: * Make a copy of the packet &
1067: * send message to routing daemon
1068: */
1069:
1070: struct mbuf *mb0;
1071: struct rtdetq *rte;
1072: u_long hash;
1073: /* int i, npkts;*/
1074: #ifdef UPCALL_TIMING
1075: struct timeval tp;
1076:
1077: GET_TIME(tp);
1078: #endif /* UPCALL_TIMING */
1079:
1080: mrt6stat.mrt6s_no_route++;
1081: #ifdef MRT6DEBUG
1082: if (mrt6debug & (DEBUG_FORWARD | DEBUG_MFC))
1083: log(LOG_DEBUG, "ip6_mforward: no rte s %s g %s\n",
1084: ip6_sprintf(&ip6->ip6_src),
1085: ip6_sprintf(&ip6->ip6_dst));
1086: #endif
1087:
1088: /*
1089: * Allocate mbufs early so that we don't do extra work if we
1090: * are just going to fail anyway.
1091: */
1092: rte = (struct rtdetq *)malloc(sizeof(*rte), M_MRTABLE,
1093: M_NOWAIT);
1094: if (rte == NULL) {
1095: splx(s);
1096: return ENOBUFS;
1097: }
1098: mb0 = m_copy(m, 0, M_COPYALL);
1099: /*
1100: * Pullup packet header if needed before storing it,
1101: * as other references may modify it in the meantime.
1102: */
1103: if (mb0 &&
1104: (M_READONLY(mb0) || mb0->m_len < sizeof(struct ip6_hdr)))
1105: mb0 = m_pullup(mb0, sizeof(struct ip6_hdr));
1106: if (mb0 == NULL) {
1107: free(rte, M_MRTABLE);
1108: splx(s);
1109: return ENOBUFS;
1110: }
1111:
1112: /* is there an upcall waiting for this packet? */
1113: hash = MF6CHASH(ip6->ip6_src, ip6->ip6_dst);
1114: for (rt = mf6ctable[hash]; rt; rt = rt->mf6c_next) {
1115: if (IN6_ARE_ADDR_EQUAL(&ip6->ip6_src,
1116: &rt->mf6c_origin.sin6_addr) &&
1117: IN6_ARE_ADDR_EQUAL(&ip6->ip6_dst,
1118: &rt->mf6c_mcastgrp.sin6_addr) &&
1119: (rt->mf6c_stall != NULL))
1120: break;
1121: }
1122:
1123: if (rt == NULL) {
1124: struct mrt6msg *im;
1125: #ifdef MRT6_OINIT
1126: struct omrt6msg *oim;
1127: #endif
1128:
1129: /* no upcall, so make a new entry */
1130: rt = (struct mf6c *)malloc(sizeof(*rt), M_MRTABLE,
1131: M_NOWAIT);
1132: if (rt == NULL) {
1133: free(rte, M_MRTABLE);
1134: m_freem(mb0);
1135: splx(s);
1136: return ENOBUFS;
1137: }
1138: /*
1139: * Make a copy of the header to send to the user
1140: * level process
1141: */
1142: mm = m_copy(mb0, 0, sizeof(struct ip6_hdr));
1143:
1144: if (mm == NULL) {
1145: free(rte, M_MRTABLE);
1146: m_freem(mb0);
1147: free(rt, M_MRTABLE);
1148: splx(s);
1149: return ENOBUFS;
1150: }
1151:
1152: /*
1153: * Send message to routing daemon
1154: */
1155: (void)memset(&sin6, 0, sizeof(sin6));
1156: sin6.sin6_len = sizeof(sin6);
1157: sin6.sin6_family = AF_INET6;
1158: sin6.sin6_addr = ip6->ip6_src;
1159:
1160: im = NULL;
1161: #ifdef MRT6_OINIT
1162: oim = NULL;
1163: #endif
1164: switch (ip6_mrouter_ver) {
1165: #ifdef MRT6_OINIT
1166: case MRT6_OINIT:
1167: oim = mtod(mm, struct omrt6msg *);
1168: oim->im6_msgtype = MRT6MSG_NOCACHE;
1169: oim->im6_mbz = 0;
1170: break;
1171: #endif
1172: case MRT6_INIT:
1173: im = mtod(mm, struct mrt6msg *);
1174: im->im6_msgtype = MRT6MSG_NOCACHE;
1175: im->im6_mbz = 0;
1176: break;
1177: default:
1178: free(rte, M_MRTABLE);
1179: m_freem(mb0);
1180: free(rt, M_MRTABLE);
1181: splx(s);
1182: return EINVAL;
1183: }
1184:
1185: #ifdef MRT6DEBUG
1186: if (mrt6debug & DEBUG_FORWARD)
1187: log(LOG_DEBUG,
1188: "getting the iif info in the kernel\n");
1189: #endif
1190:
1191: for (mifp = mif6table, mifi = 0;
1192: mifi < nummifs && mifp->m6_ifp != ifp;
1193: mifp++, mifi++)
1194: ;
1195:
1196: switch (ip6_mrouter_ver) {
1197: #ifdef MRT6_OINIT
1198: case MRT6_OINIT:
1199: oim->im6_mif = mifi;
1200: break;
1201: #endif
1202: case MRT6_INIT:
1203: im->im6_mif = mifi;
1204: break;
1205: }
1206:
1207: if (socket_send(ip6_mrouter, mm, &sin6) < 0) {
1208: log(LOG_WARNING, "ip6_mforward: ip6_mrouter "
1209: "socket queue full\n");
1210: mrt6stat.mrt6s_upq_sockfull++;
1211: free(rte, M_MRTABLE);
1212: m_freem(mb0);
1213: free(rt, M_MRTABLE);
1214: splx(s);
1215: return ENOBUFS;
1216: }
1217:
1218: mrt6stat.mrt6s_upcalls++;
1219:
1220: /* insert new entry at head of hash chain */
1221: bzero(rt, sizeof(*rt));
1222: rt->mf6c_origin.sin6_family = AF_INET6;
1223: rt->mf6c_origin.sin6_len = sizeof(struct sockaddr_in6);
1224: rt->mf6c_origin.sin6_addr = ip6->ip6_src;
1225: rt->mf6c_mcastgrp.sin6_family = AF_INET6;
1226: rt->mf6c_mcastgrp.sin6_len = sizeof(struct sockaddr_in6);
1227: rt->mf6c_mcastgrp.sin6_addr = ip6->ip6_dst;
1228: rt->mf6c_expire = UPCALL_EXPIRE;
1229: n6expire[hash]++;
1230: rt->mf6c_parent = MF6C_INCOMPLETE_PARENT;
1231:
1232: /* link into table */
1233: rt->mf6c_next = mf6ctable[hash];
1234: mf6ctable[hash] = rt;
1235: /* Add this entry to the end of the queue */
1236: rt->mf6c_stall = rte;
1237: } else {
1238: /* determine if q has overflowed */
1239: struct rtdetq **p;
1240: int npkts = 0;
1241:
1242: for (p = &rt->mf6c_stall; *p != NULL; p = &(*p)->next)
1243: if (++npkts > MAX_UPQ6) {
1244: mrt6stat.mrt6s_upq_ovflw++;
1245: free(rte, M_MRTABLE);
1246: m_freem(mb0);
1247: splx(s);
1248: return 0;
1249: }
1250:
1251: /* Add this entry to the end of the queue */
1252: *p = rte;
1253: }
1254:
1255: rte->next = NULL;
1256: rte->m = mb0;
1257: rte->ifp = ifp;
1258: #ifdef UPCALL_TIMING
1259: rte->t = tp;
1260: #endif /* UPCALL_TIMING */
1261:
1262: splx(s);
1263:
1264: return 0;
1265: }
1266: }
1267:
1268: /*
1269: * Clean up cache entries if upcalls are not serviced
1270: * Call from the Slow Timeout mechanism, every half second.
1271: */
1272: static void
1273: expire_upcalls(unused)
1274: void *unused;
1275: {
1276: struct rtdetq *rte;
1277: struct mf6c *mfc, **nptr;
1278: int i;
1279: int s;
1280:
1281: s = splsoftnet();
1282:
1283: for (i = 0; i < MF6CTBLSIZ; i++) {
1284: if (n6expire[i] == 0)
1285: continue;
1286: nptr = &mf6ctable[i];
1287: while ((mfc = *nptr) != NULL) {
1288: rte = mfc->mf6c_stall;
1289: /*
1290: * Skip real cache entries
1291: * Make sure it wasn't marked to not expire (shouldn't happen)
1292: * If it expires now
1293: */
1294: if (rte != NULL &&
1295: mfc->mf6c_expire != 0 &&
1296: --mfc->mf6c_expire == 0) {
1297: #ifdef MRT6DEBUG
1298: if (mrt6debug & DEBUG_EXPIRE)
1299: log(LOG_DEBUG, "expire_upcalls: expiring (%s %s)\n",
1300: ip6_sprintf(&mfc->mf6c_origin.sin6_addr),
1301: ip6_sprintf(&mfc->mf6c_mcastgrp.sin6_addr));
1302: #endif
1303: /*
1304: * drop all the packets
1305: * free the mbuf with the pkt, if, timing info
1306: */
1307: do {
1308: struct rtdetq *n = rte->next;
1309: m_freem(rte->m);
1310: free(rte, M_MRTABLE);
1311: rte = n;
1312: } while (rte != NULL);
1313: mrt6stat.mrt6s_cache_cleanups++;
1314: n6expire[i]--;
1315:
1316: *nptr = mfc->mf6c_next;
1317: free(mfc, M_MRTABLE);
1318: } else {
1319: nptr = &mfc->mf6c_next;
1320: }
1321: }
1322: }
1323: splx(s);
1324: timeout_set(&expire_upcalls_ch, expire_upcalls, NULL);
1325: timeout_add(&expire_upcalls_ch, EXPIRE_TIMEOUT);
1326: }
1327:
1328: /*
1329: * Packet forwarding routine once entry in the cache is made
1330: */
1331: static int
1332: ip6_mdq(m, ifp, rt)
1333: struct mbuf *m;
1334: struct ifnet *ifp;
1335: struct mf6c *rt;
1336: {
1337: struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
1338: mifi_t mifi, iif;
1339: struct mif6 *mifp;
1340: int plen = m->m_pkthdr.len;
1341:
1342: /*
1343: * Macro to send packet on mif. Since RSVP packets don't get counted on
1344: * input, they shouldn't get counted on output, so statistics keeping is
1345: * separate.
1346: */
1347:
1348: #define MC6_SEND(ip6, mifp, m) do { \
1349: if ((mifp)->m6_flags & MIFF_REGISTER) \
1350: register_send((ip6), (mifp), (m)); \
1351: else \
1352: phyint_send((ip6), (mifp), (m)); \
1353: } while (0)
1354:
1355: /*
1356: * Don't forward if it didn't arrive from the parent mif
1357: * for its origin.
1358: */
1359: mifi = rt->mf6c_parent;
1360: if ((mifi >= nummifs) || (mif6table[mifi].m6_ifp != ifp)) {
1361: /* came in the wrong interface */
1362: #ifdef MRT6DEBUG
1363: if (mrt6debug & DEBUG_FORWARD)
1364: log(LOG_DEBUG,
1365: "wrong if: ifid %d mifi %d mififid %x\n",
1366: ifp->if_index, mifi,
1367: mif6table[mifi].m6_ifp ?
1368: mif6table[mifi].m6_ifp->if_index : -1);
1369: #endif
1370: mrt6stat.mrt6s_wrong_if++;
1371: rt->mf6c_wrong_if++;
1372: /*
1373: * If we are doing PIM processing, and we are forwarding
1374: * packets on this interface, send a message to the
1375: * routing daemon.
1376: */
1377: /* have to make sure this is a valid mif */
1378: if (mifi < nummifs && mif6table[mifi].m6_ifp)
1379: if (pim6 && (m->m_flags & M_LOOP) == 0) {
1380: /*
1381: * Check the M_LOOP flag to avoid an
1382: * unnecessary PIM assert.
1383: * XXX: M_LOOP is an ad-hoc hack...
1384: */
1385: struct sockaddr_in6 sin6;
1386:
1387: struct mbuf *mm;
1388: struct mrt6msg *im;
1389: #ifdef MRT6_OINIT
1390: struct omrt6msg *oim;
1391: #endif
1392:
1393: mm = m_copy(m, 0, sizeof(struct ip6_hdr));
1394: if (mm &&
1395: (M_READONLY(mm) ||
1396: mm->m_len < sizeof(struct ip6_hdr)))
1397: mm = m_pullup(mm, sizeof(struct ip6_hdr));
1398: if (mm == NULL)
1399: return ENOBUFS;
1400:
1401: #ifdef MRT6_OINIT
1402: oim = NULL;
1403: #endif
1404: im = NULL;
1405: switch (ip6_mrouter_ver) {
1406: #ifdef MRT6_OINIT
1407: case MRT6_OINIT:
1408: oim = mtod(mm, struct omrt6msg *);
1409: oim->im6_msgtype = MRT6MSG_WRONGMIF;
1410: oim->im6_mbz = 0;
1411: break;
1412: #endif
1413: case MRT6_INIT:
1414: im = mtod(mm, struct mrt6msg *);
1415: im->im6_msgtype = MRT6MSG_WRONGMIF;
1416: im->im6_mbz = 0;
1417: break;
1418: default:
1419: m_freem(mm);
1420: return EINVAL;
1421: }
1422:
1423: for (mifp = mif6table, iif = 0;
1424: iif < nummifs && mifp &&
1425: mifp->m6_ifp != ifp;
1426: mifp++, iif++)
1427: ;
1428:
1429: (void)memset(&sin6, 0, sizeof(sin6));
1430: sin6.sin6_len = sizeof(sin6);
1431: sin6.sin6_family = AF_INET6;
1432: switch (ip6_mrouter_ver) {
1433: #ifdef MRT6_OINIT
1434: case MRT6_OINIT:
1435: oim->im6_mif = iif;
1436: sin6.sin6_addr = oim->im6_src;
1437: break;
1438: #endif
1439: case MRT6_INIT:
1440: im->im6_mif = iif;
1441: sin6.sin6_addr = im->im6_src;
1442: break;
1443: }
1444:
1445: mrt6stat.mrt6s_upcalls++;
1446:
1447: if (socket_send(ip6_mrouter, mm, &sin6) < 0) {
1448: #ifdef MRT6DEBUG
1449: if (mrt6debug)
1450: log(LOG_WARNING, "mdq, ip6_mrouter socket queue full\n");
1451: #endif
1452: ++mrt6stat.mrt6s_upq_sockfull;
1453: return ENOBUFS;
1454: } /* if socket Q full */
1455: } /* if PIM */
1456: return 0;
1457: } /* if wrong iif */
1458:
1459: /* If I sourced this packet, it counts as output, else it was input. */
1460: if (m->m_pkthdr.rcvif == NULL) {
1461: /* XXX: is rcvif really NULL when output?? */
1462: mif6table[mifi].m6_pkt_out++;
1463: mif6table[mifi].m6_bytes_out += plen;
1464: } else {
1465: mif6table[mifi].m6_pkt_in++;
1466: mif6table[mifi].m6_bytes_in += plen;
1467: }
1468: rt->mf6c_pkt_cnt++;
1469: rt->mf6c_byte_cnt += plen;
1470:
1471: /*
1472: * For each mif, forward a copy of the packet if there are group
1473: * members downstream on the interface.
1474: */
1475: for (mifp = mif6table, mifi = 0; mifi < nummifs; mifp++, mifi++)
1476: if (IF_ISSET(mifi, &rt->mf6c_ifset)) {
1477: if (mif6table[mifi].m6_ifp == NULL)
1478: continue;
1479:
1480: /*
1481: * check if the outgoing packet is going to break
1482: * a scope boundary.
1483: * XXX For packets through PIM register tunnel
1484: * interface, we believe a routing daemon.
1485: */
1486: if ((mif6table[rt->mf6c_parent].m6_flags &
1487: MIFF_REGISTER) == 0 &&
1488: (mif6table[mifi].m6_flags & MIFF_REGISTER) == 0 &&
1489: (in6_addr2scopeid(ifp, &ip6->ip6_dst) !=
1490: in6_addr2scopeid(mif6table[mifi].m6_ifp,
1491: &ip6->ip6_dst) ||
1492: in6_addr2scopeid(ifp, &ip6->ip6_src) !=
1493: in6_addr2scopeid(mif6table[mifi].m6_ifp,
1494: &ip6->ip6_src))) {
1495: ip6stat.ip6s_badscope++;
1496: continue;
1497: }
1498:
1499: mifp->m6_pkt_out++;
1500: mifp->m6_bytes_out += plen;
1501: MC6_SEND(ip6, mifp, m);
1502: }
1503: return 0;
1504: }
1505:
1506: static void
1507: phyint_send(ip6, mifp, m)
1508: struct ip6_hdr *ip6;
1509: struct mif6 *mifp;
1510: struct mbuf *m;
1511: {
1512: struct mbuf *mb_copy;
1513: struct ifnet *ifp = mifp->m6_ifp;
1514: int error = 0;
1515: int s = splsoftnet();
1516: static struct route_in6 ro;
1517: struct in6_multi *in6m;
1518: struct sockaddr_in6 *dst6;
1519: u_long linkmtu;
1520:
1521: /*
1522: * Make a new reference to the packet; make sure that
1523: * the IPv6 header is actually copied, not just referenced,
1524: * so that ip6_output() only scribbles on the copy.
1525: */
1526: mb_copy = m_copy(m, 0, M_COPYALL);
1527: if (mb_copy &&
1528: (M_READONLY(mb_copy) || mb_copy->m_len < sizeof(struct ip6_hdr)))
1529: mb_copy = m_pullup(mb_copy, sizeof(struct ip6_hdr));
1530: if (mb_copy == NULL) {
1531: splx(s);
1532: return;
1533: }
1534: /* set MCAST flag to the outgoing packet */
1535: mb_copy->m_flags |= M_MCAST;
1536:
1537: /*
1538: * If we sourced the packet, call ip6_output since we may devide
1539: * the packet into fragments when the packet is too big for the
1540: * outgoing interface.
1541: * Otherwise, we can simply send the packet to the interface
1542: * sending queue.
1543: */
1544: if (m->m_pkthdr.rcvif == NULL) {
1545: struct ip6_moptions im6o;
1546:
1547: im6o.im6o_multicast_ifp = ifp;
1548: /* XXX: ip6_output will override ip6->ip6_hlim */
1549: im6o.im6o_multicast_hlim = ip6->ip6_hlim;
1550: im6o.im6o_multicast_loop = 1;
1551: error = ip6_output(mb_copy, NULL, &ro, IPV6_FORWARDING, &im6o,
1552: NULL, NULL);
1553:
1554: #ifdef MRT6DEBUG
1555: if (mrt6debug & DEBUG_XMIT)
1556: log(LOG_DEBUG, "phyint_send on mif %d err %d\n",
1557: mifp - mif6table, error);
1558: #endif
1559: splx(s);
1560: return;
1561: }
1562:
1563: /*
1564: * If we belong to the destination multicast group
1565: * on the outgoing interface, loop back a copy.
1566: */
1567: dst6 = (struct sockaddr_in6 *)&ro.ro_dst;
1568: IN6_LOOKUP_MULTI(ip6->ip6_dst, ifp, in6m);
1569: if (in6m != NULL) {
1570: dst6->sin6_len = sizeof(struct sockaddr_in6);
1571: dst6->sin6_family = AF_INET6;
1572: dst6->sin6_addr = ip6->ip6_dst;
1573: ip6_mloopback(ifp, m, (struct sockaddr_in6 *)&ro.ro_dst);
1574: }
1575: /*
1576: * Put the packet into the sending queue of the outgoing interface
1577: * if it would fit in the MTU of the interface.
1578: */
1579: linkmtu = IN6_LINKMTU(ifp);
1580: if (mb_copy->m_pkthdr.len <= linkmtu || linkmtu < IPV6_MMTU) {
1581: dst6->sin6_len = sizeof(struct sockaddr_in6);
1582: dst6->sin6_family = AF_INET6;
1583: dst6->sin6_addr = ip6->ip6_dst;
1584: /*
1585: * We just call if_output instead of nd6_output here, since
1586: * we need no ND for a multicast forwarded packet...right?
1587: */
1588: error = (*ifp->if_output)(ifp, mb_copy,
1589: (struct sockaddr *)&ro.ro_dst, NULL);
1590: #ifdef MRT6DEBUG
1591: if (mrt6debug & DEBUG_XMIT)
1592: log(LOG_DEBUG, "phyint_send on mif %d err %d\n",
1593: mifp - mif6table, error);
1594: #endif
1595: } else {
1596: if (ip6_mcast_pmtu)
1597: icmp6_error(mb_copy, ICMP6_PACKET_TOO_BIG, 0, linkmtu);
1598: else {
1599: #ifdef MRT6DEBUG
1600: if (mrt6debug & DEBUG_XMIT)
1601: log(LOG_DEBUG,
1602: "phyint_send: packet too big on %s o %s g %s"
1603: " size %d(discarded)\n",
1604: ifp->if_xname,
1605: ip6_sprintf(&ip6->ip6_src),
1606: ip6_sprintf(&ip6->ip6_dst),
1607: mb_copy->m_pkthdr.len);
1608: #endif /* MRT6DEBUG */
1609: m_freem(mb_copy); /* simply discard the packet */
1610: }
1611: }
1612:
1613: splx(s);
1614: }
1615:
1616: static int
1617: register_send(ip6, mif, m)
1618: struct ip6_hdr *ip6;
1619: struct mif6 *mif;
1620: struct mbuf *m;
1621: {
1622: struct mbuf *mm;
1623: int i, len = m->m_pkthdr.len;
1624: struct sockaddr_in6 sin6;
1625: struct mrt6msg *im6;
1626:
1627: #ifdef MRT6DEBUG
1628: if (mrt6debug)
1629: log(LOG_DEBUG, "** IPv6 register_send **\n src %s dst %s\n",
1630: ip6_sprintf(&ip6->ip6_src), ip6_sprintf(&ip6->ip6_dst));
1631: #endif
1632: ++pim6stat.pim6s_snd_registers;
1633:
1634: /* Make a copy of the packet to send to the user level process */
1635: MGETHDR(mm, M_DONTWAIT, MT_HEADER);
1636: if (mm == NULL)
1637: return ENOBUFS;
1638: mm->m_data += max_linkhdr;
1639: mm->m_len = sizeof(struct ip6_hdr);
1640:
1641: if ((mm->m_next = m_copy(m, 0, M_COPYALL)) == NULL) {
1642: m_freem(mm);
1643: return ENOBUFS;
1644: }
1645: i = MHLEN - M_LEADINGSPACE(mm);
1646: if (i > len)
1647: i = len;
1648: mm = m_pullup(mm, i);
1649: if (mm == NULL)
1650: return ENOBUFS;
1651: /* TODO: check it! */
1652: mm->m_pkthdr.len = len + sizeof(struct ip6_hdr);
1653:
1654: /*
1655: * Send message to routing daemon
1656: */
1657: (void)memset(&sin6, 0, sizeof(sin6));
1658: sin6.sin6_len = sizeof(sin6);
1659: sin6.sin6_family = AF_INET6;
1660: sin6.sin6_addr = ip6->ip6_src;
1661:
1662: im6 = mtod(mm, struct mrt6msg *);
1663: im6->im6_msgtype = MRT6MSG_WHOLEPKT;
1664: im6->im6_mbz = 0;
1665:
1666: im6->im6_mif = mif - mif6table;
1667:
1668: /* iif info is not given for reg. encap.n */
1669: mrt6stat.mrt6s_upcalls++;
1670:
1671: if (socket_send(ip6_mrouter, mm, &sin6) < 0) {
1672: #ifdef MRT6DEBUG
1673: if (mrt6debug)
1674: log(LOG_WARNING,
1675: "register_send: ip6_mrouter socket queue full\n");
1676: #endif
1677: ++mrt6stat.mrt6s_upq_sockfull;
1678: return ENOBUFS;
1679: }
1680: return 0;
1681: }
1682:
1683: /*
1684: * PIM sparse mode hook
1685: * Receives the pim control messages, and passes them up to the listening
1686: * socket, using rip6_input.
1687: * The only message processed is the REGISTER pim message; the pim header
1688: * is stripped off, and the inner packet is passed to register_mforward.
1689: */
1690: int
1691: pim6_input(mp, offp, proto)
1692: struct mbuf **mp;
1693: int *offp, proto;
1694: {
1695: struct pim *pim; /* pointer to a pim struct */
1696: struct ip6_hdr *ip6;
1697: int pimlen;
1698: struct mbuf *m = *mp;
1699: int minlen;
1700: int off = *offp;
1701:
1702: ++pim6stat.pim6s_rcv_total;
1703:
1704: ip6 = mtod(m, struct ip6_hdr *);
1705: pimlen = m->m_pkthdr.len - *offp;
1706:
1707: /*
1708: * Validate lengths
1709: */
1710: if (pimlen < PIM_MINLEN) {
1711: ++pim6stat.pim6s_rcv_tooshort;
1712: #ifdef MRT6DEBUG
1713: if (mrt6debug & DEBUG_PIM)
1714: log(LOG_DEBUG,"pim6_input: PIM packet too short\n");
1715: #endif
1716: m_freem(m);
1717: return (IPPROTO_DONE);
1718: }
1719:
1720: /*
1721: * if the packet is at least as big as a REGISTER, go ahead
1722: * and grab the PIM REGISTER header size, to avoid another
1723: * possible m_pullup() later.
1724: *
1725: * PIM_MINLEN == pimhdr + u_int32 == 8
1726: * PIM6_REG_MINLEN == pimhdr + reghdr + eip6hdr == 4 + 4 + 40
1727: */
1728: minlen = (pimlen >= PIM6_REG_MINLEN) ? PIM6_REG_MINLEN : PIM_MINLEN;
1729:
1730: /*
1731: * Make sure that the IP6 and PIM headers in contiguous memory, and
1732: * possibly the PIM REGISTER header
1733: */
1734: IP6_EXTHDR_GET(pim, struct pim *, m, off, minlen);
1735: if (pim == NULL) {
1736: pim6stat.pim6s_rcv_tooshort++;
1737: return IPPROTO_DONE;
1738: }
1739:
1740: /* PIM version check */
1741: if (pim->pim_ver != PIM_VERSION) {
1742: ++pim6stat.pim6s_rcv_badversion;
1743: #ifdef MRT6DEBUG
1744: log(LOG_ERR,
1745: "pim6_input: incorrect version %d, expecting %d\n",
1746: pim->pim_ver, PIM_VERSION);
1747: #endif
1748: m_freem(m);
1749: return (IPPROTO_DONE);
1750: }
1751:
1752: #define PIM6_CHECKSUM
1753: #ifdef PIM6_CHECKSUM
1754: {
1755: int cksumlen;
1756:
1757: /*
1758: * Validate checksum.
1759: * If PIM REGISTER, exclude the data packet
1760: */
1761: if (pim->pim_type == PIM_REGISTER)
1762: cksumlen = PIM_MINLEN;
1763: else
1764: cksumlen = pimlen;
1765:
1766: if (in6_cksum(m, IPPROTO_PIM, off, cksumlen)) {
1767: ++pim6stat.pim6s_rcv_badsum;
1768: #ifdef MRT6DEBUG
1769: if (mrt6debug & DEBUG_PIM)
1770: log(LOG_DEBUG,
1771: "pim6_input: invalid checksum\n");
1772: #endif
1773: m_freem(m);
1774: return (IPPROTO_DONE);
1775: }
1776: }
1777: #endif /* PIM_CHECKSUM */
1778:
1779: if (pim->pim_type == PIM_REGISTER) {
1780: /*
1781: * since this is a REGISTER, we'll make a copy of the register
1782: * headers ip6+pim+u_int32_t+encap_ip6, to be passed up to the
1783: * routing daemon.
1784: */
1785: static struct sockaddr_in6 dst = { sizeof(dst), AF_INET6 };
1786:
1787: struct mbuf *mcp;
1788: struct ip6_hdr *eip6;
1789: u_int32_t *reghdr;
1790: int rc;
1791:
1792: ++pim6stat.pim6s_rcv_registers;
1793:
1794: if ((reg_mif_num >= nummifs) || (reg_mif_num == (mifi_t) -1)) {
1795: #ifdef MRT6DEBUG
1796: if (mrt6debug & DEBUG_PIM)
1797: log(LOG_DEBUG,
1798: "pim6_input: register mif not set: %d\n",
1799: reg_mif_num);
1800: #endif
1801: m_freem(m);
1802: return (IPPROTO_DONE);
1803: }
1804:
1805: reghdr = (u_int32_t *)(pim + 1);
1806:
1807: if ((ntohl(*reghdr) & PIM_NULL_REGISTER))
1808: goto pim6_input_to_daemon;
1809:
1810: /*
1811: * Validate length
1812: */
1813: if (pimlen < PIM6_REG_MINLEN) {
1814: ++pim6stat.pim6s_rcv_tooshort;
1815: ++pim6stat.pim6s_rcv_badregisters;
1816: #ifdef MRT6DEBUG
1817: log(LOG_ERR,
1818: "pim6_input: register packet size too "
1819: "small %d from %s\n",
1820: pimlen, ip6_sprintf(&ip6->ip6_src));
1821: #endif
1822: m_freem(m);
1823: return (IPPROTO_DONE);
1824: }
1825:
1826: eip6 = (struct ip6_hdr *) (reghdr + 1);
1827: #ifdef MRT6DEBUG
1828: if (mrt6debug & DEBUG_PIM)
1829: log(LOG_DEBUG,
1830: "pim6_input[register], eip6: %s -> %s, "
1831: "eip6 plen %d\n",
1832: ip6_sprintf(&eip6->ip6_src),
1833: ip6_sprintf(&eip6->ip6_dst),
1834: ntohs(eip6->ip6_plen));
1835: #endif
1836:
1837: /* verify the version number of the inner packet */
1838: if ((eip6->ip6_vfc & IPV6_VERSION_MASK) != IPV6_VERSION) {
1839: ++pim6stat.pim6s_rcv_badregisters;
1840: #ifdef MRT6DEBUG
1841: log(LOG_DEBUG, "pim6_input: invalid IP version (%d) "
1842: "of the inner packet\n",
1843: (eip6->ip6_vfc & IPV6_VERSION));
1844: #endif
1845: m_freem(m);
1846: return (IPPROTO_NONE);
1847: }
1848:
1849: /* verify the inner packet is destined to a mcast group */
1850: if (!IN6_IS_ADDR_MULTICAST(&eip6->ip6_dst)) {
1851: ++pim6stat.pim6s_rcv_badregisters;
1852: #ifdef MRT6DEBUG
1853: if (mrt6debug & DEBUG_PIM)
1854: log(LOG_DEBUG,
1855: "pim6_input: inner packet of register "
1856: "is not multicast %s\n",
1857: ip6_sprintf(&eip6->ip6_dst));
1858: #endif
1859: m_freem(m);
1860: return (IPPROTO_DONE);
1861: }
1862:
1863: /*
1864: * make a copy of the whole header to pass to the daemon later.
1865: */
1866: mcp = m_copy(m, 0, off + PIM6_REG_MINLEN);
1867: if (mcp == NULL) {
1868: #ifdef MRT6DEBUG
1869: log(LOG_ERR,
1870: "pim6_input: pim register: "
1871: "could not copy register head\n");
1872: #endif
1873: m_freem(m);
1874: return (IPPROTO_DONE);
1875: }
1876:
1877: /*
1878: * forward the inner ip6 packet; point m_data at the inner ip6.
1879: */
1880: m_adj(m, off + PIM_MINLEN);
1881: #ifdef MRT6DEBUG
1882: if (mrt6debug & DEBUG_PIM) {
1883: log(LOG_DEBUG,
1884: "pim6_input: forwarding decapsulated register: "
1885: "src %s, dst %s, mif %d\n",
1886: ip6_sprintf(&eip6->ip6_src),
1887: ip6_sprintf(&eip6->ip6_dst),
1888: reg_mif_num);
1889: }
1890: #endif
1891:
1892: rc = looutput(mif6table[reg_mif_num].m6_ifp, m,
1893: (struct sockaddr *) &dst,
1894: (struct rtentry *) NULL);
1895:
1896: /* prepare the register head to send to the mrouting daemon */
1897: m = mcp;
1898: }
1899:
1900: /*
1901: * Pass the PIM message up to the daemon; if it is a register message
1902: * pass the 'head' only up to the daemon. This includes the
1903: * encapsulator ip6 header, pim header, register header and the
1904: * encapsulated ip6 header.
1905: */
1906: pim6_input_to_daemon:
1907: rip6_input(&m, offp, proto);
1908: return (IPPROTO_DONE);
1909: }
CVSweb