1f08c3bdfSopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
2f08c3bdfSopenharmony_ci
3f08c3bdfSopenharmony_ci/*
4f08c3bdfSopenharmony_ci * Copyright (C) 2008, Linux Foundation,
5f08c3bdfSopenharmony_ci * Copyright (c) 2020 Petr Vorel <petr.vorel@gmail.com>
6f08c3bdfSopenharmony_ci * written by Michael Kerrisk <mtk.manpages@gmail.com>
7f08c3bdfSopenharmony_ci * Initial Porting to LTP by Subrata <subrata@linux.vnet.ibm.com>
8f08c3bdfSopenharmony_ci */
9f08c3bdfSopenharmony_ci
10f08c3bdfSopenharmony_ci#define _GNU_SOURCE
11f08c3bdfSopenharmony_ci#include <unistd.h>
12f08c3bdfSopenharmony_ci#include <sys/syscall.h>
13f08c3bdfSopenharmony_ci#include <sys/socket.h>
14f08c3bdfSopenharmony_ci#include <netinet/in.h>
15f08c3bdfSopenharmony_ci#include <stdlib.h>
16f08c3bdfSopenharmony_ci#include <stdio.h>
17f08c3bdfSopenharmony_ci#include <string.h>
18f08c3bdfSopenharmony_ci#include <errno.h>
19f08c3bdfSopenharmony_ci#include <linux/net.h>
20f08c3bdfSopenharmony_ci
21f08c3bdfSopenharmony_ci#include "tst_test.h"
22f08c3bdfSopenharmony_ci#include "lapi/fcntl.h"
23f08c3bdfSopenharmony_ci#include "lapi/syscalls.h"
24f08c3bdfSopenharmony_ci
25f08c3bdfSopenharmony_cistatic const char *variant_desc[] = {
26f08c3bdfSopenharmony_ci	"libc accept4()",
27f08c3bdfSopenharmony_ci	"__NR_accept4 syscall",
28f08c3bdfSopenharmony_ci	"__NR_socketcall SYS_ACCEPT4 syscall"};
29f08c3bdfSopenharmony_ci
30f08c3bdfSopenharmony_cistatic struct sockaddr_in *conn_addr, *accept_addr;
31f08c3bdfSopenharmony_cistatic int listening_fd;
32f08c3bdfSopenharmony_ci
33f08c3bdfSopenharmony_cistatic int socketcall_accept4(int fd, struct sockaddr *sockaddr, socklen_t
34f08c3bdfSopenharmony_ci			      *addrlen, int flags)
35f08c3bdfSopenharmony_ci{
36f08c3bdfSopenharmony_ci	long args[6];
37f08c3bdfSopenharmony_ci
38f08c3bdfSopenharmony_ci	args[0] = fd;
39f08c3bdfSopenharmony_ci	args[1] = (long)sockaddr;
40f08c3bdfSopenharmony_ci	args[2] = (long)addrlen;
41f08c3bdfSopenharmony_ci	args[3] = flags;
42f08c3bdfSopenharmony_ci
43f08c3bdfSopenharmony_ci	return tst_syscall(__NR_socketcall, SYS_ACCEPT4, args);
44f08c3bdfSopenharmony_ci}
45f08c3bdfSopenharmony_ci
46f08c3bdfSopenharmony_cistatic int create_listening_socket(void)
47f08c3bdfSopenharmony_ci{
48f08c3bdfSopenharmony_ci	struct sockaddr_in svaddr;
49f08c3bdfSopenharmony_ci	int lfd;
50f08c3bdfSopenharmony_ci	int optval;
51f08c3bdfSopenharmony_ci
52f08c3bdfSopenharmony_ci	memset(&svaddr, 0, sizeof(struct sockaddr_in));
53f08c3bdfSopenharmony_ci	svaddr.sin_family = AF_INET;
54f08c3bdfSopenharmony_ci	svaddr.sin_addr.s_addr = htonl(INADDR_ANY);
55f08c3bdfSopenharmony_ci	svaddr.sin_port = 0;
56f08c3bdfSopenharmony_ci
57f08c3bdfSopenharmony_ci	lfd = SAFE_SOCKET(AF_INET, SOCK_STREAM, 0);
58f08c3bdfSopenharmony_ci
59f08c3bdfSopenharmony_ci	optval = 1;
60f08c3bdfSopenharmony_ci	SAFE_SETSOCKOPT(lfd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval));
61f08c3bdfSopenharmony_ci	SAFE_BIND(lfd, (struct sockaddr *)&svaddr, sizeof(struct sockaddr_in));
62f08c3bdfSopenharmony_ci	SAFE_LISTEN(lfd, 5);
63f08c3bdfSopenharmony_ci
64f08c3bdfSopenharmony_ci	return lfd;
65f08c3bdfSopenharmony_ci}
66f08c3bdfSopenharmony_ci
67f08c3bdfSopenharmony_cistatic void setup(void)
68f08c3bdfSopenharmony_ci{
69f08c3bdfSopenharmony_ci	socklen_t slen = sizeof(*conn_addr);
70f08c3bdfSopenharmony_ci
71f08c3bdfSopenharmony_ci	tst_res(TINFO, "Testing variant: %s", variant_desc[tst_variant]);
72f08c3bdfSopenharmony_ci
73f08c3bdfSopenharmony_ci	listening_fd = create_listening_socket();
74f08c3bdfSopenharmony_ci
75f08c3bdfSopenharmony_ci	memset(conn_addr, 0, sizeof(*conn_addr));
76f08c3bdfSopenharmony_ci	SAFE_GETSOCKNAME(listening_fd, (struct sockaddr *)conn_addr, &slen);
77f08c3bdfSopenharmony_ci	conn_addr->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
78f08c3bdfSopenharmony_ci	tst_res(TINFO, "server listening on: %d", ntohs(conn_addr->sin_port));
79f08c3bdfSopenharmony_ci}
80f08c3bdfSopenharmony_ci
81f08c3bdfSopenharmony_cistatic void cleanup(void)
82f08c3bdfSopenharmony_ci{
83f08c3bdfSopenharmony_ci	SAFE_CLOSE(listening_fd);
84f08c3bdfSopenharmony_ci}
85f08c3bdfSopenharmony_ci
86f08c3bdfSopenharmony_cistatic struct test_case {
87f08c3bdfSopenharmony_ci	int cloexec;
88f08c3bdfSopenharmony_ci	int nonblock;
89f08c3bdfSopenharmony_ci} tcases[] = {
90f08c3bdfSopenharmony_ci	{ 0, 0 },
91f08c3bdfSopenharmony_ci	{ SOCK_CLOEXEC, 0 },
92f08c3bdfSopenharmony_ci	{ 0, SOCK_NONBLOCK },
93f08c3bdfSopenharmony_ci	{ SOCK_CLOEXEC, SOCK_NONBLOCK },
94f08c3bdfSopenharmony_ci};
95f08c3bdfSopenharmony_ci
96f08c3bdfSopenharmony_cistatic void verify_accept4(unsigned int nr)
97f08c3bdfSopenharmony_ci{
98f08c3bdfSopenharmony_ci	struct test_case *tcase = &tcases[nr];
99f08c3bdfSopenharmony_ci	int flags = tcase->cloexec | tcase->nonblock;
100f08c3bdfSopenharmony_ci	int connfd, acceptfd;
101f08c3bdfSopenharmony_ci	int fdf, flf, fdf_pass, flf_pass, fd_cloexec, fd_nonblock;
102f08c3bdfSopenharmony_ci	socklen_t addrlen;
103f08c3bdfSopenharmony_ci
104f08c3bdfSopenharmony_ci	connfd = SAFE_SOCKET(AF_INET, SOCK_STREAM, 0);
105f08c3bdfSopenharmony_ci	SAFE_CONNECT(connfd, (struct sockaddr *)conn_addr, sizeof(*conn_addr));
106f08c3bdfSopenharmony_ci	addrlen = sizeof(*accept_addr);
107f08c3bdfSopenharmony_ci
108f08c3bdfSopenharmony_ci	switch (tst_variant) {
109f08c3bdfSopenharmony_ci	case 0:
110f08c3bdfSopenharmony_ci		TEST(accept4(listening_fd, (struct sockaddr *)accept_addr,
111f08c3bdfSopenharmony_ci			     &addrlen, flags));
112f08c3bdfSopenharmony_ci	break;
113f08c3bdfSopenharmony_ci	case 1:
114f08c3bdfSopenharmony_ci		TEST(tst_syscall(__NR_accept4, listening_fd,
115f08c3bdfSopenharmony_ci				 (struct sockaddr *)accept_addr,
116f08c3bdfSopenharmony_ci				 &addrlen, flags));
117f08c3bdfSopenharmony_ci	break;
118f08c3bdfSopenharmony_ci	case 2:
119f08c3bdfSopenharmony_ci		TEST(socketcall_accept4(listening_fd, (struct sockaddr *)accept_addr,
120f08c3bdfSopenharmony_ci				&addrlen, flags));
121f08c3bdfSopenharmony_ci	break;
122f08c3bdfSopenharmony_ci	}
123f08c3bdfSopenharmony_ci
124f08c3bdfSopenharmony_ci	if (TST_RET == -1)
125f08c3bdfSopenharmony_ci		tst_brk(TBROK | TTERRNO, "accept4 failed");
126f08c3bdfSopenharmony_ci
127f08c3bdfSopenharmony_ci	acceptfd = TST_RET;
128f08c3bdfSopenharmony_ci
129f08c3bdfSopenharmony_ci	/* Test to see if O_CLOEXEC is as expected */
130f08c3bdfSopenharmony_ci	fdf = SAFE_FCNTL(acceptfd, F_GETFD);
131f08c3bdfSopenharmony_ci	fd_cloexec = !!(fdf & FD_CLOEXEC);
132f08c3bdfSopenharmony_ci	fdf_pass = fd_cloexec == !!tcase->cloexec;
133f08c3bdfSopenharmony_ci	if (!fdf_pass) {
134f08c3bdfSopenharmony_ci		tst_res(TFAIL, "Close-on-exec flag mismatch, %d vs %d",
135f08c3bdfSopenharmony_ci			fd_cloexec, !!tcase->cloexec);
136f08c3bdfSopenharmony_ci	}
137f08c3bdfSopenharmony_ci
138f08c3bdfSopenharmony_ci	/* Test to see if O_NONBLOCK is as expected */
139f08c3bdfSopenharmony_ci	flf = SAFE_FCNTL(acceptfd, F_GETFL);
140f08c3bdfSopenharmony_ci	fd_nonblock = !!(flf & O_NONBLOCK);
141f08c3bdfSopenharmony_ci	flf_pass = fd_nonblock == !!tcase->nonblock;
142f08c3bdfSopenharmony_ci	if (!flf_pass) {
143f08c3bdfSopenharmony_ci		tst_res(TFAIL, "nonblock flag mismatch, %d vs %d",
144f08c3bdfSopenharmony_ci		        fd_nonblock, !!tcase->nonblock);
145f08c3bdfSopenharmony_ci	}
146f08c3bdfSopenharmony_ci
147f08c3bdfSopenharmony_ci	SAFE_CLOSE(acceptfd);
148f08c3bdfSopenharmony_ci	SAFE_CLOSE(connfd);
149f08c3bdfSopenharmony_ci
150f08c3bdfSopenharmony_ci	if (fdf_pass && flf_pass) {
151f08c3bdfSopenharmony_ci		tst_res(TPASS, "Close-on-exec %d, nonblock %d",
152f08c3bdfSopenharmony_ci				fd_cloexec, fd_nonblock);
153f08c3bdfSopenharmony_ci	}
154f08c3bdfSopenharmony_ci}
155f08c3bdfSopenharmony_ci
156f08c3bdfSopenharmony_cistatic struct tst_test test = {
157f08c3bdfSopenharmony_ci	.tcnt = ARRAY_SIZE(tcases),
158f08c3bdfSopenharmony_ci	.setup = setup,
159f08c3bdfSopenharmony_ci	.cleanup = cleanup,
160f08c3bdfSopenharmony_ci	.test_variants = ARRAY_SIZE(variant_desc),
161f08c3bdfSopenharmony_ci	.test = verify_accept4,
162f08c3bdfSopenharmony_ci	.bufs = (struct tst_buffers []) {
163f08c3bdfSopenharmony_ci		{&conn_addr, .size = sizeof(*conn_addr)},
164f08c3bdfSopenharmony_ci		{&accept_addr, .size = sizeof(*accept_addr)},
165f08c3bdfSopenharmony_ci		{},
166f08c3bdfSopenharmony_ci	}
167f08c3bdfSopenharmony_ci};
168