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
8 static const struct net_device_ops dummy_netdev_ops = {
9 };
10
11 struct dev_addr_test_priv {
12 u32 addr_seen;
13 };
14
dev_addr_test_sync(struct net_device * netdev,const unsigned char * a)15 static 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
dev_addr_test_unsync(struct net_device * netdev,const unsigned char * a)24 static 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
dev_addr_test_init(struct kunit * test)34 static 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
dev_addr_test_exit(struct kunit * test)56 static 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
dev_addr_test_basic(struct kunit * test)65 static 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
dev_addr_test_sync_one(struct kunit * test)81 static 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
dev_addr_test_add_del(struct kunit * test)108 static 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
dev_addr_test_del_main(struct kunit * test)148 static 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
dev_addr_test_add_set(struct kunit * test)166 static 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
dev_addr_test_add_excl(struct kunit * test)196 static 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
218 static 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
228 static 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 };
234 kunit_test_suite(dev_addr_test_suite);
235
236 MODULE_LICENSE("GPL");
237