1 /* main.c - Application main entry point */
2
3 /*
4 * Copyright (c) 2018 Intel Corporation
5 *
6 * SPDX-License-Identifier: Apache-2.0
7 */
8
9 #define NET_LOG_LEVEL CONFIG_NET_L2_ETHERNET_LOG_LEVEL
10
11 #include <zephyr/logging/log.h>
12 LOG_MODULE_REGISTER(net_test, NET_LOG_LEVEL);
13
14 #include <zephyr/types.h>
15 #include <stdbool.h>
16 #include <stddef.h>
17 #include <string.h>
18 #include <errno.h>
19 #include <zephyr/sys/printk.h>
20 #include <zephyr/linker/sections.h>
21 #include <zephyr/random/random.h>
22
23 #include <zephyr/ztest.h>
24
25 #include <zephyr/net_buf.h>
26 #include <zephyr/net/net_ip.h>
27 #include <zephyr/net/net_pkt.h>
28 #include <zephyr/net/ethernet.h>
29 #include <zephyr/net/dummy.h>
30 #include <zephyr/net/net_l2.h>
31
32 #include "ipv6.h"
33
34 #define NET_LOG_ENABLED 1
35 #include "net_private.h"
36
37 #if NET_LOG_LEVEL >= LOG_LEVEL_DBG
38 #define DBG(fmt, ...) printk(fmt, ##__VA_ARGS__)
39 #else
40 #define DBG(fmt, ...)
41 #endif
42
43 #define TEST_PORT 9999
44
45 static char *test_data = "Test data to be sent";
46
47 /* Interface 1 addresses */
48 static struct in6_addr my_addr1 = { { { 0x20, 0x01, 0x0d, 0xb8, 1, 0, 0, 0,
49 0, 0, 0, 0, 0, 0, 0, 0x1 } } };
50
51 /* Interface 2 addresses */
52 static struct in6_addr my_addr2 = { { { 0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0,
53 0, 0, 0, 0, 0, 0, 0, 0x1 } } };
54
55 /* Destination address for test packets */
56 static struct in6_addr dst_addr = { { { 0x20, 0x01, 0x0d, 0xb8, 9, 0, 0, 0,
57 0, 0, 0, 0, 0, 0, 0, 0x1 } } };
58
59 /* Extra address is assigned to ll_addr */
60 static struct in6_addr ll_addr = { { { 0xfe, 0x80, 0x43, 0xb8, 0, 0, 0, 0,
61 0, 0, 0, 0xf2, 0xaa, 0x29, 0x02,
62 0x04 } } };
63
64 /* Keep track of all ethernet interfaces */
65 static struct net_if *eth_interfaces[2];
66
67 static struct net_context *udp_v6_ctx;
68
69 static bool test_failed;
70 static bool test_started;
71 static bool do_timestamp;
72 static bool timestamp_cb_called;
73 static struct net_if_timestamp_cb timestamp_cb;
74 static struct net_if_timestamp_cb timestamp_cb_2;
75 static struct net_if_timestamp_cb timestamp_cb_3;
76
77 static K_SEM_DEFINE(wait_data, 0, UINT_MAX);
78
79 #define WAIT_TIME K_SECONDS(1)
80
81 struct eth_context {
82 struct net_if *iface;
83 uint8_t mac_addr[6];
84 };
85
86 static struct eth_context eth_context;
87 static struct eth_context eth_context2;
88
eth_iface_init(struct net_if * iface)89 static void eth_iface_init(struct net_if *iface)
90 {
91 const struct device *dev = net_if_get_device(iface);
92 struct eth_context *context = dev->data;
93
94 net_if_set_link_addr(iface, context->mac_addr,
95 sizeof(context->mac_addr),
96 NET_LINK_ETHERNET);
97
98 ethernet_init(iface);
99 }
100
eth_tx(const struct device * dev,struct net_pkt * pkt)101 static int eth_tx(const struct device *dev, struct net_pkt *pkt)
102 {
103 if (!pkt->buffer) {
104 DBG("No data to send!\n");
105 return -ENODATA;
106 }
107
108 if (test_started) {
109 if (do_timestamp) {
110 /* Simulate the clock advancing */
111 pkt->timestamp.nanosecond = pkt->timestamp.second + 1;
112
113 net_if_add_tx_timestamp(pkt);
114 } else {
115 k_sem_give(&wait_data);
116 }
117 }
118
119 test_started = false;
120
121 return 0;
122 }
123
eth_get_capabilities(const struct device * dev)124 static enum ethernet_hw_caps eth_get_capabilities(const struct device *dev)
125 {
126 return 0;
127 }
128
129 static struct ethernet_api api_funcs = {
130 .iface_api.init = eth_iface_init,
131
132 .get_capabilities = eth_get_capabilities,
133 .send = eth_tx,
134 };
135
generate_mac(uint8_t * mac_addr)136 static void generate_mac(uint8_t *mac_addr)
137 {
138 /* 00-00-5E-00-53-xx Documentation RFC 7042 */
139 mac_addr[0] = 0x00;
140 mac_addr[1] = 0x00;
141 mac_addr[2] = 0x5E;
142 mac_addr[3] = 0x00;
143 mac_addr[4] = 0x53;
144 mac_addr[5] = sys_rand8_get();
145 }
146
eth_init(const struct device * dev)147 static int eth_init(const struct device *dev)
148 {
149 struct eth_context *context = dev->data;
150
151 generate_mac(context->mac_addr);
152
153 return 0;
154 }
155
156 ETH_NET_DEVICE_INIT(eth_test, "eth_test", eth_init, NULL,
157 ð_context, NULL, CONFIG_ETH_INIT_PRIORITY, &api_funcs,
158 NET_ETH_MTU);
159
160 ETH_NET_DEVICE_INIT(eth_test2, "eth_test2", eth_init, NULL,
161 ð_context2, NULL, CONFIG_ETH_INIT_PRIORITY, &api_funcs,
162 NET_ETH_MTU);
163
timestamp_callback(struct net_pkt * pkt)164 static void timestamp_callback(struct net_pkt *pkt)
165 {
166 timestamp_cb_called = true;
167
168 if (do_timestamp) {
169 /* This is very artificial test but make sure that we
170 * have advanced the time a bit.
171 */
172 zassert_true(pkt->timestamp.nanosecond > pkt->timestamp.second,
173 "Timestamp not working ok (%d < %d)\n",
174 pkt->timestamp.nanosecond, pkt->timestamp.second);
175 }
176
177 /* The pkt was ref'ed in send_some_data()() */
178 net_pkt_unref(pkt);
179
180 if (do_timestamp) {
181 k_sem_give(&wait_data);
182 }
183 }
184
test_timestamp_setup(void)185 void test_timestamp_setup(void)
186 {
187 struct net_if *iface;
188 struct net_pkt *pkt;
189
190 iface = eth_interfaces[0];
191
192 net_if_register_timestamp_cb(×tamp_cb, NULL, iface,
193 timestamp_callback);
194
195 timestamp_cb_called = false;
196 do_timestamp = false;
197
198 pkt = net_pkt_alloc_on_iface(iface, K_FOREVER);
199
200 /* Make sure that the callback function is called */
201 net_if_call_timestamp_cb(pkt);
202
203 zassert_true(timestamp_cb_called, "Timestamp callback not called\n");
204 zassert_equal(atomic_get(&pkt->atomic_ref), 0, "Pkt %p not released\n");
205 }
206
timestamp_callback_2(struct net_pkt * pkt)207 static void timestamp_callback_2(struct net_pkt *pkt)
208 {
209 timestamp_cb_called = true;
210
211 if (do_timestamp) {
212 /* This is very artificial test but make sure that we
213 * have advanced the time a bit.
214 */
215 zassert_true(pkt->timestamp.nanosecond > pkt->timestamp.second,
216 "Timestamp not working ok (%d < %d)\n",
217 pkt->timestamp.nanosecond, pkt->timestamp.second);
218 }
219
220 zassert_equal(eth_interfaces[1], net_pkt_iface(pkt),
221 "Invalid interface");
222
223 /* The pkt was ref'ed in send_some_data()() */
224 net_pkt_unref(pkt);
225
226 if (do_timestamp) {
227 k_sem_give(&wait_data);
228 }
229 }
230
test_timestamp_setup_2nd_iface(void)231 void test_timestamp_setup_2nd_iface(void)
232 {
233 struct net_if *iface;
234 struct net_pkt *pkt;
235
236 iface = eth_interfaces[1];
237
238 net_if_register_timestamp_cb(×tamp_cb_2, NULL, iface,
239 timestamp_callback_2);
240
241 timestamp_cb_called = false;
242 do_timestamp = false;
243
244 pkt = net_pkt_alloc_on_iface(iface, K_FOREVER);
245
246 /* Make sure that the callback function is called */
247 net_if_call_timestamp_cb(pkt);
248
249 zassert_true(timestamp_cb_called, "Timestamp callback not called\n");
250 zassert_equal(atomic_get(&pkt->atomic_ref), 0, "Pkt %p not released\n");
251 }
252
test_timestamp_setup_all(void)253 void test_timestamp_setup_all(void)
254 {
255 struct net_pkt *pkt;
256
257 net_if_register_timestamp_cb(×tamp_cb_3, NULL, NULL,
258 timestamp_callback);
259
260 timestamp_cb_called = false;
261 do_timestamp = false;
262
263 pkt = net_pkt_alloc_on_iface(eth_interfaces[0], K_FOREVER);
264
265 /* The callback is called twice because we have two matching callbacks
266 * as the interface is set to NULL when registering cb. So we need to
267 * ref the pkt here because the callback releases pkt.
268 */
269 net_pkt_ref(pkt);
270
271 /* Make sure that the callback function is called */
272 net_if_call_timestamp_cb(pkt);
273
274 zassert_true(timestamp_cb_called, "Timestamp callback not called\n");
275 zassert_equal(atomic_get(&pkt->atomic_ref), 0, "Pkt %p not released\n");
276
277 net_if_unregister_timestamp_cb(×tamp_cb_3);
278 }
279
test_timestamp_cleanup(void)280 void test_timestamp_cleanup(void)
281 {
282 struct net_if *iface;
283 struct net_pkt *pkt;
284
285 net_if_unregister_timestamp_cb(×tamp_cb);
286
287 iface = eth_interfaces[0];
288
289 timestamp_cb_called = false;
290 do_timestamp = false;
291
292 pkt = net_pkt_alloc_on_iface(iface, K_FOREVER);
293
294 /* Make sure that the callback function is not called after unregister
295 */
296 net_if_call_timestamp_cb(pkt);
297
298 zassert_false(timestamp_cb_called, "Timestamp callback called\n");
299 zassert_false(atomic_get(&pkt->atomic_ref) < 1, "Pkt %p released\n");
300
301 net_pkt_unref(pkt);
302 }
303
304 struct user_data {
305 int eth_if_count;
306 int total_if_count;
307 };
308
309 #if NET_LOG_LEVEL >= LOG_LEVEL_DBG
iface2str(struct net_if * iface)310 static const char *iface2str(struct net_if *iface)
311 {
312 #ifdef CONFIG_NET_L2_ETHERNET
313 if (net_if_l2(iface) == &NET_L2_GET_NAME(ETHERNET)) {
314 return "Ethernet";
315 }
316 #endif
317
318 return "<unknown type>";
319 }
320 #endif
321
iface_cb(struct net_if * iface,void * user_data)322 static void iface_cb(struct net_if *iface, void *user_data)
323 {
324 struct user_data *ud = user_data;
325
326 DBG("Interface %p (%s) [%d]\n", iface, iface2str(iface),
327 net_if_get_by_iface(iface));
328
329 if (net_if_l2(iface) == &NET_L2_GET_NAME(ETHERNET)) {
330 if (ud->eth_if_count >= ARRAY_SIZE(eth_interfaces)) {
331 DBG("Invalid interface %p\n", iface);
332 return;
333 }
334
335 eth_interfaces[ud->eth_if_count++] = iface;
336 }
337
338 /* By default all interfaces are down initially */
339 net_if_down(iface);
340
341 ud->total_if_count++;
342 }
343
test_address_setup(void)344 void test_address_setup(void)
345 {
346 struct net_if_addr *ifaddr;
347 struct net_if *iface1, *iface2;
348
349 struct user_data ud = { 0 };
350
351 net_if_foreach(iface_cb, &ud);
352
353 iface1 = eth_interfaces[0];
354 iface2 = eth_interfaces[1];
355
356 zassert_not_null(iface1, "Interface 1\n");
357 zassert_not_null(iface2, "Interface 2\n");
358
359 ifaddr = net_if_ipv6_addr_add(iface1, &my_addr1,
360 NET_ADDR_MANUAL, 0);
361 if (!ifaddr) {
362 DBG("Cannot add IPv6 address %s\n",
363 net_sprint_ipv6_addr(&my_addr1));
364 zassert_not_null(ifaddr, "addr1\n");
365 }
366
367 /* For testing purposes we need to set the addresses preferred */
368 ifaddr->addr_state = NET_ADDR_PREFERRED;
369
370 ifaddr = net_if_ipv6_addr_add(iface1, &ll_addr,
371 NET_ADDR_MANUAL, 0);
372 if (!ifaddr) {
373 DBG("Cannot add IPv6 address %s\n",
374 net_sprint_ipv6_addr(&ll_addr));
375 zassert_not_null(ifaddr, "ll_addr\n");
376 }
377
378 ifaddr->addr_state = NET_ADDR_PREFERRED;
379
380 ifaddr = net_if_ipv6_addr_add(iface2, &my_addr2,
381 NET_ADDR_MANUAL, 0);
382 if (!ifaddr) {
383 DBG("Cannot add IPv6 address %s\n",
384 net_sprint_ipv6_addr(&my_addr2));
385 zassert_not_null(ifaddr, "addr2\n");
386 }
387
388 ifaddr->addr_state = NET_ADDR_PREFERRED;
389
390 net_if_up(iface1);
391 net_if_up(iface2);
392
393 /* The interface might receive data which might fail the checks
394 * in the iface sending function, so we need to reset the failure
395 * flag.
396 */
397 test_failed = false;
398 }
399
add_neighbor(struct net_if * iface,struct in6_addr * addr)400 static bool add_neighbor(struct net_if *iface, struct in6_addr *addr)
401 {
402 struct net_linkaddr_storage llstorage;
403 struct net_linkaddr lladdr;
404 struct net_nbr *nbr;
405
406 llstorage.addr[0] = 0x01;
407 llstorage.addr[1] = 0x02;
408 llstorage.addr[2] = 0x33;
409 llstorage.addr[3] = 0x44;
410 llstorage.addr[4] = 0x05;
411 llstorage.addr[5] = 0x06;
412
413 lladdr.len = 6U;
414 lladdr.addr = llstorage.addr;
415 lladdr.type = NET_LINK_ETHERNET;
416
417 nbr = net_ipv6_nbr_add(iface, addr, &lladdr, false,
418 NET_IPV6_NBR_STATE_REACHABLE);
419 if (!nbr) {
420 DBG("Cannot add dst %s to neighbor cache\n",
421 net_sprint_ipv6_addr(addr));
422 return false;
423 }
424
425 return true;
426 }
427
send_some_data(struct net_if * iface)428 static void send_some_data(struct net_if *iface)
429 {
430 struct sockaddr_in6 dst_addr6 = {
431 .sin6_family = AF_INET6,
432 .sin6_port = htons(TEST_PORT),
433 };
434 struct sockaddr_in6 src_addr6 = {
435 .sin6_family = AF_INET6,
436 .sin6_port = 0,
437 };
438 int ret;
439
440 ret = net_context_get(AF_INET6, SOCK_DGRAM, IPPROTO_UDP,
441 &udp_v6_ctx);
442 zassert_equal(ret, 0, "Create IPv6 UDP context failed\n");
443
444 memcpy(&src_addr6.sin6_addr, &my_addr1, sizeof(struct in6_addr));
445 memcpy(&dst_addr6.sin6_addr, &dst_addr, sizeof(struct in6_addr));
446
447 ret = net_context_bind(udp_v6_ctx, (struct sockaddr *)&src_addr6,
448 sizeof(struct sockaddr_in6));
449 zassert_equal(ret, 0, "Context bind failure test failed\n");
450
451 ret = add_neighbor(iface, &dst_addr);
452 zassert_true(ret, "Cannot add neighbor\n");
453
454 ret = net_context_sendto(udp_v6_ctx, test_data, strlen(test_data),
455 (struct sockaddr *)&dst_addr6,
456 sizeof(struct sockaddr_in6),
457 NULL, K_NO_WAIT, NULL);
458 zassert_true(ret > 0, "Send UDP pkt failed\n");
459
460 net_context_unref(udp_v6_ctx);
461 }
462
test_check_timestamp_before_enabling(void)463 void test_check_timestamp_before_enabling(void)
464 {
465 test_started = true;
466 do_timestamp = false;
467
468 send_some_data(eth_interfaces[0]);
469
470 if (k_sem_take(&wait_data, WAIT_TIME)) {
471 DBG("Timeout while waiting interface data\n");
472 zassert_false(true, "Timeout\n");
473 }
474 }
475
test_check_timestamp_after_enabling(void)476 void test_check_timestamp_after_enabling(void)
477 {
478 test_started = true;
479 do_timestamp = true;
480
481 send_some_data(eth_interfaces[0]);
482
483 if (k_sem_take(&wait_data, WAIT_TIME)) {
484 DBG("Timeout while waiting interface data\n");
485 zassert_false(true, "Timeout\n");
486 }
487 }
488
ZTEST(net_tx_timestamp,test_tx_timestamp)489 ZTEST(net_tx_timestamp, test_tx_timestamp)
490 {
491 test_address_setup();
492 test_check_timestamp_before_enabling();
493 test_timestamp_setup();
494 test_timestamp_setup_2nd_iface();
495 test_timestamp_setup_all();
496 test_check_timestamp_after_enabling();
497 test_timestamp_cleanup();
498 }
499 ZTEST_SUITE(net_tx_timestamp, NULL, NULL, NULL, NULL, NULL);
500