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 #define TFTP_BLOCKSIZE_DEFAULT 512 /* according to RFC 1350, don't change */
26 #define TFTP_TIMEOUT 5 /* seconds */
27 #define TFTP_NUM_RETRIES 5 /* number of retries */
29 static const char * const MODE_OCTET = "octet";
30 #define MODE_OCTET_LEN 6 /* sizeof(MODE_OCTET)*/
32 static const char * const OPTION_BLOCKSIZE = "blksize";
33 #define OPTION_BLOCKSIZE_LEN 8 /* sizeof(OPTION_BLOCKSIZE) */
35 /* opcodes we support */
43 static const char *const tftp_bb_error_msg[] = {
47 "Disk full or allocation error",
48 "Illegal TFTP operation",
49 "Unknown transfer ID",
50 "File already exists",
54 #define tftp_cmd_get ENABLE_FEATURE_TFTP_GET
56 #if ENABLE_FEATURE_TFTP_PUT
57 # define tftp_cmd_put (tftp_cmd_get+ENABLE_FEATURE_TFTP_PUT)
59 # define tftp_cmd_put 0
63 #if ENABLE_FEATURE_TFTP_BLOCKSIZE
65 static int tftp_blocksize_check(int blocksize, int bufsize)
67 /* Check if the blocksize is valid:
68 * RFC2348 says between 8 and 65464,
69 * but our implementation makes it impossible
70 * to use blocksizes smaller than 22 octets.
73 if ((bufsize && (blocksize > bufsize)) ||
74 (blocksize < 8) || (blocksize > 65564)) {
75 bb_error_msg("bad blocksize");
82 static char *tftp_option_get(char *buf, int len, const char * const option)
90 /* Make sure the options are terminated correctly */
92 for (k = 0; k < len; k++) {
103 if (strcasecmp(buf, option) == 0) {
125 static int tftp(const int cmd, const struct hostent *host,
126 const char *remotefile, const int localfd,
127 const unsigned short port, int tftp_bufsize)
129 struct sockaddr_in sa;
130 struct sockaddr_in from;
138 int timeout = TFTP_NUM_RETRIES;
139 unsigned short block_nr = 1;
143 USE_FEATURE_TFTP_BLOCKSIZE(int want_option_ack = 0;)
145 /* Can't use RESERVE_CONFIG_BUFFER here since the allocation
146 * size varies meaning BUFFERS_GO_ON_STACK would fail */
147 /* We must keep the transmit and receive buffers seperate */
148 /* In case we rcv a garbage pkt and we need to rexmit the last pkt */
149 char *xbuf = xmalloc(tftp_bufsize += 4);
150 char *rbuf = xmalloc(tftp_bufsize);
152 if ((socketfd = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
153 /* need to unlink the localfile, so don't use xsocket here. */
154 bb_perror_msg("socket");
161 xbind(socketfd, (struct sockaddr *)&sa, len);
163 sa.sin_family = host->h_addrtype;
165 memcpy(&sa.sin_addr, (struct in_addr *) host->h_addr,
166 sizeof(sa.sin_addr));
169 if (cmd & tftp_cmd_get) {
172 if (cmd & tftp_cmd_put) {
180 /* first create the opcode part */
181 *((unsigned short *) cp) = htons(opcode);
184 /* add filename and mode */
185 if (((cmd & tftp_cmd_get) && (opcode == TFTP_RRQ)) ||
186 ((cmd & tftp_cmd_put) && (opcode == TFTP_WRQ)))
190 /* see if the filename fits into xbuf
191 * and fill in packet. */
192 len = strlen(remotefile) + 1;
194 if ((cp + len) >= &xbuf[tftp_bufsize - 1]) {
197 safe_strncpy(cp, remotefile, len);
201 if (too_long || ((&xbuf[tftp_bufsize - 1] - cp) < MODE_OCTET_LEN)) {
202 bb_error_msg("remote filename too long");
206 /* add "mode" part of the package */
207 memcpy(cp, MODE_OCTET, MODE_OCTET_LEN);
208 cp += MODE_OCTET_LEN;
210 #if ENABLE_FEATURE_TFTP_BLOCKSIZE
212 len = tftp_bufsize - 4; /* data block size */
214 if (len != TFTP_BLOCKSIZE_DEFAULT) {
216 if ((&xbuf[tftp_bufsize - 1] - cp) < 15) {
217 bb_error_msg("remote filename too long");
221 /* add "blksize" + number of blocks */
222 memcpy(cp, OPTION_BLOCKSIZE, OPTION_BLOCKSIZE_LEN);
223 cp += OPTION_BLOCKSIZE_LEN;
224 cp += snprintf(cp, 6, "%d", len) + 1;
231 /* add ack and data */
233 if (((cmd & tftp_cmd_get) && (opcode == TFTP_ACK)) ||
234 ((cmd & tftp_cmd_put) && (opcode == TFTP_DATA))) {
236 *((unsigned short *) cp) = htons(block_nr);
242 if ((cmd & tftp_cmd_put) && (opcode == TFTP_DATA)) {
243 len = full_read(localfd, cp, tftp_bufsize - 4);
246 bb_perror_msg(bb_msg_read_error);
250 if (len != (tftp_bufsize - 4)) {
262 timeout = TFTP_NUM_RETRIES; /* re-initialize */
267 #if ENABLE_DEBUG_TFTP
268 fprintf(stderr, "sending %u bytes\n", len);
269 for (cp = xbuf; cp < &xbuf[len]; cp++)
270 fprintf(stderr, "%02x ", (unsigned char) *cp);
271 fprintf(stderr, "\n");
273 if (sendto(socketfd, xbuf, len, 0,
274 (struct sockaddr *) &sa, sizeof(sa)) < 0) {
275 bb_perror_msg("send");
281 if (finished && (opcode == TFTP_ACK)) {
287 memset(&from, 0, sizeof(from));
288 fromlen = sizeof(from);
290 tv.tv_sec = TFTP_TIMEOUT;
294 FD_SET(socketfd, &rfds);
296 switch (select(socketfd + 1, &rfds, NULL, NULL, &tv)) {
298 len = recvfrom(socketfd, rbuf, tftp_bufsize, 0,
299 (struct sockaddr *) &from, &fromlen);
302 bb_perror_msg("recvfrom");
308 if (sa.sin_port == port) {
309 sa.sin_port = from.sin_port;
311 if (sa.sin_port == from.sin_port) {
315 /* fall-through for bad packets! */
316 /* discard the packet - treat as timeout */
317 timeout = TFTP_NUM_RETRIES;
319 bb_error_msg("timeout");
324 bb_error_msg("last timeout");
328 bb_perror_msg("select");
332 } while (timeout && (len >= 0));
334 if ((finished) || (len < 0)) {
338 /* process received packet */
340 opcode = ntohs(*((unsigned short *) rbuf));
341 tmp = ntohs(*((unsigned short *) &rbuf[2]));
343 #if ENABLE_DEBUG_TFTP
344 fprintf(stderr, "received %d bytes: %04x %04x\n", len, opcode, tmp);
347 if (opcode == TFTP_ERROR) {
348 const char *msg = NULL;
350 if (rbuf[4] != '\0') {
352 rbuf[tftp_bufsize - 1] = '\0';
353 } else if (tmp < (sizeof(tftp_bb_error_msg)
356 msg = tftp_bb_error_msg[tmp];
360 bb_error_msg("server says: %s", msg);
365 #if ENABLE_FEATURE_TFTP_BLOCKSIZE
366 if (want_option_ack) {
370 if (opcode == TFTP_OACK) {
372 /* server seems to support options */
376 res = tftp_option_get(&rbuf[2], len - 2, OPTION_BLOCKSIZE);
379 int blksize = xatoi_u(res);
381 if (tftp_blocksize_check(blksize, tftp_bufsize - 4)) {
383 if (cmd & tftp_cmd_put) {
388 #if ENABLE_DEBUG_TFTP
389 fprintf(stderr, "using %s %u\n", OPTION_BLOCKSIZE,
392 tftp_bufsize = blksize + 4;
398 * we should send ERROR 8 */
399 bb_error_msg("bad server option");
403 bb_error_msg("warning: blksize not supported by server"
404 " - reverting to 512");
406 tftp_bufsize = TFTP_BLOCKSIZE_DEFAULT + 4;
410 if ((cmd & tftp_cmd_get) && (opcode == TFTP_DATA)) {
412 if (tmp == block_nr) {
414 len = full_write(localfd, &rbuf[4], len - 4);
417 bb_perror_msg(bb_msg_write_error);
421 if (len != (tftp_bufsize - 4)) {
428 /* in case the last ack disappeared into the ether */
429 if (tmp == (block_nr - 1)) {
433 } else if (tmp + 1 == block_nr) {
434 /* Server lost our TFTP_ACK. Resend it */
441 if ((cmd & tftp_cmd_put) && (opcode == TFTP_ACK)) {
443 if (tmp == (unsigned short) (block_nr - 1)) {
454 #if ENABLE_FEATURE_CLEAN_UP
460 return finished ? EXIT_SUCCESS : EXIT_FAILURE;
463 int tftp_main(int argc, char **argv)
465 struct hostent *host = NULL;
466 const char *localfile = NULL;
467 const char *remotefile = NULL;
473 int blocksize = TFTP_BLOCKSIZE_DEFAULT;
475 /* figure out what to pass to getopt */
477 #if ENABLE_FEATURE_TFTP_BLOCKSIZE
478 char *sblocksize = NULL;
481 #define BS_ARG , &sblocksize
487 #if ENABLE_FEATURE_TFTP_GET
489 #define GET_COMPL ":g"
495 #if ENABLE_FEATURE_TFTP_PUT
497 #define PUT_COMPL ":p"
503 #if defined(CONFIG_FEATURE_TFTP_GET) && defined(CONFIG_FEATURE_TFTP_PUT)
504 opt_complementary = GET_COMPL PUT_COMPL ":?g--p:p--g";
505 #elif defined(CONFIG_FEATURE_TFTP_GET) || defined(CONFIG_FEATURE_TFTP_PUT)
506 opt_complementary = GET_COMPL PUT_COMPL;
509 cmd = getopt32(argc, argv, GET PUT "l:r:" BS, &localfile, &remotefile BS_ARG);
511 cmd &= (tftp_cmd_get | tftp_cmd_put);
512 #if ENABLE_FEATURE_TFTP_GET
513 if (cmd == tftp_cmd_get)
514 flags = O_WRONLY | O_CREAT | O_TRUNC;
516 #if ENABLE_FEATURE_TFTP_PUT
517 if (cmd == tftp_cmd_put)
521 #if ENABLE_FEATURE_TFTP_BLOCKSIZE
523 blocksize = xatoi_u(sblocksize);
524 if (!tftp_blocksize_check(blocksize, 0)) {
530 if (localfile == NULL)
531 localfile = remotefile;
532 if (remotefile == NULL)
533 remotefile = localfile;
534 if ((localfile == NULL && remotefile == NULL) || (argv[optind] == NULL))
537 if (localfile == NULL || LONE_DASH(localfile)) {
538 fd = (cmd == tftp_cmd_get) ? STDOUT_FILENO : STDIN_FILENO;
540 fd = open(localfile, flags, 0644); /* fail below */
543 bb_perror_msg_and_die("local file");
546 host = xgethostbyname(argv[optind]);
547 port = bb_lookup_port(argv[optind + 1], "udp", 69);
549 #if ENABLE_DEBUG_TFTP
550 fprintf(stderr, "using server \"%s\", remotefile \"%s\", "
551 "localfile \"%s\".\n",
552 inet_ntoa(*((struct in_addr *) host->h_addr)),
553 remotefile, localfile);
556 result = tftp(cmd, host, remotefile, fd, port, blocksize);
558 if (!(fd == STDOUT_FILENO || fd == STDIN_FILENO)) {
559 if (ENABLE_FEATURE_CLEAN_UP)
561 if (cmd == tftp_cmd_get && result != EXIT_SUCCESS)