tech-net archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Re: tftp protocol



On Fri, Oct 16, 2009 at 10:56:55PM +0200, Havard Eidnes wrote:
> Actually...  I suspect that the BUGS statement is in actual fact
> wrong, if it implies that the protocol spec makes it impossible
> to transfer files larger than 32MiB using tftp with the default
> block size of 512 bytes.  I've experienced that same problem,
> when trying to tftp updates for Cisco wireless controllers, which
> also have image files larger than 32MiB.
> 
> Cisco's "fix" for this problem is to point to a particular
> implementation of tftp daemon functionality in the form of a
> Windows program (yuk!) (and, yes, the source is available as
> well, but it has Windows-specific code littering the code, if I
> recall correctly).  The tftp client in the Cisco case uses the
> default block size of 512 bytes, and with this combination, it
> can actually transfer the wireless controller image file.
> 
> The "block numbers" in the tftp protocol are actually not
> designed to do "random access" in the server-side file, it's
> designed to distinguish between duplicate blocks and new blocks
> at the client.  If the client and server implements a 0.5 * 2^16
> "block number window", and they allow the block number to wrap
> around the 2^16 mark, it may actually work to transfer files
> larger than 32MiB without increasing the block size above the
> default 512 bytes.
> 
> The RFCs specifying the block size extension mention speed as a
> motivation for the extension, not the ability to transfer files
> larger than 32MiB...
> 
> I've not actually had the time to sit down to see if a patch
> could be made to the NetBSD tftp daemon (and client) to allow
> such operation.

FWIW, we had to fix a similar issue to tftp a large file from
the windows vista installation. Konstantin Kabassavov came up
with the attached patch; I didn't check it in details.
It also handle '\' vs '/'. 

-- 
Manuel Bouyer <bouyer%antioche.eu.org@localhost>
     NetBSD: 26 ans d'experience feront toujours la difference
--
Index: tftpd.c
===================================================================
RCS file: /cvsroot/src/libexec/tftpd/tftpd.c,v
retrieving revision 1.31
diff -u -p -u -r1.31 tftpd.c
--- tftpd.c     21 Jul 2008 13:25:47 -0000      1.31
+++ tftpd.c     17 Oct 2009 15:48:33 -0000
@@ -607,7 +607,7 @@ static void
 tftp(struct tftphdr *tp, int size)
 {
        struct formats *pf;
-       char    *cp;
+       char    *cp,*i;
        char    *filename, *mode;
        int      first, ecode, alen, etftp=0, r;
 
@@ -617,6 +617,15 @@ tftp(struct tftphdr *tp, int size)
 
        filename = cp = tp->th_stuff;
 again:
+        // KKK
+        i = cp;
+        while (i < buf + size) {
+                if (*i == 0x5c) {
+                        *i='/';
+                }
+                i++;
+        }
+
        while (cp < buf + size) {
                if (*cp == '\0')
                        break;
@@ -864,10 +873,11 @@ opcode(int code)
 void
 sendfile(struct formats *pf, int etftp, int acklength)
 {
+       volatile unsigned int blocktimes=0;
        volatile unsigned int block;
        struct tftphdr  *dp;
        struct tftphdr  *ap;    /* ack packet */
-       int              size, n;
+       int              size, n,blocktimescandidate=0;
 
        signal(SIGALRM, timer);
        ap = (struct tftphdr *)ackbuf;
@@ -918,20 +928,25 @@ send_data:
                                goto abort;
 
                        case ACK:
-                               if (ap->th_block == 0) {
+                               if ((ap->th_block == 0) && (blocktimes == 0) && 
(blocktimescandidate == 0)) { 
                                        etftp = 0;
                                        acklength = 0;
                                        dp = r_init();
                                        goto done;
                                }
-                               if (ap->th_block == block)
+                               if ((ap->th_block + (blocktimes*65536)) == 
block)
                                        goto done;
+                               if ((ap->th_block + ((blocktimes+1)*65536)) == 
block){
+                                       blocktimes++;
+                                       goto done;
+                                }
+
                                if (debug)
                                        syslog(LOG_DEBUG, "Resync ACK %u != %u",
                                            (unsigned int)ap->th_block, block);
                                /* Re-synchronize with the other side */
                                (void) synchnet(peer, tftp_blksize);
-                               if (ap->th_block == (block -1))
+                               if ((ap->th_block  + (blocktimes*65536)) == 
(block -1))
                                        goto send_data;
                        default:
                                syslog(LOG_INFO, "Received %s in sendfile\n",
@@ -943,6 +958,9 @@ done:
                if (debug)
                        syslog(LOG_DEBUG, "Received ACK for block %u", block);
                block++;
+                if (block == 65536)
+                  blocktimescandidate = 1;
+
        } while (size == tftp_blksize || block == 1);
 abort:
        (void) fclose(file);


Home | Main Index | Thread Index | Old Index