12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355 |
- /**
- * Copyright (c) 2013 - 2018, Nordic Semiconductor ASA
- *
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification,
- * are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form, except as embedded into a Nordic
- * Semiconductor ASA integrated circuit in a product or a software update for
- * such product, must reproduce the above copyright notice, this list of
- * conditions and the following disclaimer in the documentation and/or other
- * materials provided with the distribution.
- *
- * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
- * contributors may be used to endorse or promote products derived from this
- * software without specific prior written permission.
- *
- * 4. This software, with or without modification, must only be used with a
- * Nordic Semiconductor ASA integrated circuit.
- *
- * 5. Any software provided in binary form under this license must not be reverse
- * engineered, decompiled, modified and/or disassembled.
- *
- * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
- * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
- * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
- #include <stdio.h>
- #include <stdint.h>
- #include <stdbool.h>
- #include <string.h>
- #include "icmp6_api.h"
- #include "ipv6_api.h"
- #include "icmp6.h"
- #include "iot_context_manager.h"
- #include "ipv6_utils.h"
- #include "iot_common.h"
- #if ICMP6_CONFIG_LOG_ENABLED
- #define NRF_LOG_MODULE_NAME icmp6
- #define NRF_LOG_LEVEL ICMP6_CONFIG_LOG_LEVEL
- #define NRF_LOG_INFO_COLOR ICMP6_CONFIG_INFO_COLOR
- #define NRF_LOG_DEBUG_COLOR ICMP6_CONFIG_DEBUG_COLOR
- #include "nrf_log.h"
- NRF_LOG_MODULE_REGISTER();
- #define ICMP6_TRC NRF_LOG_DEBUG /**< Used for getting trace of execution in the module. */
- #define ICMP6_ERR NRF_LOG_ERROR /**< Used for logging errors in the module. */
- #define ICMP6_DUMP NRF_LOG_HEXDUMP_DEBUG /**< Used for dumping octet information to get details of bond information etc. */
- #define ICMP6_ENTRY() ICMP6_TRC(">> %s", __func__)
- #define ICMP6_EXIT() ICMP6_TRC("<< %s", __func__)
- #else // ICMP6_CONFIG_LOG_ENABLED
- #define ICMP6_TRC(...) /**< Disables traces. */
- #define ICMP6_DUMP(...) /**< Disables dumping of octet streams. */
- #define ICMP6_ERR(...) /**< Disables error logs. */
- #define ICMP6_ENTRY(...)
- #define ICMP6_EXIT(...)
- #endif // ICMP6_CONFIG_LOG_ENABLED
- /**
- * @defgroup api_param_check API Parameters check macros.
- *
- * @details Macros that verify parameters passed to the module in the APIs. These macros
- * could be mapped to nothing in final versions of code to save execution and size.
- * ICMP6_DISABLE_API_PARAM_CHECK should be set to 1 to disable these checks.
- *
- * @{
- */
- #if (ICMP6_DISABLE_API_PARAM_CHECK == 0)
- /**@brief Macro to check is module is initialized before requesting one of the module procedures. */
- #define VERIFY_MODULE_IS_INITIALIZED() \
- if (m_initialization_state == false) \
- { \
- return (SDK_ERR_MODULE_NOT_INITIALIZED | IOT_ICMP6_ERR_BASE); \
- }
- /**@brief Macro to check is module is initialized before requesting one of the module
- procedures but does not use any return code. */
- #define VERIFY_MODULE_IS_INITIALIZED_VOID() \
- if (m_initialization_state == false) \
- { \
- return; \
- }
- /**
- * @brief Verify NULL parameters are not passed to API by application.
- */
- #define NULL_PARAM_CHECK(PARAM) \
- if ((PARAM) == NULL) \
- { \
- return (NRF_ERROR_NULL | IOT_ICMP6_ERR_BASE); \
- }
- /**
- * @brief Verify packet buffer is of ICMP6 Type.
- */
- #define PACKET_TYPE_CHECK(PACKET) \
- if ((PACKET)->type != ICMP6_PACKET_TYPE) \
- { \
- return (NRF_ERROR_INVALID_PARAM | IOT_ICMP6_ERR_BASE); \
- }
- #else // ICMP6_DISABLE_API_PARAM_CHECK
- #define VERIFY_MODULE_IS_INITIALIZED()
- #define VERIFY_MODULE_IS_INITIALIZED_VOID()
- #define NULL_PARAM_CHECK(PARAM)
- #define PACKET_TYPE_CHECK(PACKET)
- #endif // ICMP6_DISABLE_API_PARAM_CHECK
- /** @} */
- /**
- * @defgroup icmp6_mutex_lock_unlock Module's Mutex Lock/Unlock Macros.
- *
- * @details Macros used to lock and unlock modules. Currently, SDK does not use mutexes but
- * framework is provided in case need arises to use an alternative architecture.
- * @{
- */
- #define ICMP6_MUTEX_LOCK() SDK_MUTEX_LOCK(m_icmp6_mutex) /**< Lock module using mutex */
- #define ICMP6_MUTEX_UNLOCK() SDK_MUTEX_UNLOCK(m_icmp6_mutex) /**< Unlock module using mutex */
- /** @} */
- #define ND_NS_HEADER_SIZE 20 /**< Size of Neighbour Solicitation message. */
- #define ND_NA_HEADER_SIZE 20 /**< Size of Neighbour Advertisement message. */
- #define ND_RS_HEADER_SIZE 4 /**< Size of Router Solicitation message. */
- #define ND_RA_HEADER_SIZE 12 /**< Size of Router Advertisement message. */
- #define ND_PAYLOAD_ADJUST_OFFSET 4 /**< Adjusting ND related payload offset as the general ICMP structure is not upheld. */
- #define ND_NA_R_FLAG 0x80 /**< Router flag. When set, the R-bit indicates that the sender is a router. */
- #define ND_NA_S_FLAG 0x40 /**< Solicited flag. When set, the S-bit indicates that the advertisement was sent in response
- to a Neighbor Solicitation .*/
- #define ND_NA_O_FLAG 0x20 /**< Override flag. When set, the O-bit indicates that the advertisement should override
- an existing cache entry and update the cached link-layer address .*/
- #define ND_OPT_TYPE_SLLAO 1 /**< Source Link Layer Address Option. */
- #define ND_OPT_TYPE_TLLAO 2 /**< Target Link Layer Address Option. */
- #define ND_OPT_TYPE_PIO 3 /**< Prefix Information Option. */
- #define ND_OPT_TYPE_RHO 4 /**< Redirected Header Option. */
- #define ND_OPT_TYPE_MTU 5 /**< Maximum Transmit Unit Option. */
- #define ND_OPT_TYPE_ARO 33 /**< Address Registration Option. */
- #define ND_OPT_TYPE_6CO 34 /**< 6LoWPAN Context Option. */
- #define ND_OPT_TYPE_6ABRO 35 /**< Authoritative Border Router Option. */
- #define ND_OPT_SLLAO_SIZE (8 * (((IPV6_LL_ADDR_SIZE) / 8) + 1)) /**< Size of SLLAO option. */
- #define ND_OPT_TLLAO_SIZE (8 * (((IPV6_LL_ADDR_SIZE) / 8) + 1)) /**< Size of TLLAO option. */
- #define ND_OPT_PIO_SIZE 32 /**< Size of PIO option. */
- #define ND_OPT_MTU_SIZE 8 /**< Size of MTU option. */
- #define ND_OPT_ARO_SIZE 16 /**< Size of ARO option. */
- #define ND_OPT_6CO_SIZE 24 /**< Size of 6CO option. */
- #define ND_OPT_6ABRO_SIZE 24 /**< Size of 6ABRO option. */
- #define ND_OPT_SLLAO_LENGTH ((ND_OPT_SLLAO_SIZE) / 8) /**< Value of length field in SLLAO option. */
- #define ND_OPT_TLLAO_LENGTH ((ND_OPT_TLLAO_SIZE) / 8) /**< Value of length field in SLLAO option. */
- #define ND_OPT_ARO_LENGTH 2 /**< Value of length field in ARO option. */
- #define ND_OPT_6CO_CID_MASK 0x0F
- #define ND_OPT_6CO_CID_POS 0
- #define ND_OPT_6CO_C_MASK 0x10
- #define ND_OPT_6CO_C_POS 4
- #define ND_OPT_PIO_L_MASK 0x80
- #define ND_OPT_PIO_L_POS 7
- #define ND_OPT_PIO_A_MASK 0x40
- #define ND_OPT_PIO_A_POS 6
- #define ND_HOP_LIMIT 255 /**< Value of Hop Limit used in Neighbour Discovery procedure. */
- #define ICMP6_OFFSET IPV6_IP_HEADER_SIZE + ICMP6_HEADER_SIZE /**< Offset of ICMPv6 packet type. */
- #define ERROR_ADDITIONAL_HEADER_SIZE 4 /**< Additional 4 bytes of information every ICMP error message contains. */
- #define ERROR_MESSAGE_HEADER_SIZE (ICMP6_HEADER_SIZE + ERROR_ADDITIONAL_HEADER_SIZE) /**< Error message header size including type, code, checksum and 32-bit parameter. */
- #define ICMP6_ERROR_OFFSET IPV6_IP_HEADER_SIZE + ERROR_MESSAGE_HEADER_SIZE /**< Offset for ICMPv6 error message. */
- /**@brief Neighbor Solicitation header. */
- typedef struct
- {
- uint32_t reserved; /**< Reserved field. */
- ipv6_addr_t target_addr; /**< Target Address field. */
- } icmp6_ns_header_t;
- /**@brief Neighbor Advertisement header. */
- typedef struct
- {
- uint8_t flags; /**< Flags (R,S and O). */
- uint8_t reserved; /**< Reserved field. */
- ipv6_addr_t target_addr; /**< Target Address field. */
- } icmp6_na_header_t;
- /**@brief Router Solicitation message's header. */
- typedef struct
- {
- uint32_t reserved; /**< Reserved field. */
- } icmp6_rs_header_t;
- /**@brief Option header of ICMPv6 packet. */
- typedef struct
- {
- uint8_t type; /**< Option type. */
- uint8_t length; /**< Length, in unit of 8 octets. */
- } nd_option_t;
- /**@brief Source Link Layer Address Option header format. */
- typedef struct
- {
- uint8_t type; /**< Option type. */
- uint8_t length; /**< Length, units of 8 octets. */
- eui64_t addr; /**< Link-layer address. */
- uint8_t padding[6]; /**< Padding. */
- } nd_option_sllao_t;
- /**@brief Target Link Layer Address Option header format. */
- typedef struct
- {
- uint8_t type; /**< Option type. */
- uint8_t length; /**< Length, units of 8 octets. */
- eui64_t addr; /**< Link-layer address. */
- uint8_t padding[6]; /**< Padding. */
- } nd_option_tllao_t;
- /**@brief Prefix Information Option header format. */
- typedef struct
- {
- uint8_t type; /**< Option type. */
- uint8_t length; /**< Length, units of 8 octets. */
- uint8_t prefix_length; /**< Prefix length. */
- uint8_t flags; /**< Flags (L/A) and reserved. */
- uint32_t valid_lifetime; /**< Valid Lifetime. */
- uint32_t preferred_lifetime; /**< Preferred Lifetime. */
- uint32_t reserved; /**< Reserved field. */
- ipv6_addr_t prefix; /**< Prefix address. */
- } nd_option_pio_t;
- /**@brief Address Registration Option header format. */
- typedef struct
- {
- uint8_t type; /**< Option type. */
- uint8_t length; /**< Length, units of 8 octets. */
- uint8_t status; /**< Status of ARO. */
- uint8_t reserved; /**< Reserved1, split to avoid alignment. */
- uint16_t reserved2; /**< Reserved2, split to avoid alignment. */
- uint16_t registration_lifetime; /**< Registration Lifetime. */
- eui64_t eui64; /**< EUI-64 source address. */
- } nd_option_aro_t;
- /**@brief 6LoWPAN Context Option header format. */
- typedef struct
- {
- uint8_t type; /**< Option type. */
- uint8_t length; /**< Length, units of 8 octets. */
- uint8_t context_length; /**< Context Length. */
- uint8_t CID_C; /**< 4-bit Context and 1-bit context compression flag. */
- uint16_t reserved; /**< Reserved. */
- uint16_t valid_lifetime; /**< Valid Lifetime. */
- ipv6_addr_t context; /**< Context IPv6 Prefix. */
- } nd_option_6co_t;
- static bool m_initialization_state = false; /**< Variable to maintain module initialization state. */
- static uint16_t m_sequence_number = 0; /**< Sequence number from ICMPv6 packet. */
- static icmp6_receive_callback_t m_event_handler = NULL; /**< Application event handler. */
- SDK_MUTEX_DEFINE(m_icmp6_mutex) /**< Mutex variable. Currently unused, this declaration does not occupy any space in RAM. */
- /**@brief Function for initializing default values of IP Header for ICMP.
- *
- * @param[in] p_ip_header Pointer to IPv6 header.
- * @param[in] hoplimit Hop Limit in IPv6 header.
- *
- * @return None.
- */
- static __INLINE void icmp_ip_header(ipv6_header_t * p_ip_header, uint8_t hoplimit)
- {
- ipv6_header_init(p_ip_header);
- p_ip_header->next_header = IPV6_NEXT_HEADER_ICMP6;
- p_ip_header->hoplimit = hoplimit;
- }
- /**@brief Function for adding SLLAO option to the packet.
- *
- * @param[in] p_interface Pointer to IoT interface.
- * @param[in] p_data Pointer to the memory where SLLAO option should be added.
- *
- * @return None.
- */
- static __INLINE void add_sllao_opt(const iot_interface_t * p_interface, nd_option_sllao_t * p_sllao)
- {
- p_sllao->type = ND_OPT_TYPE_SLLAO;
- p_sllao->length = ND_OPT_SLLAO_LENGTH;
- #if (IPV6_LL_ADDR_SIZE == 6)
- memcpy(p_sllao->addr.identifier, p_interface->local_addr.identifier, 3);
- memcpy(p_sllao->addr.identifier + 3, p_interface->local_addr.identifier + 5, 3);
- #else
- // Copy EUI-64 and add padding.
- memcpy(p_sllao->addr.identifier, p_interface->local_addr.identifier, IPV6_LL_ADDR_SIZE);
- memset(p_sllao->padding, 0, 6);
- #endif
- }
- /**@brief Function for adding TLLAO option to the packet.
- *
- * @param[in] p_interface Pointer to IoT interface.
- * @param[in] p_data Pointer to the memory where TLLAO option should be added.
- *
- * @return None.
- */
- static __INLINE void add_tllao_opt(const iot_interface_t * p_interface, nd_option_tllao_t * p_tllao)
- {
- p_tllao->type = ND_OPT_TYPE_TLLAO;
- p_tllao->length = ND_OPT_TLLAO_LENGTH;
- #if (IPV6_LL_ADDR_SIZE == 6)
- memcpy(p_tllao->addr.identifier, p_interface->local_addr.identifier, 3);
- memcpy(p_tllao->addr.identifier + 3, p_interface->local_addr.identifier + 5, 3);
- #else
- // Copy EUI-64 and add padding.
- memcpy(p_tllao->addr.identifier, p_interface->local_addr.identifier, IPV6_LL_ADDR_SIZE);
- memset(p_tllao->padding, 0, 6);
- #endif
- }
- /**@brief Function for adding ARO option to packet.
- *
- * @param[in] p_interface Pointer to IoT interface.
- * @param[in] p_data Pointer to the memory where ARO option should be added.
- * @param[in] aro_lifetime Lifetime of registration.
- *
- * @return None.
- */
- static __INLINE void add_aro_opt(const iot_interface_t * p_interface,
- nd_option_aro_t * p_aro,
- uint16_t aro_lifetime)
- {
- p_aro->type = ND_OPT_TYPE_ARO;
- p_aro->length = ND_OPT_ARO_LENGTH;
- p_aro->status = 0x00;
- p_aro->reserved = 0x00;
- p_aro->reserved2 = 0x00;
- p_aro->registration_lifetime = HTONS(aro_lifetime);
- // Copy EUI-64 and add padding.
- memcpy(p_aro->eui64.identifier, p_interface->local_addr.identifier, EUI_64_ADDR_SIZE);
- }
- #if (ICMP6_ENABLE_ND6_MESSAGES_TO_APPLICATION == 1 || ICMP6_ENABLE_ALL_MESSAGES_TO_APPLICATION == 1)
- /**@brief Function for notifying application of the ICMPv6 received packet.
- *
- * @param[in] p_interface Pointer to external interface from which packet come.
- * @param[in] p_pbuffer Pointer to packet buffer of ICMP6_PACKET_TYPE.
- * @param[in] process_result Result of internal processing packet.
- *
- * @return NRF_SUCCESS after successful processing, error otherwise.
- */
- static uint32_t app_notify_icmp_data(iot_interface_t * p_interface,
- iot_pbuffer_t * p_pbuffer,
- uint32_t process_result)
- {
- uint32_t err_code = NRF_SUCCESS;
- if (m_event_handler != NULL)
- {
- ipv6_header_t * p_ip_header = (ipv6_header_t *)
- (p_pbuffer->p_payload - ICMP6_HEADER_SIZE - IPV6_IP_HEADER_SIZE);
- icmp6_header_t * p_icmp_header = (icmp6_header_t *)
- (p_pbuffer->p_payload - ICMP6_HEADER_SIZE);
- ICMP6_MUTEX_UNLOCK();
- // Change byte order of ICMP header given to application.
- p_icmp_header->checksum = NTOHS(p_icmp_header->checksum);
- err_code = m_event_handler(p_interface,
- p_ip_header,
- p_icmp_header,
- process_result,
- p_pbuffer);
- ICMP6_MUTEX_LOCK();
- }
- return err_code;
- }
- #endif
- #if (ICMP6_ENABLE_HANDLE_ECHO_REQUEST_TO_APPLICATION == 0)
- /**@brief Function for responding on ECHO REQUEST message.
- *
- * @param[in] p_interface Pointer to external interface from which packet come.
- * @param[in] p_ip_header Pointer to IPv6 Header.
- * @param[in] p_icmp_header Pointer to ICMPv6 header.
- * @param[in] p_packet Pointer to packet buffer.
- *
- * @return NRF_SUCCESS after successful processing, error otherwise.
- */
- static void echo_reply_send(iot_interface_t * p_interface,
- ipv6_header_t * p_ip_header,
- icmp6_header_t * p_icmp_header,
- iot_pbuffer_t * p_packet)
- {
- uint32_t err_code;
- uint16_t checksum;
- iot_pbuffer_t * p_pbuffer;
- iot_pbuffer_alloc_param_t pbuff_param;
- // Headers of new packet.
- ipv6_header_t * p_reply_ip_header;
- icmp6_header_t * p_reply_icmp_header;
- ICMP6_TRC("Sending reply on Echo Request.");
- // Requesting buffer for reply
- pbuff_param.flags = PBUFFER_FLAG_DEFAULT;
- pbuff_param.type = ICMP6_PACKET_TYPE;
- pbuff_param.length = p_packet->length;
- err_code = iot_pbuffer_allocate(&pbuff_param, &p_pbuffer);
- if (err_code == NRF_SUCCESS)
- {
- p_reply_ip_header = (ipv6_header_t *)(p_pbuffer->p_payload - ICMP6_HEADER_SIZE -
- IPV6_IP_HEADER_SIZE);
- p_reply_icmp_header = (icmp6_header_t *)(p_pbuffer->p_payload - ICMP6_HEADER_SIZE);
- // Change ICMP header.
- p_reply_icmp_header->type = ICMP6_TYPE_ECHO_REPLY;
- p_reply_icmp_header->code = 0;
- p_reply_icmp_header->checksum = 0;
- // IPv6 Header initialization.
- icmp_ip_header(p_reply_ip_header, IPV6_DEFAULT_HOP_LIMIT);
- p_reply_ip_header->destaddr = p_ip_header->srcaddr;
- p_reply_ip_header->length = HTONS(p_pbuffer->length + ICMP6_HEADER_SIZE);
- if (IPV6_ADDRESS_IS_MULTICAST(&p_ip_header->destaddr))
- {
- IPV6_CREATE_LINK_LOCAL_FROM_EUI64(&p_reply_ip_header->srcaddr,
- p_interface->local_addr.identifier);
- }
- else
- {
- p_reply_ip_header->srcaddr = p_ip_header->destaddr;
- }
- // Set echo reply parameters.
- p_reply_icmp_header->sp.echo.id = p_icmp_header->sp.echo.id;
- p_reply_icmp_header->sp.echo.sequence = p_icmp_header->sp.echo.sequence;
- // Copy user data.
- memcpy(p_pbuffer->p_payload,
- p_packet->p_payload,
- p_packet->length);
- // Calculate checksum.
- checksum = p_pbuffer->length + ICMP6_HEADER_SIZE + IPV6_NEXT_HEADER_ICMP6;
- ipv6_checksum_calculate(p_reply_ip_header->srcaddr.u8, IPV6_ADDR_SIZE, &checksum, false);
- ipv6_checksum_calculate(p_reply_ip_header->destaddr.u8, IPV6_ADDR_SIZE, &checksum, false);
- ipv6_checksum_calculate(p_pbuffer->p_payload - ICMP6_HEADER_SIZE,
- p_pbuffer->length + ICMP6_HEADER_SIZE,
- &checksum,
- false);
- p_reply_icmp_header->checksum = HTONS((~checksum));
- p_pbuffer->p_payload -= ICMP6_OFFSET;
- p_pbuffer->length += ICMP6_OFFSET;
- // Send IPv6 packet.
- err_code = ipv6_send(p_interface, p_pbuffer);
- if (err_code != NRF_SUCCESS)
- {
- ICMP6_ERR("Cannot send packet buffer!");
- }
- }
- else
- {
- ICMP6_ERR("Failed to allocate packet buffer!");
- }
- }
- #endif
- /**@brief Function for responding on Neighbor Advertisement message.
- *
- * @param[in] p_interface Pointer to external interface from which packet come.
- * @param[in] p_ip_header Pointer to IPv6 Header.
- * @param[in] p_icmp_header Pointer to ICMPv6 header.
- * @param[in] p_target_addr Pointer to the IPv6 address.
- *
- * @return NRF_SUCCESS after successful processing, error otherwise.
- */
- static uint32_t na_send(iot_interface_t * p_interface,
- ipv6_header_t * p_ip_header,
- icmp6_header_t * p_icmp_header,
- ipv6_addr_t * p_target_addr)
- {
- uint32_t err_code;
- uint16_t checksum;
- iot_pbuffer_t * p_pbuffer;
- iot_pbuffer_alloc_param_t pbuff_param;
- // Headers of new packet.
- ipv6_header_t * p_reply_ip_header;
- icmp6_header_t * p_reply_icmp_header;
- icmp6_na_header_t * p_reply_na_header;
- nd_option_tllao_t * p_reply_opt_tllao_header;
- ICMP6_TRC("Sending reply on Neighbor Solocitation.");
- // Requesting buffer for reply
- pbuff_param.flags = PBUFFER_FLAG_DEFAULT;
- pbuff_param.type = ICMP6_PACKET_TYPE;
- pbuff_param.length = ND_NA_HEADER_SIZE + ND_OPT_TLLAO_SIZE - ND_PAYLOAD_ADJUST_OFFSET;
- err_code = iot_pbuffer_allocate(&pbuff_param, &p_pbuffer);
- if (err_code == NRF_SUCCESS)
- {
- p_reply_ip_header = (ipv6_header_t *)(p_pbuffer->p_payload - ICMP6_HEADER_SIZE -
- IPV6_IP_HEADER_SIZE);
- p_reply_icmp_header = (icmp6_header_t *)(p_pbuffer->p_payload - ICMP6_HEADER_SIZE);
- p_pbuffer->p_payload -= ND_PAYLOAD_ADJUST_OFFSET;
- p_reply_na_header = (icmp6_na_header_t *)(p_pbuffer->p_payload);
- p_reply_opt_tllao_header = (nd_option_tllao_t *)(p_pbuffer->p_payload + ND_NA_HEADER_SIZE);
- p_pbuffer->p_payload += ND_PAYLOAD_ADJUST_OFFSET;
- // Change ICMP header.
- p_reply_icmp_header->type = ICMP6_TYPE_NEIGHBOR_ADVERTISEMENT;
- p_reply_icmp_header->code = 0;
- p_reply_icmp_header->checksum = 0;
- // IPv6 Header initialization.
- icmp_ip_header(p_reply_ip_header, ND_HOP_LIMIT);
- p_reply_ip_header->srcaddr = *p_target_addr;
- p_reply_ip_header->destaddr = p_ip_header->srcaddr;
- p_reply_ip_header->length = HTONS(p_pbuffer->length + ICMP6_HEADER_SIZE);
- p_reply_na_header->flags = ND_NA_S_FLAG | ND_NA_O_FLAG ;
- p_reply_na_header->reserved = 0;
- p_reply_na_header->target_addr = *p_target_addr;
- // Add TLLAO option.
- add_tllao_opt(p_interface, p_reply_opt_tllao_header);
- // Calculate checksum.
- checksum = p_pbuffer->length + ICMP6_HEADER_SIZE + IPV6_NEXT_HEADER_ICMP6;
- ipv6_checksum_calculate(p_reply_ip_header->srcaddr.u8, IPV6_ADDR_SIZE, &checksum, false);
- ipv6_checksum_calculate(p_reply_ip_header->destaddr.u8, IPV6_ADDR_SIZE, &checksum, false);
- ipv6_checksum_calculate(p_pbuffer->p_payload - ICMP6_HEADER_SIZE,
- p_pbuffer->length + ICMP6_HEADER_SIZE,
- &checksum,
- false);
- p_reply_icmp_header->checksum = HTONS((~checksum));
- p_pbuffer->p_payload -= ICMP6_OFFSET;
- p_pbuffer->length += ICMP6_OFFSET;
- // Send IPv6 packet.
- err_code = ipv6_send(p_interface, p_pbuffer);
- if (err_code != NRF_SUCCESS)
- {
- ICMP6_ERR("Cannot send packet buffer!");
- }
- }
- else
- {
- ICMP6_ERR("Failed to allocate packet buffer!\r\n");
- }
- return err_code;
- }
- /**@brief Function for parsing Neighbor Solicitation message.
- *
- * @param[in] p_interface Pointer to external interface from which packet come.
- * @param[in] p_ip_header Pointer to IPv6 Header.
- * @param[in] p_icmp_header Pointer to ICMPv6 header.
- * @param[in] p_packet Pointer to packet buffer.
- *
- * @return NRF_SUCCESS after successful processing, error otherwise.
- */
- static uint32_t ns_input(iot_interface_t * p_interface,
- ipv6_header_t * p_ip_header,
- icmp6_header_t * p_icmp_header,
- iot_pbuffer_t * p_packet)
- {
- uint32_t err_code = NRF_SUCCESS;
- // Read target address.
- icmp6_ns_header_t * p_ns_header = (icmp6_ns_header_t *)p_packet->p_payload;
- if (ipv6_address_check(p_interface, &p_ns_header->target_addr) == NRF_SUCCESS)
- {
- err_code = na_send(p_interface, p_ip_header, p_icmp_header, &p_ns_header->target_addr);
- }
- return err_code;
- }
- /**@brief Function for parsing Router Advertisement message.
- * Because stack gives all control to application, internal RA parsing take care
- * only on Context Identifier.
- *
- * @param[in] p_interface Pointer to external interface from which packet come.
- * @param[in] p_ip_header Pointer to IPv6 Header.
- * @param[in] p_icmp_header Pointer to ICMPv6 header.
- * @param[in] p_packet Pointer to packet buffer.
- *
- * @return NRF_SUCCESS after successful processing, error otherwise.
- */
- static uint32_t ra_input(iot_interface_t * p_interface,
- ipv6_header_t * p_ip_header,
- icmp6_header_t * p_icmp_header,
- iot_pbuffer_t * p_packet)
- {
- uint32_t err_code;
- iot_context_t context;
- iot_context_t * p_context;
- uint16_t curr_opt_offset = ND_RA_HEADER_SIZE;
- nd_option_t * p_opt = NULL;
- nd_option_6co_t * p_6co = NULL;
- nd_option_pio_t * p_pio = NULL;
- if (!IPV6_ADDRESS_IS_LINK_LOCAL(&p_ip_header->srcaddr))
- {
- return ICMP6_INVALID_PACKET_DATA;
- }
- // Read all option we get.
- while (curr_opt_offset < p_packet->length)
- {
- p_opt = (nd_option_t *)(p_packet->p_payload + curr_opt_offset);
- if (p_opt->length == 0)
- {
- ICMP6_ERR("Invalid zero length option!");
- return ICMP6_INVALID_PACKET_DATA;
- }
- ICMP6_TRC("Option type = 0x%02x!", p_opt->type);
- // Searching for handling options.
- switch (p_opt->type)
- {
- case ND_OPT_TYPE_PIO:
- {
- p_pio = (nd_option_pio_t *)p_opt;
- if (p_pio->prefix_length != 0 &&
- (p_pio->flags & ND_OPT_PIO_A_MASK) &&
- !(p_pio->flags & ND_OPT_PIO_L_MASK))
- {
- // Ignore Link-Local address
- if (IPV6_ADDRESS_IS_LINK_LOCAL(&p_pio->prefix))
- {
- ICMP6_ERR("Ignore Link-Local prefix!");
- break;
- }
- // For now address is automatically set as a preferred.
- ipv6_addr_conf_t temp_address;
- // Set IPv6 EUI-64
- IPV6_CREATE_LINK_LOCAL_FROM_EUI64(&temp_address.addr,
- p_interface->local_addr.identifier);
- // Add prefix
- IPV6_ADDRESS_PREFIX_SET(temp_address.addr.u8,
- p_pio->prefix.u8,
- p_pio->prefix_length);
- if (p_pio->valid_lifetime != 0)
- {
- temp_address.state = IPV6_ADDR_STATE_PREFERRED;
- err_code = ipv6_address_set(p_interface, &temp_address);
- if (err_code != NRF_SUCCESS)
- {
- ICMP6_ERR("Cannot add new address! Address table full!");
- }
- }
- else
- {
- err_code = ipv6_address_remove(p_interface, &temp_address.addr);
- if (err_code != NRF_SUCCESS)
- {
- ICMP6_ERR("Cannot remove address!");
- }
- }
- }
- else
- {
- ICMP6_ERR("Prefix option has incorrect parameters!");
- return ICMP6_INVALID_PACKET_DATA;
- }
- break;
- }
- case ND_OPT_TYPE_6CO:
- {
- p_6co = (nd_option_6co_t *)p_opt;
- memset(context.prefix.u8, 0, IPV6_ADDR_SIZE);
- context.prefix = p_6co->context;
- context.prefix_len = p_6co->context_length;
- context.context_id = (p_6co->CID_C & ND_OPT_6CO_CID_MASK) >>
- ND_OPT_6CO_CID_POS;
- context.compression_flag = (p_6co->CID_C & ND_OPT_6CO_C_MASK) >>
- ND_OPT_6CO_C_POS;
- if (p_6co->valid_lifetime == 0)
- {
- err_code = iot_context_manager_get_by_cid(p_interface,
- context.context_id,
- &p_context);
- if (err_code == NRF_SUCCESS)
- {
- err_code = iot_context_manager_remove(p_interface, p_context);
- if (err_code == NRF_SUCCESS)
- {
- ICMP6_TRC("Removed context! CID = 0x%02x", context.context_id);
- }
- }
- }
- else
- {
- err_code = iot_context_manager_update(p_interface, &context);
- if (err_code == NRF_SUCCESS)
- {
- ICMP6_TRC("New context added! CID = 0x%02x", context.context_id);
- }
- }
- break;
- }
- }
- // Increment current offset option.
- curr_opt_offset += 8 * p_opt->length;
- }
- return NRF_SUCCESS;
- }
- /**@brief Function for notifying application of the ICMPv6 received packet.
- *
- * @param[in] p_interface Pointer to external interface from which packet come.
- * @param[in] p_ip_header Pointer to IPv6 Header.
- * @param[in] p_icmp_header Pointer to ICMPv6 header.
- * @param[in] p_packet Pointer to packet buffer.
- *
- * @return NRF_SUCCESS after successful processing, error otherwise.
- */
- static uint32_t ndisc_input(iot_interface_t * p_interface,
- ipv6_header_t * p_ip_header,
- icmp6_header_t * p_icmp_header,
- iot_pbuffer_t * p_packet)
- {
- uint32_t process_result;
- switch (p_icmp_header->type)
- {
- case ICMP6_TYPE_ROUTER_SOLICITATION:
- ICMP6_ERR("Got unsupported Router Solicitation message.");
- process_result = ICMP6_UNHANDLED_PACKET_TYPE;
- break;
- case ICMP6_TYPE_ROUTER_ADVERTISEMENT:
- ICMP6_TRC("Got Router Advertisement message.");
- process_result = ra_input(p_interface, p_ip_header, p_icmp_header, p_packet);
- break;
- case ICMP6_TYPE_NEIGHBOR_SOLICITATION:
- ICMP6_TRC("Got Neighbour Solicitation message.");
- process_result = ns_input(p_interface, p_ip_header, p_icmp_header, p_packet);
- break;
- case ICMP6_TYPE_NEIGHBOR_ADVERTISEMENT:
- ICMP6_TRC("Got Neighbour Advertisement message.");
- process_result = NRF_SUCCESS;
- break;
- default:
- process_result = ICMP6_UNHANDLED_PACKET_TYPE;
- break;
- }
- return process_result;
- }
- uint32_t icmp6_error_message(const iot_interface_t * p_interface,
- const ipv6_addr_t * p_src_addr,
- const ipv6_addr_t * p_dest_addr,
- const icmp6_error_message_param_t * p_param)
- {
- VERIFY_MODULE_IS_INITIALIZED();
- NULL_PARAM_CHECK(p_interface);
- NULL_PARAM_CHECK(p_src_addr);
- NULL_PARAM_CHECK(p_dest_addr);
- NULL_PARAM_CHECK(p_param);
- NULL_PARAM_CHECK(p_param->p_packet);
- ICMP6_MUTEX_LOCK();
- ICMP6_ENTRY();
- iot_pbuffer_t * p_pbuffer;
- ipv6_header_t * p_ip_header;
- icmp6_header_t * p_icmp_header;
- iot_pbuffer_alloc_param_t pbuff_param;
- uint16_t checksum;
- uint32_t err_code = NRF_SUCCESS;
- const uint32_t error_packet_length =
- (MIN(p_param->packet_len,
- ICMP6_ERROR_MESSAGE_MAX_SIZE - ICMP6_HEADER_SIZE));
- // Requesting buffer for error message.
- pbuff_param.flags = PBUFFER_FLAG_DEFAULT;
- pbuff_param.type = ICMP6_PACKET_TYPE;
- pbuff_param.length = error_packet_length;
- err_code = iot_pbuffer_allocate(&pbuff_param, &p_pbuffer);
- if (err_code == NRF_SUCCESS)
- {
- p_ip_header = (ipv6_header_t *)(p_pbuffer->p_payload - ICMP6_HEADER_SIZE -
- IPV6_IP_HEADER_SIZE);
- p_icmp_header = (icmp6_header_t *)(p_pbuffer->p_payload - ICMP6_HEADER_SIZE);
- // Change ICMP header.
- p_icmp_header->type = p_param->type;
- p_icmp_header->code = p_param->code;
- p_icmp_header->checksum = 0;
- switch (p_param->type)
- {
- case ICMP6_TYPE_PACKET_TOO_LONG:
- {
- p_icmp_header->sp.mtu = HTONL(p_param->error_field.mtu);
- break;
- }
- case ICMP6_TYPE_PARAMETER_PROBLEM:
- {
- p_icmp_header->sp.offset = HTONL(p_param->error_field.offset);
- break;
- }
- default:
- {
- p_icmp_header->sp.unused = 0;
- break;
- }
- }
- // IPv6 Header initialization.
- icmp_ip_header(p_ip_header, IPV6_DEFAULT_HOP_LIMIT);
- p_ip_header->srcaddr = *p_src_addr;
- p_ip_header->destaddr = *p_dest_addr;
- p_ip_header->length = HTONS(p_pbuffer->length + ICMP6_HEADER_SIZE);
- memcpy(p_pbuffer->p_payload, p_param->p_packet, error_packet_length);
- // Calculate checksum.
- checksum = error_packet_length + IPV6_NEXT_HEADER_ICMP6;
- ipv6_checksum_calculate(p_ip_header->srcaddr.u8, IPV6_ADDR_SIZE, &checksum, false);
- ipv6_checksum_calculate(p_ip_header->destaddr.u8, IPV6_ADDR_SIZE, &checksum, false);
- ipv6_checksum_calculate(p_pbuffer->p_payload - ICMP6_HEADER_SIZE,
- p_pbuffer->length + ICMP6_HEADER_SIZE,
- &checksum,
- false);
- // Update checksum in the packet.
- p_icmp_header->checksum = HTONS((~checksum));
- p_pbuffer->p_payload -= ICMP6_OFFSET;
- p_pbuffer->length += ICMP6_OFFSET;
- // Send IPv6 packet.
- err_code = ipv6_send(p_interface, p_pbuffer);
- }
- ICMP6_EXIT();
- ICMP6_MUTEX_UNLOCK();
- return err_code;
- }
- uint32_t icmp6_echo_request(const iot_interface_t * p_interface,
- const ipv6_addr_t * p_src_addr,
- const ipv6_addr_t * p_dest_addr,
- iot_pbuffer_t * p_request)
- {
- VERIFY_MODULE_IS_INITIALIZED();
- NULL_PARAM_CHECK(p_interface);
- NULL_PARAM_CHECK(p_src_addr);
- NULL_PARAM_CHECK(p_dest_addr);
- NULL_PARAM_CHECK(p_request);
- PACKET_TYPE_CHECK(p_request);
- uint32_t err_code = NRF_SUCCESS;
- uint16_t checksum;
- ipv6_header_t * p_ip_header;
- icmp6_header_t * p_icmp_header;
- ICMP6_MUTEX_LOCK();
- ICMP6_ENTRY();
- // Headers of IPv6 packet.
- p_ip_header = (ipv6_header_t *)(p_request->p_payload - ICMP6_HEADER_SIZE -
- IPV6_IP_HEADER_SIZE);
- p_icmp_header = (icmp6_header_t *)(p_request->p_payload - ICMP6_HEADER_SIZE);
- // Change ICMP header.
- p_icmp_header->type = ICMP6_TYPE_ECHO_REQUEST;
- p_icmp_header->code = 0;
- p_icmp_header->checksum = 0;
- // IPv6 Header initialization.
- icmp_ip_header(p_ip_header, IPV6_DEFAULT_HOP_LIMIT);
- p_ip_header->srcaddr = *p_src_addr;
- p_ip_header->destaddr = *p_dest_addr;
- p_ip_header->length = HTONS(p_request->length + ICMP6_HEADER_SIZE);
- // Set echo reply parameters.
- p_icmp_header->sp.echo.id = 0;
- p_icmp_header->sp.echo.sequence = HTONS(m_sequence_number);
- // Calculate checksum.
- checksum = p_request->length + ICMP6_HEADER_SIZE + IPV6_NEXT_HEADER_ICMP6;
- ipv6_checksum_calculate(p_ip_header->srcaddr.u8, IPV6_ADDR_SIZE, &checksum, false);
- ipv6_checksum_calculate(p_ip_header->destaddr.u8, IPV6_ADDR_SIZE, &checksum, false);
- ipv6_checksum_calculate(p_request->p_payload - ICMP6_HEADER_SIZE,
- p_request->length + ICMP6_HEADER_SIZE,
- &checksum,
- false);
- p_icmp_header->checksum = HTONS((~checksum));
- m_sequence_number++;
- p_request->p_payload -= ICMP6_OFFSET;
- p_request->length += ICMP6_OFFSET;
- // Send IPv6 packet.
- err_code = ipv6_send(p_interface, p_request);
- ICMP6_EXIT();
- ICMP6_MUTEX_UNLOCK();
- return err_code;
- }
- uint32_t icmp6_rs_send(const iot_interface_t * p_interface,
- const ipv6_addr_t * p_src_addr,
- const ipv6_addr_t * p_dest_addr)
- {
- VERIFY_MODULE_IS_INITIALIZED();
- NULL_PARAM_CHECK(p_interface);
- NULL_PARAM_CHECK(p_src_addr);
- NULL_PARAM_CHECK(p_dest_addr);
- uint32_t err_code = NRF_SUCCESS;
- uint16_t checksum;
- iot_pbuffer_t * p_pbuffer;
- iot_pbuffer_alloc_param_t pbuff_param;
- // IPv6 Headers.
- ipv6_header_t * p_ip_header;
- icmp6_header_t * p_icmp_header;
- icmp6_rs_header_t * p_rs_header;
- nd_option_sllao_t * p_sllao_opt;
- ICMP6_MUTEX_LOCK();
- ICMP6_ENTRY();
- // Requesting buffer for RS message
- pbuff_param.flags = PBUFFER_FLAG_DEFAULT;
- pbuff_param.type = ICMP6_PACKET_TYPE;
- pbuff_param.length = ND_OPT_SLLAO_SIZE;
- err_code = iot_pbuffer_allocate(&pbuff_param, &p_pbuffer);
- if (err_code == NRF_SUCCESS)
- {
- p_ip_header = (ipv6_header_t *)(p_pbuffer->p_payload - ICMP6_HEADER_SIZE -
- IPV6_IP_HEADER_SIZE);
- p_icmp_header = (icmp6_header_t *)(p_pbuffer->p_payload - ICMP6_HEADER_SIZE);
- p_rs_header = (icmp6_rs_header_t *)(&p_icmp_header->sp.unused);
- p_sllao_opt = (nd_option_sllao_t *)(p_pbuffer->p_payload);
- // Change ICMP header.
- p_icmp_header->type = ICMP6_TYPE_ROUTER_SOLICITATION;
- p_icmp_header->code = 0;
- p_icmp_header->checksum = 0;
- // IPv6 Header initialization.
- icmp_ip_header(p_ip_header, ND_HOP_LIMIT);
- p_ip_header->srcaddr = *p_src_addr;
- p_ip_header->destaddr = *p_dest_addr;
- p_ip_header->length = HTONS(p_pbuffer->length + ICMP6_HEADER_SIZE);
- // Set Router Solicitation parameter.
- p_rs_header->reserved = 0;
- // Add SLLAO option.
- add_sllao_opt(p_interface, p_sllao_opt);
- // Calculate checksum.
- checksum = p_pbuffer->length + ICMP6_HEADER_SIZE + IPV6_NEXT_HEADER_ICMP6;
- ipv6_checksum_calculate(p_ip_header->srcaddr.u8, IPV6_ADDR_SIZE, &checksum, false);
- ipv6_checksum_calculate(p_ip_header->destaddr.u8, IPV6_ADDR_SIZE, &checksum, false);
- ipv6_checksum_calculate(p_pbuffer->p_payload - ICMP6_HEADER_SIZE,
- p_pbuffer->length + ICMP6_HEADER_SIZE,
- &checksum,
- false);
- p_icmp_header->checksum = HTONS((~checksum));
- p_pbuffer->p_payload -= ICMP6_OFFSET;
- p_pbuffer->length += ICMP6_OFFSET;
- // Send IPv6 packet.
- err_code = ipv6_send(p_interface, p_pbuffer);
- }
- else
- {
- ICMP6_ERR("Failed to allocate packet buffer!");
- }
- ICMP6_EXIT();
- ICMP6_MUTEX_UNLOCK();
- return err_code;
- }
- uint32_t icmp6_ns_send(const iot_interface_t * p_interface,
- const ipv6_addr_t * p_src_addr,
- const ipv6_addr_t * p_dest_addr,
- const icmp6_ns_param_t * p_param)
- {
- VERIFY_MODULE_IS_INITIALIZED();
- NULL_PARAM_CHECK(p_interface);
- NULL_PARAM_CHECK(p_src_addr);
- NULL_PARAM_CHECK(p_dest_addr);
- NULL_PARAM_CHECK(p_param);
- uint32_t err_code = NRF_SUCCESS;
- uint16_t aro_size = 0;
- uint16_t checksum;
- iot_pbuffer_t * p_pbuffer;
- iot_pbuffer_alloc_param_t pbuff_param;
- // IPv6 Headers.
- ipv6_header_t * p_ip_header;
- icmp6_header_t * p_icmp_header;
- icmp6_ns_header_t * p_ns_header;
- nd_option_sllao_t * p_sllao_opt;
- nd_option_aro_t * p_aro_opt;
- ICMP6_MUTEX_LOCK();
- ICMP6_ENTRY();
- if (p_param->add_aro)
- {
- aro_size = ND_OPT_ARO_SIZE;
- }
- // Requesting buffer for NS message
- pbuff_param.flags = PBUFFER_FLAG_DEFAULT;
- pbuff_param.type = ICMP6_PACKET_TYPE;
- pbuff_param.length = ND_NS_HEADER_SIZE + ND_OPT_SLLAO_SIZE + \
- aro_size - ND_PAYLOAD_ADJUST_OFFSET;
- err_code = iot_pbuffer_allocate(&pbuff_param, &p_pbuffer);
- if (err_code == NRF_SUCCESS)
- {
- p_ip_header = (ipv6_header_t *)(p_pbuffer->p_payload - ICMP6_HEADER_SIZE -
- IPV6_IP_HEADER_SIZE);
- p_icmp_header = (icmp6_header_t *)(p_pbuffer->p_payload - ICMP6_HEADER_SIZE);
- p_pbuffer->p_payload -= ND_PAYLOAD_ADJUST_OFFSET;
- p_ns_header = (icmp6_ns_header_t *)(p_pbuffer->p_payload);
- p_sllao_opt = (nd_option_sllao_t *)(p_pbuffer->p_payload + ND_NS_HEADER_SIZE);
- p_aro_opt = (nd_option_aro_t *)(p_pbuffer->p_payload + ND_NS_HEADER_SIZE +
- ND_OPT_SLLAO_SIZE);
- p_pbuffer->p_payload += ND_PAYLOAD_ADJUST_OFFSET;
- // Change ICMP header.
- p_icmp_header->type = ICMP6_TYPE_NEIGHBOR_SOLICITATION;
- p_icmp_header->code = 0;
- p_icmp_header->checksum = 0;
- // IPv6 Header initialization.
- icmp_ip_header(p_ip_header, ND_HOP_LIMIT);
- p_ip_header->srcaddr = *p_src_addr;
- p_ip_header->destaddr = *p_dest_addr;
- p_ip_header->length = HTONS(p_pbuffer->length + ICMP6_HEADER_SIZE);
- // Set Neighbour Solicitation parameter.
- p_ns_header->reserved = 0;
- p_ns_header->target_addr = p_param->target_addr;
- // Add SLLAO option.
- add_sllao_opt(p_interface, p_sllao_opt);
- if (p_param->add_aro)
- {
- add_aro_opt(p_interface, p_aro_opt, p_param->aro_lifetime);
- }
- // Calculate checksum.
- checksum = p_pbuffer->length + ICMP6_HEADER_SIZE + IPV6_NEXT_HEADER_ICMP6;
- ipv6_checksum_calculate(p_ip_header->srcaddr.u8, IPV6_ADDR_SIZE, &checksum, false);
- ipv6_checksum_calculate(p_ip_header->destaddr.u8, IPV6_ADDR_SIZE, &checksum, false);
- ipv6_checksum_calculate(p_pbuffer->p_payload - ICMP6_HEADER_SIZE,
- p_pbuffer->length + ICMP6_HEADER_SIZE,
- &checksum,
- false);
- p_icmp_header->checksum = HTONS((~checksum));
- p_pbuffer->p_payload -= ICMP6_OFFSET;
- p_pbuffer->length += ICMP6_OFFSET;
- // Send IPv6 packet.
- err_code = ipv6_send(p_interface, p_pbuffer);
- }
- else
- {
- ICMP6_ERR("Failed to allocate packet buffer!");
- }
- ICMP6_EXIT();
- ICMP6_MUTEX_UNLOCK();
- return err_code;
- }
- uint32_t icmp6_receive_register(icmp6_receive_callback_t cb)
- {
- VERIFY_MODULE_IS_INITIALIZED();
- NULL_PARAM_CHECK(cb);
- UNUSED_VARIABLE(m_event_handler);
- ICMP6_MUTEX_LOCK();
- ICMP6_ENTRY();
- // Store application event handler.
- m_event_handler = cb;
- ICMP6_EXIT();
- ICMP6_MUTEX_UNLOCK();
- return NRF_SUCCESS;
- }
- uint32_t icmp6_init(void)
- {
- SDK_MUTEX_INIT(m_icmp6_mutex);
- ICMP6_MUTEX_LOCK();
- ICMP6_ENTRY();
- // Set application event handler.
- m_event_handler = NULL;
- // Indicate initialization of module.
- m_initialization_state = true;
- ICMP6_EXIT();
- ICMP6_MUTEX_UNLOCK();
- return NRF_SUCCESS;
- }
- uint32_t icmp6_input(iot_interface_t * p_interface,
- ipv6_header_t * p_ip_header,
- iot_pbuffer_t * p_packet)
- {
- VERIFY_MODULE_IS_INITIALIZED();
- NULL_PARAM_CHECK(p_interface);
- NULL_PARAM_CHECK(p_ip_header);
- NULL_PARAM_CHECK(p_packet);
- uint16_t checksum;
- uint32_t process_result = NRF_SUCCESS;
- bool is_ndisc = false;
- icmp6_header_t * p_icmp_header = (icmp6_header_t *)p_packet->p_payload;
- uint32_t err_code = NRF_SUCCESS;
- ICMP6_MUTEX_LOCK();
- ICMP6_ENTRY();
- if (p_packet->length < ICMP6_HEADER_SIZE || p_ip_header->length < ICMP6_HEADER_SIZE)
- {
- ICMP6_ERR("Received malformed packet, which has 0x%08lX bytes.", p_packet->length);
- process_result = ICMP6_MALFORMED_PACKET;
- }
- else
- {
- // Check checksum of packet.
- checksum = p_packet->length + IPV6_NEXT_HEADER_ICMP6;
- ipv6_checksum_calculate(p_ip_header->srcaddr.u8, IPV6_ADDR_SIZE, &checksum, false);
- ipv6_checksum_calculate(p_ip_header->destaddr.u8, IPV6_ADDR_SIZE, &checksum, false);
- ipv6_checksum_calculate(p_packet->p_payload, p_packet->length, &checksum, false);
- checksum = (uint16_t)~checksum;
- // Change pbuffer type.
- p_packet->type = ICMP6_PACKET_TYPE;
- p_packet->p_payload = p_packet->p_payload + ICMP6_HEADER_SIZE;
- p_packet->length -= ICMP6_HEADER_SIZE;
- if (checksum != 0)
- {
- ICMP6_ERR("Bad checksum detected. Got 0x%08x but expected 0x%08x, 0x%08lX",
- NTOHS(p_icmp_header->checksum), checksum, p_packet->length);
- process_result = ICMP6_BAD_CHECKSUM;
- }
- else
- {
- switch (p_icmp_header->type)
- {
- case ICMP6_TYPE_DESTINATION_UNREACHABLE:
- case ICMP6_TYPE_PACKET_TOO_LONG:
- case ICMP6_TYPE_TIME_EXCEED:
- case ICMP6_TYPE_PARAMETER_PROBLEM:
- {
- ICMP6_TRC("Got ICMPv6 error message with type = 0x%08x",
- p_icmp_header->type);
- p_icmp_header->sp.unused = NTOHL(p_icmp_header->sp.unused);
- break;
- }
- case ICMP6_TYPE_ECHO_REQUEST:
- case ICMP6_TYPE_ECHO_REPLY:
- {
- ICMP6_TRC("Got ICMPv6 Echo message with type = 0x%x.", p_icmp_header->type);
- ICMP6_TRC("From IPv6 Address:");
- ICMP6_DUMP(p_ip_header->srcaddr.u32, IPV6_ADDR_SIZE);
- ICMP6_TRC("Identifier: 0x%04x, Sequence Number: 0x%04x",
- NTOHS(p_icmp_header->sp.echo.id),
- NTOHS(p_icmp_header->sp.echo.sequence));
- break;
- }
- case ICMP6_TYPE_ROUTER_SOLICITATION:
- case ICMP6_TYPE_ROUTER_ADVERTISEMENT:
- case ICMP6_TYPE_NEIGHBOR_SOLICITATION:
- case ICMP6_TYPE_NEIGHBOR_ADVERTISEMENT:
- {
- p_packet->p_payload = p_packet->p_payload - ND_PAYLOAD_ADJUST_OFFSET;
- p_packet->length += ND_PAYLOAD_ADJUST_OFFSET;
- process_result = ndisc_input(p_interface,
- p_ip_header,
- p_icmp_header,
- p_packet);
- p_packet->p_payload = p_packet->p_payload + ND_PAYLOAD_ADJUST_OFFSET;
- p_packet->length -= ND_PAYLOAD_ADJUST_OFFSET;
- is_ndisc = true;
- break;
- }
- default:
- process_result = ICMP6_UNHANDLED_PACKET_TYPE;
- break;
- }
- #if (ICMP6_ENABLE_HANDLE_ECHO_REQUEST_TO_APPLICATION == 0)
- if (p_icmp_header->type == ICMP6_TYPE_ECHO_REQUEST)
- {
- echo_reply_send(p_interface, p_ip_header, p_icmp_header, p_packet);
- }
- #endif
- }
- }
- #if (ICMP6_ENABLE_ALL_MESSAGES_TO_APPLICATION == 1)
- err_code = app_notify_icmp_data(p_interface, p_packet, process_result);
- #elif (ICMP6_ENABLE_ND6_MESSAGES_TO_APPLICATION == 1)
- if (is_ndisc)
- {
- err_code = app_notify_icmp_data(p_interface, p_packet, process_result);
- }
- #endif
- ICMP6_EXIT();
- UNUSED_VARIABLE(is_ndisc);
- UNUSED_VARIABLE(process_result);
- ICMP6_MUTEX_UNLOCK();
- return err_code;
- }
|