|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. ! 3: * ! 4: * @APPLE_LICENSE_HEADER_START@ ! 5: * ! 6: * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights ! 7: * Reserved. This file contains Original Code and/or Modifications of ! 8: * Original Code as defined in and that are subject to the Apple Public ! 9: * Source License Version 1.1 (the "License"). You may not use this file ! 10: * except in compliance with the License. Please obtain a copy of the ! 11: * License at http://www.apple.com/publicsource and read it before using ! 12: * this file. ! 13: * ! 14: * The Original Code and all software distributed under the License are ! 15: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER ! 16: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, ! 17: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, ! 18: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the ! 19: * License for the specific language governing rights and limitations ! 20: * under the License. ! 21: * ! 22: * @APPLE_LICENSE_HEADER_END@ ! 23: */ ! 24: ! 25: /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */ ! 26: /* ! 27: * Copyright (c) 1988 Stephen Deering. ! 28: * Copyright (c) 1992, 1993 ! 29: * The Regents of the University of California. All rights reserved. ! 30: * ! 31: * This code is derived from software contributed to Berkeley by ! 32: * Stephen Deering of Stanford University. ! 33: * ! 34: * Redistribution and use in source and binary forms, with or without ! 35: * modification, are permitted provided that the following conditions ! 36: * are met: ! 37: * 1. Redistributions of source code must retain the above copyright ! 38: * notice, this list of conditions and the following disclaimer. ! 39: * 2. Redistributions in binary form must reproduce the above copyright ! 40: * notice, this list of conditions and the following disclaimer in the ! 41: * documentation and/or other materials provided with the distribution. ! 42: * 3. All advertising materials mentioning features or use of this software ! 43: * must display the following acknowledgement: ! 44: * This product includes software developed by the University of ! 45: * California, Berkeley and its contributors. ! 46: * 4. Neither the name of the University nor the names of its contributors ! 47: * may be used to endorse or promote products derived from this software ! 48: * without specific prior written permission. ! 49: * ! 50: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ! 51: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ! 52: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ! 53: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE ! 54: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ! 55: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ! 56: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ! 57: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ! 58: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ! 59: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ! 60: * SUCH DAMAGE. ! 61: * ! 62: * @(#)igmp.c 8.2 (Berkeley) 5/3/95 ! 63: */ ! 64: ! 65: /* Internet Group Management Protocol (IGMP) routines. */ ! 66: ! 67: ! 68: #include <sys/param.h> ! 69: #include <sys/mbuf.h> ! 70: #include <sys/socket.h> ! 71: #include <sys/protosw.h> ! 72: ! 73: #include <kernserv/machine/spl.h> ! 74: ! 75: #include <net/if.h> ! 76: #include <net/route.h> ! 77: ! 78: #include <netinet/in.h> ! 79: #include <netinet/in_var.h> ! 80: #include <netinet/in_systm.h> ! 81: #include <netinet/ip.h> ! 82: #include <netinet/ip_var.h> ! 83: #include <netinet/igmp.h> ! 84: #include <netinet/igmp_var.h> ! 85: ! 86: extern struct ifnet loif; ! 87: ! 88: struct igmpstat igmpstat; ! 89: ! 90: static int igmp_timers_are_running = 0; ! 91: static u_long igmp_all_hosts_group; ! 92: ! 93: static void igmp_sendreport __P((struct in_multi *)); ! 94: ! 95: void ! 96: igmp_init() ! 97: { ! 98: /* ! 99: * To avoid byte-swapping the same value over and over again. ! 100: */ ! 101: igmp_all_hosts_group = htonl(INADDR_ALLHOSTS_GROUP); ! 102: } ! 103: ! 104: void ! 105: igmp_input(m, iphlen) ! 106: register struct mbuf *m; ! 107: register int iphlen; ! 108: { ! 109: register struct igmp *igmp; ! 110: register struct ip *ip; ! 111: register int igmplen; ! 112: register struct ifnet *ifp = m->m_pkthdr.rcvif; ! 113: register int minlen; ! 114: register struct in_multi *inm; ! 115: register struct in_ifaddr *ia; ! 116: struct in_multistep step; ! 117: ! 118: ++igmpstat.igps_rcv_total; ! 119: ! 120: ip = mtod(m, struct ip *); ! 121: igmplen = ip->ip_len; ! 122: ! 123: /* ! 124: * Validate lengths ! 125: */ ! 126: if (igmplen < IGMP_MINLEN) { ! 127: ++igmpstat.igps_rcv_tooshort; ! 128: m_freem(m); ! 129: return; ! 130: } ! 131: minlen = iphlen + IGMP_MINLEN; ! 132: if ((m->m_flags & M_EXT || m->m_len < minlen) && ! 133: (m = m_pullup(m, minlen)) == 0) { ! 134: ++igmpstat.igps_rcv_tooshort; ! 135: return; ! 136: } ! 137: ! 138: /* ! 139: * Validate checksum ! 140: */ ! 141: m->m_data += iphlen; ! 142: m->m_len -= iphlen; ! 143: igmp = mtod(m, struct igmp *); ! 144: if (in_cksum(m, igmplen)) { ! 145: ++igmpstat.igps_rcv_badsum; ! 146: m_freem(m); ! 147: return; ! 148: } ! 149: m->m_data -= iphlen; ! 150: m->m_len += iphlen; ! 151: ip = mtod(m, struct ip *); ! 152: ! 153: switch (igmp->igmp_type) { ! 154: ! 155: case IGMP_HOST_MEMBERSHIP_QUERY: ! 156: ++igmpstat.igps_rcv_queries; ! 157: ! 158: if (ifp == &loif) ! 159: break; ! 160: ! 161: if (ip->ip_dst.s_addr != igmp_all_hosts_group) { ! 162: ++igmpstat.igps_rcv_badqueries; ! 163: m_freem(m); ! 164: return; ! 165: } ! 166: ! 167: /* ! 168: * Start the timers in all of our membership records for ! 169: * the interface on which the query arrived, except those ! 170: * that are already running and those that belong to the ! 171: * "all-hosts" group. ! 172: */ ! 173: IN_FIRST_MULTI(step, inm); ! 174: while (inm != NULL) { ! 175: if (inm->inm_ifp == ifp && inm->inm_timer == 0 && ! 176: inm->inm_addr.s_addr != igmp_all_hosts_group) { ! 177: inm->inm_timer = ! 178: IGMP_RANDOM_DELAY(inm->inm_addr); ! 179: igmp_timers_are_running = 1; ! 180: } ! 181: IN_NEXT_MULTI(step, inm); ! 182: } ! 183: ! 184: break; ! 185: ! 186: case IGMP_HOST_MEMBERSHIP_REPORT: ! 187: ++igmpstat.igps_rcv_reports; ! 188: ! 189: if (ifp == &loif) ! 190: break; ! 191: ! 192: if (!IN_MULTICAST(ntohl(igmp->igmp_group.s_addr)) || ! 193: igmp->igmp_group.s_addr != ip->ip_dst.s_addr) { ! 194: ++igmpstat.igps_rcv_badreports; ! 195: m_freem(m); ! 196: return; ! 197: } ! 198: ! 199: /* ! 200: * KLUDGE: if the IP source address of the report has an ! 201: * unspecified (i.e., zero) subnet number, as is allowed for ! 202: * a booting host, replace it with the correct subnet number ! 203: * so that a process-level multicast routing demon can ! 204: * determine which subnet it arrived from. This is necessary ! 205: * to compensate for the lack of any way for a process to ! 206: * determine the arrival interface of an incoming packet. ! 207: */ ! 208: if ((ntohl(ip->ip_src.s_addr) & IN_CLASSA_NET) == 0) { ! 209: IFP_TO_IA(ifp, ia); ! 210: if (ia) ip->ip_src.s_addr = htonl(ia->ia_subnet); ! 211: } ! 212: ! 213: /* ! 214: * If we belong to the group being reported, stop ! 215: * our timer for that group. ! 216: */ ! 217: IN_LOOKUP_MULTI(igmp->igmp_group, ifp, inm); ! 218: if (inm != NULL) { ! 219: inm->inm_timer = 0; ! 220: ++igmpstat.igps_rcv_ourreports; ! 221: } ! 222: ! 223: break; ! 224: } ! 225: ! 226: /* ! 227: * Pass all valid IGMP packets up to any process(es) listening ! 228: * on a raw IGMP socket. ! 229: */ ! 230: rip_input(m); ! 231: } ! 232: ! 233: void ! 234: igmp_joingroup(inm) ! 235: struct in_multi *inm; ! 236: { ! 237: register int s = splnet(); ! 238: ! 239: if (inm->inm_addr.s_addr == igmp_all_hosts_group || ! 240: inm->inm_ifp == &loif) ! 241: inm->inm_timer = 0; ! 242: else { ! 243: igmp_sendreport(inm); ! 244: inm->inm_timer = IGMP_RANDOM_DELAY(inm->inm_addr); ! 245: igmp_timers_are_running = 1; ! 246: } ! 247: splx(s); ! 248: } ! 249: ! 250: void ! 251: igmp_leavegroup(inm) ! 252: struct in_multi *inm; ! 253: { ! 254: /* ! 255: * No action required on leaving a group. ! 256: */ ! 257: } ! 258: ! 259: void ! 260: igmp_fasttimo() ! 261: { ! 262: register struct in_multi *inm; ! 263: register int s; ! 264: struct in_multistep step; ! 265: ! 266: /* ! 267: * Quick check to see if any work needs to be done, in order ! 268: * to minimize the overhead of fasttimo processing. ! 269: */ ! 270: if (!igmp_timers_are_running) ! 271: return; ! 272: ! 273: s = splnet(); ! 274: igmp_timers_are_running = 0; ! 275: IN_FIRST_MULTI(step, inm); ! 276: while (inm != NULL) { ! 277: if (inm->inm_timer == 0) { ! 278: /* do nothing */ ! 279: } else if (--inm->inm_timer == 0) { ! 280: igmp_sendreport(inm); ! 281: } else { ! 282: igmp_timers_are_running = 1; ! 283: } ! 284: IN_NEXT_MULTI(step, inm); ! 285: } ! 286: splx(s); ! 287: } ! 288: ! 289: static void ! 290: igmp_sendreport(inm) ! 291: register struct in_multi *inm; ! 292: { ! 293: register struct mbuf *m; ! 294: register struct igmp *igmp; ! 295: register struct ip *ip; ! 296: register struct ip_moptions *imo; ! 297: struct ip_moptions simo; ! 298: ! 299: MGETHDR(m, M_DONTWAIT, MT_HEADER); ! 300: if (m == NULL) ! 301: return; ! 302: /* ! 303: * Assume max_linkhdr + sizeof(struct ip) + IGMP_MINLEN ! 304: * is smaller than mbuf size returned by MGETHDR. ! 305: */ ! 306: m->m_data += max_linkhdr; ! 307: m->m_len = sizeof(struct ip) + IGMP_MINLEN; ! 308: m->m_pkthdr.len = sizeof(struct ip) + IGMP_MINLEN; ! 309: ! 310: ip = mtod(m, struct ip *); ! 311: ip->ip_tos = 0; ! 312: ip->ip_len = sizeof(struct ip) + IGMP_MINLEN; ! 313: ip->ip_off = 0; ! 314: ip->ip_p = IPPROTO_IGMP; ! 315: ip->ip_src.s_addr = INADDR_ANY; ! 316: ip->ip_dst = inm->inm_addr; ! 317: ! 318: m->m_data += sizeof(struct ip); ! 319: m->m_len -= sizeof(struct ip); ! 320: igmp = mtod(m, struct igmp *); ! 321: igmp->igmp_type = IGMP_HOST_MEMBERSHIP_REPORT; ! 322: igmp->igmp_code = 0; ! 323: igmp->igmp_group = inm->inm_addr; ! 324: igmp->igmp_cksum = 0; ! 325: igmp->igmp_cksum = in_cksum(m, IGMP_MINLEN); ! 326: m->m_data -= sizeof(struct ip); ! 327: m->m_len += sizeof(struct ip); ! 328: ! 329: imo = &simo; ! 330: bzero((caddr_t)imo, sizeof(*imo)); ! 331: imo->imo_multicast_ifp = inm->inm_ifp; ! 332: imo->imo_multicast_ttl = 1; ! 333: /* ! 334: * Request loopback of the report if we are acting as a multicast ! 335: * router, so that the process-level routing demon can hear it. ! 336: */ ! 337: #if MROUTING ! 338: { ! 339: extern struct socket *ip_mrouter; ! 340: imo->imo_multicast_loop = (ip_mrouter != NULL); ! 341: } ! 342: #endif ! 343: ip_output(m, NULL, NULL, 0, imo); ! 344: ! 345: ++igmpstat.igps_snd_reports; ! 346: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.