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

📄 tftp.c

📁 umon bootloader source code, support mips cpu.
💻 C
📖 第 1 页 / 共 3 页
字号:
 *	up a new transfer through the server; otherwise return 0. 
 */
int
tftpStartSrvrFilter(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 ((tftpPrevBlock == 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);
	}
}

/* tftpTransferComplete():
 * Print a message indicating that the transfer has completed.
 */
void
tftpTransferComplete(void)
{
	if ((EtherVerbose & SHOW_TFTP_STATE) || (!MFLAGS_NOTFTPPRN()))
		printf("TFTP transfer complete.\n");
}

/* 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.
 */
int
processTFTP(struct ether_header *ehdr,ushort size)
{
	static	uchar	*oaddr;
	struct	ip *ihdr;
	struct	Udphdr *uhdr;
	uchar	*data;
	int		count;
	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_STATE) || (!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;
		tftpPrevBlock = block;
		oaddr = TftpAddr;
		TftpChopCount = 0;
		disableBroadcastReception();
		break;
	case ecs(TFTP_RRQ):
		filename = tftpp+2;
		if ((EtherVerbose & SHOW_TFTP_STATE) || (!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; 

			if (!strcmp(filename,".")) {
				TftpLTMptr = TftpAddr = ls_to_mem();
				if (TftpLTMptr)
					TftpCount = strlen(TftpAddr);
				else 
					TftpCount = 0;
			}
			else {
				tfp = tfsstat(filename);
				if (!tfp) {
					SendTFTPErr(ehdr,0,"File not found",1);
					TftpCount = -1;
					return(0);
				}
				TftpAddr = (uchar *)TFS_BASE(tfp);
				TftpCount = TFS_SIZE(tfp);
			}
		}
		else {
			*comma++ = 0;
			if ((filename[0] == '$') && (getenv(&filename[1])))
				TftpAddr = (uchar *)strtol(getenv(&filename[1]),(char **)0,0);
			else
				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 = tftpPrevBlock = 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_STATE)
			printf("  Rcvd TFTP_DAT (%d,blk=%d)\n",count,block);
		else if (EtherVerbose & SHOW_TFTP_TICKER)
			ticktock();

		if (TftpState == TFTPSENTRRQ) {		/* See notes in SendTFTPRRQ() */
			tftpPrevBlock = 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 == tftpPrevBlock)) {
			SendTFTPAck(ehdr,block);	
			if (EtherVerbose & SHOW_TFTP_STATE)
				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 == tftpPrevBlock) {	/* If block didn't increment, assume */
			SendTFTPAck(ehdr,block);	/* retry.  Ack it and return here.	*/
			return(0);			/* Otherwise, if block != tftpPrevBlock+1, */
		}						/* return an error, and quit now.	*/
		else if (block != tftpPrevBlock+1) {
			SendTFTPErr(ehdr,0,"Unexpected block number",1);
			TftpCount = -1;
			return(0);
		}
		TftpCount += count;
		oaddr = TftpAddr;
		tftpPrevBlock = 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.
		 * If netascii mode is active, then this transfer is much
		 * slower...
		 * If not netascii, then we use s_memcpy() because it does
		 * a verification of each byte written and will abort as soon
		 * as a failure is detected.
		 */
		if (TftpWrqMode == MODE_NETASCII) {
			int	tmpcount = count;

			while(tmpcount) {
				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--;
			}
		}
		else {
#if INCLUDE_FLASH
			if (InFlashSpace(TftpAddr,count)) {
				SendTFTPErr(ehdr,0,"TFTP can't write directly to flash",1);
				TftpCount = -1;
				return(0);
			}
#endif
			if (s_memcpy(TftpAddr,data,count,0,0) != 0) {
				sprintf(msg,"Write error at 0x%lx",(ulong)TftpAddr);
				SendTFTPErr(ehdr,0,msg,1);
				TftpCount = -1;
				return(0);
			}
			TftpAddr += count;
		}

		/* 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_STATE) || (!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);
			}
			tftpTransferComplete();
		}
		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_STATE)
			printf("  Rcvd TFTP_ACK (blk#%d)\n",block);

		if (block == tftpPrevBlock) {
			if (TftpCount > TFTP_DATAMAX) {
				TftpCount -= TFTP_DATAMAX;
				TftpAddr += TFTP_DATAMAX;
				SendTFTPData(ehdr,block+1,TftpAddr,TftpCount);
				tftpPrevBlock++;
			}
			else if (TftpCount == TFTP_DATAMAX) {
				TftpCount = 0;
				tftpGotoState(TFTPIDLE);
				SendTFTPData(ehdr,block+1,TftpAddr,0);
				tftpPrevBlock++;
			}
			else {
				TftpAddr += TftpCount;
				TftpCount = 0;
				tftpGotoState(TFTPIDLE);
				if (TftpLTMptr) {
					free(TftpLTMptr);
					TftpLTMptr = (char *)0;
				}
				enableBroadcastReception();
				tftpTransferComplete();
			}
		}
		else if (block == tftpPrevBlock-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_STATE)
			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_STATE)
			printf("  Rcvd <%04x> unknown TFTP opcode\n", opcode);
		TftpCount = -1;
		return(-1);
	}
	SendTFTPAck(ehdr,block);
	return(0);
}

⌨️ 快捷键说明

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