📄 tftp.c
字号:
* 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 + -