3 * A simple tftpd server for busybox
5 * Copyright (C) 2001 Steven Carr <Steven_Carr@yahoo.com>
7 * Tries to follow RFC1350 and RFC2347.
8 * Only "octet" mode supported.
9 * tsize option is supported on sending files only (pxelinux support).
10 * chroot jail for security.
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-137 USA
30 #include <sys/types.h>
31 #include <sys/socket.h>
36 #include <netinet/in.h>
37 #include <arpa/inet.h>
38 #include <arpa/tftp.h>
42 #include <asm/ioctls.h>
43 #include <sys/ioctl.h>
49 #ifdef HAVE_ASM_SOCKET_H
50 #include <asm/socket.h>
55 # ifdef HAVE_SYS_WAIT_H
56 # include <sys/wait.h>
75 #if !defined(__UCLIBC__) || defined(__UCLIBC_HAS_MMU__)
78 #define FORK() vfork()
81 #define TFTP_BLOCKSIZE_DEFAULT 512 /* according to RFC 1350, don't change */
82 #define TFTP_TIMEOUT 5 /* seconds */
83 // brcm begine. Enable put only
84 #include "../../ftpd/fwsyscall.h"
86 extern UPLOAD_RESULT verifyTag(PFILE_TAG pTag, int passNumber);
87 #define DUP_PKT_CHECK_COUNT 3
89 //#define CONFIG_FEATURE_TFTPD_GET
90 #define CONFIG_FEATURE_TFTPD_PUT
91 extern char glbIfName[];
92 void perror_msg_and_die(char *);
94 void perror_msg_and_die(char * msg)
100 // if applications are killed, reset the modem.
101 int myExit(int fNeedReset, int peer)
111 * Handle initial connection protocol.
112 * +-------+---~~---+---+---~~---+---+---~~---+---+---~~---+---+--> >-------+---+---~~---+---+
113 * | opc |filename| 0 | mode | 0 | opt1 | 0 | value1 | 0 | < < optN | 0 | valueN | 0 |
114 * +-------+---~~---+---+---~~---+---+---~~---+---+---~~---+---+--> >-------+---+---~~---+---+
118 /* The options are zero terminated, retrieve a list of pointers to the first character of each option */
119 int tftpd_options (char *options, int opt_len, char **argv, int max_arg)
124 for (y = 1, x = 0; (y < max_arg) && (x < (opt_len - 1)); x++)
128 if (options[x + 1] == 0)
130 argv[y] = &options[x + 1];
139 * Send a nak packet (error message).
140 * Error code passed in is one of the
141 * standard TFTP codes, or a UNIX errno
144 void tftpd_nak (int peer, int error)
146 char buf[TFTP_BLOCKSIZE_DEFAULT + 4];
149 pkt = (struct tftphdr *) buf;
150 pkt->th_opcode = htons ((u_short) ERROR);
151 pkt->th_code = htons ((u_short) error);
156 strcpy (pkt->th_msg, "Put not supported");
157 pkt->th_code = htons (EUNDEF);
160 strcpy (pkt->th_msg, "Get not supported");
161 pkt->th_code = htons (EUNDEF);
164 strcpy (pkt->th_msg, "Undefined error code");
167 strcpy (pkt->th_msg, "File not found");
170 strcpy (pkt->th_msg, "Access violation");
173 strcpy (pkt->th_msg, "Disk full or allocation exceeded");
176 strcpy (pkt->th_msg, "Illegal TFTP operation");
179 strcpy (pkt->th_msg, "Unknown transfer ID");
182 strcpy (pkt->th_msg, "File already exists");
185 strcpy (pkt->th_msg, "No such user");
188 strcpy (pkt->th_msg, "Failure to negotiate RFC2347 options");
191 strcpy (pkt->th_msg, strerror (error - 100));
192 pkt->th_code = htons (EUNDEF);
196 send (peer, buf, strlen (pkt->th_msg) + 5, 0);
202 void tftpd_ack (int peer, int block)
206 pkt.th_opcode = htons (ACK);
207 pkt.th_block = htons (block);
209 if (send (peer, &pkt, sizeof(pkt), 0)!=sizeof(pkt))
210 perror_msg_and_die("tftpd_ack send");
217 void tftpd_oack (int peer, int count, char **list)
219 char buf[TFTP_BLOCKSIZE_DEFAULT + 4];
224 pkt=(struct tftphdr *)buf;
225 pkt->th_opcode = htons (OACK);
228 for (x=0;x<count;x++)
229 ptr=strrchr (strcpy (ptr, list[x]), '\0') + 1;
231 if ( send (peer, buf, (ptr-buf), 0)!=(ptr-buf))
232 perror_msg_and_die("tftpd_oack send");
239 void tftpd_data (int peer, int block, char *data, int size)
242 char buf[TFTP_BLOCKSIZE_DEFAULT + 4];
244 pkt=(struct tftphdr *)buf;
245 pkt->th_opcode = htons (DATA);
246 pkt->th_block = htons(block);
248 memcpy(pkt->th_data,data,size);
250 if (send (peer, &buf, size+4, 0)!=(size+4))
251 perror_msg_and_die("tftpd_data send");
254 int tftpd_getdata(int peer, int block, char *data, int size, int fNeedReset)
260 int timeout_counter = 4;
262 pkt=(struct tftphdr *)data;
265 tv.tv_sec = TFTP_TIMEOUT;
268 FD_SET (peer, &rfds);
269 switch (select (FD_SETSIZE, &rfds, NULL, NULL, &tv))
271 case 1: /* data ready */
272 len = recv (peer, data, size, 0);
274 perror_msg_and_die ("failed to read (data)");
276 pkt->th_opcode = ntohs (pkt->th_opcode);
277 pkt->th_block = ntohs (pkt->th_block);
278 if (pkt->th_opcode == ERROR)
280 bb_error_msg (pkt->th_data);
281 myExit(fNeedReset, peer);
283 if ((pkt->th_opcode == DATA) && (pkt->th_block != block))
285 //synchronize (peer);
288 case 0: /* timeout */
290 if (timeout_counter == 0)
292 bb_error_msg ("last timeout");
293 myExit(fNeedReset, peer);
297 perror_msg_and_die ("select failed");
300 }while (!(pkt->th_opcode == DATA) && (pkt->th_block == block));
306 int tftpd_getack(int peer, int block)
308 char data[TFTP_BLOCKSIZE_DEFAULT + 4];
312 int timeout_counter = 4;
315 pkt=(struct tftphdr *)data;
318 tv.tv_sec = TFTP_TIMEOUT;
321 FD_SET (peer, &rfds);
322 switch (select (FD_SETSIZE, &rfds, NULL, NULL, &tv))
324 case 1: /* data ready */
326 len = recv (peer, data, TFTP_BLOCKSIZE_DEFAULT + 4, 0);
328 perror_msg_and_die ("failed to read (data)");
330 pkt->th_opcode = ntohs (pkt->th_opcode);
331 pkt->th_block = ntohs (pkt->th_block);
333 if (pkt->th_opcode == ERROR)
335 bb_error_msg (pkt->th_data);
339 if ((pkt->th_opcode == ACK) && (pkt->th_block != block))
341 //synchronize (peer);
344 case 0: /* timeout */
346 if (timeout_counter == 0)
348 bb_error_msg ("last timeout");
353 perror_msg_and_die ("select failed");
356 }while (! ((pkt->th_opcode == ACK) && (pkt->th_block == block)) );
365 #ifndef CONFIG_FEATURE_TFTPD_GET
367 tftpd_send (int peer, struct tftphdr *tp, int n, int buffersize)
369 /* we aren't configured for sending files */
370 tftpd_nak (peer, ENOGET);
377 tftpd_send (int peer, struct tftphdr *first_pkt, int pkt_len, int buffersize)
380 char buffer[TFTP_BLOCKSIZE_DEFAULT+4];
381 char *list[64]; /* list of pointers to options and values */
383 char *reply_list[64];
384 int reply_listcount=0;
386 int block, inbytes, x;
388 listcount = tftpd_options (first_pkt->th_stuff, pkt_len, list ,64);
390 /* get the size of the file (remember, chroot() supposed to point us in the right directory) */
392 if (strcasecmp(list[1],"octet")!=0)
394 tftpd_nak(peer,EBADOP);
400 file = fopen (list[0], "r");
403 tftpd_nak (peer, ENOTFOUND);
407 fseek (file, 0, SEEK_END);
408 sprintf(tsize_ret,"%lu", ftell (file));
409 fseek (file, 0, SEEK_SET);
412 /* 0=filename, 1=mode, 2=option, 3=option_value ... */
416 /* look through the options for the ones we support */
417 for (x=2;x<listcount;x++)
419 if (strcasecmp(list[x],"tsize")==0) /* only one option supported so far */
421 reply_list[reply_listcount]=list[x];
423 reply_list[reply_listcount]=tsize_ret; /* point to the real value */
428 /* if there are any options, send an OACK instead of an ACK */
429 if (reply_listcount>0)
433 tftpd_oack(peer,reply_listcount,reply_list);
435 while (!tftpd_getack(peer,0));
440 while ((inbytes = fread(buffer,1,TFTP_BLOCKSIZE_DEFAULT,file))>0)
444 tftpd_data(peer,block,buffer,inbytes);
446 while (!tftpd_getack(peer,block));
457 #ifndef CONFIG_FEATURE_TFTPD_PUT
459 tftpd_receive (int peer, struct tftphdr *tp, int n, int buffersize)
461 /* we aren't configured for receiving files */
462 tftpd_nak (peer, ENOPUT);
470 tftpd_receive (int peer, struct tftphdr *first_pkt, int pkt_len, int buffersize)
472 // brcm FILE *file=NULL;
473 char buffer[TFTP_BLOCKSIZE_DEFAULT+4];
480 PARSE_RESULT imageType = NO_IMAGE_FORMAT;
486 unsigned int totalAllocatedSize = 0;
488 int fNeedReset = FALSE;
489 char *imagePtr = NULL;
493 //printf("tftpd_receive, peer = %d, pkt_len = %d, buffersize=%d\n", peer, pkt_len, buffersize);
495 pkt=(struct tftphdr *)buffer;
496 listcount = tftpd_options (first_pkt->th_stuff, pkt_len, list ,64);
498 /* get the size of the file (remember, chroot() supposed to point us in the right directory) */
500 //printf ("mode= %s, file= %s\n", list[1], list[0]);
501 if (strcasecmp(list[1],"octet")!=0)
503 printf("Only support 'bin' mode. Type 'bin' at tftp client\n");
504 tftpd_nak(peer,EBADOP);
510 file = fopen (list[0], "w");
513 tftpd_nak (peer, EACCESS);
521 socketPid = bcmSocketIfPid();
522 // kill the app first so that when there are heavy traffic, the UDP packet will not be lost.
523 killAllApps(socketPid, SKIP_HTTPD_APP, 0, 0); // skip kill httpd for xml config. update
524 printf("Done removing processes\n");
529 tftpd_ack(peer,block);
532 // if duplicate pkt, (for slow ack on 38R board) discard it.
533 for (i = 0; i < DUP_PKT_CHECK_COUNT; i++)
535 inbytes=tftpd_getdata(peer,block,buffer,TFTP_BLOCKSIZE_DEFAULT+4, fNeedReset);
536 if (block == (int) (*(short*)(buffer+2)))
539 // brcm fwrite(pkt->th_msg,1,inbytes-4,file);
544 if (byteRd < TFTP_BLOCKSIZE_DEFAULT) // not enough data for a valid first packet and exit
549 // The first data that is downloaded is the FILE_TAG structure.
550 // After the entire FILE_TAG structure has been downloaded, use
551 // the totalImageSize field to determine the size of pkt->th_msg to
553 if( tagSize + byteRd > TAG_LEN)
554 size = TAG_LEN - tagSize;
558 memcpy(tag + tagSize, pkt->th_msg, size);
561 if( tagSize == TAG_LEN )
563 PFILE_TAG pTag = (PFILE_TAG) tag;
565 if (verifyTag(pTag, 1) == UPLOAD_OK)
567 // if chip id mismatched.
568 if (checkChipId(pTag->chipId, pTag->signiture_2) != 0)
569 myExit(fNeedReset, peer);
570 int totalImageSize = atoi(pTag->totalImageLen);
571 // add tag len plus some pkt->th_msg for over flow during the sending...
572 totalAllocatedSize = totalImageSize + TAG_LEN + 8;
573 printf( "Allocating %d bytes for broadcom image.\n", totalAllocatedSize );
574 curPtr = (char *) malloc(totalImageSize + TAG_LEN + 8);
577 printf("Not enough memory error.");
578 myExit(fNeedReset, peer);
582 printf("Memory allocated\n");
584 memcpy(curPtr, tag, TAG_LEN);
586 uploadSize += TAG_LEN;
587 memcpy(curPtr, pkt->th_msg + size, byteRd);
591 // try to allocate the memory for .w image, same as flash size + some overhead
594 totalAllocatedSize = sysFlashSizeGet() + TOKEN_LEN;
595 printf("Allocating %d bytes for flash image.\n", totalAllocatedSize);
596 curPtr = (char *) malloc(totalAllocatedSize);
599 printf("Not enough memory error.");
600 myExit(fNeedReset, peer);
604 printf("Memory allocated\n");
606 byteRd += TAG_LEN; // add back the tag size
607 memcpy(curPtr, pkt->th_msg, byteRd);
610 } // else alloc memory for .w image
611 } //tagSize == TAG_LEN
612 } // if curPtr == NULL
614 { // not first block of data
615 memcpy(curPtr, pkt->th_msg, byteRd);
619 uploadSize += byteRd;
620 //printf("Current uploadSize= %d\n", uploadSize);
621 if (uploadSize > totalAllocatedSize) // try not to over flow the pkt->th_msg
623 printf("Failed on data corruption during file transfer or over sized image.\n");
624 printf("Upload size = %d, size allowed = %d\n", uploadSize, totalAllocatedSize);
625 myExit(fNeedReset, peer);
629 while (inbytes==(TFTP_BLOCKSIZE_DEFAULT+4));
631 tftpd_ack(peer,block); /* final acknowledge */
633 // brcm fclose(file);
635 printf("Total size: %d\n", uploadSize);
637 if ((imagePtr != NULL) &&
638 ((imageType = parseImageData(imagePtr, uploadSize, BUF_ALL_TYPES)) != NO_IMAGE_FORMAT))
640 printf("Tftp image done.\n");
641 flashImage(imagePtr, imageType, uploadSize);
646 printf("Tftp Image failed: Illegal image.\n");
648 // no reset if psi update (need httpd to process xml file)
649 if (imageType == PSI_IMAGE_FORMAT)
651 myExit(fNeedReset, peer);
656 static struct in_addr getLanIp(void) //struct in_addr *lan_ip)
661 memset(&lan, 0, sizeof(lan));
662 if ((socketfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
663 printf("Error openning socket when getting LAN info\n");
666 strcpy(lan.ifr_name, "br0");
667 if (ioctl(socketfd,SIOCGIFADDR,&lan) < 0) {
668 printf("Error getting LAN IP address\n");
672 return ((struct sockaddr_in *)&(lan.ifr_addr))->sin_addr;
676 #include <bits/socket.h>
678 #define MAXCTRLSIZE \
679 (sizeof(struct cmsghdr) + sizeof(struct sockaddr_in) + \
680 sizeof(struct cmsghdr) + sizeof(int) + 32)
684 tftpd_daemon (char *directory, char *address, int port)
687 struct sockaddr_in from;
688 struct sockaddr_in myaddr;
689 struct sockaddr_in bindaddr;
697 char buf[TFTP_BLOCKSIZE_DEFAULT + 4];
698 struct iovec iov = { buf, sizeof buf };
699 struct cmsghdr *cmsg;
700 char *ctrl = (char *)xmalloc(MAXCTRLSIZE);
701 struct msghdr msg = { (void*)&from, sizeof from, &iov, 1, (void*)ctrl, MAXCTRLSIZE, 0};
702 struct in_pktinfo *info = NULL;
708 if ((fd = socket (PF_INET, SOCK_DGRAM, 0)) < 0)
709 perror_msg_and_die ("socket");
711 // Keven Kuo -- no need for inetd
713 // set option for getting the to ip address.
714 setsockopt(fd, IPPROTO_IP, IP_PKTINFO, &i, sizeof(i));
717 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void *) &i, sizeof(i));
720 setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, (void *) &i, sizeof(i));
723 memset (&bindaddr, 0, sizeof (bindaddr));
724 bindaddr.sin_family = AF_INET;
725 bindaddr.sin_port = htons (port);
728 struct hostent *hostent;
729 hostent = xgethostbyname (address);
730 if (!hostent || hostent->h_addrtype != AF_INET)
731 perror_msg_and_die ("cannot resolve local bind address");
732 memcpy (&bindaddr.sin_addr, hostent->h_addr, hostent->h_length);
735 if (bind (fd, (struct sockaddr *) &bindaddr, sizeof (bindaddr)) < 0)
736 perror_msg_and_die ("daemon bind failed");
737 /* This means we don't want to wait() for children */
738 signal (SIGCHLD, SIG_IGN);
740 // get pid for web access function to start/stop tftpd.
744 if (!(pid_fp = fopen("/var/run/tftpd_pid", "w")))
746 printf("Error open /var/run/tftpd_pid");
749 fprintf(pid_fp, "%d\n", getpid());
759 memset(buf,0,TFTP_BLOCKSIZE_DEFAULT + 4);
760 memset (&myaddr, 0, sizeof (myaddr));
762 FD_SET (fd, &readset);
763 /* Never time out, we're in standalone mode */
764 rv = select (fd + 1, &readset, NULL, NULL, NULL);
765 if (rv == -1 && errno == EINTR)
768 continue; /* Signal caught, reloop */
773 perror_msg_and_die ("select loop");
776 bb_error_msg ("We shouldn't be timeing out!");
777 exit (0); /* Timeout, return to inetd */
780 n = recvmsg (fd, &msg, MSG_WAITALL);
783 if (n == 0) /* Keven -- Received message with zero length, reloop */
791 printf("*** error recvmsg n=%d\n", n);
800 for(cmsg=CMSG_FIRSTHDR(&msg); cmsg != NULL;cmsg =CMSG_NXTHDR(&msg,cmsg)) {
801 if (cmsg->cmsg_type == IP_PKTINFO){
802 info = (struct in_pktinfo *)CMSG_DATA(cmsg);
806 /* Process the request */
807 myaddr.sin_family = AF_INET;
808 myaddr.sin_port = htons (0); /* we want a new local port */
809 myaddr.sin_addr = getLanIp();
812 if (myaddr.sin_addr.s_addr != info->ipi_spec_dst.s_addr)
813 memcpy (&myaddr.sin_addr, &bindaddr.sin_addr,sizeof bindaddr.sin_addr);
815 /* Now that we have read the request packet from the UDP
816 socket, we fork and go back to listening to the socket. */
820 perror_msg_and_die ("cannot fork");
823 /* Child exits the while(1), parent continues to loop */
827 /* Close file descriptors we don't need */
830 /* Get a socket. This has to be done before the chroot() (/dev goes away) */
831 peer = socket (AF_INET, SOCK_DGRAM, 0);
833 perror_msg_and_die ("socket");
835 perror_msg_and_die ("chroot");
836 from.sin_family = AF_INET;
838 /* Process the request */
839 if (bind (peer, (struct sockaddr *) &myaddr, sizeof myaddr) < 0)
840 perror_msg_and_die ("daemon-child bind");
842 if (connect (peer, (struct sockaddr *) &from, sizeof from) < 0)
843 perror_msg_and_die ("daemon-child connect");
845 tp = (struct tftphdr *) buf;
847 int accessMode = bcmCheckEnable("tftp", from.sin_addr);
849 if (accessMode == CLI_ACCESS_DISABLED)
854 if (accessMode == CLI_ACCESS_REMOTE)
857 if ((bcmGetIntfNameSocket(peer, glbIfName) != 0) || glbIfName[0] == '\0')
859 printf("Failed to get remote ifc name!\n");
865 tp->th_opcode = ntohs (tp->th_opcode);
867 switch(tp->th_opcode)
870 tftpd_send (peer, tp, n, TFTP_BLOCKSIZE_DEFAULT);
873 tftpd_receive (peer, tp, n, TFTP_BLOCKSIZE_DEFAULT);
880 tftpd_main (int argc, char **argv)
883 char *address = NULL; /* address to listen to */
885 int daemonize = 1; // brcm (1 == 0);
891 char directory[256]; /* default directory "/tftpboot/" */
892 memset (directory, 0, sizeof (directory));
893 strcpy (directory, "/tftpboot/");
895 while ((opt = getopt (argc, argv, "sp:a:d:h")) != -1)
900 port = atoi (optarg);
906 daemonize = (1 == 1);
909 safe_strncpy (directory, optarg, sizeof (directory));
916 if (chdir (directory))
917 perror_msg_and_die ("Invalid Directory");
919 if (ioctl (fd, FIONBIO, &on) < 0)
920 perror_msg_and_die ("ioctl(FIONBIO)");
922 /* daemonize this process */
927 // brcm save the pid in the file for kill.
929 if (!(pid_fp = fopen("/var/run/tftpd_pid", "w")))
931 printf("Error open /var/run/tftpd_pid");
934 fprintf(pid_fp, "%d\n", f);
939 perror_msg_and_die ("cannot fork");
946 result = tftpd_daemon ("", address, port);