icmpv6_sendto.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508
  1. /****************************************************************************
  2. * net/icmpv6/icmpv6_sendto.c
  3. *
  4. * Copyright (C) 2017, 2019 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 <sys/types.h>
  40. #include <sys/socket.h>
  41. #include <stdint.h>
  42. #include <stdbool.h>
  43. #include <string.h>
  44. #include <semaphore.h>
  45. #include <assert.h>
  46. #include <debug.h>
  47. #include <netinet/in.h>
  48. #include <net/if.h>
  49. #include <arpa/inet.h>
  50. #include <nuttx/semaphore.h>
  51. #include <nuttx/mm/iob.h>
  52. #include <nuttx/net/netconfig.h>
  53. #include <nuttx/net/net.h>
  54. #include <nuttx/net/netdev.h>
  55. #include <nuttx/net/netstats.h>
  56. #include <nuttx/net/ip.h>
  57. #include <nuttx/net/icmpv6.h>
  58. #include "utils/utils.h"
  59. #include "socket/socket.h"
  60. #include "netdev/netdev.h"
  61. #include "devif/devif.h"
  62. #include "inet/inet.h"
  63. #include "icmpv6/icmpv6.h"
  64. #ifdef CONFIG_NET_ICMPv6_SOCKET
  65. /****************************************************************************
  66. * Pre-processor Definitions
  67. ****************************************************************************/
  68. #define IPv6BUF \
  69. ((struct ipv6_hdr_s *)&dev->d_buf[NET_LL_HDRLEN(dev)])
  70. #define ICMPv6BUF \
  71. ((struct icmpv6_echo_request_s *)&dev->d_buf[NET_LL_HDRLEN(dev) + IPv6_HDRLEN])
  72. /****************************************************************************
  73. * Private Types
  74. ****************************************************************************/
  75. struct icmpv6_sendto_s
  76. {
  77. FAR struct devif_callback_s *snd_cb; /* Reference to callback instance */
  78. FAR struct socket *snd_sock; /* IPPROTO_ICMP6 socket structure */
  79. sem_t snd_sem; /* Use to manage the wait for send complete */
  80. clock_t snd_time; /* Start time for determining timeouts */
  81. struct in6_addr snd_toaddr; /* The peer to send the request to */
  82. FAR const uint8_t *snd_buf; /* ICMPv6 header + data payload */
  83. uint16_t snd_buflen; /* Size of the ICMPv6 header + data payload */
  84. int16_t snd_result; /* 0: success; <0:negated errno on fail */
  85. };
  86. /****************************************************************************
  87. * Private Functions
  88. ****************************************************************************/
  89. /****************************************************************************
  90. * Name: sendto_timeout
  91. *
  92. * Description:
  93. * Check for send timeout.
  94. *
  95. * Input Parameters:
  96. * pstate - Reference to instance ot sendto state structure
  97. *
  98. * Returned Value:
  99. * true: timeout false: no timeout
  100. *
  101. * Assumptions:
  102. * The network is locked
  103. *
  104. ****************************************************************************/
  105. #ifdef CONFIG_NET_SOCKOPTS
  106. static inline int sendto_timeout(FAR struct icmpv6_sendto_s *pstate)
  107. {
  108. FAR struct socket *psock;
  109. /* Check for a timeout configured via setsockopts(SO_SNDTIMEO).
  110. * If none... we will let the send wait forever.
  111. */
  112. psock = pstate->snd_sock;
  113. if (psock != NULL && psock->s_sndtimeo != 0)
  114. {
  115. /* Check if the configured timeout has elapsed */
  116. return net_timeo(pstate->snd_time, psock->s_sndtimeo);
  117. }
  118. /* No timeout */
  119. return false;
  120. }
  121. #endif /* CONFIG_NET_SOCKOPTS */
  122. /****************************************************************************
  123. * Name: sendto_request
  124. *
  125. * Description:
  126. * Setup to send an ICMPv6 request packet
  127. *
  128. * Input Parameters:
  129. * dev - The device driver structure to use in the send operation
  130. * pstate - Reference to an instance of the ICMPv6 sendto state structure
  131. *
  132. * Returned Value:
  133. * None
  134. *
  135. * Assumptions:
  136. * The network is locked.
  137. *
  138. ****************************************************************************/
  139. static void sendto_request(FAR struct net_driver_s *dev,
  140. FAR struct icmpv6_sendto_s *pstate)
  141. {
  142. FAR struct ipv6_hdr_s *ipv6;
  143. FAR struct icmpv6_echo_request_s *icmpv6;
  144. IFF_SET_IPv6(dev->d_flags);
  145. /* The total length to send is the size of the application data plus the
  146. * IP and ICMPv6 headers (and, eventually, the Ethernet header)
  147. */
  148. dev->d_len = IPv6_HDRLEN + pstate->snd_buflen;
  149. /* The total size of the data (including the size of the ICMPv6 header) */
  150. dev->d_sndlen += pstate->snd_buflen;
  151. /* Set up the IPv6 header (most is probably already in place) */
  152. ipv6 = IPv6BUF;
  153. ipv6->vtc = 0x60; /* Version/traffic class (MS) */
  154. ipv6->tcf = 0; /* Traffic class(LS)/Flow label(MS) */
  155. ipv6->flow = 0; /* Flow label (LS) */
  156. ipv6->len[0] = (pstate->snd_buflen >> 8); /* Length excludes the IPv6 header */
  157. ipv6->len[1] = (pstate->snd_buflen & 0xff);
  158. ipv6->proto = IP_PROTO_ICMP6; /* Next header */
  159. ipv6->ttl = 255; /* Hop limit */
  160. net_ipv6addr_hdrcopy(ipv6->srcipaddr, dev->d_ipv6addr);
  161. net_ipv6addr_hdrcopy(ipv6->destipaddr, pstate->snd_toaddr.s6_addr16);
  162. /* Copy the ICMPv6 request and payload into place after the IPv6 header */
  163. icmpv6 = ICMPv6BUF;
  164. memcpy(icmpv6, pstate->snd_buf, pstate->snd_buflen);
  165. /* Calculate the ICMPv6 checksum over the ICMPv6 header and payload. */
  166. icmpv6->chksum = 0;
  167. icmpv6->chksum = ~icmpv6_chksum(dev, IPv6_HDRLEN);
  168. if (icmpv6->chksum == 0)
  169. {
  170. icmpv6->chksum = 0xffff;
  171. }
  172. ninfo("Outgoing ICMPv6 packet length: %d (%d)\n",
  173. dev->d_len, (ipv6->len[0] << 8) | ipv6->len[1]);
  174. #ifdef CONFIG_NET_STATISTICS
  175. g_netstats.icmpv6.sent++;
  176. g_netstats.ipv6.sent++;
  177. #endif
  178. }
  179. /****************************************************************************
  180. * Name: sendto_eventhandler
  181. *
  182. * Description:
  183. * This function is called with the network locked to perform the actual
  184. * ECHO request and/or ECHO reply actions when polled by the lower, device
  185. * interfacing layer.
  186. *
  187. * Input Parameters:
  188. * dev The structure of the network driver that generated the
  189. * event
  190. * pvconn The received packet, cast to (void *)
  191. * pvpriv An instance of struct icmpv6_sendto_s cast to (void *)
  192. * flags Set of events describing why the callback was invoked
  193. *
  194. * Returned Value:
  195. * Modified value of the input flags
  196. *
  197. * Assumptions:
  198. * The network is locked.
  199. *
  200. ****************************************************************************/
  201. static uint16_t sendto_eventhandler(FAR struct net_driver_s *dev,
  202. FAR void *pvconn,
  203. FAR void *pvpriv, uint16_t flags)
  204. {
  205. FAR struct icmpv6_sendto_s *pstate = (struct icmpv6_sendto_s *)pvpriv;
  206. ninfo("flags: %04x\n", flags);
  207. if (pstate != NULL)
  208. {
  209. /* Check if the network is still up */
  210. if ((flags & NETDEV_DOWN) != 0)
  211. {
  212. nerr("ERROR: Interface is down\n");
  213. pstate->snd_result = -ENETUNREACH;
  214. goto end_wait;
  215. }
  216. /* Check:
  217. * If the outgoing packet is available (it may have been claimed
  218. * by a sendto event handler serving a different thread)
  219. * -OR-
  220. * If the output buffer currently contains unprocessed incoming
  221. * data.
  222. * -OR-
  223. * If we have already sent the ECHO request
  224. *
  225. * In the first two cases, we will just have to wait for the next
  226. * polling cycle.
  227. */
  228. if (dev->d_sndlen <= 0 && /* Packet available */
  229. (flags & ICMPv6_NEWDATA) == 0) /* No incoming data */
  230. {
  231. /* Send the ICMPv6 echo request. */
  232. ninfo("Send ICMPv6 ECHO request\n");
  233. sendto_request(dev, pstate);
  234. pstate->snd_result = OK;
  235. goto end_wait;
  236. }
  237. #ifdef CONFIG_NET_SOCKOPTS
  238. /* Check if the selected timeout has elapsed */
  239. if (sendto_timeout(pstate))
  240. {
  241. int failcode;
  242. /* Check if this device is on the same network as the destination
  243. * device.
  244. */
  245. if (!net_ipv6addr_maskcmp(pstate->snd_toaddr.s6_addr16,
  246. dev->d_ipv6addr, dev->d_ipv6netmask))
  247. {
  248. /* Destination address was not on the local network served by this
  249. * device. If a timeout occurs, then the most likely reason is
  250. * that the destination address is not reachable.
  251. */
  252. nerr("ERROR: Not reachable\n");
  253. failcode = -ENETUNREACH;
  254. }
  255. else
  256. {
  257. nerr("ERROR: sendto() timeout\n");
  258. failcode = -ETIMEDOUT;
  259. }
  260. /* Report the failure */
  261. pstate->snd_result = failcode;
  262. goto end_wait;
  263. }
  264. #endif
  265. /* Continue waiting */
  266. }
  267. return flags;
  268. end_wait:
  269. ninfo("Resuming\n");
  270. /* Do not allow any further callbacks */
  271. pstate->snd_cb->flags = 0;
  272. pstate->snd_cb->priv = NULL;
  273. pstate->snd_cb->event = NULL;
  274. /* Wake up the waiting thread */
  275. nxsem_post(&pstate->snd_sem);
  276. return flags;
  277. }
  278. /****************************************************************************
  279. * Public Functions
  280. ****************************************************************************/
  281. /****************************************************************************
  282. * Name: icmpv6_sendto
  283. *
  284. * Description:
  285. * Implements the sendto() operation for the case of the IPPROTO_ICMP6
  286. * socket. The 'buf' parameter points to a block of memory that includes
  287. * an ICMPv6 request header, followed by any payload that accompanies the
  288. * request. The 'len' parameter includes both the size of the ICMPv6 header
  289. * and the following payload.
  290. *
  291. * Input Parameters:
  292. * psock A pointer to a NuttX-specific, internal socket structure
  293. * buf Data to send
  294. * len Length of data to send
  295. * flags Send flags
  296. * to Address of recipient
  297. * tolen The length of the address structure
  298. *
  299. * Returned Value:
  300. * On success, returns the number of characters sent. On error, a negated
  301. * errno value is returned (see send_to() for the list of appropriate error
  302. * values.
  303. *
  304. ****************************************************************************/
  305. ssize_t icmpv6_sendto(FAR struct socket *psock, FAR const void *buf, size_t len,
  306. int flags, FAR const struct sockaddr *to, socklen_t tolen)
  307. {
  308. FAR const struct sockaddr_in6 *inaddr;
  309. FAR struct net_driver_s *dev;
  310. FAR struct icmpv6_conn_s *conn;
  311. FAR struct icmpv6_echo_request_s *icmpv6;
  312. struct icmpv6_sendto_s state;
  313. int ret;
  314. /* Some sanity checks */
  315. DEBUGASSERT(psock != NULL && psock->s_conn != NULL &&
  316. buf != NULL && to != NULL);
  317. if (len < ICMPv6_HDRLEN || tolen < sizeof(struct sockaddr_in6))
  318. {
  319. return -EINVAL;
  320. }
  321. conn = psock->s_conn;
  322. inaddr = (FAR const struct sockaddr_in6 *)to;
  323. /* Get the device that will be used to route this ICMPv6 ECHO request */
  324. dev = netdev_findby_ripv6addr(g_ipv6_unspecaddr,
  325. inaddr->sin6_addr.s6_addr16);
  326. if (dev == NULL)
  327. {
  328. nerr("ERROR: Not reachable\n");
  329. ret = -ENETUNREACH;
  330. goto errout;
  331. }
  332. /* If we are no longer processing the same ping ID, then flush any pending
  333. * packets from the read-ahead buffer.
  334. *
  335. * REVISIT: How to we free up any lingering reponses if there are no
  336. * futher pings?
  337. */
  338. icmpv6 = (FAR struct icmpv6_echo_request_s *)buf;
  339. if (icmpv6->type != ICMPv6_ECHO_REQUEST || icmpv6->id != conn->id ||
  340. dev != conn->dev)
  341. {
  342. conn->id = 0;
  343. conn->nreqs = 0;
  344. conn->dev = NULL;
  345. iob_free_queue(&conn->readahead, IOBUSER_NET_SOCK_ICMPv6);
  346. }
  347. #ifdef CONFIG_NET_ICMPv6_NEIGHBOR
  348. /* Make sure that the IP address mapping is in the Neighbor Table */
  349. ret = icmpv6_neighbor(inaddr->sin6_addr.s6_addr16);
  350. if (ret < 0)
  351. {
  352. nerr("ERROR: Not reachable\n");
  353. ret = -ENETUNREACH;
  354. goto errout;
  355. }
  356. #endif /* CONFIG_NET_ICMPv6_NEIGHBOR */
  357. /* Initialize the state structure */
  358. /* This semaphore is used for signaling and, hence, should not have
  359. * priority inheritance enabled.
  360. */
  361. nxsem_init(&state.snd_sem, 0, 0);
  362. nxsem_setprotocol(&state.snd_sem, SEM_PRIO_NONE);
  363. state.snd_sock = psock; /* The IPPROTO_ICMP6 socket instance */
  364. state.snd_result = -ENOMEM; /* Assume allocation failure */
  365. state.snd_buf = buf; /* ICMPv6 header + data payload */
  366. state.snd_buflen = len; /* Size of the ICMPv6 header+data payload */
  367. net_ipv6addr_copy(state.snd_toaddr.s6_addr16,
  368. inaddr->sin6_addr.s6_addr16);
  369. net_lock();
  370. state.snd_time = clock_systimer();
  371. /* Set up the callback */
  372. state.snd_cb = icmpv6_callback_alloc(dev, conn);
  373. if (state.snd_cb)
  374. {
  375. state.snd_cb->flags = (ICMPv6_POLL | NETDEV_DOWN);
  376. state.snd_cb->priv = (FAR void *)&state;
  377. state.snd_cb->event = sendto_eventhandler;
  378. state.snd_result = -EINTR; /* Assume sem-wait interrupted by signal */
  379. /* Setup to receive ICMPv6 ECHO replies */
  380. if (icmpv6->type == ICMPv6_ECHO_REQUEST)
  381. {
  382. conn->id = icmpv6->id;
  383. conn->nreqs = 1;
  384. }
  385. conn->dev = dev;
  386. /* Notify the device driver of the availability of TX data */
  387. netdev_txnotify_dev(dev);
  388. /* Wait for either the send to complete or for timeout to occur.
  389. * net_lockedwait will also terminate if a signal is received.
  390. */
  391. ninfo("Start time: 0x%08x\n", state.snd_time);
  392. net_lockedwait(&state.snd_sem);
  393. icmpv6_callback_free(dev, conn, state.snd_cb);
  394. }
  395. net_unlock();
  396. /* Return the negated error number in the event of a failure, or the
  397. * number of bytes sent on success.
  398. */
  399. if (state.snd_result < 0)
  400. {
  401. nerr("ERROR: Return error=%d\n", state.snd_result);
  402. ret = state.snd_result;
  403. goto errout;
  404. }
  405. return len;
  406. errout:
  407. conn->id = 0;
  408. conn->nreqs = 0;
  409. conn->dev = NULL;
  410. iob_free_queue(&conn->readahead, IOBUSER_NET_SOCK_ICMPv6);
  411. return ret;
  412. }
  413. #endif /* CONFIG_NET_ICMPv6_SOCKET */