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 #ifdef CONFIG_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 char *buf=xmalloc(tftp_bufsize += 4);
149 if ((socketfd = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
150 /* need to unlink the localfile, so don't use xsocket here. */
151 bb_perror_msg("socket");
158 xbind(socketfd, (struct sockaddr *)&sa, len);
160 sa.sin_family = host->h_addrtype;
162 memcpy(&sa.sin_addr, (struct in_addr *) host->h_addr,
163 sizeof(sa.sin_addr));
166 if (cmd & tftp_cmd_get) {
169 if (cmd & tftp_cmd_put) {
177 /* first create the opcode part */
178 *((unsigned short *) cp) = htons(opcode);
181 /* add filename and mode */
182 if (((cmd & tftp_cmd_get) && (opcode == TFTP_RRQ)) ||
183 ((cmd & tftp_cmd_put) && (opcode == TFTP_WRQ)))
187 /* see if the filename fits into buf
188 * and fill in packet. */
189 len = strlen(remotefile) + 1;
191 if ((cp + len) >= &buf[tftp_bufsize - 1]) {
194 safe_strncpy(cp, remotefile, len);
198 if (too_long || ((&buf[tftp_bufsize - 1] - cp) < MODE_OCTET_LEN)) {
199 bb_error_msg("remote filename too long");
203 /* add "mode" part of the package */
204 memcpy(cp, MODE_OCTET, MODE_OCTET_LEN);
205 cp += MODE_OCTET_LEN;
207 #ifdef CONFIG_FEATURE_TFTP_BLOCKSIZE
209 len = tftp_bufsize - 4; /* data block size */
211 if (len != TFTP_BLOCKSIZE_DEFAULT) {
213 if ((&buf[tftp_bufsize - 1] - cp) < 15) {
214 bb_error_msg("remote filename too long");
218 /* add "blksize" + number of blocks */
219 memcpy(cp, OPTION_BLOCKSIZE, OPTION_BLOCKSIZE_LEN);
220 cp += OPTION_BLOCKSIZE_LEN;
221 cp += snprintf(cp, 6, "%d", len) + 1;
228 /* add ack and data */
230 if (((cmd & tftp_cmd_get) && (opcode == TFTP_ACK)) ||
231 ((cmd & tftp_cmd_put) && (opcode == TFTP_DATA))) {
233 *((unsigned short *) cp) = htons(block_nr);
239 if ((cmd & tftp_cmd_put) && (opcode == TFTP_DATA)) {
240 len = full_read(localfd, cp, tftp_bufsize - 4);
243 bb_perror_msg(bb_msg_read_error);
247 if (len != (tftp_bufsize - 4)) {
259 timeout = TFTP_NUM_RETRIES; /* re-initialize */
264 #ifdef CONFIG_DEBUG_TFTP
265 fprintf(stderr, "sending %u bytes\n", len);
266 for (cp = buf; cp < &buf[len]; cp++)
267 fprintf(stderr, "%02x ", (unsigned char) *cp);
268 fprintf(stderr, "\n");
270 if (sendto(socketfd, buf, len, 0,
271 (struct sockaddr *) &sa, sizeof(sa)) < 0) {
272 bb_perror_msg("send");
278 if (finished && (opcode == TFTP_ACK)) {
284 memset(&from, 0, sizeof(from));
285 fromlen = sizeof(from);
287 tv.tv_sec = TFTP_TIMEOUT;
291 FD_SET(socketfd, &rfds);
293 switch (select(socketfd + 1, &rfds, NULL, NULL, &tv)) {
295 len = recvfrom(socketfd, buf, tftp_bufsize, 0,
296 (struct sockaddr *) &from, &fromlen);
299 bb_perror_msg("recvfrom");
305 if (sa.sin_port == port) {
306 sa.sin_port = from.sin_port;
308 if (sa.sin_port == from.sin_port) {
312 /* fall-through for bad packets! */
313 /* discard the packet - treat as timeout */
314 timeout = TFTP_NUM_RETRIES;
316 bb_error_msg("timeout");
321 bb_error_msg("last timeout");
325 bb_perror_msg("select");
329 } while (timeout && (len >= 0));
331 if ((finished) || (len < 0)) {
335 /* process received packet */
337 opcode = ntohs(*((unsigned short *) buf));
338 tmp = ntohs(*((unsigned short *) &buf[2]));
340 #ifdef CONFIG_DEBUG_TFTP
341 fprintf(stderr, "received %d bytes: %04x %04x\n", len, opcode, tmp);
344 if (opcode == TFTP_ERROR) {
345 const char *msg = NULL;
347 if (buf[4] != '\0') {
349 buf[tftp_bufsize - 1] = '\0';
350 } else if (tmp < (sizeof(tftp_bb_error_msg)
353 msg = tftp_bb_error_msg[tmp];
357 bb_error_msg("server says: %s", msg);
362 #ifdef CONFIG_FEATURE_TFTP_BLOCKSIZE
363 if (want_option_ack) {
367 if (opcode == TFTP_OACK) {
369 /* server seems to support options */
373 res = tftp_option_get(&buf[2], len - 2, OPTION_BLOCKSIZE);
376 int blksize = atoi(res);
378 if (tftp_blocksize_check(blksize, tftp_bufsize - 4)) {
380 if (cmd & tftp_cmd_put) {
385 #ifdef CONFIG_DEBUG_TFTP
386 fprintf(stderr, "using %s %u\n", OPTION_BLOCKSIZE,
389 tftp_bufsize = blksize + 4;
395 * we should send ERROR 8 */
396 bb_error_msg("bad server option");
400 bb_error_msg("warning: blksize not supported by server"
401 " - reverting to 512");
403 tftp_bufsize = TFTP_BLOCKSIZE_DEFAULT + 4;
407 if ((cmd & tftp_cmd_get) && (opcode == TFTP_DATA)) {
409 if (tmp == block_nr) {
411 len = full_write(localfd, &buf[4], len - 4);
414 bb_perror_msg(bb_msg_write_error);
418 if (len != (tftp_bufsize - 4)) {
425 /* in case the last ack disappeared into the ether */
426 if (tmp == (block_nr - 1)) {
430 } else if (tmp + 1 == block_nr) {
431 /* Server lost our TFTP_ACK. Resend it */
438 if ((cmd & tftp_cmd_put) && (opcode == TFTP_ACK)) {
440 if (tmp == (unsigned short) (block_nr - 1)) {
451 #ifdef CONFIG_FEATURE_CLEAN_UP
456 return finished ? EXIT_SUCCESS : EXIT_FAILURE;
459 int tftp_main(int argc, char **argv)
461 struct hostent *host = NULL;
462 const char *localfile = NULL;
463 const char *remotefile = NULL;
469 int blocksize = TFTP_BLOCKSIZE_DEFAULT;
471 /* figure out what to pass to getopt */
473 #ifdef CONFIG_FEATURE_TFTP_BLOCKSIZE
474 char *sblocksize = NULL;
477 #define BS_ARG , &sblocksize
483 #ifdef CONFIG_FEATURE_TFTP_GET
485 #define GET_COMPL ":g"
491 #ifdef CONFIG_FEATURE_TFTP_PUT
493 #define PUT_COMPL ":p"
499 #if defined(CONFIG_FEATURE_TFTP_GET) && defined(CONFIG_FEATURE_TFTP_PUT)
500 bb_opt_complementally = GET_COMPL PUT_COMPL ":?g--p:p--g";
501 #elif defined(CONFIG_FEATURE_TFTP_GET) || defined(CONFIG_FEATURE_TFTP_PUT)
502 bb_opt_complementally = GET_COMPL PUT_COMPL;
506 cmd = bb_getopt_ulflags(argc, argv, GET PUT "l:r:" BS,
507 &localfile, &remotefile BS_ARG);
509 cmd &= (tftp_cmd_get | tftp_cmd_put);
510 #ifdef CONFIG_FEATURE_TFTP_GET
511 if (cmd == tftp_cmd_get)
512 flags = O_WRONLY | O_CREAT | O_TRUNC;
514 #ifdef CONFIG_FEATURE_TFTP_PUT
515 if (cmd == tftp_cmd_put)
519 #ifdef CONFIG_FEATURE_TFTP_BLOCKSIZE
521 blocksize = atoi(sblocksize);
522 if (!tftp_blocksize_check(blocksize, 0)) {
528 if (localfile == NULL)
529 localfile = remotefile;
530 if (remotefile == NULL)
531 remotefile = localfile;
532 if ((localfile == NULL && remotefile == NULL) || (argv[optind] == NULL))
535 if (localfile == NULL || strcmp(localfile, "-") == 0) {
536 fd = (cmd == tftp_cmd_get) ? STDOUT_FILENO : STDIN_FILENO;
538 fd = open(localfile, flags, 0644); /* fail below */
541 bb_perror_msg_and_die("local file");
544 host = xgethostbyname(argv[optind]);
545 port = bb_lookup_port(argv[optind + 1], "udp", 69);
547 #ifdef CONFIG_DEBUG_TFTP
548 fprintf(stderr, "using server \"%s\", remotefile \"%s\", "
549 "localfile \"%s\".\n",
550 inet_ntoa(*((struct in_addr *) host->h_addr)),
551 remotefile, localfile);
554 result = tftp(cmd, host, remotefile, fd, port, blocksize);
556 if (!(fd == STDOUT_FILENO || fd == STDIN_FILENO)) {
557 if (ENABLE_FEATURE_CLEAN_UP)
559 if (cmd == tftp_cmd_get && result != EXIT_SUCCESS)