1 /*
2  * Copyright (c) 2016 Intel Corporation.
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/logging/log.h>
8 LOG_MODULE_REGISTER(net_test, CONFIG_NET_MGMT_EVENT_LOG_LEVEL);
9 
10 #include <zephyr/kernel.h>
11 #include <zephyr/tc_util.h>
12 #include <errno.h>
13 #include <zephyr/toolchain.h>
14 #include <zephyr/linker/sections.h>
15 
16 #include <zephyr/net/dummy.h>
17 #include <zephyr/net/net_mgmt.h>
18 #include <zephyr/net/net_pkt.h>
19 #include <zephyr/ztest.h>
20 
21 #define THREAD_SLEEP 50 /* ms */
22 #define TEST_INFO_STRING "mgmt event info"
23 
24 #define TEST_MGMT_REQUEST		0x17AB1234
25 #define TEST_MGMT_EVENT			0x97AB1234
26 #define TEST_MGMT_EVENT_UNHANDLED	0x97AB4321
27 #define TEST_MGMT_EVENT_INFO_SIZE	\
28 	MAX(sizeof(TEST_INFO_STRING), sizeof(struct in6_addr))
29 
30 /* Notifier infra */
31 static uint64_t event2throw;
32 static uint32_t throw_times;
33 static uint32_t throw_sleep;
34 static bool with_info;
35 static bool with_static;
36 static K_THREAD_STACK_DEFINE(thrower_stack, 1024 + CONFIG_TEST_EXTRA_STACK_SIZE);
37 static struct k_thread thrower_thread_data;
38 static struct k_sem thrower_lock;
39 
40 /* Receiver infra */
41 static uint64_t rx_event;
42 static uint32_t rx_calls;
43 static size_t info_length_in_test;
44 static struct net_mgmt_event_callback rx_cb;
45 static char *info_string = TEST_INFO_STRING;
46 
47 static struct in6_addr addr6 = { { { 0xfe, 0x80, 0, 0, 0, 0, 0, 0,
48 				     0, 0, 0, 0, 0, 0, 0, 0x1 } } };
49 
50 static char info_data[TEST_MGMT_EVENT_INFO_SIZE];
51 
52 NET_MGMT_DEFINE_REQUEST_HANDLER(TEST_MGMT_REQUEST);
53 
test_mgmt_request(uint64_t mgmt_req,struct net_if * iface,void * data,size_t len)54 static int test_mgmt_request(uint64_t mgmt_req,
55 			     struct net_if *iface, void *data, size_t len)
56 {
57 	uint32_t *test_data = data;
58 
59 	ARG_UNUSED(iface);
60 
61 	if (len == sizeof(uint32_t)) {
62 		*test_data = 1U;
63 
64 		return 0;
65 	}
66 
67 	return -EIO;
68 }
69 
70 NET_MGMT_REGISTER_REQUEST_HANDLER(TEST_MGMT_REQUEST, test_mgmt_request);
71 
test_mgmt_event_handler(uint64_t mgmt_event,struct net_if * iface,void * info,size_t info_length,void * user_data)72 static void test_mgmt_event_handler(uint64_t mgmt_event, struct net_if *iface, void *info,
73 				    size_t info_length, void *user_data)
74 {
75 	if (!with_static) {
76 		return;
77 	}
78 
79 	TC_PRINT("\t\tReceived static event 0x%" PRIx64 "\n", mgmt_event);
80 
81 	ARG_UNUSED(user_data);
82 
83 	if (with_info && info) {
84 		if (info_length != info_length_in_test) {
85 			rx_calls = (uint32_t) -1;
86 			return;
87 		}
88 
89 		if (memcmp(info_data, info, info_length_in_test)) {
90 			rx_calls = (uint32_t) -1;
91 			return;
92 		}
93 	}
94 
95 	rx_event = mgmt_event;
96 	rx_calls++;
97 }
98 
99 NET_MGMT_REGISTER_EVENT_HANDLER(my_test_handler, TEST_MGMT_EVENT, test_mgmt_event_handler, NULL);
100 
fake_dev_init(const struct device * dev)101 int fake_dev_init(const struct device *dev)
102 {
103 	ARG_UNUSED(dev);
104 
105 	return 0;
106 }
107 
fake_iface_init(struct net_if * iface)108 static void fake_iface_init(struct net_if *iface)
109 {
110 	static uint8_t mac[8] = { 0x00, 0x00, 0x00, 0x00, 0x0a, 0x0b, 0x0c, 0x0d};
111 
112 	net_if_set_link_addr(iface, mac, 8, NET_LINK_DUMMY);
113 }
114 
fake_iface_send(const struct device * dev,struct net_pkt * pkt)115 static int fake_iface_send(const struct device *dev, struct net_pkt *pkt)
116 {
117 	return 0;
118 }
119 
120 static struct dummy_api fake_iface_api = {
121 	.iface_api.init = fake_iface_init,
122 	.send = fake_iface_send,
123 };
124 
125 NET_DEVICE_INIT(net_event_test, "net_event_test",
126 		fake_dev_init, NULL,
127 		NULL, NULL, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT,
128 		&fake_iface_api, DUMMY_L2, NET_L2_GET_CTX_TYPE(DUMMY_L2), 127);
129 
test_requesting_nm(void)130 void test_requesting_nm(void)
131 {
132 	uint32_t data = 0U;
133 
134 	TC_PRINT("- Request Net MGMT\n");
135 
136 	zassert_false(net_mgmt(TEST_MGMT_REQUEST, NULL, &data, sizeof(data)),
137 		      "Requesting Net MGMT failed");
138 }
139 
thrower_thread(void * p1,void * p2,void * p3)140 static void thrower_thread(void *p1, void *p2, void *p3)
141 {
142 	ARG_UNUSED(p1);
143 	ARG_UNUSED(p2);
144 	ARG_UNUSED(p3);
145 
146 	while (1) {
147 		k_sem_take(&thrower_lock, K_FOREVER);
148 
149 		TC_PRINT("\tThrowing event 0x%" PRIx64 " %u times\n",
150 			 event2throw, throw_times);
151 
152 		for (; throw_times; throw_times--) {
153 			k_msleep(throw_sleep);
154 
155 			if (with_info) {
156 				net_mgmt_event_notify_with_info(
157 					event2throw,
158 					net_if_get_first_by_type(
159 						      &NET_L2_GET_NAME(DUMMY)),
160 					info_data,
161 					TEST_MGMT_EVENT_INFO_SIZE);
162 			} else {
163 				net_mgmt_event_notify(event2throw,
164 					net_if_get_first_by_type(
165 						&NET_L2_GET_NAME(DUMMY)));
166 			}
167 
168 		}
169 	}
170 }
171 
receiver_cb(struct net_mgmt_event_callback * cb,uint64_t nm_event,struct net_if * iface)172 static void receiver_cb(struct net_mgmt_event_callback *cb,
173 			uint64_t nm_event, struct net_if *iface)
174 {
175 	TC_PRINT("\t\tReceived event 0x%" PRIx64 "\n", nm_event);
176 
177 	if (with_info && cb->info) {
178 		if (cb->info_length != info_length_in_test) {
179 			rx_calls = (uint32_t) -1;
180 			return;
181 		}
182 
183 		if (memcmp(info_data, cb->info, info_length_in_test)) {
184 			rx_calls = (uint32_t) -1;
185 			return;
186 		}
187 	}
188 
189 	rx_event = nm_event;
190 	rx_calls++;
191 }
192 
sending_event(uint32_t times,bool receiver,bool info)193 static int sending_event(uint32_t times, bool receiver, bool info)
194 {
195 	TC_PRINT("- Sending event %u times, %s a receiver, %s info\n",
196 		 times, receiver ? "with" : "without",
197 		 info ? "with" : "without");
198 
199 	event2throw = TEST_MGMT_EVENT;
200 	throw_times = times;
201 	with_info = info;
202 
203 	if (receiver) {
204 		net_mgmt_add_event_callback(&rx_cb);
205 	}
206 
207 	k_sem_give(&thrower_lock);
208 
209 	/* Let the network stack to proceed */
210 	k_msleep(THREAD_SLEEP);
211 
212 	if (receiver) {
213 		TC_PRINT("\tReceived 0x%" PRIx64 " %u times\n",
214 			 rx_event, rx_calls);
215 
216 		zassert_equal(rx_event, event2throw, "rx_event check failed");
217 		zassert_equal(rx_calls, times, "rx_calls check failed");
218 
219 		net_mgmt_del_event_callback(&rx_cb);
220 		rx_event = 0ULL;
221 		rx_calls = 0U;
222 	}
223 
224 	return TC_PASS;
225 }
226 
test_sending_event(uint32_t times,bool receiver)227 static int test_sending_event(uint32_t times, bool receiver)
228 {
229 	return sending_event(times, receiver, false);
230 }
231 
test_sending_event_info(uint32_t times,bool receiver)232 static int test_sending_event_info(uint32_t times, bool receiver)
233 {
234 	return sending_event(times, receiver, true);
235 }
236 
test_synchronous_event_listener(uint32_t times,bool on_iface)237 static int test_synchronous_event_listener(uint32_t times, bool on_iface)
238 {
239 	uint64_t event_mask;
240 	int ret;
241 
242 	TC_PRINT("- Synchronous event listener %s\n",
243 		 on_iface ? "on interface" : "");
244 
245 	event2throw = TEST_MGMT_EVENT | (on_iface ? NET_MGMT_IFACE_BIT : 0);
246 	throw_times = times;
247 	throw_sleep = 200;
248 
249 	event_mask = event2throw;
250 
251 	k_sem_give(&thrower_lock);
252 
253 	if (on_iface) {
254 		ret = net_mgmt_event_wait_on_iface(
255 			net_if_get_first_by_type(&NET_L2_GET_NAME(DUMMY)),
256 			event_mask, NULL, NULL,
257 			NULL, K_SECONDS(1));
258 	} else {
259 		ret = net_mgmt_event_wait(event_mask, NULL, NULL, NULL, NULL,
260 					  K_SECONDS(1));
261 	}
262 
263 	if (ret < 0) {
264 		if (ret == -ETIMEDOUT) {
265 			TC_ERROR("Call timed out\n");
266 		}
267 
268 		return TC_FAIL;
269 	}
270 
271 	return TC_PASS;
272 }
273 
test_static_event_listener(uint32_t times,bool info)274 static int test_static_event_listener(uint32_t times, bool info)
275 {
276 	TC_PRINT("- Static event listener %s\n", info ? "with info" : "");
277 
278 	event2throw = TEST_MGMT_EVENT;
279 	throw_times = times;
280 	throw_sleep = 0;
281 	with_info = info;
282 	with_static = true;
283 
284 	k_sem_give(&thrower_lock);
285 
286 	/* Let the network stack to proceed */
287 	k_msleep(THREAD_SLEEP);
288 
289 	TC_PRINT("\tReceived 0x%" PRIx64 " %u times\n",
290 			rx_event, rx_calls);
291 
292 	zassert_equal(rx_event, event2throw, "rx_event check failed");
293 	zassert_equal(rx_calls, times, "rx_calls check failed");
294 
295 	rx_event = 0ULL;
296 	rx_calls = 0U;
297 	with_static = false;
298 
299 	return TC_PASS;
300 }
301 
initialize_event_tests(void)302 static void initialize_event_tests(void)
303 {
304 	event2throw = 0ULL;
305 	throw_times = 0U;
306 	throw_sleep = 0;
307 	with_info = false;
308 
309 	rx_event = 0ULL;
310 	rx_calls = 0U;
311 
312 	k_sem_init(&thrower_lock, 0, UINT_MAX);
313 
314 	info_length_in_test = TEST_MGMT_EVENT_INFO_SIZE;
315 	memcpy(info_data, info_string, strlen(info_string) + 1);
316 
317 	net_mgmt_init_event_callback(&rx_cb, receiver_cb, TEST_MGMT_EVENT);
318 
319 	k_thread_create(&thrower_thread_data, thrower_stack,
320 			K_THREAD_STACK_SIZEOF(thrower_stack),
321 			thrower_thread,
322 			NULL, NULL, NULL, K_PRIO_COOP(7), 0, K_NO_WAIT);
323 }
324 
test_core_event(uint64_t event,bool (* func)(void))325 static int test_core_event(uint64_t event, bool (*func)(void))
326 {
327 	TC_PRINT("- Triggering core event: 0x%" PRIx64 "\n", event);
328 
329 	info_length_in_test = sizeof(struct in6_addr);
330 	memcpy(info_data, &addr6, sizeof(addr6));
331 
332 	net_mgmt_init_event_callback(&rx_cb, receiver_cb, event);
333 
334 	net_mgmt_add_event_callback(&rx_cb);
335 
336 	zassert_true(func(), "func() check failed");
337 
338 	/* Let the network stack to proceed */
339 	k_msleep(THREAD_SLEEP);
340 
341 	zassert_true(rx_calls > 0 && rx_calls != -1, "rx_calls empty");
342 	zassert_equal(rx_event, event, "rx_event check failed, "
343 		      "0x%" PRIx64 " vs 0x%" PRIx64, rx_event, event);
344 
345 	net_mgmt_del_event_callback(&rx_cb);
346 	rx_event = 0ULL;
347 	rx_calls = 0U;
348 
349 	return TC_PASS;
350 }
351 
_iface_ip6_add(void)352 static bool _iface_ip6_add(void)
353 {
354 	if (net_if_ipv6_addr_add(
355 		    net_if_get_first_by_type(&NET_L2_GET_NAME(DUMMY)),
356 		    &addr6, NET_ADDR_MANUAL, 0)) {
357 		return true;
358 	}
359 
360 	return false;
361 }
362 
_iface_ip6_del(void)363 static bool _iface_ip6_del(void)
364 {
365 	if (net_if_ipv6_addr_rm(
366 		    net_if_get_first_by_type(&NET_L2_GET_NAME(DUMMY)),
367 		    &addr6)) {
368 		return true;
369 	}
370 
371 	return false;
372 }
373 
ZTEST(mgmt_fn_test_suite,test_mgmt)374 ZTEST(mgmt_fn_test_suite, test_mgmt)
375 {
376 	TC_PRINT("Starting Network Management API test\n");
377 
378 	test_requesting_nm();
379 
380 	initialize_event_tests();
381 
382 	zassert_false(test_sending_event(1, false),
383 		      "test_sending_event failed");
384 
385 	zassert_false(test_sending_event(2, false),
386 		      "test_sending_event failed");
387 
388 	zassert_false(test_sending_event(1, true),
389 		      "test_sending_event failed");
390 
391 	zassert_false(test_sending_event(2, true),
392 		      "test_sending_event failed");
393 
394 	zassert_false(test_sending_event_info(1, false),
395 		      "test_sending_event failed");
396 
397 	zassert_false(test_sending_event_info(2, false),
398 		      "test_sending_event failed");
399 
400 	zassert_false(test_sending_event_info(1, true),
401 		      "test_sending_event failed");
402 
403 	zassert_false(test_sending_event_info(2, true),
404 		      "test_sending_event failed");
405 
406 	zassert_false(test_static_event_listener(1, false),
407 		      "test_static_event_listener failed");
408 
409 	zassert_false(test_static_event_listener(2, false),
410 		      "test_static_event_listener failed");
411 
412 	zassert_false(test_static_event_listener(1, true),
413 		      "test_static_event_listener failed");
414 
415 	zassert_false(test_static_event_listener(2, true),
416 		      "test_static_event_listener failed");
417 
418 	zassert_false(test_core_event(NET_EVENT_IPV6_ADDR_ADD, _iface_ip6_add),
419 		      "test_core_event failed");
420 
421 	zassert_false(test_core_event(NET_EVENT_IPV6_ADDR_DEL, _iface_ip6_del),
422 		      "test_core_event failed");
423 
424 	zassert_false(test_synchronous_event_listener(2, false),
425 		      "test_synchronous_event_listener failed");
426 
427 	zassert_false(test_synchronous_event_listener(2, true),
428 		      "test_synchronous_event_listener failed");
429 }
430 
431 static K_SEM_DEFINE(wait_for_event_processing, 0, 1);
432 
net_mgmt_event_handler(struct net_mgmt_event_callback * cb,uint64_t mgmt_event,struct net_if * iface)433 static void net_mgmt_event_handler(struct net_mgmt_event_callback *cb,
434 				   uint64_t mgmt_event, struct net_if *iface)
435 {
436 	static int cb_call_count;
437 
438 	ARG_UNUSED(cb);
439 	ARG_UNUSED(iface);
440 	ARG_UNUSED(mgmt_event);
441 
442 	k_sem_give(&wait_for_event_processing);
443 	cb_call_count++;
444 	zassert_equal(cb_call_count, 1, "Too many calls to event callback");
445 }
446 
ZTEST(mgmt_fn_test_suite,test_mgmt_duplicate_handler)447 ZTEST(mgmt_fn_test_suite, test_mgmt_duplicate_handler)
448 {
449 	struct net_mgmt_event_callback cb;
450 	int ret;
451 
452 	net_mgmt_init_event_callback(&cb, net_mgmt_event_handler, NET_EVENT_IPV6_ADDR_ADD);
453 	net_mgmt_add_event_callback(&cb);
454 	net_mgmt_add_event_callback(&cb);
455 
456 	net_mgmt_event_notify(NET_EVENT_IPV6_ADDR_ADD, NULL);
457 
458 	ret = k_sem_take(&wait_for_event_processing, K_MSEC(50));
459 	zassert_equal(ret, 0, "Event is not processed");
460 
461 	net_mgmt_del_event_callback(&cb);
462 }
463 
464 ZTEST_SUITE(mgmt_fn_test_suite, NULL, NULL, NULL, NULL, NULL);
465