1 /* ------------------------------------------------------------------------- */
4 /* A simple tftp client for busybox. */
5 /* Tries to follow RFC1350. */
6 /* Only "octet" mode and 512-byte data blocks are supported. */
8 /* Copyright (C) 2001 Magnus Damm <damm@opensource.se> */
10 /* Parts of the code based on: */
12 /* atftp: Copyright (C) 2000 Jean-Pierre Lefebvre <helix@step.polymtl.ca> */
13 /* and Remi Lefebvre <remi@debian.org> */
15 /* utftp: Copyright (C) 1999 Uwe Ohse <uwe@ohse.de> */
17 /* This program is free software; you can redistribute it and/or modify */
18 /* it under the terms of the GNU General Public License as published by */
19 /* the Free Software Foundation; either version 2 of the License, or */
20 /* (at your option) any later version. */
22 /* This program is distributed in the hope that it will be useful, */
23 /* but WITHOUT ANY WARRANTY; without even the implied warranty of */
24 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU */
25 /* General Public License for more details. */
27 /* You should have received a copy of the GNU General Public License */
28 /* along with this program; if not, write to the Free Software */
29 /* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
31 /* ------------------------------------------------------------------------- */
36 #include <sys/types.h>
37 #include <sys/socket.h>
41 #include <netinet/in.h>
42 #include <arpa/inet.h>
48 //#define BB_FEATURE_TFTP_DEBUG
50 /* we don't need #ifdefs with these constants and optimization... */
52 #ifdef BB_FEATURE_TFTP_GET
53 #define BB_TFTP_GET (1 << 0)
58 #ifdef BB_FEATURE_TFTP_PUT
59 #define BB_TFTP_PUT (1 << 1)
64 #ifdef BB_FEATURE_TFTP_DEBUG
65 #define BB_TFTP_DEBUG 1
67 #define BB_TFTP_DEBUG 0
70 #define BB_TFTP_NO_RETRIES 5
71 #define BB_TFTP_TIMEOUT 5 /* seconds */
73 #define RRQ 1 /* read request */
74 #define WRQ 2 /* write request */
75 #define DATA 3 /* data packet */
76 #define ACK 4 /* acknowledgement */
77 #define ERROR 5 /* error code */
79 #define BUFSIZE (512+4)
81 static const char *tftp_error_msg[] = {
85 "Disk full or allocation error",
86 "Illegal TFTP operation",
87 "Unknown transfer ID",
88 "File already exists",
92 static inline int tftp(int cmd, struct hostent *host,
93 char *serverfile, int localfd, int port)
95 struct sockaddr_in sa;
99 struct sockaddr_in from;
103 int len, opcode, finished;
104 int timeout, block_nr;
106 RESERVE_BB_BUFFER(buf, BUFSIZE);
108 opcode = finished = timeout = 0;
111 if ((socketfd = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
112 perror_msg("socket");
119 bind(socketfd, (struct sockaddr *)&sa, len);
121 sa.sin_family = host->h_addrtype;
122 sa.sin_port = htons(port);
123 memcpy(&sa.sin_addr, (struct in_addr *) host->h_addr,
124 sizeof(sa.sin_addr));
128 if (cmd & BB_TFTP_GET) {
132 if (cmd & BB_TFTP_PUT) {
139 /* build packet of type "opcode" */
144 *((unsigned short *) cp) = htons(opcode);
148 /* add filename and mode */
150 if ((BB_TFTP_GET && (opcode == RRQ)) ||
151 (BB_TFTP_PUT && (opcode == WRQ))) {
153 while (cp != &buf[BUFSIZE - 1]) {
154 if ((*cp = *serverfile++) == '\0')
159 if ((*cp != '\0') || (&buf[BUFSIZE - 1] - cp) < 7) {
160 error_msg("too long server-filename");
164 memcpy(cp + 1, "octet", 6);
168 /* add ack and data */
170 if ((BB_TFTP_GET && (opcode == ACK)) ||
171 (BB_TFTP_PUT && (opcode == DATA))) {
173 *((unsigned short *) cp) = htons(block_nr);
179 if (BB_TFTP_PUT && (opcode == DATA)) {
180 len = read(localfd, cp, BUFSIZE - 4);
187 if (len != (BUFSIZE - 4)) {
192 } else if (finished) {
206 printf("sending %u bytes\n", len);
208 for (cp = buf; cp < &buf[len]; cp++)
209 printf("%02x ", *cp);
213 if (sendto(socketfd, buf, len, 0,
214 (struct sockaddr *) &sa, sizeof(sa)) < 0) {
224 memset(&from, 0, sizeof(from));
225 fromlen = sizeof(from);
227 tv.tv_sec = BB_TFTP_TIMEOUT;
231 FD_SET(socketfd, &rfds);
233 switch (select(FD_SETSIZE, &rfds, NULL, NULL, &tv)) {
235 len = recvfrom(socketfd, buf,
237 (struct sockaddr *) &from, &fromlen);
240 perror_msg("recvfrom");
246 if (sa.sin_port == htons(port)) {
247 sa.sin_port = from.sin_port;
251 if (sa.sin_port == from.sin_port) {
255 /* fall-through for bad packets! */
256 /* discard the packet - treat as timeout */
259 error_msg("timeout");
262 timeout = BB_TFTP_NO_RETRIES;
269 error_msg("last timeout");
274 perror_msg("select");
278 } while (timeout && (len >= 0));
284 /* process received packet */
287 opcode = ntohs(*((unsigned short *) buf));
288 tmp = ntohs(*((unsigned short *) &buf[2]));
291 printf("received %d bytes: %04x %04x\n", len, opcode, tmp);
294 if (BB_TFTP_GET && (opcode == DATA)) {
296 if (tmp == block_nr) {
297 len = write(localfd, &buf[4], len - 4);
304 if (len != (BUFSIZE - 4)) {
313 if (BB_TFTP_PUT && (opcode == ACK)) {
315 if (tmp == (block_nr - 1)) {
325 if (opcode == ERROR) {
328 if (buf[4] != '\0') {
330 buf[BUFSIZE - 1] = '\0';
331 } else if (tmp < (sizeof(tftp_error_msg) / sizeof(char *))) {
332 msg = (char *) tftp_error_msg[tmp];
336 error_msg("server says: %s", msg);
345 return finished ? EXIT_SUCCESS : EXIT_FAILURE;
348 int tftp_main(int argc, char **argv)
352 struct hostent *host;
355 int cmd, flags, fd, bad;
357 host = (void *) serverstr = serverfile = localfile = NULL;
362 if (BB_TFTP_GET && (strcmp(argv[1], "get") == 0)) {
364 flags = O_WRONLY | O_CREAT;
369 if (BB_TFTP_PUT && (strcmp(argv[1], "put") == 0)) {
378 if (!(cmd & (BB_TFTP_GET | BB_TFTP_PUT))) {
382 for (cp = serverstr; *cp != '\0'; cp++)
390 s = xstrdup(serverstr);
391 s[cp - serverstr] = '\0';
393 host = xgethostbyname(s);
399 printf("using server \"%s\", serverfile \"%s\","
400 "localfile \"%s\".\n",
401 inet_ntoa(*((struct in_addr *) host->h_addr)),
402 serverfile, localfile);
405 if ((fd = open(localfile, flags, 0644)) < 0) {
406 perror_msg_and_die("local file");
409 flags = tftp(cmd, host, serverfile, fd, 69);