icmpv6_rnotify.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354
  1. /****************************************************************************
  2. * net/icmpv6/icmpv6_rnotify.c
  3. *
  4. * Copyright (C) 2015-2016 Gregory Nutt. All rights reserved.
  5. * Author: Gregory Nutt <gnutt@nuttx.org>
  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. *
  11. * 1. Redistributions of source code must retain the above copyright
  12. * notice, this list of conditions and the following disclaimer.
  13. * 2. Redistributions in binary form must reproduce the above copyright
  14. * notice, this list of conditions and the following disclaimer in
  15. * the documentation and/or other materials provided with the
  16. * distribution.
  17. * 3. Neither the name NuttX nor the names of its contributors may be
  18. * used to endorse or promote products derived from this software
  19. * without specific prior written permission.
  20. *
  21. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  22. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  23. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  24. * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  25. * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  26. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  27. * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
  28. * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
  29. * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  30. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
  31. * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  32. * POSSIBILITY OF SUCH DAMAGE.
  33. *
  34. ****************************************************************************/
  35. /****************************************************************************
  36. * Included Files
  37. ****************************************************************************/
  38. #include <nuttx/config.h>
  39. #include <string.h>
  40. #include <time.h>
  41. #include <semaphore.h>
  42. #include <errno.h>
  43. #include <debug.h>
  44. #include <netinet/in.h>
  45. #include <nuttx/irq.h>
  46. #include <nuttx/semaphore.h>
  47. #include <nuttx/net/net.h>
  48. #include <nuttx/net/netdev.h>
  49. #include "netdev/netdev.h"
  50. #include "utils/utils.h"
  51. #include "icmpv6/icmpv6.h"
  52. #ifdef CONFIG_NET_ICMPv6_AUTOCONF
  53. /****************************************************************************
  54. * Pre-processor Definitions
  55. ****************************************************************************/
  56. /****************************************************************************
  57. * Private Types
  58. ****************************************************************************/
  59. /****************************************************************************
  60. * Private Data
  61. ****************************************************************************/
  62. /* List of tasks waiting for Neighbor Discover events */
  63. static struct icmpv6_rnotify_s *g_icmpv6_rwaiters;
  64. /****************************************************************************
  65. * Private Functions
  66. ****************************************************************************/
  67. /****************************************************************************
  68. * Name: icmpv6_setaddresses
  69. *
  70. * Description:
  71. * We successfully obtained the Router Advertisement. See the new IPv6
  72. * addresses in the driver structure.
  73. *
  74. ****************************************************************************/
  75. static void icmpv6_setaddresses(FAR struct net_driver_s *dev,
  76. const net_ipv6addr_t draddr,
  77. const net_ipv6addr_t prefix,
  78. unsigned int preflen)
  79. {
  80. unsigned int i;
  81. /* Lock the network.
  82. *
  83. * NOTE: Normally it is required that the network be in the "down" state
  84. * when re-configuring the network interface. This is thought not to be
  85. * a problem here because.
  86. *
  87. * 1. The ICMPv6 logic here runs with the network locked so there can be
  88. * no outgoing packets with bad source IP addresses from any
  89. * asynchronous network activity using the device being reconfigured.
  90. * 2. Incoming packets depend only upon the MAC filtering. Network
  91. * drivers do not use the IP address; they filter incoming packets
  92. * using only the MAC address which is not being changed here.
  93. */
  94. net_lock();
  95. /* Create an address mask from the prefix */
  96. if (preflen > 128)
  97. {
  98. preflen = 128;
  99. }
  100. net_ipv6_pref2mask(preflen, dev->d_ipv6netmask);
  101. ninfo("preflen=%d netmask=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n",
  102. preflen, dev->d_ipv6netmask[0], dev->d_ipv6netmask[1],
  103. dev->d_ipv6netmask[2], dev->d_ipv6netmask[3], dev->d_ipv6netmask[4],
  104. dev->d_ipv6netmask[5], dev->d_ipv6netmask[6], dev->d_ipv6netmask[7]);
  105. /* Copy prefix to the current IPv6 address, applying the mask */
  106. for (i = 0; i < 7; i++)
  107. {
  108. dev->d_ipv6addr[i] = (dev->d_ipv6addr[i] & ~dev->d_ipv6netmask[i]) |
  109. (prefix[i] & dev->d_ipv6netmask[i]);
  110. }
  111. ninfo("prefix=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n",
  112. prefix[0], prefix[1], prefix[2], prefix[3],
  113. prefix[4], prefix[6], prefix[6], prefix[7]);
  114. ninfo("IP address=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n",
  115. dev->d_ipv6addr[0], dev->d_ipv6addr[1], dev->d_ipv6addr[2],
  116. dev->d_ipv6addr[3], dev->d_ipv6addr[4], dev->d_ipv6addr[6],
  117. dev->d_ipv6addr[6], dev->d_ipv6addr[7]);
  118. /* Finally, copy the router address */
  119. net_ipv6addr_copy(dev->d_ipv6draddr, draddr);
  120. ninfo("DR address=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n",
  121. dev->d_ipv6draddr[0], dev->d_ipv6draddr[1], dev->d_ipv6draddr[2],
  122. dev->d_ipv6draddr[3], dev->d_ipv6draddr[4], dev->d_ipv6draddr[6],
  123. dev->d_ipv6draddr[6], dev->d_ipv6draddr[7]);
  124. net_unlock();
  125. }
  126. /****************************************************************************
  127. * Public Functions
  128. ****************************************************************************/
  129. /****************************************************************************
  130. * Name: icmpv6_rwait_setup
  131. *
  132. * Description:
  133. * Called BEFORE an Router Solicitation is sent. This function sets up
  134. * the Router Advertisement timeout before the Router Solicitation
  135. * is sent so that there is no race condition when icmpv6_rwait() is
  136. * called.
  137. *
  138. * Assumptions:
  139. * This function is called from icmpv6_autoconfig() and executes in the
  140. * normal tasking environment.
  141. *
  142. ****************************************************************************/
  143. void icmpv6_rwait_setup(FAR struct net_driver_s *dev,
  144. FAR struct icmpv6_rnotify_s *notify)
  145. {
  146. irqstate_t flags;
  147. /* Initialize the wait structure */
  148. memcpy(notify->rn_ifname, dev->d_ifname, IFNAMSIZ);
  149. notify->rn_result = -ETIMEDOUT;
  150. /* This semaphore is used for signaling and, hence, should not have
  151. * priority inheritance enabled.
  152. */
  153. (void)nxsem_init(&notify->rn_sem, 0, 0);
  154. nxsem_setprotocol(&notify->rn_sem, SEM_PRIO_NONE);
  155. /* Add the wait structure to the list with interrupts disabled */
  156. flags = enter_critical_section();
  157. notify->rn_flink = g_icmpv6_rwaiters;
  158. g_icmpv6_rwaiters = notify;
  159. leave_critical_section(flags);
  160. }
  161. /****************************************************************************
  162. * Name: icmpv6_rwait_cancel
  163. *
  164. * Description:
  165. * Cancel any wait set after icmpv6_rwait_setup() is called but before
  166. * icmpv6_rwait()is called (icmpv6_rwait() will automatically cancel the
  167. * wait).
  168. *
  169. * Assumptions:
  170. * This function may execute in the interrupt context when called from
  171. * icmpv6_rwait().
  172. *
  173. ****************************************************************************/
  174. int icmpv6_rwait_cancel(FAR struct icmpv6_rnotify_s *notify)
  175. {
  176. FAR struct icmpv6_rnotify_s *curr;
  177. FAR struct icmpv6_rnotify_s *prev;
  178. irqstate_t flags;
  179. int ret = -ENOENT;
  180. ninfo("Canceling...\n");
  181. /* Remove our wait structure from the list (we may no longer be at the
  182. * head of the list).
  183. */
  184. flags = enter_critical_section();
  185. for (prev = NULL, curr = g_icmpv6_rwaiters;
  186. curr && curr != notify;
  187. prev = curr, curr = curr->rn_flink);
  188. DEBUGASSERT(curr && curr == notify);
  189. if (curr)
  190. {
  191. if (prev)
  192. {
  193. prev->rn_flink = notify->rn_flink;
  194. }
  195. else
  196. {
  197. g_icmpv6_rwaiters = notify->rn_flink;
  198. }
  199. ret = OK;
  200. }
  201. leave_critical_section(flags);
  202. (void)nxsem_destroy(&notify->rn_sem);
  203. return ret;
  204. }
  205. /****************************************************************************
  206. * Name: icmpv6_rwait
  207. *
  208. * Description:
  209. * Called each time that a Router Solicitation is sent. This function
  210. * will sleep until either: (1) the matching Router Advertisement is
  211. * received, or (2) a timeout occurs.
  212. *
  213. * Assumptions:
  214. * This function is called from icmpv6_autoconfig() and must execute with
  215. * the network locked.
  216. *
  217. ****************************************************************************/
  218. int icmpv6_rwait(FAR struct icmpv6_rnotify_s *notify,
  219. FAR struct timespec *timeout)
  220. {
  221. struct timespec abstime;
  222. irqstate_t flags;
  223. int ret;
  224. ninfo("Waiting...\n");
  225. /* And wait for the Neighbor Advertisement (or a timeout). Interrupts will
  226. * be re-enabled while we wait.
  227. */
  228. flags = enter_critical_section();
  229. DEBUGVERIFY(clock_gettime(CLOCK_REALTIME, &abstime));
  230. abstime.tv_sec += timeout->tv_sec;
  231. abstime.tv_nsec += timeout->tv_nsec;
  232. if (abstime.tv_nsec >= 1000000000)
  233. {
  234. abstime.tv_sec++;
  235. abstime.tv_nsec -= 1000000000;
  236. }
  237. /* REVISIT: If net_timedwait() is awakened with signal, we will return
  238. * the wrong error code.
  239. */
  240. (void)net_timedwait(&notify->rn_sem, &abstime);
  241. ret = notify->rn_result;
  242. /* Remove our wait structure from the list (we may no longer be at the
  243. * head of the list).
  244. */
  245. (void)icmpv6_rwait_cancel(notify);
  246. /* Re-enable interrupts and return the result of the wait */
  247. leave_critical_section(flags);
  248. return ret;
  249. }
  250. /****************************************************************************
  251. * Name: icmpv6_rnotify
  252. *
  253. * Description:
  254. * Called each time that a Router Advertisement is received in order to
  255. * wake-up any threads that may be waiting for this particular Router
  256. * Advertisement.
  257. *
  258. * Assumptions:
  259. * This function is called from the MAC device driver indirectly through
  260. * icmpv6_icmpv6in() will execute with the network locked.
  261. *
  262. ****************************************************************************/
  263. void icmpv6_rnotify(FAR struct net_driver_s *dev, const net_ipv6addr_t draddr,
  264. const net_ipv6addr_t prefix, unsigned int preflen)
  265. {
  266. FAR struct icmpv6_rnotify_s *curr;
  267. ninfo("Notified\n");
  268. /* Find an entry with the matching device name in the list of waiters */
  269. for (curr = g_icmpv6_rwaiters; curr; curr = curr->rn_flink)
  270. {
  271. /* Does this entry match? If the result is okay, then we have
  272. * already notified this waiter and it has not yet taken the
  273. * entry from the list.
  274. */
  275. if (curr->rn_result != OK &&
  276. strncmp(curr->rn_ifname, dev->d_ifname, IFNAMSIZ) == 0)
  277. {
  278. /* Yes.. Set the new network addresses. */
  279. icmpv6_setaddresses(dev, draddr, prefix, preflen);
  280. /* And signal the waiting, returning success */
  281. curr->rn_result = OK;
  282. nxsem_post(&curr->rn_sem);
  283. break;
  284. }
  285. }
  286. }
  287. #endif /* CONFIG_NET_ICMPv6_AUTOCONF */