2022-02-02 10:10:57 -05:00
/*
* SPDX - FileCopyrightText : 2022 Espressif Systems ( Shanghai ) CO LTD
*
* SPDX - License - Identifier : Apache - 2.0
*/
2022-09-29 03:17:13 -04:00
# include <stdio.h>
# include <string.h>
# include <esp_types.h>
2021-09-14 10:30:46 -04:00
# include "freertos/FreeRTOS.h"
# include "freertos/event_groups.h"
# include "test_utils.h"
# include "unity.h"
2022-09-29 03:17:13 -04:00
# include "unity_fixture.h"
# include "soc/soc_caps.h"
2021-09-14 10:30:46 -04:00
# include "lwip/inet.h"
# include "lwip/netdb.h"
# include "lwip/sockets.h"
# include "ping/ping_sock.h"
2022-02-02 10:10:57 -05:00
# include "dhcpserver/dhcpserver.h"
2022-10-27 06:25:00 -04:00
# include "dhcpserver/dhcpserver_options.h"
2022-09-29 08:17:14 -04:00
# include "esp_sntp.h"
2021-09-14 10:30:46 -04:00
# define ETH_PING_END_BIT BIT(1)
# define ETH_PING_DURATION_MS (5000)
# define ETH_PING_END_TIMEOUT_MS (ETH_PING_DURATION_MS * 2)
# define TEST_ICMP_DESTINATION_DOMAIN_NAME "127.0.0.1"
2022-09-29 03:17:13 -04:00
TEST_GROUP ( lwip ) ;
TEST_SETUP ( lwip )
{
}
TEST_TEAR_DOWN ( lwip )
{
}
2021-09-14 10:30:46 -04:00
static void test_on_ping_success ( esp_ping_handle_t hdl , void * args )
{
uint8_t ttl ;
uint16_t seqno ;
uint32_t elapsed_time , recv_len ;
ip_addr_t target_addr ;
esp_ping_get_profile ( hdl , ESP_PING_PROF_SEQNO , & seqno , sizeof ( seqno ) ) ;
esp_ping_get_profile ( hdl , ESP_PING_PROF_TTL , & ttl , sizeof ( ttl ) ) ;
esp_ping_get_profile ( hdl , ESP_PING_PROF_IPADDR , & target_addr , sizeof ( target_addr ) ) ;
esp_ping_get_profile ( hdl , ESP_PING_PROF_SIZE , & recv_len , sizeof ( recv_len ) ) ;
esp_ping_get_profile ( hdl , ESP_PING_PROF_TIMEGAP , & elapsed_time , sizeof ( elapsed_time ) ) ;
2022-09-29 03:17:13 -04:00
printf ( " % " PRId32 " bytes from %s icmp_seq=%d ttl=%d time=% " PRId32 " ms \n " ,
2021-09-14 10:30:46 -04:00
recv_len , inet_ntoa ( target_addr . u_addr . ip4 ) , seqno , ttl , elapsed_time ) ;
}
static void test_on_ping_timeout ( esp_ping_handle_t hdl , void * args )
{
uint16_t seqno ;
ip_addr_t target_addr ;
esp_ping_get_profile ( hdl , ESP_PING_PROF_SEQNO , & seqno , sizeof ( seqno ) ) ;
esp_ping_get_profile ( hdl , ESP_PING_PROF_IPADDR , & target_addr , sizeof ( target_addr ) ) ;
printf ( " From %s icmp_seq=%d timeout \n " , inet_ntoa ( target_addr . u_addr . ip4 ) , seqno ) ;
}
static void test_on_ping_end ( esp_ping_handle_t hdl , void * args )
{
EventGroupHandle_t eth_event_group = ( EventGroupHandle_t ) args ;
uint32_t transmitted ;
uint32_t received ;
uint32_t total_time_ms ;
esp_ping_get_profile ( hdl , ESP_PING_PROF_REQUEST , & transmitted , sizeof ( transmitted ) ) ;
esp_ping_get_profile ( hdl , ESP_PING_PROF_REPLY , & received , sizeof ( received ) ) ;
esp_ping_get_profile ( hdl , ESP_PING_PROF_DURATION , & total_time_ms , sizeof ( total_time_ms ) ) ;
2022-09-29 03:17:13 -04:00
printf ( " % " PRId32 " packets transmitted, % " PRId32 " received, time % " PRId32 " ms \n " , transmitted , received , total_time_ms ) ;
2021-09-14 10:30:46 -04:00
if ( transmitted = = received ) {
xEventGroupSetBits ( eth_event_group , ETH_PING_END_BIT ) ;
}
}
2022-09-29 03:17:13 -04:00
TEST ( lwip , localhost_ping_test )
2021-09-14 10:30:46 -04:00
{
EventBits_t bits ;
EventGroupHandle_t eth_event_group = xEventGroupCreate ( ) ;
TEST_ASSERT ( eth_event_group ! = NULL ) ;
test_case_uses_tcpip ( ) ;
// Parse IP address: Destination is a localhost address, so we don't need any interface (esp-netif/driver)
ip_addr_t target_addr ;
struct addrinfo hint ;
struct addrinfo * res = NULL ;
memset ( & hint , 0 , sizeof ( hint ) ) ;
memset ( & target_addr , 0 , sizeof ( target_addr ) ) ;
/* convert URL to IP */
TEST_ASSERT ( getaddrinfo ( TEST_ICMP_DESTINATION_DOMAIN_NAME , NULL , & hint , & res ) = = 0 ) ;
struct in_addr addr4 = ( ( struct sockaddr_in * ) ( res - > ai_addr ) ) - > sin_addr ;
inet_addr_to_ip4addr ( ip_2_ip4 ( & target_addr ) , & addr4 ) ;
freeaddrinfo ( res ) ;
esp_ping_config_t ping_config = ESP_PING_DEFAULT_CONFIG ( ) ;
ping_config . timeout_ms = 2000 ;
ping_config . target_addr = target_addr ;
ping_config . count = 0 ; // ping in infinite mode
/* set callback functions */
esp_ping_callbacks_t cbs ;
cbs . on_ping_success = test_on_ping_success ;
cbs . on_ping_timeout = test_on_ping_timeout ;
cbs . on_ping_end = test_on_ping_end ;
cbs . cb_args = eth_event_group ;
esp_ping_handle_t ping ;
TEST_ESP_OK ( esp_ping_new_session ( & ping_config , & cbs , & ping ) ) ;
/* start ping */
TEST_ESP_OK ( esp_ping_start ( ping ) ) ;
/* ping for a while */
vTaskDelay ( pdMS_TO_TICKS ( ETH_PING_DURATION_MS ) ) ;
/* stop ping */
TEST_ESP_OK ( esp_ping_stop ( ping ) ) ;
/* wait for end of ping */
bits = xEventGroupWaitBits ( eth_event_group , ETH_PING_END_BIT , true , true , pdMS_TO_TICKS ( ETH_PING_END_TIMEOUT_MS ) ) ;
TEST_ASSERT ( ( bits & ETH_PING_END_BIT ) = = ETH_PING_END_BIT ) ;
/* restart ping */
TEST_ESP_OK ( esp_ping_start ( ping ) ) ;
vTaskDelay ( pdMS_TO_TICKS ( ETH_PING_DURATION_MS ) ) ;
TEST_ESP_OK ( esp_ping_stop ( ping ) ) ;
bits = xEventGroupWaitBits ( eth_event_group , ETH_PING_END_BIT , true , true , pdMS_TO_TICKS ( ETH_PING_END_TIMEOUT_MS ) ) ;
TEST_ASSERT ( ( bits & ETH_PING_END_BIT ) = = ETH_PING_END_BIT ) ;
/* de-initialize ping process */
TEST_ESP_OK ( esp_ping_delete_session ( ping ) ) ;
vEventGroupDelete ( eth_event_group ) ;
}
2022-02-02 10:10:57 -05:00
2022-09-29 03:17:13 -04:00
TEST ( lwip , dhcp_server_init_deinit )
2022-02-02 10:10:57 -05:00
{
dhcps_t * dhcps = dhcps_new ( ) ;
2022-03-07 04:41:28 -05:00
TEST_ASSERT_NOT_NULL ( dhcps ) ;
2022-02-02 10:10:57 -05:00
ip4_addr_t ip = { . addr = IPADDR_ANY } ;
TEST_ASSERT ( dhcps_start ( dhcps , NULL , ip ) = = ERR_ARG ) ;
TEST_ASSERT ( dhcps_stop ( dhcps , NULL ) = = ERR_ARG ) ;
dhcps_delete ( dhcps ) ;
}
2022-09-29 03:17:13 -04:00
TEST ( lwip , dhcp_server_start_stop_localhost )
2022-02-02 10:10:57 -05:00
{
test_case_uses_tcpip ( ) ;
struct netif * netif ;
2022-10-27 06:25:00 -04:00
dhcps_t * dhcps ;
ip4_addr_t netmask ;
2022-02-02 10:10:57 -05:00
NETIF_FOREACH ( netif ) {
if ( netif - > name [ 0 ] = = ' l ' & & netif - > name [ 1 ] = = ' o ' ) {
break ;
}
}
TEST_ASSERT_NOT_NULL ( netif ) ;
2022-10-27 06:25:00 -04:00
//Class A
dhcps = dhcps_new ( ) ;
IP4_ADDR ( & netmask , 255 , 0 , 0 , 0 ) ;
dhcps_set_option_info ( dhcps , SUBNET_MASK , ( void * ) & netmask , sizeof ( netmask ) ) ;
ip4_addr_t a_ip = { . addr = 0x7f0001 } ;
IP4_ADDR ( & netmask , 255 , 0 , 0 , 0 ) ;
TEST_ASSERT ( dhcps_start ( dhcps , netif , a_ip ) = = ERR_OK ) ;
TEST_ASSERT ( dhcps_stop ( dhcps , netif ) = = ERR_OK ) ;
dhcps_delete ( dhcps ) ;
//Class B
dhcps = dhcps_new ( ) ;
IP4_ADDR ( & netmask , 255 , 255 , 0 , 0 ) ;
dhcps_set_option_info ( dhcps , SUBNET_MASK , ( void * ) & netmask , sizeof ( netmask ) ) ;
ip4_addr_t b_ip = { . addr = 0x1000080 } ;
TEST_ASSERT ( dhcps_start ( dhcps , netif , b_ip ) = = ERR_OK ) ;
TEST_ASSERT ( dhcps_stop ( dhcps , netif ) = = ERR_OK ) ;
dhcps_delete ( dhcps ) ;
//Class C
dhcps = dhcps_new ( ) ;
IP4_ADDR ( & netmask , 255 , 255 , 255 , 0 ) ;
dhcps_set_option_info ( dhcps , SUBNET_MASK , ( void * ) & netmask , sizeof ( netmask ) ) ;
ip4_addr_t c_ip = { . addr = 0x101A8C0 } ;
TEST_ASSERT ( dhcps_start ( dhcps , netif , c_ip ) = = ERR_OK ) ;
TEST_ASSERT ( dhcps_stop ( dhcps , netif ) = = ERR_OK ) ;
dhcps_delete ( dhcps ) ;
//Class A Subnet C
dhcps = dhcps_new ( ) ;
IP4_ADDR ( & netmask , 255 , 255 , 255 , 0 ) ;
dhcps_set_option_info ( dhcps , SUBNET_MASK , ( void * ) & netmask , sizeof ( netmask ) ) ;
TEST_ASSERT ( dhcps_start ( dhcps , netif , a_ip ) = = ERR_ARG ) ;
2022-02-02 10:10:57 -05:00
TEST_ASSERT ( dhcps_stop ( dhcps , netif ) = = ERR_OK ) ;
dhcps_delete ( dhcps ) ;
}
2022-09-29 03:17:13 -04:00
2022-09-29 08:17:14 -04:00
int test_sntp_server_create ( void )
{
struct sockaddr_in dest_addr_ip4 ;
int sock = - 1 ;
dest_addr_ip4 . sin_addr . s_addr = htonl ( INADDR_LOOPBACK ) ;
dest_addr_ip4 . sin_family = AF_INET ;
dest_addr_ip4 . sin_port = htons ( LWIP_IANA_PORT_SNTP ) ;
sock = socket ( AF_INET , SOCK_DGRAM , IPPROTO_IP ) ;
TEST_ASSERT_GREATER_OR_EQUAL ( 0 , sock ) ;
int reuse_en = 1 ;
TEST_ASSERT_GREATER_OR_EQUAL ( 0 , setsockopt ( sock , SOL_SOCKET , SO_REUSEADDR , & reuse_en , sizeof ( reuse_en ) ) ) ;
TEST_ASSERT_GREATER_OR_EQUAL ( 0 , bind ( sock , ( struct sockaddr * ) & dest_addr_ip4 , sizeof ( dest_addr_ip4 ) ) ) ;
return sock ;
}
bool test_sntp_server_reply_with_time ( int sock , int year , bool msb_flag )
{
struct sntp_timestamp {
uint32_t seconds ;
uint32_t fraction ;
} ;
const int SNTP_MSG_LEN = 48 ;
const int SNTP_MODE_CLIENT = 0x03 ;
const int SNTP_MODE_SERVER = 0x04 ;
const int SNTP_MODE_MASK = 0x07 ;
const int SNTP_OFFSET_STRATUM = 1 ;
char rx_buffer [ SNTP_MSG_LEN ] ;
struct sockaddr_storage source_addr ;
socklen_t socklen = sizeof ( source_addr ) ;
int len = recvfrom ( sock , rx_buffer , SNTP_MSG_LEN , 0 , ( struct sockaddr * ) & source_addr , & socklen ) ;
if ( len = = SNTP_MSG_LEN & & source_addr . ss_family = = PF_INET & & ( SNTP_MODE_MASK & rx_buffer [ 0 ] ) = = SNTP_MODE_CLIENT ) {
// modify the client's request to act as a server's response with the injected *xmit* timestamp
rx_buffer [ 0 ] & = ~ SNTP_MODE_CLIENT ;
rx_buffer [ 0 ] | = SNTP_MODE_SERVER ;
rx_buffer [ SNTP_OFFSET_STRATUM ] = 0x1 ;
// set the desired timestamp
struct sntp_timestamp * timestamp = ( struct sntp_timestamp * ) ( rx_buffer + SNTP_MSG_LEN - sizeof ( struct sntp_timestamp ) ) ; // xmit is the last timestamp in the datagram
int64_t seconds_since_1900 = ( 365 * 24 * 60 * 60 /* seconds per year */ + 24 * 60 * 60 / 4 /* ~ seconds per leap year */ ) * ( year - 1900 ) ;
// apply the MSB convention (set: 1968-2036, cleared: 2036-2104)
timestamp - > seconds = htonl ( ( msb_flag ? 0x80000000 : 0 ) | ( 0xFFFFFFFF & seconds_since_1900 ) ) ;
len = sendto ( sock , rx_buffer , SNTP_MSG_LEN , 0 , ( struct sockaddr * ) & source_addr , sizeof ( source_addr ) ) ;
if ( len = = SNTP_MSG_LEN ) {
return true ;
}
}
return false ;
}
void test_sntp_timestamps ( int year , bool msb_flag )
{
int sock = test_sntp_server_create ( ) ;
// setup lwip's SNTP in polling mode
sntp_setoperatingmode ( SNTP_OPMODE_POLL ) ;
sntp_setservername ( 0 , " 127.0.0.1 " ) ;
sntp_init ( ) ;
// wait until time sync
int retry = 0 ;
while ( sntp_get_sync_status ( ) = = SNTP_SYNC_STATUS_RESET ) {
TEST_ASSERT_TRUE ( test_sntp_server_reply_with_time ( sock , year , msb_flag ) ) ; // post the SNTP server's reply
retry + + ;
TEST_ASSERT_LESS_THAN ( 3 , retry ) ;
}
// check time and assert the year
time_t now ;
struct tm timeinfo ;
time ( & now ) ;
localtime_r ( & now , & timeinfo ) ;
TEST_ASSERT_EQUAL ( year , 1900 + timeinfo . tm_year ) ;
// close the SNTP and the fake server
sntp_stop ( ) ;
close ( sock ) ;
}
TEST ( lwip , sntp_client_time_2015 )
{
test_case_uses_tcpip ( ) ;
test_sntp_timestamps ( 2015 , true ) ; // NTP timestamp MSB is set for time before 2036
}
TEST ( lwip , sntp_client_time_2048 )
{
test_case_uses_tcpip ( ) ;
test_sntp_timestamps ( 2048 , false ) ; // NTP timestamp MSB is cleared for time after 2036
}
2022-09-29 03:17:13 -04:00
TEST_GROUP_RUNNER ( lwip )
{
RUN_TEST_CASE ( lwip , localhost_ping_test )
RUN_TEST_CASE ( lwip , dhcp_server_init_deinit )
RUN_TEST_CASE ( lwip , dhcp_server_start_stop_localhost )
2022-09-29 08:17:14 -04:00
RUN_TEST_CASE ( lwip , sntp_client_time_2015 )
RUN_TEST_CASE ( lwip , sntp_client_time_2048 )
2022-09-29 03:17:13 -04:00
}
void app_main ( void )
{
UNITY_MAIN ( lwip ) ;
}