1/*
2 *
3 *   Copyright (c) International Business Machines  Corp., 2001
4 *
5 *   This program is free software;  you can redistribute it and/or modify
6 *   it under the terms of the GNU General Public License as published by
7 *   the Free Software Foundation; either version 2 of the License, or
8 *   (at your option) any later version.
9 *
10 *   This program is distributed in the hope that it will be useful,
11 *   but WITHOUT ANY WARRANTY;  without even the implied warranty of
12 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
13 *   the GNU General Public License for more details.
14 *
15 *   You should have received a copy of the GNU General Public License
16 *   along with this program;  if not, write to the Free Software
17 *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19
20/*
21 * Test Name: sockioctl01
22 *
23 * Test Description:
24 *  Verify that ioctl() on sockets returns the proper errno for various
25 *  failure cases
26 */
27
28#include <stdio.h>
29#include <unistd.h>
30#include <errno.h>
31#include <fcntl.h>
32
33#include <sys/types.h>
34#include <sys/socket.h>
35#include <sys/signal.h>
36#include <sys/ioctl.h>
37#include <sys/stat.h>
38
39#include <netinet/in.h>
40#include <net/if.h>
41
42#include "test.h"
43#include "safe_macros.h"
44
45char *TCID = "sockioctl01";
46int testno;
47
48static int s; /* socket descriptor */
49static struct sockaddr_in sin0, fsin1;
50static struct ifconf ifc;
51static struct ifreq ifr;
52static int sinlen;
53static int optval;
54
55static char buf[8192];
56
57static void setup(void);
58static void setup0(void);
59static void setup1(void);
60static void setup2(void);
61static void setup3(void);
62
63static void cleanup(void);
64static void cleanup0(void);
65static void cleanup1(void);
66
67struct test_case_t {
68	int domain;		/* PF_INET, PF_UNIX, ... */
69	int type;		/* SOCK_STREAM, SOCK_DGRAM ... */
70	int proto;		/* protocol number (usually 0 = default) */
71	int cmd;		/* IPPROTO_* */
72	void *arg;
73	struct sockaddr *sin;
74	int salen;
75	int retval;		/* syscall return value */
76	int experrno;		/* expected errno */
77	void (*setup) (void);
78	void (*cleanup) (void);
79	char *desc;
80} tdat[] = {
81	{
82	PF_INET, SOCK_STREAM, 0, SIOCATMARK, &optval,
83		    (struct sockaddr *)&fsin1, sizeof(fsin1), -1,
84		    EBADF, setup0, cleanup0, "bad file descriptor"}
85	, {
86	PF_INET, SOCK_STREAM, 0, SIOCATMARK, &optval,
87		    (struct sockaddr *)&fsin1, sizeof(fsin1), -1,
88		    EINVAL, setup0, cleanup0, "not a socket"}
89	,
90#if !defined(UCLINUX)
91	{
92	PF_INET, SOCK_STREAM, 0, SIOCATMARK, 0,
93		    (struct sockaddr *)&fsin1, sizeof(fsin1), -1,
94		    EFAULT, setup1, cleanup1, "invalid option buffer"}
95	,
96#endif
97	{
98	PF_INET, SOCK_DGRAM, 0, SIOCATMARK, &optval,
99		    (struct sockaddr *)&fsin1, sizeof(fsin1), -1,
100		    EINVAL, setup1, cleanup1, "ATMARK on UDP"}
101	, {
102	PF_INET, SOCK_DGRAM, 0, SIOCGIFCONF, &ifc,
103		    (struct sockaddr *)&fsin1, sizeof(fsin1), 0,
104		    0, setup2, cleanup1, "SIOCGIFCONF"}
105	, {
106	PF_INET, SOCK_DGRAM, 0, SIOCGIFFLAGS, &ifr,
107		    (struct sockaddr *)&fsin1, sizeof(fsin1), 0,
108		    0, setup3, cleanup1, "SIOCGIFFLAGS"}
109	, {
110	PF_INET, SOCK_DGRAM, 0, SIOCGIFFLAGS, 0,
111		    (struct sockaddr *)&fsin1, sizeof(fsin1), -1,
112		    EFAULT, setup3, cleanup1, "SIOCGIFFLAGS with invalid ifr"}
113	, {
114	PF_INET, SOCK_DGRAM, 0, SIOCSIFFLAGS, 0,
115		    (struct sockaddr *)&fsin1, sizeof(fsin1), -1,
116		    EFAULT, setup3, cleanup1, "SIOCSIFFLAGS with invalid ifr"}
117,};
118
119int TST_TOTAL = sizeof(tdat) / sizeof(tdat[0]);
120
121int main(int argc, char *argv[])
122{
123	int lc;
124
125	tst_parse_opts(argc, argv, NULL, NULL);
126
127	setup();
128
129	for (lc = 0; TEST_LOOPING(lc); ++lc) {
130		tst_count = 0;
131		for (testno = 0; testno < TST_TOTAL; ++testno) {
132			tdat[testno].setup();
133
134			TEST(ioctl(s, tdat[testno].cmd, tdat[testno].arg));
135			if (TEST_RETURN != tdat[testno].retval ||
136			    (TEST_RETURN < 0 &&
137			     TEST_ERRNO != tdat[testno].experrno)) {
138				tst_resm(TFAIL, "%s ; returned"
139					 " %ld (expected %d), errno %d (expected"
140					 " %d)", tdat[testno].desc,
141					 TEST_RETURN, tdat[testno].retval,
142					 TEST_ERRNO, tdat[testno].experrno);
143			} else {
144				tst_resm(TPASS, "%s successful",
145					 tdat[testno].desc);
146			}
147			tdat[testno].cleanup();
148		}
149	}
150
151	cleanup();
152	tst_exit();
153}
154
155static void setup(void)
156{
157	TEST_PAUSE;
158
159	sin0.sin_family = AF_INET;
160	sin0.sin_port = 0;
161	sin0.sin_addr.s_addr = INADDR_ANY;
162
163	tst_tmpdir();
164}
165
166static void cleanup(void)
167{
168	tst_rmdir();
169}
170
171static void setup0(void)
172{
173	if (tdat[testno].experrno == EBADF) {
174		s = 1025;	/* anything not an open file */
175	} else {
176		unlink("test");
177
178		if ((mknod("test", S_IRWXU | S_IFIFO, 0)) == -1) {
179			tst_brkm(TBROK, cleanup, "Could not create test - "
180				 "errno: %s", strerror(errno));
181		}
182
183		if ((s = open("test", O_RDWR)) == -1) {
184			tst_brkm(TBROK, cleanup, "Could not open test - "
185				 "errno: %s", strerror(errno));
186		}
187
188		/*
189		 * kernel commit 46ce341b2f176c2611f12ac390adf862e932eb02
190		 * changed -EINVAL to -ENOIOCTLCMD, so vfs_ioctl now
191		 * returns -ENOTTY.
192		 */
193		if ((tst_kvercmp(3, 5, 0)) >= 0)
194			tdat[testno].experrno = ENOTTY;
195	}
196}
197
198static void cleanup0(void)
199{
200	if (tdat[testno].experrno != EBADF) {
201		(void)close(s);
202		s = -1;
203	}
204}
205
206static void setup1(void)
207{
208	s = SAFE_SOCKET(cleanup, tdat[testno].domain, tdat[testno].type,
209			tdat[testno].proto);
210	SAFE_BIND(cleanup, s, (struct sockaddr *)&sin0, sizeof(sin0));
211	sinlen = sizeof(fsin1);
212
213	if (strncmp(tdat[testno].desc, "ATMARK on UDP", 14) == 0) {
214		if ((tst_kvercmp(2, 6, 39)) >= 0)
215			tdat[testno].experrno = ENOTTY;
216	}
217}
218
219static void setup2(void)
220{
221	s = SAFE_SOCKET(cleanup, tdat[testno].domain, tdat[testno].type,
222			tdat[testno].proto);
223	ifc.ifc_len = sizeof(buf);
224	ifc.ifc_buf = buf;
225}
226
227static void setup3(void)
228{
229	setup2();
230	SAFE_IOCTL(cleanup, s, SIOCGIFCONF, &ifc);
231	ifr = *(struct ifreq *)ifc.ifc_buf;
232}
233
234static void cleanup1(void)
235{
236	(void)close(s);
237	s = -1;
238}
239