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