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, ¶ms, 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