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

📄 tftp.c

📁 完整的Bell实验室的嵌入式文件系统TFS
💻 C
📖 第 1 页 / 共 3 页
字号:
 *  a client wants to start up a transfer. *  If TftpState is IDLE, ERROR or TIMEOUT, this means it is safe to start *  up a new transfer through the server; otherwise return 0.  */inttftpStartSrvrFilter(struct ether_header *ehdr,struct Udphdr *uhdr){    if ((TftpState == TFTPIDLE) || (TftpState == TFTPERROR) ||        (TftpState == TFTPTIMEOUT)) {        TftpTfsFname[0] = 0;        TftpRmtPort = ecs(uhdr->uh_sport);        tftpGotoState(TFTPACTIVE);        return(1);    }    /* If block is zero and the incoming WRQ request is from the same     * port as was previously recorded, then assume the ACK sent back     * to the requester was not received, and this is a WRQ that is     * being re-sent.  That being the case, just send the Ack back.     */    else if ((tftpLastblock == 0) && (TftpRmtPort == uhdr->uh_sport)) {        SendTFTPAck(ehdr,0);        return(0);    }    else {        printf("   (tftp busy)\n");        /* Note: the value of TftpState is not changed (final arg to         * SendTFTPErr is 0) to TFTPERROR.  This is because         * we received a RRQ/WRQ request while processing a different         * TFTP transfer.  We want to send the error response to the         * sender, but we don't want to stay in an error state because         * there is another valid TFTP transfer in progress.         */        SendTFTPErr(ehdr,0,"TFTP server busy.",0);        return(0);    }}/* processTFTP(): *  This function handles the majority of the TFTP requests that a *  TFTP server must be able to handle.  There is no real robust  *  error handling, but it seems to work pretty well. *  Refer to Stevens' "UNIX Network Programming" chap 12 for details *  on TFTP. *  Note: During TFTP, promiscuity, broadcast & multicast reception *  are all turned off.  This is done to speed up the file transfer. */intprocessTFTP(struct ether_header *ehdr,ushort size){    static  uchar   *oaddr;    struct  ip *ihdr;    struct  Udphdr *uhdr;    uchar   *data;    int     count, tmpcount;    ushort  opcode, block, errcode;    char    *comma, *tftpp, *filename, *mode, *errstring, msg[64];    if (TftpTurnedOff)        return(0);    ihdr = (struct ip *)(ehdr + 1);    uhdr = (struct Udphdr *)((char *)ihdr + IP_HLEN(ihdr));    tftpp = (char *)(uhdr + 1);    opcode = *(ushort *)tftpp;    switch (opcode) {    case ecs(TFTP_WRQ):        filename = tftpp+2;        if ((EtherVerbose & SHOW_TFTP) || (!MFLAGS_NOTFTPPRN()))            printf("TFTP rcvd WRQ: file %s\n", filename);        if (!tftpStartSrvrFilter(ehdr,uhdr))            return(0);        mode = filename;        while(*mode)            mode++;        mode++;                /* Destination of WRQ can be an address (0x...), environment         * variable ($...) or a TFS filename...         */        if ((filename[0] == '$') && (getenv(&filename[1]))) {            TftpAddr = (uchar *)strtol(getenv(&filename[1]),(char **)0,0);        }        else if ((filename[0] == '0') && (filename[1] == 'x')) {            TftpAddr = (uchar *)strtol(filename,(char **)0,0);        }        else {            if (MFLAGS_NOTFTPOVW() && tfsstat(filename)) {                SendTFTPErr(ehdr,6,"File already exists.",1);                return(0);            }            TftpAddr = (uchar *)getAppRamStart();            strncpy(TftpTfsFname,filename,sizeof(TftpTfsFname)-1);            TftpTfsFname[sizeof(TftpTfsFname)-1] = 0;        }        TftpCount = -1; /* not used with WRQ, so clear it */        /* Convert mode to lower case... */        strtolower(mode);        if (!strcmp(mode,"netascii"))            TftpWrqMode = MODE_NETASCII;        else if (!strcmp(mode,"octet"))            TftpWrqMode = MODE_OCTET;        else {            SendTFTPErr(ehdr,0,"Mode not supported.",1);            TftpWrqMode = MODE_NULL;            TftpCount = -1;            return(0);        }        block = 0;        tftpLastblock = block;        oaddr = TftpAddr;        TftpChopCount = 0;        disableBroadcastReception();        break;    case ecs(TFTP_RRQ):        filename = tftpp+2;        if ((EtherVerbose & SHOW_TFTP) || (!MFLAGS_NOTFTPPRN()))            printf("TFTP rcvd RRQ: file %s\n",filename);        if (!tftpStartSrvrFilter(ehdr,uhdr))            return(0);        mode = filename;        while(*mode) mode++;        mode++;        comma = strchr(filename,',');        if (!comma) {            TFILE   *tfp;             tfp = tfsstat(filename);            if (!tfp) {                SendTFTPErr(ehdr,0,"File not found, try 'address,count'",1);                TftpCount = -1;                return(0);            }            TftpAddr = (uchar *)TFS_BASE(tfp);            TftpCount = TFS_SIZE(tfp);        }        else {            comma++;            TftpAddr = (uchar *)strtol(filename,(char **)0,0);            TftpCount = strtol(comma,(char **)0,0);        }        if (strcmp(mode,"octet")) {            SendTFTPErr(ehdr,0,"Must use binary mode",1);            TftpCount = -1;            return(0);        }        block = tftpLastblock = 1;        disableBroadcastReception();        tftpGotoState(TFTPACTIVE);        SendTFTPData(ehdr,block,TftpAddr,TftpCount);        return(0);    case ecs(TFTP_DAT):        block = ecs(*(ushort *)(tftpp+2));        count = ecs(uhdr->uh_ulen) - (sizeof(struct Udphdr)+4);        if (EtherVerbose & SHOW_TFTP)            printf("  Rcvd TFTP_DAT (%d,blk=%d)\n",count,block);        if (TftpState == TFTPSENTRRQ) {     /* See notes in SendTFTPRRQ() */            tftpLastblock = 0;            if (block == 1) {                TftpRmtPort = ecs(uhdr->uh_sport);                tftpGotoState(TFTPACTIVE);            }            else {                SendTFTPErr(ehdr,0,"invalid block",1);                return(0);            }        }        /* Since we don't ACK the final TFTP_DAT from the server until after         * the file has been written, it is possible that we will receive         * a re-transmitted TFTP_DAT from the server.  This is ignored by         * Sending another ACK...         */        else if ((TftpState == TFTPIDLE) && (block == tftpLastblock)) {            SendTFTPAck(ehdr,block);                if (EtherVerbose & SHOW_TFTP)                printf("  (packet ignored)\n");            return(0);                      }        else if (TftpState != TFTPACTIVE) {            SendTFTPErr(ehdr,0,"invalid state",1);            return(0);        }        if (ecs(uhdr->uh_sport) != TftpRmtPort) {            SendTFTPErr(ehdr,0,"invalid source port",0);            return(0);        }        if (block == tftpLastblock) {   /* If block didn't increment, assume */            SendTFTPAck(ehdr,block);    /* retry.  Ack it and return here.  */            return(0);          /* Otherwise, if block != tftpLastblock+1, */        }                       /* return an error, and quit now.   */        else if (block != tftpLastblock+1) {            SendTFTPErr(ehdr,0,"Unexpected block number",1);            TftpCount = -1;            return(0);        }        TftpCount += count;        oaddr = TftpAddr;        tftpLastblock = block;        data = (uchar *)(tftpp+4);        /* If count is less than TFTP_DATAMAX, this must be the last         * packet of the transfer, so clean up state here.         */        if (count < TFTP_DATAMAX) {            enableBroadcastReception();            tftpGotoState(TFTPIDLE);        }        /* Copy data from enet buffer to TftpAddr location... */        tmpcount = count;        while(tmpcount) {                   if (TftpWrqMode == MODE_NETASCII) {                if (*data == 0x0d) {                    data++;                    tmpcount--;                    TftpChopCount++;                    continue;                }            }                            *TftpAddr = *data;            if (*TftpAddr != *data) {                sprintf(msg,"Write error at 0x%lx",(ulong)TftpAddr);                SendTFTPErr(ehdr,0,msg,1);                TftpCount = -1;                return(0);            }            TftpAddr++;            data++;            tmpcount--;        }        /* Check for transfer complete (count < TFTP_DATAMAX)... */        if (count < TFTP_DATAMAX) {            if (TftpTfsFname[0]) {                char *fcomma, *icomma, *flags, *info;                int err;                /* If the transfer is complete and TftpTfsFname[0]                 * is non-zero, then write the data to the specified                 * TFS file... Note that a comma in the filename is                 * used to find the start of (if any) the TFS flags                 * string.  A second comma, marks the info field.                 */                info = (char *)0;                flags = (char *)0;                fcomma = strchr(TftpTfsFname,',');                if (fcomma) {                    icomma = strchr(fcomma+1,',');                    if (icomma) {                        *icomma = 0;                        info = icomma+1;                    }                    if (tfsctrl(TFS_FATOB,(long)(fcomma+1),0) != -1) {                        *fcomma = 0;                        flags = fcomma+1;                    }                    else {                        SendTFTPErr(ehdr,0,"Invalid flag spec.",1);                        TftpTfsFname[0] = 0;                        break;                    }                }                if ((EtherVerbose & SHOW_TFTP) || (!MFLAGS_NOTFTPPRN()))                    printf("TFTP adding file: '%s' to TFS.\n",TftpTfsFname);                err = tfsadd(TftpTfsFname,info,flags,                    (char *)getAppRamStart(),TftpCount+1-TftpChopCount);                if (err != TFS_OKAY) {                    sprintf(msg,"TFS err: %s",                        (char *)tfsctrl(TFS_ERRMSG,err,0));                    SendTFTPErr(ehdr,0,msg,1);                }                TftpTfsFname[0] = 0;            }            else {                int cnt;                char *addr;                /* If the transfer is complete and no file add is to                 * be done, then we flush d-cache and invalidate                 * i-cache across the memory space that was just                 * copied to.  This is necessary in case the                 * binary data that was just transferred is code.                 */                cnt = TftpCount + 1;                addr = TftpAddr - cnt;                flushDcache(addr,cnt);                invalidateIcache(addr,cnt);            }            if ((EtherVerbose & SHOW_TFTP) || (!MFLAGS_NOTFTPPRN()))                printf("TFTP transfer complete.\n");        }        break;    case ecs(TFTP_ACK):        block = ecs(*(ushort *)(tftpp+2));        if (TftpState != TFTPACTIVE) {            SendTFTPErr(ehdr,0,"Illegal server state for incoming TFTP_ACK",1);            return(0);        }        if (EtherVerbose & SHOW_TFTP)            printf("  Rcvd TFTP_ACK (blk#%d)\n",block);        if (block == tftpLastblock) {            if (TftpCount > TFTP_DATAMAX) {                TftpCount -= TFTP_DATAMAX;                TftpAddr += TFTP_DATAMAX;                SendTFTPData(ehdr,block+1,TftpAddr,TftpCount);                tftpLastblock++;            }            else if (TftpCount == TFTP_DATAMAX) {                TftpCount = 0;                tftpGotoState(TFTPIDLE);                SendTFTPData(ehdr,block+1,TftpAddr,0);                tftpLastblock++;            }            else {                TftpAddr += TftpCount;                TftpCount = 0;                tftpGotoState(TFTPIDLE);                enableBroadcastReception();            }        }        else if (block == tftpLastblock-1) {            SendTFTPData(ehdr,block+1,TftpAddr,TftpCount);        }        else {            SendTFTPErr(ehdr,0,"Blockno confused",1);            TftpCount = -1;            return(0);        }        return(0);    case ecs(TFTP_ERR):        errcode = ecs(*(ushort *)(tftpp+2));        errstring = tftpp+4;        if (EtherVerbose & SHOW_TFTP)            printf("  Rcvd TFTP_ERR #%d (%s)\n",errcode,errstring);        TftpCount = -1;        tftpGotoState(TFTPERROR);        strncpy(TftpErrString,errstring,sizeof(TftpErrString)-1);        TftpErrString[sizeof(TftpErrString)-1] = 0;        return(0);    default:        if (EtherVerbose & SHOW_TFTP)            printf("  Rcvd <%04x> unknown TFTP opcode\n", opcode);

⌨️ 快捷键说明

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