⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tftp.c

📁 完整的Bell实验室的嵌入式文件系统TFS
💻 C
📖 第 1 页 / 共 3 页
字号:
/* tftp.c: *  This code supports the monitor's TFTP server. *  TFTP is covered under RFC 783. * *  General notice: *  This code is part of a boot-monitor package developed as a generic base *  platform for embedded system designs.  As such, it is likely to be *  distributed to various projects beyond the control of the original *  author.  Please notify the author of any enhancements made or bugs found *  so that all may benefit from the changes.  In addition, notification back *  to the author will allow the new user to pick up changes that may have *  been made by other users after this version of the code was distributed. * *  Note1: the majority of this code was edited with 4-space tabs. *  Note2: as more and more contributions are accepted, the term "author" *         is becoming a mis-representation of credit. * *  Original author:    Ed Sutter *  Email:              esutter@lucent.com *  Phone:              908-582-2351 */#include "config.h"#if INCLUDE_TFTP#include "endian.h"#include "genlib.h"#include "cpuio.h"#include "ether.h"#include "tfs.h"#include "tfsprivate.h"#include "monflags.h"#include "stddefs.h"#include "cli.h"#define MODE_NULL       0#define MODE_NETASCII   1#define MODE_OCTET      2void ShowTftpStats();int SendTFTPData(struct ether_header *,ushort,uchar *,int);int SendTFTPErr(struct ether_header *,short,char *,int);int SendTFTPAck(struct ether_header *,ushort);int SendTFTPRRQ(uchar *,uchar *,char *,char *,uchar *);static ushort   tftpLastblock;  /* Keeps the value of the block number of                                 * the last TFTP transaction.                                 */static int tftpRetry_delayloops;/* Number of times tftpStateCheck() must be                                 * called to reach tftpRetry_delaysecs.                                 */static int tftpRetry_delaysecs; /* Number of seconds to wait prior to retry. */static int tftpRetry_lastchance;/* Set if we are on the last retry and are                                 * about to give up.                                 */static int TftpWrqMode;         /* Set to MODE_NETASCII, MODE_OCTET or                                 * MODE_NULL based on the incoming WRQ                                 * request                                 */static int TftpChopCount;       /* Number of characters chopped from the                                 * incoming file because of NETASCII                                 * conversion (remove 0x0d).                                 */static int TftpLastPktSize;static uchar TftpLastPkt[TFTP_PKTOVERHEAD+TFTP_DATAMAX+4];                                /* Storage of last packet sent.  This is                                 * used if it is determined that the packet                                 * most recently sent must be sent again.                                 */static long TftpRetryTimeout;   /* Count used during a TFTP transfer to                                 * kick off a retransmission of a packet.                                 * It is cleared each time a valid packet                                 * is sent, and incremented by the                                 * tftpStateCheck() function.                                 */static ushort TftpRmtPort;      /* Remote port of tftp transfer */static uchar *TftpAddr;         /* Current destination address used for tftp                                 * file transfer into local memory.                                 */static int  TftpCount;          /* Running total number of bytes transferred                                 * for a particular tftp transaction.                                 */static int  TftpState;          /* Used to keep track of the current state                                 * of a tftp transaction.                                 */static int  TftpTurnedOff;      /* If non-zero, then tftp is disabled. */static char TftpErrString[32];  /* Used to post a tftp error message. */static char TftpTfsFname[TFSNAMESIZE+64];   /* Store name of WRQ destination                                             * file (plus flags & info).                                             */char *tftpStringState(int state){    switch(state) {        case TFTPOFF:            return("OFF");        case TFTPIDLE:            return("IDLE");        case TFTPACTIVE:            return("ACTIVE");        case TFTPERROR:            return("ERROR");        case TFTPSENTRRQ:            return("SENTRRQ");        case TFTPTIMEOUT:            return("TIMEOUT");        default:            return("???");    }}inttftpGotoState(int state){    int ostate;    ostate = TftpState;    TftpState = state;    if ((EtherVerbose & SHOW_TFTP) && (state != ostate))        printf("  TFTP State change %s -> %s\n",            tftpStringState(ostate), tftpStringState(state));    return(ostate);}/* tftpGet(): *  Return size of file if successful; else 0. */inttftpGet(ulong addr,char *tftpsrvr,char *mode, char *hostfile,char *tfsfile,    char *tfsflags,char *tfsinfo){    int     done;    char    buf[32];    uchar   binip[8], binenet[8], *enetaddr;    setenv("TFTPGET",0);    /* Convert IP address to binary: */    if (IpToBin(tftpsrvr,binip) < 0)        return(0);    /* Get the ethernet address for the IP: */    /* Give ARP the same verbosity (if any) set up for TFTP: */    if (EtherVerbose & SHOW_TFTP)        EtherVerbose |= SHOW_ARP;    enetaddr = ArpEther(binip,binenet,0);    EtherVerbose &= ~SHOW_ARP;    if (!enetaddr) {        printf("ARP failed for %s\n",tftpsrvr);        return(0);    }    /* Initialize the retransmission delay calculator: */    RetransmitDelay(DELAY_INIT_TFTP);    printf("Retrieving %s from %s...",hostfile,tftpsrvr);    if (EtherVerbose & SHOW_TFTP)        printf("\n");    /* Send the TFTP RRQ to initiate the transfer. */    if (SendTFTPRRQ(binip,binenet,hostfile,mode,(uchar *)addr) < 0) {        printf("RRQ failed\n");        return(0);    }    /* Wait for TftpState to indicate that the transaction has completed... */    done = 0;    while(!done) {        pollethernet();        switch(TftpState) {            case TFTPIDLE:                printf(" %d bytes",TftpCount);                done = 1;                break;            case TFTPERROR:                printf(" host error: %s\n",TftpErrString);                done = 2;                break;            case TFTPTIMEOUT:                printf(" timing out (%d bytes rcvd)\n",TftpCount);                done = 2;                break;            default:                break;        }    }    if (done == 2)        return(0);    if (tfsfile) {        int err, filesize;        filesize = TftpCount - TftpChopCount;        printf("\nAdding %s (size=%d) to TFS...",tfsfile,filesize);        err = tfsadd(tfsfile,tfsinfo,tfsflags,(uchar *)addr,filesize);        if (err != TFS_OKAY)            printf("%s: %s\n",tfsfile,(char *)tfsctrl(TFS_ERRMSG,err,0));    }    printf("\n");    sprintf(buf,"%d",TftpCount);    setenv("TFTPGET",buf);    return(TftpCount);}/* tftpInit(): *  Called by the ethenet initialization to initialize state variables. */voidtftpInit(){    TftpCount = -1;    TftpRmtPort = 0;    TftpTurnedOff = 0;    tftpGotoState(TFTPIDLE);    TftpAddr = (uchar *)0;}/* storePktAndSend(): *  The final stage in sending a TFTP packet... *  1. Compute IP and UDP checksums; *  2. Copy ethernet packet to a buffer so that it can be resent *      if necessary (by tftpStateCheck()). *  3. Store the size of the packet;  *  4. Send the packet out the interface. *  5. Reset the timeout count and re-transmission delay variables. */voidstorePktAndSend(struct ip *ipp, struct ether_header *epkt,int size){    ipChksum(ipp);                          /* Compute csum of ip hdr */    udpChksum(ipp);                         /* Compute UDP checksum */                                            /* Copy packet to static buffer */    memcpy((char *)TftpLastPkt,(char *)epkt,size);    TftpLastPktSize = size;                 /* Copy size to static location */    sendBuffer(size);                       /* Send buffer out ethernet i*/    /* Clear the retry timeout counters and re-initialize the */    /* re-transmission delay variables. */    TftpRetryTimeout = 0;       tftpRetry_lastchance = 0;    tftpRetry_delayloops = 0;    RetransmitDelay(DELAY_INIT_TFTP);}/* getTftpSrcPort(): *  Each time a TFTP RRQ goes out, use a new source port number. *  Cycle through a block of 256 port numbers... */ushortgetTftpSrcPort(void){    if (TftpSrcPort < (IPPORT_TFTPSRC+256))        TftpSrcPort++;    else        TftpSrcPort = IPPORT_TFTPSRC;    return(TftpSrcPort);}/* tftpStateCheck(): *  Called by the pollethernet function to support the ability to retry *  on a TFTP transmission that appears to have terminated prematurely *  due to a lost packet.  If a packet is sent and the response is not *  received within about 1-2 seconds, the packet is re-sent.  The retry *  will repeat 8 times; then give up and set the TFTP state to idle. * *  Taken from RFC 1350 section 2 "Overview of the Protocol"... *  ... If a packet gets lost in the network, the intended recipient will *  timeout and may retransmit his last packet (which may be data or an *  acknowledgement), thus causing the sender of the lost packet to retransmit *  the lost packet. * *  Taken from RFC 1123 section 4.2.3.2 "Timeout Algorithms"... *  ... a TFTP implementation MUST use an adaptive timeout ... */voidtftpStateCheck(void){    uchar   *buf;    ushort  tftp_opcode;    struct  ip *ihdr;    struct  Udphdr *uhdr;    struct  ether_header *ehdr;    switch(TftpState) {        case TFTPIDLE:        case TFTPTIMEOUT:        case TFTPERROR:            tftpRetry_lastchance = tftpRetry_delayloops = 0;            return;        default:            break;    }    if (!tftpRetry_delayloops) {        tftpRetry_delaysecs = RetransmitDelay(DELAY_OR_TIMEOUT_RETURN);        tftpRetry_delayloops = tftpRetry_delaysecs * LoopsPerSecond;    }        /* If the value in TftpRetryTimeout reaches the tftpRetry_delayloops */    /* value, then assume it is time to re-transmit a packet... */    if (++TftpRetryTimeout < tftpRetry_delayloops)        return;    if (tftpRetry_lastchance) {        if (EtherVerbose & SHOW_TFTP)            printf("  TFTP_RETRY giving up\n");        tftpGotoState(TFTPTIMEOUT);        enableBroadcastReception();        TftpRetryTimeout = 0;        return;    }    /* Get a transmit buffer and copy the packet that was last sent.     * Insert a new IP ID, recalculate the checksums and send it again...     * If the opcode of the packet to be re-transmitted is RRQ, then     * use a new port number.     */    buf = (uchar *)getXmitBuffer();    memcpy((char *)buf,(char *)TftpLastPkt,TftpLastPktSize);    ehdr = (struct ether_header *)buf;    ihdr = (struct ip *)(ehdr + 1);    uhdr = (struct Udphdr *)(ihdr + 1);    tftp_opcode = *(ushort *)(uhdr + 1);    ihdr->ip_id = ipId();    if (tftp_opcode == ecs(TFTP_RRQ)) {        uhdr->uh_sport = getTftpSrcPort();        self_ecs(uhdr->uh_sport);    }    ipChksum(ihdr);    udpChksum(ihdr);    sendBuffer(TftpLastPktSize);    if (EtherVerbose & SHOW_TFTP)        printf("  TFTP_RETRY (%d secs)\n",tftpRetry_delaysecs);    tftpRetry_delayloops = 0;    if (RetransmitDelay(DELAY_INCREMENT) == RETRANSMISSION_TIMEOUT)        tftpRetry_lastchance = 1;    TftpRetryTimeout = 0;    return;}/* tftpStartSrvrFilter(): *  Called when either a TFTP_RRQ or TFTP_WRQ is received indicating that

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -