/**@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; }
/**@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; } }
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; }
/**@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"); } }
/**@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(); }
/**@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; } } }