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