Esempio n. 1
0
/**@brief Function for adding new 6lowpan interface to interface table.
 *
 * @param[in]    p_6lo_interface  Pointer to 6LoWPAN interface.
 * @param[out]   p_index          Pointer to index of internal network interface.
 *
 * @return      NRF_SUCCESS on success, otherwise NRF_ERROR_NO_MEM error.
 */
static uint32_t interface_add(iot_interface_t * p_interface,
                              uint32_t        * p_index )
{
    uint32_t         index;
    uint32_t         err_code;
    ipv6_addr_conf_t linklocal_addr;

    for (index = 0; index < IPV6_MAX_INTERFACE; index++)
    {
        if (m_interfaces[index].p_interface == NULL)
        {
            m_interfaces[index].p_interface = p_interface;
            p_interface->p_upper_stack      = (void *) index;
            (*p_index) = index;

            // Add link local address.
            IPV6_CREATE_LINK_LOCAL_FROM_EUI64(&linklocal_addr.addr, p_interface->local_addr.identifier);
            linklocal_addr.state = IPV6_ADDR_STATE_PREFERRED;

            err_code = addr_set(p_interface, &linklocal_addr);
            if (err_code != NRF_SUCCESS)
            {
                IPV6_ERR("Cannot add link-local address to interface!");
            }

            return NRF_SUCCESS;
        }
    }

    return NRF_ERROR_NO_MEM;
}
Esempio n. 2
0
static void ip_app_handler(iot_interface_t * p_interface, ipv6_event_t * p_event)
{
    uint32_t    err_code;
    ipv6_addr_t src_addr;

    APPL_LOG("[APPL]: Got IP Application Handler Event on interface 0x%p\r\n", p_interface);

    switch (p_event->event_id)
    {
        case IPV6_EVT_INTERFACE_ADD:
#ifdef COMMISSIONING_ENABLED
            commissioning_joining_mode_timer_ctrl(JOINING_MODE_TIMER_STOP_RESET);
#endif // COMMISSIONING_ENABLED
            APPL_LOG("[APPL]: New interface added!\r\n");
            mp_interface = p_interface;

            m_display_state = LEDS_IPV6_IF_UP;

            APPL_LOG("[APPL]: Sending Router Solicitation to all routers!\r\n");

            // Create Link Local addresses
            IPV6_CREATE_LINK_LOCAL_FROM_EUI64(&src_addr, p_interface->local_addr.identifier);

            // Delay first solicitation due to possible restriction on other side.
            nrf_delay_ms(APP_RTR_SOLICITATION_DELAY);

            // Send Router Solicitation to all routers.
            err_code = icmp6_rs_send(p_interface,
                                     &src_addr,
                                     &m_local_routers_multicast_addr);
            APP_ERROR_CHECK(err_code);
        break;

        case IPV6_EVT_INTERFACE_DELETE:
#ifdef COMMISSIONING_ENABLED
            commissioning_joining_mode_timer_ctrl(JOINING_MODE_TIMER_START);
#endif // COMMISSIONING_ENABLED
            APPL_LOG("[APPL]: Interface removed!\r\n");
            mp_interface = NULL;

            m_display_state = LEDS_IPV6_IF_DOWN;

            // Stop application state machine timer.
            m_app_state = APP_STATE_IDLE;
            err_code = app_timer_stop(m_app_timer);
            APP_ERROR_CHECK(err_code);
            break;

        case IPV6_EVT_INTERFACE_RX_DATA:
            APPL_LOG("[APPL]: Got unsupported protocol data!\r\n");
            break;

        default:
            // Unknown event. Should not happen.
            break;
    }
}
Esempio n. 3
0
/**@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("[ICMP6]: Option can't has 0 bytes!\r\n"); 
            return ICMP6_INVALID_PACKET_DATA;
        }

        ICMP6_ERR("[ICMP6]: Option type = 0x%02x!\r\n", 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("[ICMP6]: Ignore Link-Local prefix!\r\n");
                        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("[ICMP6]: Cannot add new address! Address table is full!\r\n"); 
                        }
                    }
                    else
                    {
                        err_code = ipv6_address_remove(p_interface, &temp_address.addr);
                        
                        if(err_code != NRF_SUCCESS)
                        {
                            ICMP6_ERR("[ICMP6]: Cannot remove address!\r\n"); 
                        }
                    }
                }
                else
                {
                    ICMP6_ERR("[ICMP6]: Prefix option has incorrect parameters!\r\n"); 
                    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("[ICMP6]: Removed context! CID = 0x%02x\r\n", context.context_id);
                        }
                    }

                }
                else
                {
                    err_code = iot_context_manager_update(p_interface, &context);
                        
                    if(err_code == NRF_SUCCESS)
                    {
                        ICMP6_TRC("[ICMP6]: New context added! CID = 0x%02x\r\n", context.context_id);
                    }
                }

                break;
            }
        }

        // Increment current offset option.
        curr_opt_offset += 8 * p_opt->length;
    }

    return NRF_SUCCESS;
}
Esempio n. 4
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_echo_header_t * p_reply_echo_header;
    icmp6_echo_header_t * p_echo_header = (icmp6_echo_header_t *)(p_packet->p_payload);

    ICMP6_TRC("[ICMP6]: Sending reply on Echo Request.\r\n");

    // 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_reallocate(&pbuff_param, p_pbuffer);
    // This will be available after deciding when freeing received
    // packet. Because when we do reallocate, which cause using same buffer,
    // We can free it before sending procedure occurs!
    // Now we free the memory at the end of ipv6_input.
    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_reply_echo_header = (icmp6_echo_header_t *)(p_pbuffer->p_payload);

        // 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_echo_header->identifier      = p_echo_header->identifier;
        p_reply_echo_header->sequence_number = p_echo_header->sequence_number;

        // Copy user data.       
        memcpy(p_pbuffer->p_payload + ICMP6_ECHO_REQUEST_PAYLOAD_OFFSET,
               p_packet->p_payload  + ICMP6_ECHO_REQUEST_PAYLOAD_OFFSET,
               p_packet->length     - ICMP6_ECHO_REQUEST_PAYLOAD_OFFSET);

        // 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("[ICMP6]: Cannot send packet buffer!\r\n");
        }
    }
    else
    {
        ICMP6_ERR("[ICMP6]: Failed to allocate packet buffer!\r\n");   
    }
}