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