1 /* main.c - Application main entry point */
2 
3 /*
4  * Copyright (c) 2020 Intel Corporation
5  *
6  * SPDX-License-Identifier: Apache-2.0
7  */
8 
9 #include <zephyr/kernel.h>
10 #include <zephyr/linker/sections.h>
11 #include <zephyr/pm/device.h>
12 #include <zephyr/ztest.h>
13 #include <zephyr/random/random.h>
14 
15 #include <zephyr/net/ethernet.h>
16 #include <zephyr/net/dummy.h>
17 #include <zephyr/net/net_if.h>
18 #include <zephyr/net/socket.h>
19 
20 struct fake_dev_context {
21 	uint8_t mac_addr[sizeof(struct net_eth_addr)];
22 	struct net_if *iface;
23 };
24 
fake_dev_pm_action(const struct device * dev,enum pm_device_action action)25 static int fake_dev_pm_action(const struct device *dev,
26 			      enum pm_device_action action)
27 {
28 	struct fake_dev_context *ctx = dev->data;
29 	int ret;
30 
31 	switch (action) {
32 	case PM_DEVICE_ACTION_SUSPEND:
33 		ret = net_if_suspend(ctx->iface);
34 		if (ret == -EBUSY) {
35 			goto out;
36 		}
37 		break;
38 	case PM_DEVICE_ACTION_RESUME:
39 		ret = net_if_resume(ctx->iface);
40 		break;
41 	default:
42 		ret = -ENOTSUP;
43 		break;
44 	}
45 
46 out:
47 
48 	return ret;
49 }
50 
51 
fake_dev_send(const struct device * dev,struct net_pkt * pkt)52 static int fake_dev_send(const struct device *dev, struct net_pkt *pkt)
53 {
54 	ARG_UNUSED(dev);
55 	ARG_UNUSED(pkt);
56 
57 	return 0;
58 }
59 
fake_dev_get_mac(struct fake_dev_context * ctx)60 static uint8_t *fake_dev_get_mac(struct fake_dev_context *ctx)
61 {
62 	if (ctx->mac_addr[2] == 0x00) {
63 		/* 00-00-5E-00-53-xx Documentation RFC 7042 */
64 		ctx->mac_addr[0] = 0x00;
65 		ctx->mac_addr[1] = 0x00;
66 		ctx->mac_addr[2] = 0x5E;
67 		ctx->mac_addr[3] = 0x00;
68 		ctx->mac_addr[4] = 0x53;
69 		ctx->mac_addr[5] = sys_rand8_get();
70 	}
71 
72 	return ctx->mac_addr;
73 }
74 
fake_dev_iface_init(struct net_if * iface)75 static void fake_dev_iface_init(struct net_if *iface)
76 {
77 	const struct device *dev = net_if_get_device(iface);
78 	struct fake_dev_context *ctx = dev->data;
79 	uint8_t *mac = fake_dev_get_mac(ctx);
80 
81 	net_if_set_link_addr(iface, mac, 6, NET_LINK_ETHERNET);
82 
83 	ctx->iface = iface;
84 }
85 
86 struct fake_dev_context fake_dev_context_data;
87 
88 static struct dummy_api fake_dev_if_api = {
89 	.iface_api.init = fake_dev_iface_init,
90 	.send = fake_dev_send,
91 };
92 
93 #define _ETH_L2_LAYER    DUMMY_L2
94 #define _ETH_L2_CTX_TYPE NET_L2_GET_CTX_TYPE(DUMMY_L2)
95 
96 PM_DEVICE_DEFINE(fake_dev, fake_dev_pm_action);
97 
98 NET_DEVICE_INIT(fake_dev, "fake_dev",
99 		NULL, PM_DEVICE_GET(fake_dev),
100 		&fake_dev_context_data, NULL,
101 		CONFIG_KERNEL_INIT_PRIORITY_DEFAULT,
102 		&fake_dev_if_api, _ETH_L2_LAYER, _ETH_L2_CTX_TYPE, 127);
103 
test_setup(void)104 void *test_setup(void)
105 {
106 	struct net_if *iface;
107 	struct in_addr in4addr_my = { { { 192, 168, 0, 2 } } };
108 	struct net_if_addr *ifaddr;
109 
110 	iface = net_if_get_first_by_type(&NET_L2_GET_NAME(DUMMY));
111 
112 	net_if_up(iface);
113 
114 	ifaddr = net_if_ipv4_addr_add(iface, &in4addr_my, NET_ADDR_MANUAL, 0);
115 	zassert_not_null(ifaddr, "Could not add iface address");
116 	return NULL;
117 }
118 
ZTEST(test_net_pm_test_suite,test_pm)119 ZTEST(test_net_pm_test_suite, test_pm)
120 {
121 	struct net_if *iface =
122 		net_if_get_first_by_type(&NET_L2_GET_NAME(DUMMY));
123 	const struct device *dev = net_if_get_device(iface);
124 	char data[] = "some data";
125 	struct sockaddr_in addr4;
126 	int sock;
127 	int ret;
128 
129 	addr4.sin_family = AF_INET;
130 	addr4.sin_port = htons(12345);
131 	zsock_inet_pton(AF_INET, "192.168.0.1", &addr4.sin_addr);
132 
133 	sock = zsock_socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
134 	zassert_true(sock >= 0, "Could not open socket");
135 
136 	zassert_false(net_if_is_suspended(iface), "net iface is not suspended");
137 
138 	/* Let's send some data, it should go through */
139 	ret = zsock_sendto(sock, data, ARRAY_SIZE(data), 0,
140 			   (struct sockaddr *)&addr4, sizeof(struct sockaddr_in));
141 	zassert_true(ret > 0, "Could not send data");
142 
143 	/* Let's make sure net stack's thread gets ran, or setting PM state
144 	 * might return -EBUSY instead
145 	 */
146 	k_yield();
147 
148 	ret = pm_device_action_run(dev, PM_DEVICE_ACTION_SUSPEND);
149 	zassert_true(ret == 0, "Could not set state");
150 
151 	zassert_true(net_if_is_suspended(iface), "net iface is not suspended");
152 
153 	/* Let's try to suspend it again, it should fail relevantly */
154 	ret = pm_device_action_run(dev, PM_DEVICE_ACTION_SUSPEND);
155 	zassert_true(ret == -EALREADY, "Could change state");
156 
157 	zassert_true(net_if_is_suspended(iface), "net iface is not suspended");
158 
159 	/* Let's send some data, it should fail relevantly */
160 	ret = zsock_sendto(sock, data, ARRAY_SIZE(data), 0,
161 			   (struct sockaddr *)&addr4, sizeof(struct sockaddr_in));
162 	zassert_true(ret < 0, "Could send data");
163 
164 	ret = pm_device_action_run(dev, PM_DEVICE_ACTION_RESUME);
165 	zassert_true(ret == 0, "Could not set state");
166 
167 	zassert_false(net_if_is_suspended(iface), "net iface is suspended");
168 
169 	ret = pm_device_action_run(dev, PM_DEVICE_ACTION_RESUME);
170 	zassert_true(ret == -EALREADY, "Could change state");
171 
172 	/* Let's send some data, it should go through */
173 	ret = zsock_sendto(sock, data, ARRAY_SIZE(data), 0,
174 			   (struct sockaddr *)&addr4, sizeof(struct sockaddr_in));
175 	zassert_true(ret > 0, "Could not send data");
176 
177 	zsock_close(sock);
178 }
179 
180 ZTEST_SUITE(test_net_pm_test_suite, NULL, test_setup, NULL, NULL, NULL);
181