1 /* vi: set sw=4 ts=4: */
2 /* -------------------------------------------------------------------------
5 * A simple tftp client for busybox.
6 * Tries to follow RFC1350.
7 * Only "octet" mode supported.
8 * Optional blocksize negotiation (RFC2347 + RFC2348)
10 * Copyright (C) 2001 Magnus Damm <damm@opensource.se>
12 * Parts of the code based on:
14 * atftp: Copyright (C) 2000 Jean-Pierre Lefebvre <helix@step.polymtl.ca>
15 * and Remi Lefebvre <remi@debian.org>
17 * utftp: Copyright (C) 1999 Uwe Ohse <uwe@ohse.de>
19 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
20 * ------------------------------------------------------------------------- */
25 #include <sys/types.h>
26 #include <sys/socket.h>
29 #include <netinet/in.h>
30 #include <arpa/inet.h>
37 #define TFTP_BLOCKSIZE_DEFAULT 512 /* according to RFC 1350, don't change */
38 #define TFTP_TIMEOUT 5 /* seconds */
39 #define TFTP_NUM_RETRIES 5 /* number of retries */
41 /* RFC2348 says between 8 and 65464 */
42 #define TFTP_OCTECTS_MIN 8
43 #define TFTP_OCTECTS_MAX 65464
45 static const char * const MODE_OCTET = "octet";
46 #define MODE_OCTET_LEN 6 /* sizeof(MODE_OCTET)*/
48 static const char * const OPTION_BLOCKSIZE = "blksize";
49 #define OPTION_BLOCKSIZE_LEN 8 /* sizeof(OPTION_BLOCKSIZE) */
51 /* opcodes we support */
59 static const char *const tftp_bb_error_msg[] = {
63 "Disk full or allocation error",
64 "Illegal TFTP operation",
65 "Unknown transfer ID",
66 "File already exists",
70 #define tftp_cmd_get ENABLE_FEATURE_TFTP_GET
72 #if ENABLE_FEATURE_TFTP_PUT
73 # define tftp_cmd_put (tftp_cmd_get+ENABLE_FEATURE_TFTP_PUT)
75 # define tftp_cmd_put 0
79 #ifdef CONFIG_FEATURE_TFTP_BLOCKSIZE
81 static int tftp_blocksize_check(int blocksize, int bufsize)
83 /* Check if the blocksize is valid:
84 * RFC2348 says between 8 and 65464,
85 * but our implementation makes it impossible
86 * to use blocksizes smaller than 22 octets.
89 if ((bufsize && (blocksize > bufsize)) ||
90 (blocksize < TFTP_OCTECTS_MIN) || (blocksize > TFTP_OCTECTS_MAX)) {
91 bb_error_msg("bad blocksize");
98 static char *tftp_option_get(char *buf, int len, const char const *option)
106 /* Make sure the options are terminated correctly */
108 for (k = 0; k < len; k++) {
109 if (buf[k] == '\0') {
119 if (strcasecmp(buf, option) == 0) {
141 static int tftp(const int cmd, const struct hostent *host,
142 const char *remotefile, const int localfd,
143 const unsigned short port, int tftp_bufsize)
145 #define cmd_get cmd & tftp_cmd_get
146 #define cmd_put cmd & tftp_cmd_put
147 struct sockaddr_in sa;
148 struct sockaddr_in from;
156 int timeout = TFTP_NUM_RETRIES;
157 unsigned short block_nr = 1;
161 USE_FEATURE_TFTP_BLOCKSIZE(int want_option_ack = 0;)
163 /* Can't use RESERVE_CONFIG_BUFFER here since the allocation
164 * size varies meaning BUFFERS_GO_ON_STACK would fail */
165 char *buf=xmalloc(tftp_bufsize += 4);
167 if ((socketfd = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
168 /* need to unlink the localfile, so don't use bb_xsocket here. */
169 bb_perror_msg("socket");
176 bb_xbind(socketfd, (struct sockaddr *)&sa, len);
178 sa.sin_family = host->h_addrtype;
180 memcpy(&sa.sin_addr, (struct in_addr *) host->h_addr,
181 sizeof(sa.sin_addr));
195 /* first create the opcode part */
196 *((unsigned short *) cp) = htons(opcode);
199 /* add filename and mode */
200 if (((cmd_get) && (opcode == TFTP_RRQ)) ||
201 ((cmd_put) && (opcode == TFTP_WRQ)))
205 /* see if the filename fits into buf
206 * and fill in packet. */
207 len = strlen(remotefile) + 1;
209 if ((cp + len) >= &buf[tftp_bufsize - 1]) {
212 safe_strncpy(cp, remotefile, len);
216 if (too_long || ((&buf[tftp_bufsize - 1] - cp) < MODE_OCTET_LEN)) {
217 bb_error_msg("remote filename too long");
221 /* add "mode" part of the package */
222 memcpy(cp, MODE_OCTET, MODE_OCTET_LEN);
223 cp += MODE_OCTET_LEN;
225 #ifdef CONFIG_FEATURE_TFTP_BLOCKSIZE
227 len = tftp_bufsize - 4; /* data block size */
229 if (len != TFTP_BLOCKSIZE_DEFAULT) {
231 if ((&buf[tftp_bufsize - 1] - cp) < 15) {
232 bb_error_msg("remote filename too long");
236 /* add "blksize" + number of blocks */
237 memcpy(cp, OPTION_BLOCKSIZE, OPTION_BLOCKSIZE_LEN);
238 cp += OPTION_BLOCKSIZE_LEN;
239 cp += snprintf(cp, 6, "%d", len) + 1;
246 /* add ack and data */
248 if (((cmd_get) && (opcode == TFTP_ACK)) ||
249 ((cmd_put) && (opcode == TFTP_DATA))) {
251 *((unsigned short *) cp) = htons(block_nr);
257 if ((cmd_put) && (opcode == TFTP_DATA)) {
258 len = bb_full_read(localfd, cp, tftp_bufsize - 4);
261 bb_perror_msg(bb_msg_read_error);
265 if (len != (tftp_bufsize - 4)) {
277 timeout = TFTP_NUM_RETRIES; /* re-initialize */
282 #ifdef CONFIG_FEATURE_TFTP_DEBUG
283 fprintf(stderr, "sending %u bytes\n", len);
284 for (cp = buf; cp < &buf[len]; cp++)
285 fprintf(stderr, "%02x ", (unsigned char) *cp);
286 fprintf(stderr, "\n");
288 if (sendto(socketfd, buf, len, 0,
289 (struct sockaddr *) &sa, sizeof(sa)) < 0) {
290 bb_perror_msg("send");
296 if (finished && (opcode == TFTP_ACK)) {
302 memset(&from, 0, sizeof(from));
303 fromlen = sizeof(from);
305 tv.tv_sec = TFTP_TIMEOUT;
309 FD_SET(socketfd, &rfds);
311 switch (select(socketfd + 1, &rfds, NULL, NULL, &tv)) {
313 len = recvfrom(socketfd, buf, tftp_bufsize, 0,
314 (struct sockaddr *) &from, &fromlen);
317 bb_perror_msg("recvfrom");
323 if (sa.sin_port == port) {
324 sa.sin_port = from.sin_port;
326 if (sa.sin_port == from.sin_port) {
330 /* fall-through for bad packets! */
331 /* discard the packet - treat as timeout */
332 timeout = TFTP_NUM_RETRIES;
334 bb_error_msg("timeout");
339 bb_error_msg("last timeout");
343 bb_perror_msg("select");
347 } while (timeout && (len >= 0));
349 if ((finished) || (len < 0)) {
353 /* process received packet */
355 opcode = ntohs(*((unsigned short *) buf));
356 tmp = ntohs(*((unsigned short *) &buf[2]));
358 #ifdef CONFIG_FEATURE_TFTP_DEBUG
359 fprintf(stderr, "received %d bytes: %04x %04x\n", len, opcode, tmp);
362 if (opcode == TFTP_ERROR) {
363 const char *msg = NULL;
365 if (buf[4] != '\0') {
367 buf[tftp_bufsize - 1] = '\0';
368 } else if (tmp < (sizeof(tftp_bb_error_msg)
371 msg = tftp_bb_error_msg[tmp];
375 bb_error_msg("server says: %s", msg);
380 #ifdef CONFIG_FEATURE_TFTP_BLOCKSIZE
381 if (want_option_ack) {
385 if (opcode == TFTP_OACK) {
387 /* server seems to support options */
391 res = tftp_option_get(&buf[2], len - 2, OPTION_BLOCKSIZE);
394 int blksize = atoi(res);
396 if (tftp_blocksize_check(blksize, tftp_bufsize - 4)) {
403 #ifdef CONFIG_FEATURE_TFTP_DEBUG
404 fprintf(stderr, "using %s %u\n", OPTION_BLOCKSIZE,
407 tftp_bufsize = blksize + 4;
413 * we should send ERROR 8 */
414 bb_error_msg("bad server option");
418 bb_error_msg("warning: blksize not supported by server"
419 " - reverting to 512");
421 tftp_bufsize = TFTP_BLOCKSIZE_DEFAULT + 4;
425 if ((cmd_get) && (opcode == TFTP_DATA)) {
427 if (tmp == block_nr) {
429 len = bb_full_write(localfd, &buf[4], len - 4);
432 bb_perror_msg(bb_msg_write_error);
436 if (len != (tftp_bufsize - 4)) {
443 /* in case the last ack disappeared into the ether */
444 if (tmp == (block_nr - 1)) {
448 } else if (tmp + 1 == block_nr) {
449 /* Server lost our TFTP_ACK. Resend it */
456 if ((cmd_put) && (opcode == TFTP_ACK)) {
458 if (tmp == (unsigned short) (block_nr - 1)) {
469 #ifdef CONFIG_FEATURE_CLEAN_UP
474 return finished ? EXIT_SUCCESS : EXIT_FAILURE;
477 int tftp_main(int argc, char **argv)
479 struct hostent *host = NULL;
480 const char *localfile = NULL;
481 const char *remotefile = NULL;
487 int blocksize = TFTP_BLOCKSIZE_DEFAULT;
489 /* figure out what to pass to getopt */
491 #ifdef CONFIG_FEATURE_TFTP_BLOCKSIZE
492 char *sblocksize = NULL;
495 #define BS_ARG , &sblocksize
501 #ifdef CONFIG_FEATURE_TFTP_GET
503 #define GET_COMPL ":g"
509 #ifdef CONFIG_FEATURE_TFTP_PUT
511 #define PUT_COMPL ":p"
517 #if defined(CONFIG_FEATURE_TFTP_GET) && defined(CONFIG_FEATURE_TFTP_PUT)
518 bb_opt_complementally = GET_COMPL PUT_COMPL ":?g--p:p--g";
519 #elif defined(CONFIG_FEATURE_TFTP_GET) || defined(CONFIG_FEATURE_TFTP_PUT)
520 bb_opt_complementally = GET_COMPL PUT_COMPL;
522 #error "Either CONFIG_FEATURE_TFTP_GET or CONFIG_FEATURE_TFTP_PUT must be defined"
526 cmd = bb_getopt_ulflags(argc, argv, GET PUT "l:r:" BS,
527 &localfile, &remotefile BS_ARG);
529 cmd &= (tftp_cmd_get | tftp_cmd_put);
530 #ifdef CONFIG_FEATURE_TFTP_GET
531 if (cmd == tftp_cmd_get)
532 flags = O_WRONLY | O_CREAT | O_TRUNC;
534 #ifdef CONFIG_FEATURE_TFTP_PUT
535 if (cmd == tftp_cmd_put)
539 #ifdef CONFIG_FEATURE_TFTP_BLOCKSIZE
541 blocksize = atoi(sblocksize);
542 if (!tftp_blocksize_check(blocksize, 0)) {
548 if (localfile == NULL)
549 localfile = remotefile;
550 if (remotefile == NULL)
551 remotefile = localfile;
552 if ((localfile == NULL && remotefile == NULL) || (argv[optind] == NULL))
555 if (localfile == NULL || strcmp(localfile, "-") == 0) {
556 fd = (cmd == tftp_cmd_get) ? STDOUT_FILENO : STDIN_FILENO;
558 fd = open(localfile, flags, 0644); /* fail below */
561 bb_perror_msg_and_die("local file");
564 host = xgethostbyname(argv[optind]);
565 port = bb_lookup_port(argv[optind + 1], "udp", 69);
567 #ifdef CONFIG_FEATURE_TFTP_DEBUG
568 fprintf(stderr, "using server \"%s\", remotefile \"%s\", "
569 "localfile \"%s\".\n",
570 inet_ntoa(*((struct in_addr *) host->h_addr)),
571 remotefile, localfile);
574 result = tftp(cmd, host, remotefile, fd, port, blocksize);
576 #ifdef CONFIG_FEATURE_CLEAN_UP
577 if (!(fd == STDOUT_FILENO || fd == STDIN_FILENO)) {
581 if (cmd == tftp_cmd_get && result != EXIT_SUCCESS)