xref: /linux/drivers/net/wireguard/selftest/allowedips.c (revision a1c613ae4c322ddd58d5a8539dbfba2a0380a8c0)
1e7096c13SJason A. Donenfeld // SPDX-License-Identifier: GPL-2.0
2e7096c13SJason A. Donenfeld /*
3e7096c13SJason A. Donenfeld  * Copyright (C) 2015-2019 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
4e7096c13SJason A. Donenfeld  *
5e7096c13SJason A. Donenfeld  * This contains some basic static unit tests for the allowedips data structure.
6e7096c13SJason A. Donenfeld  * It also has two additional modes that are disabled and meant to be used by
7e7096c13SJason A. Donenfeld  * folks directly playing with this file. If you define the macro
8e7096c13SJason A. Donenfeld  * DEBUG_PRINT_TRIE_GRAPHVIZ to be 1, then every time there's a full tree in
9e7096c13SJason A. Donenfeld  * memory, it will be printed out as KERN_DEBUG in a format that can be passed
10e7096c13SJason A. Donenfeld  * to graphviz (the dot command) to visualize it. If you define the macro
11e7096c13SJason A. Donenfeld  * DEBUG_RANDOM_TRIE to be 1, then there will be an extremely costly set of
12e7096c13SJason A. Donenfeld  * randomized tests done against a trivial implementation, which may take
13e7096c13SJason A. Donenfeld  * upwards of a half-hour to complete. There's no set of users who should be
14e7096c13SJason A. Donenfeld  * enabling these, and the only developers that should go anywhere near these
15e7096c13SJason A. Donenfeld  * nobs are the ones who are reading this comment.
16e7096c13SJason A. Donenfeld  */
17e7096c13SJason A. Donenfeld 
18e7096c13SJason A. Donenfeld #ifdef DEBUG
19e7096c13SJason A. Donenfeld 
20e7096c13SJason A. Donenfeld #include <linux/siphash.h>
21e7096c13SJason A. Donenfeld 
print_node(struct allowedips_node * node,u8 bits)22e7096c13SJason A. Donenfeld static __init void print_node(struct allowedips_node *node, u8 bits)
23e7096c13SJason A. Donenfeld {
24e7096c13SJason A. Donenfeld 	char *fmt_connection = KERN_DEBUG "\t\"%p/%d\" -> \"%p/%d\";\n";
25bf7b042dSJason A. Donenfeld 	char *fmt_declaration = KERN_DEBUG "\t\"%p/%d\"[style=%s, color=\"#%06x\"];\n";
26bf7b042dSJason A. Donenfeld 	u8 ip1[16], ip2[16], cidr1, cidr2;
27e7096c13SJason A. Donenfeld 	char *style = "dotted";
28e7096c13SJason A. Donenfeld 	u32 color = 0;
29e7096c13SJason A. Donenfeld 
30bf7b042dSJason A. Donenfeld 	if (node == NULL)
31bf7b042dSJason A. Donenfeld 		return;
32e7096c13SJason A. Donenfeld 	if (bits == 32) {
33e7096c13SJason A. Donenfeld 		fmt_connection = KERN_DEBUG "\t\"%pI4/%d\" -> \"%pI4/%d\";\n";
34bf7b042dSJason A. Donenfeld 		fmt_declaration = KERN_DEBUG "\t\"%pI4/%d\"[style=%s, color=\"#%06x\"];\n";
35e7096c13SJason A. Donenfeld 	} else if (bits == 128) {
36e7096c13SJason A. Donenfeld 		fmt_connection = KERN_DEBUG "\t\"%pI6/%d\" -> \"%pI6/%d\";\n";
37bf7b042dSJason A. Donenfeld 		fmt_declaration = KERN_DEBUG "\t\"%pI6/%d\"[style=%s, color=\"#%06x\"];\n";
38e7096c13SJason A. Donenfeld 	}
39e7096c13SJason A. Donenfeld 	if (node->peer) {
40e7096c13SJason A. Donenfeld 		hsiphash_key_t key = { { 0 } };
41e7096c13SJason A. Donenfeld 
42e7096c13SJason A. Donenfeld 		memcpy(&key, &node->peer, sizeof(node->peer));
43e7096c13SJason A. Donenfeld 		color = hsiphash_1u32(0xdeadbeef, &key) % 200 << 16 |
44e7096c13SJason A. Donenfeld 			hsiphash_1u32(0xbabecafe, &key) % 200 << 8 |
45e7096c13SJason A. Donenfeld 			hsiphash_1u32(0xabad1dea, &key) % 200;
46e7096c13SJason A. Donenfeld 		style = "bold";
47e7096c13SJason A. Donenfeld 	}
48bf7b042dSJason A. Donenfeld 	wg_allowedips_read_node(node, ip1, &cidr1);
49bf7b042dSJason A. Donenfeld 	printk(fmt_declaration, ip1, cidr1, style, color);
50e7096c13SJason A. Donenfeld 	if (node->bit[0]) {
51bf7b042dSJason A. Donenfeld 		wg_allowedips_read_node(rcu_dereference_raw(node->bit[0]), ip2, &cidr2);
52bf7b042dSJason A. Donenfeld 		printk(fmt_connection, ip1, cidr1, ip2, cidr2);
53e7096c13SJason A. Donenfeld 	}
54e7096c13SJason A. Donenfeld 	if (node->bit[1]) {
55bf7b042dSJason A. Donenfeld 		wg_allowedips_read_node(rcu_dereference_raw(node->bit[1]), ip2, &cidr2);
56bf7b042dSJason A. Donenfeld 		printk(fmt_connection, ip1, cidr1, ip2, cidr2);
57e7096c13SJason A. Donenfeld 	}
58bf7b042dSJason A. Donenfeld 	if (node->bit[0])
59bf7b042dSJason A. Donenfeld 		print_node(rcu_dereference_raw(node->bit[0]), bits);
60bf7b042dSJason A. Donenfeld 	if (node->bit[1])
61bf7b042dSJason A. Donenfeld 		print_node(rcu_dereference_raw(node->bit[1]), bits);
62e7096c13SJason A. Donenfeld }
63e7096c13SJason A. Donenfeld 
print_tree(struct allowedips_node __rcu * top,u8 bits)64e7096c13SJason A. Donenfeld static __init void print_tree(struct allowedips_node __rcu *top, u8 bits)
65e7096c13SJason A. Donenfeld {
66e7096c13SJason A. Donenfeld 	printk(KERN_DEBUG "digraph trie {\n");
67e7096c13SJason A. Donenfeld 	print_node(rcu_dereference_raw(top), bits);
68e7096c13SJason A. Donenfeld 	printk(KERN_DEBUG "}\n");
69e7096c13SJason A. Donenfeld }
70e7096c13SJason A. Donenfeld 
71e7096c13SJason A. Donenfeld enum {
72e7096c13SJason A. Donenfeld 	NUM_PEERS = 2000,
73e7096c13SJason A. Donenfeld 	NUM_RAND_ROUTES = 400,
74e7096c13SJason A. Donenfeld 	NUM_MUTATED_ROUTES = 100,
75e7096c13SJason A. Donenfeld 	NUM_QUERIES = NUM_RAND_ROUTES * NUM_MUTATED_ROUTES * 30
76e7096c13SJason A. Donenfeld };
77e7096c13SJason A. Donenfeld 
78e7096c13SJason A. Donenfeld struct horrible_allowedips {
79e7096c13SJason A. Donenfeld 	struct hlist_head head;
80e7096c13SJason A. Donenfeld };
81e7096c13SJason A. Donenfeld 
82e7096c13SJason A. Donenfeld struct horrible_allowedips_node {
83e7096c13SJason A. Donenfeld 	struct hlist_node table;
84e7096c13SJason A. Donenfeld 	union nf_inet_addr ip;
85e7096c13SJason A. Donenfeld 	union nf_inet_addr mask;
86e7096c13SJason A. Donenfeld 	u8 ip_version;
87e7096c13SJason A. Donenfeld 	void *value;
88e7096c13SJason A. Donenfeld };
89e7096c13SJason A. Donenfeld 
horrible_allowedips_init(struct horrible_allowedips * table)90e7096c13SJason A. Donenfeld static __init void horrible_allowedips_init(struct horrible_allowedips *table)
91e7096c13SJason A. Donenfeld {
92e7096c13SJason A. Donenfeld 	INIT_HLIST_HEAD(&table->head);
93e7096c13SJason A. Donenfeld }
94e7096c13SJason A. Donenfeld 
horrible_allowedips_free(struct horrible_allowedips * table)95e7096c13SJason A. Donenfeld static __init void horrible_allowedips_free(struct horrible_allowedips *table)
96e7096c13SJason A. Donenfeld {
97e7096c13SJason A. Donenfeld 	struct horrible_allowedips_node *node;
98e7096c13SJason A. Donenfeld 	struct hlist_node *h;
99e7096c13SJason A. Donenfeld 
100e7096c13SJason A. Donenfeld 	hlist_for_each_entry_safe(node, h, &table->head, table) {
101e7096c13SJason A. Donenfeld 		hlist_del(&node->table);
102e7096c13SJason A. Donenfeld 		kfree(node);
103e7096c13SJason A. Donenfeld 	}
104e7096c13SJason A. Donenfeld }
105e7096c13SJason A. Donenfeld 
horrible_cidr_to_mask(u8 cidr)106e7096c13SJason A. Donenfeld static __init inline union nf_inet_addr horrible_cidr_to_mask(u8 cidr)
107e7096c13SJason A. Donenfeld {
108e7096c13SJason A. Donenfeld 	union nf_inet_addr mask;
109e7096c13SJason A. Donenfeld 
110bf7b042dSJason A. Donenfeld 	memset(&mask, 0, sizeof(mask));
111bf7b042dSJason A. Donenfeld 	memset(&mask.all, 0xff, cidr / 8);
112e7096c13SJason A. Donenfeld 	if (cidr % 32)
113e7096c13SJason A. Donenfeld 		mask.all[cidr / 32] = (__force u32)htonl(
114e7096c13SJason A. Donenfeld 			(0xFFFFFFFFUL << (32 - (cidr % 32))) & 0xFFFFFFFFUL);
115e7096c13SJason A. Donenfeld 	return mask;
116e7096c13SJason A. Donenfeld }
117e7096c13SJason A. Donenfeld 
horrible_mask_to_cidr(union nf_inet_addr subnet)118e7096c13SJason A. Donenfeld static __init inline u8 horrible_mask_to_cidr(union nf_inet_addr subnet)
119e7096c13SJason A. Donenfeld {
120e7096c13SJason A. Donenfeld 	return hweight32(subnet.all[0]) + hweight32(subnet.all[1]) +
121e7096c13SJason A. Donenfeld 	       hweight32(subnet.all[2]) + hweight32(subnet.all[3]);
122e7096c13SJason A. Donenfeld }
123e7096c13SJason A. Donenfeld 
124e7096c13SJason A. Donenfeld static __init inline void
horrible_mask_self(struct horrible_allowedips_node * node)125e7096c13SJason A. Donenfeld horrible_mask_self(struct horrible_allowedips_node *node)
126e7096c13SJason A. Donenfeld {
127e7096c13SJason A. Donenfeld 	if (node->ip_version == 4) {
128e7096c13SJason A. Donenfeld 		node->ip.ip &= node->mask.ip;
129e7096c13SJason A. Donenfeld 	} else if (node->ip_version == 6) {
130e7096c13SJason A. Donenfeld 		node->ip.ip6[0] &= node->mask.ip6[0];
131e7096c13SJason A. Donenfeld 		node->ip.ip6[1] &= node->mask.ip6[1];
132e7096c13SJason A. Donenfeld 		node->ip.ip6[2] &= node->mask.ip6[2];
133e7096c13SJason A. Donenfeld 		node->ip.ip6[3] &= node->mask.ip6[3];
134e7096c13SJason A. Donenfeld 	}
135e7096c13SJason A. Donenfeld }
136e7096c13SJason A. Donenfeld 
137e7096c13SJason A. Donenfeld static __init inline bool
horrible_match_v4(const struct horrible_allowedips_node * node,struct in_addr * ip)138bf7b042dSJason A. Donenfeld horrible_match_v4(const struct horrible_allowedips_node *node, struct in_addr *ip)
139e7096c13SJason A. Donenfeld {
140e7096c13SJason A. Donenfeld 	return (ip->s_addr & node->mask.ip) == node->ip.ip;
141e7096c13SJason A. Donenfeld }
142e7096c13SJason A. Donenfeld 
143e7096c13SJason A. Donenfeld static __init inline bool
horrible_match_v6(const struct horrible_allowedips_node * node,struct in6_addr * ip)144bf7b042dSJason A. Donenfeld horrible_match_v6(const struct horrible_allowedips_node *node, struct in6_addr *ip)
145e7096c13SJason A. Donenfeld {
146bf7b042dSJason A. Donenfeld 	return (ip->in6_u.u6_addr32[0] & node->mask.ip6[0]) == node->ip.ip6[0] &&
147bf7b042dSJason A. Donenfeld 	       (ip->in6_u.u6_addr32[1] & node->mask.ip6[1]) == node->ip.ip6[1] &&
148bf7b042dSJason A. Donenfeld 	       (ip->in6_u.u6_addr32[2] & node->mask.ip6[2]) == node->ip.ip6[2] &&
149e7096c13SJason A. Donenfeld 	       (ip->in6_u.u6_addr32[3] & node->mask.ip6[3]) == node->ip.ip6[3];
150e7096c13SJason A. Donenfeld }
151e7096c13SJason A. Donenfeld 
152e7096c13SJason A. Donenfeld static __init void
horrible_insert_ordered(struct horrible_allowedips * table,struct horrible_allowedips_node * node)153bf7b042dSJason A. Donenfeld horrible_insert_ordered(struct horrible_allowedips *table, struct horrible_allowedips_node *node)
154e7096c13SJason A. Donenfeld {
155e7096c13SJason A. Donenfeld 	struct horrible_allowedips_node *other = NULL, *where = NULL;
156e7096c13SJason A. Donenfeld 	u8 my_cidr = horrible_mask_to_cidr(node->mask);
157e7096c13SJason A. Donenfeld 
158e7096c13SJason A. Donenfeld 	hlist_for_each_entry(other, &table->head, table) {
159bf7b042dSJason A. Donenfeld 		if (other->ip_version == node->ip_version &&
160bf7b042dSJason A. Donenfeld 		    !memcmp(&other->mask, &node->mask, sizeof(union nf_inet_addr)) &&
161bf7b042dSJason A. Donenfeld 		    !memcmp(&other->ip, &node->ip, sizeof(union nf_inet_addr))) {
162e7096c13SJason A. Donenfeld 			other->value = node->value;
163e7096c13SJason A. Donenfeld 			kfree(node);
164e7096c13SJason A. Donenfeld 			return;
165e7096c13SJason A. Donenfeld 		}
166bf7b042dSJason A. Donenfeld 	}
167bf7b042dSJason A. Donenfeld 	hlist_for_each_entry(other, &table->head, table) {
168e7096c13SJason A. Donenfeld 		where = other;
169e7096c13SJason A. Donenfeld 		if (horrible_mask_to_cidr(other->mask) <= my_cidr)
170e7096c13SJason A. Donenfeld 			break;
171e7096c13SJason A. Donenfeld 	}
172e7096c13SJason A. Donenfeld 	if (!other && !where)
173e7096c13SJason A. Donenfeld 		hlist_add_head(&node->table, &table->head);
174e7096c13SJason A. Donenfeld 	else if (!other)
175e7096c13SJason A. Donenfeld 		hlist_add_behind(&node->table, &where->table);
176e7096c13SJason A. Donenfeld 	else
177e7096c13SJason A. Donenfeld 		hlist_add_before(&node->table, &where->table);
178e7096c13SJason A. Donenfeld }
179e7096c13SJason A. Donenfeld 
180e7096c13SJason A. Donenfeld static __init int
horrible_allowedips_insert_v4(struct horrible_allowedips * table,struct in_addr * ip,u8 cidr,void * value)181e7096c13SJason A. Donenfeld horrible_allowedips_insert_v4(struct horrible_allowedips *table,
182e7096c13SJason A. Donenfeld 			      struct in_addr *ip, u8 cidr, void *value)
183e7096c13SJason A. Donenfeld {
184bf7b042dSJason A. Donenfeld 	struct horrible_allowedips_node *node = kzalloc(sizeof(*node), GFP_KERNEL);
185e7096c13SJason A. Donenfeld 
186e7096c13SJason A. Donenfeld 	if (unlikely(!node))
187e7096c13SJason A. Donenfeld 		return -ENOMEM;
188e7096c13SJason A. Donenfeld 	node->ip.in = *ip;
189e7096c13SJason A. Donenfeld 	node->mask = horrible_cidr_to_mask(cidr);
190e7096c13SJason A. Donenfeld 	node->ip_version = 4;
191e7096c13SJason A. Donenfeld 	node->value = value;
192e7096c13SJason A. Donenfeld 	horrible_mask_self(node);
193e7096c13SJason A. Donenfeld 	horrible_insert_ordered(table, node);
194e7096c13SJason A. Donenfeld 	return 0;
195e7096c13SJason A. Donenfeld }
196e7096c13SJason A. Donenfeld 
197e7096c13SJason A. Donenfeld static __init int
horrible_allowedips_insert_v6(struct horrible_allowedips * table,struct in6_addr * ip,u8 cidr,void * value)198e7096c13SJason A. Donenfeld horrible_allowedips_insert_v6(struct horrible_allowedips *table,
199e7096c13SJason A. Donenfeld 			      struct in6_addr *ip, u8 cidr, void *value)
200e7096c13SJason A. Donenfeld {
201bf7b042dSJason A. Donenfeld 	struct horrible_allowedips_node *node = kzalloc(sizeof(*node), GFP_KERNEL);
202e7096c13SJason A. Donenfeld 
203e7096c13SJason A. Donenfeld 	if (unlikely(!node))
204e7096c13SJason A. Donenfeld 		return -ENOMEM;
205e7096c13SJason A. Donenfeld 	node->ip.in6 = *ip;
206e7096c13SJason A. Donenfeld 	node->mask = horrible_cidr_to_mask(cidr);
207e7096c13SJason A. Donenfeld 	node->ip_version = 6;
208e7096c13SJason A. Donenfeld 	node->value = value;
209e7096c13SJason A. Donenfeld 	horrible_mask_self(node);
210e7096c13SJason A. Donenfeld 	horrible_insert_ordered(table, node);
211e7096c13SJason A. Donenfeld 	return 0;
212e7096c13SJason A. Donenfeld }
213e7096c13SJason A. Donenfeld 
214e7096c13SJason A. Donenfeld static __init void *
horrible_allowedips_lookup_v4(struct horrible_allowedips * table,struct in_addr * ip)215bf7b042dSJason A. Donenfeld horrible_allowedips_lookup_v4(struct horrible_allowedips *table, struct in_addr *ip)
216e7096c13SJason A. Donenfeld {
217e7096c13SJason A. Donenfeld 	struct horrible_allowedips_node *node;
218e7096c13SJason A. Donenfeld 
219e7096c13SJason A. Donenfeld 	hlist_for_each_entry(node, &table->head, table) {
220bf7b042dSJason A. Donenfeld 		if (node->ip_version == 4 && horrible_match_v4(node, ip))
221bf7b042dSJason A. Donenfeld 			return node->value;
222e7096c13SJason A. Donenfeld 	}
223bf7b042dSJason A. Donenfeld 	return NULL;
224e7096c13SJason A. Donenfeld }
225e7096c13SJason A. Donenfeld 
226e7096c13SJason A. Donenfeld static __init void *
horrible_allowedips_lookup_v6(struct horrible_allowedips * table,struct in6_addr * ip)227bf7b042dSJason A. Donenfeld horrible_allowedips_lookup_v6(struct horrible_allowedips *table, struct in6_addr *ip)
228e7096c13SJason A. Donenfeld {
229e7096c13SJason A. Donenfeld 	struct horrible_allowedips_node *node;
230e7096c13SJason A. Donenfeld 
231e7096c13SJason A. Donenfeld 	hlist_for_each_entry(node, &table->head, table) {
232bf7b042dSJason A. Donenfeld 		if (node->ip_version == 6 && horrible_match_v6(node, ip))
233bf7b042dSJason A. Donenfeld 			return node->value;
234bf7b042dSJason A. Donenfeld 	}
235bf7b042dSJason A. Donenfeld 	return NULL;
236bf7b042dSJason A. Donenfeld }
237bf7b042dSJason A. Donenfeld 
238bf7b042dSJason A. Donenfeld 
239bf7b042dSJason A. Donenfeld static __init void
horrible_allowedips_remove_by_value(struct horrible_allowedips * table,void * value)240bf7b042dSJason A. Donenfeld horrible_allowedips_remove_by_value(struct horrible_allowedips *table, void *value)
241bf7b042dSJason A. Donenfeld {
242bf7b042dSJason A. Donenfeld 	struct horrible_allowedips_node *node;
243bf7b042dSJason A. Donenfeld 	struct hlist_node *h;
244bf7b042dSJason A. Donenfeld 
245bf7b042dSJason A. Donenfeld 	hlist_for_each_entry_safe(node, h, &table->head, table) {
246bf7b042dSJason A. Donenfeld 		if (node->value != value)
247e7096c13SJason A. Donenfeld 			continue;
248bf7b042dSJason A. Donenfeld 		hlist_del(&node->table);
249bf7b042dSJason A. Donenfeld 		kfree(node);
250e7096c13SJason A. Donenfeld 	}
251bf7b042dSJason A. Donenfeld 
252e7096c13SJason A. Donenfeld }
253e7096c13SJason A. Donenfeld 
randomized_test(void)254e7096c13SJason A. Donenfeld static __init bool randomized_test(void)
255e7096c13SJason A. Donenfeld {
256e7096c13SJason A. Donenfeld 	unsigned int i, j, k, mutate_amount, cidr;
257e7096c13SJason A. Donenfeld 	u8 ip[16], mutate_mask[16], mutated[16];
258e7096c13SJason A. Donenfeld 	struct wg_peer **peers, *peer;
259e7096c13SJason A. Donenfeld 	struct horrible_allowedips h;
260e7096c13SJason A. Donenfeld 	DEFINE_MUTEX(mutex);
261e7096c13SJason A. Donenfeld 	struct allowedips t;
262e7096c13SJason A. Donenfeld 	bool ret = false;
263e7096c13SJason A. Donenfeld 
264e7096c13SJason A. Donenfeld 	mutex_init(&mutex);
265e7096c13SJason A. Donenfeld 
266e7096c13SJason A. Donenfeld 	wg_allowedips_init(&t);
267e7096c13SJason A. Donenfeld 	horrible_allowedips_init(&h);
268e7096c13SJason A. Donenfeld 
269e7096c13SJason A. Donenfeld 	peers = kcalloc(NUM_PEERS, sizeof(*peers), GFP_KERNEL);
270e7096c13SJason A. Donenfeld 	if (unlikely(!peers)) {
271e7096c13SJason A. Donenfeld 		pr_err("allowedips random self-test malloc: FAIL\n");
272e7096c13SJason A. Donenfeld 		goto free;
273e7096c13SJason A. Donenfeld 	}
274e7096c13SJason A. Donenfeld 	for (i = 0; i < NUM_PEERS; ++i) {
275e7096c13SJason A. Donenfeld 		peers[i] = kzalloc(sizeof(*peers[i]), GFP_KERNEL);
276e7096c13SJason A. Donenfeld 		if (unlikely(!peers[i])) {
277e7096c13SJason A. Donenfeld 			pr_err("allowedips random self-test malloc: FAIL\n");
278e7096c13SJason A. Donenfeld 			goto free;
279e7096c13SJason A. Donenfeld 		}
280e7096c13SJason A. Donenfeld 		kref_init(&peers[i]->refcount);
28146cfe8eeSJason A. Donenfeld 		INIT_LIST_HEAD(&peers[i]->allowedips_list);
282e7096c13SJason A. Donenfeld 	}
283e7096c13SJason A. Donenfeld 
284e7096c13SJason A. Donenfeld 	mutex_lock(&mutex);
285e7096c13SJason A. Donenfeld 
286e7096c13SJason A. Donenfeld 	for (i = 0; i < NUM_RAND_ROUTES; ++i) {
287197173dbSJason A. Donenfeld 		get_random_bytes(ip, 4);
288e8a533cbSJason A. Donenfeld 		cidr = get_random_u32_inclusive(1, 32);
2898032bf12SJason A. Donenfeld 		peer = peers[get_random_u32_below(NUM_PEERS)];
290e7096c13SJason A. Donenfeld 		if (wg_allowedips_insert_v4(&t, (struct in_addr *)ip, cidr,
291e7096c13SJason A. Donenfeld 					    peer, &mutex) < 0) {
292e7096c13SJason A. Donenfeld 			pr_err("allowedips random self-test malloc: FAIL\n");
293e7096c13SJason A. Donenfeld 			goto free_locked;
294e7096c13SJason A. Donenfeld 		}
295e7096c13SJason A. Donenfeld 		if (horrible_allowedips_insert_v4(&h, (struct in_addr *)ip,
296e7096c13SJason A. Donenfeld 						  cidr, peer) < 0) {
297e7096c13SJason A. Donenfeld 			pr_err("allowedips random self-test malloc: FAIL\n");
298e7096c13SJason A. Donenfeld 			goto free_locked;
299e7096c13SJason A. Donenfeld 		}
300e7096c13SJason A. Donenfeld 		for (j = 0; j < NUM_MUTATED_ROUTES; ++j) {
301e7096c13SJason A. Donenfeld 			memcpy(mutated, ip, 4);
302197173dbSJason A. Donenfeld 			get_random_bytes(mutate_mask, 4);
3038032bf12SJason A. Donenfeld 			mutate_amount = get_random_u32_below(32);
304e7096c13SJason A. Donenfeld 			for (k = 0; k < mutate_amount / 8; ++k)
305e7096c13SJason A. Donenfeld 				mutate_mask[k] = 0xff;
306e7096c13SJason A. Donenfeld 			mutate_mask[k] = 0xff
307e7096c13SJason A. Donenfeld 					 << ((8 - (mutate_amount % 8)) % 8);
308e7096c13SJason A. Donenfeld 			for (; k < 4; ++k)
309e7096c13SJason A. Donenfeld 				mutate_mask[k] = 0;
310e7096c13SJason A. Donenfeld 			for (k = 0; k < 4; ++k)
311e7096c13SJason A. Donenfeld 				mutated[k] = (mutated[k] & mutate_mask[k]) |
312e7096c13SJason A. Donenfeld 					     (~mutate_mask[k] &
3137e3cf084SJason A. Donenfeld 					      get_random_u8());
314e8a533cbSJason A. Donenfeld 			cidr = get_random_u32_inclusive(1, 32);
3158032bf12SJason A. Donenfeld 			peer = peers[get_random_u32_below(NUM_PEERS)];
316e7096c13SJason A. Donenfeld 			if (wg_allowedips_insert_v4(&t,
317e7096c13SJason A. Donenfeld 						    (struct in_addr *)mutated,
318e7096c13SJason A. Donenfeld 						    cidr, peer, &mutex) < 0) {
31946cfe8eeSJason A. Donenfeld 				pr_err("allowedips random self-test malloc: FAIL\n");
320e7096c13SJason A. Donenfeld 				goto free_locked;
321e7096c13SJason A. Donenfeld 			}
322e7096c13SJason A. Donenfeld 			if (horrible_allowedips_insert_v4(&h,
323e7096c13SJason A. Donenfeld 				(struct in_addr *)mutated, cidr, peer)) {
324e7096c13SJason A. Donenfeld 				pr_err("allowedips random self-test malloc: FAIL\n");
325e7096c13SJason A. Donenfeld 				goto free_locked;
326e7096c13SJason A. Donenfeld 			}
327e7096c13SJason A. Donenfeld 		}
328e7096c13SJason A. Donenfeld 	}
329e7096c13SJason A. Donenfeld 
330e7096c13SJason A. Donenfeld 	for (i = 0; i < NUM_RAND_ROUTES; ++i) {
331197173dbSJason A. Donenfeld 		get_random_bytes(ip, 16);
332e8a533cbSJason A. Donenfeld 		cidr = get_random_u32_inclusive(1, 128);
3338032bf12SJason A. Donenfeld 		peer = peers[get_random_u32_below(NUM_PEERS)];
334e7096c13SJason A. Donenfeld 		if (wg_allowedips_insert_v6(&t, (struct in6_addr *)ip, cidr,
335e7096c13SJason A. Donenfeld 					    peer, &mutex) < 0) {
336e7096c13SJason A. Donenfeld 			pr_err("allowedips random self-test malloc: FAIL\n");
337e7096c13SJason A. Donenfeld 			goto free_locked;
338e7096c13SJason A. Donenfeld 		}
339e7096c13SJason A. Donenfeld 		if (horrible_allowedips_insert_v6(&h, (struct in6_addr *)ip,
340e7096c13SJason A. Donenfeld 						  cidr, peer) < 0) {
341e7096c13SJason A. Donenfeld 			pr_err("allowedips random self-test malloc: FAIL\n");
342e7096c13SJason A. Donenfeld 			goto free_locked;
343e7096c13SJason A. Donenfeld 		}
344e7096c13SJason A. Donenfeld 		for (j = 0; j < NUM_MUTATED_ROUTES; ++j) {
345e7096c13SJason A. Donenfeld 			memcpy(mutated, ip, 16);
346197173dbSJason A. Donenfeld 			get_random_bytes(mutate_mask, 16);
3478032bf12SJason A. Donenfeld 			mutate_amount = get_random_u32_below(128);
348e7096c13SJason A. Donenfeld 			for (k = 0; k < mutate_amount / 8; ++k)
349e7096c13SJason A. Donenfeld 				mutate_mask[k] = 0xff;
350e7096c13SJason A. Donenfeld 			mutate_mask[k] = 0xff
351e7096c13SJason A. Donenfeld 					 << ((8 - (mutate_amount % 8)) % 8);
352e7096c13SJason A. Donenfeld 			for (; k < 4; ++k)
353e7096c13SJason A. Donenfeld 				mutate_mask[k] = 0;
354e7096c13SJason A. Donenfeld 			for (k = 0; k < 4; ++k)
355e7096c13SJason A. Donenfeld 				mutated[k] = (mutated[k] & mutate_mask[k]) |
356e7096c13SJason A. Donenfeld 					     (~mutate_mask[k] &
3577e3cf084SJason A. Donenfeld 					      get_random_u8());
358e8a533cbSJason A. Donenfeld 			cidr = get_random_u32_inclusive(1, 128);
3598032bf12SJason A. Donenfeld 			peer = peers[get_random_u32_below(NUM_PEERS)];
360e7096c13SJason A. Donenfeld 			if (wg_allowedips_insert_v6(&t,
361e7096c13SJason A. Donenfeld 						    (struct in6_addr *)mutated,
362e7096c13SJason A. Donenfeld 						    cidr, peer, &mutex) < 0) {
363e7096c13SJason A. Donenfeld 				pr_err("allowedips random self-test malloc: FAIL\n");
364e7096c13SJason A. Donenfeld 				goto free_locked;
365e7096c13SJason A. Donenfeld 			}
366e7096c13SJason A. Donenfeld 			if (horrible_allowedips_insert_v6(
367e7096c13SJason A. Donenfeld 				    &h, (struct in6_addr *)mutated, cidr,
368e7096c13SJason A. Donenfeld 				    peer)) {
369e7096c13SJason A. Donenfeld 				pr_err("allowedips random self-test malloc: FAIL\n");
370e7096c13SJason A. Donenfeld 				goto free_locked;
371e7096c13SJason A. Donenfeld 			}
372e7096c13SJason A. Donenfeld 		}
373e7096c13SJason A. Donenfeld 	}
374e7096c13SJason A. Donenfeld 
375e7096c13SJason A. Donenfeld 	mutex_unlock(&mutex);
376e7096c13SJason A. Donenfeld 
377e7096c13SJason A. Donenfeld 	if (IS_ENABLED(DEBUG_PRINT_TRIE_GRAPHVIZ)) {
378e7096c13SJason A. Donenfeld 		print_tree(t.root4, 32);
379e7096c13SJason A. Donenfeld 		print_tree(t.root6, 128);
380e7096c13SJason A. Donenfeld 	}
381e7096c13SJason A. Donenfeld 
382bf7b042dSJason A. Donenfeld 	for (j = 0;; ++j) {
383e7096c13SJason A. Donenfeld 		for (i = 0; i < NUM_QUERIES; ++i) {
384197173dbSJason A. Donenfeld 			get_random_bytes(ip, 4);
385bf7b042dSJason A. Donenfeld 			if (lookup(t.root4, 32, ip) != horrible_allowedips_lookup_v4(&h, (struct in_addr *)ip)) {
386bf7b042dSJason A. Donenfeld 				horrible_allowedips_lookup_v4(&h, (struct in_addr *)ip);
387bf7b042dSJason A. Donenfeld 				pr_err("allowedips random v4 self-test: FAIL\n");
388e7096c13SJason A. Donenfeld 				goto free;
389e7096c13SJason A. Donenfeld 			}
390197173dbSJason A. Donenfeld 			get_random_bytes(ip, 16);
391bf7b042dSJason A. Donenfeld 			if (lookup(t.root6, 128, ip) != horrible_allowedips_lookup_v6(&h, (struct in6_addr *)ip)) {
392bf7b042dSJason A. Donenfeld 				pr_err("allowedips random v6 self-test: FAIL\n");
393bf7b042dSJason A. Donenfeld 				goto free;
394bf7b042dSJason A. Donenfeld 			}
395bf7b042dSJason A. Donenfeld 		}
396bf7b042dSJason A. Donenfeld 		if (j >= NUM_PEERS)
397bf7b042dSJason A. Donenfeld 			break;
398bf7b042dSJason A. Donenfeld 		mutex_lock(&mutex);
399bf7b042dSJason A. Donenfeld 		wg_allowedips_remove_by_peer(&t, peers[j], &mutex);
400bf7b042dSJason A. Donenfeld 		mutex_unlock(&mutex);
401bf7b042dSJason A. Donenfeld 		horrible_allowedips_remove_by_value(&h, peers[j]);
402e7096c13SJason A. Donenfeld 	}
403e7096c13SJason A. Donenfeld 
404bf7b042dSJason A. Donenfeld 	if (t.root4 || t.root6) {
405bf7b042dSJason A. Donenfeld 		pr_err("allowedips random self-test removal: FAIL\n");
406e7096c13SJason A. Donenfeld 		goto free;
407e7096c13SJason A. Donenfeld 	}
408bf7b042dSJason A. Donenfeld 
409e7096c13SJason A. Donenfeld 	ret = true;
410e7096c13SJason A. Donenfeld 
411e7096c13SJason A. Donenfeld free:
412e7096c13SJason A. Donenfeld 	mutex_lock(&mutex);
413e7096c13SJason A. Donenfeld free_locked:
414e7096c13SJason A. Donenfeld 	wg_allowedips_free(&t, &mutex);
415e7096c13SJason A. Donenfeld 	mutex_unlock(&mutex);
416e7096c13SJason A. Donenfeld 	horrible_allowedips_free(&h);
417e7096c13SJason A. Donenfeld 	if (peers) {
418e7096c13SJason A. Donenfeld 		for (i = 0; i < NUM_PEERS; ++i)
419e7096c13SJason A. Donenfeld 			kfree(peers[i]);
420e7096c13SJason A. Donenfeld 	}
421e7096c13SJason A. Donenfeld 	kfree(peers);
422e7096c13SJason A. Donenfeld 	return ret;
423e7096c13SJason A. Donenfeld }
424e7096c13SJason A. Donenfeld 
ip4(u8 a,u8 b,u8 c,u8 d)425e7096c13SJason A. Donenfeld static __init inline struct in_addr *ip4(u8 a, u8 b, u8 c, u8 d)
426e7096c13SJason A. Donenfeld {
427e7096c13SJason A. Donenfeld 	static struct in_addr ip;
428e7096c13SJason A. Donenfeld 	u8 *split = (u8 *)&ip;
429e7096c13SJason A. Donenfeld 
430e7096c13SJason A. Donenfeld 	split[0] = a;
431e7096c13SJason A. Donenfeld 	split[1] = b;
432e7096c13SJason A. Donenfeld 	split[2] = c;
433e7096c13SJason A. Donenfeld 	split[3] = d;
434e7096c13SJason A. Donenfeld 	return &ip;
435e7096c13SJason A. Donenfeld }
436e7096c13SJason A. Donenfeld 
ip6(u32 a,u32 b,u32 c,u32 d)437e7096c13SJason A. Donenfeld static __init inline struct in6_addr *ip6(u32 a, u32 b, u32 c, u32 d)
438e7096c13SJason A. Donenfeld {
439e7096c13SJason A. Donenfeld 	static struct in6_addr ip;
440e7096c13SJason A. Donenfeld 	__be32 *split = (__be32 *)&ip;
441e7096c13SJason A. Donenfeld 
442e7096c13SJason A. Donenfeld 	split[0] = cpu_to_be32(a);
443e7096c13SJason A. Donenfeld 	split[1] = cpu_to_be32(b);
444e7096c13SJason A. Donenfeld 	split[2] = cpu_to_be32(c);
445e7096c13SJason A. Donenfeld 	split[3] = cpu_to_be32(d);
446e7096c13SJason A. Donenfeld 	return &ip;
447e7096c13SJason A. Donenfeld }
448e7096c13SJason A. Donenfeld 
init_peer(void)449e7096c13SJason A. Donenfeld static __init struct wg_peer *init_peer(void)
450e7096c13SJason A. Donenfeld {
451e7096c13SJason A. Donenfeld 	struct wg_peer *peer = kzalloc(sizeof(*peer), GFP_KERNEL);
452e7096c13SJason A. Donenfeld 
453e7096c13SJason A. Donenfeld 	if (!peer)
454e7096c13SJason A. Donenfeld 		return NULL;
455e7096c13SJason A. Donenfeld 	kref_init(&peer->refcount);
456e7096c13SJason A. Donenfeld 	INIT_LIST_HEAD(&peer->allowedips_list);
457e7096c13SJason A. Donenfeld 	return peer;
458e7096c13SJason A. Donenfeld }
459e7096c13SJason A. Donenfeld 
460e7096c13SJason A. Donenfeld #define insert(version, mem, ipa, ipb, ipc, ipd, cidr)                       \
461e7096c13SJason A. Donenfeld 	wg_allowedips_insert_v##version(&t, ip##version(ipa, ipb, ipc, ipd), \
462e7096c13SJason A. Donenfeld 					cidr, mem, &mutex)
463e7096c13SJason A. Donenfeld 
464e7096c13SJason A. Donenfeld #define maybe_fail() do {                                               \
465e7096c13SJason A. Donenfeld 		++i;                                                    \
466e7096c13SJason A. Donenfeld 		if (!_s) {                                              \
467e7096c13SJason A. Donenfeld 			pr_info("allowedips self-test %zu: FAIL\n", i); \
468e7096c13SJason A. Donenfeld 			success = false;                                \
469e7096c13SJason A. Donenfeld 		}                                                       \
470e7096c13SJason A. Donenfeld 	} while (0)
471e7096c13SJason A. Donenfeld 
472e7096c13SJason A. Donenfeld #define test(version, mem, ipa, ipb, ipc, ipd) do {                          \
473e7096c13SJason A. Donenfeld 		bool _s = lookup(t.root##version, (version) == 4 ? 32 : 128, \
474e7096c13SJason A. Donenfeld 				 ip##version(ipa, ipb, ipc, ipd)) == (mem);  \
475e7096c13SJason A. Donenfeld 		maybe_fail();                                                \
476e7096c13SJason A. Donenfeld 	} while (0)
477e7096c13SJason A. Donenfeld 
478e7096c13SJason A. Donenfeld #define test_negative(version, mem, ipa, ipb, ipc, ipd) do {                 \
479e7096c13SJason A. Donenfeld 		bool _s = lookup(t.root##version, (version) == 4 ? 32 : 128, \
480e7096c13SJason A. Donenfeld 				 ip##version(ipa, ipb, ipc, ipd)) != (mem);  \
481e7096c13SJason A. Donenfeld 		maybe_fail();                                                \
482e7096c13SJason A. Donenfeld 	} while (0)
483e7096c13SJason A. Donenfeld 
484e7096c13SJason A. Donenfeld #define test_boolean(cond) do {   \
485e7096c13SJason A. Donenfeld 		bool _s = (cond); \
486e7096c13SJason A. Donenfeld 		maybe_fail();     \
487e7096c13SJason A. Donenfeld 	} while (0)
488e7096c13SJason A. Donenfeld 
wg_allowedips_selftest(void)489e7096c13SJason A. Donenfeld bool __init wg_allowedips_selftest(void)
490e7096c13SJason A. Donenfeld {
491e7096c13SJason A. Donenfeld 	bool found_a = false, found_b = false, found_c = false, found_d = false,
492e7096c13SJason A. Donenfeld 	     found_e = false, found_other = false;
493e7096c13SJason A. Donenfeld 	struct wg_peer *a = init_peer(), *b = init_peer(), *c = init_peer(),
494e7096c13SJason A. Donenfeld 		       *d = init_peer(), *e = init_peer(), *f = init_peer(),
495e7096c13SJason A. Donenfeld 		       *g = init_peer(), *h = init_peer();
496e7096c13SJason A. Donenfeld 	struct allowedips_node *iter_node;
497e7096c13SJason A. Donenfeld 	bool success = false;
498e7096c13SJason A. Donenfeld 	struct allowedips t;
499e7096c13SJason A. Donenfeld 	DEFINE_MUTEX(mutex);
500e7096c13SJason A. Donenfeld 	struct in6_addr ip;
501e7096c13SJason A. Donenfeld 	size_t i = 0, count = 0;
502e7096c13SJason A. Donenfeld 	__be64 part;
503e7096c13SJason A. Donenfeld 
504e7096c13SJason A. Donenfeld 	mutex_init(&mutex);
505e7096c13SJason A. Donenfeld 	mutex_lock(&mutex);
506e7096c13SJason A. Donenfeld 	wg_allowedips_init(&t);
507e7096c13SJason A. Donenfeld 
508e7096c13SJason A. Donenfeld 	if (!a || !b || !c || !d || !e || !f || !g || !h) {
509e7096c13SJason A. Donenfeld 		pr_err("allowedips self-test malloc: FAIL\n");
510e7096c13SJason A. Donenfeld 		goto free;
511e7096c13SJason A. Donenfeld 	}
512e7096c13SJason A. Donenfeld 
513e7096c13SJason A. Donenfeld 	insert(4, a, 192, 168, 4, 0, 24);
514e7096c13SJason A. Donenfeld 	insert(4, b, 192, 168, 4, 4, 32);
515e7096c13SJason A. Donenfeld 	insert(4, c, 192, 168, 0, 0, 16);
516e7096c13SJason A. Donenfeld 	insert(4, d, 192, 95, 5, 64, 27);
517e7096c13SJason A. Donenfeld 	/* replaces previous entry, and maskself is required */
518e7096c13SJason A. Donenfeld 	insert(4, c, 192, 95, 5, 65, 27);
519e7096c13SJason A. Donenfeld 	insert(6, d, 0x26075300, 0x60006b00, 0, 0xc05f0543, 128);
520e7096c13SJason A. Donenfeld 	insert(6, c, 0x26075300, 0x60006b00, 0, 0, 64);
521e7096c13SJason A. Donenfeld 	insert(4, e, 0, 0, 0, 0, 0);
522e7096c13SJason A. Donenfeld 	insert(6, e, 0, 0, 0, 0, 0);
523e7096c13SJason A. Donenfeld 	/* replaces previous entry */
524e7096c13SJason A. Donenfeld 	insert(6, f, 0, 0, 0, 0, 0);
525e7096c13SJason A. Donenfeld 	insert(6, g, 0x24046800, 0, 0, 0, 32);
526e7096c13SJason A. Donenfeld 	/* maskself is required */
527e7096c13SJason A. Donenfeld 	insert(6, h, 0x24046800, 0x40040800, 0xdeadbeef, 0xdeadbeef, 64);
528e7096c13SJason A. Donenfeld 	insert(6, a, 0x24046800, 0x40040800, 0xdeadbeef, 0xdeadbeef, 128);
529e7096c13SJason A. Donenfeld 	insert(6, c, 0x24446800, 0x40e40800, 0xdeaebeef, 0xdefbeef, 128);
530e7096c13SJason A. Donenfeld 	insert(6, b, 0x24446800, 0xf0e40800, 0xeeaebeef, 0, 98);
531e7096c13SJason A. Donenfeld 	insert(4, g, 64, 15, 112, 0, 20);
532e7096c13SJason A. Donenfeld 	/* maskself is required */
533e7096c13SJason A. Donenfeld 	insert(4, h, 64, 15, 123, 211, 25);
534e7096c13SJason A. Donenfeld 	insert(4, a, 10, 0, 0, 0, 25);
535e7096c13SJason A. Donenfeld 	insert(4, b, 10, 0, 0, 128, 25);
536e7096c13SJason A. Donenfeld 	insert(4, a, 10, 1, 0, 0, 30);
537e7096c13SJason A. Donenfeld 	insert(4, b, 10, 1, 0, 4, 30);
538e7096c13SJason A. Donenfeld 	insert(4, c, 10, 1, 0, 8, 29);
539e7096c13SJason A. Donenfeld 	insert(4, d, 10, 1, 0, 16, 29);
540e7096c13SJason A. Donenfeld 
541e7096c13SJason A. Donenfeld 	if (IS_ENABLED(DEBUG_PRINT_TRIE_GRAPHVIZ)) {
542e7096c13SJason A. Donenfeld 		print_tree(t.root4, 32);
543e7096c13SJason A. Donenfeld 		print_tree(t.root6, 128);
544e7096c13SJason A. Donenfeld 	}
545e7096c13SJason A. Donenfeld 
546e7096c13SJason A. Donenfeld 	success = true;
547e7096c13SJason A. Donenfeld 
548e7096c13SJason A. Donenfeld 	test(4, a, 192, 168, 4, 20);
549e7096c13SJason A. Donenfeld 	test(4, a, 192, 168, 4, 0);
550e7096c13SJason A. Donenfeld 	test(4, b, 192, 168, 4, 4);
551e7096c13SJason A. Donenfeld 	test(4, c, 192, 168, 200, 182);
552e7096c13SJason A. Donenfeld 	test(4, c, 192, 95, 5, 68);
553e7096c13SJason A. Donenfeld 	test(4, e, 192, 95, 5, 96);
554e7096c13SJason A. Donenfeld 	test(6, d, 0x26075300, 0x60006b00, 0, 0xc05f0543);
555e7096c13SJason A. Donenfeld 	test(6, c, 0x26075300, 0x60006b00, 0, 0xc02e01ee);
556e7096c13SJason A. Donenfeld 	test(6, f, 0x26075300, 0x60006b01, 0, 0);
557e7096c13SJason A. Donenfeld 	test(6, g, 0x24046800, 0x40040806, 0, 0x1006);
558e7096c13SJason A. Donenfeld 	test(6, g, 0x24046800, 0x40040806, 0x1234, 0x5678);
559e7096c13SJason A. Donenfeld 	test(6, f, 0x240467ff, 0x40040806, 0x1234, 0x5678);
560e7096c13SJason A. Donenfeld 	test(6, f, 0x24046801, 0x40040806, 0x1234, 0x5678);
561e7096c13SJason A. Donenfeld 	test(6, h, 0x24046800, 0x40040800, 0x1234, 0x5678);
562e7096c13SJason A. Donenfeld 	test(6, h, 0x24046800, 0x40040800, 0, 0);
563e7096c13SJason A. Donenfeld 	test(6, h, 0x24046800, 0x40040800, 0x10101010, 0x10101010);
564e7096c13SJason A. Donenfeld 	test(6, a, 0x24046800, 0x40040800, 0xdeadbeef, 0xdeadbeef);
565e7096c13SJason A. Donenfeld 	test(4, g, 64, 15, 116, 26);
566e7096c13SJason A. Donenfeld 	test(4, g, 64, 15, 127, 3);
567e7096c13SJason A. Donenfeld 	test(4, g, 64, 15, 123, 1);
568e7096c13SJason A. Donenfeld 	test(4, h, 64, 15, 123, 128);
569e7096c13SJason A. Donenfeld 	test(4, h, 64, 15, 123, 129);
570e7096c13SJason A. Donenfeld 	test(4, a, 10, 0, 0, 52);
571e7096c13SJason A. Donenfeld 	test(4, b, 10, 0, 0, 220);
572e7096c13SJason A. Donenfeld 	test(4, a, 10, 1, 0, 2);
573e7096c13SJason A. Donenfeld 	test(4, b, 10, 1, 0, 6);
574e7096c13SJason A. Donenfeld 	test(4, c, 10, 1, 0, 10);
575e7096c13SJason A. Donenfeld 	test(4, d, 10, 1, 0, 20);
576e7096c13SJason A. Donenfeld 
577e7096c13SJason A. Donenfeld 	insert(4, a, 1, 0, 0, 0, 32);
578e7096c13SJason A. Donenfeld 	insert(4, a, 64, 0, 0, 0, 32);
579e7096c13SJason A. Donenfeld 	insert(4, a, 128, 0, 0, 0, 32);
580e7096c13SJason A. Donenfeld 	insert(4, a, 192, 0, 0, 0, 32);
581e7096c13SJason A. Donenfeld 	insert(4, a, 255, 0, 0, 0, 32);
582e7096c13SJason A. Donenfeld 	wg_allowedips_remove_by_peer(&t, a, &mutex);
583e7096c13SJason A. Donenfeld 	test_negative(4, a, 1, 0, 0, 0);
584e7096c13SJason A. Donenfeld 	test_negative(4, a, 64, 0, 0, 0);
585e7096c13SJason A. Donenfeld 	test_negative(4, a, 128, 0, 0, 0);
586e7096c13SJason A. Donenfeld 	test_negative(4, a, 192, 0, 0, 0);
587e7096c13SJason A. Donenfeld 	test_negative(4, a, 255, 0, 0, 0);
588e7096c13SJason A. Donenfeld 
589e7096c13SJason A. Donenfeld 	wg_allowedips_free(&t, &mutex);
590e7096c13SJason A. Donenfeld 	wg_allowedips_init(&t);
591e7096c13SJason A. Donenfeld 	insert(4, a, 192, 168, 0, 0, 16);
592e7096c13SJason A. Donenfeld 	insert(4, a, 192, 168, 0, 0, 24);
593e7096c13SJason A. Donenfeld 	wg_allowedips_remove_by_peer(&t, a, &mutex);
594e7096c13SJason A. Donenfeld 	test_negative(4, a, 192, 168, 0, 1);
595e7096c13SJason A. Donenfeld 
596*46622219SJason A. Donenfeld 	/* These will hit the WARN_ON(len >= MAX_ALLOWEDIPS_DEPTH) in free_node
597c31b14d8SJason A. Donenfeld 	 * if something goes wrong.
598e7096c13SJason A. Donenfeld 	 */
599*46622219SJason A. Donenfeld 	for (i = 0; i < 64; ++i) {
600*46622219SJason A. Donenfeld 		part = cpu_to_be64(~0LLU << i);
601*46622219SJason A. Donenfeld 		memset(&ip, 0xff, 8);
602*46622219SJason A. Donenfeld 		memcpy((u8 *)&ip + 8, &part, 8);
603*46622219SJason A. Donenfeld 		wg_allowedips_insert_v6(&t, &ip, 128, a, &mutex);
604*46622219SJason A. Donenfeld 		memcpy(&ip, &part, 8);
605*46622219SJason A. Donenfeld 		memset((u8 *)&ip + 8, 0, 8);
606e7096c13SJason A. Donenfeld 		wg_allowedips_insert_v6(&t, &ip, 128, a, &mutex);
607e7096c13SJason A. Donenfeld 	}
608*46622219SJason A. Donenfeld 	memset(&ip, 0, 16);
609*46622219SJason A. Donenfeld 	wg_allowedips_insert_v6(&t, &ip, 128, a, &mutex);
610e7096c13SJason A. Donenfeld 	wg_allowedips_free(&t, &mutex);
611e7096c13SJason A. Donenfeld 
612e7096c13SJason A. Donenfeld 	wg_allowedips_init(&t);
613e7096c13SJason A. Donenfeld 	insert(4, a, 192, 95, 5, 93, 27);
614e7096c13SJason A. Donenfeld 	insert(6, a, 0x26075300, 0x60006b00, 0, 0xc05f0543, 128);
615e7096c13SJason A. Donenfeld 	insert(4, a, 10, 1, 0, 20, 29);
616e7096c13SJason A. Donenfeld 	insert(6, a, 0x26075300, 0x6d8a6bf8, 0xdab1f1df, 0xc05f1523, 83);
617e7096c13SJason A. Donenfeld 	insert(6, a, 0x26075300, 0x6d8a6bf8, 0xdab1f1df, 0xc05f1523, 21);
618e7096c13SJason A. Donenfeld 	list_for_each_entry(iter_node, &a->allowedips_list, peer_list) {
619e7096c13SJason A. Donenfeld 		u8 cidr, ip[16] __aligned(__alignof(u64));
620e7096c13SJason A. Donenfeld 		int family = wg_allowedips_read_node(iter_node, ip, &cidr);
621e7096c13SJason A. Donenfeld 
622e7096c13SJason A. Donenfeld 		count++;
623e7096c13SJason A. Donenfeld 
624e7096c13SJason A. Donenfeld 		if (cidr == 27 && family == AF_INET &&
625e7096c13SJason A. Donenfeld 		    !memcmp(ip, ip4(192, 95, 5, 64), sizeof(struct in_addr)))
626e7096c13SJason A. Donenfeld 			found_a = true;
627e7096c13SJason A. Donenfeld 		else if (cidr == 128 && family == AF_INET6 &&
628e7096c13SJason A. Donenfeld 			 !memcmp(ip, ip6(0x26075300, 0x60006b00, 0, 0xc05f0543),
629e7096c13SJason A. Donenfeld 				 sizeof(struct in6_addr)))
630e7096c13SJason A. Donenfeld 			found_b = true;
631e7096c13SJason A. Donenfeld 		else if (cidr == 29 && family == AF_INET &&
632e7096c13SJason A. Donenfeld 			 !memcmp(ip, ip4(10, 1, 0, 16), sizeof(struct in_addr)))
633e7096c13SJason A. Donenfeld 			found_c = true;
634e7096c13SJason A. Donenfeld 		else if (cidr == 83 && family == AF_INET6 &&
635e7096c13SJason A. Donenfeld 			 !memcmp(ip, ip6(0x26075300, 0x6d8a6bf8, 0xdab1e000, 0),
636e7096c13SJason A. Donenfeld 				 sizeof(struct in6_addr)))
637e7096c13SJason A. Donenfeld 			found_d = true;
638e7096c13SJason A. Donenfeld 		else if (cidr == 21 && family == AF_INET6 &&
639e7096c13SJason A. Donenfeld 			 !memcmp(ip, ip6(0x26075000, 0, 0, 0),
640e7096c13SJason A. Donenfeld 				 sizeof(struct in6_addr)))
641e7096c13SJason A. Donenfeld 			found_e = true;
642e7096c13SJason A. Donenfeld 		else
643e7096c13SJason A. Donenfeld 			found_other = true;
644e7096c13SJason A. Donenfeld 	}
645e7096c13SJason A. Donenfeld 	test_boolean(count == 5);
646e7096c13SJason A. Donenfeld 	test_boolean(found_a);
647e7096c13SJason A. Donenfeld 	test_boolean(found_b);
648e7096c13SJason A. Donenfeld 	test_boolean(found_c);
649e7096c13SJason A. Donenfeld 	test_boolean(found_d);
650e7096c13SJason A. Donenfeld 	test_boolean(found_e);
651e7096c13SJason A. Donenfeld 	test_boolean(!found_other);
652e7096c13SJason A. Donenfeld 
653e7096c13SJason A. Donenfeld 	if (IS_ENABLED(DEBUG_RANDOM_TRIE) && success)
654e7096c13SJason A. Donenfeld 		success = randomized_test();
655e7096c13SJason A. Donenfeld 
656e7096c13SJason A. Donenfeld 	if (success)
657e7096c13SJason A. Donenfeld 		pr_info("allowedips self-tests: pass\n");
658e7096c13SJason A. Donenfeld 
659e7096c13SJason A. Donenfeld free:
660e7096c13SJason A. Donenfeld 	wg_allowedips_free(&t, &mutex);
661e7096c13SJason A. Donenfeld 	kfree(a);
662e7096c13SJason A. Donenfeld 	kfree(b);
663e7096c13SJason A. Donenfeld 	kfree(c);
664e7096c13SJason A. Donenfeld 	kfree(d);
665e7096c13SJason A. Donenfeld 	kfree(e);
666e7096c13SJason A. Donenfeld 	kfree(f);
667e7096c13SJason A. Donenfeld 	kfree(g);
668e7096c13SJason A. Donenfeld 	kfree(h);
669e7096c13SJason A. Donenfeld 	mutex_unlock(&mutex);
670e7096c13SJason A. Donenfeld 
671e7096c13SJason A. Donenfeld 	return success;
672e7096c13SJason A. Donenfeld }
673e7096c13SJason A. Donenfeld 
674e7096c13SJason A. Donenfeld #undef test_negative
675e7096c13SJason A. Donenfeld #undef test
676e7096c13SJason A. Donenfeld #undef remove
677e7096c13SJason A. Donenfeld #undef insert
678e7096c13SJason A. Donenfeld #undef init_peer
679e7096c13SJason A. Donenfeld 
680e7096c13SJason A. Donenfeld #endif
681