1 /*
2  * Copyright (c) 2024 Espressif Systems (Shanghai) Co., Ltd.
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/kernel.h>
8 #include <zephyr/ztest.h>
9 #include <zephyr/logging/log.h>
10 
11 #include <zephyr/net/net_if.h>
12 #include <zephyr/net/net_core.h>
13 #include <zephyr/net/net_context.h>
14 #include <zephyr/net/net_mgmt.h>
15 #include <zephyr/net/ethernet.h>
16 #include <zephyr/net/icmp.h>
17 
18 LOG_MODULE_REGISTER(ethernet_test, LOG_LEVEL_INF);
19 
20 #include "net_private.h"
21 
22 #define DHCP_OPTION_NTP (42)
23 #define TEST_DATA       "ICMP dummy data"
24 
25 K_SEM_DEFINE(net_event, 0, 1);
26 
27 static struct net_if *iface;
28 
29 static uint8_t ntp_server[4];
30 static struct net_mgmt_event_callback mgmt_cb;
31 static struct net_dhcpv4_option_callback dhcp_cb;
32 
ipv4_event(struct net_mgmt_event_callback * cb,uint32_t mgmt_event,struct net_if * iface)33 static void ipv4_event(struct net_mgmt_event_callback *cb, uint32_t mgmt_event,
34 		       struct net_if *iface)
35 {
36 	if ((mgmt_event != NET_EVENT_IPV4_ADDR_ADD) ||
37 	    (iface->config.ip.ipv4->unicast[0].ipv4.addr_type != NET_ADDR_DHCP)) {
38 		return;
39 	}
40 
41 	char buf[NET_IPV4_ADDR_LEN];
42 
43 	LOG_INF("Address[%d]: %s", net_if_get_by_iface(iface),
44 		net_addr_ntop(AF_INET, &iface->config.ip.ipv4->unicast[0].ipv4.address.in_addr, buf,
45 			      sizeof(buf)));
46 	LOG_INF("Subnet[%d]: %s", net_if_get_by_iface(iface),
47 		net_addr_ntop(AF_INET, &iface->config.ip.ipv4->unicast[0].netmask, buf,
48 			      sizeof(buf)));
49 	LOG_INF("Router[%d]: %s", net_if_get_by_iface(iface),
50 		net_addr_ntop(AF_INET, &iface->config.ip.ipv4->gw, buf, sizeof(buf)));
51 	LOG_INF("Lease time[%d]: %u seconds", net_if_get_by_iface(iface),
52 		iface->config.dhcpv4.lease_time);
53 
54 	/* release processing of IPV4 event by test case */
55 	k_sem_give(&net_event);
56 }
57 
icmp_event(struct net_icmp_ctx * ctx,struct net_pkt * pkt,struct net_icmp_ip_hdr * hdr,struct net_icmp_hdr * icmp_hdr,void * user_data)58 static int icmp_event(struct net_icmp_ctx *ctx, struct net_pkt *pkt, struct net_icmp_ip_hdr *hdr,
59 		      struct net_icmp_hdr *icmp_hdr, void *user_data)
60 {
61 	struct net_ipv4_hdr *ip_hdr = hdr->ipv4;
62 
63 	LOG_INF("Received echo reply from %s", net_sprint_ipv4_addr(&ip_hdr->src));
64 
65 	k_sem_give(&net_event);
66 
67 	return 0;
68 }
69 
option_handler(struct net_dhcpv4_option_callback * cb,size_t length,enum net_dhcpv4_msg_type msg_type,struct net_if * iface)70 static void option_handler(struct net_dhcpv4_option_callback *cb, size_t length,
71 			   enum net_dhcpv4_msg_type msg_type, struct net_if *iface)
72 {
73 	char buf[NET_IPV4_ADDR_LEN];
74 
75 	LOG_INF("DHCP Option %d: %s", cb->option,
76 		net_addr_ntop(AF_INET, cb->data, buf, sizeof(buf)));
77 }
78 
ZTEST(ethernet,test_dhcp_check)79 ZTEST(ethernet, test_dhcp_check)
80 {
81 	LOG_INF("Waiting for IPV4 assign event...");
82 
83 	zassert_equal(k_sem_take(&net_event, K_SECONDS(CONFIG_DHCP_ASSIGN_TIMEOUT)), 0,
84 		      "IPV4 address assign event timeout");
85 
86 	LOG_INF("DHCP check successful");
87 }
88 
ZTEST(ethernet,test_icmp_check)89 ZTEST(ethernet, test_icmp_check)
90 {
91 	struct net_icmp_ping_params params;
92 	struct net_icmp_ctx ctx;
93 	struct in_addr gw_addr_4;
94 	struct sockaddr_in dst4 = {0};
95 	int ret;
96 
97 	gw_addr_4 = net_if_ipv4_get_gw(iface);
98 	zassert_not_equal(gw_addr_4.s_addr, 0, "Gateway address is not set");
99 
100 	ret = net_icmp_init_ctx(&ctx, NET_ICMPV4_ECHO_REPLY, 0, icmp_event);
101 	zassert_equal(ret, 0, "Cannot init ICMP (%d)", ret);
102 
103 	dst4.sin_family = AF_INET;
104 	memcpy(&dst4.sin_addr, &gw_addr_4, sizeof(gw_addr_4));
105 
106 	params.identifier = 1234;
107 	params.sequence = 5678;
108 	params.tc_tos = 1;
109 	params.priority = 2;
110 	params.data = TEST_DATA;
111 	params.data_size = sizeof(TEST_DATA);
112 
113 	LOG_INF("Pinging the gateway...");
114 
115 	ret = net_icmp_send_echo_request(&ctx, iface, (struct sockaddr *)&dst4, &params, NULL);
116 	zassert_equal(ret, 0, "Cannot send ICMP echo request (%d)", ret);
117 
118 	zassert_equal(k_sem_take(&net_event, K_SECONDS(CONFIG_GATEWAY_PING_TIMEOUT)), 0,
119 		      "Gateway ping (ICMP) timed out");
120 
121 	net_icmp_cleanup_ctx(&ctx);
122 }
123 
ethernet_setup(void)124 static void *ethernet_setup(void)
125 {
126 	iface = net_if_get_first_by_type(&NET_L2_GET_NAME(ETHERNET));
127 
128 	net_mgmt_init_event_callback(&mgmt_cb, ipv4_event, NET_EVENT_IPV4_ADDR_ADD);
129 	net_mgmt_add_event_callback(&mgmt_cb);
130 
131 	net_dhcpv4_init_option_callback(&dhcp_cb, option_handler, DHCP_OPTION_NTP, ntp_server,
132 					sizeof(ntp_server));
133 	net_dhcpv4_add_option_callback(&dhcp_cb);
134 
135 	/* reset semaphore that tracks IPV4 assign event */
136 	k_sem_reset(&net_event);
137 
138 	LOG_INF("Starting DHCPv4 client on %s: index=%d", net_if_get_device(iface)->name,
139 		net_if_get_by_iface(iface));
140 
141 	net_dhcpv4_start(iface);
142 
143 	return NULL;
144 }
145 
146 ZTEST_SUITE(ethernet, NULL, ethernet_setup, NULL, NULL, NULL);
147