icmpv6_netpoll.c 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333
  1. /****************************************************************************
  2. * net/icmpv6/icmpv6_netpoll.c
  3. *
  4. * Copyright (C) 2017-2018 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 <stdint.h>
  40. #include <poll.h>
  41. #include <debug.h>
  42. #include <nuttx/kmalloc.h>
  43. #include <nuttx/net/net.h>
  44. #include <devif/devif.h>
  45. #include "netdev/netdev.h"
  46. #include "icmpv6/icmpv6.h"
  47. #ifdef CONFIG_MM_IOB
  48. /****************************************************************************
  49. * Private Types
  50. ****************************************************************************/
  51. /* This is an allocated container that holds the poll-related information */
  52. struct icmpv6_poll_s
  53. {
  54. FAR struct socket *psock; /* IPPROTO_ICMP6 socket structure */
  55. FAR struct pollfd *fds; /* Needed to handle poll events */
  56. FAR struct devif_callback_s *cb; /* Needed to teardown the poll */
  57. };
  58. /****************************************************************************
  59. * Private Functions
  60. ****************************************************************************/
  61. /****************************************************************************
  62. * Name: icmpv6_poll_eventhandler
  63. *
  64. * Description:
  65. * This function is called to perform the actual UDP receive operation
  66. * via the device interface layer.
  67. *
  68. * Input Parameters:
  69. * dev The structure of the network driver that caused the event
  70. * conn The connection structure associated with the socket
  71. * flags Set of events describing why the callback was invoked
  72. *
  73. * Returned Value:
  74. * None
  75. *
  76. * Assumptions:
  77. * This function must be called with the network locked.
  78. *
  79. ****************************************************************************/
  80. static uint16_t icmpv6_poll_eventhandler(FAR struct net_driver_s *dev,
  81. FAR void *pvconn,
  82. FAR void *pvpriv, uint16_t flags)
  83. {
  84. FAR struct icmpv6_poll_s *info = (FAR struct icmpv6_poll_s *)pvpriv;
  85. FAR struct icmpv6_conn_s *conn;
  86. FAR struct socket *psock;
  87. pollevent_t eventset;
  88. ninfo("flags: %04x\n", flags);
  89. DEBUGASSERT(info == NULL || info->fds != NULL);
  90. /* 'priv' might be null in some race conditions (?). Only process the
  91. * the event if this poll is from the same device that the request was
  92. * sent out on.
  93. */
  94. if (info != NULL)
  95. {
  96. /* Is this a response on the same device that we sent the request out
  97. * on?
  98. */
  99. psock = info->psock;
  100. DEBUGASSERT(psock != NULL && psock->s_conn != NULL);
  101. conn = psock->s_conn;
  102. if (dev != conn->dev)
  103. {
  104. ninfo("Wrong device\n");
  105. return flags;
  106. }
  107. /* Check for data or connection availability events. */
  108. eventset = 0;
  109. if ((flags & ICMPv6_ECHOREPLY) != 0)
  110. {
  111. eventset |= (POLLIN & info->fds->events);
  112. }
  113. /* ICMP_POLL is a sign that we are free to send data. */
  114. if ((flags & DEVPOLL_MASK) == ICMPv6_POLL)
  115. {
  116. eventset |= (POLLOUT & info->fds->events);
  117. }
  118. /* Check for loss of connection events. */
  119. if ((flags & NETDEV_DOWN) != 0)
  120. {
  121. eventset |= ((POLLHUP | POLLERR) & info->fds->events);
  122. }
  123. /* Awaken the caller of poll() is requested event occurred. */
  124. if (eventset)
  125. {
  126. info->fds->revents |= eventset;
  127. nxsem_post(info->fds->sem);
  128. }
  129. }
  130. return flags;
  131. }
  132. /****************************************************************************
  133. * Public Functions
  134. ****************************************************************************/
  135. /****************************************************************************
  136. * Name: icmpv6_pollsetup
  137. *
  138. * Description:
  139. * Setup to monitor events on one ICMP socket
  140. *
  141. * Input Parameters:
  142. * psock - The IPPROTO_ICMP socket of interest
  143. * fds - The structure describing the events to be monitored, OR NULL if
  144. * this is a request to stop monitoring events.
  145. *
  146. * Returned Value:
  147. * 0: Success; Negated errno on failure
  148. *
  149. ****************************************************************************/
  150. int icmpv6_pollsetup(FAR struct socket *psock, FAR struct pollfd *fds)
  151. {
  152. FAR struct icmpv6_conn_s *conn = psock->s_conn;
  153. FAR struct icmpv6_poll_s *info;
  154. FAR struct devif_callback_s *cb;
  155. int ret;
  156. DEBUGASSERT(conn != NULL && fds != NULL);
  157. /* Allocate a container to hold the poll information */
  158. info = (FAR struct icmpv6_poll_s *)kmm_malloc(sizeof(struct icmpv6_poll_s));
  159. if (!info)
  160. {
  161. return -ENOMEM;
  162. }
  163. /* Some of the following must be atomic */
  164. net_lock();
  165. /* Get the device that will provide the provide the NETDEV_DOWN event.
  166. * NOTE: in the event that the local socket is bound to IN6ADDR_ANY, the
  167. * dev value will be zero and there will be no NETDEV_DOWN notifications.
  168. */
  169. /* Allocate a ICMP callback structure */
  170. if (conn->dev == NULL)
  171. {
  172. conn->dev = netdev_default();
  173. }
  174. cb = icmpv6_callback_alloc(conn->dev);
  175. if (cb == NULL)
  176. {
  177. ret = -EBUSY;
  178. goto errout_with_lock;
  179. }
  180. /* Initialize the poll info container */
  181. info->psock = psock;
  182. info->fds = fds;
  183. info->cb = cb;
  184. /* Initialize the callback structure. Save the reference to the info
  185. * structure as callback private data so that it will be available during
  186. * callback processing.
  187. */
  188. cb->flags = 0;
  189. cb->priv = (FAR void *)info;
  190. cb->event = icmpv6_poll_eventhandler;
  191. if ((info->fds->events & POLLOUT) != 0)
  192. {
  193. cb->flags |= ICMPv6_POLL;
  194. }
  195. if ((info->fds->events & POLLIN) != 0)
  196. {
  197. cb->flags |= ICMPv6_NEWDATA;
  198. }
  199. if ((info->fds->events & (POLLHUP | POLLERR)) != 0)
  200. {
  201. cb->flags |= NETDEV_DOWN;
  202. }
  203. /* Save the reference in the poll info structure as fds private as well
  204. * for use during poll teardown as well.
  205. */
  206. fds->priv = (FAR void *)info;
  207. /* Check for read data availability now */
  208. if (!IOB_QEMPTY(&conn->readahead))
  209. {
  210. /* Normal data may be read without blocking. */
  211. fds->revents |= (POLLRDNORM & fds->events);
  212. }
  213. /* Check if any requested events are already in effect */
  214. if (fds->revents != 0)
  215. {
  216. /* Yes.. then signal the poll logic */
  217. nxsem_post(fds->sem);
  218. }
  219. net_unlock();
  220. return OK;
  221. errout_with_lock:
  222. kmm_free(info);
  223. net_unlock();
  224. return ret;
  225. }
  226. /****************************************************************************
  227. * Name: icmpv6_pollteardown
  228. *
  229. * Description:
  230. * Teardown monitoring of events on an ICMP socket
  231. *
  232. * Input Parameters:
  233. * psock - The IPPROTO_ICMP socket of interest
  234. * fds - The structure describing the events to be monitored, OR NULL if
  235. * this is a request to stop monitoring events.
  236. *
  237. * Returned Value:
  238. * 0: Success; Negated errno on failure
  239. *
  240. ****************************************************************************/
  241. int icmpv6_pollteardown(FAR struct socket *psock, FAR struct pollfd *fds)
  242. {
  243. FAR struct icmpv6_conn_s *conn;
  244. FAR struct icmpv6_poll_s *info;
  245. DEBUGASSERT(psock != NULL && psock->s_conn != NULL &&
  246. fds != NULL && fds->priv != NULL);
  247. conn = psock->s_conn;
  248. /* Recover the socket descriptor poll state info from the poll structure */
  249. info = (FAR struct icmpv6_poll_s *)fds->priv;
  250. DEBUGASSERT(info != NULL && info->fds != NULL && info->cb != NULL);
  251. if (info != NULL)
  252. {
  253. /* Release the callback */
  254. net_lock();
  255. icmpv6_callback_free(conn->dev, info->cb);
  256. net_unlock();
  257. /* Release the poll/select data slot */
  258. info->fds->priv = NULL;
  259. /* Then free the poll info container */
  260. kmm_free(info);
  261. }
  262. return OK;
  263. }
  264. #endif /* !CONFIG_MM_IOB */