]> git.karo-electronics.de Git - karo-tx-uboot.git/blobdiff - net/tftp.c
net: tftpput: Add support for receiving ICMP packets
[karo-tx-uboot.git] / net / tftp.c
index c0342a869d4777979cc867649e524c437a36c533..da8eeaa58de179195e1151f95361269859cc9101 100644 (file)
@@ -2,6 +2,8 @@
  * Copyright 1994, 1995, 2000 Neil Russell.
  * (See License)
  * Copyright 2000, 2001 DENX Software Engineering, Wolfgang Denk, wd@denx.de
+ * Copyright 2011 Comelit Group SpA,
+ *                Luca Ceresoli <luca.ceresoli@comelit.it>
  */
 
 #include <common.h>
@@ -58,9 +60,9 @@ enum {
        TFTP_ERR_FILE_ALREADY_EXISTS = 6,
 };
 
-static IPaddr_t TftpServerIP;
+static IPaddr_t TftpRemoteIP;
 /* The UDP port at their end */
-static int     TftpServerPort;
+static int     TftpRemotePort;
 /* The UDP port at our end */
 static int     TftpOurPort;
 static int     TftpTimeoutCount;
@@ -80,11 +82,12 @@ static int  TftpTsize;
 static short   TftpNumchars;
 #endif
 
-#define STATE_RRQ      1
+#define STATE_SEND_RRQ 1
 #define STATE_DATA     2
 #define STATE_TOO_LARGE        3
 #define STATE_BAD_MAGIC        4
 #define STATE_OACK     5
+#define STATE_RECV_WRQ 6
 
 /* default TFTP block size */
 #define TFTP_BLOCK_SIZE                512
@@ -125,8 +128,8 @@ static unsigned short TftpBlkSizeOption = TFTP_MTU_BLOCKSIZE;
 #define MTFTP_BITMAPSIZE       0x1000
 static unsigned *Bitmap;
 static int PrevBitmapHole, Mapsize = MTFTP_BITMAPSIZE;
-static uchar ProhibitMcast = 0, MasterClient = 0;
-static uchar Multicast = 0;
+static uchar ProhibitMcast, MasterClient;
+static uchar Multicast;
 extern IPaddr_t Mcast_addr;
 static int Mcast_port;
 static ulong TftpEndingBlock; /* can get 'last' block before done..*/
@@ -136,8 +139,10 @@ static void parse_multicast_oack(char *pkt, int len);
 static void
 mcast_cleanup(void)
 {
-       if (Mcast_addr) eth_mcast_join(Mcast_addr, 0);
-       if (Bitmap) free(Bitmap);
+       if (Mcast_addr)
+               eth_mcast_join(Mcast_addr, 0);
+       if (Bitmap)
+               free(Bitmap);
        Bitmap = NULL;
        Mcast_addr = Multicast = Mcast_port = 0;
        TftpEndingBlock = -1;
@@ -146,7 +151,7 @@ mcast_cleanup(void)
 #endif /* CONFIG_MCAST_TFTP */
 
 static __inline__ void
-store_block(unsigned block, uchar * src, unsigned len)
+store_block(unsigned block, uchar *src, unsigned len)
 {
        ulong offset = block * TftpBlkSize + TftpBlockWrapOffset;
        ulong newsize = offset + len;
@@ -193,9 +198,9 @@ static void TftpTimeout(void);
 static void
 TftpSend(void)
 {
-       volatile uchar *        pkt;
-       volatile uchar *        xp;
-       int                     len = 0;
+       volatile uchar *pkt;
+       volatile uchar *xp;
+       int             len = 0;
        volatile ushort *s;
 
 #ifdef CONFIG_MCAST_TFTP
@@ -213,7 +218,7 @@ TftpSend(void)
 
        switch (TftpState) {
 
-       case STATE_RRQ:
+       case STATE_SEND_RRQ:
                xp = pkt;
                s = (ushort *)pkt;
                *s++ = htons(TFTP_RRQ);
@@ -255,6 +260,8 @@ TftpSend(void)
                                                            (Mapsize*8), 0);
                /*..falling..*/
 #endif
+
+       case STATE_RECV_WRQ:
        case STATE_DATA:
                xp = pkt;
                s = (ushort *)pkt;
@@ -287,7 +294,7 @@ TftpSend(void)
                break;
        }
 
-       NetSendUDPPacket(NetServerEther, TftpServerIP, TftpServerPort,
+       NetSendUDPPacket(NetServerEther, TftpRemoteIP, TftpRemotePort,
                         TftpOurPort, len);
 }
 
@@ -305,15 +312,14 @@ TftpHandler(uchar *pkt, unsigned dest, IPaddr_t sip, unsigned src,
                if (Multicast
                 && (!Mcast_port || (dest != Mcast_port)))
 #endif
-               return;
+                       return;
        }
-       if (TftpState != STATE_RRQ && src != TftpServerPort) {
+       if (TftpState != STATE_SEND_RRQ && src != TftpRemotePort &&
+           TftpState != STATE_RECV_WRQ)
                return;
-       }
 
-       if (len < 2) {
+       if (len < 2)
                return;
-       }
        len -= 2;
        /* warning: don't use increment (++) in ntohs() macros!! */
        s = (ushort *)pkt;
@@ -322,37 +328,49 @@ TftpHandler(uchar *pkt, unsigned dest, IPaddr_t sip, unsigned src,
        switch (ntohs(proto)) {
 
        case TFTP_RRQ:
-       case TFTP_WRQ:
        case TFTP_ACK:
                break;
        default:
                break;
 
+#ifdef CONFIG_CMD_TFTPSRV
+       case TFTP_WRQ:
+               debug("Got WRQ\n");
+               TftpRemoteIP = sip;
+               TftpRemotePort = src;
+               TftpOurPort = 1024 + (get_timer(0) % 3072);
+               TftpLastBlock = 0;
+               TftpBlockWrap = 0;
+               TftpBlockWrapOffset = 0;
+               TftpSend(); /* Send ACK(0) */
+               break;
+#endif
+
        case TFTP_OACK:
                debug("Got OACK: %s %s\n",
                        pkt,
                        pkt + strlen((char *)pkt) + 1);
                TftpState = STATE_OACK;
-               TftpServerPort = src;
+               TftpRemotePort = src;
                /*
                 * Check for 'blksize' option.
                 * Careful: "i" is signed, "len" is unsigned, thus
                 * something like "len-8" may give a *huge* number
                 */
                for (i = 0; i+8 < len; i++) {
-                       if (strcmp((char*)pkt+i, "blksize") == 0) {
+                       if (strcmp((char *)pkt+i, "blksize") == 0) {
                                TftpBlkSize = (unsigned short)
-                                       simple_strtoul((char*)pkt+i+8, NULL,
+                                       simple_strtoul((char *)pkt+i+8, NULL,
                                                       10);
                                debug("Blocksize ack: %s, %d\n",
-                                       (char*)pkt+i+8, TftpBlkSize);
+                                       (char *)pkt+i+8, TftpBlkSize);
                        }
 #ifdef CONFIG_TFTP_TSIZE
-                       if (strcmp((char*)pkt+i, "tsize") == 0) {
-                               TftpTsize = simple_strtoul((char*)pkt+i+6,
+                       if (strcmp((char *)pkt+i, "tsize") == 0) {
+                               TftpTsize = simple_strtoul((char *)pkt+i+6,
                                                           NULL, 10);
                                debug("size = %s, %d\n",
-                                        (char*)pkt+i+6, TftpTsize);
+                                        (char *)pkt+i+6, TftpTsize);
                        }
 #endif
                }
@@ -393,20 +411,20 @@ TftpHandler(uchar *pkt, unsigned dest, IPaddr_t sip, unsigned src,
                }
 #endif
                else {
-                       if (((TftpBlock - 1) % 10) == 0) {
+                       if (((TftpBlock - 1) % 10) == 0)
                                putc('#');
-                       } else if ((TftpBlock % (10 * HASHES_PER_LINE)) == 0) {
+                       else if ((TftpBlock % (10 * HASHES_PER_LINE)) == 0)
                                puts("\n\t ");
-                       }
                }
 
-               if (TftpState == STATE_RRQ)
+               if (TftpState == STATE_SEND_RRQ)
                        debug("Server did not acknowledge timeout option!\n");
 
-               if (TftpState == STATE_RRQ || TftpState == STATE_OACK) {
+               if (TftpState == STATE_SEND_RRQ || TftpState == STATE_OACK ||
+                   TftpState == STATE_RECV_WRQ) {
                        /* first block received */
                        TftpState = STATE_DATA;
-                       TftpServerPort = src;
+                       TftpRemotePort = src;
                        TftpLastBlock = 0;
                        TftpBlockWrap = 0;
                        TftpBlockWrapOffset = 0;
@@ -440,8 +458,8 @@ TftpHandler(uchar *pkt, unsigned dest, IPaddr_t sip, unsigned src,
                store_block(TftpBlock - 1, pkt + 2, len);
 
                /*
-                *      Acknoledge the block just received, which will prompt
-                *      the server for the next one.
+                *      Acknowledge the block just received, which will prompt
+                *      the remote for the next one.
                 */
 #ifdef CONFIG_MCAST_TFTP
                /* if I am the MasterClient, actively calculate what my next
@@ -538,7 +556,8 @@ TftpTimeout(void)
        } else {
                puts("T ");
                NetSetTimeout(TftpTimeoutMSecs, TftpTimeout);
-               TftpSend();
+               if (TftpState != STATE_RECV_WRQ)
+                       TftpSend();
        }
 }
 
@@ -552,10 +571,12 @@ TftpStart(void)
         * Allow the user to choose TFTP blocksize and timeout.
         * TFTP protocol has a minimal timeout of 1 second.
         */
-       if ((ep = getenv("tftpblocksize")) != NULL)
+       ep = getenv("tftpblocksize");
+       if (ep != NULL)
                TftpBlkSizeOption = simple_strtol(ep, NULL, 10);
 
-       if ((ep = getenv("tftptimeout")) != NULL)
+       ep = getenv("tftptimeout");
+       if (ep != NULL)
                TftpTimeoutMSecs = simple_strtol(ep, NULL, 10);
 
        if (TftpTimeoutMSecs < 1000) {
@@ -568,7 +589,7 @@ TftpStart(void)
        debug("TFTP blocksize = %i, timeout = %ld ms\n",
                TftpBlkSizeOption, TftpTimeoutMSecs);
 
-       TftpServerIP = NetServerIP;
+       TftpRemoteIP = NetServerIP;
        if (BootFile[0] == '\0') {
                sprintf(default_filename, "%02lX%02lX%02lX%02lX.img",
                        NetOurIP & 0xFF,
@@ -588,25 +609,24 @@ TftpStart(void)
                        strncpy(tftp_filename, BootFile, MAX_LEN);
                        tftp_filename[MAX_LEN-1] = 0;
                } else {
-                       TftpServerIP = string_to_ip(BootFile);
+                       TftpRemoteIP = string_to_ip(BootFile);
                        strncpy(tftp_filename, p + 1, MAX_LEN);
                        tftp_filename[MAX_LEN-1] = 0;
                }
        }
 
-#if defined(CONFIG_NET_MULTI)
        printf("Using %s device\n", eth_get_name());
-#endif
        printf("TFTP from server %pI4"
-               "; our IP address is %pI4", &TftpServerIP, &NetOurIP);
+               "; our IP address is %pI4", &TftpRemoteIP, &NetOurIP);
 
        /* Check if we need to send across this subnet */
        if (NetOurGatewayIP && NetOurSubnetMask) {
-           IPaddr_t OurNet     = NetOurIP    & NetOurSubnetMask;
-           IPaddr_t ServerNet  = TftpServerIP & NetOurSubnetMask;
+               IPaddr_t OurNet = NetOurIP    & NetOurSubnetMask;
+               IPaddr_t RemoteNet      = TftpRemoteIP & NetOurSubnetMask;
 
-           if (OurNet != ServerNet)
-               printf("; sending through gateway %pI4", &NetOurGatewayIP);
+               if (OurNet != RemoteNet)
+                       printf("; sending through gateway %pI4",
+                              &NetOurGatewayIP);
        }
        putc('\n');
 
@@ -628,19 +648,19 @@ TftpStart(void)
        NetSetTimeout(TftpTimeoutMSecs, TftpTimeout);
        NetSetHandler(TftpHandler);
 
-       TftpServerPort = WELL_KNOWN_PORT;
+       TftpRemotePort = WELL_KNOWN_PORT;
        TftpTimeoutCount = 0;
-       TftpState = STATE_RRQ;
+       TftpState = STATE_SEND_RRQ;
        /* Use a pseudo-random port unless a specific port is set */
        TftpOurPort = 1024 + (get_timer(0) % 3072);
 
 #ifdef CONFIG_TFTP_PORT
-       if ((ep = getenv("tftpdstp")) != NULL) {
-               TftpServerPort = simple_strtol(ep, NULL, 10);
-       }
-       if ((ep = getenv("tftpsrcp")) != NULL) {
+       ep = getenv("tftpdstp");
+       if (ep != NULL)
+               TftpRemotePort = simple_strtol(ep, NULL, 10);
+       ep = getenv("tftpsrcp");
+       if (ep != NULL)
                TftpOurPort = simple_strtol(ep, NULL, 10);
-       }
 #endif
        TftpBlock = 0;
 
@@ -659,6 +679,38 @@ TftpStart(void)
        TftpSend();
 }
 
+#ifdef CONFIG_CMD_TFTPSRV
+void
+TftpStartServer(void)
+{
+       tftp_filename[0] = 0;
+
+       printf("Using %s device\n", eth_get_name());
+       printf("Listening for TFTP transfer on %pI4\n", &NetOurIP);
+       printf("Load address: 0x%lx\n", load_addr);
+
+       puts("Loading: *\b");
+
+       TftpTimeoutCountMax = TIMEOUT_COUNT;
+       TftpTimeoutCount = 0;
+       TftpTimeoutMSecs = TIMEOUT;
+       NetSetTimeout(TftpTimeoutMSecs, TftpTimeout);
+
+       /* Revert TftpBlkSize to dflt */
+       TftpBlkSize = TFTP_BLOCK_SIZE;
+       TftpBlock = 0;
+       TftpOurPort = WELL_KNOWN_PORT;
+
+#ifdef CONFIG_TFTP_TSIZE
+       TftpTsize = 0;
+       TftpNumchars = 0;
+#endif
+
+       TftpState = STATE_RECV_WRQ;
+       NetSetHandler(TftpHandler);
+}
+#endif /* CONFIG_CMD_TFTPSRV */
+
 #ifdef CONFIG_MCAST_TFTP
 /* Credits: atftp project.
  */
@@ -704,7 +756,8 @@ static void parse_multicast_oack(char *pkt, int len)
                        }
                }
        }
-       if (!port || !mc_adr || !mc) return;
+       if (!port || !mc_adr || !mc)
+               return;
        if (Multicast && MasterClient) {
                printf("I got a OACK as master Client, WRONG!\n");
                return;
@@ -721,7 +774,8 @@ static void parse_multicast_oack(char *pkt, int len)
                /* I malloc instead of pre-declare; so that if the file ends
                 * up being too big for this bitmap I can retry
                 */
-               if (!(Bitmap = malloc(Mapsize))) {
+               Bitmap = malloc(Mapsize);
+               if (!Bitmap) {
                        printf("No Bitmap, no multicast. Sorry.\n");
                        ProhibitMcast = 1;
                        return;
@@ -734,7 +788,8 @@ static void parse_multicast_oack(char *pkt, int len)
        if (Mcast_addr != addr) {
                if (Mcast_addr)
                        eth_mcast_join(Mcast_addr, 0);
-               if (eth_mcast_join(Mcast_addr = addr, 1)) {
+               Mcast_addr = addr;
+               if (eth_mcast_join(Mcast_addr, 1)) {
                        printf("Fail to set mcast, revert to TFTP\n");
                        ProhibitMcast = 1;
                        mcast_cleanup();