让uboot的tftp支持上传功能

转载:http://blog.chinaunix.net/uid-20737871-id-2124122.html

 

uboot下的tftp下载功能是非常重要和常见的功能。但是偶尔有些特殊需求的人需要使用uboot的tftp具有上传功能。
默认的uboot没有tftp上传功能,如果需要修改uboot代码。
使用时键入第4个参数,则不同于3个参数的tftp下载功能。
#tftp 50400000 xx.bin 10000
TFTP to server 192.168.0.30; our IP address is 192.168.0.152
Upload Filename 'xx.bin'.
Upload from address: 0x50400000, 0.064 MB to be send ...
Uploading: %#   [ Connected ]

         0.064 MB upload ok.
这条命令将板子上0x50400000 开始,长度0x10000的数据上传到远程tftp服务器,命名为xx.bin

这个修改在uboot1.3.4和2008.10版本上测试通过。
1、修改common/cmd_net.c
注释掉

    /*
    int do_tftpb (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
    {
        return netboot_common (TFTP, cmdtp, argc, argv);
    }
    U_BOOT_CMD(
        tftpboot,    3,    1,    do_tftpb,
        "tftpboot- boot image via network using TFTP protocol\n",
        "[loadAddress] [[hostIPaddr:]bootfilename]\n"
    );
    */

 

可以看出默认uboot执行tftp命令其实调用的是tftpboot,uboot果然是看命名的前面几个字母而不是全名。例如print命令只需要键入pri。
接着添加
    int do_tftp (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
    {
        return netboot_common (TFTP, cmdtp, argc, argv);
    }
    U_BOOT_CMD(
        tftp,    4,    1,    do_tftp,
        "tftp\t- download or upload image via network using TFTP protocol\n",
        "[loadAddress] [bootfilename] <upload_size>\n"
    );

 

然后修改netboot_common成如下代码
    static int
    netboot_common (proto_t proto, cmd_tbl_t *cmdtp, int argc, char *argv[])
    {
        extern ulong upload_addr;
        extern ulong upload_size;
        char *s;
        int rcode = 0;
        int size;
        /* pre-set load_addr */
        if ((s = getenv("loadaddr")) != NULL) {
            load_addr = simple_strtoul(s, NULL, 16);
        }
        switch (argc) {
        case 1:
            break;
        case 2:    /* only one arg - accept two forms:
             * just load address, or just boot file name.
             * The latter form must be written "filename" here.
             */
            if (argv[1][0] == '"') {    /* just boot filename */
                copy_filename (BootFile, argv[1], sizeof(BootFile));
            } else {            /* load address    */
                load_addr = simple_strtoul(argv[1], NULL, 16);
            }
            break;
        case 3:    load_addr = simple_strtoul(argv[1], NULL, 16);
            copy_filename (BootFile, argv[2], sizeof(BootFile));
            upload_size = 0;
            
            break;
        
        case 4:
            upload_addr = simple_strtoul(argv[1], NULL, 16);
            upload_size = simple_strtoul(argv[3], NULL, 16);
            copy_filename (BootFile, argv[2], sizeof(BootFile));
            break;
        default: printf ("Usage:\n%s\n", cmdtp->usage);
            show_boot_progress (-80);
            return 1;
        }
        show_boot_progress (80);
        if ((size = NetLoop(proto)) < 0) {
            show_boot_progress (-81);
            return 1;
        }
        show_boot_progress (81);
        /* NetLoop ok, update environment */
        netboot_update_env();
        /* done if no file was loaded (no errors though) */
        if (size == 0) {
            show_boot_progress (-82);
            return 0;
        }
        /* flush cache */
        flush_cache(load_addr, size);
        /* Loading ok, check if we should attempt an auto-start */
        if (((s = getenv("autostart")) != NULL) && (strcmp(s,"yes") == 0)) {
            char *local_args[2];
            local_args[0] = argv[0];
            local_args[1] = NULL;
            printf ("Automatic boot of image at addr 0x%08lX ...\n",
                load_addr);
            show_boot_progress (82);
            rcode = do_bootm (cmdtp, 0, 1, local_args);
        }
    #ifdef CONFIG_AUTOSCRIPT
        if (((s = getenv("autoscript")) != NULL) && (strcmp(s,"yes") == 0)) {
            printf ("Running autoscript at addr 0x%08lX", load_addr);
            s = getenv ("autoscript_uname");
            if (s)
                printf (":%s ...\n", s);
            else
                puts (" ...\n");
            show_boot_progress (83);
            rcode = autoscript (load_addr, s);
        }
    #endif
        if (rcode < 0)
            show_boot_progress (-83);
        else
            show_boot_progress (84);
        return rcode;
    }

 

2、修改net/tftp.c 为
    /*
    * Copyright 1994, 1995, 2000 Neil Russell.
    * (See License)
    * Copyright 2000, 2001 DENX Software Engineering, Wolfgang Denk, wd@denx.de
    */
    #include <common.h>
    #include <command.h>
    #include <net.h>
    #include "tftp.h"
    #include "bootp.h"
    #undef ET_DEBUG
    #if defined(CONFIG_CMD_NET)
    #define WELL_KNOWN_PORT 69 /* Well known TFTP port # */
    #define TIMEOUT 1 /* Seconds to timeout for a lost pkt */
    #ifndef CONFIG_NET_RETRY_COUNT
    # define TIMEOUT_COUNT 10 /* # of timeouts before giving up */
    #else
    # define TIMEOUT_COUNT (CONFIG_NET_RETRY_COUNT * 2)
    #endif
    /* (for checking the image size) */
    #define TBLKS_PER_HASHES 64
    #define HASHES_PER_LINE 32 /* Number of "loading" hashes per line */
    /*
    * TFTP operations.
    */
    #define TFTP_RRQ 1
    #define TFTP_WRQ 2
    #define TFTP_DATA 3
    #define TFTP_ACK 4
    #define TFTP_ERROR 5
    #define TFTP_OACK 6
    #define STATE_OK 0
    #define STATE_ERROR 3
    #define STATE_WRQ 6
    #define STATE_ACK 7
    static IPaddr_t TftpServerIP;
    static int TftpServerPort; /* The UDP port at their end */
    static int TftpOurPort; /* The UDP port at our end */
    static int TftpTimeoutCount;
    static ulong TftpBlock; /* packet sequence number */
    static ulong TftpLastBlock; /* last packet sequence number received */
    static ulong TftpBlockWrap; /* count of sequence number wraparounds */
    static ulong TftpBlockWrapOffset; /* memory offset due to wrapping */
    static int TftpState;
    #define STATE_RRQ 1
    #define STATE_DATA 2
    #define STATE_TOO_LARGE 3
    #define STATE_BAD_MAGIC 4
    #define STATE_OACK 5
    #define TFTP_BLOCK_SIZE 512 /* default TFTP block size */
    #define TFTP_SEQUENCE_SIZE ((ulong)(1<<16)) /* sequence number is 16 bit */
    #define DEFAULT_NAME_LEN (8 + 4 + 1)
    static char default_filename[DEFAULT_NAME_LEN];
    #ifndef CONFIG_TFTP_FILE_NAME_MAX_LEN
    #define MAX_LEN 128
    #else
    #define MAX_LEN CONFIG_TFTP_FILE_NAME_MAX_LEN
    #endif
    static char tftp_filename[MAX_LEN];
    #ifdef CFG_DIRECT_FLASH_TFTP
    extern flash_info_t flash_info[];
    #endif
    ulong upload_addr = CFG_LOAD_ADDR; /* Default upLoad Address */
    ulong upload_size = 0;
    /* 512 is poor choice for ethernet, MTU is typically 1500.
    * Minus eth.hdrs thats 1468. Can get 2x better throughput with
    * almost-MTU block sizes. At least try... fall back to 512 if need be.
    */
    #define TFTP_MTU_BLOCKSIZE 1468
    static unsigned short TftpBlkSize=TFTP_BLOCK_SIZE;
    static unsigned short TftpBlkSizeOption=TFTP_MTU_BLOCKSIZE;
    #ifdef CONFIG_MCAST_TFTP
    #include <malloc.h>
    #define MTFTP_BITMAPSIZE 0x1000
    static unsigned *Bitmap;
    static int PrevBitmapHole,Mapsize=MTFTP_BITMAPSIZE;
    static uchar ProhibitMcast=0, MasterClient=0;
    static uchar Multicast=0;
    extern IPaddr_t Mcast_addr;
    static int Mcast_port;
    static ulong TftpEndingBlock; /* can get 'last' block before done..*/
    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);
    Bitmap=NULL;
    Mcast_addr = Multicast = Mcast_port = 0;
    TftpEndingBlock = -1;
    }
    #endif /* CONFIG_MCAST_TFTP */
    static __inline__ void
    store_block (unsigned block, uchar * src, unsigned len)
    {
    ulong offset = block * TftpBlkSize + TftpBlockWrapOffset;
    ulong newsize = offset + len;
    #ifdef CFG_DIRECT_FLASH_TFTP
    int i, rc = 0;
    for (i=0; i<CFG_MAX_FLASH_BANKS; i++) {
    /* start address in flash? */
    if (flash_info[i].flash_id == FLASH_UNKNOWN)
    continue;
    if ((load_addr + offset >= flash_info[i].start[0]) && (load_addr + offset < flash_info[i].start[0] + flash_info[i].size)) {
    rc = 1;
    break;
    }
    }
    if (rc) { /* Flash is destination for this packet */
    rc = flash_write ((char *)src, (ulong)(load_addr+offset), len);
    if (rc) {
    flash_perror (rc);
    NetState = NETLOOP_FAIL;
    return;
    }
    }
    else
    #endif /* CFG_DIRECT_FLASH_TFTP */
    {
    (void)memcpy((void *)(load_addr + offset), src, len);
    }
    #ifdef CONFIG_MCAST_TFTP
    if (Multicast)
    ext2_set_bit(block, Bitmap);
    #endif
    if (NetBootFileXferSize < newsize)
    NetBootFileXferSize = newsize;
    }
    static void TftpSend (void);
    static void TftpTimeout (void);
    /**********************************************************************/
    static void
    TftpSend (void)
    {
    volatile uchar * pkt;
    volatile uchar * xp;
    int len = 0;
    int uplen=0;
    volatile ushort *s;
    #ifdef CONFIG_MCAST_TFTP
    /* Multicast TFTP.. non-MasterClients do not ACK data. */
    if (Multicast
    && (TftpState == STATE_DATA)
    && (MasterClient == 0))
    return;
    #endif
    /*
    * We will always be sending some sort of packet, so
    * cobble together the packet headers now.
    */
    pkt = NetTxPacket + NetEthHdrSize() + IP_HDR_SIZE;
    switch (TftpState) {
    case STATE_RRQ:
    case STATE_WRQ:
    xp = pkt;
    s = (ushort *)pkt;
    if(TftpState == STATE_WRQ)
    *s++ = htons(TFTP_WRQ);
    else *s++ = htons(TFTP_RRQ);
    pkt = (uchar *)s;
    strcpy ((char *)pkt, tftp_filename);
    pkt += strlen(tftp_filename) + 1;
    strcpy ((char *)pkt, "octet");
    pkt += 5 /*strlen("octet")*/ + 1;
    strcpy ((char *)pkt, "timeout");
    pkt += 7 /*strlen("timeout")*/ + 1;
    sprintf((char *)pkt, "%d", TIMEOUT);
    #ifdef ET_DEBUG
    printf("send option \"timeout %s\"\n", (char *)pkt);
    #endif
    pkt += strlen((char *)pkt) + 1;
    /* try for more effic. blk size */
    if(TftpState == STATE_WRQ)
    pkt += sprintf((char *)pkt,"blksize%c%d%c",
    0,TftpBlkSizeOption,0);
    else
    pkt += sprintf((char *)pkt,"blksize%c%d%c",
    0,TftpBlkSizeOption,0);
    #ifdef CONFIG_MCAST_TFTP
    /* Check all preconditions before even trying the option */
    if (!ProhibitMcast
    && (Bitmap=malloc(Mapsize))
    && eth_get_dev()->mcast) {
    free(Bitmap);
    Bitmap=NULL;
    pkt += sprintf((char *)pkt,"multicast%c%c",0,0);
    }
    #endif /* CONFIG_MCAST_TFTP */
    len = pkt - xp;
    printf("%%");
    break;
    case STATE_OACK:
    #ifdef CONFIG_MCAST_TFTP
    /* My turn! Start at where I need blocks I missed.*/
    if (Multicast)
    TftpBlock=ext2_find_next_zero_bit(Bitmap,(Mapsize*8),0);
    /*..falling..*/
    #endif
    case STATE_DATA:
    xp = pkt;
    s = (ushort *)pkt;
    *s++ = htons(TFTP_ACK);
    *s++ = htons(TftpBlock);
    pkt = (uchar *)s;
    len = pkt - xp;
    break;
    case STATE_TOO_LARGE:
    xp = pkt;
    s = (ushort *)pkt;
    *s++ = htons(TFTP_ERROR);
    *s++ = htons(3);
    pkt = (uchar *)s;
    strcpy ((char *)pkt, "File too large");
    pkt += 14 /*strlen("File too large")*/ + 1;
    len = pkt - xp;
    break;
    case STATE_BAD_MAGIC:
    xp = pkt;
    s = (ushort *)pkt;
    *s++ = htons(TFTP_ERROR);
    *s++ = htons(2);
    pkt = (uchar *)s;
    strcpy ((char *)pkt, "File has bad magic");
    pkt += 18 /*strlen("File has bad magic")*/ + 1;
    len = pkt - xp;
    break;
    case STATE_ACK:
    xp = pkt;
    s = (ushort *)pkt;
    *s++ = htons(TFTP_DATA);
    *s++ = htons(TftpBlock+1);
    pkt = (uchar *)s;
    uplen = (upload_size-TftpBlock*TftpBlkSize);
    uplen = uplen > TftpBlkSize ? TftpBlkSize : uplen;
    memcpy((void*)pkt, (const char*)upload_addr + TftpBlock*TftpBlkSize , uplen);
    pkt += uplen;
    len = pkt - xp;
    break;
    default:
    return;
    }
    NetSendUDPPacket(NetServerEther, TftpServerIP, TftpServerPort, TftpOurPort, len);
    }
    static void tftp_show_transferd(int block, unsigned long wrap)
    {
    #define SHOW_TRANSFERD(tail) printf ("\t[%2lu.%03lu MB]%s", ((block-1)* TftpBlkSize + wrap)>>20, \
    (((block-1) * TftpBlkSize + wrap)&0x0FFFFF)>>10, tail)
    if( ((block-1) & (TBLKS_PER_HASHES-1)) == 0)
    putc('#');
    if( ((block-1) & (TBLKS_PER_HASHES*HASHES_PER_LINE-1)) == 0) {
    if((block-1) ==0) {
    if(wrap==0) {
    puts("\t[ Connected ]\n");
    } else {
    SHOW_TRANSFERD(" [BlockCounter Reset]\n");
    }
    } else {
    SHOW_TRANSFERD("\n");
    }
    }
    #undef SHOW_TRANSFERD
    }
    static void
    TftpHandler (uchar * pkt, unsigned dest, unsigned src, unsigned len)
    {
    ushort proto;
    ushort *s;
    int i;
    if (dest != TftpOurPort) {
    #ifdef CONFIG_MCAST_TFTP
    if (Multicast
    && (!Mcast_port || (dest != Mcast_port)))
    #endif
    return;
    }
    if ( !(TftpState==STATE_RRQ || TftpState==STATE_WRQ) && src != TftpServerPort) {
    return;
    }
    if (len < 2) {
    return;
    }
    len -= 2;
    /* warning: don't use increment (++) in ntohs() macros!! */
    s = (ushort *)pkt;
    proto = *s++;
    pkt = (uchar *)s;
    switch (ntohs(proto)) {
    case TFTP_RRQ:
    case TFTP_WRQ:
    break;
    case TFTP_ACK:
    TftpServerPort = src;
    TftpState=STATE_ACK;
    TftpBlock = ntohs(*(ushort *)pkt);
    if(TftpLastBlock == TftpBlock) {
    putc('%');
    } else {
    tftp_show_transferd(TftpBlock, TftpBlockWrapOffset);
    }
    TftpLastBlock = TftpBlock;
    NetSetTimeout (TIMEOUT * CFG_HZ, TftpTimeout);
    if(TftpBlkSize*TftpBlock> upload_size )
    {
    NetState = NETLOOP_SUCCESS;
    TftpState = STATE_OK;
    printf ("\n\t %lu.%03lu MB upload ok.\n", (TftpBlockWrapOffset+upload_size)>>20,
    ((TftpBlockWrapOffset+upload_size)&0x0FFFFF)>>10);
    break;
    }
    TftpSend (); /* Send ACK */
    break;
    default:
    break;
    case TFTP_OACK:
    #ifdef ET_DEBUG
    printf("Got OACK: %s %s\n", pkt, pkt+strlen(pkt)+1);
    #endif
    if(TftpState == STATE_WRQ)
    {
    TftpState = STATE_ACK;
    TftpBlock = 0;
    }
    else
    {
    TftpState = STATE_OACK;
    }
    TftpServerPort = 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) {
    TftpBlkSize = (unsigned short)
    simple_strtoul((char*)pkt+i+8,NULL,10);
    #ifdef ET_DEBUG
    printf ("Blocksize ack: %s, %d\n",
    (char*)pkt+i+8,TftpBlkSize);
    #endif
    break;
    }
    }
    #ifdef CONFIG_MCAST_TFTP
    parse_multicast_oack((char *)pkt,len-1);
    if ((Multicast) && (!MasterClient))
    TftpState = STATE_DATA; /* passive.. */
    else
    #endif
    TftpSend (); /* Send ACK */
    break;
    case TFTP_DATA:
    if (len < 2)
    return;
    len -= 2;
    TftpBlock = ntohs(*(ushort *)pkt);
    /*
    * RFC1350 specifies that the first data packet will
    * have sequence number 1. If we receive a sequence
    * number of 0 this means that there was a wrap
    * around of the (16 bit) counter.
    */
    if (TftpBlock == 0) {
    TftpBlockWrap++;
    TftpBlockWrapOffset += TftpBlkSize * TFTP_SEQUENCE_SIZE;
    printf ("\n\t %lu MB received\n\t ", TftpBlockWrapOffset>>20);
    } else {
    #if 0
    if (((TftpBlock - 1) % 10) == 0) {
    putc ('#');
    } else if ((TftpBlock % (10 * HASHES_PER_LINE)) == 0) {
    puts ("\n\t ");
    }
    #endif
    tftp_show_transferd(TftpBlock, TftpBlockWrapOffset);
    }
    #ifdef ET_DEBUG
    if (TftpState == STATE_RRQ) {
    puts ("Server did not acknowledge timeout option!\n");
    }
    #endif
    if (TftpState == STATE_RRQ || TftpState == STATE_OACK) {
    /* first block received */
    TftpState = STATE_DATA;
    TftpServerPort = src;
    TftpLastBlock = 0;
    TftpBlockWrap = 0;
    TftpBlockWrapOffset = 0;
    #ifdef CONFIG_MCAST_TFTP
    if (Multicast) { /* start!=1 common if mcast */
    TftpLastBlock = TftpBlock - 1;
    } else
    #endif
    if (TftpBlock != 1) { /* Assertion */
    printf ("\nTFTP error: "
    "First block is not block 1 (%ld)\n"
    "Starting again\n\n",
    TftpBlock);
    NetStartAgain ();
    break;
    }
    }
    if (TftpBlock == TftpLastBlock) {
    /*
    * Same block again; ignore it.
    */
    putc ('%');
    break;
    }
    TftpLastBlock = TftpBlock;
    NetSetTimeout (TIMEOUT * CFG_HZ, TftpTimeout);
    store_block (TftpBlock - 1, pkt + 2, len);
    /*
    * Acknoledge the block just received, which will prompt
    * the server for the next one.
    */
    #ifdef CONFIG_MCAST_TFTP
    /* if I am the MasterClient, actively calculate what my next
    * needed block is; else I'm passive; not ACKING
    */
    if (Multicast) {
    if (len < TftpBlkSize) {
    TftpEndingBlock = TftpBlock;
    } else if (MasterClient) {
    TftpBlock = PrevBitmapHole =
    ext2_find_next_zero_bit(
    Bitmap,
    (Mapsize*8),
    PrevBitmapHole);
    if (TftpBlock > ((Mapsize*8) - 1)) {
    printf ("tftpfile too big\n");
    /* try to double it and retry */
    Mapsize<<=1;
    mcast_cleanup();
    NetStartAgain ();
    return;
    }
    TftpLastBlock = TftpBlock;
    }
    }
    #endif
    TftpSend ();
    #ifdef CONFIG_MCAST_TFTP
    if (Multicast) {
    if (MasterClient && (TftpBlock >= TftpEndingBlock)) {
    puts ("\nMulticast tftp done\n");
    mcast_cleanup();
    NetState = NETLOOP_SUCCESS;
    }
    }
    else
    #endif
    if (len < TftpBlkSize) {
    /*
    * We received the whole thing. Try to
    * run it.
    */
    printf ("\n\t %lu.%03lu MB download ok.\n", ((TftpBlock-1)* TftpBlkSize + TftpBlockWrapOffset)>>20,
    (((TftpBlock-1) * TftpBlkSize + TftpBlockWrapOffset)&0x0FFFFF)>>10);
    puts ("\ndone\n");
    NetState = NETLOOP_SUCCESS;
    }
    break;
    case TFTP_ERROR:
    printf ("\nTFTP error: '%s' (%d)\n",
    pkt + 2, ntohs(*(ushort *)pkt));
    puts ("Starting again\n\n");
    #ifdef CONFIG_MCAST_TFTP
    mcast_cleanup();
    #endif
    NetStartAgain ();
    break;
    }
    }
    static void
    TftpTimeout (void)
    {
    if (++TftpTimeoutCount > TIMEOUT_COUNT) {
    puts ("\nRetry count exceeded; starting again\n");
    #ifdef CONFIG_MCAST_TFTP
    mcast_cleanup();
    #endif
    NetStartAgain ();
    } else {
    puts ("T ");
    NetSetTimeout (TIMEOUT * CFG_HZ, TftpTimeout);
    TftpSend ();
    }
    }
    void
    TftpStart (void)
    {
    #ifdef CONFIG_TFTP_PORT
    char *ep; /* Environment pointer */
    #endif
    if(upload_size)
    TftpState = STATE_WRQ;
    else TftpState = STATE_RRQ;
    TftpServerIP = NetServerIP;
    if (BootFile[0] == '\0') {
    sprintf(default_filename, "%02lX%02lX%02lX%02lX.img",
    NetOurIP & 0xFF,
    (NetOurIP >> 8) & 0xFF,
    (NetOurIP >> 16) & 0xFF,
    (NetOurIP >> 24) & 0xFF );
    strncpy(tftp_filename, default_filename, MAX_LEN);
    tftp_filename[MAX_LEN-1] = 0;
    printf ("*** Warning: no boot file name; using '%s'\n",
    tftp_filename);
    } else {
    char *p = strchr (BootFile, ':');
    if (p == NULL) {
    strncpy(tftp_filename, BootFile, MAX_LEN);
    tftp_filename[MAX_LEN-1] = 0;
    } else {
    *p++ = '\0';
    TftpServerIP = string_to_ip (BootFile);
    strncpy(tftp_filename, p, MAX_LEN);
    tftp_filename[MAX_LEN-1] = 0;
    }
    }
    #if defined(CONFIG_NET_MULTI)
    printf ("Using %s device\n", eth_get_name());
    #endif
    if( TftpState == STATE_WRQ)
    {
    puts ("TFTP to server "); print_IPaddr (NetServerIP);
    }
    else
    {
    puts ("TFTP from server "); print_IPaddr (TftpServerIP);
    }
    puts ("; our IP address is "); print_IPaddr (NetOurIP);
    /* Check if we need to send across this subnet */
    if (NetOurGatewayIP && NetOurSubnetMask) {
    IPaddr_t OurNet = NetOurIP & NetOurSubnetMask;
    IPaddr_t ServerNet = TftpServerIP & NetOurSubnetMask;
    if (OurNet != ServerNet) {
    puts ("; sending through gateway ");
    print_IPaddr (NetOurGatewayIP) ;
    }
    }
    putc ('\n');
    if( TftpState == STATE_WRQ)
    printf ("Upload Filename '%s'.", tftp_filename);
    else printf ("Download Filename '%s'.", tftp_filename);
    if (NetBootFileSize) {
    printf (" Size is 0x%x Bytes = ", NetBootFileSize<<9);
    print_size (NetBootFileSize<<9, "");
    }
    putc ('\n');
    if( TftpState == STATE_WRQ)
    {
    printf ("Upload from address: 0x%lx, ", upload_addr);
    printf ("%lu.%03lu MB to be send ...\n", upload_size>>20, (upload_size&0x0FFFFF)>>10);
    printf ("Uploading: *\b");
    }
    else
    {
    printf ("Download to address: 0x%lx\n", load_addr);
    printf ("Downloading: *\b");
    }
    NetSetTimeout (TIMEOUT * CFG_HZ, TftpTimeout);
    NetSetHandler (TftpHandler);
    TftpServerPort = WELL_KNOWN_PORT;
    TftpTimeoutCount = 0;
    /* 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) {
    TftpOurPort= simple_strtol(ep, NULL, 10);
    }
    #endif
    TftpBlock = 0;
    TftpLastBlock = 0;
    TftpBlockWrap = 0;
    TftpBlockWrapOffset = 0;
    /* zero out server ether in case the server ip has changed */
    memset(NetServerEther, 0, 6);
    /* Revert TftpBlkSize to dflt */
    TftpBlkSize = TFTP_BLOCK_SIZE;
    #ifdef CONFIG_MCAST_TFTP
    mcast_cleanup();
    #endif
    TftpSend ();
    }
    #ifdef CONFIG_MCAST_TFTP
    /* Credits: atftp project.
    */
    /* pick up BcastAddr, Port, and whether I am [now] the master-client. *
    * Frame:
    * +-------+-----------+---+-------~~-------+---+
    * | opc | multicast | 0 | addr, port, mc | 0 |
    * +-------+-----------+---+-------~~-------+---+
    * The multicast addr/port becomes what I listen to, and if 'mc' is '1' then
    * I am the new master-client so must send ACKs to DataBlocks. If I am not
    * master-client, I'm a passive client, gathering what DataBlocks I may and
    * making note of which ones I got in my bitmask.
    * In theory, I never go from master->passive..
    * .. this comes in with pkt already pointing just past opc
    */
    static void parse_multicast_oack(char *pkt, int len)
    {
    int i;
    IPaddr_t addr;
    char *mc_adr, *port, *mc;
    mc_adr=port=mc=NULL;
    /* march along looking for 'multicast\0', which has to start at least
    * 14 bytes back from the end.
    */
    for (i=0;i<len-14;i++)
    if (strcmp (pkt+i,"multicast") == 0)
    break;
    if (i >= (len-14)) /* non-Multicast OACK, ign. */
    return;
    i+=10; /* strlen multicast */
    mc_adr = pkt+i;
    for (;i<len;i++) {
    if (*(pkt+i) == ',') {
    *(pkt+i) = '\0';
    if (port) {
    mc = pkt+i+1;
    break;
    } else {
    port = pkt+i+1;
    }
    }
    }
    if (!port || !mc_adr || !mc ) return;
    if (Multicast && MasterClient) {
    printf ("I got a OACK as master Client, WRONG!\n");
    return;
    }
    /* ..I now accept packets destined for this MCAST addr, port */
    if (!Multicast) {
    if (Bitmap) {
    printf ("Internal failure! no mcast.\n");
    free(Bitmap);
    Bitmap=NULL;
    ProhibitMcast=1;
    return ;
    }
    /* 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))) {
    printf ("No Bitmap, no multicast. Sorry.\n");
    ProhibitMcast=1;
    return;
    }
    memset (Bitmap,0,Mapsize);
    PrevBitmapHole = 0;
    Multicast = 1;
    }
    addr = string_to_ip(mc_adr);
    if (Mcast_addr != addr) {
    if (Mcast_addr)
    eth_mcast_join(Mcast_addr, 0);
    if (eth_mcast_join(Mcast_addr=addr, 1)) {
    printf ("Fail to set mcast, revert to TFTP\n");
    ProhibitMcast=1;
    mcast_cleanup();
    NetStartAgain();
    }
    }
    MasterClient = (unsigned char)simple_strtoul((char *)mc,NULL,10);
    Mcast_port = (unsigned short)simple_strtoul(port,NULL,10);
    printf ("Multicast: %s:%d [%d]\n", mc_adr, Mcast_port, MasterClient);
    return;
    }
    #endif /* Multicast TFTP */
    #endif

 

posted @ 2014-05-28 18:22  dolinux  阅读(3521)  评论(0编辑  收藏  举报