www.usr.com/support/gpl/USR9107_release.1.4.tar.gz
[bcm963xx.git] / userapps / opensource / busybox / networking / tftpd.c
1 /* 
2  * $Id$
3  * A simple tftpd server for busybox
4  *
5  * Copyright (C) 2001 Steven Carr <Steven_Carr@yahoo.com>
6  *
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.
11  *
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.
16  *
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.
21  *
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
25  */
26
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <sys/types.h>
31 #include <sys/socket.h>
32 #include <sys/time.h>
33 #include <sys/stat.h>
34 #include <netdb.h>
35 #include <syslog.h>
36 #include <netinet/in.h>
37 #include <arpa/inet.h>
38 #include <arpa/tftp.h>
39 #include <unistd.h>
40 #include <fcntl.h>
41 #include <ctype.h>
42 #include <asm/ioctls.h>
43 #include <sys/ioctl.h>
44 #include <signal.h>
45 #include <errno.h>
46
47 // Keven Kuo
48 #include <config.h>
49 #ifdef HAVE_ASM_SOCKET_H
50 #include <asm/socket.h>
51 #endif
52 #ifdef HAVE_WAIT_H
53 # include <wait.h>
54 #else
55 # ifdef HAVE_SYS_WAIT_H
56 #  include <sys/wait.h>
57 # endif
58 #endif
59
60 #include "busybox.h"
61
62 // Keven Kuo
63 #define DAEMONIZE
64
65 #ifndef OACK
66 #define OACK 6
67 #endif
68 #ifndef EOPTNEG
69 #define EOPTNEG 8
70 #endif
71
72 #define ENOPUT -2
73 #define ENOGET -3
74
75 #if !defined(__UCLIBC__) || defined(__UCLIBC_HAS_MMU__)
76 #define FORK() fork()
77 #else
78 #define FORK() vfork()
79 #endif
80
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"
85 #include "bcmTag.h"
86 extern UPLOAD_RESULT verifyTag(PFILE_TAG pTag, int passNumber);
87 #define DUP_PKT_CHECK_COUNT      3
88 //Enable put only
89 //#define CONFIG_FEATURE_TFTPD_GET
90 #define CONFIG_FEATURE_TFTPD_PUT
91 extern char glbIfName[];
92 void perror_msg_and_die(char *);
93
94 void perror_msg_and_die(char * msg)
95 {
96     printf("%s\n", msg);
97     exit(-1);
98 }
99
100 // if applications are killed, reset the modem.
101 int myExit(int fNeedReset, int peer)
102 {
103     close(peer);
104     if (fNeedReset)
105         sysMipsSoftReset();
106     exit(0);
107 }
108
109 // brcm end
110 /*
111  * Handle initial connection protocol.
112  *     +-------+---~~---+---+---~~---+---+---~~---+---+---~~---+---+-->  >-------+---+---~~---+---+
113  *     |  opc  |filename| 0 |  mode  | 0 |  opt1  | 0 | value1 | 0 | <  <  optN  | 0 | valueN | 0 |
114  *     +-------+---~~---+---+---~~---+---+---~~---+---+---~~---+---+-->  >-------+---+---~~---+---+
115  *             ^--->
116  */
117
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)
120 {
121   int x;
122   int y;
123   argv[0] = options;
124   for (y = 1, x = 0; (y < max_arg) && (x < (opt_len - 1)); x++)
125     {
126       if (options[x] == 0)
127         {
128           if (options[x + 1] == 0)
129             return y;
130           argv[y] = &options[x + 1];
131           y++;
132         }
133     }
134   return y;
135 }
136
137
138 /*
139  * Send a nak packet (error message).
140  * Error code passed in is one of the
141  * standard TFTP codes, or a UNIX errno
142  * offset by 100.
143  */
144 void tftpd_nak (int peer, int error)
145 {
146   char buf[TFTP_BLOCKSIZE_DEFAULT + 4];
147   struct tftphdr *pkt;
148
149   pkt = (struct tftphdr *) buf;
150   pkt->th_opcode = htons ((u_short) ERROR);
151   pkt->th_code = htons ((u_short) error);
152
153   switch (error)
154     {
155     case ENOPUT:
156       strcpy (pkt->th_msg, "Put not supported");
157       pkt->th_code = htons (EUNDEF);
158       break;
159     case ENOGET:
160       strcpy (pkt->th_msg, "Get not supported");
161       pkt->th_code = htons (EUNDEF);
162       break;
163     case EUNDEF:
164       strcpy (pkt->th_msg, "Undefined error code");
165       break;
166     case ENOTFOUND:
167       strcpy (pkt->th_msg, "File not found");
168       break;
169     case EACCESS:
170       strcpy (pkt->th_msg, "Access violation");
171       break;
172     case ENOSPACE:
173       strcpy (pkt->th_msg, "Disk full or allocation exceeded");
174       break;
175     case EBADOP:
176       strcpy (pkt->th_msg, "Illegal TFTP operation");
177       break;
178     case EBADID:
179       strcpy (pkt->th_msg, "Unknown transfer ID");
180       break;
181     case EEXISTS:
182       strcpy (pkt->th_msg, "File already exists");
183       break;
184     case ENOUSER:
185       strcpy (pkt->th_msg, "No such user");
186       break;
187     case EOPTNEG:
188       strcpy (pkt->th_msg, "Failure to negotiate RFC2347 options");
189       break;
190     default:
191       strcpy (pkt->th_msg, strerror (error - 100));
192       pkt->th_code = htons (EUNDEF);
193       break;
194     }
195
196   send (peer, buf, strlen (pkt->th_msg) + 5, 0);
197 }
198
199 /*
200  * Send a ack packet 
201  */
202 void tftpd_ack (int peer, int block)
203 {
204   struct tftphdr pkt;
205
206   pkt.th_opcode = htons (ACK);
207   pkt.th_block = htons (block);
208
209   if (send (peer, &pkt, sizeof(pkt), 0)!=sizeof(pkt))
210         perror_msg_and_die("tftpd_ack send");
211 }
212
213
214 /*
215  * send an oack
216  */
217 void tftpd_oack (int peer, int count, char **list)
218 {
219   char buf[TFTP_BLOCKSIZE_DEFAULT + 4];
220   struct tftphdr *pkt;
221   int x;
222   char *ptr;
223
224   pkt=(struct tftphdr *)buf;
225   pkt->th_opcode = htons (OACK);
226   ptr=pkt->th_stuff;
227   
228   for (x=0;x<count;x++)
229          ptr=strrchr (strcpy (ptr, list[x]), '\0') + 1;
230
231  if ( send (peer, buf, (ptr-buf), 0)!=(ptr-buf))
232         perror_msg_and_die("tftpd_oack send");
233 }
234
235
236 /*
237  * send data
238  */
239 void tftpd_data (int peer, int block, char *data, int size)
240 {
241   struct tftphdr *pkt;
242   char buf[TFTP_BLOCKSIZE_DEFAULT + 4];
243
244   pkt=(struct tftphdr *)buf;
245   pkt->th_opcode = htons (DATA);
246   pkt->th_block  = htons(block);
247   
248   memcpy(pkt->th_data,data,size);
249
250   if (send (peer, &buf, size+4, 0)!=(size+4))
251         perror_msg_and_die("tftpd_data send");
252 }
253
254 int tftpd_getdata(int peer, int block, char *data, int size, int fNeedReset)
255 {
256   struct tftphdr *pkt;
257   struct timeval tv;
258   fd_set rfds;
259   int len=-1;
260   int timeout_counter = 4;
261   
262   pkt=(struct tftphdr *)data;
263   
264   do {  
265       tv.tv_sec = TFTP_TIMEOUT;
266       tv.tv_usec = 0;
267       FD_ZERO (&rfds);
268       FD_SET (peer, &rfds);
269       switch (select (FD_SETSIZE, &rfds, NULL, NULL, &tv))
270         {
271         case 1:         /* data ready */
272           len = recv (peer, data, size, 0);
273           if (len < 0)
274             perror_msg_and_die ("failed to read (data)");
275
276           pkt->th_opcode = ntohs (pkt->th_opcode);
277           pkt->th_block = ntohs (pkt->th_block);
278           if (pkt->th_opcode == ERROR)
279             {
280               bb_error_msg (pkt->th_data);
281               myExit(fNeedReset, peer);
282             }
283           if ((pkt->th_opcode == DATA) && (pkt->th_block != block))
284             {
285               //synchronize (peer);
286             }
287           break;
288         case 0:         /* timeout */
289           timeout_counter--;
290           if (timeout_counter == 0)
291             {
292               bb_error_msg ("last timeout");
293               myExit(fNeedReset, peer);
294             }
295           break;
296         default:                /* error */
297           perror_msg_and_die ("select failed");
298           break;
299         }
300    }while (!(pkt->th_opcode == DATA) && (pkt->th_block == block));
301    return len;
302 }
303
304
305
306 int tftpd_getack(int peer, int block)
307 {
308   char data[TFTP_BLOCKSIZE_DEFAULT + 4];
309   struct tftphdr *pkt;
310   struct timeval tv;
311   fd_set rfds;
312   int timeout_counter = 4;
313   int len;
314   
315   pkt=(struct tftphdr *)data;
316
317   do {  
318       tv.tv_sec = TFTP_TIMEOUT;
319       tv.tv_usec = 0;
320       FD_ZERO (&rfds);
321       FD_SET (peer, &rfds);
322       switch (select (FD_SETSIZE, &rfds, NULL, NULL, &tv))
323         {
324         case 1:         /* data ready */
325
326           len = recv (peer, data, TFTP_BLOCKSIZE_DEFAULT + 4, 0);
327           if (len < 0)
328             perror_msg_and_die ("failed to read (data)");
329
330           pkt->th_opcode = ntohs (pkt->th_opcode);
331           pkt->th_block = ntohs (pkt->th_block);
332
333           if (pkt->th_opcode == ERROR)
334             {
335               bb_error_msg (pkt->th_data);
336               exit (0);
337             }
338
339           if ((pkt->th_opcode == ACK) && (pkt->th_block != block))
340             {
341               //synchronize (peer);
342             }
343           break;
344         case 0:         /* timeout */
345           timeout_counter--;
346           if (timeout_counter == 0)
347             {
348               bb_error_msg ("last timeout");
349               exit (0);
350             }
351           break;
352         default:                /* error */
353           perror_msg_and_die ("select failed");
354           break;
355         }
356    }while (! ((pkt->th_opcode == ACK) && (pkt->th_block == block)) );
357
358   return (1==1);
359 }
360
361
362
363
364
365 #ifndef CONFIG_FEATURE_TFTPD_GET
366 void
367 tftpd_send (int peer, struct tftphdr *tp, int n, int buffersize)
368 {
369         /* we aren't configured for sending files */
370         tftpd_nak (peer, ENOGET);
371         close (peer);
372         exit(0);
373 }
374
375 #else
376 void
377 tftpd_send (int peer, struct tftphdr *first_pkt, int pkt_len, int buffersize)
378 {
379         FILE *file=NULL;
380         char buffer[TFTP_BLOCKSIZE_DEFAULT+4];
381         char *list[64]; /* list of pointers to options and values */
382         int listcount;
383         char *reply_list[64];
384         int reply_listcount=0;
385         char tsize_ret[32];
386         int block, inbytes, x;
387         
388         listcount = tftpd_options (first_pkt->th_stuff, pkt_len, list ,64);
389
390         /* get the size of the file (remember, chroot() supposed to point us in the right directory) */
391
392         if (strcasecmp(list[1],"octet")!=0)
393         {
394                 tftpd_nak(peer,EBADOP);
395                 close(peer);
396                 exit(0);
397         }
398
399
400         file = fopen (list[0], "r");
401         if (file == NULL)
402         {
403           tftpd_nak (peer, ENOTFOUND);
404           close(peer);
405           exit(0);
406         }
407         fseek (file, 0, SEEK_END);
408         sprintf(tsize_ret,"%lu", ftell (file));
409         fseek (file, 0, SEEK_SET);
410
411
412         /* 0=filename, 1=mode, 2=option, 3=option_value ... */
413         block = 1;
414         reply_listcount=0;
415
416         /* look through the options for the ones we support */
417         for (x=2;x<listcount;x++)
418         {
419                 if (strcasecmp(list[x],"tsize")==0) /* only one option supported so far */
420                 {
421                         reply_list[reply_listcount]=list[x];            
422                         reply_listcount++;
423                         reply_list[reply_listcount]=tsize_ret; /* point to the real value */
424                         reply_listcount++;
425                 }
426         }
427
428         /* if there are any options, send an OACK instead of an ACK */
429         if (reply_listcount>0)
430         {
431                 do
432                 {
433                         tftpd_oack(peer,reply_listcount,reply_list);
434                 }
435                 while (!tftpd_getack(peer,0));
436         }       
437
438
439         /* Send the file! */
440         while ((inbytes = fread(buffer,1,TFTP_BLOCKSIZE_DEFAULT,file))>0)
441         {
442                 do
443                 {
444                         tftpd_data(peer,block,buffer,inbytes);
445                 }
446                 while (!tftpd_getack(peer,block));
447                 block++;
448         }
449         fclose(file);
450         close(peer);
451         exit (0);
452 }
453
454 #endif
455
456
457 #ifndef CONFIG_FEATURE_TFTPD_PUT
458 void
459 tftpd_receive (int peer, struct tftphdr *tp, int n, int buffersize)
460 {
461         /* we aren't configured for receiving files */
462         tftpd_nak (peer, ENOPUT);
463         close (peer);
464         exit(0);
465 }
466
467 #else
468 void
469 //brcm begin
470 tftpd_receive (int peer, struct tftphdr *first_pkt, int pkt_len, int buffersize)
471 {
472 // brcm FILE *file=NULL;
473         char buffer[TFTP_BLOCKSIZE_DEFAULT+4];
474         struct tftphdr *pkt;
475         int block, inbytes;
476         char *list[64];
477         int listcount;
478
479     //brcm begin
480     PARSE_RESULT imageType = NO_IMAGE_FORMAT;
481     int byteRd = 0;
482     char tag[TAG_LEN];
483     int tagSize = 0;
484     int size = 0;
485     char *curPtr = NULL;
486     unsigned int totalAllocatedSize = 0;
487     int socketPid = 0;
488     int fNeedReset = FALSE;
489          char *imagePtr = NULL;
490     int uploadSize = 0;
491     int i = 0;   
492
493 //printf("tftpd_receive, peer = %d, pkt_len = %d, buffersize=%d\n", peer, pkt_len, buffersize);
494
495         pkt=(struct tftphdr *)buffer;
496         listcount = tftpd_options (first_pkt->th_stuff, pkt_len, list ,64);
497
498         /* get the size of the file (remember, chroot() supposed to point us in the right directory) */
499
500 //printf ("mode= %s, file= %s\n", list[1], list[0]);    
501     if (strcasecmp(list[1],"octet")!=0)
502         {
503         printf("Only support 'bin' mode. Type 'bin' at tftp client\n");
504                 tftpd_nak(peer,EBADOP);
505                 close(peer);
506                 exit(0);
507         }
508
509 #if 0//brcm
510     file = fopen (list[0], "w");
511         if (file == NULL)
512         {
513           tftpd_nak (peer, EACCESS);
514           close(peer);
515           exit(0);
516         }
517 #endif //brcm
518
519     block=0;
520
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");
525     fNeedReset = TRUE;
526
527         do
528         {
529                 tftpd_ack(peer,block);
530                 block++;
531
532       // if duplicate pkt, (for slow ack on 38R board) discard it.
533       for (i = 0; i < DUP_PKT_CHECK_COUNT; i++)
534       {
535          inbytes=tftpd_getdata(peer,block,buffer,TFTP_BLOCKSIZE_DEFAULT+4, fNeedReset);
536          if (block == (int) (*(short*)(buffer+2)))
537             break;
538       }
539                 // brcm fwrite(pkt->th_msg,1,inbytes-4,file);
540         byteRd=inbytes-4;
541         // brcm begin
542         if (curPtr == NULL) 
543         {
544             if (byteRd < TFTP_BLOCKSIZE_DEFAULT)   // not enough data for a valid first packet and exit
545             {
546                 uploadSize = byteRd;
547                 break;
548             }
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
552             // allocate.
553             if( tagSize + byteRd > TAG_LEN)
554                 size = TAG_LEN - tagSize;
555             else 
556                 size = byteRd;
557
558             memcpy(tag + tagSize, pkt->th_msg, size);
559             tagSize += size;
560             byteRd -= size;
561             if( tagSize == TAG_LEN ) 
562             {
563                 PFILE_TAG pTag = (PFILE_TAG) tag;
564
565                 if (verifyTag(pTag, 1) == UPLOAD_OK) 
566                 {
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);
575                     if (curPtr == NULL) 
576                     {
577                         printf("Not enough memory error.");       
578                         myExit(fNeedReset, peer);
579                     }
580                     else 
581                     {
582                         printf("Memory allocated\n");
583                         imagePtr = curPtr;
584                         memcpy(curPtr, tag, TAG_LEN);
585                         curPtr += TAG_LEN;
586                         uploadSize += TAG_LEN;
587                         memcpy(curPtr, pkt->th_msg + size, byteRd);
588                         curPtr += byteRd;
589                     }
590                 }
591                 // try to allocate the memory for .w image, same as flash size + some overhead
592                 else 
593                 {   
594                     totalAllocatedSize = sysFlashSizeGet() + TOKEN_LEN;
595                     printf("Allocating %d bytes for flash image.\n", totalAllocatedSize);
596                     curPtr = (char *) malloc(totalAllocatedSize);
597                     if(curPtr == NULL) 
598                     {
599                         printf("Not enough memory error.");       
600                         myExit(fNeedReset, peer);
601                     }
602                     else 
603                     {
604                         printf("Memory allocated\n");
605                         imagePtr = curPtr;
606                         byteRd += TAG_LEN;          // add back the tag size
607                         memcpy(curPtr, pkt->th_msg, byteRd);
608                         curPtr += byteRd;
609                     }
610                 }  // else alloc memory for .w image
611             } //tagSize == TAG_LEN
612         } // if curPtr == NULL
613         else 
614         { // not first block of data
615             memcpy(curPtr, pkt->th_msg, byteRd);
616             curPtr += byteRd;
617         }
618         
619         uploadSize += byteRd;
620 //printf("Current uploadSize= %d\n", uploadSize);
621         if (uploadSize > totalAllocatedSize) // try not to over flow the pkt->th_msg
622         {       
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);
626         }
627         // brcm end
628         }
629         while (inbytes==(TFTP_BLOCKSIZE_DEFAULT+4));
630
631     tftpd_ack(peer,block); /* final acknowledge */
632
633 // brcm fclose(file);
634
635     printf("Total size: %d\n", uploadSize);
636
637     if ((imagePtr != NULL) && 
638         ((imageType = parseImageData(imagePtr, uploadSize, BUF_ALL_TYPES)) != NO_IMAGE_FORMAT)) 
639     {
640         printf("Tftp image done.\n");
641         flashImage(imagePtr, imageType, uploadSize);
642         if (imagePtr)
643                 free(imagePtr);
644     }
645     else 
646         printf("Tftp Image failed: Illegal image.\n");
647
648     // no reset if psi update (need httpd to process xml file)
649     if (imageType == PSI_IMAGE_FORMAT)
650         fNeedReset=FALSE;
651     myExit(fNeedReset, peer);
652 }
653 // brcm end
654 #endif
655
656 static struct in_addr getLanIp(void) //struct in_addr *lan_ip)
657 {
658    int socketfd;
659    struct ifreq lan;
660
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");
664    }
665    else  {
666         strcpy(lan.ifr_name, "br0");
667         if (ioctl(socketfd,SIOCGIFADDR,&lan) < 0) {
668             printf("Error getting LAN IP address\n");
669         }
670    }
671    close(socketfd);
672    return ((struct sockaddr_in *)&(lan.ifr_addr))->sin_addr;
673 }
674
675 // brcm -- from igmp
676 #include <bits/socket.h>
677 #include <sys/uio.h>
678 #define MAXCTRLSIZE                                             \
679         (sizeof(struct cmsghdr) + sizeof(struct sockaddr_in) +  \
680         sizeof(struct cmsghdr) + sizeof(int) + 32)
681 // brmc end
682
683 static int
684 tftpd_daemon (char *directory, char *address, int port)
685 {
686   struct tftphdr *tp;
687   struct sockaddr_in from;
688   struct sockaddr_in myaddr;
689   struct sockaddr_in bindaddr;
690   int fd = -1;
691   int peer;
692   int rv;
693   int n;
694   pid_t pid;
695   int i = 1;
696
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;
703
704 #ifdef DAEMONIZE
705     daemon(0,1);
706 #endif
707
708   if ((fd = socket (PF_INET, SOCK_DGRAM, 0)) < 0)
709     perror_msg_and_die ("socket");
710
711   // Keven Kuo -- no need for inetd
712 #ifdef DAEMONIZE
713   // set option for getting the to ip address.
714   setsockopt(fd, IPPROTO_IP, IP_PKTINFO, &i, sizeof(i)); 
715 #else
716   #ifdef SO_REUSEADDR
717   setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void *) &i, sizeof(i));
718   #endif
719   #ifdef SO_REUSEPORT
720   setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, (void *) &i, sizeof(i));
721   #endif
722 #endif
723   memset (&bindaddr, 0, sizeof (bindaddr));
724   bindaddr.sin_family = AF_INET;
725   bindaddr.sin_port = htons (port);
726   if (address != NULL)
727   {
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);
733   }
734
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);
739
740   // get pid for web access function to start/stop tftpd.
741 #ifdef DAEMONIZE
742   {
743     FILE *pid_fp;
744     if (!(pid_fp = fopen("/var/run/tftpd_pid", "w"))) 
745     {
746         printf("Error open /var/run/tftpd_pid");
747         exit(0);
748     }
749     fprintf(pid_fp, "%d\n", getpid());
750     fclose(pid_fp);
751   }
752 #endif
753
754 #ifdef DAEMONIZE
755   while (1)
756 #endif
757   {
758       fd_set readset;
759       memset(buf,0,TFTP_BLOCKSIZE_DEFAULT + 4);
760       memset (&myaddr, 0, sizeof (myaddr));
761       FD_ZERO (&readset);
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)
766         // Keven Kuo
767 #ifdef DAEMONIZE
768         continue;               /* Signal caught, reloop */
769 #else
770         exit (0);
771 #endif
772       if (rv == -1)
773         perror_msg_and_die ("select loop");
774       if (rv == 0)
775       {
776           bb_error_msg ("We shouldn't be timeing out!");
777           exit (0);             /* Timeout, return to inetd */
778       }
779
780       n = recvmsg (fd, &msg, MSG_WAITALL);
781       if (n <= 0)
782       {
783           if (n == 0)  /* Keven -- Received message with zero length, reloop */
784             // Keven Kuo
785 #ifdef DAEMONIZE
786             continue;
787 #else
788             exit (0);
789 #endif
790           else {        
791             printf("*** error recvmsg n=%d\n", n);
792             // Keven Kuo
793 #ifdef DAEMONIZE
794             break;
795 #else
796             exit (0);
797 #endif
798           }
799       }
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);
803             break;
804           }
805       }
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();
810
811 #ifdef DAEMONIZE
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);
814
815           /* Now that we have read the request packet from the UDP
816              socket, we fork and go back to listening to the socket. */
817           pid = FORK ();
818
819           if (pid < 0)
820               perror_msg_and_die ("cannot fork");
821           if (pid == 0)
822               break;
823           /* Child exits the while(1), parent continues to loop */
824 #endif
825   }
826
827   /* Close file descriptors we don't need */
828   // brcm close (fd);
829
830   /* Get a socket.  This has to be done before the chroot() (/dev goes away) */
831   peer = socket (AF_INET, SOCK_DGRAM, 0);
832   if (peer < 0)
833     perror_msg_and_die ("socket");
834   if (chroot ("."))
835     perror_msg_and_die ("chroot");
836   from.sin_family = AF_INET;
837
838   /* Process the request */
839   if (bind (peer, (struct sockaddr *) &myaddr, sizeof myaddr) < 0)
840     perror_msg_and_die ("daemon-child bind");
841
842   if (connect (peer, (struct sockaddr *) &from, sizeof from) < 0)
843     perror_msg_and_die ("daemon-child connect");
844
845   tp = (struct tftphdr *) buf;
846
847   int accessMode = bcmCheckEnable("tftp", from.sin_addr);
848
849   if (accessMode == CLI_ACCESS_DISABLED) 
850   {
851     close(peer);
852     exit(0);
853   }
854   if (accessMode == CLI_ACCESS_REMOTE) 
855   {
856     glbIfName[0] = '\0';
857     if ((bcmGetIntfNameSocket(peer, glbIfName) != 0) || glbIfName[0] == '\0') 
858     {
859       printf("Failed to get remote ifc name!\n");
860       close(peer);
861       exit(0);
862     }
863   }
864   
865   tp->th_opcode = ntohs (tp->th_opcode);
866
867   switch(tp->th_opcode)
868   {
869         case RRQ:
870             tftpd_send (peer, tp, n, TFTP_BLOCKSIZE_DEFAULT);
871             break;
872         case WRQ:
873             tftpd_receive (peer, tp, n, TFTP_BLOCKSIZE_DEFAULT);
874             break;
875   }
876   exit (0);
877 }
878
879 int
880 tftpd_main (int argc, char **argv)
881 {
882   int result;
883   char *address = NULL;         /* address to listen to */
884   int port = 69;
885   int daemonize = 1;            // brcm (1 == 0);
886
887 #if 0 //brcm  
888   int on = 1;
889   int fd = 0;
890   int opt;  
891   char directory[256];          /* default directory "/tftpboot/" */
892   memset (directory, 0, sizeof (directory));
893   strcpy (directory, "/tftpboot/");
894
895   while ((opt = getopt (argc, argv, "sp:a:d:h")) != -1)
896     {
897       switch (opt)
898         {
899         case 'p':
900           port = atoi (optarg);
901           break;
902         case 'a':
903           address = optarg;
904           break;
905         case 's':
906           daemonize = (1 == 1);
907           break;
908         case 'd':
909           safe_strncpy (directory, optarg, sizeof (directory));
910           break;
911         case 'h':
912           show_usage ();
913           break;
914         }
915     }
916   if (chdir (directory))
917     perror_msg_and_die ("Invalid Directory");
918
919   if (ioctl (fd, FIONBIO, &on) < 0)
920     perror_msg_and_die ("ioctl(FIONBIO)");
921
922   /* daemonize this process */
923   if (daemonize)
924   {
925       pid_t f = FORK ();
926       if (f > 0) {
927         // brcm save the pid in the file for kill.
928         FILE *pid_fp;
929         if (!(pid_fp = fopen("/var/run/tftpd_pid", "w"))) 
930         {
931             printf("Error open /var/run/tftpd_pid");
932             exit(0);
933         }
934         fprintf(pid_fp, "%d\n", f);
935         fclose(pid_fp);
936         exit (0);
937       }
938       if (f < 0)
939         perror_msg_and_die ("cannot fork");
940       close (0);
941       close (1);
942       close (2);
943   }
944 #endif //brcm
945
946   result = tftpd_daemon ("", address, port);
947   return (result);
948 }
949