|  | /* | 
|  | * Copyright (c) 2016 Intel Corporation. | 
|  | * | 
|  | * Licensed under the Apache License, Version 2.0 (the "License"); | 
|  | * you may not use this file except in compliance with the License. | 
|  | * You may obtain a copy of the License at | 
|  | * | 
|  | *     http://www.apache.org/licenses/LICENSE-2.0 | 
|  | * | 
|  | * Unless required by applicable law or agreed to in writing, software | 
|  | * distributed under the License is distributed on an "AS IS" BASIS, | 
|  | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
|  | * See the License for the specific language governing permissions and | 
|  | * limitations under the License. | 
|  | */ | 
|  |  | 
|  | #include <zephyr.h> | 
|  | #include <tc_util.h> | 
|  | #include <errno.h> | 
|  | #include <toolchain.h> | 
|  | #include <sections.h> | 
|  |  | 
|  | #include <net/net_mgmt.h> | 
|  | #include <net/nbuf.h> | 
|  |  | 
|  | #define TEST_MGMT_REQUEST		0x0ABC1234 | 
|  | #define TEST_MGMT_EVENT			0x8ABC1234 | 
|  | #define TEST_MGMT_EVENT_UNHANDLED	0x8ABC4321 | 
|  |  | 
|  | /* Notifier infra */ | 
|  | static uint32_t event2throw; | 
|  | static uint32_t throw_times; | 
|  | static char __noinit __stack thrower_stack[512]; | 
|  | static struct k_sem thrower_lock; | 
|  |  | 
|  | /* Receiver infra */ | 
|  | static uint32_t rx_event; | 
|  | static uint32_t rx_calls; | 
|  | static struct net_mgmt_event_callback rx_cb; | 
|  |  | 
|  | static struct in6_addr addr6 = { { { 0xfe, 0x80, 0, 0, 0, 0, 0, 0, | 
|  | 0, 0, 0, 0, 0, 0, 0, 0x1 } } }; | 
|  |  | 
|  | static int test_mgmt_request(uint32_t mgmt_request, | 
|  | struct net_if *iface, void *data, uint32_t len) | 
|  | { | 
|  | uint32_t *test_data = data; | 
|  |  | 
|  | ARG_UNUSED(iface); | 
|  |  | 
|  | if (len == sizeof(uint32_t)) { | 
|  | *test_data = 1; | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | return -EIO; | 
|  | } | 
|  |  | 
|  | NET_MGMT_REGISTER_REQUEST_HANDLER(TEST_MGMT_REQUEST, test_mgmt_request); | 
|  |  | 
|  | int fake_dev_init(struct device *dev) | 
|  | { | 
|  | ARG_UNUSED(dev); | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static void fake_iface_init(struct net_if *iface) | 
|  | { | 
|  | uint8_t mac[8] = { 0x00, 0x00, 0x00, 0x00, 0x0a, 0x0b, 0x0c, 0x0d}; | 
|  |  | 
|  | net_if_set_link_addr(iface, mac, 8); | 
|  | } | 
|  |  | 
|  | static int fake_iface_send(struct net_if *iface, struct net_buf *buf) | 
|  | { | 
|  | net_nbuf_unref(buf); | 
|  |  | 
|  | return NET_OK; | 
|  | } | 
|  |  | 
|  | static struct net_if_api fake_iface_api = { | 
|  | .init = fake_iface_init, | 
|  | .send = fake_iface_send, | 
|  | }; | 
|  |  | 
|  | NET_DEVICE_INIT(net_event_test, "net_event_test", | 
|  | fake_dev_init, NULL, NULL, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, | 
|  | &fake_iface_api, DUMMY_L2, NET_L2_GET_CTX_TYPE(DUMMY_L2), 127); | 
|  |  | 
|  | static inline int test_requesting_nm(void) | 
|  | { | 
|  | uint32_t data = 0; | 
|  |  | 
|  | TC_PRINT("- Request Net MGMT\n"); | 
|  |  | 
|  | if (net_mgmt(TEST_MGMT_REQUEST, NULL, &data, sizeof(data))) { | 
|  | return TC_FAIL; | 
|  | } | 
|  |  | 
|  | return TC_PASS; | 
|  | } | 
|  |  | 
|  | static void thrower_thread(void) | 
|  | { | 
|  | while (1) { | 
|  | k_sem_take(&thrower_lock, K_FOREVER); | 
|  |  | 
|  | TC_PRINT("\tThrowing event 0x%08X %u times\n", | 
|  | event2throw, throw_times); | 
|  |  | 
|  | for (; throw_times; throw_times--) { | 
|  | net_mgmt_event_notify(event2throw, NULL); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | static void receiver_cb(struct net_mgmt_event_callback *cb, | 
|  | uint32_t nm_event, struct net_if *iface) | 
|  | { | 
|  | TC_PRINT("\t\tReceived event 0x%08X\n", nm_event); | 
|  |  | 
|  | rx_event = nm_event; | 
|  | rx_calls++; | 
|  | } | 
|  |  | 
|  | static inline int test_sending_event(uint32_t times, bool receiver) | 
|  | { | 
|  | int ret = TC_PASS; | 
|  |  | 
|  | TC_PRINT("- Sending event %u times, %s a receiver\n", | 
|  | times, receiver ? "with" : "without"); | 
|  |  | 
|  | event2throw = TEST_MGMT_EVENT; | 
|  | throw_times = times; | 
|  |  | 
|  | if (receiver) { | 
|  | net_mgmt_add_event_callback(&rx_cb); | 
|  | } | 
|  |  | 
|  | k_sem_give(&thrower_lock); | 
|  |  | 
|  | k_yield(); | 
|  |  | 
|  | if (receiver) { | 
|  | TC_PRINT("\tReceived 0x%08X %u times\n", | 
|  | rx_event, rx_calls); | 
|  |  | 
|  | if (rx_event != event2throw) { | 
|  | ret = TC_FAIL; | 
|  | } | 
|  |  | 
|  | if (rx_calls != times) { | 
|  | ret = TC_FAIL; | 
|  | } | 
|  |  | 
|  | net_mgmt_del_event_callback(&rx_cb); | 
|  | rx_event = rx_calls = 0; | 
|  | } | 
|  |  | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | static void initialize_event_tests(void) | 
|  | { | 
|  | event2throw = 0; | 
|  | throw_times = 0; | 
|  |  | 
|  | rx_event = 0; | 
|  | rx_calls = 0; | 
|  |  | 
|  | k_sem_init(&thrower_lock, 0, UINT_MAX); | 
|  |  | 
|  | net_mgmt_init_event_callback(&rx_cb, receiver_cb, TEST_MGMT_EVENT); | 
|  |  | 
|  | k_thread_spawn(thrower_stack, sizeof(thrower_stack), | 
|  | (k_thread_entry_t)thrower_thread, | 
|  | NULL, NULL, NULL, K_PRIO_COOP(7), 0, 0); | 
|  | } | 
|  |  | 
|  | static int test_core_event(uint32_t event, bool (*func)(void)) | 
|  | { | 
|  | int ret = TC_PASS; | 
|  |  | 
|  | TC_PRINT("- Triggering core event: 0x%08X\n", event); | 
|  |  | 
|  | net_mgmt_init_event_callback(&rx_cb, receiver_cb, event); | 
|  |  | 
|  | net_mgmt_add_event_callback(&rx_cb); | 
|  |  | 
|  | if (!func()) { | 
|  | ret = TC_FAIL; | 
|  | goto out; | 
|  | } | 
|  |  | 
|  | k_yield(); | 
|  |  | 
|  | if (!rx_calls) { | 
|  | ret = TC_FAIL; | 
|  | goto out; | 
|  | } | 
|  |  | 
|  | if (rx_event != event) { | 
|  | ret = TC_FAIL; | 
|  | } | 
|  |  | 
|  | out: | 
|  | net_mgmt_del_event_callback(&rx_cb); | 
|  | rx_event = rx_calls = 0; | 
|  |  | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | static bool _iface_ip6_add(void) | 
|  | { | 
|  | if (net_if_ipv6_addr_add(net_if_get_default(), | 
|  | &addr6, NET_ADDR_MANUAL, 0)) { | 
|  | return true; | 
|  | } | 
|  |  | 
|  | return false; | 
|  | } | 
|  |  | 
|  | static bool _iface_ip6_del(void) | 
|  | { | 
|  | if (net_if_ipv6_addr_rm(net_if_get_default(), &addr6)) { | 
|  | return true; | 
|  | } | 
|  |  | 
|  | return false; | 
|  | } | 
|  |  | 
|  | void main(void) | 
|  | { | 
|  | int status = TC_FAIL; | 
|  |  | 
|  | TC_PRINT("Starting Network Management API test\n"); | 
|  |  | 
|  | if (test_requesting_nm() != TC_PASS) { | 
|  | goto end; | 
|  | } | 
|  |  | 
|  | initialize_event_tests(); | 
|  |  | 
|  | if (test_sending_event(1, false) != TC_PASS) { | 
|  | goto end; | 
|  | } | 
|  |  | 
|  | if (test_sending_event(2, false) != TC_PASS) { | 
|  | goto end; | 
|  | } | 
|  |  | 
|  | if (test_sending_event(1, true) != TC_PASS) { | 
|  | goto end; | 
|  | } | 
|  |  | 
|  | if (test_sending_event(2, true) != TC_PASS) { | 
|  | goto end; | 
|  | } | 
|  |  | 
|  | if (test_core_event(NET_EVENT_IPV6_ADDR_ADD, | 
|  | _iface_ip6_add) != TC_PASS) { | 
|  | goto end; | 
|  | } | 
|  |  | 
|  | if (test_core_event(NET_EVENT_IPV6_ADDR_DEL, | 
|  | _iface_ip6_del) != TC_PASS) { | 
|  | goto end; | 
|  | } | 
|  |  | 
|  | status = TC_PASS; | 
|  |  | 
|  | end: | 
|  | TC_END_RESULT(status); | 
|  | TC_END_REPORT(status); | 
|  | } |