mld6.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476
  1. /* $OpenBSD: mld6.c,v 1.42 2015/06/16 11:09:40 mpi Exp $ */
  2. /* $KAME: mld6.c,v 1.26 2001/02/16 14:50:35 itojun Exp $ */
  3. /*
  4. * Copyright (C) 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.1 (Berkeley) 7/19/93
  64. */
  65. #include <sys/param.h>
  66. #include <sys/systm.h>
  67. #include <sys/mbuf.h>
  68. #include <sys/socket.h>
  69. #include <sys/protosw.h>
  70. #include <sys/syslog.h>
  71. #include <net/if.h>
  72. #include <net/if_var.h>
  73. #include <netinet/in.h>
  74. #include <netinet6/in6_var.h>
  75. #include <netinet/ip6.h>
  76. #include <netinet6/ip6_var.h>
  77. #include <netinet/icmp6.h>
  78. #include <netinet6/mld6.h>
  79. #include <netinet6/mld6_var.h>
  80. static struct ip6_pktopts ip6_opts;
  81. static int mld_timers_are_running;
  82. /* XXX: These are necessary for KAME's link-local hack */
  83. static struct in6_addr mld_all_nodes_linklocal = IN6ADDR_LINKLOCAL_ALLNODES_INIT;
  84. static struct in6_addr mld_all_routers_linklocal = IN6ADDR_LINKLOCAL_ALLROUTERS_INIT;
  85. void mld6_checktimer(struct ifnet *);
  86. static void mld6_sendpkt(struct in6_multi *, int, const struct in6_addr *);
  87. void
  88. mld6_init()
  89. {
  90. static u_int8_t hbh_buf[8];
  91. struct ip6_hbh *hbh = (struct ip6_hbh *)hbh_buf;
  92. u_int16_t rtalert_code = htons((u_int16_t)IP6OPT_RTALERT_MLD);
  93. mld_timers_are_running = 0;
  94. /* ip6h_nxt will be fill in later */
  95. hbh->ip6h_len = 0; /* (8 >> 3) - 1 */
  96. /* XXX: grotty hard coding... */
  97. hbh_buf[2] = IP6OPT_PADN; /* 2 byte padding */
  98. hbh_buf[3] = 0;
  99. hbh_buf[4] = IP6OPT_ROUTER_ALERT;
  100. hbh_buf[5] = IP6OPT_RTALERT_LEN - 2;
  101. bcopy((caddr_t)&rtalert_code, &hbh_buf[6], sizeof(u_int16_t));
  102. ip6_opts.ip6po_hbh = hbh;
  103. }
  104. void
  105. mld6_start_listening(struct in6_multi *in6m)
  106. {
  107. int s = splsoftnet();
  108. /*
  109. * RFC2710 page 10:
  110. * The node never sends a Report or Done for the link-scope all-nodes
  111. * address.
  112. * MLD messages are never sent for multicast addresses whose scope is 0
  113. * (reserved) or 1 (node-local).
  114. */
  115. mld_all_nodes_linklocal.s6_addr16[1] = htons(in6m->in6m_ifidx);/* XXX */
  116. if (IN6_ARE_ADDR_EQUAL(&in6m->in6m_addr, &mld_all_nodes_linklocal) ||
  117. __IPV6_ADDR_MC_SCOPE(&in6m->in6m_addr) < __IPV6_ADDR_SCOPE_LINKLOCAL) {
  118. in6m->in6m_timer = 0;
  119. in6m->in6m_state = MLD_OTHERLISTENER;
  120. } else {
  121. mld6_sendpkt(in6m, MLD_LISTENER_REPORT, NULL);
  122. in6m->in6m_timer =
  123. MLD_RANDOM_DELAY(MLD_V1_MAX_RI *
  124. PR_FASTHZ);
  125. in6m->in6m_state = MLD_IREPORTEDLAST;
  126. mld_timers_are_running = 1;
  127. }
  128. splx(s);
  129. }
  130. void
  131. mld6_stop_listening(struct in6_multi *in6m)
  132. {
  133. int s = splsoftnet();
  134. mld_all_nodes_linklocal.s6_addr16[1] = htons(in6m->in6m_ifidx);/* XXX */
  135. mld_all_routers_linklocal.s6_addr16[1] =
  136. htons(in6m->in6m_ifidx); /* XXX: necessary when mrouting */
  137. if (in6m->in6m_state == MLD_IREPORTEDLAST &&
  138. (!IN6_ARE_ADDR_EQUAL(&in6m->in6m_addr, &mld_all_nodes_linklocal)) &&
  139. __IPV6_ADDR_MC_SCOPE(&in6m->in6m_addr) > __IPV6_ADDR_SCOPE_INTFACELOCAL)
  140. mld6_sendpkt(in6m, MLD_LISTENER_DONE,
  141. &mld_all_routers_linklocal);
  142. splx(s);
  143. }
  144. void
  145. mld6_input(struct mbuf *m, int off)
  146. {
  147. struct ip6_hdr *ip6;
  148. struct mld_hdr *mldh;
  149. struct ifnet *ifp;
  150. struct in6_multi *in6m;
  151. struct ifmaddr *ifma;
  152. int timer; /* timer value in the MLD query header */
  153. ifp = if_get(m->m_pkthdr.ph_ifidx);
  154. if (ifp == NULL) {
  155. m_freem(m);
  156. return;
  157. }
  158. IP6_EXTHDR_GET(mldh, struct mld_hdr *, m, off, sizeof(*mldh));
  159. if (mldh == NULL) {
  160. icmp6stat.icp6s_tooshort++;
  161. return;
  162. }
  163. /* source address validation */
  164. ip6 = mtod(m, struct ip6_hdr *);/* in case mpullup */
  165. if (!IN6_IS_ADDR_LINKLOCAL(&ip6->ip6_src)) {
  166. #if 0
  167. char src[INET6_ADDRSTRLEN], grp[INET6_ADDRSTRLEN];
  168. log(LOG_ERR,
  169. "mld_input: src %s is not link-local (grp=%s)\n",
  170. inet_ntop(AF_INET6, &ip6->ip6_src, src, sizeof(src)),
  171. inet_ntop(AF_INET6, &mldh->mld_addr, grp, sizeof(grp)));
  172. #endif
  173. /*
  174. * spec (RFC2710) does not explicitly
  175. * specify to discard the packet from a non link-local
  176. * source address. But we believe it's expected to do so.
  177. */
  178. m_freem(m);
  179. return;
  180. }
  181. /*
  182. * In the MLD6 specification, there are 3 states and a flag.
  183. *
  184. * In Non-Listener state, we simply don't have a membership record.
  185. * In Delaying Listener state, our timer is running (in6m->in6m_timer)
  186. * In Idle Listener state, our timer is not running (in6m->in6m_timer==0)
  187. *
  188. * The flag is in6m->in6m_state, it is set to MLD_OTHERLISTENER if
  189. * we have heard a report from another member, or MLD_IREPORTEDLAST
  190. * if we sent the last report.
  191. */
  192. switch(mldh->mld_type) {
  193. case MLD_LISTENER_QUERY:
  194. if (ifp->if_flags & IFF_LOOPBACK)
  195. break;
  196. if (!IN6_IS_ADDR_UNSPECIFIED(&mldh->mld_addr) &&
  197. !IN6_IS_ADDR_MULTICAST(&mldh->mld_addr))
  198. break; /* print error or log stat? */
  199. if (IN6_IS_ADDR_MC_LINKLOCAL(&mldh->mld_addr))
  200. mldh->mld_addr.s6_addr16[1] =
  201. htons(ifp->if_index); /* XXX */
  202. /*
  203. * - Start the timers in all of our membership records
  204. * that the query applies to for the interface on
  205. * which the query arrived excl. those that belong
  206. * to the "all-nodes" group (ff02::1).
  207. * - Restart any timer that is already running but has
  208. * A value longer than the requested timeout.
  209. * - Use the value specified in the query message as
  210. * the maximum timeout.
  211. */
  212. /*
  213. * XXX: System timer resolution is too low to handle Max
  214. * Response Delay, so set 1 to the internal timer even if
  215. * the calculated value equals to zero when Max Response
  216. * Delay is positive.
  217. */
  218. timer = ntohs(mldh->mld_maxdelay)*PR_FASTHZ/MLD_TIMER_SCALE;
  219. if (timer == 0 && mldh->mld_maxdelay)
  220. timer = 1;
  221. mld_all_nodes_linklocal.s6_addr16[1] =
  222. htons(ifp->if_index); /* XXX */
  223. TAILQ_FOREACH(ifma, &ifp->if_maddrlist, ifma_list) {
  224. if (ifma->ifma_addr->sa_family != AF_INET6)
  225. continue;
  226. in6m = ifmatoin6m(ifma);
  227. if (IN6_ARE_ADDR_EQUAL(&in6m->in6m_addr,
  228. &mld_all_nodes_linklocal) ||
  229. __IPV6_ADDR_MC_SCOPE(&in6m->in6m_addr) <
  230. __IPV6_ADDR_SCOPE_LINKLOCAL)
  231. continue;
  232. if (IN6_IS_ADDR_UNSPECIFIED(&mldh->mld_addr) ||
  233. IN6_ARE_ADDR_EQUAL(&mldh->mld_addr,
  234. &in6m->in6m_addr))
  235. {
  236. if (timer == 0) {
  237. /* send a report immediately */
  238. mld6_sendpkt(in6m, MLD_LISTENER_REPORT,
  239. NULL);
  240. in6m->in6m_timer = 0; /* reset timer */
  241. in6m->in6m_state = MLD_IREPORTEDLAST;
  242. } else if (in6m->in6m_timer == 0 || /* idle */
  243. in6m->in6m_timer > timer) {
  244. in6m->in6m_timer =
  245. MLD_RANDOM_DELAY(timer);
  246. mld_timers_are_running = 1;
  247. }
  248. }
  249. }
  250. if (IN6_IS_ADDR_MC_LINKLOCAL(&mldh->mld_addr))
  251. mldh->mld_addr.s6_addr16[1] = 0; /* XXX */
  252. break;
  253. case MLD_LISTENER_REPORT:
  254. /*
  255. * For fast leave to work, we have to know that we are the
  256. * last person to send a report for this group. Reports
  257. * can potentially get looped back if we are a multicast
  258. * router, so discard reports sourced by me.
  259. * Note that it is impossible to check IFF_LOOPBACK flag of
  260. * ifp for this purpose, since ip6_mloopback pass the physical
  261. * interface to looutput.
  262. */
  263. if (m->m_flags & M_LOOP) /* XXX: grotty flag, but efficient */
  264. break;
  265. if (!IN6_IS_ADDR_MULTICAST(&mldh->mld_addr))
  266. break;
  267. if (IN6_IS_ADDR_MC_LINKLOCAL(&mldh->mld_addr))
  268. mldh->mld_addr.s6_addr16[1] =
  269. htons(ifp->if_index); /* XXX */
  270. /*
  271. * If we belong to the group being reported, stop
  272. * our timer for that group.
  273. */
  274. IN6_LOOKUP_MULTI(mldh->mld_addr, ifp, in6m);
  275. if (in6m) {
  276. in6m->in6m_timer = 0; /* transit to idle state */
  277. in6m->in6m_state = MLD_OTHERLISTENER; /* clear flag */
  278. }
  279. if (IN6_IS_ADDR_MC_LINKLOCAL(&mldh->mld_addr))
  280. mldh->mld_addr.s6_addr16[1] = 0; /* XXX */
  281. break;
  282. default: /* this is impossible */
  283. #if 0
  284. /*
  285. * this case should be impossible because of filtering in
  286. * icmp6_input(). But we explicitly disabled this part
  287. * just in case.
  288. */
  289. log(LOG_ERR, "mld_input: illegal type(%d)", mldh->mld_type);
  290. #endif
  291. break;
  292. }
  293. m_freem(m);
  294. }
  295. void
  296. mld6_fasttimeo(void)
  297. {
  298. struct ifnet *ifp;
  299. int s;
  300. /*
  301. * Quick check to see if any work needs to be done, in order
  302. * to minimize the overhead of fasttimo processing.
  303. */
  304. if (!mld_timers_are_running)
  305. return;
  306. s = splsoftnet();
  307. mld_timers_are_running = 0;
  308. TAILQ_FOREACH(ifp, &ifnet, if_list)
  309. mld6_checktimer(ifp);
  310. splx(s);
  311. }
  312. void
  313. mld6_checktimer(struct ifnet *ifp)
  314. {
  315. struct in6_multi *in6m;
  316. struct ifmaddr *ifma;
  317. splsoftassert(IPL_SOFTNET);
  318. TAILQ_FOREACH(ifma, &ifp->if_maddrlist, ifma_list) {
  319. if (ifma->ifma_addr->sa_family != AF_INET6)
  320. continue;
  321. in6m = ifmatoin6m(ifma);
  322. if (in6m->in6m_timer == 0) {
  323. /* do nothing */
  324. } else if (--in6m->in6m_timer == 0) {
  325. mld6_sendpkt(in6m, MLD_LISTENER_REPORT, NULL);
  326. in6m->in6m_state = MLD_IREPORTEDLAST;
  327. } else {
  328. mld_timers_are_running = 1;
  329. }
  330. }
  331. }
  332. static void
  333. mld6_sendpkt(struct in6_multi *in6m, int type, const struct in6_addr *dst)
  334. {
  335. struct mbuf *mh, *md;
  336. struct mld_hdr *mldh;
  337. struct ip6_hdr *ip6;
  338. struct ip6_moptions im6o;
  339. struct in6_ifaddr *ia6;
  340. struct ifnet *ifp;
  341. int ignflags;
  342. ifp = if_get(in6m->in6m_ifidx);
  343. if (ifp == NULL)
  344. return;
  345. /*
  346. * At first, find a link local address on the outgoing interface
  347. * to use as the source address of the MLD packet.
  348. * We do not reject tentative addresses for MLD report to deal with
  349. * the case where we first join a link-local address.
  350. */
  351. ignflags = (IN6_IFF_NOTREADY|IN6_IFF_ANYCAST) & ~IN6_IFF_TENTATIVE;
  352. if ((ia6 = in6ifa_ifpforlinklocal(ifp, ignflags)) == NULL)
  353. return;
  354. if ((ia6->ia6_flags & IN6_IFF_TENTATIVE))
  355. ia6 = NULL;
  356. /*
  357. * Allocate mbufs to store ip6 header and MLD header.
  358. * We allocate 2 mbufs and make chain in advance because
  359. * it is more convenient when inserting the hop-by-hop option later.
  360. */
  361. MGETHDR(mh, M_DONTWAIT, MT_HEADER);
  362. if (mh == NULL)
  363. return;
  364. MGET(md, M_DONTWAIT, MT_DATA);
  365. if (md == NULL) {
  366. m_free(mh);
  367. return;
  368. }
  369. mh->m_next = md;
  370. mh->m_pkthdr.ph_ifidx = 0;
  371. mh->m_pkthdr.ph_rtableid = ifp->if_rdomain;
  372. mh->m_pkthdr.len = sizeof(struct ip6_hdr) + sizeof(struct mld_hdr);
  373. mh->m_len = sizeof(struct ip6_hdr);
  374. MH_ALIGN(mh, sizeof(struct ip6_hdr));
  375. /* fill in the ip6 header */
  376. ip6 = mtod(mh, struct ip6_hdr *);
  377. ip6->ip6_flow = 0;
  378. ip6->ip6_vfc &= ~IPV6_VERSION_MASK;
  379. ip6->ip6_vfc |= IPV6_VERSION;
  380. /* ip6_plen will be set later */
  381. ip6->ip6_nxt = IPPROTO_ICMPV6;
  382. /* ip6_hlim will be set by im6o.im6o_hlim */
  383. ip6->ip6_src = ia6 ? ia6->ia_addr.sin6_addr : in6addr_any;
  384. ip6->ip6_dst = dst ? *dst : in6m->in6m_addr;
  385. /* fill in the MLD header */
  386. md->m_len = sizeof(struct mld_hdr);
  387. mldh = mtod(md, struct mld_hdr *);
  388. mldh->mld_type = type;
  389. mldh->mld_code = 0;
  390. mldh->mld_cksum = 0;
  391. /* XXX: we assume the function will not be called for query messages */
  392. mldh->mld_maxdelay = 0;
  393. mldh->mld_reserved = 0;
  394. mldh->mld_addr = in6m->in6m_addr;
  395. if (IN6_IS_ADDR_MC_LINKLOCAL(&mldh->mld_addr))
  396. mldh->mld_addr.s6_addr16[1] = 0; /* XXX */
  397. mh->m_pkthdr.csum_flags |= M_ICMP_CSUM_OUT;
  398. /* construct multicast option */
  399. bzero(&im6o, sizeof(im6o));
  400. im6o.im6o_ifidx = ifp->if_index;
  401. im6o.im6o_hlim = 1;
  402. /*
  403. * Request loopback of the report if we are acting as a multicast
  404. * router, so that the process-level routing daemon can hear it.
  405. */
  406. #ifdef MROUTING
  407. im6o.im6o_loop = (ip6_mrouter != NULL);
  408. #endif
  409. /* increment output statictics */
  410. icmp6stat.icp6s_outhist[type]++;
  411. icmp6_ifstat_inc(ifp, ifs6_out_msg);
  412. switch (type) {
  413. case MLD_LISTENER_QUERY:
  414. icmp6_ifstat_inc(ifp, ifs6_out_mldquery);
  415. break;
  416. case MLD_LISTENER_REPORT:
  417. icmp6_ifstat_inc(ifp, ifs6_out_mldreport);
  418. break;
  419. case MLD_LISTENER_DONE:
  420. icmp6_ifstat_inc(ifp, ifs6_out_mlddone);
  421. break;
  422. }
  423. ip6_output(mh, &ip6_opts, NULL, ia6 ? 0 : IPV6_UNSPECSRC, &im6o, NULL,
  424. NULL);
  425. }