mld_join.c 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  1. /****************************************************************************
  2. * net/mld/mld_join.c
  3. *
  4. * Licensed to the Apache Software Foundation (ASF) under one or more
  5. * contributor license agreements. See the NOTICE file distributed with
  6. * this work for additional information regarding copyright ownership. The
  7. * ASF licenses this file to you under the Apache License, Version 2.0 (the
  8. * "License"); you may not use this file except in compliance with the
  9. * License. You may obtain a copy of the License at
  10. *
  11. * http://www.apache.org/licenses/LICENSE-2.0
  12. *
  13. * Unless required by applicable law or agreed to in writing, software
  14. * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  15. * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  16. * License for the specific language governing permissions and limitations
  17. * under the License.
  18. *
  19. ****************************************************************************/
  20. /****************************************************************************
  21. * Included Files
  22. ****************************************************************************/
  23. #include <nuttx/config.h>
  24. #include <assert.h>
  25. #include <debug.h>
  26. #include <netinet/in.h>
  27. #include <nuttx/net/netconfig.h>
  28. #include <nuttx/net/netstats.h>
  29. #include <nuttx/net/ip.h>
  30. #include <nuttx/net/mld.h>
  31. #include "netdev/netdev.h"
  32. #include "mld/mld.h"
  33. #ifdef CONFIG_NET_MLD
  34. /****************************************************************************
  35. * Public Functions
  36. ****************************************************************************/
  37. /****************************************************************************
  38. * Name: mld_group_startup
  39. *
  40. * Description:
  41. * Set up the startup actions when the first member from this host joins
  42. * the group.
  43. *
  44. * Assumptions:
  45. * The network is locked.
  46. *
  47. ****************************************************************************/
  48. static int mld_group_startup(FAR const struct ipv6_mreq *mrec,
  49. FAR struct net_driver_s *dev,
  50. FAR struct mld_group_s *group)
  51. {
  52. int ret;
  53. /* Send the Version 2 Multicast Listener Report (Assumes MLDv2 mode
  54. * initially).
  55. */
  56. MLD_STATINCR(g_netstats.mld.report_sched);
  57. ret = mld_waitmsg(group, MLD_SEND_V2REPORT);
  58. if (ret < 0)
  59. {
  60. mlderr("ERROR: Failed to schedule Report: %d\n", ret);
  61. return ret;
  62. }
  63. /* And start the timer at 1 second */
  64. SET_MLD_STARTUP(group->flags);
  65. group->count = MLD_UNSOLREPORT_COUNT - 1;
  66. mld_start_polltimer(group, MSEC2TICK(MLD_UNSOLREPORT_MSEC));
  67. /* Add the group (MAC) address to the Ethernet drivers MAC filter list */
  68. mld_addmcastmac(dev, mrec->ipv6mr_multiaddr.s6_addr16);
  69. return OK;
  70. }
  71. /****************************************************************************
  72. * Public Functions
  73. ****************************************************************************/
  74. /****************************************************************************
  75. * Name: mld_joingroup
  76. *
  77. * Description:
  78. * Add the specified group address to the group. This function
  79. * implements the logic for the IPV6_JOIN_GROUP socket option.
  80. *
  81. * The IPV6_JOIN_GROUP socket option is used to join a multicast group.
  82. * This is accomplished by using the setsockopt() API and specifying the
  83. * address of the ipv6_mreq structure containing the IPv6 multicast address
  84. * and the local IPv6 multicast interface index. The stack chooses a
  85. * default multicast interface if an interface index of 0 is passed. The
  86. * values specified in the IPV6_MREQ structure used by IPV6_JOIN_GROUP
  87. * and IPV6_LEAVE_GROUP must be symmetrical. The format of the ipv6_mreq
  88. * structure can be found in include/netinet/in.h
  89. *
  90. * Assumptions:
  91. * The network is locked.
  92. *
  93. ****************************************************************************/
  94. int mld_joingroup(FAR const struct ipv6_mreq *mrec)
  95. {
  96. FAR struct net_driver_s *dev;
  97. FAR struct mld_group_s *group;
  98. int ret;
  99. DEBUGASSERT(mrec != NULL);
  100. /* Assure that the group address is an IPv6 multicast address */
  101. if (!net_is_addr_mcast(mrec->ipv6mr_multiaddr.s6_addr16))
  102. {
  103. return -EINVAL;
  104. }
  105. /* Get the device from the interface index. Use the default network device
  106. * if an interface index of 0 is provided.
  107. */
  108. if (mrec->ipv6mr_interface == 0)
  109. {
  110. dev = netdev_default();
  111. }
  112. else
  113. {
  114. dev = netdev_findbyindex(mrec->ipv6mr_interface);
  115. }
  116. if (dev == NULL)
  117. {
  118. mlderr("ERROR: No device for this interface index: %u\n",
  119. mrec->ipv6mr_interface);
  120. return -ENODEV;
  121. }
  122. mldinfo("Join group: %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n",
  123. mrec->ipv6mr_multiaddr.s6_addr16[0],
  124. mrec->ipv6mr_multiaddr.s6_addr16[1],
  125. mrec->ipv6mr_multiaddr.s6_addr16[2],
  126. mrec->ipv6mr_multiaddr.s6_addr16[3],
  127. mrec->ipv6mr_multiaddr.s6_addr16[4],
  128. mrec->ipv6mr_multiaddr.s6_addr16[5],
  129. mrec->ipv6mr_multiaddr.s6_addr16[5],
  130. mrec->ipv6mr_multiaddr.s6_addr16[7]);
  131. /* Check if a this address is already in the group */
  132. group = mld_grpfind(dev, mrec->ipv6mr_multiaddr.s6_addr16);
  133. if (group == NULL)
  134. {
  135. /* No... allocate a new entry */
  136. mldinfo("Allocate new group entry\n");
  137. group = mld_grpalloc(dev, mrec->ipv6mr_multiaddr.s6_addr16);
  138. if (group == NULL)
  139. {
  140. return -ENOMEM;
  141. }
  142. /* Indicate one request to join the group from this host */
  143. group->njoins = 1;
  144. /* Set up the group startup operations */
  145. ret = mld_group_startup(mrec, dev, group);
  146. if (ret < 0)
  147. {
  148. mlderr("ERROR: Failed to start group: %d\n", ret);
  149. mld_grpfree(dev, group);
  150. return ret;
  151. }
  152. MLD_STATINCR(g_netstats.mld.njoins);
  153. /* REVISIT: It is expected that higher level logic will set up
  154. * the routing table entry for the new multicast address. That
  155. * is not done here.
  156. */
  157. }
  158. else
  159. {
  160. /* The group already exists; a task from this host is joining an
  161. * existing group.
  162. */
  163. mldinfo("Join existing group\n");
  164. #ifdef CONFIG_NET_MLD_ROUTER
  165. /* In the Router case this could still be the first join from this
  166. * host. If this is the first join from this host, then we need to
  167. * perform the group startup operations.
  168. */
  169. if (group->join == 0)
  170. {
  171. /* This is the for join from this host. Perform out start up
  172. * operations.
  173. */
  174. ret = mld_group_startup(mrec, dev, group);
  175. if (ret < 0)
  176. {
  177. mlderr("ERROR: Failed to start group: %d\n", ret);
  178. mld_grpfree(dev, group);
  179. return ret;
  180. }
  181. }
  182. #else
  183. /* Not a router? Then there must be another join from this host or
  184. * how could the group have been created?
  185. */
  186. DEBUGASSERT(group->njoins > 0);
  187. #endif
  188. /* Indicate one more request to join the group from this host */
  189. DEBUGASSERT(group->njoins < UINT8_MAX);
  190. group->njoins++;
  191. MLD_STATINCR(g_netstats.mld.njoins);
  192. }
  193. return OK;
  194. }
  195. #endif /* CONFIG_NET_MLD */