icmpv6_input.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598
  1. /****************************************************************************
  2. * net/icmpv6/icmpv6_input.c
  3. * Handling incoming ICMPv6 input
  4. *
  5. * Copyright (C) 2015, 2017-2018 Gregory Nutt. All rights reserved.
  6. * Author: Gregory Nutt <gnutt@nuttx.org>
  7. *
  8. * Adapted for NuttX from logic in uIP which also has a BSD-like license:
  9. *
  10. * Original author Adam Dunkels <adam@dunkels.com>
  11. * Copyright () 2001-2003, Adam Dunkels.
  12. * All rights reserved.
  13. *
  14. * Redistribution and use in source and binary forms, with or without
  15. * modification, are permitted provided that the following conditions
  16. * are met:
  17. *
  18. * 1. Redistributions of source code must retain the above copyright
  19. * notice, this list of conditions and the following disclaimer.
  20. * 2. Redistributions in binary form must reproduce the above copyright
  21. * notice, this list of conditions and the following disclaimer in the
  22. * documentation and/or other materials provided with the distribution.
  23. * 3. The name of the author may not be used to endorse or promote
  24. * products derived from this software without specific prior
  25. * written permission.
  26. *
  27. * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
  28. * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  29. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  30. * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
  31. * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  32. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
  33. * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  34. * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
  35. * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  36. * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  37. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  38. *
  39. ****************************************************************************/
  40. /****************************************************************************
  41. * Included Files
  42. ****************************************************************************/
  43. #include <nuttx/config.h>
  44. #include <stdint.h>
  45. #include <string.h>
  46. #include <debug.h>
  47. #include <nuttx/net/netconfig.h>
  48. #include <nuttx/net/netdev.h>
  49. #include <nuttx/net/netstats.h>
  50. #include <nuttx/net/icmpv6.h>
  51. #include "devif/devif.h"
  52. #include "neighbor/neighbor.h"
  53. #include "utils/utils.h"
  54. #include "icmpv6/icmpv6.h"
  55. #include "mld/mld.h"
  56. #ifdef CONFIG_NET_ICMPv6
  57. /****************************************************************************
  58. * Pre-processor Definitions
  59. ****************************************************************************/
  60. #define IPv6BUF ((FAR struct ipv6_hdr_s *)&dev->d_buf[NET_LL_HDRLEN(dev)])
  61. #define ICMPv6BUF ((FAR struct icmpv6_hdr_s *) \
  62. (&dev->d_buf[NET_LL_HDRLEN(dev)] + iplen))
  63. #define ICMPv6REPLY ((FAR struct icmpv6_echo_reply_s *)icmpv6)
  64. #define ICMPv6SIZE ((dev)->d_len - iplen)
  65. #define ICMPv6SOLICIT ((struct icmpv6_neighbor_solicit_s *)icmpv6)
  66. #define ICMPv6ADVERTISE ((struct icmpv6_neighbor_advertise_s *)icmpv6)
  67. #define ICMPv6RADVERTISE ((struct icmpv6_router_advertise_s *)icmpv6)
  68. #define MLDQUERY ((FAR struct mld_mcast_listen_query_s *)icmpv6)
  69. #define MLDREPORT_V1 ((FAR struct mld_mcast_listen_report_v1_s *)icmpv6)
  70. #define MLDREPORT_V2 ((FAR struct mld_mcast_listen_report_v2_s *)icmpv6)
  71. #define MLDDONE ((FAR struct mld_mcast_listen_done_s *)icmpv6)
  72. /****************************************************************************
  73. * Private Functions
  74. ****************************************************************************/
  75. /****************************************************************************
  76. * Name: icmpv6_datahandler
  77. *
  78. * Description:
  79. * Handle ICMPv6 echo replies that are not accepted by the application.
  80. *
  81. * Input Parameters:
  82. * dev - Device instance only the input packet in d_buf, length = d_len;
  83. * conn - A pointer to the ICMPv6 connection structure
  84. * buffer - A pointer to the buffer to be copied to the read-ahead
  85. * buffers
  86. * buflen - The number of bytes to copy to the read-ahead buffer.
  87. *
  88. * Returned Value:
  89. * The number of bytes actually buffered is returned. This will be either
  90. * zero or equal to buflen; partial packets are not buffered.
  91. *
  92. ****************************************************************************/
  93. #ifdef CONFIG_NET_ICMPv6_SOCKET
  94. static uint16_t icmpv6_datahandler(FAR struct net_driver_s *dev,
  95. FAR struct icmpv6_conn_s *conn,
  96. unsigned int iplen)
  97. {
  98. FAR struct ipv6_hdr_s *ipv6;
  99. FAR struct icmpv6_hdr_s *icmpv6;
  100. FAR struct iob_s *iob;
  101. struct sockaddr_in6 inaddr;
  102. uint16_t offset;
  103. uint16_t buflen;
  104. uint8_t addrsize;
  105. int ret;
  106. /* Try to allocate on I/O buffer to start the chain without waiting (and
  107. * throttling as necessary). If we would have to wait, then drop the
  108. * packet.
  109. */
  110. iob = iob_tryalloc(true, IOBUSER_NET_SOCK_ICMPv6);
  111. if (iob == NULL)
  112. {
  113. nerr("ERROR: Failed to create new I/O buffer chain\n");
  114. goto drop;
  115. }
  116. /* Put the IPv6 address at the beginning of the read-ahead buffer */
  117. ipv6 = IPv6BUF;
  118. inaddr.sin6_family = AF_INET6;
  119. inaddr.sin6_port = 0;
  120. net_ipv6addr_copy(inaddr.sin6_addr.s6_addr16, ipv6->srcipaddr);
  121. /* Copy the src address info into the I/O buffer chain. We will not wait
  122. * for an I/O buffer to become available in this context. It there is
  123. * any failure to allocated, the entire I/O buffer chain will be discarded.
  124. */
  125. addrsize = sizeof(struct sockaddr_in6);
  126. ret = iob_trycopyin(iob, &addrsize, sizeof(uint8_t), 0, true,
  127. IOBUSER_NET_SOCK_ICMPv6);
  128. if (ret < 0)
  129. {
  130. /* On a failure, iob_trycopyin return a negated error value but does
  131. * not free any I/O buffers.
  132. */
  133. nerr("ERROR: Failed to length to the I/O buffer chain: %d\n", ret);
  134. goto drop_with_chain;
  135. }
  136. offset = sizeof(uint8_t);
  137. ret = iob_trycopyin(iob, (FAR const uint8_t *)&inaddr,
  138. sizeof(struct sockaddr_in6), offset, true,
  139. IOBUSER_NET_SOCK_ICMPv6);
  140. if (ret < 0)
  141. {
  142. /* On a failure, iob_trycopyin return a negated error value but does
  143. * not free any I/O buffers.
  144. */
  145. nerr("ERROR: Failed to source address to the I/O buffer chain: %d\n",
  146. ret);
  147. goto drop_with_chain;
  148. }
  149. offset += sizeof(struct sockaddr_in6);
  150. /* Copy the new ICMPv6 reply into the I/O buffer chain (without waiting) */
  151. buflen = ICMPv6SIZE;
  152. icmpv6 = ICMPv6BUF;
  153. ret = iob_trycopyin(iob, (FAR uint8_t *)ICMPv6REPLY, buflen, offset, true,
  154. IOBUSER_NET_SOCK_ICMPv6);
  155. if (ret < 0)
  156. {
  157. /* On a failure, iob_copyin return a negated error value but does
  158. * not free any I/O buffers.
  159. */
  160. nerr("ERROR: Failed to add data to the I/O buffer chain: %d\n", ret);
  161. goto drop_with_chain;
  162. }
  163. /* Add the new I/O buffer chain to the tail of the read-ahead queue (again
  164. * without waiting).
  165. */
  166. ret = iob_tryadd_queue(iob, &conn->readahead);
  167. if (ret < 0)
  168. {
  169. nerr("ERROR: Failed to queue the I/O buffer chain: %d\n", ret);
  170. goto drop_with_chain;
  171. }
  172. ninfo("Buffered %d bytes\n", buflen + addrsize + 1);
  173. dev->d_len = 0;
  174. return buflen;
  175. drop_with_chain:
  176. iob_free_chain(iob, IOBUSER_NET_SOCK_ICMPv6);
  177. drop:
  178. dev->d_len = 0;
  179. return 0;
  180. }
  181. #endif
  182. /****************************************************************************
  183. * Public Functions
  184. ****************************************************************************/
  185. /****************************************************************************
  186. * Name: icmpv6_input
  187. *
  188. * Description:
  189. * Handle incoming ICMPv6 input
  190. *
  191. * Input Parameters:
  192. * dev - The device driver structure containing the received ICMPv6
  193. * packet
  194. * iplen - The size of the IPv6 header. This may be larger than
  195. * IPv6_HDRLEN the IPv6 header if IPv6 extension headers are
  196. * present.
  197. *
  198. * Returned Value:
  199. * None
  200. *
  201. * Assumptions:
  202. * The network is locked.
  203. *
  204. ****************************************************************************/
  205. void icmpv6_input(FAR struct net_driver_s *dev, unsigned int iplen)
  206. {
  207. FAR struct ipv6_hdr_s *ipv6 = IPv6BUF;
  208. FAR struct icmpv6_hdr_s *icmpv6 = ICMPv6BUF;
  209. #ifdef CONFIG_NET_STATISTICS
  210. g_netstats.icmpv6.recv++;
  211. #endif
  212. /* REVISIT:
  213. * - Verify that the message length is valid.
  214. * - Verify the ICMPv6 checksum
  215. */
  216. /* Handle the ICMPv6 message by its type */
  217. switch (icmpv6->type)
  218. {
  219. /* If we get a neighbor solicitation for our address we should send
  220. * a neighbor advertisement message back.
  221. */
  222. case ICMPv6_NEIGHBOR_SOLICIT:
  223. {
  224. FAR struct icmpv6_neighbor_solicit_s *sol;
  225. /* Check if we are the target of the solicitation */
  226. sol = ICMPv6SOLICIT;
  227. if (net_ipv6addr_cmp(sol->tgtaddr, dev->d_ipv6addr))
  228. {
  229. if (sol->opttype == ICMPv6_OPT_SRCLLADDR)
  230. {
  231. /* Save the sender's address mapping in our Neighbor Table. */
  232. neighbor_add(dev, ipv6->srcipaddr, sol->srclladdr);
  233. }
  234. /* Yes.. Send a neighbor advertisement back to where the neighbor
  235. * solicitation came from.
  236. */
  237. icmpv6_advertise(dev, ipv6->srcipaddr);
  238. /* All statistics have been updated. Nothing to do but exit. */
  239. return;
  240. }
  241. else
  242. {
  243. goto icmpv6_drop_packet;
  244. }
  245. }
  246. break;
  247. /* Check if we received a Neighbor Advertisement */
  248. case ICMPv6_NEIGHBOR_ADVERTISE:
  249. {
  250. FAR struct icmpv6_neighbor_advertise_s *adv;
  251. /* If the IPv6 destination address matches our address, and if so,
  252. * add the neighbor address mapping to the list of neighbors.
  253. *
  254. * Missing checks:
  255. * optlen = 1 (8 octets)
  256. * Should only update Neighbor Table if
  257. * [O]verride bit is set in flags
  258. */
  259. adv = ICMPv6ADVERTISE;
  260. if (net_ipv6addr_cmp(ipv6->destipaddr, dev->d_ipv6addr))
  261. {
  262. /* This message is required to support the Target link-layer
  263. * address option.
  264. */
  265. if (adv->opttype == ICMPv6_OPT_TGTLLADDR)
  266. {
  267. /* Save the sender's address mapping in our Neighbor Table. */
  268. neighbor_add(dev, ipv6->srcipaddr, adv->tgtlladdr);
  269. }
  270. #ifdef CONFIG_NET_ICMPv6_NEIGHBOR
  271. /* Then notify any logic waiting for the Neighbor Advertisement */
  272. icmpv6_notify(ipv6->srcipaddr);
  273. #endif
  274. /* We consumed the packet but we don't send anything in
  275. * response.
  276. */
  277. goto icmpv6_send_nothing;
  278. }
  279. goto icmpv6_drop_packet;
  280. }
  281. break;
  282. #ifdef CONFIG_NET_ICMPv6_ROUTER
  283. /* Check if we received a Router Solicitation */
  284. case ICMPV6_ROUTER_SOLICIT:
  285. {
  286. /* Just give a knee-jerk Router Advertisement in respond with no
  287. * further examination of the Router Solicitation.
  288. */
  289. icmpv6_radvertise(dev);
  290. /* All statistics have been updated. Nothing to do but exit. */
  291. return;
  292. }
  293. #endif
  294. #ifdef CONFIG_NET_ICMPv6_AUTOCONF
  295. /* Check if we received a Router Advertisement */
  296. case ICMPV6_ROUTER_ADVERTISE:
  297. {
  298. FAR struct icmpv6_router_advertise_s *adv;
  299. FAR uint8_t *options;
  300. bool prefix = false;
  301. uint16_t pktlen;
  302. uint16_t optlen;
  303. int ndx;
  304. /* Get the length of the option data */
  305. pktlen = (uint16_t)ipv6->len[0] << 8 | ipv6->len[1];
  306. if (pktlen <= ICMPv6_RADV_MINLEN)
  307. {
  308. /* Too small to contain any options */
  309. goto icmpv6_drop_packet;
  310. }
  311. optlen = ICMPv6_RADV_OPTLEN(pktlen);
  312. /* We need to have a valid router advertisement with a Prefix and
  313. * with the "A" bit set in the flags. Options immediately follow
  314. * the ICMPv6 router advertisement.
  315. */
  316. adv = ICMPv6RADVERTISE;
  317. options = (FAR uint8_t *)adv +
  318. sizeof(struct icmpv6_router_advertise_s);
  319. for (ndx = 0; ndx + sizeof(struct icmpv6_prefixinfo_s) <= optlen; )
  320. {
  321. FAR struct icmpv6_srclladdr_s *sllopt =
  322. (FAR struct icmpv6_srclladdr_s *)&options[ndx];
  323. if (sllopt->opttype == ICMPv6_OPT_SRCLLADDR)
  324. {
  325. neighbor_add(dev, ipv6->srcipaddr, sllopt->srclladdr);
  326. }
  327. FAR struct icmpv6_prefixinfo_s *opt =
  328. (FAR struct icmpv6_prefixinfo_s *)&options[ndx];
  329. /* Is this the sought for prefix? Is it the correct size? Is
  330. * the "A" flag set?
  331. */
  332. if (opt->opttype == ICMPv6_OPT_PREFIX &&
  333. (opt->flags & ICMPv6_PRFX_FLAG_A) != 0)
  334. {
  335. /* Yes.. Notify any waiting threads */
  336. icmpv6_rnotify(dev, ipv6->srcipaddr,
  337. opt->prefix, opt->preflen);
  338. prefix = true;
  339. }
  340. /* Skip to the next option (units of octets) */
  341. ndx += (opt->optlen << 3);
  342. }
  343. if (prefix)
  344. {
  345. goto icmpv6_send_nothing;
  346. }
  347. goto icmpv6_drop_packet;
  348. }
  349. break;
  350. #endif
  351. /* Handle the ICMPv6 Echo Request */
  352. case ICMPv6_ECHO_REQUEST:
  353. {
  354. /* ICMPv6 echo (i.e., ping) processing. This is simple, we only
  355. * change the ICMPv6 type from ECHO to ECHO_REPLY and update the
  356. * ICMPv6 checksum before we return the packet.
  357. */
  358. icmpv6->type = ICMPv6_ECHO_REPLY;
  359. net_ipv6addr_copy(ipv6->destipaddr, ipv6->srcipaddr);
  360. net_ipv6addr_copy(ipv6->srcipaddr, dev->d_ipv6addr);
  361. icmpv6->chksum = 0;
  362. icmpv6->chksum = ~icmpv6_chksum(dev, iplen);
  363. }
  364. break;
  365. #ifdef CONFIG_NET_ICMPv6_SOCKET
  366. /* If an ICMPv6 echo reply is received then there should also be
  367. * a thread waiting to received the echo response.
  368. */
  369. case ICMPv6_ECHO_REPLY:
  370. {
  371. FAR struct icmpv6_echo_reply_s *reply;
  372. FAR struct icmpv6_conn_s *conn;
  373. uint16_t flags = ICMPv6_NEWDATA;
  374. /* Nothing consumed the ICMP reply. That might be because this is
  375. * an old, invalid reply or simply because the ping application
  376. * has not yet put its poll or recv in place.
  377. */
  378. /* Is there any connection that might expect this reply? */
  379. reply = ICMPv6REPLY;
  380. conn = icmpv6_findconn(dev, reply->id);
  381. if (conn == NULL)
  382. {
  383. /* No.. drop the packet */
  384. goto icmpv6_drop_packet;
  385. }
  386. /* Dispatch the ECHO reply to the waiting thread */
  387. flags = devif_conn_event(dev, conn, flags, conn->list);
  388. /* Was the ECHO reply consumed by any waiting thread? */
  389. if ((flags & ICMPv6_NEWDATA) != 0)
  390. {
  391. uint16_t nbuffered;
  392. /* Yes.. Add the ICMP echo reply to the IPPROTO_ICMP socket read
  393. * ahead buffer.
  394. */
  395. nbuffered = icmpv6_datahandler(dev, conn, iplen);
  396. if (nbuffered == 0)
  397. {
  398. /* Could not buffer the data.. drop the packet */
  399. goto icmpv6_drop_packet;
  400. }
  401. }
  402. goto icmpv6_send_nothing;
  403. }
  404. break;
  405. #endif
  406. #ifdef CONFIG_NET_MLD
  407. /* Dispatch received Multicast Listener Discovery (MLD) packets. */
  408. case ICMPV6_MCAST_LISTEN_QUERY: /* Multicast Listener Query, RFC 2710 and RFC 3810 */
  409. {
  410. FAR struct mld_mcast_listen_query_s *query = MLDQUERY;
  411. int ret;
  412. ret = mld_query(dev, query);
  413. if (ret < 0)
  414. {
  415. goto icmpv6_drop_packet;
  416. }
  417. }
  418. break;
  419. case ICMPV6_MCAST_LISTEN_REPORT_V1: /* Version 1 Multicast Listener Report, RFC 2710 */
  420. {
  421. FAR struct mld_mcast_listen_report_v1_s *report = MLDREPORT_V1;
  422. int ret;
  423. ret = mld_report_v1(dev, report);
  424. if (ret < 0)
  425. {
  426. goto icmpv6_drop_packet;
  427. }
  428. }
  429. break;
  430. case ICMPV6_MCAST_LISTEN_REPORT_V2: /* Version 2 Multicast Listener Report, RFC 3810 */
  431. {
  432. FAR struct mld_mcast_listen_report_v2_s *report = MLDREPORT_V2;
  433. int ret;
  434. ret = mld_report_v2(dev, report);
  435. if (ret < 0)
  436. {
  437. goto icmpv6_drop_packet;
  438. }
  439. }
  440. break;
  441. case ICMPV6_MCAST_LISTEN_DONE: /* Multicast Listener Done, RFC 2710 */
  442. {
  443. FAR struct mld_mcast_listen_done_s *done = MLDDONE;
  444. int ret;
  445. ret = mld_done(dev, done);
  446. if (ret < 0)
  447. {
  448. goto icmpv6_drop_packet;
  449. }
  450. }
  451. break;
  452. #endif
  453. default:
  454. {
  455. nwarn("WARNING: Unknown ICMPv6 type: %d\n", icmpv6->type);
  456. goto icmpv6_type_error;
  457. }
  458. }
  459. #ifdef CONFIG_NET_STATISTICS
  460. if (dev->d_len > 0)
  461. {
  462. ninfo("Outgoing ICMPv6 packet length: %d (%d)\n",
  463. dev->d_len, (ipv6->len[0] << 8) | ipv6->len[1]);
  464. g_netstats.icmpv6.sent++;
  465. g_netstats.ipv6.sent++;
  466. }
  467. #endif
  468. return;
  469. icmpv6_type_error:
  470. #ifdef CONFIG_NET_STATISTICS
  471. g_netstats.icmpv6.typeerr++;
  472. #endif
  473. icmpv6_drop_packet:
  474. #ifdef CONFIG_NET_STATISTICS
  475. g_netstats.icmpv6.drop++;
  476. #endif
  477. icmpv6_send_nothing:
  478. dev->d_len = 0;
  479. }
  480. #endif /* CONFIG_NET_ICMPv6 */