Exemple #1
0
/**@brief Callback handler to receive data on UDP port.
 *
 * @param[in]   p_socket         Socket identifier.
 * @param[in]   p_ip_header      IPv6 header containing source and destination addresses.
 * @param[in]   p_udp_header     UDP header identifying local and remote endpoints.
 * @param[in]   process_result   Result of data reception, there could be possible errors like
 *                               invalid checksum etc.
 * @param[in]   iot_pbuffer_t    Packet buffer containing the received data packet.
 *
 * @retval      NRF_SUCCESS      Indicates received data was handled successfully, else an error
 *                               code indicating reason for failure.
 */
uint32_t rx_udp_port_app_handler(const udp6_socket_t * p_socket,
                                 const ipv6_header_t * p_ip_header,
                                 const udp6_header_t * p_udp_header,
                                 uint32_t              process_result,
                                 iot_pbuffer_t       * p_rx_packet)
{
    // APPL_LOG("[APPL]: Got UDP6 data on socket 0x%08lx\r\n", p_socket->socket_id);
    // APPL_LOG("[APPL]: Source IPv6 Address: ");
    // APPL_ADDR(p_ip_header->srcaddr);

    APP_ERROR_CHECK(process_result);

    // Print PORTs
    // APPL_LOG("[APPL]: UDP Destination port: %lx\r\n", HTONS(p_udp_header->destport));
    // APPL_LOG("[APPL]: UDP Source port: %lx\r\n",      HTONS(p_udp_header->srcport));

    // UDP packet received from the Client node.
    APPL_LOG("[APPL]: Received UDP packet sequence number: %ld\r\n", \
             uint32_decode(&p_rx_packet->p_payload[0]));

    iot_pbuffer_alloc_param_t   pbuff_param;
    iot_pbuffer_t             * p_tx_buffer;

    pbuff_param.flags  = PBUFFER_FLAG_DEFAULT;
    pbuff_param.type   = UDP6_PACKET_TYPE;
    pbuff_param.length = p_rx_packet->length;

    // Allocate packet buffer.
    uint32_t err_code = iot_pbuffer_allocate(&pbuff_param, &p_tx_buffer);
    APP_ERROR_CHECK(err_code);

    memcpy(p_tx_buffer->p_payload, p_rx_packet->p_payload, p_rx_packet->length);

    // Send back the received packet payload without any modification. 
    err_code = udp6_socket_sendto(&m_udp_socket, &p_ip_header->srcaddr, HTONS(UDP_PORT), p_tx_buffer);
    APP_ERROR_CHECK(err_code);

    m_display_state  = LEDS_TX_UDP_PACKET;
    m_udp_tx_occured = true;

    return NRF_SUCCESS;
}
Exemple #2
0
/**@brief Application state machine used for sending DNS Query and Echo Request.
 *
 * @param[in]   p_context   Pointer used for passing context. No context used in this application.
 */
static void app_fsm(void * p_context)
{
    uint32_t                   err_code;
    iot_pbuffer_t            * p_buffer;
    iot_pbuffer_alloc_param_t  pbuff_param;
    ipv6_addr_t                src_addr;

    switch(m_app_state)
    {
      case APP_STATE_QUERYING:
          APPL_LOG("[APPL]: Application in querying state.\r\n");
          // Set number of retransmission to 0.
          m_echo_req_retry_count = 0;

          // Turn off LED_THREE and LED_FOUR
          LEDS_OFF((LED_THREE | LED_FOUR));

          // Find all IPv6 address corresponds to APP_HOSTNAME domain.
          err_code = dns6_query(APP_HOSTNAME, app_dns_handler);
          APP_ERROR_CHECK(err_code);

          // Change state to resolving.
          m_app_state = APP_STATE_RESOLVING;
        break;
      case APP_STATE_RESOLVING:
          APPL_LOG("[APPL]: Application in resolving state.\r\n");
          // Wait for DNS response.
          break;
      case APP_STATE_PINGING:
          APPL_LOG("[APPL]: Application in pinging state.\r\n");

          if(m_echo_req_retry_count < APP_MAX_ECHO_REQUEST_RTR)
          {
              pbuff_param.flags  = PBUFFER_FLAG_DEFAULT;
              pbuff_param.type   = ICMP6_PACKET_TYPE;
              pbuff_param.length = ICMP6_ECHO_REQUEST_PAYLOAD_OFFSET + 10;

              // Allocate packet buffer.
              err_code = iot_pbuffer_allocate(&pbuff_param, &p_buffer);
              APP_ERROR_CHECK(err_code);

              // Fill payload of Echo Request with 'A' letters.
              memset(p_buffer->p_payload + ICMP6_ECHO_REQUEST_PAYLOAD_OFFSET, 'A', 10);

              // Find proper source address for given destination one.
              err_code = ipv6_address_find_best_match(&mp_interface, &src_addr, &m_hostname_address);
              APP_ERROR_CHECK(err_code);

              // Send Echo Request to all nodes.
              err_code = icmp6_echo_request(mp_interface, &src_addr, &m_hostname_address, p_buffer);
              APP_ERROR_CHECK(err_code);

              // Increase retransmission number.
              m_echo_req_retry_count++;
          }
          else
          {
              APPL_LOG("[APPL]: Failed, no Echo Response received.\r\n");
              // Go to initial state.
              m_app_state = APP_STATE_QUERYING;
          }
          break;
      default:
        break;
    }
}
Exemple #3
0
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_TRC("[ICMP6]: >> icmp6_ndisc_ns_send\r\n");

    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;

    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_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);

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

    ICMP6_TRC("[ICMP6]: << icmp6_ndisc_ns_send\r\n");

    ICMP6_MUTEX_UNLOCK();

    return err_code;
}
Exemple #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");   
    }
}
Exemple #5
0
/**@brief Function for receiving 6LoWPAN module events.
 *
 * @param[in]   p_6lo_interface  Pointer to 6LoWPAN interface.
 * @param[in]   p_6lo_event      Pointer to 6LoWPAN related event.
 *
 * @return      None.
 */
static void ble_6lowpan_evt_handler(iot_interface_t     * p_interface,
                                    ble_6lowpan_event_t * p_6lo_event)
{
    bool                        rx_failure = false;
    uint32_t                    err_code;
    uint32_t                    interface_id;
    iot_pbuffer_t             * p_pbuffer;
    iot_pbuffer_alloc_param_t   pbuff_param;

    IPV6_MUTEX_LOCK();

    IPV6_ENTRY();
    IPV6_TRC("In 6LoWPAN Handler:");

    interface_id = interface_get_by_6lo(p_interface);

    switch (p_6lo_event->event_id)
    {
        case BLE_6LO_EVT_ERROR:
        {
            IPV6_ERR("Got error, with result %08lx", p_6lo_event->event_result);
            break;
        }
        case BLE_6LO_EVT_INTERFACE_ADD:
        {
            IPV6_TRC("New interface established!");

            // Add interface to internal table.
            err_code = interface_add(p_interface, &interface_id);

            if (NRF_SUCCESS == err_code)
            {
                IPV6_TRC("Added new network interface to internal table.");

                err_code = iot_context_manager_table_alloc(p_interface);

                if (err_code == NRF_SUCCESS)
                {
                    IPV6_TRC("Successfully allocated context table!");
                }
                else
                {
                    IPV6_ERR("Failed to allocate context table!");
                }

                // Increase number of up interfaces.
                m_interfaces_count++;

                // Notify application.
                app_notify_interface_add(p_interface);
            }
            else
            {
                IPV6_ERR("Cannot add new interface. Table is full.");
            }

            break;
        }
        case BLE_6LO_EVT_INTERFACE_DELETE:
        {
            IPV6_TRC("Interface disconnected!");

            if (interface_id < IPV6_MAX_INTERFACE)
            {
                IPV6_TRC("Removed network interface.");

                // Notify application.
                app_notify_interface_delete(p_interface);

                err_code = iot_context_manager_table_free(p_interface);

                if (err_code == NRF_SUCCESS)
                {
                    IPV6_TRC("Successfully freed context table!");
                }

                // Decrease number of up interfaces.
                m_interfaces_count--;

                // Remove interface from internal table.
                interface_delete(interface_id);
            }
            break;
        }
        case BLE_6LO_EVT_INTERFACE_DATA_RX:
        {
            IPV6_TRC("Got data with size = %d!",
                     p_6lo_event->event_param.rx_event_param.packet_len);
            IPV6_TRC("Data: ");
            IPV6_DUMP(p_6lo_event->event_param.rx_event_param.p_packet,
                      p_6lo_event->event_param.rx_event_param.packet_len);

            if (interface_id < IPV6_MAX_INTERFACE)
            {
                if (p_6lo_event->event_result == NRF_ERROR_NOT_FOUND)
                {
                    IPV6_ERR("Cannot restore IPv6 addresses!");
                    IPV6_ERR("Source CID = 0x%x, Destination CID = 0x%x",
                             p_6lo_event->event_param.rx_event_param.rx_contexts.src_cntxt_id,
                             p_6lo_event->event_param.rx_event_param.rx_contexts.dest_cntxt_id);

                    // Indicates failure.
                    rx_failure = true;
                    break;
                }

                // Check if packet is for us.
                ipv6_addr_t * p_addr =
                  (ipv6_addr_t *)&p_6lo_event->event_param.rx_event_param.p_packet[DEST_ADDR_OFFSET];

                err_code = addr_check(interface_id, p_addr, true);

                // If no address found - drop message.
                if (err_code != NRF_SUCCESS)
                {
                    IPV6_ERR("Packet received on unknown address!");
                    rx_failure = true;
                    break;
                }

                // Try to allocate pbuffer, with no memory.
                pbuff_param.flags  = PBUFFER_FLAG_NO_MEM_ALLOCATION;
                pbuff_param.type   = RAW_PACKET_TYPE;
                pbuff_param.length = p_6lo_event->event_param.rx_event_param.packet_len;

                // Try to allocate pbuffer for receiving data.
                err_code = iot_pbuffer_allocate(&pbuff_param, &p_pbuffer);

                if (err_code == NRF_SUCCESS)
                {
                    p_pbuffer->p_memory  = p_6lo_event->event_param.rx_event_param.p_packet;
                    p_pbuffer->p_payload = p_pbuffer->p_memory + IPV6_IP_HEADER_SIZE;
                    p_pbuffer->length   -= IPV6_IP_HEADER_SIZE;

                    // Execute multiplexer.
                    err_code = ipv6_input(p_interface, p_pbuffer);

                    if (err_code != NRF_SUCCESS)
                    {
                        IPV6_ERR("Failed while processing packet, error = 0x%08lX!", err_code);
                    }
                }
                else
                {
                    IPV6_ERR("Failed to allocate packet buffer!");
                    rx_failure = true;
                }
            }
            else
            {
                IPV6_ERR("[6LOWPAN]: Got data to unknown interface!");
                rx_failure = true;
            }

            break;
        }
        default:
            break;
    }

    if (rx_failure == true)
    {
        UNUSED_VARIABLE(nrf_free(p_6lo_event->event_param.rx_event_param.p_packet));
    }

    IPV6_EXIT();

    IPV6_MUTEX_UNLOCK();
}
Exemple #6
0
/**@brief Timer callback used for transmitting Echo Request and UDP6 packets depending on
 *        application state.
 *
 * @param[in]   p_context   Pointer used for passing context. No context used in this application.
 */
static void tx_timeout_handler(void * p_context)
{
    uint32_t err_code;

    switch (m_node_state)
    {
        case APP_STATE_IPV6_IF_DOWN:
        {
            return;
        }
        case APP_STATE_IPV6_IF_UP:
        {
            APPL_LOG("[APPL]: Ping remote node. \r\n");

            iot_pbuffer_alloc_param_t   pbuff_param;
            iot_pbuffer_t             * p_buffer;

            pbuff_param.flags  = PBUFFER_FLAG_DEFAULT;
            pbuff_param.type   = ICMP6_PACKET_TYPE;
            pbuff_param.length = ICMP6_ECHO_REQUEST_PAYLOAD_OFFSET + 10;

            // Allocate packet buffer.
            err_code = iot_pbuffer_allocate(&pbuff_param, &p_buffer);
            APP_ERROR_CHECK(err_code);

            ipv6_addr_t dest_ipv6_addr;
            memcpy(&dest_ipv6_addr.u8[0], (uint8_t[]){SERVER_IPV6_ADDRESS}, IPV6_ADDR_SIZE);

            iot_interface_t * p_interface;
            ipv6_addr_t       src_ipv6_addr;
            err_code = ipv6_address_find_best_match(&p_interface,
                                                    &src_ipv6_addr,
                                                    &dest_ipv6_addr);
            APP_ERROR_CHECK(err_code);

            memset(p_buffer->p_payload + ICMP6_ECHO_REQUEST_PAYLOAD_OFFSET, 'A', 10);

            // Send Echo Request to peer.
            err_code = icmp6_echo_request(p_interface, &src_ipv6_addr, &dest_ipv6_addr, p_buffer);
            APP_ERROR_CHECK(err_code);

            err_code = app_timer_start(m_tx_node_timer, APP_PING_INTERVAL, NULL);
            APP_ERROR_CHECK(err_code);

            break;
        }
        case APP_STATE_PEER_REACHABLE:
        {
            uint32_t ind_buff = 0;
            err_code = get_packet_buffer_index(&ind_buff, (uint32_t *)&m_invalid_pkt_seq_num);
            if (err_code == NRF_ERROR_NOT_FOUND)
            {
                // Buffer of expected packets full, checking if peer is reachable.
                APPL_LOG("[APPL]: %ld packets transmitted, %d packets lost. Resetting counter. \r\n", \
                             m_pkt_seq_num, PACKET_BUFFER_LEN);
                m_node_state    = APP_STATE_IPV6_IF_UP;
                m_display_state = LEDS_TX_ECHO_REQUEST;
                m_pkt_seq_num = 0;
                memset(&m_packet_buffer[0][0], 0x00, sizeof(m_packet_buffer));
                err_code = app_timer_start(m_tx_node_timer, APP_PING_INTERVAL, NULL);
                APP_ERROR_CHECK(err_code);
                return;
            }

            ++m_pkt_seq_num;
            if (m_pkt_seq_num == INVALID_PACKET_SEQ_NUMBER)
            {
                ++m_pkt_seq_num;
            }

            test_packet_payload_t packet;
            uint8_t encoded_seq_num[TEST_PACKET_NUM_LEN];
            UNUSED_VARIABLE(uint32_encode(m_pkt_seq_num, &encoded_seq_num[0]));
            // The first 4 bytes of the payload is the packet sequence number.
            memcpy(&packet.packet_seq_num[0], &encoded_seq_num[0], TEST_PACKET_NUM_LEN);
            // The rest of the payload is random bytes.
            do
            {
                err_code = sd_rand_application_vector_get(&packet.packet_data[0], \
                                                          sizeof(packet.packet_data));
            }
            while (err_code == NRF_ERROR_SOC_RAND_NOT_ENOUGH_VALUES);
            APP_ERROR_CHECK(err_code);

            iot_pbuffer_alloc_param_t   pbuff_param;
            iot_pbuffer_t             * p_buffer;

            pbuff_param.flags  = PBUFFER_FLAG_DEFAULT;
            pbuff_param.type   = UDP6_PACKET_TYPE;
            pbuff_param.length = TEST_PACKET_PAYLOAD_LEN;

            // Allocate packet buffer.
            err_code = iot_pbuffer_allocate(&pbuff_param, &p_buffer);
            APP_ERROR_CHECK(err_code);

            memcpy(p_buffer->p_payload, &packet.packet_seq_num[0], TEST_PACKET_NUM_LEN);
            memcpy(p_buffer->p_payload+TEST_PACKET_NUM_LEN, &packet.packet_data[0], TEST_PACKET_DATA_LEN);

            ipv6_addr_t dest_ipv6_addr;
            memset(&dest_ipv6_addr, 0x00, sizeof(ipv6_addr_t));
            memcpy(&dest_ipv6_addr.u8[0], (uint8_t[]){SERVER_IPV6_ADDRESS}, IPV6_ADDR_SIZE);

            // Transmit UDP6 packet.
            err_code = udp6_socket_sendto(&m_udp_socket, &dest_ipv6_addr, HTONS(UDP_PORT), p_buffer);
            APP_ERROR_CHECK(err_code);

            APPL_LOG("[APPL]: Transmitted UDP packet sequence number: %ld\r\n", m_pkt_seq_num);

            // Store sent packet amongst expected packets.
            memcpy(&m_packet_buffer[ind_buff][0], &packet.packet_seq_num[0], TEST_PACKET_NUM_LEN);
            memcpy(&m_packet_buffer[ind_buff][TEST_PACKET_NUM_LEN], &packet.packet_data[0], TEST_PACKET_DATA_LEN);

            if (m_pkt_seq_num == 1)
            {
                err_code = app_timer_start(m_tx_node_timer, (TX_INTERVAL*5), NULL); // Slow start.
                APP_ERROR_CHECK(err_code);
            }
            else
            {
                err_code = app_timer_start(m_tx_node_timer, TX_INTERVAL, NULL);
                APP_ERROR_CHECK(err_code);
            }

            break;
        }
        default:
        {
            break;
        }
    }
}