ip_mroute.c revision 1817
1/* 2 * Copyright (c) 1989 Stephen Deering 3 * Copyright (c) 1992, 1993 4 * The Regents of the University of California. All rights reserved. 5 * 6 * This code is derived from software contributed to Berkeley by 7 * Stephen Deering of Stanford University. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. All advertising materials mentioning features or use of this software 18 * must display the following acknowledgement: 19 * This product includes software developed by the University of 20 * California, Berkeley and its contributors. 21 * 4. Neither the name of the University nor the names of its contributors 22 * may be used to endorse or promote products derived from this software 23 * without specific prior written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 35 * SUCH DAMAGE. 36 * 37 * @(#)ip_mroute.c 8.2 (Berkeley) 11/15/93 38 * $Id$ 39 */ 40 41/* 42 * Procedures for the kernel part of DVMRP, 43 * a Distance-Vector Multicast Routing Protocol. 44 * (See RFC-1075.) 45 * 46 * Written by David Waitzman, BBN Labs, August 1988. 47 * Modified by Steve Deering, Stanford, February 1989. 48 * 49 * MROUTING 1.1 50 */ 51 52#ifndef MROUTING 53int ip_mrtproto; /* for netstat only */ 54#else 55 56#include <sys/param.h> 57#include <sys/systm.h> 58#include <sys/errno.h> 59#include <sys/ioctl.h> 60#include <sys/malloc.h> 61#include <sys/mbuf.h> 62#include <sys/protosw.h> 63#include <sys/socket.h> 64#include <sys/socketvar.h> 65#include <sys/time.h> 66 67#include <net/if.h> 68#include <net/route.h> 69#include <net/raw_cb.h> 70 71#include <netinet/in.h> 72#include <netinet/in_systm.h> 73#include <netinet/ip.h> 74#include <netinet/in_pcb.h> 75#include <netinet/in_var.h> 76#include <netinet/ip_var.h> 77 78#include <netinet/igmp.h> 79#include <netinet/igmp_var.h> 80#include <netinet/ip_mroute.h> 81 82/* Static forwards */ 83static int ip_mrouter_init __P((struct socket *)); 84static int add_vif __P((struct vifctl *)); 85static int del_vif __P((vifi_t *vifip)); 86static int add_lgrp __P((struct lgrplctl *)); 87static int del_lgrp __P((struct lgrplctl *)); 88static int grplst_member __P((struct vif *, struct in_addr)); 89static u_long nethash __P((struct in_addr in)); 90static int add_mrt __P((struct mrtctl *)); 91static int del_mrt __P((struct in_addr *)); 92static struct mrt *mrtfind __P((struct in_addr)); 93static void phyint_send __P((struct mbuf *, struct vif *)); 94static void tunnel_send __P((struct mbuf *, struct vif *)); 95 96#define INSIZ sizeof(struct in_addr) 97#define same(a1, a2) (bcmp((caddr_t)(a1), (caddr_t)(a2), INSIZ) == 0) 98#define satosin(sa) ((struct sockaddr_in *)(sa)) 99 100/* 101 * Globals. All but ip_mrouter and ip_mrtproto could be static, 102 * except for netstat or debugging purposes. 103 */ 104struct socket *ip_mrouter = NULL; 105int ip_mrtproto = IGMP_DVMRP; /* for netstat only */ 106 107struct mrt *mrttable[MRTHASHSIZ]; 108struct vif viftable[MAXVIFS]; 109struct mrtstat mrtstat; 110 111/* 112 * Private variables. 113 */ 114static vifi_t numvifs = 0; 115static struct mrt *cached_mrt = NULL; 116static u_long cached_origin; 117static u_long cached_originmask; 118 119/* 120 * Handle DVMRP setsockopt commands to modify the multicast routing tables. 121 */ 122int 123ip_mrouter_cmd(cmd, so, m) 124 register int cmd; 125 register struct socket *so; 126 register struct mbuf *m; 127{ 128 register int error = 0; 129 130 if (cmd != DVMRP_INIT && so != ip_mrouter) 131 error = EACCES; 132 else switch (cmd) { 133 134 case DVMRP_INIT: 135 error = ip_mrouter_init(so); 136 break; 137 138 case DVMRP_DONE: 139 error = ip_mrouter_done(); 140 break; 141 142 case DVMRP_ADD_VIF: 143 if (m == NULL || m->m_len < sizeof(struct vifctl)) 144 error = EINVAL; 145 else 146 error = add_vif(mtod(m, struct vifctl *)); 147 break; 148 149 case DVMRP_DEL_VIF: 150 if (m == NULL || m->m_len < sizeof(short)) 151 error = EINVAL; 152 else 153 error = del_vif(mtod(m, vifi_t *)); 154 break; 155 156 case DVMRP_ADD_LGRP: 157 if (m == NULL || m->m_len < sizeof(struct lgrplctl)) 158 error = EINVAL; 159 else 160 error = add_lgrp(mtod(m, struct lgrplctl *)); 161 break; 162 163 case DVMRP_DEL_LGRP: 164 if (m == NULL || m->m_len < sizeof(struct lgrplctl)) 165 error = EINVAL; 166 else 167 error = del_lgrp(mtod(m, struct lgrplctl *)); 168 break; 169 170 case DVMRP_ADD_MRT: 171 if (m == NULL || m->m_len < sizeof(struct mrtctl)) 172 error = EINVAL; 173 else 174 error = add_mrt(mtod(m, struct mrtctl *)); 175 break; 176 177 case DVMRP_DEL_MRT: 178 if (m == NULL || m->m_len < sizeof(struct in_addr)) 179 error = EINVAL; 180 else 181 error = del_mrt(mtod(m, struct in_addr *)); 182 break; 183 184 default: 185 error = EOPNOTSUPP; 186 break; 187 } 188 return (error); 189} 190 191/* 192 * Enable multicast routing 193 */ 194static int 195ip_mrouter_init(so) 196 register struct socket *so; 197{ 198 if (so->so_type != SOCK_RAW || 199 so->so_proto->pr_protocol != IPPROTO_IGMP) 200 return (EOPNOTSUPP); 201 202 if (ip_mrouter != NULL) 203 return (EADDRINUSE); 204 205 ip_mrouter = so; 206 207 return (0); 208} 209 210/* 211 * Disable multicast routing 212 */ 213int 214ip_mrouter_done() 215{ 216 register vifi_t vifi; 217 register int i; 218 register struct ifnet *ifp; 219 register int s; 220 struct ifreq ifr; 221 222 s = splnet(); 223 224 /* 225 * For each phyint in use, free its local group list and 226 * disable promiscuous reception of all IP multicasts. 227 */ 228 for (vifi = 0; vifi < numvifs; vifi++) { 229 if (viftable[vifi].v_lcl_addr.s_addr != 0 && 230 !(viftable[vifi].v_flags & VIFF_TUNNEL)) { 231 if (viftable[vifi].v_lcl_grps) 232 free(viftable[vifi].v_lcl_grps, M_MRTABLE); 233 satosin(&ifr.ifr_addr)->sin_family = AF_INET; 234 satosin(&ifr.ifr_addr)->sin_addr.s_addr = INADDR_ANY; 235 ifp = viftable[vifi].v_ifp; 236 (*ifp->if_ioctl)(ifp, SIOCDELMULTI, (caddr_t)&ifr); 237 } 238 } 239 bzero((caddr_t)viftable, sizeof(viftable)); 240 numvifs = 0; 241 242 /* 243 * Free any multicast route entries. 244 */ 245 for (i = 0; i < MRTHASHSIZ; i++) 246 if (mrttable[i]) 247 free(mrttable[i], M_MRTABLE); 248 bzero((caddr_t)mrttable, sizeof(mrttable)); 249 cached_mrt = NULL; 250 251 ip_mrouter = NULL; 252 253 splx(s); 254 return (0); 255} 256 257/* 258 * Add a vif to the vif table 259 */ 260static int 261add_vif(vifcp) 262 register struct vifctl *vifcp; 263{ 264 register struct vif *vifp = viftable + vifcp->vifc_vifi; 265 register struct ifaddr *ifa; 266 register struct ifnet *ifp; 267 struct ifreq ifr; 268 register int error, s; 269 static struct sockaddr_in sin = { sizeof(sin), AF_INET }; 270 271 if (vifcp->vifc_vifi >= MAXVIFS) 272 return (EINVAL); 273 if (vifp->v_lcl_addr.s_addr != 0) 274 return (EADDRINUSE); 275 276 /* Find the interface with an address in AF_INET family */ 277 sin.sin_addr = vifcp->vifc_lcl_addr; 278 ifa = ifa_ifwithaddr((struct sockaddr *)&sin); 279 if (ifa == 0) 280 return (EADDRNOTAVAIL); 281 282 s = splnet(); 283 284 if (vifcp->vifc_flags & VIFF_TUNNEL) 285 vifp->v_rmt_addr = vifcp->vifc_rmt_addr; 286 else { 287 /* Make sure the interface supports multicast */ 288 ifp = ifa->ifa_ifp; 289 if ((ifp->if_flags & IFF_MULTICAST) == 0) { 290 splx(s); 291 return (EOPNOTSUPP); 292 } 293 /* 294 * Enable promiscuous reception of all IP multicasts 295 * from the interface. 296 */ 297 satosin(&ifr.ifr_addr)->sin_family = AF_INET; 298 satosin(&ifr.ifr_addr)->sin_addr.s_addr = INADDR_ANY; 299 error = (*ifp->if_ioctl)(ifp, SIOCADDMULTI, (caddr_t)&ifr); 300 if (error) { 301 splx(s); 302 return (error); 303 } 304 } 305 306 vifp->v_flags = vifcp->vifc_flags; 307 vifp->v_threshold = vifcp->vifc_threshold; 308 vifp->v_lcl_addr = vifcp->vifc_lcl_addr; 309 vifp->v_ifp = ifa->ifa_ifp; 310 311 /* Adjust numvifs up if the vifi is higher than numvifs */ 312 if (numvifs <= vifcp->vifc_vifi) 313 numvifs = vifcp->vifc_vifi + 1; 314 315 splx(s); 316 return (0); 317} 318 319/* 320 * Delete a vif from the vif table 321 */ 322static int 323del_vif(vifip) 324 register vifi_t *vifip; 325{ 326 register struct vif *vifp = viftable + *vifip; 327 register struct ifnet *ifp; 328 register int i, s; 329 struct ifreq ifr; 330 331 if (*vifip >= numvifs) 332 return (EINVAL); 333 if (vifp->v_lcl_addr.s_addr == 0) 334 return (EADDRNOTAVAIL); 335 336 s = splnet(); 337 338 if (!(vifp->v_flags & VIFF_TUNNEL)) { 339 if (vifp->v_lcl_grps) 340 free(vifp->v_lcl_grps, M_MRTABLE); 341 satosin(&ifr.ifr_addr)->sin_family = AF_INET; 342 satosin(&ifr.ifr_addr)->sin_addr.s_addr = INADDR_ANY; 343 ifp = vifp->v_ifp; 344 (*ifp->if_ioctl)(ifp, SIOCDELMULTI, (caddr_t)&ifr); 345 } 346 347 bzero((caddr_t)vifp, sizeof (*vifp)); 348 349 /* Adjust numvifs down */ 350 for (i = numvifs - 1; i >= 0; i--) 351 if (viftable[i].v_lcl_addr.s_addr != 0) 352 break; 353 numvifs = i + 1; 354 355 splx(s); 356 return (0); 357} 358 359/* 360 * Add the multicast group in the lgrpctl to the list of local multicast 361 * group memberships associated with the vif indexed by gcp->lgc_vifi. 362 */ 363static int 364add_lgrp(gcp) 365 register struct lgrplctl *gcp; 366{ 367 register struct vif *vifp; 368 register int s; 369 370 if (gcp->lgc_vifi >= numvifs) 371 return (EINVAL); 372 373 vifp = viftable + gcp->lgc_vifi; 374 if (vifp->v_lcl_addr.s_addr == 0 || (vifp->v_flags & VIFF_TUNNEL)) 375 return (EADDRNOTAVAIL); 376 377 /* If not enough space in existing list, allocate a larger one */ 378 s = splnet(); 379 if (vifp->v_lcl_grps_n + 1 >= vifp->v_lcl_grps_max) { 380 register int num; 381 register struct in_addr *ip; 382 383 num = vifp->v_lcl_grps_max; 384 if (num <= 0) 385 num = 32; /* initial number */ 386 else 387 num += num; /* double last number */ 388 ip = (struct in_addr *)malloc(num * sizeof(*ip), 389 M_MRTABLE, M_NOWAIT); 390 if (ip == NULL) { 391 splx(s); 392 return (ENOBUFS); 393 } 394 395 bzero((caddr_t)ip, num * sizeof(*ip)); /* XXX paranoid */ 396 bcopy((caddr_t)vifp->v_lcl_grps, (caddr_t)ip, 397 vifp->v_lcl_grps_n * sizeof(*ip)); 398 399 vifp->v_lcl_grps_max = num; 400 if (vifp->v_lcl_grps) 401 free(vifp->v_lcl_grps, M_MRTABLE); 402 vifp->v_lcl_grps = ip; 403 404 splx(s); 405 } 406 407 vifp->v_lcl_grps[vifp->v_lcl_grps_n++] = gcp->lgc_gaddr; 408 409 if (gcp->lgc_gaddr.s_addr == vifp->v_cached_group) 410 vifp->v_cached_result = 1; 411 412 splx(s); 413 return (0); 414} 415 416/* 417 * Delete the the local multicast group associated with the vif 418 * indexed by gcp->lgc_vifi. 419 */ 420 421static int 422del_lgrp(gcp) 423 register struct lgrplctl *gcp; 424{ 425 register struct vif *vifp; 426 register int i, error, s; 427 428 if (gcp->lgc_vifi >= numvifs) 429 return (EINVAL); 430 vifp = viftable + gcp->lgc_vifi; 431 if (vifp->v_lcl_addr.s_addr == 0 || (vifp->v_flags & VIFF_TUNNEL)) 432 return (EADDRNOTAVAIL); 433 434 s = splnet(); 435 436 if (gcp->lgc_gaddr.s_addr == vifp->v_cached_group) 437 vifp->v_cached_result = 0; 438 439 error = EADDRNOTAVAIL; 440 for (i = 0; i < vifp->v_lcl_grps_n; ++i) 441 if (same(&gcp->lgc_gaddr, &vifp->v_lcl_grps[i])) { 442 error = 0; 443 vifp->v_lcl_grps_n--; 444 bcopy((caddr_t)&vifp->v_lcl_grps[i + 1], 445 (caddr_t)&vifp->v_lcl_grps[i], 446 (vifp->v_lcl_grps_n - i) * sizeof(struct in_addr)); 447 error = 0; 448 break; 449 } 450 451 splx(s); 452 return (error); 453} 454 455/* 456 * Return 1 if gaddr is a member of the local group list for vifp. 457 */ 458static int 459grplst_member(vifp, gaddr) 460 register struct vif *vifp; 461 struct in_addr gaddr; 462{ 463 register int i, s; 464 register u_long addr; 465 466 mrtstat.mrts_grp_lookups++; 467 468 addr = gaddr.s_addr; 469 if (addr == vifp->v_cached_group) 470 return (vifp->v_cached_result); 471 472 mrtstat.mrts_grp_misses++; 473 474 for (i = 0; i < vifp->v_lcl_grps_n; ++i) 475 if (addr == vifp->v_lcl_grps[i].s_addr) { 476 s = splnet(); 477 vifp->v_cached_group = addr; 478 vifp->v_cached_result = 1; 479 splx(s); 480 return (1); 481 } 482 s = splnet(); 483 vifp->v_cached_group = addr; 484 vifp->v_cached_result = 0; 485 splx(s); 486 return (0); 487} 488 489/* 490 * A simple hash function: returns MRTHASHMOD of the low-order octet of 491 * the argument's network or subnet number. 492 */ 493static u_long 494nethash(in) 495 struct in_addr in; 496{ 497 register u_long n; 498 499 n = in_netof(in); 500 while ((n & 0xff) == 0) 501 n >>= 8; 502 return (MRTHASHMOD(n)); 503} 504 505/* 506 * Add an mrt entry 507 */ 508static int 509add_mrt(mrtcp) 510 register struct mrtctl *mrtcp; 511{ 512 struct mrt *rt; 513 u_long hash; 514 int s; 515 516 if (rt = mrtfind(mrtcp->mrtc_origin)) { 517 /* Just update the route */ 518 s = splnet(); 519 rt->mrt_parent = mrtcp->mrtc_parent; 520 VIFM_COPY(mrtcp->mrtc_children, rt->mrt_children); 521 VIFM_COPY(mrtcp->mrtc_leaves, rt->mrt_leaves); 522 splx(s); 523 return (0); 524 } 525 526 s = splnet(); 527 528 rt = (struct mrt *)malloc(sizeof(*rt), M_MRTABLE, M_NOWAIT); 529 if (rt == NULL) { 530 splx(s); 531 return (ENOBUFS); 532 } 533 534 /* 535 * insert new entry at head of hash chain 536 */ 537 rt->mrt_origin = mrtcp->mrtc_origin; 538 rt->mrt_originmask = mrtcp->mrtc_originmask; 539 rt->mrt_parent = mrtcp->mrtc_parent; 540 VIFM_COPY(mrtcp->mrtc_children, rt->mrt_children); 541 VIFM_COPY(mrtcp->mrtc_leaves, rt->mrt_leaves); 542 /* link into table */ 543 hash = nethash(mrtcp->mrtc_origin); 544 rt->mrt_next = mrttable[hash]; 545 mrttable[hash] = rt; 546 547 splx(s); 548 return (0); 549} 550 551/* 552 * Delete an mrt entry 553 */ 554static int 555del_mrt(origin) 556 register struct in_addr *origin; 557{ 558 register struct mrt *rt, *prev_rt; 559 register u_long hash = nethash(*origin); 560 register int s; 561 562 for (prev_rt = rt = mrttable[hash]; rt; prev_rt = rt, rt = rt->mrt_next) 563 if (origin->s_addr == rt->mrt_origin.s_addr) 564 break; 565 if (!rt) 566 return (ESRCH); 567 568 s = splnet(); 569 570 if (rt == cached_mrt) 571 cached_mrt = NULL; 572 573 if (prev_rt == rt) 574 mrttable[hash] = rt->mrt_next; 575 else 576 prev_rt->mrt_next = rt->mrt_next; 577 free(rt, M_MRTABLE); 578 579 splx(s); 580 return (0); 581} 582 583/* 584 * Find a route for a given origin IP address. 585 */ 586static struct mrt * 587mrtfind(origin) 588 struct in_addr origin; 589{ 590 register struct mrt *rt; 591 register u_int hash; 592 register int s; 593 594 mrtstat.mrts_mrt_lookups++; 595 596 if (cached_mrt != NULL && 597 (origin.s_addr & cached_originmask) == cached_origin) 598 return (cached_mrt); 599 600 mrtstat.mrts_mrt_misses++; 601 602 hash = nethash(origin); 603 for (rt = mrttable[hash]; rt; rt = rt->mrt_next) 604 if ((origin.s_addr & rt->mrt_originmask.s_addr) == 605 rt->mrt_origin.s_addr) { 606 s = splnet(); 607 cached_mrt = rt; 608 cached_origin = rt->mrt_origin.s_addr; 609 cached_originmask = rt->mrt_originmask.s_addr; 610 splx(s); 611 return (rt); 612 } 613 return (NULL); 614} 615 616/* 617 * IP multicast forwarding function. This function assumes that the packet 618 * pointed to by "ip" has arrived on (or is about to be sent to) the interface 619 * pointed to by "ifp", and the packet is to be relayed to other networks 620 * that have members of the packet's destination IP multicast group. 621 * 622 * The packet is returned unscathed to the caller, unless it is tunneled 623 * or erroneous, in which case a non-zero return value tells the caller to 624 * discard it. 625 */ 626 627#define IP_HDR_LEN 20 /* # bytes of fixed IP header (excluding options) */ 628#define TUNNEL_LEN 12 /* # bytes of IP option for tunnel encapsulation */ 629 630int 631ip_mforward(m, ifp) 632 register struct mbuf *m; 633 register struct ifnet *ifp; 634{ 635 register struct ip *ip = mtod(m, struct ip *); 636 register struct mrt *rt; 637 register struct vif *vifp; 638 register int vifi; 639 register u_char *ipoptions; 640 u_long tunnel_src; 641 642 if (ip->ip_hl < (IP_HDR_LEN + TUNNEL_LEN) >> 2 || 643 (ipoptions = (u_char *)(ip + 1))[1] != IPOPT_LSRR ) { 644 /* 645 * Packet arrived via a physical interface. 646 */ 647 tunnel_src = 0; 648 } else { 649 /* 650 * Packet arrived through a tunnel. 651 * 652 * A tunneled packet has a single NOP option and a 653 * two-element loose-source-and-record-route (LSRR) 654 * option immediately following the fixed-size part of 655 * the IP header. At this point in processing, the IP 656 * header should contain the following IP addresses: 657 * 658 * original source - in the source address field 659 * destination group - in the destination address field 660 * remote tunnel end-point - in the first element of LSRR 661 * one of this host's addrs - in the second element of LSRR 662 * 663 * NOTE: RFC-1075 would have the original source and 664 * remote tunnel end-point addresses swapped. However, 665 * that could cause delivery of ICMP error messages to 666 * innocent applications on intermediate routing 667 * hosts! Therefore, we hereby change the spec. 668 */ 669 670 /* 671 * Verify that the tunnel options are well-formed. 672 */ 673 if (ipoptions[0] != IPOPT_NOP || 674 ipoptions[2] != 11 || /* LSRR option length */ 675 ipoptions[3] != 12 || /* LSRR address pointer */ 676 (tunnel_src = *(u_long *)(&ipoptions[4])) == 0) { 677 mrtstat.mrts_bad_tunnel++; 678 return (1); 679 } 680 681 /* 682 * Delete the tunnel options from the packet. 683 */ 684 ovbcopy((caddr_t)(ipoptions + TUNNEL_LEN), (caddr_t)ipoptions, 685 (unsigned)(m->m_len - (IP_HDR_LEN + TUNNEL_LEN))); 686 m->m_len -= TUNNEL_LEN; 687 ip->ip_len -= TUNNEL_LEN; 688 ip->ip_hl -= TUNNEL_LEN >> 2; 689 } 690 691 /* 692 * Don't forward a packet with time-to-live of zero or one, 693 * or a packet destined to a local-only group. 694 */ 695 if (ip->ip_ttl <= 1 || 696 ntohl(ip->ip_dst.s_addr) <= INADDR_MAX_LOCAL_GROUP) 697 return ((int)tunnel_src); 698 699 /* 700 * Don't forward if we don't have a route for the packet's origin. 701 */ 702 if (!(rt = mrtfind(ip->ip_src))) { 703 mrtstat.mrts_no_route++; 704 return ((int)tunnel_src); 705 } 706 707 /* 708 * Don't forward if it didn't arrive from the parent vif for its origin. 709 */ 710 vifi = rt->mrt_parent; 711 if (tunnel_src == 0 ) { 712 if ((viftable[vifi].v_flags & VIFF_TUNNEL) || 713 viftable[vifi].v_ifp != ifp ) 714 return ((int)tunnel_src); 715 } else { 716 if (!(viftable[vifi].v_flags & VIFF_TUNNEL) || 717 viftable[vifi].v_rmt_addr.s_addr != tunnel_src ) 718 return ((int)tunnel_src); 719 } 720 721 /* 722 * For each vif, decide if a copy of the packet should be forwarded. 723 * Forward if: 724 * - the ttl exceeds the vif's threshold AND 725 * - the vif is a child in the origin's route AND 726 * - ( the vif is not a leaf in the origin's route OR 727 * the destination group has members on the vif ) 728 * 729 * (This might be speeded up with some sort of cache -- someday.) 730 */ 731 for (vifp = viftable, vifi = 0; vifi < numvifs; vifp++, vifi++) { 732 if (ip->ip_ttl > vifp->v_threshold && 733 VIFM_ISSET(vifi, rt->mrt_children) && 734 (!VIFM_ISSET(vifi, rt->mrt_leaves) || 735 grplst_member(vifp, ip->ip_dst))) { 736 if (vifp->v_flags & VIFF_TUNNEL) 737 tunnel_send(m, vifp); 738 else 739 phyint_send(m, vifp); 740 } 741 } 742 743 return ((int)tunnel_src); 744} 745 746static void 747phyint_send(m, vifp) 748 register struct mbuf *m; 749 register struct vif *vifp; 750{ 751 register struct ip *ip = mtod(m, struct ip *); 752 register struct mbuf *mb_copy; 753 register struct ip_moptions *imo; 754 register int error; 755 struct ip_moptions simo; 756 757 mb_copy = m_copy(m, 0, M_COPYALL); 758 if (mb_copy == NULL) 759 return; 760 761 imo = &simo; 762 imo->imo_multicast_ifp = vifp->v_ifp; 763 imo->imo_multicast_ttl = ip->ip_ttl - 1; 764 imo->imo_multicast_loop = 1; 765 766 error = ip_output(mb_copy, NULL, NULL, IP_FORWARDING, imo); 767} 768 769static void 770tunnel_send(m, vifp) 771 register struct mbuf *m; 772 register struct vif *vifp; 773{ 774 register struct ip *ip = mtod(m, struct ip *); 775 register struct mbuf *mb_copy, *mb_opts; 776 register struct ip *ip_copy; 777 register int error; 778 register u_char *cp; 779 780 /* 781 * Make sure that adding the tunnel options won't exceed the 782 * maximum allowed number of option bytes. 783 */ 784 if (ip->ip_hl > (60 - TUNNEL_LEN) >> 2) { 785 mrtstat.mrts_cant_tunnel++; 786 return; 787 } 788 789 /* 790 * Get a private copy of the IP header so that changes to some 791 * of the IP fields don't damage the original header, which is 792 * examined later in ip_input.c. 793 */ 794 mb_copy = m_copy(m, IP_HDR_LEN, M_COPYALL); 795 if (mb_copy == NULL) 796 return; 797 MGETHDR(mb_opts, M_DONTWAIT, MT_HEADER); 798 if (mb_opts == NULL) { 799 m_freem(mb_copy); 800 return; 801 } 802 /* 803 * Make mb_opts be the new head of the packet chain. 804 * Any options of the packet were left in the old packet chain head 805 */ 806 mb_opts->m_next = mb_copy; 807 mb_opts->m_len = IP_HDR_LEN + TUNNEL_LEN; 808 mb_opts->m_data += MSIZE - mb_opts->m_len; 809 810 ip_copy = mtod(mb_opts, struct ip *); 811 /* 812 * Copy the base ip header to the new head mbuf. 813 */ 814 *ip_copy = *ip; 815 ip_copy->ip_ttl--; 816 ip_copy->ip_dst = vifp->v_rmt_addr; /* remote tunnel end-point */ 817 /* 818 * Adjust the ip header length to account for the tunnel options. 819 */ 820 ip_copy->ip_hl += TUNNEL_LEN >> 2; 821 ip_copy->ip_len += TUNNEL_LEN; 822 /* 823 * Add the NOP and LSRR after the base ip header 824 */ 825 cp = (u_char *)(ip_copy + 1); 826 *cp++ = IPOPT_NOP; 827 *cp++ = IPOPT_LSRR; 828 *cp++ = 11; /* LSRR option length */ 829 *cp++ = 8; /* LSSR pointer to second element */ 830 *(u_long*)cp = vifp->v_lcl_addr.s_addr; /* local tunnel end-point */ 831 cp += 4; 832 *(u_long*)cp = ip->ip_dst.s_addr; /* destination group */ 833 834 error = ip_output(mb_opts, NULL, NULL, IP_FORWARDING, NULL); 835} 836#endif 837