icmpv6_sendmsg.c 14 KB

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