icmp_sendmsg.c 14 KB

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