162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (C) 2015-2019 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * This contains some basic static unit tests for the allowedips data structure.
662306a36Sopenharmony_ci * It also has two additional modes that are disabled and meant to be used by
762306a36Sopenharmony_ci * folks directly playing with this file. If you define the macro
862306a36Sopenharmony_ci * DEBUG_PRINT_TRIE_GRAPHVIZ to be 1, then every time there's a full tree in
962306a36Sopenharmony_ci * memory, it will be printed out as KERN_DEBUG in a format that can be passed
1062306a36Sopenharmony_ci * to graphviz (the dot command) to visualize it. If you define the macro
1162306a36Sopenharmony_ci * DEBUG_RANDOM_TRIE to be 1, then there will be an extremely costly set of
1262306a36Sopenharmony_ci * randomized tests done against a trivial implementation, which may take
1362306a36Sopenharmony_ci * upwards of a half-hour to complete. There's no set of users who should be
1462306a36Sopenharmony_ci * enabling these, and the only developers that should go anywhere near these
1562306a36Sopenharmony_ci * nobs are the ones who are reading this comment.
1662306a36Sopenharmony_ci */
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci#ifdef DEBUG
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci#include <linux/siphash.h>
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_cistatic __init void print_node(struct allowedips_node *node, u8 bits)
2362306a36Sopenharmony_ci{
2462306a36Sopenharmony_ci	char *fmt_connection = KERN_DEBUG "\t\"%p/%d\" -> \"%p/%d\";\n";
2562306a36Sopenharmony_ci	char *fmt_declaration = KERN_DEBUG "\t\"%p/%d\"[style=%s, color=\"#%06x\"];\n";
2662306a36Sopenharmony_ci	u8 ip1[16], ip2[16], cidr1, cidr2;
2762306a36Sopenharmony_ci	char *style = "dotted";
2862306a36Sopenharmony_ci	u32 color = 0;
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci	if (node == NULL)
3162306a36Sopenharmony_ci		return;
3262306a36Sopenharmony_ci	if (bits == 32) {
3362306a36Sopenharmony_ci		fmt_connection = KERN_DEBUG "\t\"%pI4/%d\" -> \"%pI4/%d\";\n";
3462306a36Sopenharmony_ci		fmt_declaration = KERN_DEBUG "\t\"%pI4/%d\"[style=%s, color=\"#%06x\"];\n";
3562306a36Sopenharmony_ci	} else if (bits == 128) {
3662306a36Sopenharmony_ci		fmt_connection = KERN_DEBUG "\t\"%pI6/%d\" -> \"%pI6/%d\";\n";
3762306a36Sopenharmony_ci		fmt_declaration = KERN_DEBUG "\t\"%pI6/%d\"[style=%s, color=\"#%06x\"];\n";
3862306a36Sopenharmony_ci	}
3962306a36Sopenharmony_ci	if (node->peer) {
4062306a36Sopenharmony_ci		hsiphash_key_t key = { { 0 } };
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci		memcpy(&key, &node->peer, sizeof(node->peer));
4362306a36Sopenharmony_ci		color = hsiphash_1u32(0xdeadbeef, &key) % 200 << 16 |
4462306a36Sopenharmony_ci			hsiphash_1u32(0xbabecafe, &key) % 200 << 8 |
4562306a36Sopenharmony_ci			hsiphash_1u32(0xabad1dea, &key) % 200;
4662306a36Sopenharmony_ci		style = "bold";
4762306a36Sopenharmony_ci	}
4862306a36Sopenharmony_ci	wg_allowedips_read_node(node, ip1, &cidr1);
4962306a36Sopenharmony_ci	printk(fmt_declaration, ip1, cidr1, style, color);
5062306a36Sopenharmony_ci	if (node->bit[0]) {
5162306a36Sopenharmony_ci		wg_allowedips_read_node(rcu_dereference_raw(node->bit[0]), ip2, &cidr2);
5262306a36Sopenharmony_ci		printk(fmt_connection, ip1, cidr1, ip2, cidr2);
5362306a36Sopenharmony_ci	}
5462306a36Sopenharmony_ci	if (node->bit[1]) {
5562306a36Sopenharmony_ci		wg_allowedips_read_node(rcu_dereference_raw(node->bit[1]), ip2, &cidr2);
5662306a36Sopenharmony_ci		printk(fmt_connection, ip1, cidr1, ip2, cidr2);
5762306a36Sopenharmony_ci	}
5862306a36Sopenharmony_ci	if (node->bit[0])
5962306a36Sopenharmony_ci		print_node(rcu_dereference_raw(node->bit[0]), bits);
6062306a36Sopenharmony_ci	if (node->bit[1])
6162306a36Sopenharmony_ci		print_node(rcu_dereference_raw(node->bit[1]), bits);
6262306a36Sopenharmony_ci}
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_cistatic __init void print_tree(struct allowedips_node __rcu *top, u8 bits)
6562306a36Sopenharmony_ci{
6662306a36Sopenharmony_ci	printk(KERN_DEBUG "digraph trie {\n");
6762306a36Sopenharmony_ci	print_node(rcu_dereference_raw(top), bits);
6862306a36Sopenharmony_ci	printk(KERN_DEBUG "}\n");
6962306a36Sopenharmony_ci}
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_cienum {
7262306a36Sopenharmony_ci	NUM_PEERS = 2000,
7362306a36Sopenharmony_ci	NUM_RAND_ROUTES = 400,
7462306a36Sopenharmony_ci	NUM_MUTATED_ROUTES = 100,
7562306a36Sopenharmony_ci	NUM_QUERIES = NUM_RAND_ROUTES * NUM_MUTATED_ROUTES * 30
7662306a36Sopenharmony_ci};
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_cistruct horrible_allowedips {
7962306a36Sopenharmony_ci	struct hlist_head head;
8062306a36Sopenharmony_ci};
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_cistruct horrible_allowedips_node {
8362306a36Sopenharmony_ci	struct hlist_node table;
8462306a36Sopenharmony_ci	union nf_inet_addr ip;
8562306a36Sopenharmony_ci	union nf_inet_addr mask;
8662306a36Sopenharmony_ci	u8 ip_version;
8762306a36Sopenharmony_ci	void *value;
8862306a36Sopenharmony_ci};
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_cistatic __init void horrible_allowedips_init(struct horrible_allowedips *table)
9162306a36Sopenharmony_ci{
9262306a36Sopenharmony_ci	INIT_HLIST_HEAD(&table->head);
9362306a36Sopenharmony_ci}
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_cistatic __init void horrible_allowedips_free(struct horrible_allowedips *table)
9662306a36Sopenharmony_ci{
9762306a36Sopenharmony_ci	struct horrible_allowedips_node *node;
9862306a36Sopenharmony_ci	struct hlist_node *h;
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci	hlist_for_each_entry_safe(node, h, &table->head, table) {
10162306a36Sopenharmony_ci		hlist_del(&node->table);
10262306a36Sopenharmony_ci		kfree(node);
10362306a36Sopenharmony_ci	}
10462306a36Sopenharmony_ci}
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_cistatic __init inline union nf_inet_addr horrible_cidr_to_mask(u8 cidr)
10762306a36Sopenharmony_ci{
10862306a36Sopenharmony_ci	union nf_inet_addr mask;
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci	memset(&mask, 0, sizeof(mask));
11162306a36Sopenharmony_ci	memset(&mask.all, 0xff, cidr / 8);
11262306a36Sopenharmony_ci	if (cidr % 32)
11362306a36Sopenharmony_ci		mask.all[cidr / 32] = (__force u32)htonl(
11462306a36Sopenharmony_ci			(0xFFFFFFFFUL << (32 - (cidr % 32))) & 0xFFFFFFFFUL);
11562306a36Sopenharmony_ci	return mask;
11662306a36Sopenharmony_ci}
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_cistatic __init inline u8 horrible_mask_to_cidr(union nf_inet_addr subnet)
11962306a36Sopenharmony_ci{
12062306a36Sopenharmony_ci	return hweight32(subnet.all[0]) + hweight32(subnet.all[1]) +
12162306a36Sopenharmony_ci	       hweight32(subnet.all[2]) + hweight32(subnet.all[3]);
12262306a36Sopenharmony_ci}
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_cistatic __init inline void
12562306a36Sopenharmony_cihorrible_mask_self(struct horrible_allowedips_node *node)
12662306a36Sopenharmony_ci{
12762306a36Sopenharmony_ci	if (node->ip_version == 4) {
12862306a36Sopenharmony_ci		node->ip.ip &= node->mask.ip;
12962306a36Sopenharmony_ci	} else if (node->ip_version == 6) {
13062306a36Sopenharmony_ci		node->ip.ip6[0] &= node->mask.ip6[0];
13162306a36Sopenharmony_ci		node->ip.ip6[1] &= node->mask.ip6[1];
13262306a36Sopenharmony_ci		node->ip.ip6[2] &= node->mask.ip6[2];
13362306a36Sopenharmony_ci		node->ip.ip6[3] &= node->mask.ip6[3];
13462306a36Sopenharmony_ci	}
13562306a36Sopenharmony_ci}
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_cistatic __init inline bool
13862306a36Sopenharmony_cihorrible_match_v4(const struct horrible_allowedips_node *node, struct in_addr *ip)
13962306a36Sopenharmony_ci{
14062306a36Sopenharmony_ci	return (ip->s_addr & node->mask.ip) == node->ip.ip;
14162306a36Sopenharmony_ci}
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_cistatic __init inline bool
14462306a36Sopenharmony_cihorrible_match_v6(const struct horrible_allowedips_node *node, struct in6_addr *ip)
14562306a36Sopenharmony_ci{
14662306a36Sopenharmony_ci	return (ip->in6_u.u6_addr32[0] & node->mask.ip6[0]) == node->ip.ip6[0] &&
14762306a36Sopenharmony_ci	       (ip->in6_u.u6_addr32[1] & node->mask.ip6[1]) == node->ip.ip6[1] &&
14862306a36Sopenharmony_ci	       (ip->in6_u.u6_addr32[2] & node->mask.ip6[2]) == node->ip.ip6[2] &&
14962306a36Sopenharmony_ci	       (ip->in6_u.u6_addr32[3] & node->mask.ip6[3]) == node->ip.ip6[3];
15062306a36Sopenharmony_ci}
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_cistatic __init void
15362306a36Sopenharmony_cihorrible_insert_ordered(struct horrible_allowedips *table, struct horrible_allowedips_node *node)
15462306a36Sopenharmony_ci{
15562306a36Sopenharmony_ci	struct horrible_allowedips_node *other = NULL, *where = NULL;
15662306a36Sopenharmony_ci	u8 my_cidr = horrible_mask_to_cidr(node->mask);
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci	hlist_for_each_entry(other, &table->head, table) {
15962306a36Sopenharmony_ci		if (other->ip_version == node->ip_version &&
16062306a36Sopenharmony_ci		    !memcmp(&other->mask, &node->mask, sizeof(union nf_inet_addr)) &&
16162306a36Sopenharmony_ci		    !memcmp(&other->ip, &node->ip, sizeof(union nf_inet_addr))) {
16262306a36Sopenharmony_ci			other->value = node->value;
16362306a36Sopenharmony_ci			kfree(node);
16462306a36Sopenharmony_ci			return;
16562306a36Sopenharmony_ci		}
16662306a36Sopenharmony_ci	}
16762306a36Sopenharmony_ci	hlist_for_each_entry(other, &table->head, table) {
16862306a36Sopenharmony_ci		where = other;
16962306a36Sopenharmony_ci		if (horrible_mask_to_cidr(other->mask) <= my_cidr)
17062306a36Sopenharmony_ci			break;
17162306a36Sopenharmony_ci	}
17262306a36Sopenharmony_ci	if (!other && !where)
17362306a36Sopenharmony_ci		hlist_add_head(&node->table, &table->head);
17462306a36Sopenharmony_ci	else if (!other)
17562306a36Sopenharmony_ci		hlist_add_behind(&node->table, &where->table);
17662306a36Sopenharmony_ci	else
17762306a36Sopenharmony_ci		hlist_add_before(&node->table, &where->table);
17862306a36Sopenharmony_ci}
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_cistatic __init int
18162306a36Sopenharmony_cihorrible_allowedips_insert_v4(struct horrible_allowedips *table,
18262306a36Sopenharmony_ci			      struct in_addr *ip, u8 cidr, void *value)
18362306a36Sopenharmony_ci{
18462306a36Sopenharmony_ci	struct horrible_allowedips_node *node = kzalloc(sizeof(*node), GFP_KERNEL);
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_ci	if (unlikely(!node))
18762306a36Sopenharmony_ci		return -ENOMEM;
18862306a36Sopenharmony_ci	node->ip.in = *ip;
18962306a36Sopenharmony_ci	node->mask = horrible_cidr_to_mask(cidr);
19062306a36Sopenharmony_ci	node->ip_version = 4;
19162306a36Sopenharmony_ci	node->value = value;
19262306a36Sopenharmony_ci	horrible_mask_self(node);
19362306a36Sopenharmony_ci	horrible_insert_ordered(table, node);
19462306a36Sopenharmony_ci	return 0;
19562306a36Sopenharmony_ci}
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_cistatic __init int
19862306a36Sopenharmony_cihorrible_allowedips_insert_v6(struct horrible_allowedips *table,
19962306a36Sopenharmony_ci			      struct in6_addr *ip, u8 cidr, void *value)
20062306a36Sopenharmony_ci{
20162306a36Sopenharmony_ci	struct horrible_allowedips_node *node = kzalloc(sizeof(*node), GFP_KERNEL);
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_ci	if (unlikely(!node))
20462306a36Sopenharmony_ci		return -ENOMEM;
20562306a36Sopenharmony_ci	node->ip.in6 = *ip;
20662306a36Sopenharmony_ci	node->mask = horrible_cidr_to_mask(cidr);
20762306a36Sopenharmony_ci	node->ip_version = 6;
20862306a36Sopenharmony_ci	node->value = value;
20962306a36Sopenharmony_ci	horrible_mask_self(node);
21062306a36Sopenharmony_ci	horrible_insert_ordered(table, node);
21162306a36Sopenharmony_ci	return 0;
21262306a36Sopenharmony_ci}
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_cistatic __init void *
21562306a36Sopenharmony_cihorrible_allowedips_lookup_v4(struct horrible_allowedips *table, struct in_addr *ip)
21662306a36Sopenharmony_ci{
21762306a36Sopenharmony_ci	struct horrible_allowedips_node *node;
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_ci	hlist_for_each_entry(node, &table->head, table) {
22062306a36Sopenharmony_ci		if (node->ip_version == 4 && horrible_match_v4(node, ip))
22162306a36Sopenharmony_ci			return node->value;
22262306a36Sopenharmony_ci	}
22362306a36Sopenharmony_ci	return NULL;
22462306a36Sopenharmony_ci}
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_cistatic __init void *
22762306a36Sopenharmony_cihorrible_allowedips_lookup_v6(struct horrible_allowedips *table, struct in6_addr *ip)
22862306a36Sopenharmony_ci{
22962306a36Sopenharmony_ci	struct horrible_allowedips_node *node;
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_ci	hlist_for_each_entry(node, &table->head, table) {
23262306a36Sopenharmony_ci		if (node->ip_version == 6 && horrible_match_v6(node, ip))
23362306a36Sopenharmony_ci			return node->value;
23462306a36Sopenharmony_ci	}
23562306a36Sopenharmony_ci	return NULL;
23662306a36Sopenharmony_ci}
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_cistatic __init void
24062306a36Sopenharmony_cihorrible_allowedips_remove_by_value(struct horrible_allowedips *table, void *value)
24162306a36Sopenharmony_ci{
24262306a36Sopenharmony_ci	struct horrible_allowedips_node *node;
24362306a36Sopenharmony_ci	struct hlist_node *h;
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_ci	hlist_for_each_entry_safe(node, h, &table->head, table) {
24662306a36Sopenharmony_ci		if (node->value != value)
24762306a36Sopenharmony_ci			continue;
24862306a36Sopenharmony_ci		hlist_del(&node->table);
24962306a36Sopenharmony_ci		kfree(node);
25062306a36Sopenharmony_ci	}
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_ci}
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_cistatic __init bool randomized_test(void)
25562306a36Sopenharmony_ci{
25662306a36Sopenharmony_ci	unsigned int i, j, k, mutate_amount, cidr;
25762306a36Sopenharmony_ci	u8 ip[16], mutate_mask[16], mutated[16];
25862306a36Sopenharmony_ci	struct wg_peer **peers, *peer;
25962306a36Sopenharmony_ci	struct horrible_allowedips h;
26062306a36Sopenharmony_ci	DEFINE_MUTEX(mutex);
26162306a36Sopenharmony_ci	struct allowedips t;
26262306a36Sopenharmony_ci	bool ret = false;
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_ci	mutex_init(&mutex);
26562306a36Sopenharmony_ci
26662306a36Sopenharmony_ci	wg_allowedips_init(&t);
26762306a36Sopenharmony_ci	horrible_allowedips_init(&h);
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_ci	peers = kcalloc(NUM_PEERS, sizeof(*peers), GFP_KERNEL);
27062306a36Sopenharmony_ci	if (unlikely(!peers)) {
27162306a36Sopenharmony_ci		pr_err("allowedips random self-test malloc: FAIL\n");
27262306a36Sopenharmony_ci		goto free;
27362306a36Sopenharmony_ci	}
27462306a36Sopenharmony_ci	for (i = 0; i < NUM_PEERS; ++i) {
27562306a36Sopenharmony_ci		peers[i] = kzalloc(sizeof(*peers[i]), GFP_KERNEL);
27662306a36Sopenharmony_ci		if (unlikely(!peers[i])) {
27762306a36Sopenharmony_ci			pr_err("allowedips random self-test malloc: FAIL\n");
27862306a36Sopenharmony_ci			goto free;
27962306a36Sopenharmony_ci		}
28062306a36Sopenharmony_ci		kref_init(&peers[i]->refcount);
28162306a36Sopenharmony_ci		INIT_LIST_HEAD(&peers[i]->allowedips_list);
28262306a36Sopenharmony_ci	}
28362306a36Sopenharmony_ci
28462306a36Sopenharmony_ci	mutex_lock(&mutex);
28562306a36Sopenharmony_ci
28662306a36Sopenharmony_ci	for (i = 0; i < NUM_RAND_ROUTES; ++i) {
28762306a36Sopenharmony_ci		get_random_bytes(ip, 4);
28862306a36Sopenharmony_ci		cidr = get_random_u32_inclusive(1, 32);
28962306a36Sopenharmony_ci		peer = peers[get_random_u32_below(NUM_PEERS)];
29062306a36Sopenharmony_ci		if (wg_allowedips_insert_v4(&t, (struct in_addr *)ip, cidr,
29162306a36Sopenharmony_ci					    peer, &mutex) < 0) {
29262306a36Sopenharmony_ci			pr_err("allowedips random self-test malloc: FAIL\n");
29362306a36Sopenharmony_ci			goto free_locked;
29462306a36Sopenharmony_ci		}
29562306a36Sopenharmony_ci		if (horrible_allowedips_insert_v4(&h, (struct in_addr *)ip,
29662306a36Sopenharmony_ci						  cidr, peer) < 0) {
29762306a36Sopenharmony_ci			pr_err("allowedips random self-test malloc: FAIL\n");
29862306a36Sopenharmony_ci			goto free_locked;
29962306a36Sopenharmony_ci		}
30062306a36Sopenharmony_ci		for (j = 0; j < NUM_MUTATED_ROUTES; ++j) {
30162306a36Sopenharmony_ci			memcpy(mutated, ip, 4);
30262306a36Sopenharmony_ci			get_random_bytes(mutate_mask, 4);
30362306a36Sopenharmony_ci			mutate_amount = get_random_u32_below(32);
30462306a36Sopenharmony_ci			for (k = 0; k < mutate_amount / 8; ++k)
30562306a36Sopenharmony_ci				mutate_mask[k] = 0xff;
30662306a36Sopenharmony_ci			mutate_mask[k] = 0xff
30762306a36Sopenharmony_ci					 << ((8 - (mutate_amount % 8)) % 8);
30862306a36Sopenharmony_ci			for (; k < 4; ++k)
30962306a36Sopenharmony_ci				mutate_mask[k] = 0;
31062306a36Sopenharmony_ci			for (k = 0; k < 4; ++k)
31162306a36Sopenharmony_ci				mutated[k] = (mutated[k] & mutate_mask[k]) |
31262306a36Sopenharmony_ci					     (~mutate_mask[k] &
31362306a36Sopenharmony_ci					      get_random_u8());
31462306a36Sopenharmony_ci			cidr = get_random_u32_inclusive(1, 32);
31562306a36Sopenharmony_ci			peer = peers[get_random_u32_below(NUM_PEERS)];
31662306a36Sopenharmony_ci			if (wg_allowedips_insert_v4(&t,
31762306a36Sopenharmony_ci						    (struct in_addr *)mutated,
31862306a36Sopenharmony_ci						    cidr, peer, &mutex) < 0) {
31962306a36Sopenharmony_ci				pr_err("allowedips random self-test malloc: FAIL\n");
32062306a36Sopenharmony_ci				goto free_locked;
32162306a36Sopenharmony_ci			}
32262306a36Sopenharmony_ci			if (horrible_allowedips_insert_v4(&h,
32362306a36Sopenharmony_ci				(struct in_addr *)mutated, cidr, peer)) {
32462306a36Sopenharmony_ci				pr_err("allowedips random self-test malloc: FAIL\n");
32562306a36Sopenharmony_ci				goto free_locked;
32662306a36Sopenharmony_ci			}
32762306a36Sopenharmony_ci		}
32862306a36Sopenharmony_ci	}
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_ci	for (i = 0; i < NUM_RAND_ROUTES; ++i) {
33162306a36Sopenharmony_ci		get_random_bytes(ip, 16);
33262306a36Sopenharmony_ci		cidr = get_random_u32_inclusive(1, 128);
33362306a36Sopenharmony_ci		peer = peers[get_random_u32_below(NUM_PEERS)];
33462306a36Sopenharmony_ci		if (wg_allowedips_insert_v6(&t, (struct in6_addr *)ip, cidr,
33562306a36Sopenharmony_ci					    peer, &mutex) < 0) {
33662306a36Sopenharmony_ci			pr_err("allowedips random self-test malloc: FAIL\n");
33762306a36Sopenharmony_ci			goto free_locked;
33862306a36Sopenharmony_ci		}
33962306a36Sopenharmony_ci		if (horrible_allowedips_insert_v6(&h, (struct in6_addr *)ip,
34062306a36Sopenharmony_ci						  cidr, peer) < 0) {
34162306a36Sopenharmony_ci			pr_err("allowedips random self-test malloc: FAIL\n");
34262306a36Sopenharmony_ci			goto free_locked;
34362306a36Sopenharmony_ci		}
34462306a36Sopenharmony_ci		for (j = 0; j < NUM_MUTATED_ROUTES; ++j) {
34562306a36Sopenharmony_ci			memcpy(mutated, ip, 16);
34662306a36Sopenharmony_ci			get_random_bytes(mutate_mask, 16);
34762306a36Sopenharmony_ci			mutate_amount = get_random_u32_below(128);
34862306a36Sopenharmony_ci			for (k = 0; k < mutate_amount / 8; ++k)
34962306a36Sopenharmony_ci				mutate_mask[k] = 0xff;
35062306a36Sopenharmony_ci			mutate_mask[k] = 0xff
35162306a36Sopenharmony_ci					 << ((8 - (mutate_amount % 8)) % 8);
35262306a36Sopenharmony_ci			for (; k < 4; ++k)
35362306a36Sopenharmony_ci				mutate_mask[k] = 0;
35462306a36Sopenharmony_ci			for (k = 0; k < 4; ++k)
35562306a36Sopenharmony_ci				mutated[k] = (mutated[k] & mutate_mask[k]) |
35662306a36Sopenharmony_ci					     (~mutate_mask[k] &
35762306a36Sopenharmony_ci					      get_random_u8());
35862306a36Sopenharmony_ci			cidr = get_random_u32_inclusive(1, 128);
35962306a36Sopenharmony_ci			peer = peers[get_random_u32_below(NUM_PEERS)];
36062306a36Sopenharmony_ci			if (wg_allowedips_insert_v6(&t,
36162306a36Sopenharmony_ci						    (struct in6_addr *)mutated,
36262306a36Sopenharmony_ci						    cidr, peer, &mutex) < 0) {
36362306a36Sopenharmony_ci				pr_err("allowedips random self-test malloc: FAIL\n");
36462306a36Sopenharmony_ci				goto free_locked;
36562306a36Sopenharmony_ci			}
36662306a36Sopenharmony_ci			if (horrible_allowedips_insert_v6(
36762306a36Sopenharmony_ci				    &h, (struct in6_addr *)mutated, cidr,
36862306a36Sopenharmony_ci				    peer)) {
36962306a36Sopenharmony_ci				pr_err("allowedips random self-test malloc: FAIL\n");
37062306a36Sopenharmony_ci				goto free_locked;
37162306a36Sopenharmony_ci			}
37262306a36Sopenharmony_ci		}
37362306a36Sopenharmony_ci	}
37462306a36Sopenharmony_ci
37562306a36Sopenharmony_ci	mutex_unlock(&mutex);
37662306a36Sopenharmony_ci
37762306a36Sopenharmony_ci	if (IS_ENABLED(DEBUG_PRINT_TRIE_GRAPHVIZ)) {
37862306a36Sopenharmony_ci		print_tree(t.root4, 32);
37962306a36Sopenharmony_ci		print_tree(t.root6, 128);
38062306a36Sopenharmony_ci	}
38162306a36Sopenharmony_ci
38262306a36Sopenharmony_ci	for (j = 0;; ++j) {
38362306a36Sopenharmony_ci		for (i = 0; i < NUM_QUERIES; ++i) {
38462306a36Sopenharmony_ci			get_random_bytes(ip, 4);
38562306a36Sopenharmony_ci			if (lookup(t.root4, 32, ip) != horrible_allowedips_lookup_v4(&h, (struct in_addr *)ip)) {
38662306a36Sopenharmony_ci				horrible_allowedips_lookup_v4(&h, (struct in_addr *)ip);
38762306a36Sopenharmony_ci				pr_err("allowedips random v4 self-test: FAIL\n");
38862306a36Sopenharmony_ci				goto free;
38962306a36Sopenharmony_ci			}
39062306a36Sopenharmony_ci			get_random_bytes(ip, 16);
39162306a36Sopenharmony_ci			if (lookup(t.root6, 128, ip) != horrible_allowedips_lookup_v6(&h, (struct in6_addr *)ip)) {
39262306a36Sopenharmony_ci				pr_err("allowedips random v6 self-test: FAIL\n");
39362306a36Sopenharmony_ci				goto free;
39462306a36Sopenharmony_ci			}
39562306a36Sopenharmony_ci		}
39662306a36Sopenharmony_ci		if (j >= NUM_PEERS)
39762306a36Sopenharmony_ci			break;
39862306a36Sopenharmony_ci		mutex_lock(&mutex);
39962306a36Sopenharmony_ci		wg_allowedips_remove_by_peer(&t, peers[j], &mutex);
40062306a36Sopenharmony_ci		mutex_unlock(&mutex);
40162306a36Sopenharmony_ci		horrible_allowedips_remove_by_value(&h, peers[j]);
40262306a36Sopenharmony_ci	}
40362306a36Sopenharmony_ci
40462306a36Sopenharmony_ci	if (t.root4 || t.root6) {
40562306a36Sopenharmony_ci		pr_err("allowedips random self-test removal: FAIL\n");
40662306a36Sopenharmony_ci		goto free;
40762306a36Sopenharmony_ci	}
40862306a36Sopenharmony_ci
40962306a36Sopenharmony_ci	ret = true;
41062306a36Sopenharmony_ci
41162306a36Sopenharmony_cifree:
41262306a36Sopenharmony_ci	mutex_lock(&mutex);
41362306a36Sopenharmony_cifree_locked:
41462306a36Sopenharmony_ci	wg_allowedips_free(&t, &mutex);
41562306a36Sopenharmony_ci	mutex_unlock(&mutex);
41662306a36Sopenharmony_ci	horrible_allowedips_free(&h);
41762306a36Sopenharmony_ci	if (peers) {
41862306a36Sopenharmony_ci		for (i = 0; i < NUM_PEERS; ++i)
41962306a36Sopenharmony_ci			kfree(peers[i]);
42062306a36Sopenharmony_ci	}
42162306a36Sopenharmony_ci	kfree(peers);
42262306a36Sopenharmony_ci	return ret;
42362306a36Sopenharmony_ci}
42462306a36Sopenharmony_ci
42562306a36Sopenharmony_cistatic __init inline struct in_addr *ip4(u8 a, u8 b, u8 c, u8 d)
42662306a36Sopenharmony_ci{
42762306a36Sopenharmony_ci	static struct in_addr ip;
42862306a36Sopenharmony_ci	u8 *split = (u8 *)&ip;
42962306a36Sopenharmony_ci
43062306a36Sopenharmony_ci	split[0] = a;
43162306a36Sopenharmony_ci	split[1] = b;
43262306a36Sopenharmony_ci	split[2] = c;
43362306a36Sopenharmony_ci	split[3] = d;
43462306a36Sopenharmony_ci	return &ip;
43562306a36Sopenharmony_ci}
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_cistatic __init inline struct in6_addr *ip6(u32 a, u32 b, u32 c, u32 d)
43862306a36Sopenharmony_ci{
43962306a36Sopenharmony_ci	static struct in6_addr ip;
44062306a36Sopenharmony_ci	__be32 *split = (__be32 *)&ip;
44162306a36Sopenharmony_ci
44262306a36Sopenharmony_ci	split[0] = cpu_to_be32(a);
44362306a36Sopenharmony_ci	split[1] = cpu_to_be32(b);
44462306a36Sopenharmony_ci	split[2] = cpu_to_be32(c);
44562306a36Sopenharmony_ci	split[3] = cpu_to_be32(d);
44662306a36Sopenharmony_ci	return &ip;
44762306a36Sopenharmony_ci}
44862306a36Sopenharmony_ci
44962306a36Sopenharmony_cistatic __init struct wg_peer *init_peer(void)
45062306a36Sopenharmony_ci{
45162306a36Sopenharmony_ci	struct wg_peer *peer = kzalloc(sizeof(*peer), GFP_KERNEL);
45262306a36Sopenharmony_ci
45362306a36Sopenharmony_ci	if (!peer)
45462306a36Sopenharmony_ci		return NULL;
45562306a36Sopenharmony_ci	kref_init(&peer->refcount);
45662306a36Sopenharmony_ci	INIT_LIST_HEAD(&peer->allowedips_list);
45762306a36Sopenharmony_ci	return peer;
45862306a36Sopenharmony_ci}
45962306a36Sopenharmony_ci
46062306a36Sopenharmony_ci#define insert(version, mem, ipa, ipb, ipc, ipd, cidr)                       \
46162306a36Sopenharmony_ci	wg_allowedips_insert_v##version(&t, ip##version(ipa, ipb, ipc, ipd), \
46262306a36Sopenharmony_ci					cidr, mem, &mutex)
46362306a36Sopenharmony_ci
46462306a36Sopenharmony_ci#define maybe_fail() do {                                               \
46562306a36Sopenharmony_ci		++i;                                                    \
46662306a36Sopenharmony_ci		if (!_s) {                                              \
46762306a36Sopenharmony_ci			pr_info("allowedips self-test %zu: FAIL\n", i); \
46862306a36Sopenharmony_ci			success = false;                                \
46962306a36Sopenharmony_ci		}                                                       \
47062306a36Sopenharmony_ci	} while (0)
47162306a36Sopenharmony_ci
47262306a36Sopenharmony_ci#define test(version, mem, ipa, ipb, ipc, ipd) do {                          \
47362306a36Sopenharmony_ci		bool _s = lookup(t.root##version, (version) == 4 ? 32 : 128, \
47462306a36Sopenharmony_ci				 ip##version(ipa, ipb, ipc, ipd)) == (mem);  \
47562306a36Sopenharmony_ci		maybe_fail();                                                \
47662306a36Sopenharmony_ci	} while (0)
47762306a36Sopenharmony_ci
47862306a36Sopenharmony_ci#define test_negative(version, mem, ipa, ipb, ipc, ipd) do {                 \
47962306a36Sopenharmony_ci		bool _s = lookup(t.root##version, (version) == 4 ? 32 : 128, \
48062306a36Sopenharmony_ci				 ip##version(ipa, ipb, ipc, ipd)) != (mem);  \
48162306a36Sopenharmony_ci		maybe_fail();                                                \
48262306a36Sopenharmony_ci	} while (0)
48362306a36Sopenharmony_ci
48462306a36Sopenharmony_ci#define test_boolean(cond) do {   \
48562306a36Sopenharmony_ci		bool _s = (cond); \
48662306a36Sopenharmony_ci		maybe_fail();     \
48762306a36Sopenharmony_ci	} while (0)
48862306a36Sopenharmony_ci
48962306a36Sopenharmony_cibool __init wg_allowedips_selftest(void)
49062306a36Sopenharmony_ci{
49162306a36Sopenharmony_ci	bool found_a = false, found_b = false, found_c = false, found_d = false,
49262306a36Sopenharmony_ci	     found_e = false, found_other = false;
49362306a36Sopenharmony_ci	struct wg_peer *a = init_peer(), *b = init_peer(), *c = init_peer(),
49462306a36Sopenharmony_ci		       *d = init_peer(), *e = init_peer(), *f = init_peer(),
49562306a36Sopenharmony_ci		       *g = init_peer(), *h = init_peer();
49662306a36Sopenharmony_ci	struct allowedips_node *iter_node;
49762306a36Sopenharmony_ci	bool success = false;
49862306a36Sopenharmony_ci	struct allowedips t;
49962306a36Sopenharmony_ci	DEFINE_MUTEX(mutex);
50062306a36Sopenharmony_ci	struct in6_addr ip;
50162306a36Sopenharmony_ci	size_t i = 0, count = 0;
50262306a36Sopenharmony_ci	__be64 part;
50362306a36Sopenharmony_ci
50462306a36Sopenharmony_ci	mutex_init(&mutex);
50562306a36Sopenharmony_ci	mutex_lock(&mutex);
50662306a36Sopenharmony_ci	wg_allowedips_init(&t);
50762306a36Sopenharmony_ci
50862306a36Sopenharmony_ci	if (!a || !b || !c || !d || !e || !f || !g || !h) {
50962306a36Sopenharmony_ci		pr_err("allowedips self-test malloc: FAIL\n");
51062306a36Sopenharmony_ci		goto free;
51162306a36Sopenharmony_ci	}
51262306a36Sopenharmony_ci
51362306a36Sopenharmony_ci	insert(4, a, 192, 168, 4, 0, 24);
51462306a36Sopenharmony_ci	insert(4, b, 192, 168, 4, 4, 32);
51562306a36Sopenharmony_ci	insert(4, c, 192, 168, 0, 0, 16);
51662306a36Sopenharmony_ci	insert(4, d, 192, 95, 5, 64, 27);
51762306a36Sopenharmony_ci	/* replaces previous entry, and maskself is required */
51862306a36Sopenharmony_ci	insert(4, c, 192, 95, 5, 65, 27);
51962306a36Sopenharmony_ci	insert(6, d, 0x26075300, 0x60006b00, 0, 0xc05f0543, 128);
52062306a36Sopenharmony_ci	insert(6, c, 0x26075300, 0x60006b00, 0, 0, 64);
52162306a36Sopenharmony_ci	insert(4, e, 0, 0, 0, 0, 0);
52262306a36Sopenharmony_ci	insert(6, e, 0, 0, 0, 0, 0);
52362306a36Sopenharmony_ci	/* replaces previous entry */
52462306a36Sopenharmony_ci	insert(6, f, 0, 0, 0, 0, 0);
52562306a36Sopenharmony_ci	insert(6, g, 0x24046800, 0, 0, 0, 32);
52662306a36Sopenharmony_ci	/* maskself is required */
52762306a36Sopenharmony_ci	insert(6, h, 0x24046800, 0x40040800, 0xdeadbeef, 0xdeadbeef, 64);
52862306a36Sopenharmony_ci	insert(6, a, 0x24046800, 0x40040800, 0xdeadbeef, 0xdeadbeef, 128);
52962306a36Sopenharmony_ci	insert(6, c, 0x24446800, 0x40e40800, 0xdeaebeef, 0xdefbeef, 128);
53062306a36Sopenharmony_ci	insert(6, b, 0x24446800, 0xf0e40800, 0xeeaebeef, 0, 98);
53162306a36Sopenharmony_ci	insert(4, g, 64, 15, 112, 0, 20);
53262306a36Sopenharmony_ci	/* maskself is required */
53362306a36Sopenharmony_ci	insert(4, h, 64, 15, 123, 211, 25);
53462306a36Sopenharmony_ci	insert(4, a, 10, 0, 0, 0, 25);
53562306a36Sopenharmony_ci	insert(4, b, 10, 0, 0, 128, 25);
53662306a36Sopenharmony_ci	insert(4, a, 10, 1, 0, 0, 30);
53762306a36Sopenharmony_ci	insert(4, b, 10, 1, 0, 4, 30);
53862306a36Sopenharmony_ci	insert(4, c, 10, 1, 0, 8, 29);
53962306a36Sopenharmony_ci	insert(4, d, 10, 1, 0, 16, 29);
54062306a36Sopenharmony_ci
54162306a36Sopenharmony_ci	if (IS_ENABLED(DEBUG_PRINT_TRIE_GRAPHVIZ)) {
54262306a36Sopenharmony_ci		print_tree(t.root4, 32);
54362306a36Sopenharmony_ci		print_tree(t.root6, 128);
54462306a36Sopenharmony_ci	}
54562306a36Sopenharmony_ci
54662306a36Sopenharmony_ci	success = true;
54762306a36Sopenharmony_ci
54862306a36Sopenharmony_ci	test(4, a, 192, 168, 4, 20);
54962306a36Sopenharmony_ci	test(4, a, 192, 168, 4, 0);
55062306a36Sopenharmony_ci	test(4, b, 192, 168, 4, 4);
55162306a36Sopenharmony_ci	test(4, c, 192, 168, 200, 182);
55262306a36Sopenharmony_ci	test(4, c, 192, 95, 5, 68);
55362306a36Sopenharmony_ci	test(4, e, 192, 95, 5, 96);
55462306a36Sopenharmony_ci	test(6, d, 0x26075300, 0x60006b00, 0, 0xc05f0543);
55562306a36Sopenharmony_ci	test(6, c, 0x26075300, 0x60006b00, 0, 0xc02e01ee);
55662306a36Sopenharmony_ci	test(6, f, 0x26075300, 0x60006b01, 0, 0);
55762306a36Sopenharmony_ci	test(6, g, 0x24046800, 0x40040806, 0, 0x1006);
55862306a36Sopenharmony_ci	test(6, g, 0x24046800, 0x40040806, 0x1234, 0x5678);
55962306a36Sopenharmony_ci	test(6, f, 0x240467ff, 0x40040806, 0x1234, 0x5678);
56062306a36Sopenharmony_ci	test(6, f, 0x24046801, 0x40040806, 0x1234, 0x5678);
56162306a36Sopenharmony_ci	test(6, h, 0x24046800, 0x40040800, 0x1234, 0x5678);
56262306a36Sopenharmony_ci	test(6, h, 0x24046800, 0x40040800, 0, 0);
56362306a36Sopenharmony_ci	test(6, h, 0x24046800, 0x40040800, 0x10101010, 0x10101010);
56462306a36Sopenharmony_ci	test(6, a, 0x24046800, 0x40040800, 0xdeadbeef, 0xdeadbeef);
56562306a36Sopenharmony_ci	test(4, g, 64, 15, 116, 26);
56662306a36Sopenharmony_ci	test(4, g, 64, 15, 127, 3);
56762306a36Sopenharmony_ci	test(4, g, 64, 15, 123, 1);
56862306a36Sopenharmony_ci	test(4, h, 64, 15, 123, 128);
56962306a36Sopenharmony_ci	test(4, h, 64, 15, 123, 129);
57062306a36Sopenharmony_ci	test(4, a, 10, 0, 0, 52);
57162306a36Sopenharmony_ci	test(4, b, 10, 0, 0, 220);
57262306a36Sopenharmony_ci	test(4, a, 10, 1, 0, 2);
57362306a36Sopenharmony_ci	test(4, b, 10, 1, 0, 6);
57462306a36Sopenharmony_ci	test(4, c, 10, 1, 0, 10);
57562306a36Sopenharmony_ci	test(4, d, 10, 1, 0, 20);
57662306a36Sopenharmony_ci
57762306a36Sopenharmony_ci	insert(4, a, 1, 0, 0, 0, 32);
57862306a36Sopenharmony_ci	insert(4, a, 64, 0, 0, 0, 32);
57962306a36Sopenharmony_ci	insert(4, a, 128, 0, 0, 0, 32);
58062306a36Sopenharmony_ci	insert(4, a, 192, 0, 0, 0, 32);
58162306a36Sopenharmony_ci	insert(4, a, 255, 0, 0, 0, 32);
58262306a36Sopenharmony_ci	wg_allowedips_remove_by_peer(&t, a, &mutex);
58362306a36Sopenharmony_ci	test_negative(4, a, 1, 0, 0, 0);
58462306a36Sopenharmony_ci	test_negative(4, a, 64, 0, 0, 0);
58562306a36Sopenharmony_ci	test_negative(4, a, 128, 0, 0, 0);
58662306a36Sopenharmony_ci	test_negative(4, a, 192, 0, 0, 0);
58762306a36Sopenharmony_ci	test_negative(4, a, 255, 0, 0, 0);
58862306a36Sopenharmony_ci
58962306a36Sopenharmony_ci	wg_allowedips_free(&t, &mutex);
59062306a36Sopenharmony_ci	wg_allowedips_init(&t);
59162306a36Sopenharmony_ci	insert(4, a, 192, 168, 0, 0, 16);
59262306a36Sopenharmony_ci	insert(4, a, 192, 168, 0, 0, 24);
59362306a36Sopenharmony_ci	wg_allowedips_remove_by_peer(&t, a, &mutex);
59462306a36Sopenharmony_ci	test_negative(4, a, 192, 168, 0, 1);
59562306a36Sopenharmony_ci
59662306a36Sopenharmony_ci	/* These will hit the WARN_ON(len >= MAX_ALLOWEDIPS_DEPTH) in free_node
59762306a36Sopenharmony_ci	 * if something goes wrong.
59862306a36Sopenharmony_ci	 */
59962306a36Sopenharmony_ci	for (i = 0; i < 64; ++i) {
60062306a36Sopenharmony_ci		part = cpu_to_be64(~0LLU << i);
60162306a36Sopenharmony_ci		memset(&ip, 0xff, 8);
60262306a36Sopenharmony_ci		memcpy((u8 *)&ip + 8, &part, 8);
60362306a36Sopenharmony_ci		wg_allowedips_insert_v6(&t, &ip, 128, a, &mutex);
60462306a36Sopenharmony_ci		memcpy(&ip, &part, 8);
60562306a36Sopenharmony_ci		memset((u8 *)&ip + 8, 0, 8);
60662306a36Sopenharmony_ci		wg_allowedips_insert_v6(&t, &ip, 128, a, &mutex);
60762306a36Sopenharmony_ci	}
60862306a36Sopenharmony_ci	memset(&ip, 0, 16);
60962306a36Sopenharmony_ci	wg_allowedips_insert_v6(&t, &ip, 128, a, &mutex);
61062306a36Sopenharmony_ci	wg_allowedips_free(&t, &mutex);
61162306a36Sopenharmony_ci
61262306a36Sopenharmony_ci	wg_allowedips_init(&t);
61362306a36Sopenharmony_ci	insert(4, a, 192, 95, 5, 93, 27);
61462306a36Sopenharmony_ci	insert(6, a, 0x26075300, 0x60006b00, 0, 0xc05f0543, 128);
61562306a36Sopenharmony_ci	insert(4, a, 10, 1, 0, 20, 29);
61662306a36Sopenharmony_ci	insert(6, a, 0x26075300, 0x6d8a6bf8, 0xdab1f1df, 0xc05f1523, 83);
61762306a36Sopenharmony_ci	insert(6, a, 0x26075300, 0x6d8a6bf8, 0xdab1f1df, 0xc05f1523, 21);
61862306a36Sopenharmony_ci	list_for_each_entry(iter_node, &a->allowedips_list, peer_list) {
61962306a36Sopenharmony_ci		u8 cidr, ip[16] __aligned(__alignof(u64));
62062306a36Sopenharmony_ci		int family = wg_allowedips_read_node(iter_node, ip, &cidr);
62162306a36Sopenharmony_ci
62262306a36Sopenharmony_ci		count++;
62362306a36Sopenharmony_ci
62462306a36Sopenharmony_ci		if (cidr == 27 && family == AF_INET &&
62562306a36Sopenharmony_ci		    !memcmp(ip, ip4(192, 95, 5, 64), sizeof(struct in_addr)))
62662306a36Sopenharmony_ci			found_a = true;
62762306a36Sopenharmony_ci		else if (cidr == 128 && family == AF_INET6 &&
62862306a36Sopenharmony_ci			 !memcmp(ip, ip6(0x26075300, 0x60006b00, 0, 0xc05f0543),
62962306a36Sopenharmony_ci				 sizeof(struct in6_addr)))
63062306a36Sopenharmony_ci			found_b = true;
63162306a36Sopenharmony_ci		else if (cidr == 29 && family == AF_INET &&
63262306a36Sopenharmony_ci			 !memcmp(ip, ip4(10, 1, 0, 16), sizeof(struct in_addr)))
63362306a36Sopenharmony_ci			found_c = true;
63462306a36Sopenharmony_ci		else if (cidr == 83 && family == AF_INET6 &&
63562306a36Sopenharmony_ci			 !memcmp(ip, ip6(0x26075300, 0x6d8a6bf8, 0xdab1e000, 0),
63662306a36Sopenharmony_ci				 sizeof(struct in6_addr)))
63762306a36Sopenharmony_ci			found_d = true;
63862306a36Sopenharmony_ci		else if (cidr == 21 && family == AF_INET6 &&
63962306a36Sopenharmony_ci			 !memcmp(ip, ip6(0x26075000, 0, 0, 0),
64062306a36Sopenharmony_ci				 sizeof(struct in6_addr)))
64162306a36Sopenharmony_ci			found_e = true;
64262306a36Sopenharmony_ci		else
64362306a36Sopenharmony_ci			found_other = true;
64462306a36Sopenharmony_ci	}
64562306a36Sopenharmony_ci	test_boolean(count == 5);
64662306a36Sopenharmony_ci	test_boolean(found_a);
64762306a36Sopenharmony_ci	test_boolean(found_b);
64862306a36Sopenharmony_ci	test_boolean(found_c);
64962306a36Sopenharmony_ci	test_boolean(found_d);
65062306a36Sopenharmony_ci	test_boolean(found_e);
65162306a36Sopenharmony_ci	test_boolean(!found_other);
65262306a36Sopenharmony_ci
65362306a36Sopenharmony_ci	if (IS_ENABLED(DEBUG_RANDOM_TRIE) && success)
65462306a36Sopenharmony_ci		success = randomized_test();
65562306a36Sopenharmony_ci
65662306a36Sopenharmony_ci	if (success)
65762306a36Sopenharmony_ci		pr_info("allowedips self-tests: pass\n");
65862306a36Sopenharmony_ci
65962306a36Sopenharmony_cifree:
66062306a36Sopenharmony_ci	wg_allowedips_free(&t, &mutex);
66162306a36Sopenharmony_ci	kfree(a);
66262306a36Sopenharmony_ci	kfree(b);
66362306a36Sopenharmony_ci	kfree(c);
66462306a36Sopenharmony_ci	kfree(d);
66562306a36Sopenharmony_ci	kfree(e);
66662306a36Sopenharmony_ci	kfree(f);
66762306a36Sopenharmony_ci	kfree(g);
66862306a36Sopenharmony_ci	kfree(h);
66962306a36Sopenharmony_ci	mutex_unlock(&mutex);
67062306a36Sopenharmony_ci
67162306a36Sopenharmony_ci	return success;
67262306a36Sopenharmony_ci}
67362306a36Sopenharmony_ci
67462306a36Sopenharmony_ci#undef test_negative
67562306a36Sopenharmony_ci#undef test
67662306a36Sopenharmony_ci#undef remove
67762306a36Sopenharmony_ci#undef insert
67862306a36Sopenharmony_ci#undef init_peer
67962306a36Sopenharmony_ci
68062306a36Sopenharmony_ci#endif
681