IGMP.C
上传用户:tjbfgc
上传日期:2013-03-31
资源大小:140k
文件大小:8k
源码类别:

网络编程

开发平台:

C/C++

  1. /*
  2.  * Copyright (c) 1988 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.  * @(#)igmp.c 8.1 (Berkeley) 7/19/93
  38.  */
  39. /* Internet Group Management Protocol (IGMP) routines. */
  40. #include <sys/param.h>
  41. #include <sys/mbuf.h>
  42. #include <sys/socket.h>
  43. #include <sys/protosw.h>
  44. #include <net/if.h>
  45. #include <net/route.h>
  46. #include <netinet/in.h>
  47. #include <netinet/in_var.h>
  48. #include <netinet/in_systm.h>
  49. #include <netinet/ip.h>
  50. #include <netinet/ip_var.h>
  51. #include <netinet/igmp.h>
  52. #include <netinet/igmp_var.h>
  53. extern struct ifnet loif;
  54. static int igmp_timers_are_running = 0;
  55. static u_long igmp_all_hosts_group;
  56. static void igmp_sendreport __P((struct in_multi *));
  57. void
  58. igmp_init()
  59. {
  60. /*
  61.  * To avoid byte-swapping the same value over and over again.
  62.  */
  63. igmp_all_hosts_group = htonl(INADDR_ALLHOSTS_GROUP);
  64. }
  65. void
  66. igmp_input(m, iphlen)
  67. register struct mbuf *m;
  68. register int iphlen;
  69. {
  70. register struct igmp *igmp;
  71. register struct ip *ip;
  72. register int igmplen;
  73. register struct ifnet *ifp = m->m_pkthdr.rcvif;
  74. register int minlen;
  75. register struct in_multi *inm;
  76. register struct in_ifaddr *ia;
  77. struct in_multistep step;
  78. ++igmpstat.igps_rcv_total;
  79. ip = mtod(m, struct ip *);
  80. igmplen = ip->ip_len;
  81. /*
  82.  * Validate lengths
  83.  */
  84. if (igmplen < IGMP_MINLEN) {
  85. ++igmpstat.igps_rcv_tooshort;
  86. m_freem(m);
  87. return;
  88. }
  89. minlen = iphlen + IGMP_MINLEN;
  90. if ((m->m_flags & M_EXT || m->m_len < minlen) &&
  91.     (m = m_pullup(m, minlen)) == 0) {
  92. ++igmpstat.igps_rcv_tooshort;
  93. return;
  94. }
  95. /*
  96.  * Validate checksum
  97.  */
  98. m->m_data += iphlen;
  99. m->m_len -= iphlen;
  100. igmp = mtod(m, struct igmp *);
  101. if (in_cksum(m, igmplen)) {
  102. ++igmpstat.igps_rcv_badsum;
  103. m_freem(m);
  104. return;
  105. }
  106. m->m_data -= iphlen;
  107. m->m_len += iphlen;
  108. ip = mtod(m, struct ip *);
  109. switch (igmp->igmp_type) {
  110. case IGMP_HOST_MEMBERSHIP_QUERY:
  111. ++igmpstat.igps_rcv_queries;
  112. if (ifp == &loif)
  113. break;
  114. if (ip->ip_dst.s_addr != igmp_all_hosts_group) {
  115. ++igmpstat.igps_rcv_badqueries;
  116. m_freem(m);
  117. return;
  118. }
  119. /*
  120.  * Start the timers in all of our membership records for
  121.  * the interface on which the query arrived, except those
  122.  * that are already running and those that belong to the
  123.  * "all-hosts" group.
  124.  */
  125. IN_FIRST_MULTI(step, inm);
  126. while (inm != NULL) {
  127. if (inm->inm_ifp == ifp && inm->inm_timer == 0 &&
  128.     inm->inm_addr.s_addr != igmp_all_hosts_group) {
  129. inm->inm_timer =
  130.     IGMP_RANDOM_DELAY(inm->inm_addr);
  131. igmp_timers_are_running = 1;
  132. }
  133. IN_NEXT_MULTI(step, inm);
  134. }
  135. break;
  136. case IGMP_HOST_MEMBERSHIP_REPORT:
  137. ++igmpstat.igps_rcv_reports;
  138. if (ifp == &loif)
  139. break;
  140. if (!IN_MULTICAST(ntohl(igmp->igmp_group.s_addr)) ||
  141.     igmp->igmp_group.s_addr != ip->ip_dst.s_addr) {
  142. ++igmpstat.igps_rcv_badreports;
  143. m_freem(m);
  144. return;
  145. }
  146. /*
  147.  * KLUDGE: if the IP source address of the report has an
  148.  * unspecified (i.e., zero) subnet number, as is allowed for
  149.  * a booting host, replace it with the correct subnet number
  150.  * so that a process-level multicast routing demon can
  151.  * determine which subnet it arrived from.  This is necessary
  152.  * to compensate for the lack of any way for a process to
  153.  * determine the arrival interface of an incoming packet.
  154.  */
  155. if ((ntohl(ip->ip_src.s_addr) & IN_CLASSA_NET) == 0) {
  156. IFP_TO_IA(ifp, ia);
  157. if (ia) ip->ip_src.s_addr = htonl(ia->ia_subnet);
  158. }
  159. /*
  160.  * If we belong to the group being reported, stop
  161.  * our timer for that group.
  162.  */
  163. IN_LOOKUP_MULTI(igmp->igmp_group, ifp, inm);
  164. if (inm != NULL) {
  165. inm->inm_timer = 0;
  166. ++igmpstat.igps_rcv_ourreports;
  167. }
  168. break;
  169. }
  170. /*
  171.  * Pass all valid IGMP packets up to any process(es) listening
  172.  * on a raw IGMP socket.
  173.  */
  174. rip_input(m);
  175. }
  176. void
  177. igmp_joingroup(inm)
  178. struct in_multi *inm;
  179. {
  180. register int s = splnet();
  181. if (inm->inm_addr.s_addr == igmp_all_hosts_group ||
  182.     inm->inm_ifp == &loif)
  183. inm->inm_timer = 0;
  184. else {
  185. igmp_sendreport(inm);
  186. inm->inm_timer = IGMP_RANDOM_DELAY(inm->inm_addr);
  187. igmp_timers_are_running = 1;
  188. }
  189. splx(s);
  190. }
  191. void
  192. igmp_leavegroup(inm)
  193. struct in_multi *inm;
  194. {
  195. /*
  196.  * No action required on leaving a group.
  197.  */
  198. }
  199. void
  200. igmp_fasttimo()
  201. {
  202. register struct in_multi *inm;
  203. register int s;
  204. struct in_multistep step;
  205. /*
  206.  * Quick check to see if any work needs to be done, in order
  207.  * to minimize the overhead of fasttimo processing.
  208.  */
  209. if (!igmp_timers_are_running)
  210. return;
  211. s = splnet();
  212. igmp_timers_are_running = 0;
  213. IN_FIRST_MULTI(step, inm);
  214. while (inm != NULL) {
  215. if (inm->inm_timer == 0) {
  216. /* do nothing */
  217. } else if (--inm->inm_timer == 0) {
  218. igmp_sendreport(inm);
  219. } else {
  220. igmp_timers_are_running = 1;
  221. }
  222. IN_NEXT_MULTI(step, inm);
  223. }
  224. splx(s);
  225. }
  226. static void
  227. igmp_sendreport(inm)
  228. register struct in_multi *inm;
  229. {
  230. register struct mbuf *m;
  231. register struct igmp *igmp;
  232. register struct ip *ip;
  233. register struct ip_moptions *imo;
  234. struct ip_moptions simo;
  235. MGETHDR(m, M_DONTWAIT, MT_HEADER);
  236. if (m == NULL)
  237. return;
  238. /*
  239.  * Assume max_linkhdr + sizeof(struct ip) + IGMP_MINLEN
  240.  * is smaller than mbuf size returned by MGETHDR.
  241.  */
  242. m->m_data += max_linkhdr;
  243. m->m_len = sizeof(struct ip) + IGMP_MINLEN;
  244. m->m_pkthdr.len = sizeof(struct ip) + IGMP_MINLEN;
  245. ip = mtod(m, struct ip *);
  246. ip->ip_tos = 0;
  247. ip->ip_len = sizeof(struct ip) + IGMP_MINLEN;
  248. ip->ip_off = 0;
  249. ip->ip_p = IPPROTO_IGMP;
  250. ip->ip_src.s_addr = INADDR_ANY;
  251. ip->ip_dst = inm->inm_addr;
  252. igmp = (struct igmp *)(ip + 1);
  253. igmp->igmp_type = IGMP_HOST_MEMBERSHIP_REPORT;
  254. igmp->igmp_code = 0;
  255. igmp->igmp_group = inm->inm_addr;
  256. igmp->igmp_cksum = 0;
  257. igmp->igmp_cksum = in_cksum(m, IGMP_MINLEN);
  258. imo = &simo;
  259. bzero((caddr_t)imo, sizeof(*imo));
  260. imo->imo_multicast_ifp = inm->inm_ifp;
  261. imo->imo_multicast_ttl = 1;
  262. /*
  263.  * Request loopback of the report if we are acting as a multicast
  264.  * router, so that the process-level routing demon can hear it.
  265.  */
  266. #ifdef MROUTING
  267.     {
  268. extern struct socket *ip_mrouter;
  269. imo->imo_multicast_loop = (ip_mrouter != NULL);
  270.     }
  271. #endif
  272. ip_output(m, NULL, NULL, 0, imo);
  273. ++igmpstat.igps_snd_reports;
  274. }