1/* SCTP kernel Implementation
2 * Copyright (c) 2003 Hewlett-Packard Development Company, L.P
3 * (C) Copyright IBM Corp. 2004
4 *
5 * This file has test cases to test negative scenarios for getsockopt ()
6 * setsockopt () call for 1-1 style sockets
7 *
8 * setsockopt () Tests:
9 * -------------------
10 * TEST1: setsockopt: Bad socket descriptor
11 * TEST2: setsockopt: Invalid socket
12 * TEST3: setsockopt: Invalid level
13 * TEST4: setsockopt: Invalid option buffer
14 * TEST5: setsockopt: Invalid option name
15 * TEST6: getsockopt: Bad socket descriptor
16 * TEST7: getsockopt: Invalid socket
17 * TEST8: getsockopt: Invalid option buffer
18 * TEST9: getsockopt: Invalid option name
19 *
20 * TEST10: getsockopt: SCTP_INITMSG
21 * TEST11: setsockopt: SCTP_INITMSG
22 * TEST12: setsockopt: SO_LINGER
23 * TEST13: getsockopt: SO_LINGER
24 * TEST14: getsockopt: SO_RCVBUF
25 * TEST15: getsockopt: SCTP_STATUS
26 * TEST16: setsockopt: SO_RCVBUF
27 * TEST17: setsockopt: SO_SNDBUF
28 * TEST18: getsockopt: SO_SNDBUF
29 * TEST19: getsockopt: SCTP_PRIMARY_ADDR
30 * TEST20: setsockopt: SCTP_PRIMARY_ADDR
31 * TEST21: getsockopt: SCTP_ASSOCINFO
32 * TEST22: setsockopt: SCTP_ASSOCINFO
33 *
34 * The SCTP implementation is free software;
35 * you can redistribute it and/or modify it under the terms of
36 * the GNU General Public License as published by
37 * the Free Software Foundation; either version 2, or (at your option)
38 * any later version.
39 *
40 * The SCTP implementation is distributed in the hope that it
41 * will be useful, but WITHOUT ANY WARRANTY; without even the implied
42 *                 ************************
43 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
44 * See the GNU General Public License for more details.
45 *
46 * You should have received a copy of the GNU General Public License
47 * along with GNU CC; see the file COPYING.  If not, write to
48 * the Free Software Foundation, 59 Temple Place - Suite 330,
49 * Boston, MA 02111-1307, USA.
50 *
51 * Please send any bug reports or fixes you make to the
52 * email address(es):
53 *    lksctp developers <lksctp-developers@lists.sourceforge.net>
54 *
55 * Or submit a bug report through the following website:
56 *    http://www.sf.net/projects/lksctp
57 *
58 * Any bugs reported given to us we will try to fix... any fixes shared will
59 * be incorporated into the next SCTP release.
60 *
61 */
62
63#include <stdio.h>
64#include <unistd.h>
65#include <fcntl.h>
66#include <stdlib.h>
67#include <string.h>
68#include <sys/types.h>
69#include <sys/socket.h>
70#include <netinet/in.h>
71#include <errno.h>
72#include <netinet/sctp.h>
73#include <sys/uio.h>
74#include <sctputil.h>
75
76char *TCID = __FILE__;
77int TST_TOTAL = 22;
78int TST_CNT = 0;
79
80int
81main(void)
82{
83	int error;
84	socklen_t len;
85	int sk, sk1, sk2, acpt_sk, pf_class;
86	struct sctp_rtoinfo grtinfo;
87	struct sockaddr_in lstn_addr, conn_addr;
88	struct sctp_initmsg ginmsg; /*get the value for SCTP_INITMSG*/
89	struct sctp_initmsg sinmsg; /*set the value for SCTP_INITMSG*/
90	struct linger slinger; /*SO_LINGER structure*/
91	struct linger glinger; /*SO_LINGER structure*/
92	struct sockaddr_in addr;
93	struct sockaddr_in *gaddr;
94	struct sctp_status gstatus; /*SCTP_STATUS option*/
95	int rcvbuf_val_get, rcvbuf_val_set; /*get and set var for SO_RCVBUF*/
96	int sndbuf_val_get, sndbuf_val_set;/*get and set var for SO_SNDBUF*/
97	struct sctp_prim gprimaddr;/*SCTP_PRIMARY_ADDR get*/
98	struct sctp_prim sprimaddr;/*SCTP_PRIMARY_ADDR set*/
99	struct sctp_assocparams sassocparams;  /* SCTP_ASSOCPARAMS set */
100	struct sctp_assocparams gassocparams;  /* SCTP_ASSOCPARAMS get */
101	int fd, err_no = 0;
102	char filename[21];
103
104	/* Rather than fflush() throughout the code, set stdout to
105         * be unbuffered.
106         */
107        setvbuf(stdout, NULL, _IONBF, 0);
108        setvbuf(stderr, NULL, _IONBF, 0);
109
110	pf_class = PF_INET;
111
112	sk = test_socket(pf_class, SOCK_STREAM, IPPROTO_SCTP);
113
114	/*setsockopt() TEST1: Bad socket descriptor EBADF, Expected error*/
115        error = setsockopt(-1, IPPROTO_SCTP, 0, 0, 0);
116	if (error != -1 || errno != EBADF)
117		tst_brkm(TBROK, tst_exit, "setsockopt with a bad socket "
118			 "descriptor error:%d, errno:%d", error, errno);
119
120	tst_resm(TPASS, "setsockopt() with a bad socket descriptor - EBADF");
121
122	/*setsockopt() TEST2: Invalid socket ENOTSOCK, Expected error*/
123	strcpy(filename, "/tmp/sctptest.XXXXXX");
124	fd = mkstemp(filename);
125	if (fd == -1)
126		tst_brkm(TBROK, tst_exit, "Failed to mkstemp %s: %s",
127				filename, strerror(errno));
128	error = setsockopt(fd, IPPROTO_SCTP, 0, 0, 0);
129	if (error == -1)
130		err_no = errno;
131	close(fd);
132	unlink(filename);
133	if (error != -1 || err_no != ENOTSOCK)
134		tst_brkm(TBROK, tst_exit, "setsockopt with an invalid socket "
135			 "error:%d, errno:%d", error, err_no);
136
137	tst_resm(TPASS, "setsockopt() with an invalid socket - ENOTSOCK");
138
139	/*setsockopt() TEST3: Invalid level ENOPROTOOPT, Expected error*/
140        error = setsockopt(sk, -1, SCTP_RTOINFO, 0, 0);
141	if (error != -1 || errno != ENOPROTOOPT)
142		tst_brkm(TBROK, tst_exit, "setsockopt with invalid level "
143			 "error:%d, errno:%d", error, errno);
144
145	tst_resm(TPASS, "setsockopt() with an invalid level - ENOPROTOOPT");
146
147	/*setsockopt() TEST4: Invalid option buffer EFAULT, Expected error*/
148        error = setsockopt(sk, IPPROTO_SCTP, SCTP_RTOINFO,
149		(const struct sctp_rtoinfo *)-1, sizeof(struct sctp_rtoinfo));
150	if (error != -1 || errno != EFAULT)
151		tst_brkm(TBROK, tst_exit, "setsockopt with invalid option "
152			 "buffer error:%d, errno:%d", error, errno);
153
154	tst_resm(TPASS, "setsockopt() with invalid option buffer - EFAULT");
155
156	/*setsockopt() TEST5: Invalid option Name EOPNOTSUPP, Expected error*/
157        error = setsockopt(sk, IPPROTO_SCTP, SCTP_AUTOCLOSE, 0, 0);
158	if (error != -1 || errno != EOPNOTSUPP)
159		tst_brkm(TBROK, tst_exit, "setsockopt with invalid option "
160			 "name error:%d, errno:%d", error, errno);
161
162	tst_resm(TPASS, "setsockopt() with invalid option name - EOPNOTSUPP");
163
164	/*getsockopt() TEST6: Bad socket descriptor EBADF, Expected error*/
165        error = getsockopt(-1, IPPROTO_SCTP, 0, 0, 0);
166	if (error != -1 || errno != EBADF)
167		tst_brkm(TBROK, tst_exit, "getsockopt with a bad socket "
168			 "descriptor error:%d, errno:%d", error, errno);
169
170	tst_resm(TPASS, "getsockopt() with a bad socket descriptor - EBADF");
171
172	/*getsockopt() TEST7: Invalid socket ENOTSOCK, Expected error*/
173	strcpy(filename, "/tmp/sctptest.XXXXXX");
174	fd = mkstemp(filename);
175	if (fd == -1)
176		tst_brkm(TBROK, tst_exit, "Failed to mkstemp %s: %s",
177				filename, strerror(errno));
178	error = getsockopt(fd, IPPROTO_SCTP, 0, 0, 0);
179	if (error == -1)
180		err_no = errno;
181	close(fd);
182	unlink(filename);
183	if (error != -1 || err_no != ENOTSOCK)
184		tst_brkm(TBROK, tst_exit, "getsockopt with an invalid socket "
185			 "error:%d, errno:%d", error, err_no);
186
187	tst_resm(TPASS, "getsockopt() with an invalid socket - ENOTSOCK");
188#if 0
189	/*getsockopt() TEST3: Invalid level ENOPROTOOPT, Expected error*/
190	/*I have commented this test case because it is returning EOPNOTSUPP.
191	When I checked the code there also it is returning EOPNOTSUPP. As this
192	is not specific to TCP style, I do not want to do the code change*/
193
194        error = getsockopt(sk, -1, SCTP_RTOINFO, 0, 0);
195	if (error != -1 || errno != ENOPROTOOPT)
196		tst_brkm(TBROK, tst_exit, "getsockopt with invalid level "
197			 "error:%d, errno:%d", error, errno);
198
199	tst_resm(TPASS, "getsockopt() with an invalid level - ENOPROTOOPT");
200#endif
201	len = sizeof(struct sctp_rtoinfo);
202
203	/*getsockopt() TEST8: Invalid option buffer EFAULT, Expected error*/
204        error = getsockopt(sk, IPPROTO_SCTP, SCTP_RTOINFO,
205			   (struct sctp_rtoinfo *)-1, &len);
206	if (error != -1 || errno != EFAULT)
207		tst_brkm(TBROK, tst_exit, "getsockopt with invalid option "
208			 "buffer error:%d, errno:%d", error, errno);
209
210	tst_resm(TPASS, "getsockopt() with invalid option buffer - EFAULT");
211
212	/*getsockopt() TEST9: Invalid option Name EOPNOTSUPP, Expected error*/
213        error = getsockopt(sk, IPPROTO_SCTP, SCTP_AUTOCLOSE, &grtinfo, &len);
214	if (error != -1 || errno != EOPNOTSUPP)
215		tst_brkm(TBROK, tst_exit, "getsockopt with invalid option "
216			 "name error:%d, errno:%d", error, errno);
217
218	tst_resm(TPASS, "getsockopt() with invalid option name - EOPNOTSUPP");
219
220	close(sk);
221
222	sk1 = test_socket(pf_class, SOCK_STREAM, IPPROTO_SCTP);
223	sk2 = test_socket(pf_class, SOCK_STREAM, IPPROTO_SCTP);
224
225	lstn_addr.sin_family = AF_INET;
226        lstn_addr.sin_addr.s_addr = SCTP_IP_LOOPBACK;
227        lstn_addr.sin_port = htons(SCTP_TESTPORT_1);
228
229	conn_addr.sin_family = AF_INET;
230        conn_addr.sin_addr.s_addr = SCTP_IP_LOOPBACK;
231        conn_addr.sin_port = htons(SCTP_TESTPORT_1);
232
233        len = sizeof(struct sctp_initmsg);
234
235	/* TEST10: Test cases for getsockopt SCTP_INITMSG */
236	test_getsockopt(sk1, SCTP_INITMSG, &ginmsg, &len);
237
238	tst_resm(TPASS, "getsockopt() SCTP_INITMSG - SUCCESS");
239
240	sinmsg.sinit_num_ostreams = 5;
241        sinmsg.sinit_max_instreams = 5;
242        sinmsg.sinit_max_attempts = 3;
243        sinmsg.sinit_max_init_timeo = 30;
244	/* TEST11: Test case for setsockopt SCTP_INITMSG */
245	test_setsockopt(sk1, SCTP_INITMSG, &sinmsg, sizeof(sinmsg));
246
247	test_getsockopt(sk1, SCTP_INITMSG, &ginmsg, &len);
248
249	if (sinmsg.sinit_num_ostreams != ginmsg.sinit_num_ostreams &&
250	    sinmsg.sinit_max_instreams != ginmsg.sinit_max_instreams &&
251	    sinmsg.sinit_max_attempts != ginmsg.sinit_max_attempts &&
252	    sinmsg.sinit_max_init_timeo != ginmsg.sinit_max_init_timeo)
253		tst_brkm(TBROK, tst_exit, "setsockopt/getsockopt SCTP_INITMSG "
254			 "compare failed");
255
256	tst_resm(TPASS, "setsockopt() SCTP_INITMSG - SUCCESS");
257
258	/*Now get the values on different endpoint*/
259	test_getsockopt(sk2, SCTP_INITMSG, &ginmsg, &len);
260
261	/*Comparison should not succeed here*/
262	if (sinmsg.sinit_num_ostreams == ginmsg.sinit_num_ostreams &&
263	    sinmsg.sinit_max_instreams == ginmsg.sinit_max_instreams &&
264	    sinmsg.sinit_max_attempts == ginmsg.sinit_max_attempts &&
265	    sinmsg.sinit_max_init_timeo == ginmsg.sinit_max_init_timeo)
266		tst_brkm(TBROK, tst_exit, "setsockopt/getsockopt SCTP_INITMSG "
267			 "unexpected compare success");
268
269	/* SO_LINGER Test with l_onff = 0 and l_linger = 0 */
270	slinger.l_onoff = 0;
271	slinger.l_linger = 0;
272	test_bind(sk1, (struct sockaddr *) &lstn_addr, sizeof(lstn_addr));
273	test_listen(sk1, 10 );
274	len = sizeof(struct sockaddr_in);
275	test_connect(sk2, (struct sockaddr *) &conn_addr, len);
276
277	acpt_sk = test_accept(sk1, (struct sockaddr *)&addr, &len);
278
279        len = sizeof(struct linger);
280	/* TEST12: Test case for setsockopt SO_LINGER */
281	error = setsockopt(sk2, SOL_SOCKET, SO_LINGER, &slinger, len);
282	if (error < 0)
283		tst_brkm(TBROK, tst_exit, "setsockopt SO_LINGER "
284                         "error:%d, errno:%d", error, errno);
285
286	tst_resm(TPASS, "setsockopt() SO_LINGER - SUCCESS");
287
288	/* TEST13: Test case for getsockopt SO_LINGER */
289	error = getsockopt(sk2, SOL_SOCKET, SO_LINGER, &glinger, &len);
290	if (error < 0)
291		tst_brkm(TBROK, tst_exit, "getsockopt SO_LINGER "
292                         "error:%d, errno:%d", error, errno);
293
294	tst_resm(TPASS, "getsockopt() SO_LINGER - SUCCESS");
295
296	if (slinger.l_onoff != glinger.l_onoff ||
297	    slinger.l_linger != glinger.l_linger)
298		tst_brkm(TBROK, tst_exit, "setsockopt/getsockopt SO_LINGER "
299			 "compare failed");
300
301	/*First gets the default SO_RCVBUF value and comapres with the
302	value obtained from SCTP_STATUS*/
303	len = sizeof(int);
304	/* TEST14: Test case for getsockopt SO_RCVBUF */
305	error = getsockopt(sk2, SOL_SOCKET, SO_RCVBUF, &rcvbuf_val_get, &len);
306	if (error < 0)
307		tst_brkm(TBROK, tst_exit, "getsockopt SO_RCVBUF "
308                         "error:%d, errno:%d", error, errno);
309
310	tst_resm(TPASS, "getsockopt() SO_RCVBUF - SUCCESS");
311
312	len = sizeof(struct sctp_status);
313	/* TEST15: Test case for getsockopt SCTP_STATUS */
314	error = getsockopt(sk2, IPPROTO_SCTP, SCTP_STATUS, &gstatus, &len);
315	if (error < 0)
316		tst_brkm(TBROK, tst_exit, "getsockopt SCTP_STATUS "
317                         "error:%d, errno:%d", error, errno);
318
319	tst_resm(TPASS, "getsockopt() SCTP_STATUS - SUCCESS");
320
321	/* Reducing the SO_RCVBUF value using setsockopt() */
322	/* Upstream has changed the MIN_RCVBUF (2048 + sizeof(struct sk_buff)) */
323	len = sizeof(int);
324	rcvbuf_val_set = 2048;
325	/* TEST16: Test case for setsockopt SO_RCVBUF */
326	error = setsockopt(sk2, SOL_SOCKET, SO_RCVBUF, &rcvbuf_val_set, len);
327	if (error < 0)
328		tst_brkm(TBROK, tst_exit, "setsockopt SO_RCVBUF "
329                         "error:%d, errno:%d", error, errno);
330
331	tst_resm(TPASS, "setsockopt() SO_RCVBUF - SUCCESS");
332
333	error = getsockopt(sk2, SOL_SOCKET, SO_RCVBUF, &rcvbuf_val_get, &len);
334	if (error < 0)
335		tst_brkm(TBROK, tst_exit, "getsockopt SO_RCVBUF "
336                         "error:%d, errno:%d", error, errno);
337
338	if ((2 * rcvbuf_val_set) != rcvbuf_val_get)
339		tst_brkm(TBROK, tst_exit, "Comparison failed:Set value and "
340			 "got value differs Set Value=%d Get Value=%d",
341			 (2*rcvbuf_val_set), rcvbuf_val_get);
342
343	sndbuf_val_set = 5000;
344	/* TEST17: Test case for setsockopt SO_SNDBUF */
345	error = setsockopt(sk2, SOL_SOCKET, SO_SNDBUF, &sndbuf_val_set, len);
346	if (error < 0)
347		tst_brkm(TBROK, tst_exit, "setsockopt SO_SNDBUF "
348                         "error:%d, errno:%d", error, errno);
349
350	tst_resm(TPASS, "setsockopt() SO_SNDBUF - SUCCESS");
351
352	/* TEST18: Test case for getsockopt SO_SNDBUF */
353	error = getsockopt(sk2, SOL_SOCKET, SO_SNDBUF, &sndbuf_val_get, &len);
354	if (error < 0)
355		tst_brkm(TBROK, tst_exit, "getsockopt SO_SNDBUF "
356                         "error:%d, errno:%d", error, errno);
357
358	tst_resm(TPASS, "getsockopt() SO_SNDBUF - SUCCESS");
359
360	if ((2 * sndbuf_val_set) != sndbuf_val_get)
361		tst_brkm(TBROK, tst_exit, "Comparison failed:Set value and "
362			 "got value differs Set Value=%d Get Value=%d\n",
363			 (2*sndbuf_val_set), sndbuf_val_get);
364
365
366	/* Getting the primary address using SCTP_PRIMARY_ADDR */
367        len = sizeof(struct sctp_prim);
368	/* TEST19: Test case for getsockopt SCTP_PRIMARY_ADDR */
369	error = getsockopt(sk2,IPPROTO_SCTP, SCTP_PRIMARY_ADDR, &gprimaddr,
370			   &len);
371	if (error < 0)
372		tst_brkm(TBROK, tst_exit, "getsockopt SCTP_PRIMARY_ADDR "
373                         "error:%d, errno:%d", error, errno);
374
375	tst_resm(TPASS, "getsockopt() SCTP_PRIMARY_ADDR - SUCCESS");
376
377	gaddr = (struct sockaddr_in *) &gprimaddr.ssp_addr;
378	if(htons(gaddr->sin_port) != lstn_addr.sin_port &&
379	   gaddr->sin_family != lstn_addr.sin_family &&
380	   gaddr->sin_addr.s_addr != lstn_addr.sin_addr.s_addr)
381		tst_brkm(TBROK, tst_exit, "getsockopt SCTP_PRIMARY_ADDR value "
382			 "mismatch");
383
384	memcpy(&sprimaddr, &gprimaddr, sizeof(struct sctp_prim));
385
386	/* TEST20: Test case for setsockopt SCTP_PRIMARY_ADDR */
387	error = setsockopt(sk2,IPPROTO_SCTP, SCTP_PRIMARY_ADDR, &sprimaddr,
388			   len);
389	if (error < 0)
390		tst_brkm(TBROK, tst_exit, "setsockopt SCTP_PRIMARY_ADDR "
391                         "error:%d, errno:%d", error, errno);
392
393	tst_resm(TPASS, "setsockopt() SCTP_PRIMARY_ADDR - SUCCESS");
394
395	/* TEST21: Test case for getsockopt SCTP_PRIMARY_ADDR */
396	/* Getting the association info using SCTP_ASSOCINFO */
397        len = sizeof(struct sctp_assocparams);
398	error = getsockopt(sk2, IPPROTO_SCTP, SCTP_ASSOCINFO, &gassocparams,
399			   &len);
400	if (error < 0)
401		tst_brkm(TBROK, tst_exit, "getsockopt SCTP_ASSOCINFO "
402                         "error:%d, errno:%d", error, errno);
403
404	tst_resm(TPASS, "getsockopt() SCTP_ASSOCINFO - SUCCESS");
405
406	/* TEST21: Test case for setsockopt SCTP_ASSOCINFO */
407	memcpy(&sassocparams, &gassocparams, sizeof(struct sctp_assocparams));
408	sassocparams.sasoc_asocmaxrxt += 5;
409	sassocparams.sasoc_cookie_life += 10;
410
411	error = setsockopt(sk2, IPPROTO_SCTP, SCTP_ASSOCINFO, &sassocparams,
412			   len);
413	if (error < 0)
414		tst_brkm(TBROK, tst_exit, "setsockopt SCTP_ASSOCINFO "
415                         "error:%d, errno:%d", error, errno);
416
417	error = getsockopt(sk2, IPPROTO_SCTP, SCTP_ASSOCINFO, &gassocparams,
418			   &len);
419	if (error < 0)
420		tst_brkm(TBROK, tst_exit, "getsockopt SCTP_ASSOCINFO "
421                         "error:%d, errno:%d", error, errno);
422
423	if (sassocparams.sasoc_asocmaxrxt != gassocparams.sasoc_asocmaxrxt ||
424	    sassocparams.sasoc_cookie_life != gassocparams.sasoc_cookie_life)
425		tst_brkm(TBROK, tst_exit, "getsockopt SCTP_ASSOCINFO value "
426			 "mismatch");
427	tst_resm(TPASS, "setsockopt() SCTP_ASSOCINFO - SUCCESS");
428
429	close(sk2);
430	close(sk1);
431	close(acpt_sk);
432
433	return 0;
434}
435