162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (c) 2023 Oracle and/or its affiliates.
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * KUnit test of the handshake upcall mechanism.
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include <kunit/test.h>
962306a36Sopenharmony_ci#include <kunit/visibility.h>
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#include <linux/kernel.h>
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci#include <net/sock.h>
1462306a36Sopenharmony_ci#include <net/genetlink.h>
1562306a36Sopenharmony_ci#include <net/netns/generic.h>
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci#include <uapi/linux/handshake.h>
1862306a36Sopenharmony_ci#include "handshake.h"
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ciMODULE_IMPORT_NS(EXPORTED_FOR_KUNIT_TESTING);
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_cistatic int test_accept_func(struct handshake_req *req, struct genl_info *info,
2362306a36Sopenharmony_ci			    int fd)
2462306a36Sopenharmony_ci{
2562306a36Sopenharmony_ci	return 0;
2662306a36Sopenharmony_ci}
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_cistatic void test_done_func(struct handshake_req *req, unsigned int status,
2962306a36Sopenharmony_ci			   struct genl_info *info)
3062306a36Sopenharmony_ci{
3162306a36Sopenharmony_ci}
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_cistruct handshake_req_alloc_test_param {
3462306a36Sopenharmony_ci	const char			*desc;
3562306a36Sopenharmony_ci	struct handshake_proto		*proto;
3662306a36Sopenharmony_ci	gfp_t				gfp;
3762306a36Sopenharmony_ci	bool				expect_success;
3862306a36Sopenharmony_ci};
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_cistatic struct handshake_proto handshake_req_alloc_proto_2 = {
4162306a36Sopenharmony_ci	.hp_handler_class	= HANDSHAKE_HANDLER_CLASS_NONE,
4262306a36Sopenharmony_ci};
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_cistatic struct handshake_proto handshake_req_alloc_proto_3 = {
4562306a36Sopenharmony_ci	.hp_handler_class	= HANDSHAKE_HANDLER_CLASS_MAX,
4662306a36Sopenharmony_ci};
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_cistatic struct handshake_proto handshake_req_alloc_proto_4 = {
4962306a36Sopenharmony_ci	.hp_handler_class	= HANDSHAKE_HANDLER_CLASS_TLSHD,
5062306a36Sopenharmony_ci};
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_cistatic struct handshake_proto handshake_req_alloc_proto_5 = {
5362306a36Sopenharmony_ci	.hp_handler_class	= HANDSHAKE_HANDLER_CLASS_TLSHD,
5462306a36Sopenharmony_ci	.hp_accept		= test_accept_func,
5562306a36Sopenharmony_ci};
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_cistatic struct handshake_proto handshake_req_alloc_proto_6 = {
5862306a36Sopenharmony_ci	.hp_handler_class	= HANDSHAKE_HANDLER_CLASS_TLSHD,
5962306a36Sopenharmony_ci	.hp_privsize		= UINT_MAX,
6062306a36Sopenharmony_ci	.hp_accept		= test_accept_func,
6162306a36Sopenharmony_ci	.hp_done		= test_done_func,
6262306a36Sopenharmony_ci};
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_cistatic struct handshake_proto handshake_req_alloc_proto_good = {
6562306a36Sopenharmony_ci	.hp_handler_class	= HANDSHAKE_HANDLER_CLASS_TLSHD,
6662306a36Sopenharmony_ci	.hp_accept		= test_accept_func,
6762306a36Sopenharmony_ci	.hp_done		= test_done_func,
6862306a36Sopenharmony_ci};
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_cistatic const
7162306a36Sopenharmony_cistruct handshake_req_alloc_test_param handshake_req_alloc_params[] = {
7262306a36Sopenharmony_ci	{
7362306a36Sopenharmony_ci		.desc			= "handshake_req_alloc NULL proto",
7462306a36Sopenharmony_ci		.proto			= NULL,
7562306a36Sopenharmony_ci		.gfp			= GFP_KERNEL,
7662306a36Sopenharmony_ci		.expect_success		= false,
7762306a36Sopenharmony_ci	},
7862306a36Sopenharmony_ci	{
7962306a36Sopenharmony_ci		.desc			= "handshake_req_alloc CLASS_NONE",
8062306a36Sopenharmony_ci		.proto			= &handshake_req_alloc_proto_2,
8162306a36Sopenharmony_ci		.gfp			= GFP_KERNEL,
8262306a36Sopenharmony_ci		.expect_success		= false,
8362306a36Sopenharmony_ci	},
8462306a36Sopenharmony_ci	{
8562306a36Sopenharmony_ci		.desc			= "handshake_req_alloc CLASS_MAX",
8662306a36Sopenharmony_ci		.proto			= &handshake_req_alloc_proto_3,
8762306a36Sopenharmony_ci		.gfp			= GFP_KERNEL,
8862306a36Sopenharmony_ci		.expect_success		= false,
8962306a36Sopenharmony_ci	},
9062306a36Sopenharmony_ci	{
9162306a36Sopenharmony_ci		.desc			= "handshake_req_alloc no callbacks",
9262306a36Sopenharmony_ci		.proto			= &handshake_req_alloc_proto_4,
9362306a36Sopenharmony_ci		.gfp			= GFP_KERNEL,
9462306a36Sopenharmony_ci		.expect_success		= false,
9562306a36Sopenharmony_ci	},
9662306a36Sopenharmony_ci	{
9762306a36Sopenharmony_ci		.desc			= "handshake_req_alloc no done callback",
9862306a36Sopenharmony_ci		.proto			= &handshake_req_alloc_proto_5,
9962306a36Sopenharmony_ci		.gfp			= GFP_KERNEL,
10062306a36Sopenharmony_ci		.expect_success		= false,
10162306a36Sopenharmony_ci	},
10262306a36Sopenharmony_ci	{
10362306a36Sopenharmony_ci		.desc			= "handshake_req_alloc excessive privsize",
10462306a36Sopenharmony_ci		.proto			= &handshake_req_alloc_proto_6,
10562306a36Sopenharmony_ci		.gfp			= GFP_KERNEL | __GFP_NOWARN,
10662306a36Sopenharmony_ci		.expect_success		= false,
10762306a36Sopenharmony_ci	},
10862306a36Sopenharmony_ci	{
10962306a36Sopenharmony_ci		.desc			= "handshake_req_alloc all good",
11062306a36Sopenharmony_ci		.proto			= &handshake_req_alloc_proto_good,
11162306a36Sopenharmony_ci		.gfp			= GFP_KERNEL,
11262306a36Sopenharmony_ci		.expect_success		= true,
11362306a36Sopenharmony_ci	},
11462306a36Sopenharmony_ci};
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_cistatic void
11762306a36Sopenharmony_cihandshake_req_alloc_get_desc(const struct handshake_req_alloc_test_param *param,
11862306a36Sopenharmony_ci			     char *desc)
11962306a36Sopenharmony_ci{
12062306a36Sopenharmony_ci	strscpy(desc, param->desc, KUNIT_PARAM_DESC_SIZE);
12162306a36Sopenharmony_ci}
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci/* Creates the function handshake_req_alloc_gen_params */
12462306a36Sopenharmony_ciKUNIT_ARRAY_PARAM(handshake_req_alloc, handshake_req_alloc_params,
12562306a36Sopenharmony_ci		  handshake_req_alloc_get_desc);
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_cistatic void handshake_req_alloc_case(struct kunit *test)
12862306a36Sopenharmony_ci{
12962306a36Sopenharmony_ci	const struct handshake_req_alloc_test_param *param = test->param_value;
13062306a36Sopenharmony_ci	struct handshake_req *result;
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci	/* Arrange */
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_ci	/* Act */
13562306a36Sopenharmony_ci	result = handshake_req_alloc(param->proto, param->gfp);
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_ci	/* Assert */
13862306a36Sopenharmony_ci	if (param->expect_success)
13962306a36Sopenharmony_ci		KUNIT_EXPECT_NOT_NULL(test, result);
14062306a36Sopenharmony_ci	else
14162306a36Sopenharmony_ci		KUNIT_EXPECT_NULL(test, result);
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ci	kfree(result);
14462306a36Sopenharmony_ci}
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_cistatic void handshake_req_submit_test1(struct kunit *test)
14762306a36Sopenharmony_ci{
14862306a36Sopenharmony_ci	struct socket *sock;
14962306a36Sopenharmony_ci	int err, result;
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_ci	/* Arrange */
15262306a36Sopenharmony_ci	err = __sock_create(&init_net, PF_INET, SOCK_STREAM, IPPROTO_TCP,
15362306a36Sopenharmony_ci			    &sock, 1);
15462306a36Sopenharmony_ci	KUNIT_ASSERT_EQ(test, err, 0);
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci	/* Act */
15762306a36Sopenharmony_ci	result = handshake_req_submit(sock, NULL, GFP_KERNEL);
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ci	/* Assert */
16062306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, result, -EINVAL);
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci	sock_release(sock);
16362306a36Sopenharmony_ci}
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_cistatic void handshake_req_submit_test2(struct kunit *test)
16662306a36Sopenharmony_ci{
16762306a36Sopenharmony_ci	struct handshake_req *req;
16862306a36Sopenharmony_ci	int result;
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_ci	/* Arrange */
17162306a36Sopenharmony_ci	req = handshake_req_alloc(&handshake_req_alloc_proto_good, GFP_KERNEL);
17262306a36Sopenharmony_ci	KUNIT_ASSERT_NOT_NULL(test, req);
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_ci	/* Act */
17562306a36Sopenharmony_ci	result = handshake_req_submit(NULL, req, GFP_KERNEL);
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_ci	/* Assert */
17862306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, result, -EINVAL);
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_ci	/* handshake_req_submit() destroys @req on error */
18162306a36Sopenharmony_ci}
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_cistatic void handshake_req_submit_test3(struct kunit *test)
18462306a36Sopenharmony_ci{
18562306a36Sopenharmony_ci	struct handshake_req *req;
18662306a36Sopenharmony_ci	struct socket *sock;
18762306a36Sopenharmony_ci	int err, result;
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_ci	/* Arrange */
19062306a36Sopenharmony_ci	req = handshake_req_alloc(&handshake_req_alloc_proto_good, GFP_KERNEL);
19162306a36Sopenharmony_ci	KUNIT_ASSERT_NOT_NULL(test, req);
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_ci	err = __sock_create(&init_net, PF_INET, SOCK_STREAM, IPPROTO_TCP,
19462306a36Sopenharmony_ci			    &sock, 1);
19562306a36Sopenharmony_ci	KUNIT_ASSERT_EQ(test, err, 0);
19662306a36Sopenharmony_ci	sock->file = NULL;
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_ci	/* Act */
19962306a36Sopenharmony_ci	result = handshake_req_submit(sock, req, GFP_KERNEL);
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_ci	/* Assert */
20262306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, result, -EINVAL);
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci	/* handshake_req_submit() destroys @req on error */
20562306a36Sopenharmony_ci	sock_release(sock);
20662306a36Sopenharmony_ci}
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_cistatic void handshake_req_submit_test4(struct kunit *test)
20962306a36Sopenharmony_ci{
21062306a36Sopenharmony_ci	struct handshake_req *req, *result;
21162306a36Sopenharmony_ci	struct socket *sock;
21262306a36Sopenharmony_ci	struct file *filp;
21362306a36Sopenharmony_ci	int err;
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_ci	/* Arrange */
21662306a36Sopenharmony_ci	req = handshake_req_alloc(&handshake_req_alloc_proto_good, GFP_KERNEL);
21762306a36Sopenharmony_ci	KUNIT_ASSERT_NOT_NULL(test, req);
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_ci	err = __sock_create(&init_net, PF_INET, SOCK_STREAM, IPPROTO_TCP,
22062306a36Sopenharmony_ci			    &sock, 1);
22162306a36Sopenharmony_ci	KUNIT_ASSERT_EQ(test, err, 0);
22262306a36Sopenharmony_ci	filp = sock_alloc_file(sock, O_NONBLOCK, NULL);
22362306a36Sopenharmony_ci	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, filp);
22462306a36Sopenharmony_ci	KUNIT_ASSERT_NOT_NULL(test, sock->sk);
22562306a36Sopenharmony_ci	sock->file = filp;
22662306a36Sopenharmony_ci
22762306a36Sopenharmony_ci	err = handshake_req_submit(sock, req, GFP_KERNEL);
22862306a36Sopenharmony_ci	KUNIT_ASSERT_EQ(test, err, 0);
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_ci	/* Act */
23162306a36Sopenharmony_ci	result = handshake_req_hash_lookup(sock->sk);
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_ci	/* Assert */
23462306a36Sopenharmony_ci	KUNIT_EXPECT_NOT_NULL(test, result);
23562306a36Sopenharmony_ci	KUNIT_EXPECT_PTR_EQ(test, req, result);
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ci	handshake_req_cancel(sock->sk);
23862306a36Sopenharmony_ci	fput(filp);
23962306a36Sopenharmony_ci}
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_cistatic void handshake_req_submit_test5(struct kunit *test)
24262306a36Sopenharmony_ci{
24362306a36Sopenharmony_ci	struct handshake_req *req;
24462306a36Sopenharmony_ci	struct handshake_net *hn;
24562306a36Sopenharmony_ci	struct socket *sock;
24662306a36Sopenharmony_ci	struct file *filp;
24762306a36Sopenharmony_ci	struct net *net;
24862306a36Sopenharmony_ci	int saved, err;
24962306a36Sopenharmony_ci
25062306a36Sopenharmony_ci	/* Arrange */
25162306a36Sopenharmony_ci	req = handshake_req_alloc(&handshake_req_alloc_proto_good, GFP_KERNEL);
25262306a36Sopenharmony_ci	KUNIT_ASSERT_NOT_NULL(test, req);
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_ci	err = __sock_create(&init_net, PF_INET, SOCK_STREAM, IPPROTO_TCP,
25562306a36Sopenharmony_ci			    &sock, 1);
25662306a36Sopenharmony_ci	KUNIT_ASSERT_EQ(test, err, 0);
25762306a36Sopenharmony_ci	filp = sock_alloc_file(sock, O_NONBLOCK, NULL);
25862306a36Sopenharmony_ci	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, filp);
25962306a36Sopenharmony_ci	KUNIT_ASSERT_NOT_NULL(test, sock->sk);
26062306a36Sopenharmony_ci	sock->file = filp;
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_ci	net = sock_net(sock->sk);
26362306a36Sopenharmony_ci	hn = handshake_pernet(net);
26462306a36Sopenharmony_ci	KUNIT_ASSERT_NOT_NULL(test, hn);
26562306a36Sopenharmony_ci
26662306a36Sopenharmony_ci	saved = hn->hn_pending;
26762306a36Sopenharmony_ci	hn->hn_pending = hn->hn_pending_max + 1;
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_ci	/* Act */
27062306a36Sopenharmony_ci	err = handshake_req_submit(sock, req, GFP_KERNEL);
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_ci	/* Assert */
27362306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, err, -EAGAIN);
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_ci	fput(filp);
27662306a36Sopenharmony_ci	hn->hn_pending = saved;
27762306a36Sopenharmony_ci}
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_cistatic void handshake_req_submit_test6(struct kunit *test)
28062306a36Sopenharmony_ci{
28162306a36Sopenharmony_ci	struct handshake_req *req1, *req2;
28262306a36Sopenharmony_ci	struct socket *sock;
28362306a36Sopenharmony_ci	struct file *filp;
28462306a36Sopenharmony_ci	int err;
28562306a36Sopenharmony_ci
28662306a36Sopenharmony_ci	/* Arrange */
28762306a36Sopenharmony_ci	req1 = handshake_req_alloc(&handshake_req_alloc_proto_good, GFP_KERNEL);
28862306a36Sopenharmony_ci	KUNIT_ASSERT_NOT_NULL(test, req1);
28962306a36Sopenharmony_ci	req2 = handshake_req_alloc(&handshake_req_alloc_proto_good, GFP_KERNEL);
29062306a36Sopenharmony_ci	KUNIT_ASSERT_NOT_NULL(test, req2);
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_ci	err = __sock_create(&init_net, PF_INET, SOCK_STREAM, IPPROTO_TCP,
29362306a36Sopenharmony_ci			    &sock, 1);
29462306a36Sopenharmony_ci	KUNIT_ASSERT_EQ(test, err, 0);
29562306a36Sopenharmony_ci	filp = sock_alloc_file(sock, O_NONBLOCK, NULL);
29662306a36Sopenharmony_ci	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, filp);
29762306a36Sopenharmony_ci	KUNIT_ASSERT_NOT_NULL(test, sock->sk);
29862306a36Sopenharmony_ci	sock->file = filp;
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_ci	/* Act */
30162306a36Sopenharmony_ci	err = handshake_req_submit(sock, req1, GFP_KERNEL);
30262306a36Sopenharmony_ci	KUNIT_ASSERT_EQ(test, err, 0);
30362306a36Sopenharmony_ci	err = handshake_req_submit(sock, req2, GFP_KERNEL);
30462306a36Sopenharmony_ci
30562306a36Sopenharmony_ci	/* Assert */
30662306a36Sopenharmony_ci	KUNIT_EXPECT_EQ(test, err, -EBUSY);
30762306a36Sopenharmony_ci
30862306a36Sopenharmony_ci	handshake_req_cancel(sock->sk);
30962306a36Sopenharmony_ci	fput(filp);
31062306a36Sopenharmony_ci}
31162306a36Sopenharmony_ci
31262306a36Sopenharmony_cistatic void handshake_req_cancel_test1(struct kunit *test)
31362306a36Sopenharmony_ci{
31462306a36Sopenharmony_ci	struct handshake_req *req;
31562306a36Sopenharmony_ci	struct socket *sock;
31662306a36Sopenharmony_ci	struct file *filp;
31762306a36Sopenharmony_ci	bool result;
31862306a36Sopenharmony_ci	int err;
31962306a36Sopenharmony_ci
32062306a36Sopenharmony_ci	/* Arrange */
32162306a36Sopenharmony_ci	req = handshake_req_alloc(&handshake_req_alloc_proto_good, GFP_KERNEL);
32262306a36Sopenharmony_ci	KUNIT_ASSERT_NOT_NULL(test, req);
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_ci	err = __sock_create(&init_net, PF_INET, SOCK_STREAM, IPPROTO_TCP,
32562306a36Sopenharmony_ci			    &sock, 1);
32662306a36Sopenharmony_ci	KUNIT_ASSERT_EQ(test, err, 0);
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_ci	filp = sock_alloc_file(sock, O_NONBLOCK, NULL);
32962306a36Sopenharmony_ci	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, filp);
33062306a36Sopenharmony_ci	sock->file = filp;
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_ci	err = handshake_req_submit(sock, req, GFP_KERNEL);
33362306a36Sopenharmony_ci	KUNIT_ASSERT_EQ(test, err, 0);
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_ci	/* NB: handshake_req hasn't been accepted */
33662306a36Sopenharmony_ci
33762306a36Sopenharmony_ci	/* Act */
33862306a36Sopenharmony_ci	result = handshake_req_cancel(sock->sk);
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_ci	/* Assert */
34162306a36Sopenharmony_ci	KUNIT_EXPECT_TRUE(test, result);
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_ci	fput(filp);
34462306a36Sopenharmony_ci}
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_cistatic void handshake_req_cancel_test2(struct kunit *test)
34762306a36Sopenharmony_ci{
34862306a36Sopenharmony_ci	struct handshake_req *req, *next;
34962306a36Sopenharmony_ci	struct handshake_net *hn;
35062306a36Sopenharmony_ci	struct socket *sock;
35162306a36Sopenharmony_ci	struct file *filp;
35262306a36Sopenharmony_ci	struct net *net;
35362306a36Sopenharmony_ci	bool result;
35462306a36Sopenharmony_ci	int err;
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_ci	/* Arrange */
35762306a36Sopenharmony_ci	req = handshake_req_alloc(&handshake_req_alloc_proto_good, GFP_KERNEL);
35862306a36Sopenharmony_ci	KUNIT_ASSERT_NOT_NULL(test, req);
35962306a36Sopenharmony_ci
36062306a36Sopenharmony_ci	err = __sock_create(&init_net, PF_INET, SOCK_STREAM, IPPROTO_TCP,
36162306a36Sopenharmony_ci			    &sock, 1);
36262306a36Sopenharmony_ci	KUNIT_ASSERT_EQ(test, err, 0);
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_ci	filp = sock_alloc_file(sock, O_NONBLOCK, NULL);
36562306a36Sopenharmony_ci	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, filp);
36662306a36Sopenharmony_ci	sock->file = filp;
36762306a36Sopenharmony_ci
36862306a36Sopenharmony_ci	err = handshake_req_submit(sock, req, GFP_KERNEL);
36962306a36Sopenharmony_ci	KUNIT_ASSERT_EQ(test, err, 0);
37062306a36Sopenharmony_ci
37162306a36Sopenharmony_ci	net = sock_net(sock->sk);
37262306a36Sopenharmony_ci	hn = handshake_pernet(net);
37362306a36Sopenharmony_ci	KUNIT_ASSERT_NOT_NULL(test, hn);
37462306a36Sopenharmony_ci
37562306a36Sopenharmony_ci	/* Pretend to accept this request */
37662306a36Sopenharmony_ci	next = handshake_req_next(hn, HANDSHAKE_HANDLER_CLASS_TLSHD);
37762306a36Sopenharmony_ci	KUNIT_ASSERT_PTR_EQ(test, req, next);
37862306a36Sopenharmony_ci
37962306a36Sopenharmony_ci	/* Act */
38062306a36Sopenharmony_ci	result = handshake_req_cancel(sock->sk);
38162306a36Sopenharmony_ci
38262306a36Sopenharmony_ci	/* Assert */
38362306a36Sopenharmony_ci	KUNIT_EXPECT_TRUE(test, result);
38462306a36Sopenharmony_ci
38562306a36Sopenharmony_ci	fput(filp);
38662306a36Sopenharmony_ci}
38762306a36Sopenharmony_ci
38862306a36Sopenharmony_cistatic void handshake_req_cancel_test3(struct kunit *test)
38962306a36Sopenharmony_ci{
39062306a36Sopenharmony_ci	struct handshake_req *req, *next;
39162306a36Sopenharmony_ci	struct handshake_net *hn;
39262306a36Sopenharmony_ci	struct socket *sock;
39362306a36Sopenharmony_ci	struct file *filp;
39462306a36Sopenharmony_ci	struct net *net;
39562306a36Sopenharmony_ci	bool result;
39662306a36Sopenharmony_ci	int err;
39762306a36Sopenharmony_ci
39862306a36Sopenharmony_ci	/* Arrange */
39962306a36Sopenharmony_ci	req = handshake_req_alloc(&handshake_req_alloc_proto_good, GFP_KERNEL);
40062306a36Sopenharmony_ci	KUNIT_ASSERT_NOT_NULL(test, req);
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_ci	err = __sock_create(&init_net, PF_INET, SOCK_STREAM, IPPROTO_TCP,
40362306a36Sopenharmony_ci			    &sock, 1);
40462306a36Sopenharmony_ci	KUNIT_ASSERT_EQ(test, err, 0);
40562306a36Sopenharmony_ci
40662306a36Sopenharmony_ci	filp = sock_alloc_file(sock, O_NONBLOCK, NULL);
40762306a36Sopenharmony_ci	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, filp);
40862306a36Sopenharmony_ci	sock->file = filp;
40962306a36Sopenharmony_ci
41062306a36Sopenharmony_ci	err = handshake_req_submit(sock, req, GFP_KERNEL);
41162306a36Sopenharmony_ci	KUNIT_ASSERT_EQ(test, err, 0);
41262306a36Sopenharmony_ci
41362306a36Sopenharmony_ci	net = sock_net(sock->sk);
41462306a36Sopenharmony_ci	hn = handshake_pernet(net);
41562306a36Sopenharmony_ci	KUNIT_ASSERT_NOT_NULL(test, hn);
41662306a36Sopenharmony_ci
41762306a36Sopenharmony_ci	/* Pretend to accept this request */
41862306a36Sopenharmony_ci	next = handshake_req_next(hn, HANDSHAKE_HANDLER_CLASS_TLSHD);
41962306a36Sopenharmony_ci	KUNIT_ASSERT_PTR_EQ(test, req, next);
42062306a36Sopenharmony_ci
42162306a36Sopenharmony_ci	/* Pretend to complete this request */
42262306a36Sopenharmony_ci	handshake_complete(next, -ETIMEDOUT, NULL);
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_ci	/* Act */
42562306a36Sopenharmony_ci	result = handshake_req_cancel(sock->sk);
42662306a36Sopenharmony_ci
42762306a36Sopenharmony_ci	/* Assert */
42862306a36Sopenharmony_ci	KUNIT_EXPECT_FALSE(test, result);
42962306a36Sopenharmony_ci
43062306a36Sopenharmony_ci	fput(filp);
43162306a36Sopenharmony_ci}
43262306a36Sopenharmony_ci
43362306a36Sopenharmony_cistatic struct handshake_req *handshake_req_destroy_test;
43462306a36Sopenharmony_ci
43562306a36Sopenharmony_cistatic void test_destroy_func(struct handshake_req *req)
43662306a36Sopenharmony_ci{
43762306a36Sopenharmony_ci	handshake_req_destroy_test = req;
43862306a36Sopenharmony_ci}
43962306a36Sopenharmony_ci
44062306a36Sopenharmony_cistatic struct handshake_proto handshake_req_alloc_proto_destroy = {
44162306a36Sopenharmony_ci	.hp_handler_class	= HANDSHAKE_HANDLER_CLASS_TLSHD,
44262306a36Sopenharmony_ci	.hp_accept		= test_accept_func,
44362306a36Sopenharmony_ci	.hp_done		= test_done_func,
44462306a36Sopenharmony_ci	.hp_destroy		= test_destroy_func,
44562306a36Sopenharmony_ci};
44662306a36Sopenharmony_ci
44762306a36Sopenharmony_cistatic void handshake_req_destroy_test1(struct kunit *test)
44862306a36Sopenharmony_ci{
44962306a36Sopenharmony_ci	struct handshake_req *req;
45062306a36Sopenharmony_ci	struct socket *sock;
45162306a36Sopenharmony_ci	struct file *filp;
45262306a36Sopenharmony_ci	int err;
45362306a36Sopenharmony_ci
45462306a36Sopenharmony_ci	/* Arrange */
45562306a36Sopenharmony_ci	handshake_req_destroy_test = NULL;
45662306a36Sopenharmony_ci
45762306a36Sopenharmony_ci	req = handshake_req_alloc(&handshake_req_alloc_proto_destroy, GFP_KERNEL);
45862306a36Sopenharmony_ci	KUNIT_ASSERT_NOT_NULL(test, req);
45962306a36Sopenharmony_ci
46062306a36Sopenharmony_ci	err = __sock_create(&init_net, PF_INET, SOCK_STREAM, IPPROTO_TCP,
46162306a36Sopenharmony_ci			    &sock, 1);
46262306a36Sopenharmony_ci	KUNIT_ASSERT_EQ(test, err, 0);
46362306a36Sopenharmony_ci
46462306a36Sopenharmony_ci	filp = sock_alloc_file(sock, O_NONBLOCK, NULL);
46562306a36Sopenharmony_ci	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, filp);
46662306a36Sopenharmony_ci	sock->file = filp;
46762306a36Sopenharmony_ci
46862306a36Sopenharmony_ci	err = handshake_req_submit(sock, req, GFP_KERNEL);
46962306a36Sopenharmony_ci	KUNIT_ASSERT_EQ(test, err, 0);
47062306a36Sopenharmony_ci
47162306a36Sopenharmony_ci	handshake_req_cancel(sock->sk);
47262306a36Sopenharmony_ci
47362306a36Sopenharmony_ci	/* Act */
47462306a36Sopenharmony_ci	/* Ensure the close/release/put process has run to
47562306a36Sopenharmony_ci	 * completion before checking the result.
47662306a36Sopenharmony_ci	 */
47762306a36Sopenharmony_ci	__fput_sync(filp);
47862306a36Sopenharmony_ci
47962306a36Sopenharmony_ci	/* Assert */
48062306a36Sopenharmony_ci	KUNIT_EXPECT_PTR_EQ(test, handshake_req_destroy_test, req);
48162306a36Sopenharmony_ci}
48262306a36Sopenharmony_ci
48362306a36Sopenharmony_cistatic struct kunit_case handshake_api_test_cases[] = {
48462306a36Sopenharmony_ci	{
48562306a36Sopenharmony_ci		.name			= "req_alloc API fuzzing",
48662306a36Sopenharmony_ci		.run_case		= handshake_req_alloc_case,
48762306a36Sopenharmony_ci		.generate_params	= handshake_req_alloc_gen_params,
48862306a36Sopenharmony_ci	},
48962306a36Sopenharmony_ci	{
49062306a36Sopenharmony_ci		.name			= "req_submit NULL req arg",
49162306a36Sopenharmony_ci		.run_case		= handshake_req_submit_test1,
49262306a36Sopenharmony_ci	},
49362306a36Sopenharmony_ci	{
49462306a36Sopenharmony_ci		.name			= "req_submit NULL sock arg",
49562306a36Sopenharmony_ci		.run_case		= handshake_req_submit_test2,
49662306a36Sopenharmony_ci	},
49762306a36Sopenharmony_ci	{
49862306a36Sopenharmony_ci		.name			= "req_submit NULL sock->file",
49962306a36Sopenharmony_ci		.run_case		= handshake_req_submit_test3,
50062306a36Sopenharmony_ci	},
50162306a36Sopenharmony_ci	{
50262306a36Sopenharmony_ci		.name			= "req_lookup works",
50362306a36Sopenharmony_ci		.run_case		= handshake_req_submit_test4,
50462306a36Sopenharmony_ci	},
50562306a36Sopenharmony_ci	{
50662306a36Sopenharmony_ci		.name			= "req_submit max pending",
50762306a36Sopenharmony_ci		.run_case		= handshake_req_submit_test5,
50862306a36Sopenharmony_ci	},
50962306a36Sopenharmony_ci	{
51062306a36Sopenharmony_ci		.name			= "req_submit multiple",
51162306a36Sopenharmony_ci		.run_case		= handshake_req_submit_test6,
51262306a36Sopenharmony_ci	},
51362306a36Sopenharmony_ci	{
51462306a36Sopenharmony_ci		.name			= "req_cancel before accept",
51562306a36Sopenharmony_ci		.run_case		= handshake_req_cancel_test1,
51662306a36Sopenharmony_ci	},
51762306a36Sopenharmony_ci	{
51862306a36Sopenharmony_ci		.name			= "req_cancel after accept",
51962306a36Sopenharmony_ci		.run_case		= handshake_req_cancel_test2,
52062306a36Sopenharmony_ci	},
52162306a36Sopenharmony_ci	{
52262306a36Sopenharmony_ci		.name			= "req_cancel after done",
52362306a36Sopenharmony_ci		.run_case		= handshake_req_cancel_test3,
52462306a36Sopenharmony_ci	},
52562306a36Sopenharmony_ci	{
52662306a36Sopenharmony_ci		.name			= "req_destroy works",
52762306a36Sopenharmony_ci		.run_case		= handshake_req_destroy_test1,
52862306a36Sopenharmony_ci	},
52962306a36Sopenharmony_ci	{}
53062306a36Sopenharmony_ci};
53162306a36Sopenharmony_ci
53262306a36Sopenharmony_cistatic struct kunit_suite handshake_api_suite = {
53362306a36Sopenharmony_ci       .name                   = "Handshake API tests",
53462306a36Sopenharmony_ci       .test_cases             = handshake_api_test_cases,
53562306a36Sopenharmony_ci};
53662306a36Sopenharmony_ci
53762306a36Sopenharmony_cikunit_test_suites(&handshake_api_suite);
53862306a36Sopenharmony_ci
53962306a36Sopenharmony_ciMODULE_DESCRIPTION("Test handshake upcall API functions");
54062306a36Sopenharmony_ciMODULE_LICENSE("GPL");
541