Annotation of sys/netinet6/ip6_mroute.c, Revision 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