xref: /freebsd/libexec/tftpd/tests/functional.c (revision abd87254)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
3  *
4  * Copyright (c) 2018 Alan Somers.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  */
27 
28 #include <sys/param.h>
29 #include <sys/socket.h>
30 #include <sys/stat.h>
31 #include <sys/wait.h>
32 
33 #include <netinet/in.h>
34 
35 #include <errno.h>
36 #include <fcntl.h>
37 #include <signal.h>
38 #include <stdalign.h>
39 #include <stdio.h>
40 #include <unistd.h>
41 
42 #include <atf-c.h>
43 #include <libutil.h>
44 
45 static const uint16_t BASEPORT = 6969;
46 static const char pidfile[] = "tftpd.pid";
47 static int protocol = PF_UNSPEC;
48 static int s = -1;	/* tftp client socket */
49 static struct sockaddr_storage addr; /* Destination address for the client */
50 static bool s_flag = false;	/* Pass -s to tftpd */
51 static bool w_flag = false;	/* Pass -w to tftpd */
52 
53 /* Helper functions*/
54 static void require_bufeq(const char *expected, size_t expected_len,
55     const char *actual, size_t len);
56 
57 /*
58  * Receive a response from tftpd
59  * @param	hdr		The reply's expected header, as a char array
60  * @param	contents	The reply's expected contents, as a char array
61  * @param	contents_len	Length of contents
62  */
63 #define RECV(hdr, contents, contents_len) do {				\
64 	char buffer[1024];						\
65 	struct sockaddr_storage from;					\
66 	socklen_t fromlen = sizeof(from);				\
67 	ssize_t r = recvfrom(s, buffer, sizeof(buffer), 0,		\
68 	    (struct sockaddr *)&from, &fromlen);			\
69 	ATF_REQUIRE(r > 0);						\
70 	require_bufeq((hdr), sizeof(hdr), buffer,			\
71 	    MIN((size_t)r, sizeof(hdr)));				\
72 	require_bufeq((const char *) (contents), (contents_len),	\
73 	    &buffer[sizeof(hdr)], r - sizeof(hdr));			\
74 	if (protocol == PF_INET) {					\
75 		((struct sockaddr_in *)&addr)->sin_port =		\
76 		    ((struct sockaddr_in *)&from)->sin_port;		\
77 	} else {							\
78 		((struct sockaddr_in6 *)&addr)->sin6_port =		\
79 		    ((struct sockaddr_in6 *)&from)->sin6_port;		\
80 	}								\
81 } while(0)
82 
83 static void
84 recv_ack(uint16_t blocknum)
85 {
86 	char hdr[] = {0, 4, blocknum >> 8, blocknum & 0xFF};
87 	RECV(hdr, NULL, 0);
88 }
89 
90 static void
91 recv_oack(const char *options, size_t options_len)
92 {
93 	char hdr[] = {0, 6};
94 	RECV(hdr, options, options_len);
95 }
96 
97 /*
98  * Receive a data packet from tftpd
99  * @param	blocknum	Expected block number to be received
100  * @param	contents	Pointer to expected contents
101  * @param	contents_len	Length of contents expected to receive
102  */
103 static void
104 recv_data(uint16_t blocknum, const char *contents, size_t contents_len)
105 {
106 	char hdr[] = {0, 3, blocknum >> 8, blocknum & 0xFF};
107 	RECV(hdr, contents, contents_len);
108 }
109 
110 #define RECV_ERROR(code, msg) do {					\
111 	char hdr[] = {0, 5, code >> 8, code & 0xFF};			\
112 	RECV(hdr, msg, sizeof(msg));					\
113 } while (0)
114 
115 /*
116  * send a command to tftpd.
117  * @param	cmd		Command to send, as a char array
118  */
119 static void
120 send_bytes(const void *cmd, size_t len)
121 {
122 	ssize_t r;
123 
124 	r = sendto(s, cmd, len, 0, (struct sockaddr *)(&addr), addr.ss_len);
125 	ATF_REQUIRE(r >= 0);
126 	ATF_REQUIRE_EQ(len, (size_t)r);
127 }
128 
129 static void
130 send_data(uint16_t blocknum, const char *contents, size_t contents_len)
131 {
132 	char buffer[1024];
133 
134 	buffer[0] = 0;	/* DATA opcode high byte */
135 	buffer[1] = 3;	/* DATA opcode low byte */
136 	buffer[2] = blocknum >> 8;
137 	buffer[3] = blocknum & 0xFF;
138 	memmove(&buffer[4], contents, contents_len);
139 	send_bytes(buffer, 4 + contents_len);
140 }
141 
142 /*
143  * send a command to tftpd.
144  * @param	cmd		Command to send, as a const string
145  *				(terminating NUL will be ignored)
146  */
147 #define SEND_STR(cmd)							\
148 	ATF_REQUIRE_EQ(sizeof(cmd) - 1,					\
149 	    sendto(s, (cmd), sizeof(cmd) - 1, 0,			\
150 	    (struct sockaddr *)(&addr), addr.ss_len))
151 
152 /*
153  * Acknowledge block blocknum
154  */
155 static void
156 send_ack(uint16_t blocknum)
157 {
158 	char packet[] = {
159 		0, 4,		/* ACK opcode in BE */
160 		blocknum >> 8,
161 		blocknum & 0xFF
162 	};
163 
164 	send_bytes(packet, sizeof(packet));
165 }
166 
167 /*
168  * build an option string
169  */
170 #define OPTION_STR(name, value)	name "\000" value "\000"
171 
172 /*
173  * send a read request to tftpd.
174  * @param	filename	filename as a string, absolute or relative
175  * @param	mode		either "octet" or "netascii"
176  */
177 #define SEND_RRQ(filename, mode)					\
178 	SEND_STR("\0\001" filename "\0" mode "\0")
179 
180 /*
181  * send a read request with options
182  */
183 #define SEND_RRQ_OPT(filename, mode, options)				\
184 	SEND_STR("\0\001" filename "\0" mode "\000" options)
185 
186 /*
187  * send a write request to tftpd.
188  * @param	filename	filename as a string, absolute or relative
189  * @param	mode		either "octet" or "netascii"
190  */
191 #define SEND_WRQ(filename, mode)					\
192 	SEND_STR("\0\002" filename "\0" mode "\0")
193 
194 /*
195  * send a write request with options
196  */
197 #define SEND_WRQ_OPT(filename, mode, options)				\
198 	SEND_STR("\0\002" filename "\0" mode "\000" options)
199 
200 /* Define a test case, for both IPv4 and IPv6 */
201 #define TFTPD_TC_DEFINE(name, head, ...)				\
202 static void								\
203 name ## _body(void);							\
204 ATF_TC_WITH_CLEANUP(name ## _v4);					\
205 ATF_TC_HEAD(name ## _v4, tc)						\
206 {									\
207 	head								\
208 }									\
209 ATF_TC_BODY(name ## _v4, tc)						\
210 {									\
211 	int exitcode = 0;						\
212 	__VA_ARGS__;							\
213 	protocol = AF_INET;						\
214 	s = setup(&addr, __COUNTER__);					\
215 	name ## _body();						\
216 	close(s);							\
217 	if (exitcode >= 0)						\
218 		check_server(exitcode);					\
219 }									\
220 ATF_TC_CLEANUP(name ## _v4, tc)						\
221 {									\
222 	cleanup();							\
223 }									\
224 ATF_TC_WITH_CLEANUP(name ## _v6);					\
225 ATF_TC_HEAD(name ## _v6, tc)						\
226 {									\
227 	head								\
228 }									\
229 ATF_TC_BODY(name ## _v6, tc)						\
230 {									\
231 	int exitcode = 0;						\
232 	__VA_ARGS__;							\
233 	protocol = AF_INET6;						\
234 	s = setup(&addr, __COUNTER__);					\
235 	name ## _body();						\
236 	close(s);							\
237 	if (exitcode >= 0)						\
238 		check_server(exitcode);					\
239 }									\
240 ATF_TC_CLEANUP(name ## _v6, tc)						\
241 {									\
242 	cleanup();							\
243 }									\
244 static void								\
245 name ## _body(void)
246 
247 /* Add the IPv4 and IPv6 versions of a test case */
248 #define TFTPD_TC_ADD(tp, name) do {					\
249 	ATF_TP_ADD_TC(tp, name ## _v4);					\
250 	ATF_TP_ADD_TC(tp, name ## _v6);					\
251 } while (0)
252 
253 static void
254 sigalrm(int signo __unused)
255 {
256 }
257 
258 /* Check that server exits with specific exit code */
259 static void
260 check_server(int exitcode)
261 {
262 	struct sigaction sa = { .sa_handler = sigalrm };
263 	struct itimerval it = { .it_value = { .tv_sec = 30 } };
264 	FILE *f;
265 	pid_t pid;
266 	int wstatus;
267 
268 	f = fopen(pidfile, "r");
269 	ATF_REQUIRE(f != NULL);
270 	ATF_REQUIRE_INTEQ(1, fscanf(f, "%d", &pid));
271 	ATF_CHECK_INTEQ(0, fclose(f));
272 	ATF_REQUIRE_INTEQ(0, sigaction(SIGALRM, &sa, NULL));
273 	ATF_REQUIRE_EQ(0, setitimer(ITIMER_REAL, &it, NULL));
274 	ATF_REQUIRE_EQ(pid, waitpid(pid, &wstatus, 0));
275 	ATF_CHECK(WIFEXITED(wstatus));
276 	ATF_CHECK_INTEQ(exitcode, WEXITSTATUS(wstatus));
277 	unlink(pidfile);
278 }
279 
280 /* Standard cleanup used by all testcases */
281 static void
282 cleanup(void)
283 {
284 	FILE *f;
285 	pid_t pid;
286 
287 	f = fopen(pidfile, "r");
288 	if (f == NULL)
289 		return;
290 	unlink(pidfile);
291 	if (fscanf(f, "%d", &pid) == 1) {
292 		kill(pid, SIGTERM);
293 		waitpid(pid, NULL, 0);
294 	}
295 	fclose(f);
296 }
297 
298 /* Assert that two binary buffers are identical */
299 static void
300 require_bufeq(const char *expected, size_t expected_len,
301     const char *actual, size_t len)
302 {
303 	size_t i;
304 
305 	ATF_REQUIRE_EQ_MSG(expected_len, len,
306 	    "Expected %zu bytes but got %zu", expected_len, len);
307 	for (i = 0; i < len; i++) {
308 		ATF_REQUIRE_EQ_MSG(expected[i], actual[i],
309 		    "Expected %#hhx at position %zu; got %hhx instead",
310 		    expected[i], i, actual[i]);
311 	}
312 }
313 
314 /*
315  * Start tftpd and return its communicating socket
316  * @param	to	Will be filled in for use with sendto
317  * @param	idx	Unique identifier of the test case
318  * @return		Socket ready to use
319  */
320 static int
321 setup(struct sockaddr_storage *to, uint16_t idx)
322 {
323 	int client_s, server_s, pid, argv_idx;
324 	char execname[] = "/usr/libexec/tftpd";
325 	char s_flag_str[] = "-s";
326 	char w_flag_str[] = "-w";
327 	char pwd[MAXPATHLEN];
328 	char *argv[10];
329 	struct sockaddr_in addr4;
330 	struct sockaddr_in6 addr6;
331 	struct sockaddr *server_addr;
332 	struct pidfh *pfh;
333 	uint16_t port = BASEPORT + idx;
334 	socklen_t len;
335 	int pd[2];
336 
337 	ATF_REQUIRE_EQ(0, pipe2(pd, O_CLOEXEC));
338 
339 	if (protocol == PF_INET) {
340 		len = sizeof(addr4);
341 		bzero(&addr4, len);
342 		addr4.sin_len = len;
343 		addr4.sin_family = PF_INET;
344 		addr4.sin_port = htons(port);
345 		server_addr = (struct sockaddr *)&addr4;
346 	} else {
347 		len = sizeof(addr6);
348 		bzero(&addr6, len);
349 		addr6.sin6_len = len;
350 		addr6.sin6_family = PF_INET6;
351 		addr6.sin6_port = htons(port);
352 		server_addr = (struct sockaddr *)&addr6;
353 	}
354 
355 	ATF_REQUIRE_EQ(pwd, getcwd(pwd, sizeof(pwd)));
356 
357 	/* Must bind(2) pre-fork so it happens before the client's send(2) */
358 	server_s = socket(protocol, SOCK_DGRAM, 0);
359 	if (server_s < 0 && errno == EAFNOSUPPORT) {
360 		atf_tc_skip("This test requires IPv%d support",
361 		    protocol == PF_INET ? 4 : 6);
362 	}
363 	ATF_REQUIRE_MSG(server_s >= 0,
364 	    "socket failed with error %s", strerror(errno));
365 	ATF_REQUIRE_EQ_MSG(0, bind(server_s, server_addr, len),
366 	    "bind failed with error %s", strerror(errno));
367 
368 	pid = fork();
369 	switch (pid) {
370 	case -1:
371 		atf_tc_fail("fork failed");
372 		break;
373 	case 0:
374 		/* In child */
375 		pfh = pidfile_open(pidfile, 0644, NULL);
376 		ATF_REQUIRE_MSG(pfh != NULL,
377 		    "pidfile_open: %s", strerror(errno));
378 		ATF_REQUIRE_EQ(0, pidfile_write(pfh));
379 		ATF_REQUIRE_EQ(0, pidfile_close(pfh));
380 
381 		bzero(argv, sizeof(argv));
382 		argv[0] = execname;
383 		argv_idx = 1;
384 		if (w_flag)
385 			argv[argv_idx++] = w_flag_str;
386 		if (s_flag)
387 			argv[argv_idx++] = s_flag_str;
388 		argv[argv_idx++] = pwd;
389 		ATF_REQUIRE_EQ(STDOUT_FILENO, dup2(server_s, STDOUT_FILENO));
390 		ATF_REQUIRE_EQ(STDIN_FILENO, dup2(server_s, STDIN_FILENO));
391 		ATF_REQUIRE_EQ(STDERR_FILENO, dup2(server_s, STDERR_FILENO));
392 		execv(execname, argv);
393 		atf_tc_fail("exec failed");
394 		break;
395 	default:
396 		/* In parent */
397 		ATF_REQUIRE_INTEQ(0, close(pd[1]));
398 		/* block until other end is closed on exec() or exit() */
399 		ATF_REQUIRE_INTEQ(0, read(pd[0], &pd[1], sizeof(pd[1])));
400 		ATF_REQUIRE_INTEQ(0, close(pd[0]));
401 		bzero(to, sizeof(*to));
402 		if (protocol == PF_INET) {
403 			struct sockaddr_in *to4 = (struct sockaddr_in *)to;
404 			to4->sin_len = sizeof(*to4);
405 			to4->sin_family = PF_INET;
406 			to4->sin_port = htons(port);
407 			to4->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
408 		} else {
409 			struct in6_addr loopback = IN6ADDR_LOOPBACK_INIT;
410 			struct sockaddr_in6 *to6 = (struct sockaddr_in6 *)to;
411 			to6->sin6_len = sizeof(*to6);
412 			to6->sin6_family = PF_INET6;
413 			to6->sin6_port = htons(port);
414 			to6->sin6_addr = loopback;
415 		}
416 
417 		ATF_REQUIRE_INTEQ(0, close(server_s));
418 		ATF_REQUIRE((client_s = socket(protocol, SOCK_DGRAM, 0)) > 0);
419 		break;
420 	}
421 
422 	/* Clear the client's umask.  Test cases will specify exact modes */
423 	umask(0000);
424 
425 	return (client_s);
426 }
427 
428 /* Like write(2), but never returns less than the requested length */
429 static void
430 write_all(int fd, const void *buf, size_t nbytes)
431 {
432 	ssize_t r;
433 
434 	while (nbytes > 0) {
435 		r = write(fd, buf, nbytes);
436 		ATF_REQUIRE(r > 0);
437 		nbytes -= (size_t)r;
438 		buf = (const char *)buf + (size_t)r;
439 	}
440 }
441 
442 
443 /*
444  * Test Cases
445  */
446 
447 /*
448  * Read a file, specified by absolute pathname.
449  */
450 TFTPD_TC_DEFINE(abspath,)
451 {
452 	int fd;
453 	char command[1024];
454 	size_t pathlen;
455 	char suffix[] = {'\0', 'o', 'c', 't', 'e', 't', '\0'};
456 
457 	command[0] = 0;		/* RRQ high byte */
458 	command[1] = 1;		/* RRQ low byte */
459 	ATF_REQUIRE(getcwd(&command[2], sizeof(command) - 2) != NULL);
460 	pathlen = strlcat(&command[2], "/abspath.txt", sizeof(command) - 2);
461 	ATF_REQUIRE(pathlen + sizeof(suffix) < sizeof(command) - 2);
462 	memmove(&command[2 + pathlen], suffix, sizeof(suffix));
463 
464 	fd = open("abspath.txt", O_CREAT | O_RDONLY, 0644);
465 	ATF_REQUIRE(fd >= 0);
466 	close(fd);
467 
468 	send_bytes(command, 2 + pathlen + sizeof(suffix));
469 	recv_data(1, NULL, 0);
470 	send_ack(1);
471 }
472 
473 /*
474  * Attempt to read a file outside of the allowed directory(ies)
475  */
476 TFTPD_TC_DEFINE(dotdot,)
477 {
478 	ATF_REQUIRE_EQ(0, mkdir("subdir", 0777));
479 	SEND_RRQ("../disallowed.txt", "octet");
480 	RECV_ERROR(2, "Access violation");
481 	s = setup(&addr, __COUNTER__);
482 	SEND_RRQ("subdir/../../disallowed.txt", "octet");
483 	RECV_ERROR(2, "Access violation");
484 	s = setup(&addr, __COUNTER__);
485 	SEND_RRQ("/etc/passwd", "octet");
486 	RECV_ERROR(2, "Access violation");
487 }
488 
489 /*
490  * With "-s", tftpd should chroot to the specified directory
491  */
492 TFTPD_TC_DEFINE(s_flag,
493     atf_tc_set_md_var(tc, "require.user", "root");,
494     s_flag = true)
495 {
496 	int fd;
497 	char contents[] = "small";
498 
499 	fd = open("small.txt", O_RDWR | O_CREAT, 0644);
500 	ATF_REQUIRE(fd >= 0);
501 	write_all(fd, contents, strlen(contents) + 1);
502 	close(fd);
503 
504 	SEND_RRQ("/small.txt", "octet");
505 	recv_data(1, contents, strlen(contents) + 1);
506 	send_ack(1);
507 }
508 
509 /*
510  * Read a file, and simulate a dropped ACK packet
511  */
512 TFTPD_TC_DEFINE(rrq_dropped_ack,)
513 {
514 	int fd;
515 	char contents[] = "small";
516 
517 	fd = open("small.txt", O_RDWR | O_CREAT, 0644);
518 	ATF_REQUIRE(fd >= 0);
519 	write_all(fd, contents, strlen(contents) + 1);
520 	close(fd);
521 
522 	SEND_RRQ("small.txt", "octet");
523 	recv_data(1, contents, strlen(contents) + 1);
524 	/*
525 	 * client "sends" the ack, but network drops it
526 	 * Eventually, tftpd should resend the data packet
527 	 */
528 	recv_data(1, contents, strlen(contents) + 1);
529 	send_ack(1);
530 }
531 
532 /*
533  * Read a file, and simulate a dropped DATA packet
534  */
535 TFTPD_TC_DEFINE(rrq_dropped_data,)
536 {
537 	int fd;
538 	size_t i;
539 	uint32_t contents[192];
540 	char buffer[1024];
541 
542 	for (i = 0; i < nitems(contents); i++)
543 		contents[i] = i;
544 
545 	fd = open("medium.txt", O_RDWR | O_CREAT, 0644);
546 	ATF_REQUIRE(fd >= 0);
547 	write_all(fd, contents, sizeof(contents));
548 	close(fd);
549 
550 	SEND_RRQ("medium.txt", "octet");
551 	recv_data(1, (const char *)&contents[0], 512);
552 	send_ack(1);
553 	(void) recvfrom(s, buffer, sizeof(buffer), 0, NULL, NULL);
554 	/*
555 	 * server "sends" the data, but network drops it
556 	 * Eventually, client should resend the last ACK
557 	 */
558 	send_ack(1);
559 	recv_data(2, (const char *)&contents[128], 256);
560 	send_ack(2);
561 }
562 
563 /*
564  * Read a medium file, and simulate a duplicated ACK packet
565  */
566 TFTPD_TC_DEFINE(rrq_duped_ack,)
567 {
568 	int fd;
569 	size_t i;
570 	uint32_t contents[192];
571 
572 	for (i = 0; i < nitems(contents); i++)
573 		contents[i] = i;
574 
575 	fd = open("medium.txt", O_RDWR | O_CREAT, 0644);
576 	ATF_REQUIRE(fd >= 0);
577 	write_all(fd, contents, sizeof(contents));
578 	close(fd);
579 
580 	SEND_RRQ("medium.txt", "octet");
581 	recv_data(1, (const char *)&contents[0], 512);
582 	send_ack(1);
583 	send_ack(1);	/* Dupe an ACK packet */
584 	recv_data(2, (const char *)&contents[128], 256);
585 	recv_data(2, (const char *)&contents[128], 256);
586 	send_ack(2);
587 }
588 
589 
590 /*
591  * Attempt to read a file without read permissions
592  */
593 TFTPD_TC_DEFINE(rrq_eaccess,)
594 {
595 	int fd;
596 
597 	fd = open("empty.txt", O_CREAT | O_RDONLY, 0000);
598 	ATF_REQUIRE(fd >= 0);
599 	close(fd);
600 
601 	SEND_RRQ("empty.txt", "octet");
602 	RECV_ERROR(2, "Access violation");
603 }
604 
605 /*
606  * Read an empty file
607  */
608 TFTPD_TC_DEFINE(rrq_empty,)
609 {
610 	int fd;
611 
612 	fd = open("empty.txt", O_CREAT | O_RDONLY, 0644);
613 	ATF_REQUIRE(fd >= 0);
614 	close(fd);
615 
616 	SEND_RRQ("empty.txt", "octet");
617 	recv_data(1, NULL, 0);
618 	send_ack(1);
619 }
620 
621 /*
622  * Read a medium file of more than one block
623  */
624 TFTPD_TC_DEFINE(rrq_medium,)
625 {
626 	int fd;
627 	size_t i;
628 	uint32_t contents[192];
629 
630 	for (i = 0; i < nitems(contents); i++)
631 		contents[i] = i;
632 
633 	fd = open("medium.txt", O_RDWR | O_CREAT, 0644);
634 	ATF_REQUIRE(fd >= 0);
635 	write_all(fd, contents, sizeof(contents));
636 	close(fd);
637 
638 	SEND_RRQ("medium.txt", "octet");
639 	recv_data(1, (const char *)&contents[0], 512);
640 	send_ack(1);
641 	recv_data(2, (const char *)&contents[128], 256);
642 	send_ack(2);
643 }
644 
645 /*
646  * Read a medium file with a window size of 2.
647  */
648 TFTPD_TC_DEFINE(rrq_medium_window,)
649 {
650 	int fd;
651 	size_t i;
652 	uint32_t contents[192];
653 	char options[] = OPTION_STR("windowsize", "2");
654 
655 	for (i = 0; i < nitems(contents); i++)
656 		contents[i] = i;
657 
658 	fd = open("medium.txt", O_RDWR | O_CREAT, 0644);
659 	ATF_REQUIRE(fd >= 0);
660 	write_all(fd, contents, sizeof(contents));
661 	close(fd);
662 
663 	SEND_RRQ_OPT("medium.txt", "octet", OPTION_STR("windowsize", "2"));
664 	recv_oack(options, sizeof(options) - 1);
665 	send_ack(0);
666 	recv_data(1, (const char *)&contents[0], 512);
667 	recv_data(2, (const char *)&contents[128], 256);
668 	send_ack(2);
669 }
670 
671 /*
672  * Read a file in netascii format
673  */
674 TFTPD_TC_DEFINE(rrq_netascii,)
675 {
676 	int fd;
677 	char contents[] = "foo\nbar\rbaz\n";
678 	/*
679 	 * Weirdly, RFC-764 says that CR must be followed by NUL if a line feed
680 	 * is not intended
681 	 */
682 	char expected[] = "foo\r\nbar\r\0baz\r\n";
683 
684 	fd = open("unix.txt", O_RDWR | O_CREAT, 0644);
685 	ATF_REQUIRE(fd >= 0);
686 	write_all(fd, contents, strlen(contents) + 1);
687 	close(fd);
688 
689 	SEND_RRQ("unix.txt", "netascii");
690 	recv_data(1, expected, sizeof(expected));
691 	send_ack(1);
692 }
693 
694 /*
695  * Read a file that doesn't exist
696  */
697 TFTPD_TC_DEFINE(rrq_nonexistent,)
698 {
699 	SEND_RRQ("nonexistent.txt", "octet");
700 	RECV_ERROR(1, "File not found");
701 }
702 
703 /*
704  * Attempt to read a file whose name exceeds PATH_MAX
705  */
706 TFTPD_TC_DEFINE(rrq_path_max,)
707 {
708 #define AReallyBigFileName \
709 	    "AReallyBigFileNameXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"\
710 	    "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"\
711 	    "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"\
712 	    "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"\
713 	    "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"\
714 	    "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"\
715 	    "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"\
716 	    "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"\
717 	    "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"\
718 	    "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"\
719 	    "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"\
720 	    "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"\
721 	    "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"\
722 	    "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"\
723 	    "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"\
724 	    "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"\
725 	    ".txt"
726 	ATF_REQUIRE_MSG(strlen(AReallyBigFileName) > PATH_MAX,
727 	    "Somebody increased PATH_MAX.  Update the test");
728 	SEND_RRQ(AReallyBigFileName, "octet");
729 	RECV_ERROR(4, "Illegal TFTP operation");
730 }
731 
732 /*
733  * Read a small file of less than one block
734  */
735 TFTPD_TC_DEFINE(rrq_small,)
736 {
737 	int fd;
738 	char contents[] = "small";
739 
740 	fd = open("small.txt", O_RDWR | O_CREAT, 0644);
741 	ATF_REQUIRE(fd >= 0);
742 	write_all(fd, contents, strlen(contents) + 1);
743 	close(fd);
744 
745 	SEND_RRQ("small.txt", "octet");
746 	recv_data(1, contents, strlen(contents) + 1);
747 	send_ack(1);
748 }
749 
750 /*
751  * Read a file following the example in RFC 7440.
752  */
753 TFTPD_TC_DEFINE(rrq_window_rfc7440,)
754 {
755 	int fd;
756 	size_t i;
757 	char options[] = OPTION_STR("windowsize", "4");
758 	alignas(uint32_t) char contents[13 * 512 - 4];
759 	uint32_t *u32p;
760 
761 	u32p = (uint32_t *)contents;
762 	for (i = 0; i < sizeof(contents) / sizeof(uint32_t); i++)
763 		u32p[i] = i;
764 
765 	fd = open("rfc7440.txt", O_RDWR | O_CREAT, 0644);
766 	ATF_REQUIRE(fd >= 0);
767 	write_all(fd, contents, sizeof(contents));
768 	close(fd);
769 
770 	SEND_RRQ_OPT("rfc7440.txt", "octet", OPTION_STR("windowsize", "4"));
771 	recv_oack(options, sizeof(options) - 1);
772 	send_ack(0);
773 	recv_data(1, &contents[0 * 512], 512);
774 	recv_data(2, &contents[1 * 512], 512);
775 	recv_data(3, &contents[2 * 512], 512);
776 	recv_data(4, &contents[3 * 512], 512);
777 	send_ack(4);
778 	recv_data(5, &contents[4 * 512], 512);
779 	recv_data(6, &contents[5 * 512], 512);
780 	recv_data(7, &contents[6 * 512], 512);
781 	recv_data(8, &contents[7 * 512], 512);
782 
783 	/* ACK 5 as if 6-8 were dropped. */
784 	send_ack(5);
785 	recv_data(6, &contents[5 * 512], 512);
786 	recv_data(7, &contents[6 * 512], 512);
787 	recv_data(8, &contents[7 * 512], 512);
788 	recv_data(9, &contents[8 * 512], 512);
789 	send_ack(9);
790 	recv_data(10, &contents[9 * 512], 512);
791 	recv_data(11, &contents[10 * 512], 512);
792 	recv_data(12, &contents[11 * 512], 512);
793 	recv_data(13, &contents[12 * 512], 508);
794 
795 	/* Drop ACK and after timeout receive 10-13. */
796 	recv_data(10, &contents[9 * 512], 512);
797 	recv_data(11, &contents[10 * 512], 512);
798 	recv_data(12, &contents[11 * 512], 512);
799 	recv_data(13, &contents[12 * 512], 508);
800 	send_ack(13);
801 }
802 
803 /*
804  * Try to transfer a file with an unknown mode.
805  */
806 TFTPD_TC_DEFINE(unknown_modes,)
807 {
808 	SEND_RRQ("foo.txt", "ascii");	/* Misspelling of "ascii" */
809 	RECV_ERROR(4, "Illegal TFTP operation");
810 	s = setup(&addr, __COUNTER__);
811 	SEND_RRQ("foo.txt", "binary");	/* Obsolete.  Use "octet" instead */
812 	RECV_ERROR(4, "Illegal TFTP operation");
813 	s = setup(&addr, __COUNTER__);
814 	SEND_RRQ("foo.txt", "en_US.UTF-8");
815 	RECV_ERROR(4, "Illegal TFTP operation");
816 	s = setup(&addr, __COUNTER__);
817 	SEND_RRQ("foo.txt", "mail");	/* Obsolete in RFC-1350 */
818 	RECV_ERROR(4, "Illegal TFTP operation");
819 }
820 
821 /*
822  * Send an unknown opcode.  tftpd should respond with the appropriate error
823  */
824 TFTPD_TC_DEFINE(unknown_opcode,)
825 {
826 	/* Looks like an RRQ or WRQ request, but with a bad opcode */
827 	SEND_STR("\0\007foo.txt\0octet\0");
828 	RECV_ERROR(4, "Illegal TFTP operation");
829 }
830 
831 /*
832  * Invoke tftpd with "-w" and write to a nonexistent file.
833  */
834 TFTPD_TC_DEFINE(w_flag,, w_flag = 1;)
835 {
836 	int fd;
837 	ssize_t r;
838 	char contents[] = "small";
839 	char buffer[1024];
840 	size_t contents_len;
841 
842 	contents_len = strlen(contents) + 1;
843 	SEND_WRQ("small.txt", "octet");
844 	recv_ack(0);
845 	send_data(1, contents, contents_len);
846 	recv_ack(1);
847 
848 	fd = open("small.txt", O_RDONLY);
849 	ATF_REQUIRE(fd >= 0);
850 	r = read(fd, buffer, sizeof(buffer));
851 	ATF_REQUIRE(r > 0);
852 	close(fd);
853 	require_bufeq(contents, contents_len, buffer, (size_t)r);
854 }
855 
856 /*
857  * Write a medium file, and simulate a dropped ACK packet
858  */
859 TFTPD_TC_DEFINE(wrq_dropped_ack,)
860 {
861 	int fd;
862 	size_t i;
863 	ssize_t r;
864 	uint32_t contents[192];
865 	char buffer[1024];
866 
867 	for (i = 0; i < nitems(contents); i++)
868 		contents[i] = i;
869 
870 	fd = open("medium.txt", O_RDWR | O_CREAT, 0666);
871 	ATF_REQUIRE(fd >= 0);
872 	close(fd);
873 
874 	SEND_WRQ("medium.txt", "octet");
875 	recv_ack(0);
876 	send_data(1, (const char *)&contents[0], 512);
877 	/*
878 	 * Servers "sends" an ACK packet, but network drops it.
879 	 * Eventually, server should resend the last ACK
880 	 */
881 	(void) recvfrom(s, buffer, sizeof(buffer), 0, NULL, NULL);
882 	recv_ack(1);
883 	send_data(2, (const char *)&contents[128], 256);
884 	recv_ack(2);
885 
886 	fd = open("medium.txt", O_RDONLY);
887 	ATF_REQUIRE(fd >= 0);
888 	r = read(fd, buffer, sizeof(buffer));
889 	ATF_REQUIRE(r > 0);
890 	close(fd);
891 	require_bufeq((const char *)contents, 768, buffer, (size_t)r);
892 }
893 
894 /*
895  * Write a small file, and simulate a dropped DATA packet
896  */
897 TFTPD_TC_DEFINE(wrq_dropped_data,)
898 {
899 	int fd;
900 	ssize_t r;
901 	char contents[] = "small";
902 	size_t contents_len;
903 	char buffer[1024];
904 
905 	fd = open("small.txt", O_RDWR | O_CREAT, 0666);
906 	ATF_REQUIRE(fd >= 0);
907 	close(fd);
908 	contents_len = strlen(contents) + 1;
909 
910 	SEND_WRQ("small.txt", "octet");
911 	recv_ack(0);
912 	/*
913 	 * Client "sends" a DATA packet, but network drops it.
914 	 * Eventually, server should resend the last ACK
915 	 */
916 	recv_ack(0);
917 	send_data(1, contents, contents_len);
918 	recv_ack(1);
919 
920 	fd = open("small.txt", O_RDONLY);
921 	ATF_REQUIRE(fd >= 0);
922 	r = read(fd, buffer, sizeof(buffer));
923 	ATF_REQUIRE(r > 0);
924 	close(fd);
925 	require_bufeq(contents, contents_len, buffer, (size_t)r);
926 }
927 
928 /*
929  * Write a medium file, and simulate a duplicated DATA packet
930  */
931 TFTPD_TC_DEFINE(wrq_duped_data,)
932 {
933 	int fd;
934 	size_t i;
935 	ssize_t r;
936 	uint32_t contents[192];
937 	char buffer[1024];
938 
939 	for (i = 0; i < nitems(contents); i++)
940 		contents[i] = i;
941 
942 	fd = open("medium.txt", O_RDWR | O_CREAT, 0666);
943 	ATF_REQUIRE(fd >= 0);
944 	close(fd);
945 
946 	SEND_WRQ("medium.txt", "octet");
947 	recv_ack(0);
948 	send_data(1, (const char *)&contents[0], 512);
949 	send_data(1, (const char *)&contents[0], 512);
950 	recv_ack(1);
951 	recv_ack(1);
952 	send_data(2, (const char *)&contents[128], 256);
953 	recv_ack(2);
954 
955 	fd = open("medium.txt", O_RDONLY);
956 	ATF_REQUIRE(fd >= 0);
957 	r = read(fd, buffer, sizeof(buffer));
958 	ATF_REQUIRE(r > 0);
959 	close(fd);
960 	require_bufeq((const char *)contents, 768, buffer, (size_t)r);
961 }
962 
963 /*
964  * Attempt to write a file without write permissions
965  */
966 TFTPD_TC_DEFINE(wrq_eaccess,)
967 {
968 	int fd;
969 
970 	fd = open("empty.txt", O_CREAT | O_RDONLY, 0440);
971 	ATF_REQUIRE(fd >= 0);
972 	close(fd);
973 
974 	SEND_WRQ("empty.txt", "octet");
975 	RECV_ERROR(2, "Access violation");
976 }
977 
978 /*
979  * Attempt to write a file without world write permissions, but with world
980  * read permissions
981  */
982 TFTPD_TC_DEFINE(wrq_eaccess_world_readable,)
983 {
984 	int fd;
985 
986 	fd = open("empty.txt", O_CREAT | O_RDONLY, 0444);
987 	ATF_REQUIRE(fd >= 0);
988 	close(fd);
989 
990 	SEND_WRQ("empty.txt", "octet");
991 	RECV_ERROR(2, "Access violation");
992 }
993 
994 
995 /*
996  * Write a medium file of more than one block
997  */
998 TFTPD_TC_DEFINE(wrq_medium,)
999 {
1000 	int fd;
1001 	size_t i;
1002 	ssize_t r;
1003 	uint32_t contents[192];
1004 	char buffer[1024];
1005 
1006 	for (i = 0; i < nitems(contents); i++)
1007 		contents[i] = i;
1008 
1009 	fd = open("medium.txt", O_RDWR | O_CREAT, 0666);
1010 	ATF_REQUIRE(fd >= 0);
1011 	close(fd);
1012 
1013 	SEND_WRQ("medium.txt", "octet");
1014 	recv_ack(0);
1015 	send_data(1, (const char *)&contents[0], 512);
1016 	recv_ack(1);
1017 	send_data(2, (const char *)&contents[128], 256);
1018 	recv_ack(2);
1019 
1020 	fd = open("medium.txt", O_RDONLY);
1021 	ATF_REQUIRE(fd >= 0);
1022 	r = read(fd, buffer, sizeof(buffer));
1023 	ATF_REQUIRE(r > 0);
1024 	close(fd);
1025 	require_bufeq((const char *)contents, 768, buffer, (size_t)r);
1026 }
1027 
1028 /*
1029  * Write a medium file with a window size of 2.
1030  */
1031 TFTPD_TC_DEFINE(wrq_medium_window,)
1032 {
1033 	int fd;
1034 	size_t i;
1035 	ssize_t r;
1036 	uint32_t contents[192];
1037 	char buffer[1024];
1038 	char options[] = OPTION_STR("windowsize", "2");
1039 
1040 	for (i = 0; i < nitems(contents); i++)
1041 		contents[i] = i;
1042 
1043 	fd = open("medium.txt", O_RDWR | O_CREAT, 0666);
1044 	ATF_REQUIRE(fd >= 0);
1045 	close(fd);
1046 
1047 	SEND_WRQ_OPT("medium.txt", "octet", OPTION_STR("windowsize", "2"));
1048 	recv_oack(options, sizeof(options) - 1);
1049 	send_data(1, (const char *)&contents[0], 512);
1050 	send_data(2, (const char *)&contents[128], 256);
1051 	recv_ack(2);
1052 
1053 	fd = open("medium.txt", O_RDONLY);
1054 	ATF_REQUIRE(fd >= 0);
1055 	r = read(fd, buffer, sizeof(buffer));
1056 	ATF_REQUIRE(r > 0);
1057 	close(fd);
1058 	require_bufeq((const char *)contents, 768, buffer, (size_t)r);
1059 }
1060 
1061 /*
1062  * Write a file in netascii format
1063  */
1064 TFTPD_TC_DEFINE(wrq_netascii,)
1065 {
1066 	int fd;
1067 	ssize_t r;
1068 	/*
1069 	 * Weirdly, RFC-764 says that CR must be followed by NUL if a line feed
1070 	 * is not intended
1071 	 */
1072 	char contents[] = "foo\r\nbar\r\0baz\r\n";
1073 	char expected[] = "foo\nbar\rbaz\n";
1074 	size_t contents_len;
1075 	char buffer[1024];
1076 
1077 	fd = open("unix.txt", O_RDWR | O_CREAT, 0666);
1078 	ATF_REQUIRE(fd >= 0);
1079 	close(fd);
1080 	contents_len = sizeof(contents);
1081 
1082 	SEND_WRQ("unix.txt", "netascii");
1083 	recv_ack(0);
1084 	send_data(1, contents, contents_len);
1085 	recv_ack(1);
1086 
1087 	fd = open("unix.txt", O_RDONLY);
1088 	ATF_REQUIRE(fd >= 0);
1089 	r = read(fd, buffer, sizeof(buffer));
1090 	ATF_REQUIRE(r > 0);
1091 	close(fd);
1092 	require_bufeq(expected, sizeof(expected), buffer, (size_t)r);
1093 }
1094 
1095 /*
1096  * Attempt to write to a nonexistent file.  With the default options, this
1097  * isn't allowed.
1098  */
1099 TFTPD_TC_DEFINE(wrq_nonexistent,)
1100 {
1101 	SEND_WRQ("nonexistent.txt", "octet");
1102 	RECV_ERROR(1, "File not found");
1103 }
1104 
1105 /*
1106  * Write a small file of less than one block
1107  */
1108 TFTPD_TC_DEFINE(wrq_small,)
1109 {
1110 	int fd;
1111 	ssize_t r;
1112 	char contents[] = "small";
1113 	size_t contents_len;
1114 	char buffer[1024];
1115 
1116 	fd = open("small.txt", O_RDWR | O_CREAT, 0666);
1117 	ATF_REQUIRE(fd >= 0);
1118 	close(fd);
1119 	contents_len = strlen(contents) + 1;
1120 
1121 	SEND_WRQ("small.txt", "octet");
1122 	recv_ack(0);
1123 	send_data(1, contents, contents_len);
1124 	recv_ack(1);
1125 
1126 	fd = open("small.txt", O_RDONLY);
1127 	ATF_REQUIRE(fd >= 0);
1128 	r = read(fd, buffer, sizeof(buffer));
1129 	ATF_REQUIRE(r > 0);
1130 	close(fd);
1131 	require_bufeq(contents, contents_len, buffer, (size_t)r);
1132 }
1133 
1134 /*
1135  * Write an empty file over a non-empty one
1136  */
1137 TFTPD_TC_DEFINE(wrq_truncate,)
1138 {
1139 	int fd;
1140 	char contents[] = "small";
1141 	struct stat sb;
1142 
1143 	fd = open("small.txt", O_RDWR | O_CREAT, 0666);
1144 	ATF_REQUIRE(fd >= 0);
1145 	write_all(fd, contents, strlen(contents) + 1);
1146 	close(fd);
1147 
1148 	SEND_WRQ("small.txt", "octet");
1149 	recv_ack(0);
1150 	send_data(1, NULL, 0);
1151 	recv_ack(1);
1152 
1153 	ATF_REQUIRE_EQ(0, stat("small.txt", &sb));
1154 	ATF_REQUIRE_EQ(0, sb.st_size);
1155 }
1156 
1157 /*
1158  * Write a file following the example in RFC 7440.
1159  */
1160 TFTPD_TC_DEFINE(wrq_window_rfc7440,)
1161 {
1162 	int fd;
1163 	size_t i;
1164 	ssize_t r;
1165 	char options[] = OPTION_STR("windowsize", "4");
1166 	alignas(uint32_t) char contents[13 * 512 - 4];
1167 	char buffer[sizeof(contents)];
1168 	uint32_t *u32p;
1169 
1170 	u32p = (uint32_t *)contents;
1171 	for (i = 0; i < sizeof(contents) / sizeof(uint32_t); i++)
1172 		u32p[i] = i;
1173 
1174 	fd = open("rfc7440.txt", O_RDWR | O_CREAT, 0666);
1175 	ATF_REQUIRE(fd >= 0);
1176 	close(fd);
1177 
1178 	SEND_WRQ_OPT("rfc7440.txt", "octet", OPTION_STR("windowsize", "4"));
1179 	recv_oack(options, sizeof(options) - 1);
1180 	send_data(1, &contents[0 * 512], 512);
1181 	send_data(2, &contents[1 * 512], 512);
1182 	send_data(3, &contents[2 * 512], 512);
1183 	send_data(4, &contents[3 * 512], 512);
1184 	recv_ack(4);
1185 	send_data(5, &contents[4 * 512], 512);
1186 
1187 	/* Drop 6-8. */
1188 	recv_ack(5);
1189 	send_data(6, &contents[5 * 512], 512);
1190 	send_data(7, &contents[6 * 512], 512);
1191 	send_data(8, &contents[7 * 512], 512);
1192 	send_data(9, &contents[8 * 512], 512);
1193 	recv_ack(9);
1194 
1195 	/* Drop 11. */
1196 	send_data(10, &contents[9 * 512], 512);
1197 	send_data(12, &contents[11 * 512], 512);
1198 
1199 	/*
1200 	 * We can't send 13 here as tftpd has probably already seen 12
1201 	 * and sent the ACK of 10 if running locally.  While it would
1202 	 * recover by sending another ACK of 10, our state machine
1203 	 * would be out of sync.
1204 	 */
1205 
1206 	/* Ignore ACK for 10 and resend 10-13. */
1207 	recv_ack(10);
1208 	send_data(10, &contents[9 * 512], 512);
1209 	send_data(11, &contents[10 * 512], 512);
1210 	send_data(12, &contents[11 * 512], 512);
1211 	send_data(13, &contents[12 * 512], 508);
1212 	recv_ack(13);
1213 
1214 	fd = open("rfc7440.txt", O_RDONLY);
1215 	ATF_REQUIRE(fd >= 0);
1216 	r = read(fd, buffer, sizeof(buffer));
1217 	ATF_REQUIRE(r > 0);
1218 	close(fd);
1219 	require_bufeq(contents, sizeof(contents), buffer, (size_t)r);
1220 }
1221 
1222 /*
1223  * Send less than four bytes
1224  */
1225 TFTPD_TC_DEFINE(short_packet1, /* no head */, exitcode = 1)
1226 {
1227 	SEND_STR("\1");
1228 }
1229 TFTPD_TC_DEFINE(short_packet2, /* no head */, exitcode = 1)
1230 {
1231 	SEND_STR("\1\2");
1232 }
1233 TFTPD_TC_DEFINE(short_packet3, /* no head */, exitcode = 1)
1234 {
1235 	SEND_STR("\1\2\3");
1236 }
1237 
1238 
1239 /*
1240  * Main
1241  */
1242 
1243 ATF_TP_ADD_TCS(tp)
1244 {
1245 	TFTPD_TC_ADD(tp, abspath);
1246 	TFTPD_TC_ADD(tp, dotdot);
1247 	TFTPD_TC_ADD(tp, s_flag);
1248 	TFTPD_TC_ADD(tp, rrq_dropped_ack);
1249 	TFTPD_TC_ADD(tp, rrq_dropped_data);
1250 	TFTPD_TC_ADD(tp, rrq_duped_ack);
1251 	TFTPD_TC_ADD(tp, rrq_eaccess);
1252 	TFTPD_TC_ADD(tp, rrq_empty);
1253 	TFTPD_TC_ADD(tp, rrq_medium);
1254 	TFTPD_TC_ADD(tp, rrq_medium_window);
1255 	TFTPD_TC_ADD(tp, rrq_netascii);
1256 	TFTPD_TC_ADD(tp, rrq_nonexistent);
1257 	TFTPD_TC_ADD(tp, rrq_path_max);
1258 	TFTPD_TC_ADD(tp, rrq_small);
1259 	TFTPD_TC_ADD(tp, rrq_window_rfc7440);
1260 	TFTPD_TC_ADD(tp, unknown_modes);
1261 	TFTPD_TC_ADD(tp, unknown_opcode);
1262 	TFTPD_TC_ADD(tp, w_flag);
1263 	TFTPD_TC_ADD(tp, wrq_dropped_ack);
1264 	TFTPD_TC_ADD(tp, wrq_dropped_data);
1265 	TFTPD_TC_ADD(tp, wrq_duped_data);
1266 	TFTPD_TC_ADD(tp, wrq_eaccess);
1267 	TFTPD_TC_ADD(tp, wrq_eaccess_world_readable);
1268 	TFTPD_TC_ADD(tp, wrq_medium);
1269 	TFTPD_TC_ADD(tp, wrq_medium_window);
1270 	TFTPD_TC_ADD(tp, wrq_netascii);
1271 	TFTPD_TC_ADD(tp, wrq_nonexistent);
1272 	TFTPD_TC_ADD(tp, wrq_small);
1273 	TFTPD_TC_ADD(tp, wrq_truncate);
1274 	TFTPD_TC_ADD(tp, wrq_window_rfc7440);
1275 	TFTPD_TC_ADD(tp, short_packet1);
1276 	TFTPD_TC_ADD(tp, short_packet2);
1277 	TFTPD_TC_ADD(tp, short_packet3);
1278 
1279 	return (atf_no_error());
1280 }
1281