igmp.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693
  1. /* $OpenBSD: igmp.c,v 1.49 2015/06/16 11:09:40 mpi Exp $ */
  2. /* $NetBSD: igmp.c,v 1.15 1996/02/13 23:41:25 christos Exp $ */
  3. /*
  4. * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
  5. * All rights reserved.
  6. *
  7. * Redistribution and use in source and binary forms, with or without
  8. * modification, are permitted provided that the following conditions
  9. * are met:
  10. * 1. Redistributions of source code must retain the above copyright
  11. * notice, this list of conditions and the following disclaimer.
  12. * 2. Redistributions in binary form must reproduce the above copyright
  13. * notice, this list of conditions and the following disclaimer in the
  14. * documentation and/or other materials provided with the distribution.
  15. * 3. Neither the name of the project nor the names of its contributors
  16. * may be used to endorse or promote products derived from this software
  17. * without specific prior written permission.
  18. *
  19. * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
  20. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  21. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  22. * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
  23. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  24. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  25. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  26. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  27. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  28. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  29. * SUCH DAMAGE.
  30. */
  31. /*
  32. * Copyright (c) 1988 Stephen Deering.
  33. * Copyright (c) 1992, 1993
  34. * The Regents of the University of California. All rights reserved.
  35. *
  36. * This code is derived from software contributed to Berkeley by
  37. * Stephen Deering of Stanford University.
  38. *
  39. * Redistribution and use in source and binary forms, with or without
  40. * modification, are permitted provided that the following conditions
  41. * are met:
  42. * 1. Redistributions of source code must retain the above copyright
  43. * notice, this list of conditions and the following disclaimer.
  44. * 2. Redistributions in binary form must reproduce the above copyright
  45. * notice, this list of conditions and the following disclaimer in the
  46. * documentation and/or other materials provided with the distribution.
  47. * 3. Neither the name of the University nor the names of its contributors
  48. * may be used to endorse or promote products derived from this software
  49. * without specific prior written permission.
  50. *
  51. * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  52. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  53. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  54. * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  55. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  56. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  57. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  58. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  59. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  60. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  61. * SUCH DAMAGE.
  62. *
  63. * @(#)igmp.c 8.2 (Berkeley) 5/3/95
  64. */
  65. /*
  66. * Internet Group Management Protocol (IGMP) routines.
  67. *
  68. * Written by Steve Deering, Stanford, May 1988.
  69. * Modified by Rosen Sharma, Stanford, Aug 1994.
  70. * Modified by Bill Fenner, Xerox PARC, Feb 1995.
  71. *
  72. * MULTICAST Revision: 1.3
  73. */
  74. #include <sys/param.h>
  75. #include <sys/mbuf.h>
  76. #include <sys/systm.h>
  77. #include <sys/socket.h>
  78. #include <sys/protosw.h>
  79. #include <sys/sysctl.h>
  80. #include <net/if.h>
  81. #include <net/if_var.h>
  82. #include <netinet/in.h>
  83. #include <netinet/in_var.h>
  84. #include <netinet/ip.h>
  85. #include <netinet/ip_var.h>
  86. #include <netinet/igmp.h>
  87. #include <netinet/igmp_var.h>
  88. #include <sys/stdarg.h>
  89. #define IP_MULTICASTOPTS 0
  90. int *igmpctl_vars[IGMPCTL_MAXID] = IGMPCTL_VARS;
  91. int igmp_timers_are_running;
  92. static struct router_info *rti_head;
  93. static struct mbuf *router_alert;
  94. struct igmpstat igmpstat;
  95. void igmp_checktimer(struct ifnet *);
  96. void igmp_sendpkt(struct in_multi *, int, in_addr_t);
  97. int rti_fill(struct in_multi *);
  98. struct router_info * rti_find(struct ifnet *);
  99. void
  100. igmp_init(void)
  101. {
  102. struct ipoption *ra;
  103. igmp_timers_are_running = 0;
  104. rti_head = 0;
  105. router_alert = m_get(M_DONTWAIT, MT_DATA);
  106. if (router_alert == NULL) {
  107. printf("%s: no mbuf\n", __func__);
  108. return;
  109. }
  110. /*
  111. * Construct a Router Alert option (RAO) to use in report
  112. * messages as required by RFC2236. This option has the
  113. * following format:
  114. *
  115. * | 10010100 | 00000100 | 2 octet value |
  116. *
  117. * where a value of "0" indicates that routers shall examine
  118. * the packet.
  119. */
  120. ra = mtod(router_alert, struct ipoption *);
  121. ra->ipopt_dst.s_addr = INADDR_ANY;
  122. ra->ipopt_list[0] = IPOPT_RA;
  123. ra->ipopt_list[1] = 0x04;
  124. ra->ipopt_list[2] = 0x00;
  125. ra->ipopt_list[3] = 0x00;
  126. router_alert->m_len = sizeof(ra->ipopt_dst) + ra->ipopt_list[1];
  127. }
  128. /* Return -1 for error. */
  129. int
  130. rti_fill(struct in_multi *inm)
  131. {
  132. struct router_info *rti;
  133. for (rti = rti_head; rti != 0; rti = rti->rti_next) {
  134. if (rti->rti_ifp->if_index == inm->inm_ifidx) {
  135. inm->inm_rti = rti;
  136. if (rti->rti_type == IGMP_v1_ROUTER)
  137. return (IGMP_v1_HOST_MEMBERSHIP_REPORT);
  138. else
  139. return (IGMP_v2_HOST_MEMBERSHIP_REPORT);
  140. }
  141. }
  142. rti = (struct router_info *)malloc(sizeof(struct router_info),
  143. M_MRTABLE, M_NOWAIT);
  144. if (rti == NULL)
  145. return (-1);
  146. rti->rti_ifp = if_get(inm->inm_ifidx);
  147. rti->rti_type = IGMP_v2_ROUTER;
  148. rti->rti_next = rti_head;
  149. rti_head = rti;
  150. inm->inm_rti = rti;
  151. return (IGMP_v2_HOST_MEMBERSHIP_REPORT);
  152. }
  153. struct router_info *
  154. rti_find(struct ifnet *ifp)
  155. {
  156. struct router_info *rti;
  157. for (rti = rti_head; rti != 0; rti = rti->rti_next) {
  158. if (rti->rti_ifp == ifp)
  159. return (rti);
  160. }
  161. rti = (struct router_info *)malloc(sizeof(struct router_info),
  162. M_MRTABLE, M_NOWAIT);
  163. if (rti == NULL)
  164. return (NULL);
  165. rti->rti_ifp = ifp;
  166. rti->rti_type = IGMP_v2_ROUTER;
  167. rti->rti_next = rti_head;
  168. rti_head = rti;
  169. return (rti);
  170. }
  171. void
  172. rti_delete(struct ifnet *ifp)
  173. {
  174. struct router_info *rti, **prti = &rti_head;
  175. for (rti = rti_head; rti != 0; rti = rti->rti_next) {
  176. if (rti->rti_ifp == ifp) {
  177. *prti = rti->rti_next;
  178. free(rti, M_MRTABLE, 0);
  179. break;
  180. }
  181. prti = &rti->rti_next;
  182. }
  183. }
  184. void
  185. igmp_input(struct mbuf *m, ...)
  186. {
  187. int iphlen;
  188. struct ifnet *ifp;
  189. struct ip *ip = mtod(m, struct ip *);
  190. struct igmp *igmp;
  191. int igmplen;
  192. int minlen;
  193. struct ifmaddr *ifma;
  194. struct in_multi *inm;
  195. struct router_info *rti;
  196. struct in_ifaddr *ia;
  197. int timer;
  198. va_list ap;
  199. va_start(ap, m);
  200. iphlen = va_arg(ap, int);
  201. va_end(ap);
  202. ++igmpstat.igps_rcv_total;
  203. igmplen = ntohs(ip->ip_len) - iphlen;
  204. ifp = if_get(m->m_pkthdr.ph_ifidx);
  205. if (ifp == NULL) {
  206. m_freem(m);
  207. return;
  208. }
  209. /*
  210. * Validate lengths
  211. */
  212. if (igmplen < IGMP_MINLEN) {
  213. ++igmpstat.igps_rcv_tooshort;
  214. m_freem(m);
  215. return;
  216. }
  217. minlen = iphlen + IGMP_MINLEN;
  218. if ((m->m_flags & M_EXT || m->m_len < minlen) &&
  219. (m = m_pullup(m, minlen)) == NULL) {
  220. ++igmpstat.igps_rcv_tooshort;
  221. return;
  222. }
  223. /*
  224. * Validate checksum
  225. */
  226. m->m_data += iphlen;
  227. m->m_len -= iphlen;
  228. igmp = mtod(m, struct igmp *);
  229. if (in_cksum(m, igmplen)) {
  230. ++igmpstat.igps_rcv_badsum;
  231. m_freem(m);
  232. return;
  233. }
  234. m->m_data -= iphlen;
  235. m->m_len += iphlen;
  236. ip = mtod(m, struct ip *);
  237. switch (igmp->igmp_type) {
  238. case IGMP_HOST_MEMBERSHIP_QUERY:
  239. ++igmpstat.igps_rcv_queries;
  240. if (ifp->if_flags & IFF_LOOPBACK)
  241. break;
  242. if (igmp->igmp_code == 0) {
  243. rti = rti_find(ifp);
  244. if (rti == NULL) {
  245. m_freem(m);
  246. return;
  247. }
  248. rti->rti_type = IGMP_v1_ROUTER;
  249. rti->rti_age = 0;
  250. if (ip->ip_dst.s_addr != INADDR_ALLHOSTS_GROUP) {
  251. ++igmpstat.igps_rcv_badqueries;
  252. m_freem(m);
  253. return;
  254. }
  255. /*
  256. * Start the timers in all of our membership records
  257. * for the interface on which the query arrived,
  258. * except those that are already running and those
  259. * that belong to a "local" group (224.0.0.X).
  260. */
  261. TAILQ_FOREACH(ifma, &ifp->if_maddrlist, ifma_list) {
  262. if (ifma->ifma_addr->sa_family != AF_INET)
  263. continue;
  264. inm = ifmatoinm(ifma);
  265. if (inm->inm_timer == 0 &&
  266. !IN_LOCAL_GROUP(inm->inm_addr.s_addr)) {
  267. inm->inm_state = IGMP_DELAYING_MEMBER;
  268. inm->inm_timer = IGMP_RANDOM_DELAY(
  269. IGMP_MAX_HOST_REPORT_DELAY * PR_FASTHZ);
  270. igmp_timers_are_running = 1;
  271. }
  272. }
  273. } else {
  274. if (!IN_MULTICAST(ip->ip_dst.s_addr)) {
  275. ++igmpstat.igps_rcv_badqueries;
  276. m_freem(m);
  277. return;
  278. }
  279. timer = igmp->igmp_code * PR_FASTHZ / IGMP_TIMER_SCALE;
  280. if (timer == 0)
  281. timer = 1;
  282. /*
  283. * Start the timers in all of our membership records
  284. * for the interface on which the query arrived,
  285. * except those that are already running and those
  286. * that belong to a "local" group (224.0.0.X). For
  287. * timers already running, check if they need to be
  288. * reset.
  289. */
  290. TAILQ_FOREACH(ifma, &ifp->if_maddrlist, ifma_list) {
  291. if (ifma->ifma_addr->sa_family != AF_INET)
  292. continue;
  293. inm = ifmatoinm(ifma);
  294. if (!IN_LOCAL_GROUP(inm->inm_addr.s_addr) &&
  295. (ip->ip_dst.s_addr == INADDR_ALLHOSTS_GROUP ||
  296. ip->ip_dst.s_addr == inm->inm_addr.s_addr)) {
  297. switch (inm->inm_state) {
  298. case IGMP_DELAYING_MEMBER:
  299. if (inm->inm_timer <= timer)
  300. break;
  301. /* FALLTHROUGH */
  302. case IGMP_IDLE_MEMBER:
  303. case IGMP_LAZY_MEMBER:
  304. case IGMP_AWAKENING_MEMBER:
  305. inm->inm_state =
  306. IGMP_DELAYING_MEMBER;
  307. inm->inm_timer =
  308. IGMP_RANDOM_DELAY(timer);
  309. igmp_timers_are_running = 1;
  310. break;
  311. case IGMP_SLEEPING_MEMBER:
  312. inm->inm_state =
  313. IGMP_AWAKENING_MEMBER;
  314. break;
  315. }
  316. }
  317. }
  318. }
  319. break;
  320. case IGMP_v1_HOST_MEMBERSHIP_REPORT:
  321. ++igmpstat.igps_rcv_reports;
  322. if (ifp->if_flags & IFF_LOOPBACK)
  323. break;
  324. if (!IN_MULTICAST(igmp->igmp_group.s_addr) ||
  325. igmp->igmp_group.s_addr != ip->ip_dst.s_addr) {
  326. ++igmpstat.igps_rcv_badreports;
  327. m_freem(m);
  328. return;
  329. }
  330. /*
  331. * KLUDGE: if the IP source address of the report has an
  332. * unspecified (i.e., zero) subnet number, as is allowed for
  333. * a booting host, replace it with the correct subnet number
  334. * so that a process-level multicast routing daemon can
  335. * determine which subnet it arrived from. This is necessary
  336. * to compensate for the lack of any way for a process to
  337. * determine the arrival interface of an incoming packet.
  338. */
  339. if ((ip->ip_src.s_addr & IN_CLASSA_NET) == 0) {
  340. IFP_TO_IA(ifp, ia);
  341. if (ia)
  342. ip->ip_src.s_addr = ia->ia_net;
  343. }
  344. /*
  345. * If we belong to the group being reported, stop
  346. * our timer for that group.
  347. */
  348. IN_LOOKUP_MULTI(igmp->igmp_group, ifp, inm);
  349. if (inm != NULL) {
  350. inm->inm_timer = 0;
  351. ++igmpstat.igps_rcv_ourreports;
  352. switch (inm->inm_state) {
  353. case IGMP_IDLE_MEMBER:
  354. case IGMP_LAZY_MEMBER:
  355. case IGMP_AWAKENING_MEMBER:
  356. case IGMP_SLEEPING_MEMBER:
  357. inm->inm_state = IGMP_SLEEPING_MEMBER;
  358. break;
  359. case IGMP_DELAYING_MEMBER:
  360. if (inm->inm_rti->rti_type == IGMP_v1_ROUTER)
  361. inm->inm_state = IGMP_LAZY_MEMBER;
  362. else
  363. inm->inm_state = IGMP_SLEEPING_MEMBER;
  364. break;
  365. }
  366. }
  367. break;
  368. case IGMP_v2_HOST_MEMBERSHIP_REPORT:
  369. #ifdef MROUTING
  370. /*
  371. * Make sure we don't hear our own membership report. Fast
  372. * leave requires knowing that we are the only member of a
  373. * group.
  374. */
  375. IFP_TO_IA(ifp, ia);
  376. if (ia && ip->ip_src.s_addr == ia->ia_addr.sin_addr.s_addr)
  377. break;
  378. #endif
  379. ++igmpstat.igps_rcv_reports;
  380. if (ifp->if_flags & IFF_LOOPBACK)
  381. break;
  382. if (!IN_MULTICAST(igmp->igmp_group.s_addr) ||
  383. igmp->igmp_group.s_addr != ip->ip_dst.s_addr) {
  384. ++igmpstat.igps_rcv_badreports;
  385. m_freem(m);
  386. return;
  387. }
  388. /*
  389. * KLUDGE: if the IP source address of the report has an
  390. * unspecified (i.e., zero) subnet number, as is allowed for
  391. * a booting host, replace it with the correct subnet number
  392. * so that a process-level multicast routing daemon can
  393. * determine which subnet it arrived from. This is necessary
  394. * to compensate for the lack of any way for a process to
  395. * determine the arrival interface of an incoming packet.
  396. */
  397. if ((ip->ip_src.s_addr & IN_CLASSA_NET) == 0) {
  398. #ifndef MROUTING
  399. IFP_TO_IA(ifp, ia);
  400. #endif
  401. if (ia)
  402. ip->ip_src.s_addr = ia->ia_net;
  403. }
  404. /*
  405. * If we belong to the group being reported, stop
  406. * our timer for that group.
  407. */
  408. IN_LOOKUP_MULTI(igmp->igmp_group, ifp, inm);
  409. if (inm != NULL) {
  410. inm->inm_timer = 0;
  411. ++igmpstat.igps_rcv_ourreports;
  412. switch (inm->inm_state) {
  413. case IGMP_DELAYING_MEMBER:
  414. case IGMP_IDLE_MEMBER:
  415. case IGMP_AWAKENING_MEMBER:
  416. inm->inm_state = IGMP_LAZY_MEMBER;
  417. break;
  418. case IGMP_LAZY_MEMBER:
  419. case IGMP_SLEEPING_MEMBER:
  420. break;
  421. }
  422. }
  423. break;
  424. }
  425. /*
  426. * Pass all valid IGMP packets up to any process(es) listening
  427. * on a raw IGMP socket.
  428. */
  429. rip_input(m);
  430. }
  431. void
  432. igmp_joingroup(struct in_multi *inm)
  433. {
  434. struct ifnet* ifp;
  435. int i, s;
  436. ifp = if_get(inm->inm_ifidx);
  437. s = splsoftnet();
  438. inm->inm_state = IGMP_IDLE_MEMBER;
  439. if (!IN_LOCAL_GROUP(inm->inm_addr.s_addr) &&
  440. ifp && (ifp->if_flags & IFF_LOOPBACK) == 0) {
  441. if ((i = rti_fill(inm)) == -1) {
  442. splx(s);
  443. return;
  444. }
  445. igmp_sendpkt(inm, i, 0);
  446. inm->inm_state = IGMP_DELAYING_MEMBER;
  447. inm->inm_timer = IGMP_RANDOM_DELAY(
  448. IGMP_MAX_HOST_REPORT_DELAY * PR_FASTHZ);
  449. igmp_timers_are_running = 1;
  450. } else
  451. inm->inm_timer = 0;
  452. splx(s);
  453. }
  454. void
  455. igmp_leavegroup(struct in_multi *inm)
  456. {
  457. struct ifnet* ifp;
  458. int s;
  459. ifp = if_get(inm->inm_ifidx);
  460. s = splsoftnet();
  461. switch (inm->inm_state) {
  462. case IGMP_DELAYING_MEMBER:
  463. case IGMP_IDLE_MEMBER:
  464. if (!IN_LOCAL_GROUP(inm->inm_addr.s_addr) &&
  465. ifp && (ifp->if_flags & IFF_LOOPBACK) == 0)
  466. if (inm->inm_rti->rti_type != IGMP_v1_ROUTER)
  467. igmp_sendpkt(inm, IGMP_HOST_LEAVE_MESSAGE,
  468. INADDR_ALLROUTERS_GROUP);
  469. break;
  470. case IGMP_LAZY_MEMBER:
  471. case IGMP_AWAKENING_MEMBER:
  472. case IGMP_SLEEPING_MEMBER:
  473. break;
  474. }
  475. splx(s);
  476. }
  477. void
  478. igmp_fasttimo(void)
  479. {
  480. struct ifnet *ifp;
  481. int s;
  482. /*
  483. * Quick check to see if any work needs to be done, in order
  484. * to minimize the overhead of fasttimo processing.
  485. */
  486. if (!igmp_timers_are_running)
  487. return;
  488. s = splsoftnet();
  489. igmp_timers_are_running = 0;
  490. TAILQ_FOREACH(ifp, &ifnet, if_list)
  491. igmp_checktimer(ifp);
  492. splx(s);
  493. }
  494. void
  495. igmp_checktimer(struct ifnet *ifp)
  496. {
  497. struct in_multi *inm;
  498. struct ifmaddr *ifma;
  499. splsoftassert(IPL_SOFTNET);
  500. TAILQ_FOREACH(ifma, &ifp->if_maddrlist, ifma_list) {
  501. if (ifma->ifma_addr->sa_family != AF_INET)
  502. continue;
  503. inm = ifmatoinm(ifma);
  504. if (inm->inm_timer == 0) {
  505. /* do nothing */
  506. } else if (--inm->inm_timer == 0) {
  507. if (inm->inm_state == IGMP_DELAYING_MEMBER) {
  508. if (inm->inm_rti->rti_type == IGMP_v1_ROUTER)
  509. igmp_sendpkt(inm,
  510. IGMP_v1_HOST_MEMBERSHIP_REPORT, 0);
  511. else
  512. igmp_sendpkt(inm,
  513. IGMP_v2_HOST_MEMBERSHIP_REPORT, 0);
  514. inm->inm_state = IGMP_IDLE_MEMBER;
  515. }
  516. } else {
  517. igmp_timers_are_running = 1;
  518. }
  519. }
  520. }
  521. void
  522. igmp_slowtimo(void)
  523. {
  524. struct router_info *rti;
  525. int s;
  526. s = splsoftnet();
  527. for (rti = rti_head; rti != 0; rti = rti->rti_next) {
  528. if (rti->rti_type == IGMP_v1_ROUTER &&
  529. ++rti->rti_age >= IGMP_AGE_THRESHOLD) {
  530. rti->rti_type = IGMP_v2_ROUTER;
  531. }
  532. }
  533. splx(s);
  534. }
  535. void
  536. igmp_sendpkt(struct in_multi *inm, int type, in_addr_t addr)
  537. {
  538. struct mbuf *m;
  539. struct igmp *igmp;
  540. struct ip *ip;
  541. struct ip_moptions imo;
  542. MGETHDR(m, M_DONTWAIT, MT_HEADER);
  543. if (m == NULL)
  544. return;
  545. /*
  546. * Assume max_linkhdr + sizeof(struct ip) + IGMP_MINLEN
  547. * is smaller than mbuf size returned by MGETHDR.
  548. */
  549. m->m_data += max_linkhdr;
  550. m->m_len = sizeof(struct ip) + IGMP_MINLEN;
  551. m->m_pkthdr.len = sizeof(struct ip) + IGMP_MINLEN;
  552. ip = mtod(m, struct ip *);
  553. ip->ip_tos = 0;
  554. ip->ip_len = htons(sizeof(struct ip) + IGMP_MINLEN);
  555. ip->ip_off = 0;
  556. ip->ip_p = IPPROTO_IGMP;
  557. ip->ip_src.s_addr = INADDR_ANY;
  558. if (addr) {
  559. ip->ip_dst.s_addr = addr;
  560. } else {
  561. ip->ip_dst = inm->inm_addr;
  562. }
  563. m->m_data += sizeof(struct ip);
  564. m->m_len -= sizeof(struct ip);
  565. igmp = mtod(m, struct igmp *);
  566. igmp->igmp_type = type;
  567. igmp->igmp_code = 0;
  568. igmp->igmp_group = inm->inm_addr;
  569. igmp->igmp_cksum = 0;
  570. igmp->igmp_cksum = in_cksum(m, IGMP_MINLEN);
  571. m->m_data -= sizeof(struct ip);
  572. m->m_len += sizeof(struct ip);
  573. imo.imo_ifidx = inm->inm_ifidx;
  574. imo.imo_ttl = 1;
  575. /*
  576. * Request loopback of the report if we are acting as a multicast
  577. * router, so that the process-level routing daemon can hear it.
  578. */
  579. #ifdef MROUTING
  580. imo.imo_loop = (ip_mrouter != NULL);
  581. #else
  582. imo.imo_loop = 0;
  583. #endif /* MROUTING */
  584. ip_output(m, router_alert, NULL, IP_MULTICASTOPTS, &imo, NULL, 0);
  585. ++igmpstat.igps_snd_reports;
  586. }
  587. /*
  588. * Sysctl for igmp variables.
  589. */
  590. int
  591. igmp_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp,
  592. void *newp, size_t newlen)
  593. {
  594. /* All sysctl names at this level are terminal. */
  595. if (namelen != 1)
  596. return (ENOTDIR);
  597. switch (name[0]) {
  598. case IGMPCTL_STATS:
  599. if (newp != NULL)
  600. return (EPERM);
  601. return (sysctl_struct(oldp, oldlenp, newp, newlen,
  602. &igmpstat, sizeof(igmpstat)));
  603. default:
  604. if (name[0] < IGMPCTL_MAXID)
  605. return (sysctl_int_arr(igmpctl_vars, name, namelen,
  606. oldp, oldlenp, newp, newlen));
  607. return (ENOPROTOOPT);
  608. }
  609. /* NOTREACHED */
  610. }