| /* main.c - Application main entry point */ |
| |
| /* |
| * Copyright (c) 2020 Intel Corporation |
| * |
| * SPDX-License-Identifier: Apache-2.0 |
| */ |
| |
| #include <zephyr.h> |
| #include <linker/sections.h> |
| #include <ztest.h> |
| #include <random/rand32.h> |
| |
| #include <net/ethernet.h> |
| #include <net/dummy.h> |
| #include <net/net_if.h> |
| #include <net/socket.h> |
| |
| struct fake_dev_context { |
| uint8_t mac_addr[sizeof(struct net_eth_addr)]; |
| struct net_if *iface; |
| }; |
| |
| static int fake_dev_pm_control(const struct device *dev, |
| enum pm_device_state state) |
| { |
| struct fake_dev_context *ctx = dev->data; |
| int ret = 0; |
| |
| if (state == PM_DEVICE_STATE_SUSPEND) { |
| ret = net_if_suspend(ctx->iface); |
| if (ret == -EBUSY) { |
| goto out; |
| } |
| } else if (state == PM_DEVICE_STATE_ACTIVE) { |
| ret = net_if_resume(ctx->iface); |
| } |
| |
| out: |
| |
| return ret; |
| } |
| |
| |
| static int fake_dev_send(const struct device *dev, struct net_pkt *pkt) |
| { |
| ARG_UNUSED(dev); |
| ARG_UNUSED(pkt); |
| |
| return 0; |
| } |
| |
| static uint8_t *fake_dev_get_mac(struct fake_dev_context *ctx) |
| { |
| if (ctx->mac_addr[2] == 0x00) { |
| /* 00-00-5E-00-53-xx Documentation RFC 7042 */ |
| ctx->mac_addr[0] = 0x00; |
| ctx->mac_addr[1] = 0x00; |
| ctx->mac_addr[2] = 0x5E; |
| ctx->mac_addr[3] = 0x00; |
| ctx->mac_addr[4] = 0x53; |
| ctx->mac_addr[5] = sys_rand32_get(); |
| } |
| |
| return ctx->mac_addr; |
| } |
| |
| static void fake_dev_iface_init(struct net_if *iface) |
| { |
| const struct device *dev = net_if_get_device(iface); |
| struct fake_dev_context *ctx = dev->data; |
| uint8_t *mac = fake_dev_get_mac(ctx); |
| |
| net_if_set_link_addr(iface, mac, 6, NET_LINK_ETHERNET); |
| |
| ctx->iface = iface; |
| } |
| |
| int fake_dev_init(const struct device *dev) |
| { |
| ARG_UNUSED(dev); |
| |
| return 0; |
| } |
| |
| struct fake_dev_context fake_dev_context_data; |
| |
| static struct dummy_api fake_dev_if_api = { |
| .iface_api.init = fake_dev_iface_init, |
| .send = fake_dev_send, |
| }; |
| |
| #define _ETH_L2_LAYER DUMMY_L2 |
| #define _ETH_L2_CTX_TYPE NET_L2_GET_CTX_TYPE(DUMMY_L2) |
| |
| NET_DEVICE_INIT(fake_dev, "fake_dev", |
| fake_dev_init, fake_dev_pm_control, |
| &fake_dev_context_data, NULL, |
| CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, |
| &fake_dev_if_api, _ETH_L2_LAYER, _ETH_L2_CTX_TYPE, 127); |
| |
| void test_setup(void) |
| { |
| struct net_if *iface; |
| struct in_addr in4addr_my = { { { 192, 168, 0, 2 } } }; |
| struct net_if_addr *ifaddr; |
| |
| iface = net_if_get_first_by_type(&NET_L2_GET_NAME(DUMMY)); |
| |
| net_if_up(iface); |
| |
| ifaddr = net_if_ipv4_addr_add(iface, &in4addr_my, NET_ADDR_MANUAL, 0); |
| zassert_not_null(ifaddr, "Could not add iface address"); |
| } |
| |
| void test_pm(void) |
| { |
| struct net_if *iface = |
| net_if_get_first_by_type(&NET_L2_GET_NAME(DUMMY)); |
| const struct device *dev = net_if_get_device(iface); |
| char data[] = "some data"; |
| struct sockaddr_in addr4; |
| int sock; |
| int ret; |
| |
| addr4.sin_family = AF_INET; |
| addr4.sin_port = htons(12345); |
| inet_pton(AF_INET, "192.168.0.1", &addr4.sin_addr); |
| |
| sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); |
| zassert_true(sock >= 0, "Could not open socket"); |
| |
| zassert_false(net_if_is_suspended(iface), "net iface is not suspended"); |
| |
| /* Let's send some data, it should go through */ |
| ret = sendto(sock, data, ARRAY_SIZE(data), 0, |
| (struct sockaddr *)&addr4, sizeof(struct sockaddr_in)); |
| zassert_true(ret > 0, "Could not send data"); |
| |
| /* Let's make sure net stack's thread gets ran, or setting PM state |
| * might return -EBUSY instead |
| */ |
| k_yield(); |
| |
| ret = pm_device_state_set(dev, PM_DEVICE_STATE_SUSPEND); |
| zassert_true(ret == 0, "Could not set state"); |
| |
| zassert_true(net_if_is_suspended(iface), "net iface is not suspended"); |
| |
| /* Let's try to suspend it again, it should fail relevantly */ |
| ret = pm_device_state_set(dev, PM_DEVICE_STATE_SUSPEND); |
| zassert_true(ret == -EALREADY, "Could change state"); |
| |
| zassert_true(net_if_is_suspended(iface), "net iface is not suspended"); |
| |
| /* Let's send some data, it should fail relevantly */ |
| ret = sendto(sock, data, ARRAY_SIZE(data), 0, |
| (struct sockaddr *)&addr4, sizeof(struct sockaddr_in)); |
| zassert_true(ret < 0, "Could send data"); |
| |
| ret = pm_device_state_set(dev, PM_DEVICE_STATE_ACTIVE); |
| zassert_true(ret == 0, "Could not set state"); |
| |
| zassert_false(net_if_is_suspended(iface), "net iface is suspended"); |
| |
| ret = pm_device_state_set(dev, PM_DEVICE_STATE_ACTIVE); |
| zassert_true(ret == -EALREADY, "Could change state"); |
| |
| /* Let's send some data, it should go through */ |
| ret = sendto(sock, data, ARRAY_SIZE(data), 0, |
| (struct sockaddr *)&addr4, sizeof(struct sockaddr_in)); |
| zassert_true(ret > 0, "Could not send data"); |
| |
| close(sock); |
| } |
| |
| void test_main(void) |
| { |
| ztest_test_suite(test_net_pm, |
| ztest_unit_test(test_setup), |
| ztest_unit_test(test_pm)); |
| ztest_run_test_suite(test_net_pm); |
| } |