icmp6.c 55 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355
  1. /**
  2. * Copyright (c) 2013 - 2019, Nordic Semiconductor ASA
  3. *
  4. * All rights reserved.
  5. *
  6. * Redistribution and use in source and binary forms, with or without modification,
  7. * are permitted provided that the following conditions are met:
  8. *
  9. * 1. Redistributions of source code must retain the above copyright notice, this
  10. * list of conditions and the following disclaimer.
  11. *
  12. * 2. Redistributions in binary form, except as embedded into a Nordic
  13. * Semiconductor ASA integrated circuit in a product or a software update for
  14. * such product, must reproduce the above copyright notice, this list of
  15. * conditions and the following disclaimer in the documentation and/or other
  16. * materials provided with the distribution.
  17. *
  18. * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
  19. * contributors may be used to endorse or promote products derived from this
  20. * software without specific prior written permission.
  21. *
  22. * 4. This software, with or without modification, must only be used with a
  23. * Nordic Semiconductor ASA integrated circuit.
  24. *
  25. * 5. Any software provided in binary form under this license must not be reverse
  26. * engineered, decompiled, modified and/or disassembled.
  27. *
  28. * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
  29. * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  30. * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
  31. * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
  32. * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  33. * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
  34. * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  35. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  36. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
  37. * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  38. *
  39. */
  40. #include <stdio.h>
  41. #include <stdint.h>
  42. #include <stdbool.h>
  43. #include <string.h>
  44. #include "icmp6_api.h"
  45. #include "ipv6_api.h"
  46. #include "icmp6.h"
  47. #include "iot_context_manager.h"
  48. #include "ipv6_utils.h"
  49. #include "iot_common.h"
  50. #if ICMP6_CONFIG_LOG_ENABLED
  51. #define NRF_LOG_MODULE_NAME icmp6
  52. #define NRF_LOG_LEVEL ICMP6_CONFIG_LOG_LEVEL
  53. #define NRF_LOG_INFO_COLOR ICMP6_CONFIG_INFO_COLOR
  54. #define NRF_LOG_DEBUG_COLOR ICMP6_CONFIG_DEBUG_COLOR
  55. #include "nrf_log.h"
  56. NRF_LOG_MODULE_REGISTER();
  57. #define ICMP6_TRC NRF_LOG_DEBUG /**< Used for getting trace of execution in the module. */
  58. #define ICMP6_ERR NRF_LOG_ERROR /**< Used for logging errors in the module. */
  59. #define ICMP6_DUMP NRF_LOG_HEXDUMP_DEBUG /**< Used for dumping octet information to get details of bond information etc. */
  60. #define ICMP6_ENTRY() ICMP6_TRC(">> %s", __func__)
  61. #define ICMP6_EXIT() ICMP6_TRC("<< %s", __func__)
  62. #else // ICMP6_CONFIG_LOG_ENABLED
  63. #define ICMP6_TRC(...) /**< Disables traces. */
  64. #define ICMP6_DUMP(...) /**< Disables dumping of octet streams. */
  65. #define ICMP6_ERR(...) /**< Disables error logs. */
  66. #define ICMP6_ENTRY(...)
  67. #define ICMP6_EXIT(...)
  68. #endif // ICMP6_CONFIG_LOG_ENABLED
  69. /**
  70. * @defgroup api_param_check API Parameters check macros.
  71. *
  72. * @details Macros that verify parameters passed to the module in the APIs. These macros
  73. * could be mapped to nothing in final versions of code to save execution and size.
  74. * ICMP6_DISABLE_API_PARAM_CHECK should be set to 1 to disable these checks.
  75. *
  76. * @{
  77. */
  78. #if (ICMP6_DISABLE_API_PARAM_CHECK == 0)
  79. /**@brief Macro to check is module is initialized before requesting one of the module procedures. */
  80. #define VERIFY_MODULE_IS_INITIALIZED() \
  81. if (m_initialization_state == false) \
  82. { \
  83. return (SDK_ERR_MODULE_NOT_INITIALIZED | IOT_ICMP6_ERR_BASE); \
  84. }
  85. /**@brief Macro to check is module is initialized before requesting one of the module
  86. procedures but does not use any return code. */
  87. #define VERIFY_MODULE_IS_INITIALIZED_VOID() \
  88. if (m_initialization_state == false) \
  89. { \
  90. return; \
  91. }
  92. /**
  93. * @brief Verify NULL parameters are not passed to API by application.
  94. */
  95. #define NULL_PARAM_CHECK(PARAM) \
  96. if ((PARAM) == NULL) \
  97. { \
  98. return (NRF_ERROR_NULL | IOT_ICMP6_ERR_BASE); \
  99. }
  100. /**
  101. * @brief Verify packet buffer is of ICMP6 Type.
  102. */
  103. #define PACKET_TYPE_CHECK(PACKET) \
  104. if ((PACKET)->type != ICMP6_PACKET_TYPE) \
  105. { \
  106. return (NRF_ERROR_INVALID_PARAM | IOT_ICMP6_ERR_BASE); \
  107. }
  108. #else // ICMP6_DISABLE_API_PARAM_CHECK
  109. #define VERIFY_MODULE_IS_INITIALIZED()
  110. #define VERIFY_MODULE_IS_INITIALIZED_VOID()
  111. #define NULL_PARAM_CHECK(PARAM)
  112. #define PACKET_TYPE_CHECK(PACKET)
  113. #endif // ICMP6_DISABLE_API_PARAM_CHECK
  114. /** @} */
  115. /**
  116. * @defgroup icmp6_mutex_lock_unlock Module's Mutex Lock/Unlock Macros.
  117. *
  118. * @details Macros used to lock and unlock modules. Currently, SDK does not use mutexes but
  119. * framework is provided in case need arises to use an alternative architecture.
  120. * @{
  121. */
  122. #define ICMP6_MUTEX_LOCK() SDK_MUTEX_LOCK(m_icmp6_mutex) /**< Lock module using mutex */
  123. #define ICMP6_MUTEX_UNLOCK() SDK_MUTEX_UNLOCK(m_icmp6_mutex) /**< Unlock module using mutex */
  124. /** @} */
  125. #define ND_NS_HEADER_SIZE 20 /**< Size of Neighbour Solicitation message. */
  126. #define ND_NA_HEADER_SIZE 20 /**< Size of Neighbour Advertisement message. */
  127. #define ND_RS_HEADER_SIZE 4 /**< Size of Router Solicitation message. */
  128. #define ND_RA_HEADER_SIZE 12 /**< Size of Router Advertisement message. */
  129. #define ND_PAYLOAD_ADJUST_OFFSET 4 /**< Adjusting ND related payload offset as the general ICMP structure is not upheld. */
  130. #define ND_NA_R_FLAG 0x80 /**< Router flag. When set, the R-bit indicates that the sender is a router. */
  131. #define ND_NA_S_FLAG 0x40 /**< Solicited flag. When set, the S-bit indicates that the advertisement was sent in response
  132. to a Neighbor Solicitation .*/
  133. #define ND_NA_O_FLAG 0x20 /**< Override flag. When set, the O-bit indicates that the advertisement should override
  134. an existing cache entry and update the cached link-layer address .*/
  135. #define ND_OPT_TYPE_SLLAO 1 /**< Source Link Layer Address Option. */
  136. #define ND_OPT_TYPE_TLLAO 2 /**< Target Link Layer Address Option. */
  137. #define ND_OPT_TYPE_PIO 3 /**< Prefix Information Option. */
  138. #define ND_OPT_TYPE_RHO 4 /**< Redirected Header Option. */
  139. #define ND_OPT_TYPE_MTU 5 /**< Maximum Transmit Unit Option. */
  140. #define ND_OPT_TYPE_ARO 33 /**< Address Registration Option. */
  141. #define ND_OPT_TYPE_6CO 34 /**< 6LoWPAN Context Option. */
  142. #define ND_OPT_TYPE_6ABRO 35 /**< Authoritative Border Router Option. */
  143. #define ND_OPT_SLLAO_SIZE (8 * (((IPV6_LL_ADDR_SIZE) / 8) + 1)) /**< Size of SLLAO option. */
  144. #define ND_OPT_TLLAO_SIZE (8 * (((IPV6_LL_ADDR_SIZE) / 8) + 1)) /**< Size of TLLAO option. */
  145. #define ND_OPT_PIO_SIZE 32 /**< Size of PIO option. */
  146. #define ND_OPT_MTU_SIZE 8 /**< Size of MTU option. */
  147. #define ND_OPT_ARO_SIZE 16 /**< Size of ARO option. */
  148. #define ND_OPT_6CO_SIZE 24 /**< Size of 6CO option. */
  149. #define ND_OPT_6ABRO_SIZE 24 /**< Size of 6ABRO option. */
  150. #define ND_OPT_SLLAO_LENGTH ((ND_OPT_SLLAO_SIZE) / 8) /**< Value of length field in SLLAO option. */
  151. #define ND_OPT_TLLAO_LENGTH ((ND_OPT_TLLAO_SIZE) / 8) /**< Value of length field in SLLAO option. */
  152. #define ND_OPT_ARO_LENGTH 2 /**< Value of length field in ARO option. */
  153. #define ND_OPT_6CO_CID_MASK 0x0F
  154. #define ND_OPT_6CO_CID_POS 0
  155. #define ND_OPT_6CO_C_MASK 0x10
  156. #define ND_OPT_6CO_C_POS 4
  157. #define ND_OPT_PIO_L_MASK 0x80
  158. #define ND_OPT_PIO_L_POS 7
  159. #define ND_OPT_PIO_A_MASK 0x40
  160. #define ND_OPT_PIO_A_POS 6
  161. #define ND_HOP_LIMIT 255 /**< Value of Hop Limit used in Neighbour Discovery procedure. */
  162. #define ICMP6_OFFSET IPV6_IP_HEADER_SIZE + ICMP6_HEADER_SIZE /**< Offset of ICMPv6 packet type. */
  163. #define ERROR_ADDITIONAL_HEADER_SIZE 4 /**< Additional 4 bytes of information every ICMP error message contains. */
  164. #define ERROR_MESSAGE_HEADER_SIZE (ICMP6_HEADER_SIZE + ERROR_ADDITIONAL_HEADER_SIZE) /**< Error message header size including type, code, checksum and 32-bit parameter. */
  165. #define ICMP6_ERROR_OFFSET IPV6_IP_HEADER_SIZE + ERROR_MESSAGE_HEADER_SIZE /**< Offset for ICMPv6 error message. */
  166. /**@brief Neighbor Solicitation header. */
  167. typedef struct
  168. {
  169. uint32_t reserved; /**< Reserved field. */
  170. ipv6_addr_t target_addr; /**< Target Address field. */
  171. } icmp6_ns_header_t;
  172. /**@brief Neighbor Advertisement header. */
  173. typedef struct
  174. {
  175. uint8_t flags; /**< Flags (R,S and O). */
  176. uint8_t reserved; /**< Reserved field. */
  177. ipv6_addr_t target_addr; /**< Target Address field. */
  178. } icmp6_na_header_t;
  179. /**@brief Router Solicitation message's header. */
  180. typedef struct
  181. {
  182. uint32_t reserved; /**< Reserved field. */
  183. } icmp6_rs_header_t;
  184. /**@brief Option header of ICMPv6 packet. */
  185. typedef struct
  186. {
  187. uint8_t type; /**< Option type. */
  188. uint8_t length; /**< Length, in unit of 8 octets. */
  189. } nd_option_t;
  190. /**@brief Source Link Layer Address Option header format. */
  191. typedef struct
  192. {
  193. uint8_t type; /**< Option type. */
  194. uint8_t length; /**< Length, units of 8 octets. */
  195. eui64_t addr; /**< Link-layer address. */
  196. uint8_t padding[6]; /**< Padding. */
  197. } nd_option_sllao_t;
  198. /**@brief Target Link Layer Address Option header format. */
  199. typedef struct
  200. {
  201. uint8_t type; /**< Option type. */
  202. uint8_t length; /**< Length, units of 8 octets. */
  203. eui64_t addr; /**< Link-layer address. */
  204. uint8_t padding[6]; /**< Padding. */
  205. } nd_option_tllao_t;
  206. /**@brief Prefix Information Option header format. */
  207. typedef struct
  208. {
  209. uint8_t type; /**< Option type. */
  210. uint8_t length; /**< Length, units of 8 octets. */
  211. uint8_t prefix_length; /**< Prefix length. */
  212. uint8_t flags; /**< Flags (L/A) and reserved. */
  213. uint32_t valid_lifetime; /**< Valid Lifetime. */
  214. uint32_t preferred_lifetime; /**< Preferred Lifetime. */
  215. uint32_t reserved; /**< Reserved field. */
  216. ipv6_addr_t prefix; /**< Prefix address. */
  217. } nd_option_pio_t;
  218. /**@brief Address Registration Option header format. */
  219. typedef struct
  220. {
  221. uint8_t type; /**< Option type. */
  222. uint8_t length; /**< Length, units of 8 octets. */
  223. uint8_t status; /**< Status of ARO. */
  224. uint8_t reserved; /**< Reserved1, split to avoid alignment. */
  225. uint16_t reserved2; /**< Reserved2, split to avoid alignment. */
  226. uint16_t registration_lifetime; /**< Registration Lifetime. */
  227. eui64_t eui64; /**< EUI-64 source address. */
  228. } nd_option_aro_t;
  229. /**@brief 6LoWPAN Context Option header format. */
  230. typedef struct
  231. {
  232. uint8_t type; /**< Option type. */
  233. uint8_t length; /**< Length, units of 8 octets. */
  234. uint8_t context_length; /**< Context Length. */
  235. uint8_t CID_C; /**< 4-bit Context and 1-bit context compression flag. */
  236. uint16_t reserved; /**< Reserved. */
  237. uint16_t valid_lifetime; /**< Valid Lifetime. */
  238. ipv6_addr_t context; /**< Context IPv6 Prefix. */
  239. } nd_option_6co_t;
  240. static bool m_initialization_state = false; /**< Variable to maintain module initialization state. */
  241. static uint16_t m_sequence_number = 0; /**< Sequence number from ICMPv6 packet. */
  242. static icmp6_receive_callback_t m_event_handler = NULL; /**< Application event handler. */
  243. SDK_MUTEX_DEFINE(m_icmp6_mutex) /**< Mutex variable. Currently unused, this declaration does not occupy any space in RAM. */
  244. /**@brief Function for initializing default values of IP Header for ICMP.
  245. *
  246. * @param[in] p_ip_header Pointer to IPv6 header.
  247. * @param[in] hoplimit Hop Limit in IPv6 header.
  248. *
  249. * @return None.
  250. */
  251. static __INLINE void icmp_ip_header(ipv6_header_t * p_ip_header, uint8_t hoplimit)
  252. {
  253. ipv6_header_init(p_ip_header);
  254. p_ip_header->next_header = IPV6_NEXT_HEADER_ICMP6;
  255. p_ip_header->hoplimit = hoplimit;
  256. }
  257. /**@brief Function for adding SLLAO option to the packet.
  258. *
  259. * @param[in] p_interface Pointer to IoT interface.
  260. * @param[in] p_data Pointer to the memory where SLLAO option should be added.
  261. *
  262. * @return None.
  263. */
  264. static __INLINE void add_sllao_opt(const iot_interface_t * p_interface, nd_option_sllao_t * p_sllao)
  265. {
  266. p_sllao->type = ND_OPT_TYPE_SLLAO;
  267. p_sllao->length = ND_OPT_SLLAO_LENGTH;
  268. #if (IPV6_LL_ADDR_SIZE == 6)
  269. memcpy(p_sllao->addr.identifier, p_interface->local_addr.identifier, 3);
  270. memcpy(p_sllao->addr.identifier + 3, p_interface->local_addr.identifier + 5, 3);
  271. #else
  272. // Copy EUI-64 and add padding.
  273. memcpy(p_sllao->addr.identifier, p_interface->local_addr.identifier, IPV6_LL_ADDR_SIZE);
  274. memset(p_sllao->padding, 0, 6);
  275. #endif
  276. }
  277. /**@brief Function for adding TLLAO option to the packet.
  278. *
  279. * @param[in] p_interface Pointer to IoT interface.
  280. * @param[in] p_data Pointer to the memory where TLLAO option should be added.
  281. *
  282. * @return None.
  283. */
  284. static __INLINE void add_tllao_opt(const iot_interface_t * p_interface, nd_option_tllao_t * p_tllao)
  285. {
  286. p_tllao->type = ND_OPT_TYPE_TLLAO;
  287. p_tllao->length = ND_OPT_TLLAO_LENGTH;
  288. #if (IPV6_LL_ADDR_SIZE == 6)
  289. memcpy(p_tllao->addr.identifier, p_interface->local_addr.identifier, 3);
  290. memcpy(p_tllao->addr.identifier + 3, p_interface->local_addr.identifier + 5, 3);
  291. #else
  292. // Copy EUI-64 and add padding.
  293. memcpy(p_tllao->addr.identifier, p_interface->local_addr.identifier, IPV6_LL_ADDR_SIZE);
  294. memset(p_tllao->padding, 0, 6);
  295. #endif
  296. }
  297. /**@brief Function for adding ARO option to packet.
  298. *
  299. * @param[in] p_interface Pointer to IoT interface.
  300. * @param[in] p_data Pointer to the memory where ARO option should be added.
  301. * @param[in] aro_lifetime Lifetime of registration.
  302. *
  303. * @return None.
  304. */
  305. static __INLINE void add_aro_opt(const iot_interface_t * p_interface,
  306. nd_option_aro_t * p_aro,
  307. uint16_t aro_lifetime)
  308. {
  309. p_aro->type = ND_OPT_TYPE_ARO;
  310. p_aro->length = ND_OPT_ARO_LENGTH;
  311. p_aro->status = 0x00;
  312. p_aro->reserved = 0x00;
  313. p_aro->reserved2 = 0x00;
  314. p_aro->registration_lifetime = HTONS(aro_lifetime);
  315. // Copy EUI-64 and add padding.
  316. memcpy(p_aro->eui64.identifier, p_interface->local_addr.identifier, EUI_64_ADDR_SIZE);
  317. }
  318. #if (ICMP6_ENABLE_ND6_MESSAGES_TO_APPLICATION == 1 || ICMP6_ENABLE_ALL_MESSAGES_TO_APPLICATION == 1)
  319. /**@brief Function for notifying application of the ICMPv6 received packet.
  320. *
  321. * @param[in] p_interface Pointer to external interface from which packet come.
  322. * @param[in] p_pbuffer Pointer to packet buffer of ICMP6_PACKET_TYPE.
  323. * @param[in] process_result Result of internal processing packet.
  324. *
  325. * @return NRF_SUCCESS after successful processing, error otherwise.
  326. */
  327. static uint32_t app_notify_icmp_data(iot_interface_t * p_interface,
  328. iot_pbuffer_t * p_pbuffer,
  329. uint32_t process_result)
  330. {
  331. uint32_t err_code = NRF_SUCCESS;
  332. if (m_event_handler != NULL)
  333. {
  334. ipv6_header_t * p_ip_header = (ipv6_header_t *)
  335. (p_pbuffer->p_payload - ICMP6_HEADER_SIZE - IPV6_IP_HEADER_SIZE);
  336. icmp6_header_t * p_icmp_header = (icmp6_header_t *)
  337. (p_pbuffer->p_payload - ICMP6_HEADER_SIZE);
  338. ICMP6_MUTEX_UNLOCK();
  339. // Change byte order of ICMP header given to application.
  340. p_icmp_header->checksum = NTOHS(p_icmp_header->checksum);
  341. err_code = m_event_handler(p_interface,
  342. p_ip_header,
  343. p_icmp_header,
  344. process_result,
  345. p_pbuffer);
  346. ICMP6_MUTEX_LOCK();
  347. }
  348. return err_code;
  349. }
  350. #endif
  351. #if (ICMP6_ENABLE_HANDLE_ECHO_REQUEST_TO_APPLICATION == 0)
  352. /**@brief Function for responding on ECHO REQUEST message.
  353. *
  354. * @param[in] p_interface Pointer to external interface from which packet come.
  355. * @param[in] p_ip_header Pointer to IPv6 Header.
  356. * @param[in] p_icmp_header Pointer to ICMPv6 header.
  357. * @param[in] p_packet Pointer to packet buffer.
  358. *
  359. * @return NRF_SUCCESS after successful processing, error otherwise.
  360. */
  361. static void echo_reply_send(iot_interface_t * p_interface,
  362. ipv6_header_t * p_ip_header,
  363. icmp6_header_t * p_icmp_header,
  364. iot_pbuffer_t * p_packet)
  365. {
  366. uint32_t err_code;
  367. uint16_t checksum;
  368. iot_pbuffer_t * p_pbuffer;
  369. iot_pbuffer_alloc_param_t pbuff_param;
  370. // Headers of new packet.
  371. ipv6_header_t * p_reply_ip_header;
  372. icmp6_header_t * p_reply_icmp_header;
  373. ICMP6_TRC("Sending reply on Echo Request.");
  374. // Requesting buffer for reply
  375. pbuff_param.flags = PBUFFER_FLAG_DEFAULT;
  376. pbuff_param.type = ICMP6_PACKET_TYPE;
  377. pbuff_param.length = p_packet->length;
  378. err_code = iot_pbuffer_allocate(&pbuff_param, &p_pbuffer);
  379. if (err_code == NRF_SUCCESS)
  380. {
  381. p_reply_ip_header = (ipv6_header_t *)(p_pbuffer->p_payload - ICMP6_HEADER_SIZE -
  382. IPV6_IP_HEADER_SIZE);
  383. p_reply_icmp_header = (icmp6_header_t *)(p_pbuffer->p_payload - ICMP6_HEADER_SIZE);
  384. // Change ICMP header.
  385. p_reply_icmp_header->type = ICMP6_TYPE_ECHO_REPLY;
  386. p_reply_icmp_header->code = 0;
  387. p_reply_icmp_header->checksum = 0;
  388. // IPv6 Header initialization.
  389. icmp_ip_header(p_reply_ip_header, IPV6_DEFAULT_HOP_LIMIT);
  390. p_reply_ip_header->destaddr = p_ip_header->srcaddr;
  391. p_reply_ip_header->length = HTONS(p_pbuffer->length + ICMP6_HEADER_SIZE);
  392. if (IPV6_ADDRESS_IS_MULTICAST(&p_ip_header->destaddr))
  393. {
  394. IPV6_CREATE_LINK_LOCAL_FROM_EUI64(&p_reply_ip_header->srcaddr,
  395. p_interface->local_addr.identifier);
  396. }
  397. else
  398. {
  399. p_reply_ip_header->srcaddr = p_ip_header->destaddr;
  400. }
  401. // Set echo reply parameters.
  402. p_reply_icmp_header->sp.echo.id = p_icmp_header->sp.echo.id;
  403. p_reply_icmp_header->sp.echo.sequence = p_icmp_header->sp.echo.sequence;
  404. // Copy user data.
  405. memcpy(p_pbuffer->p_payload,
  406. p_packet->p_payload,
  407. p_packet->length);
  408. // Calculate checksum.
  409. checksum = p_pbuffer->length + ICMP6_HEADER_SIZE + IPV6_NEXT_HEADER_ICMP6;
  410. ipv6_checksum_calculate(p_reply_ip_header->srcaddr.u8, IPV6_ADDR_SIZE, &checksum, false);
  411. ipv6_checksum_calculate(p_reply_ip_header->destaddr.u8, IPV6_ADDR_SIZE, &checksum, false);
  412. ipv6_checksum_calculate(p_pbuffer->p_payload - ICMP6_HEADER_SIZE,
  413. p_pbuffer->length + ICMP6_HEADER_SIZE,
  414. &checksum,
  415. false);
  416. p_reply_icmp_header->checksum = HTONS((~checksum));
  417. p_pbuffer->p_payload -= ICMP6_OFFSET;
  418. p_pbuffer->length += ICMP6_OFFSET;
  419. // Send IPv6 packet.
  420. err_code = ipv6_send(p_interface, p_pbuffer);
  421. if (err_code != NRF_SUCCESS)
  422. {
  423. ICMP6_ERR("Cannot send packet buffer!");
  424. }
  425. }
  426. else
  427. {
  428. ICMP6_ERR("Failed to allocate packet buffer!");
  429. }
  430. }
  431. #endif
  432. /**@brief Function for responding on Neighbor Advertisement message.
  433. *
  434. * @param[in] p_interface Pointer to external interface from which packet come.
  435. * @param[in] p_ip_header Pointer to IPv6 Header.
  436. * @param[in] p_icmp_header Pointer to ICMPv6 header.
  437. * @param[in] p_target_addr Pointer to the IPv6 address.
  438. *
  439. * @return NRF_SUCCESS after successful processing, error otherwise.
  440. */
  441. static uint32_t na_send(iot_interface_t * p_interface,
  442. ipv6_header_t * p_ip_header,
  443. icmp6_header_t * p_icmp_header,
  444. ipv6_addr_t * p_target_addr)
  445. {
  446. uint32_t err_code;
  447. uint16_t checksum;
  448. iot_pbuffer_t * p_pbuffer;
  449. iot_pbuffer_alloc_param_t pbuff_param;
  450. // Headers of new packet.
  451. ipv6_header_t * p_reply_ip_header;
  452. icmp6_header_t * p_reply_icmp_header;
  453. icmp6_na_header_t * p_reply_na_header;
  454. nd_option_tllao_t * p_reply_opt_tllao_header;
  455. ICMP6_TRC("Sending reply on Neighbor Solocitation.");
  456. // Requesting buffer for reply
  457. pbuff_param.flags = PBUFFER_FLAG_DEFAULT;
  458. pbuff_param.type = ICMP6_PACKET_TYPE;
  459. pbuff_param.length = ND_NA_HEADER_SIZE + ND_OPT_TLLAO_SIZE - ND_PAYLOAD_ADJUST_OFFSET;
  460. err_code = iot_pbuffer_allocate(&pbuff_param, &p_pbuffer);
  461. if (err_code == NRF_SUCCESS)
  462. {
  463. p_reply_ip_header = (ipv6_header_t *)(p_pbuffer->p_payload - ICMP6_HEADER_SIZE -
  464. IPV6_IP_HEADER_SIZE);
  465. p_reply_icmp_header = (icmp6_header_t *)(p_pbuffer->p_payload - ICMP6_HEADER_SIZE);
  466. p_pbuffer->p_payload -= ND_PAYLOAD_ADJUST_OFFSET;
  467. p_reply_na_header = (icmp6_na_header_t *)(p_pbuffer->p_payload);
  468. p_reply_opt_tllao_header = (nd_option_tllao_t *)(p_pbuffer->p_payload + ND_NA_HEADER_SIZE);
  469. p_pbuffer->p_payload += ND_PAYLOAD_ADJUST_OFFSET;
  470. // Change ICMP header.
  471. p_reply_icmp_header->type = ICMP6_TYPE_NEIGHBOR_ADVERTISEMENT;
  472. p_reply_icmp_header->code = 0;
  473. p_reply_icmp_header->checksum = 0;
  474. // IPv6 Header initialization.
  475. icmp_ip_header(p_reply_ip_header, ND_HOP_LIMIT);
  476. p_reply_ip_header->srcaddr = *p_target_addr;
  477. p_reply_ip_header->destaddr = p_ip_header->srcaddr;
  478. p_reply_ip_header->length = HTONS(p_pbuffer->length + ICMP6_HEADER_SIZE);
  479. p_reply_na_header->flags = ND_NA_S_FLAG | ND_NA_O_FLAG ;
  480. p_reply_na_header->reserved = 0;
  481. p_reply_na_header->target_addr = *p_target_addr;
  482. // Add TLLAO option.
  483. add_tllao_opt(p_interface, p_reply_opt_tllao_header);
  484. // Calculate checksum.
  485. checksum = p_pbuffer->length + ICMP6_HEADER_SIZE + IPV6_NEXT_HEADER_ICMP6;
  486. ipv6_checksum_calculate(p_reply_ip_header->srcaddr.u8, IPV6_ADDR_SIZE, &checksum, false);
  487. ipv6_checksum_calculate(p_reply_ip_header->destaddr.u8, IPV6_ADDR_SIZE, &checksum, false);
  488. ipv6_checksum_calculate(p_pbuffer->p_payload - ICMP6_HEADER_SIZE,
  489. p_pbuffer->length + ICMP6_HEADER_SIZE,
  490. &checksum,
  491. false);
  492. p_reply_icmp_header->checksum = HTONS((~checksum));
  493. p_pbuffer->p_payload -= ICMP6_OFFSET;
  494. p_pbuffer->length += ICMP6_OFFSET;
  495. // Send IPv6 packet.
  496. err_code = ipv6_send(p_interface, p_pbuffer);
  497. if (err_code != NRF_SUCCESS)
  498. {
  499. ICMP6_ERR("Cannot send packet buffer!");
  500. }
  501. }
  502. else
  503. {
  504. ICMP6_ERR("Failed to allocate packet buffer!\r\n");
  505. }
  506. return err_code;
  507. }
  508. /**@brief Function for parsing Neighbor Solicitation message.
  509. *
  510. * @param[in] p_interface Pointer to external interface from which packet come.
  511. * @param[in] p_ip_header Pointer to IPv6 Header.
  512. * @param[in] p_icmp_header Pointer to ICMPv6 header.
  513. * @param[in] p_packet Pointer to packet buffer.
  514. *
  515. * @return NRF_SUCCESS after successful processing, error otherwise.
  516. */
  517. static uint32_t ns_input(iot_interface_t * p_interface,
  518. ipv6_header_t * p_ip_header,
  519. icmp6_header_t * p_icmp_header,
  520. iot_pbuffer_t * p_packet)
  521. {
  522. uint32_t err_code = NRF_SUCCESS;
  523. // Read target address.
  524. icmp6_ns_header_t * p_ns_header = (icmp6_ns_header_t *)p_packet->p_payload;
  525. if (ipv6_address_check(p_interface, &p_ns_header->target_addr) == NRF_SUCCESS)
  526. {
  527. err_code = na_send(p_interface, p_ip_header, p_icmp_header, &p_ns_header->target_addr);
  528. }
  529. return err_code;
  530. }
  531. /**@brief Function for parsing Router Advertisement message.
  532. * Because stack gives all control to application, internal RA parsing take care
  533. * only on Context Identifier.
  534. *
  535. * @param[in] p_interface Pointer to external interface from which packet come.
  536. * @param[in] p_ip_header Pointer to IPv6 Header.
  537. * @param[in] p_icmp_header Pointer to ICMPv6 header.
  538. * @param[in] p_packet Pointer to packet buffer.
  539. *
  540. * @return NRF_SUCCESS after successful processing, error otherwise.
  541. */
  542. static uint32_t ra_input(iot_interface_t * p_interface,
  543. ipv6_header_t * p_ip_header,
  544. icmp6_header_t * p_icmp_header,
  545. iot_pbuffer_t * p_packet)
  546. {
  547. uint32_t err_code;
  548. iot_context_t context;
  549. iot_context_t * p_context;
  550. uint16_t curr_opt_offset = ND_RA_HEADER_SIZE;
  551. nd_option_t * p_opt = NULL;
  552. nd_option_6co_t * p_6co = NULL;
  553. nd_option_pio_t * p_pio = NULL;
  554. if (!IPV6_ADDRESS_IS_LINK_LOCAL(&p_ip_header->srcaddr))
  555. {
  556. return ICMP6_INVALID_PACKET_DATA;
  557. }
  558. // Read all option we get.
  559. while (curr_opt_offset < p_packet->length)
  560. {
  561. p_opt = (nd_option_t *)(p_packet->p_payload + curr_opt_offset);
  562. if (p_opt->length == 0)
  563. {
  564. ICMP6_ERR("Invalid zero length option!");
  565. return ICMP6_INVALID_PACKET_DATA;
  566. }
  567. ICMP6_TRC("Option type = 0x%02x!", p_opt->type);
  568. // Searching for handling options.
  569. switch (p_opt->type)
  570. {
  571. case ND_OPT_TYPE_PIO:
  572. {
  573. p_pio = (nd_option_pio_t *)p_opt;
  574. if (p_pio->prefix_length != 0 &&
  575. (p_pio->flags & ND_OPT_PIO_A_MASK) &&
  576. !(p_pio->flags & ND_OPT_PIO_L_MASK))
  577. {
  578. // Ignore Link-Local address
  579. if (IPV6_ADDRESS_IS_LINK_LOCAL(&p_pio->prefix))
  580. {
  581. ICMP6_ERR("Ignore Link-Local prefix!");
  582. break;
  583. }
  584. // For now address is automatically set as a preferred.
  585. ipv6_addr_conf_t temp_address;
  586. // Set IPv6 EUI-64
  587. IPV6_CREATE_LINK_LOCAL_FROM_EUI64(&temp_address.addr,
  588. p_interface->local_addr.identifier);
  589. // Add prefix
  590. IPV6_ADDRESS_PREFIX_SET(temp_address.addr.u8,
  591. p_pio->prefix.u8,
  592. p_pio->prefix_length);
  593. if (p_pio->valid_lifetime != 0)
  594. {
  595. temp_address.state = IPV6_ADDR_STATE_PREFERRED;
  596. err_code = ipv6_address_set(p_interface, &temp_address);
  597. if (err_code != NRF_SUCCESS)
  598. {
  599. ICMP6_ERR("Cannot add new address! Address table full!");
  600. }
  601. }
  602. else
  603. {
  604. err_code = ipv6_address_remove(p_interface, &temp_address.addr);
  605. if (err_code != NRF_SUCCESS)
  606. {
  607. ICMP6_ERR("Cannot remove address!");
  608. }
  609. }
  610. }
  611. else
  612. {
  613. ICMP6_ERR("Prefix option has incorrect parameters!");
  614. return ICMP6_INVALID_PACKET_DATA;
  615. }
  616. break;
  617. }
  618. case ND_OPT_TYPE_6CO:
  619. {
  620. p_6co = (nd_option_6co_t *)p_opt;
  621. memset(context.prefix.u8, 0, IPV6_ADDR_SIZE);
  622. context.prefix = p_6co->context;
  623. context.prefix_len = p_6co->context_length;
  624. context.context_id = (p_6co->CID_C & ND_OPT_6CO_CID_MASK) >>
  625. ND_OPT_6CO_CID_POS;
  626. context.compression_flag = (p_6co->CID_C & ND_OPT_6CO_C_MASK) >>
  627. ND_OPT_6CO_C_POS;
  628. if (p_6co->valid_lifetime == 0)
  629. {
  630. err_code = iot_context_manager_get_by_cid(p_interface,
  631. context.context_id,
  632. &p_context);
  633. if (err_code == NRF_SUCCESS)
  634. {
  635. err_code = iot_context_manager_remove(p_interface, p_context);
  636. if (err_code == NRF_SUCCESS)
  637. {
  638. ICMP6_TRC("Removed context! CID = 0x%02x", context.context_id);
  639. }
  640. }
  641. }
  642. else
  643. {
  644. err_code = iot_context_manager_update(p_interface, &context);
  645. if (err_code == NRF_SUCCESS)
  646. {
  647. ICMP6_TRC("New context added! CID = 0x%02x", context.context_id);
  648. }
  649. }
  650. break;
  651. }
  652. }
  653. // Increment current offset option.
  654. curr_opt_offset += 8 * p_opt->length;
  655. }
  656. return NRF_SUCCESS;
  657. }
  658. /**@brief Function for notifying application of the ICMPv6 received packet.
  659. *
  660. * @param[in] p_interface Pointer to external interface from which packet come.
  661. * @param[in] p_ip_header Pointer to IPv6 Header.
  662. * @param[in] p_icmp_header Pointer to ICMPv6 header.
  663. * @param[in] p_packet Pointer to packet buffer.
  664. *
  665. * @return NRF_SUCCESS after successful processing, error otherwise.
  666. */
  667. static uint32_t ndisc_input(iot_interface_t * p_interface,
  668. ipv6_header_t * p_ip_header,
  669. icmp6_header_t * p_icmp_header,
  670. iot_pbuffer_t * p_packet)
  671. {
  672. uint32_t process_result;
  673. switch (p_icmp_header->type)
  674. {
  675. case ICMP6_TYPE_ROUTER_SOLICITATION:
  676. ICMP6_ERR("Got unsupported Router Solicitation message.");
  677. process_result = ICMP6_UNHANDLED_PACKET_TYPE;
  678. break;
  679. case ICMP6_TYPE_ROUTER_ADVERTISEMENT:
  680. ICMP6_TRC("Got Router Advertisement message.");
  681. process_result = ra_input(p_interface, p_ip_header, p_icmp_header, p_packet);
  682. break;
  683. case ICMP6_TYPE_NEIGHBOR_SOLICITATION:
  684. ICMP6_TRC("Got Neighbour Solicitation message.");
  685. process_result = ns_input(p_interface, p_ip_header, p_icmp_header, p_packet);
  686. break;
  687. case ICMP6_TYPE_NEIGHBOR_ADVERTISEMENT:
  688. ICMP6_TRC("Got Neighbour Advertisement message.");
  689. process_result = NRF_SUCCESS;
  690. break;
  691. default:
  692. process_result = ICMP6_UNHANDLED_PACKET_TYPE;
  693. break;
  694. }
  695. return process_result;
  696. }
  697. uint32_t icmp6_error_message(const iot_interface_t * p_interface,
  698. const ipv6_addr_t * p_src_addr,
  699. const ipv6_addr_t * p_dest_addr,
  700. const icmp6_error_message_param_t * p_param)
  701. {
  702. VERIFY_MODULE_IS_INITIALIZED();
  703. NULL_PARAM_CHECK(p_interface);
  704. NULL_PARAM_CHECK(p_src_addr);
  705. NULL_PARAM_CHECK(p_dest_addr);
  706. NULL_PARAM_CHECK(p_param);
  707. NULL_PARAM_CHECK(p_param->p_packet);
  708. ICMP6_MUTEX_LOCK();
  709. ICMP6_ENTRY();
  710. iot_pbuffer_t * p_pbuffer;
  711. ipv6_header_t * p_ip_header;
  712. icmp6_header_t * p_icmp_header;
  713. iot_pbuffer_alloc_param_t pbuff_param;
  714. uint16_t checksum;
  715. uint32_t err_code = NRF_SUCCESS;
  716. const uint32_t error_packet_length =
  717. (MIN(p_param->packet_len,
  718. ICMP6_ERROR_MESSAGE_MAX_SIZE - ICMP6_HEADER_SIZE));
  719. // Requesting buffer for error message.
  720. pbuff_param.flags = PBUFFER_FLAG_DEFAULT;
  721. pbuff_param.type = ICMP6_PACKET_TYPE;
  722. pbuff_param.length = error_packet_length;
  723. err_code = iot_pbuffer_allocate(&pbuff_param, &p_pbuffer);
  724. if (err_code == NRF_SUCCESS)
  725. {
  726. p_ip_header = (ipv6_header_t *)(p_pbuffer->p_payload - ICMP6_HEADER_SIZE -
  727. IPV6_IP_HEADER_SIZE);
  728. p_icmp_header = (icmp6_header_t *)(p_pbuffer->p_payload - ICMP6_HEADER_SIZE);
  729. // Change ICMP header.
  730. p_icmp_header->type = p_param->type;
  731. p_icmp_header->code = p_param->code;
  732. p_icmp_header->checksum = 0;
  733. switch (p_param->type)
  734. {
  735. case ICMP6_TYPE_PACKET_TOO_LONG:
  736. {
  737. p_icmp_header->sp.mtu = HTONL(p_param->error_field.mtu);
  738. break;
  739. }
  740. case ICMP6_TYPE_PARAMETER_PROBLEM:
  741. {
  742. p_icmp_header->sp.offset = HTONL(p_param->error_field.offset);
  743. break;
  744. }
  745. default:
  746. {
  747. p_icmp_header->sp.unused = 0;
  748. break;
  749. }
  750. }
  751. // IPv6 Header initialization.
  752. icmp_ip_header(p_ip_header, IPV6_DEFAULT_HOP_LIMIT);
  753. p_ip_header->srcaddr = *p_src_addr;
  754. p_ip_header->destaddr = *p_dest_addr;
  755. p_ip_header->length = HTONS(p_pbuffer->length + ICMP6_HEADER_SIZE);
  756. memcpy(p_pbuffer->p_payload, p_param->p_packet, error_packet_length);
  757. // Calculate checksum.
  758. checksum = error_packet_length + IPV6_NEXT_HEADER_ICMP6;
  759. ipv6_checksum_calculate(p_ip_header->srcaddr.u8, IPV6_ADDR_SIZE, &checksum, false);
  760. ipv6_checksum_calculate(p_ip_header->destaddr.u8, IPV6_ADDR_SIZE, &checksum, false);
  761. ipv6_checksum_calculate(p_pbuffer->p_payload - ICMP6_HEADER_SIZE,
  762. p_pbuffer->length + ICMP6_HEADER_SIZE,
  763. &checksum,
  764. false);
  765. // Update checksum in the packet.
  766. p_icmp_header->checksum = HTONS((~checksum));
  767. p_pbuffer->p_payload -= ICMP6_OFFSET;
  768. p_pbuffer->length += ICMP6_OFFSET;
  769. // Send IPv6 packet.
  770. err_code = ipv6_send(p_interface, p_pbuffer);
  771. }
  772. ICMP6_EXIT();
  773. ICMP6_MUTEX_UNLOCK();
  774. return err_code;
  775. }
  776. uint32_t icmp6_echo_request(const iot_interface_t * p_interface,
  777. const ipv6_addr_t * p_src_addr,
  778. const ipv6_addr_t * p_dest_addr,
  779. iot_pbuffer_t * p_request)
  780. {
  781. VERIFY_MODULE_IS_INITIALIZED();
  782. NULL_PARAM_CHECK(p_interface);
  783. NULL_PARAM_CHECK(p_src_addr);
  784. NULL_PARAM_CHECK(p_dest_addr);
  785. NULL_PARAM_CHECK(p_request);
  786. PACKET_TYPE_CHECK(p_request);
  787. uint32_t err_code = NRF_SUCCESS;
  788. uint16_t checksum;
  789. ipv6_header_t * p_ip_header;
  790. icmp6_header_t * p_icmp_header;
  791. ICMP6_MUTEX_LOCK();
  792. ICMP6_ENTRY();
  793. // Headers of IPv6 packet.
  794. p_ip_header = (ipv6_header_t *)(p_request->p_payload - ICMP6_HEADER_SIZE -
  795. IPV6_IP_HEADER_SIZE);
  796. p_icmp_header = (icmp6_header_t *)(p_request->p_payload - ICMP6_HEADER_SIZE);
  797. // Change ICMP header.
  798. p_icmp_header->type = ICMP6_TYPE_ECHO_REQUEST;
  799. p_icmp_header->code = 0;
  800. p_icmp_header->checksum = 0;
  801. // IPv6 Header initialization.
  802. icmp_ip_header(p_ip_header, IPV6_DEFAULT_HOP_LIMIT);
  803. p_ip_header->srcaddr = *p_src_addr;
  804. p_ip_header->destaddr = *p_dest_addr;
  805. p_ip_header->length = HTONS(p_request->length + ICMP6_HEADER_SIZE);
  806. // Set echo reply parameters.
  807. p_icmp_header->sp.echo.id = 0;
  808. p_icmp_header->sp.echo.sequence = HTONS(m_sequence_number);
  809. // Calculate checksum.
  810. checksum = p_request->length + ICMP6_HEADER_SIZE + IPV6_NEXT_HEADER_ICMP6;
  811. ipv6_checksum_calculate(p_ip_header->srcaddr.u8, IPV6_ADDR_SIZE, &checksum, false);
  812. ipv6_checksum_calculate(p_ip_header->destaddr.u8, IPV6_ADDR_SIZE, &checksum, false);
  813. ipv6_checksum_calculate(p_request->p_payload - ICMP6_HEADER_SIZE,
  814. p_request->length + ICMP6_HEADER_SIZE,
  815. &checksum,
  816. false);
  817. p_icmp_header->checksum = HTONS((~checksum));
  818. m_sequence_number++;
  819. p_request->p_payload -= ICMP6_OFFSET;
  820. p_request->length += ICMP6_OFFSET;
  821. // Send IPv6 packet.
  822. err_code = ipv6_send(p_interface, p_request);
  823. ICMP6_EXIT();
  824. ICMP6_MUTEX_UNLOCK();
  825. return err_code;
  826. }
  827. uint32_t icmp6_rs_send(const iot_interface_t * p_interface,
  828. const ipv6_addr_t * p_src_addr,
  829. const ipv6_addr_t * p_dest_addr)
  830. {
  831. VERIFY_MODULE_IS_INITIALIZED();
  832. NULL_PARAM_CHECK(p_interface);
  833. NULL_PARAM_CHECK(p_src_addr);
  834. NULL_PARAM_CHECK(p_dest_addr);
  835. uint32_t err_code = NRF_SUCCESS;
  836. uint16_t checksum;
  837. iot_pbuffer_t * p_pbuffer;
  838. iot_pbuffer_alloc_param_t pbuff_param;
  839. // IPv6 Headers.
  840. ipv6_header_t * p_ip_header;
  841. icmp6_header_t * p_icmp_header;
  842. icmp6_rs_header_t * p_rs_header;
  843. nd_option_sllao_t * p_sllao_opt;
  844. ICMP6_MUTEX_LOCK();
  845. ICMP6_ENTRY();
  846. // Requesting buffer for RS message
  847. pbuff_param.flags = PBUFFER_FLAG_DEFAULT;
  848. pbuff_param.type = ICMP6_PACKET_TYPE;
  849. pbuff_param.length = ND_OPT_SLLAO_SIZE;
  850. err_code = iot_pbuffer_allocate(&pbuff_param, &p_pbuffer);
  851. if (err_code == NRF_SUCCESS)
  852. {
  853. p_ip_header = (ipv6_header_t *)(p_pbuffer->p_payload - ICMP6_HEADER_SIZE -
  854. IPV6_IP_HEADER_SIZE);
  855. p_icmp_header = (icmp6_header_t *)(p_pbuffer->p_payload - ICMP6_HEADER_SIZE);
  856. p_rs_header = (icmp6_rs_header_t *)(&p_icmp_header->sp.unused);
  857. p_sllao_opt = (nd_option_sllao_t *)(p_pbuffer->p_payload);
  858. // Change ICMP header.
  859. p_icmp_header->type = ICMP6_TYPE_ROUTER_SOLICITATION;
  860. p_icmp_header->code = 0;
  861. p_icmp_header->checksum = 0;
  862. // IPv6 Header initialization.
  863. icmp_ip_header(p_ip_header, ND_HOP_LIMIT);
  864. p_ip_header->srcaddr = *p_src_addr;
  865. p_ip_header->destaddr = *p_dest_addr;
  866. p_ip_header->length = HTONS(p_pbuffer->length + ICMP6_HEADER_SIZE);
  867. // Set Router Solicitation parameter.
  868. p_rs_header->reserved = 0;
  869. // Add SLLAO option.
  870. add_sllao_opt(p_interface, p_sllao_opt);
  871. // Calculate checksum.
  872. checksum = p_pbuffer->length + ICMP6_HEADER_SIZE + IPV6_NEXT_HEADER_ICMP6;
  873. ipv6_checksum_calculate(p_ip_header->srcaddr.u8, IPV6_ADDR_SIZE, &checksum, false);
  874. ipv6_checksum_calculate(p_ip_header->destaddr.u8, IPV6_ADDR_SIZE, &checksum, false);
  875. ipv6_checksum_calculate(p_pbuffer->p_payload - ICMP6_HEADER_SIZE,
  876. p_pbuffer->length + ICMP6_HEADER_SIZE,
  877. &checksum,
  878. false);
  879. p_icmp_header->checksum = HTONS((~checksum));
  880. p_pbuffer->p_payload -= ICMP6_OFFSET;
  881. p_pbuffer->length += ICMP6_OFFSET;
  882. // Send IPv6 packet.
  883. err_code = ipv6_send(p_interface, p_pbuffer);
  884. }
  885. else
  886. {
  887. ICMP6_ERR("Failed to allocate packet buffer!");
  888. }
  889. ICMP6_EXIT();
  890. ICMP6_MUTEX_UNLOCK();
  891. return err_code;
  892. }
  893. uint32_t icmp6_ns_send(const iot_interface_t * p_interface,
  894. const ipv6_addr_t * p_src_addr,
  895. const ipv6_addr_t * p_dest_addr,
  896. const icmp6_ns_param_t * p_param)
  897. {
  898. VERIFY_MODULE_IS_INITIALIZED();
  899. NULL_PARAM_CHECK(p_interface);
  900. NULL_PARAM_CHECK(p_src_addr);
  901. NULL_PARAM_CHECK(p_dest_addr);
  902. NULL_PARAM_CHECK(p_param);
  903. uint32_t err_code = NRF_SUCCESS;
  904. uint16_t aro_size = 0;
  905. uint16_t checksum;
  906. iot_pbuffer_t * p_pbuffer;
  907. iot_pbuffer_alloc_param_t pbuff_param;
  908. // IPv6 Headers.
  909. ipv6_header_t * p_ip_header;
  910. icmp6_header_t * p_icmp_header;
  911. icmp6_ns_header_t * p_ns_header;
  912. nd_option_sllao_t * p_sllao_opt;
  913. nd_option_aro_t * p_aro_opt;
  914. ICMP6_MUTEX_LOCK();
  915. ICMP6_ENTRY();
  916. if (p_param->add_aro)
  917. {
  918. aro_size = ND_OPT_ARO_SIZE;
  919. }
  920. // Requesting buffer for NS message
  921. pbuff_param.flags = PBUFFER_FLAG_DEFAULT;
  922. pbuff_param.type = ICMP6_PACKET_TYPE;
  923. pbuff_param.length = ND_NS_HEADER_SIZE + ND_OPT_SLLAO_SIZE + \
  924. aro_size - ND_PAYLOAD_ADJUST_OFFSET;
  925. err_code = iot_pbuffer_allocate(&pbuff_param, &p_pbuffer);
  926. if (err_code == NRF_SUCCESS)
  927. {
  928. p_ip_header = (ipv6_header_t *)(p_pbuffer->p_payload - ICMP6_HEADER_SIZE -
  929. IPV6_IP_HEADER_SIZE);
  930. p_icmp_header = (icmp6_header_t *)(p_pbuffer->p_payload - ICMP6_HEADER_SIZE);
  931. p_pbuffer->p_payload -= ND_PAYLOAD_ADJUST_OFFSET;
  932. p_ns_header = (icmp6_ns_header_t *)(p_pbuffer->p_payload);
  933. p_sllao_opt = (nd_option_sllao_t *)(p_pbuffer->p_payload + ND_NS_HEADER_SIZE);
  934. p_aro_opt = (nd_option_aro_t *)(p_pbuffer->p_payload + ND_NS_HEADER_SIZE +
  935. ND_OPT_SLLAO_SIZE);
  936. p_pbuffer->p_payload += ND_PAYLOAD_ADJUST_OFFSET;
  937. // Change ICMP header.
  938. p_icmp_header->type = ICMP6_TYPE_NEIGHBOR_SOLICITATION;
  939. p_icmp_header->code = 0;
  940. p_icmp_header->checksum = 0;
  941. // IPv6 Header initialization.
  942. icmp_ip_header(p_ip_header, ND_HOP_LIMIT);
  943. p_ip_header->srcaddr = *p_src_addr;
  944. p_ip_header->destaddr = *p_dest_addr;
  945. p_ip_header->length = HTONS(p_pbuffer->length + ICMP6_HEADER_SIZE);
  946. // Set Neighbour Solicitation parameter.
  947. p_ns_header->reserved = 0;
  948. p_ns_header->target_addr = p_param->target_addr;
  949. // Add SLLAO option.
  950. add_sllao_opt(p_interface, p_sllao_opt);
  951. if (p_param->add_aro)
  952. {
  953. add_aro_opt(p_interface, p_aro_opt, p_param->aro_lifetime);
  954. }
  955. // Calculate checksum.
  956. checksum = p_pbuffer->length + ICMP6_HEADER_SIZE + IPV6_NEXT_HEADER_ICMP6;
  957. ipv6_checksum_calculate(p_ip_header->srcaddr.u8, IPV6_ADDR_SIZE, &checksum, false);
  958. ipv6_checksum_calculate(p_ip_header->destaddr.u8, IPV6_ADDR_SIZE, &checksum, false);
  959. ipv6_checksum_calculate(p_pbuffer->p_payload - ICMP6_HEADER_SIZE,
  960. p_pbuffer->length + ICMP6_HEADER_SIZE,
  961. &checksum,
  962. false);
  963. p_icmp_header->checksum = HTONS((~checksum));
  964. p_pbuffer->p_payload -= ICMP6_OFFSET;
  965. p_pbuffer->length += ICMP6_OFFSET;
  966. // Send IPv6 packet.
  967. err_code = ipv6_send(p_interface, p_pbuffer);
  968. }
  969. else
  970. {
  971. ICMP6_ERR("Failed to allocate packet buffer!");
  972. }
  973. ICMP6_EXIT();
  974. ICMP6_MUTEX_UNLOCK();
  975. return err_code;
  976. }
  977. uint32_t icmp6_receive_register(icmp6_receive_callback_t cb)
  978. {
  979. VERIFY_MODULE_IS_INITIALIZED();
  980. NULL_PARAM_CHECK(cb);
  981. UNUSED_VARIABLE(m_event_handler);
  982. ICMP6_MUTEX_LOCK();
  983. ICMP6_ENTRY();
  984. // Store application event handler.
  985. m_event_handler = cb;
  986. ICMP6_EXIT();
  987. ICMP6_MUTEX_UNLOCK();
  988. return NRF_SUCCESS;
  989. }
  990. uint32_t icmp6_init(void)
  991. {
  992. SDK_MUTEX_INIT(m_icmp6_mutex);
  993. ICMP6_MUTEX_LOCK();
  994. ICMP6_ENTRY();
  995. // Set application event handler.
  996. m_event_handler = NULL;
  997. // Indicate initialization of module.
  998. m_initialization_state = true;
  999. ICMP6_EXIT();
  1000. ICMP6_MUTEX_UNLOCK();
  1001. return NRF_SUCCESS;
  1002. }
  1003. uint32_t icmp6_input(iot_interface_t * p_interface,
  1004. ipv6_header_t * p_ip_header,
  1005. iot_pbuffer_t * p_packet)
  1006. {
  1007. VERIFY_MODULE_IS_INITIALIZED();
  1008. NULL_PARAM_CHECK(p_interface);
  1009. NULL_PARAM_CHECK(p_ip_header);
  1010. NULL_PARAM_CHECK(p_packet);
  1011. uint16_t checksum;
  1012. uint32_t process_result = NRF_SUCCESS;
  1013. bool is_ndisc = false;
  1014. icmp6_header_t * p_icmp_header = (icmp6_header_t *)p_packet->p_payload;
  1015. uint32_t err_code = NRF_SUCCESS;
  1016. ICMP6_MUTEX_LOCK();
  1017. ICMP6_ENTRY();
  1018. if (p_packet->length < ICMP6_HEADER_SIZE || p_ip_header->length < ICMP6_HEADER_SIZE)
  1019. {
  1020. ICMP6_ERR("Received malformed packet, which has 0x%08lX bytes.", p_packet->length);
  1021. process_result = ICMP6_MALFORMED_PACKET;
  1022. }
  1023. else
  1024. {
  1025. // Check checksum of packet.
  1026. checksum = p_packet->length + IPV6_NEXT_HEADER_ICMP6;
  1027. ipv6_checksum_calculate(p_ip_header->srcaddr.u8, IPV6_ADDR_SIZE, &checksum, false);
  1028. ipv6_checksum_calculate(p_ip_header->destaddr.u8, IPV6_ADDR_SIZE, &checksum, false);
  1029. ipv6_checksum_calculate(p_packet->p_payload, p_packet->length, &checksum, false);
  1030. checksum = (uint16_t)~checksum;
  1031. // Change pbuffer type.
  1032. p_packet->type = ICMP6_PACKET_TYPE;
  1033. p_packet->p_payload = p_packet->p_payload + ICMP6_HEADER_SIZE;
  1034. p_packet->length -= ICMP6_HEADER_SIZE;
  1035. if (checksum != 0)
  1036. {
  1037. ICMP6_ERR("Bad checksum detected. Got 0x%08x but expected 0x%08x, 0x%08lX",
  1038. NTOHS(p_icmp_header->checksum), checksum, p_packet->length);
  1039. process_result = ICMP6_BAD_CHECKSUM;
  1040. }
  1041. else
  1042. {
  1043. switch (p_icmp_header->type)
  1044. {
  1045. case ICMP6_TYPE_DESTINATION_UNREACHABLE:
  1046. case ICMP6_TYPE_PACKET_TOO_LONG:
  1047. case ICMP6_TYPE_TIME_EXCEED:
  1048. case ICMP6_TYPE_PARAMETER_PROBLEM:
  1049. {
  1050. ICMP6_TRC("Got ICMPv6 error message with type = 0x%08x",
  1051. p_icmp_header->type);
  1052. p_icmp_header->sp.unused = NTOHL(p_icmp_header->sp.unused);
  1053. break;
  1054. }
  1055. case ICMP6_TYPE_ECHO_REQUEST:
  1056. case ICMP6_TYPE_ECHO_REPLY:
  1057. {
  1058. ICMP6_TRC("Got ICMPv6 Echo message with type = 0x%x.", p_icmp_header->type);
  1059. ICMP6_TRC("From IPv6 Address:");
  1060. ICMP6_DUMP(p_ip_header->srcaddr.u32, IPV6_ADDR_SIZE);
  1061. ICMP6_TRC("Identifier: 0x%04x, Sequence Number: 0x%04x",
  1062. NTOHS(p_icmp_header->sp.echo.id),
  1063. NTOHS(p_icmp_header->sp.echo.sequence));
  1064. break;
  1065. }
  1066. case ICMP6_TYPE_ROUTER_SOLICITATION:
  1067. case ICMP6_TYPE_ROUTER_ADVERTISEMENT:
  1068. case ICMP6_TYPE_NEIGHBOR_SOLICITATION:
  1069. case ICMP6_TYPE_NEIGHBOR_ADVERTISEMENT:
  1070. {
  1071. p_packet->p_payload = p_packet->p_payload - ND_PAYLOAD_ADJUST_OFFSET;
  1072. p_packet->length += ND_PAYLOAD_ADJUST_OFFSET;
  1073. process_result = ndisc_input(p_interface,
  1074. p_ip_header,
  1075. p_icmp_header,
  1076. p_packet);
  1077. p_packet->p_payload = p_packet->p_payload + ND_PAYLOAD_ADJUST_OFFSET;
  1078. p_packet->length -= ND_PAYLOAD_ADJUST_OFFSET;
  1079. is_ndisc = true;
  1080. break;
  1081. }
  1082. default:
  1083. process_result = ICMP6_UNHANDLED_PACKET_TYPE;
  1084. break;
  1085. }
  1086. #if (ICMP6_ENABLE_HANDLE_ECHO_REQUEST_TO_APPLICATION == 0)
  1087. if (p_icmp_header->type == ICMP6_TYPE_ECHO_REQUEST)
  1088. {
  1089. echo_reply_send(p_interface, p_ip_header, p_icmp_header, p_packet);
  1090. }
  1091. #endif
  1092. }
  1093. }
  1094. #if (ICMP6_ENABLE_ALL_MESSAGES_TO_APPLICATION == 1)
  1095. err_code = app_notify_icmp_data(p_interface, p_packet, process_result);
  1096. #elif (ICMP6_ENABLE_ND6_MESSAGES_TO_APPLICATION == 1)
  1097. if (is_ndisc)
  1098. {
  1099. err_code = app_notify_icmp_data(p_interface, p_packet, process_result);
  1100. }
  1101. #endif
  1102. ICMP6_EXIT();
  1103. UNUSED_VARIABLE(is_ndisc);
  1104. UNUSED_VARIABLE(process_result);
  1105. ICMP6_MUTEX_UNLOCK();
  1106. return err_code;
  1107. }