1// SPDX-License-Identifier: GPL-2.0-or-later
2
3#include <kunit/test.h>
4#include <linux/etherdevice.h>
5#include <linux/netdevice.h>
6#include <linux/rtnetlink.h>
7
8static const struct net_device_ops dummy_netdev_ops = {
9};
10
11struct dev_addr_test_priv {
12	u32 addr_seen;
13};
14
15static int dev_addr_test_sync(struct net_device *netdev, const unsigned char *a)
16{
17	struct dev_addr_test_priv *datp = netdev_priv(netdev);
18
19	if (a[0] < 31 && !memchr_inv(a, a[0], ETH_ALEN))
20		datp->addr_seen |= 1 << a[0];
21	return 0;
22}
23
24static int dev_addr_test_unsync(struct net_device *netdev,
25				const unsigned char *a)
26{
27	struct dev_addr_test_priv *datp = netdev_priv(netdev);
28
29	if (a[0] < 31 && !memchr_inv(a, a[0], ETH_ALEN))
30		datp->addr_seen &= ~(1 << a[0]);
31	return 0;
32}
33
34static int dev_addr_test_init(struct kunit *test)
35{
36	struct dev_addr_test_priv *datp;
37	struct net_device *netdev;
38	int err;
39
40	netdev = alloc_etherdev(sizeof(*datp));
41	KUNIT_ASSERT_TRUE(test, !!netdev);
42
43	test->priv = netdev;
44	netdev->netdev_ops = &dummy_netdev_ops;
45
46	err = register_netdev(netdev);
47	if (err) {
48		free_netdev(netdev);
49		KUNIT_FAIL(test, "Can't register netdev %d", err);
50	}
51
52	rtnl_lock();
53	return 0;
54}
55
56static void dev_addr_test_exit(struct kunit *test)
57{
58	struct net_device *netdev = test->priv;
59
60	rtnl_unlock();
61	unregister_netdev(netdev);
62	free_netdev(netdev);
63}
64
65static void dev_addr_test_basic(struct kunit *test)
66{
67	struct net_device *netdev = test->priv;
68	u8 addr[ETH_ALEN];
69
70	KUNIT_EXPECT_TRUE(test, !!netdev->dev_addr);
71
72	memset(addr, 2, sizeof(addr));
73	eth_hw_addr_set(netdev, addr);
74	KUNIT_EXPECT_MEMEQ(test, netdev->dev_addr, addr, sizeof(addr));
75
76	memset(addr, 3, sizeof(addr));
77	dev_addr_set(netdev, addr);
78	KUNIT_EXPECT_MEMEQ(test, netdev->dev_addr, addr, sizeof(addr));
79}
80
81static void dev_addr_test_sync_one(struct kunit *test)
82{
83	struct net_device *netdev = test->priv;
84	struct dev_addr_test_priv *datp;
85	u8 addr[ETH_ALEN];
86
87	datp = netdev_priv(netdev);
88
89	memset(addr, 1, sizeof(addr));
90	eth_hw_addr_set(netdev, addr);
91
92	__hw_addr_sync_dev(&netdev->dev_addrs, netdev, dev_addr_test_sync,
93			   dev_addr_test_unsync);
94	KUNIT_EXPECT_EQ(test, 2, datp->addr_seen);
95
96	memset(addr, 2, sizeof(addr));
97	eth_hw_addr_set(netdev, addr);
98
99	datp->addr_seen = 0;
100	__hw_addr_sync_dev(&netdev->dev_addrs, netdev, dev_addr_test_sync,
101			   dev_addr_test_unsync);
102	/* It's not going to sync anything because the main address is
103	 * considered synced and we overwrite in place.
104	 */
105	KUNIT_EXPECT_EQ(test, 0, datp->addr_seen);
106}
107
108static void dev_addr_test_add_del(struct kunit *test)
109{
110	struct net_device *netdev = test->priv;
111	struct dev_addr_test_priv *datp;
112	u8 addr[ETH_ALEN];
113	int i;
114
115	datp = netdev_priv(netdev);
116
117	for (i = 1; i < 4; i++) {
118		memset(addr, i, sizeof(addr));
119		KUNIT_EXPECT_EQ(test, 0, dev_addr_add(netdev, addr,
120						      NETDEV_HW_ADDR_T_LAN));
121	}
122	/* Add 3 again */
123	KUNIT_EXPECT_EQ(test, 0, dev_addr_add(netdev, addr,
124					      NETDEV_HW_ADDR_T_LAN));
125
126	__hw_addr_sync_dev(&netdev->dev_addrs, netdev, dev_addr_test_sync,
127			   dev_addr_test_unsync);
128	KUNIT_EXPECT_EQ(test, 0xf, datp->addr_seen);
129
130	KUNIT_EXPECT_EQ(test, 0, dev_addr_del(netdev, addr,
131					      NETDEV_HW_ADDR_T_LAN));
132
133	__hw_addr_sync_dev(&netdev->dev_addrs, netdev, dev_addr_test_sync,
134			   dev_addr_test_unsync);
135	KUNIT_EXPECT_EQ(test, 0xf, datp->addr_seen);
136
137	for (i = 1; i < 4; i++) {
138		memset(addr, i, sizeof(addr));
139		KUNIT_EXPECT_EQ(test, 0, dev_addr_del(netdev, addr,
140						      NETDEV_HW_ADDR_T_LAN));
141	}
142
143	__hw_addr_sync_dev(&netdev->dev_addrs, netdev, dev_addr_test_sync,
144			   dev_addr_test_unsync);
145	KUNIT_EXPECT_EQ(test, 1, datp->addr_seen);
146}
147
148static void dev_addr_test_del_main(struct kunit *test)
149{
150	struct net_device *netdev = test->priv;
151	u8 addr[ETH_ALEN];
152
153	memset(addr, 1, sizeof(addr));
154	eth_hw_addr_set(netdev, addr);
155
156	KUNIT_EXPECT_EQ(test, -ENOENT, dev_addr_del(netdev, addr,
157						    NETDEV_HW_ADDR_T_LAN));
158	KUNIT_EXPECT_EQ(test, 0, dev_addr_add(netdev, addr,
159					      NETDEV_HW_ADDR_T_LAN));
160	KUNIT_EXPECT_EQ(test, 0, dev_addr_del(netdev, addr,
161					      NETDEV_HW_ADDR_T_LAN));
162	KUNIT_EXPECT_EQ(test, -ENOENT, dev_addr_del(netdev, addr,
163						    NETDEV_HW_ADDR_T_LAN));
164}
165
166static void dev_addr_test_add_set(struct kunit *test)
167{
168	struct net_device *netdev = test->priv;
169	struct dev_addr_test_priv *datp;
170	u8 addr[ETH_ALEN];
171	int i;
172
173	datp = netdev_priv(netdev);
174
175	/* There is no external API like dev_addr_add_excl(),
176	 * so shuffle the tree a little bit and exploit aliasing.
177	 */
178	for (i = 1; i < 16; i++) {
179		memset(addr, i, sizeof(addr));
180		KUNIT_EXPECT_EQ(test, 0, dev_addr_add(netdev, addr,
181						      NETDEV_HW_ADDR_T_LAN));
182	}
183
184	memset(addr, i, sizeof(addr));
185	eth_hw_addr_set(netdev, addr);
186	KUNIT_EXPECT_EQ(test, 0, dev_addr_add(netdev, addr,
187					      NETDEV_HW_ADDR_T_LAN));
188	memset(addr, 0, sizeof(addr));
189	eth_hw_addr_set(netdev, addr);
190
191	__hw_addr_sync_dev(&netdev->dev_addrs, netdev, dev_addr_test_sync,
192			   dev_addr_test_unsync);
193	KUNIT_EXPECT_EQ(test, 0xffff, datp->addr_seen);
194}
195
196static void dev_addr_test_add_excl(struct kunit *test)
197{
198	struct net_device *netdev = test->priv;
199	u8 addr[ETH_ALEN];
200	int i;
201
202	for (i = 0; i < 10; i++) {
203		memset(addr, i, sizeof(addr));
204		KUNIT_EXPECT_EQ(test, 0, dev_uc_add_excl(netdev, addr));
205	}
206	KUNIT_EXPECT_EQ(test, -EEXIST, dev_uc_add_excl(netdev, addr));
207
208	for (i = 0; i < 10; i += 2) {
209		memset(addr, i, sizeof(addr));
210		KUNIT_EXPECT_EQ(test, 0, dev_uc_del(netdev, addr));
211	}
212	for (i = 1; i < 10; i += 2) {
213		memset(addr, i, sizeof(addr));
214		KUNIT_EXPECT_EQ(test, -EEXIST, dev_uc_add_excl(netdev, addr));
215	}
216}
217
218static struct kunit_case dev_addr_test_cases[] = {
219	KUNIT_CASE(dev_addr_test_basic),
220	KUNIT_CASE(dev_addr_test_sync_one),
221	KUNIT_CASE(dev_addr_test_add_del),
222	KUNIT_CASE(dev_addr_test_del_main),
223	KUNIT_CASE(dev_addr_test_add_set),
224	KUNIT_CASE(dev_addr_test_add_excl),
225	{}
226};
227
228static struct kunit_suite dev_addr_test_suite = {
229	.name = "dev-addr-list-test",
230	.test_cases = dev_addr_test_cases,
231	.init = dev_addr_test_init,
232	.exit = dev_addr_test_exit,
233};
234kunit_test_suite(dev_addr_test_suite);
235
236MODULE_DESCRIPTION("KUnit tests for struct netdev_hw_addr_list");
237MODULE_LICENSE("GPL");
238