www.pudn.com > uc_tftp.rar > tftp.c


 
/****************************************************************************** 
* Filename     : tftp.c                                                       * 
* Program      : loader.                                                      * 
* Copyright    : Copyright (C) 2001, Young-Su, Ahn.                           * 
* Author       : Young-Su, Ahn                            * 
* Description  : Use Tftp.                                                    * 
*                Make tftp packet and transmit it.                            * 
*                Handling received Tftp packet.                               * 
* Created at   : Wed Mar 13 2001.                                             * 
* Based on     : pptboot-0.5.3, CS8900A device driver.                        * 
* Modified by  :                                                              * 
* Modified at  :                                                              * 
******************************************************************************/ 
/* This program is free software; you can redistribute it and/or modify 
 * it under the terms of the GNU General Public License as published by 
 * the Free Software Foundation; either version 2 of the License, or 
 * (at your option) any later version. 
 * 
 * This program is distributed in the hope that it will be useful, 
 * but WITHOUT ANY WARRANTY; without even the implied warranty of 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
 * GNU General Public License for more details. 
 */ 
 
#include "main.h" 
 
#define TFTP_PORT					69		// Well known TFTP port # 
#define TFTP_TIMEOUT				5		// Seconds to tftpTimeout for a lost pkt 
#define TIMEOUT_COUNT				10		// # of tftpTimeouts before giving up 
 
// TFTP operations. 
#define TFTP_RRQ					1 
#define TFTP_WRQ					2 
#define TFTP_DATA					3 
#define TFTP_ACK					4 
#define TFTP_ERROR					5 
 
 
#define TFTP_NONE					0 
#define TFTP_STATE_RRQ				1 
#define TFTP_STATE_DATA				2 
#define TFTP_STATE_TOO_LARGE		3 
#define TFTP_STATE_BAD_MAGIC		4 
#define TFTP_STATE_SUCCESS			5 
#define TFTP_STATE_FAILURE			6 
 
 
static short	tftpState = 0; 
static short	tftpBlock = 0; 
static short	tftpLastBlock = 0; 
static U32		loadAddr = 0; 
short			tftpPort = 69; 
short			tftpHostPort=0; 
short			tftpClientPort = 7777; 
static char		requestFile[128]; 
static U32		tftpTimeout; 
 
// Prototypes. 
//bool			TftpStart(char *filename); 
bool			TftpStart(int itype); 
void			TftpTx(char *txBuf); 
 
/**********************************************************************/ 
// ¿ªÇÒ : tftp [filename] [addr]ÀÇ ÀÎÀÚ¸¦  tftp¸¦ ½ÇÇàÇϱâ À§ÇÑ ÇÔ¼ö¿Í  
//        ¿¬°á. 
// ¸Å°³ :  
// ¹Ýȯ : ¼º°øÇϸé true, ½ÇÆÐÇϸé false. 
// ÁÖÀÇ :  
bool DoTftp(int itype) 
{ 
	// tftp·Î ¹ÞÀº file data¸¦ ±â·ÏÇÒ ÁÖ¼Ò¸¦ »ý¼º. 
	if (itype==0) 
	{ 
		loadAddr = (U32)KERNEL_DRAM_BASE; 
	} 
	else if(itype==1) 
	{ 
		loadAddr = (U32)RAMDISK_DRAM_BASE; 
	} 
	else 
	{ 
		loadAddr = (U32)LOADER_DRAM_DOWN_BASE;	 
	} 
 
 
	// IP°¡ ¾øÀ¸¸é bootp¸¦ ½ÇÇàÇÏ¿© IP¸¦ ÇÒ´ç ¹ÞÀ½. 
	if (clientIP==0){ 
		Serial_Printf("\tNo IP. Bootp start...\n\r"); 
		if (DoBootp()==false) 
		{ 
			Serial_Printf("\tBootp failed. try again.\n\r"); 
			return false; 
		} 
	} 
 
	return TftpStart(itype); 
 
}	// DoTftp. 
 
 
// ¿ªÇÒ : tftp¸¦ ½ÇÇàÇÒ È¯°æ Ãâ·Â. 
// ¸Å°³ :  
// ¹Ýȯ : ¼º°øÇϸé true, ½ÇÆÐÇϸé false. 
// ÁÖÀÇ :  
//bool TftpStart(char *filename) 
 
 
 
bool TftpStart(int itype) 
{ 
	char		*txPktBuf, *rxPktBuf; 
	char 		*kfd="zImage"; 
	char 		*rfd="ramdisk.gz"; 
	char 		*bfd="kloader.bin"; 
 
 
	txPktBuf = (char *)PktBuf; 
	rxPktBuf = (char *)PktBuf; 
	 
	 
	Serial_Printf("\ni-type = %d\n",itype); 
	 
	 
	// tftp ½ÇÇà ȯ°æ Ãâ·Â. 
	Serial_Printf("TFTP Start...\n\r"); 
	 
	Serial_Printf("\tHost   (server) IP       : "); 
	PrintIPAddr(hostIP); 
	Serial_Printf("\n\r"); 
	 
	Serial_Printf("\tClient (target) IP       : "); 
	PrintIPAddr(clientIP); 
	Serial_Printf("\n\r"); 
 
	if(itype == 0) StrCpy(requestFile, kfd); 
	else if(itype == 1) StrCpy(requestFile, rfd); 
	else StrCpy(requestFile, bfd); 
 
	Serial_Printf("\tLoading Filename         : %s",requestFile); 
	Serial_Printf("\n\r"); 
 
	Serial_Printf("\tSave Address             : 0x%x",loadAddr); 
	Serial_Printf("\n\r"); 
	 
	Serial_Printf("\n\r\rLoading start...\n\r"); 
 
	// tftp ½ÃÀÛ È¯°æ. 
	protocol = PROT_TFTP; 
	tftpState = TFTP_STATE_RRQ; 
	tftpHostPort = 0; 
 
	// tftp request packet Àü¼Û. 
	TftpTx(txPktBuf); 
 
	// tftpTimeoutÀº À̰÷¿¡¼­ Á¤Çϸç, tftp data packetÀ» ¹ÞÀ» ¶§¸¶´Ù °»½ÅµÈ´Ù. 
	// ½Ã°£ÀÌ ÃʰúÇϸé tftp´Â ½ÇÆÐ·Î °£ÁÖÇϰí Áß´ÜÇÑ´Ù. 
	tftpTimeout = GetTime() + TFTP_TIMEOUT * HZ; 
	 
	// tftp°¡ ¼º°øÇϰųª ½ÇÆÐÇÒ ¶§±îÁö tftp data pakcetÀ» ¼ö½Å. 
	while (tftpState!=TFTP_STATE_SUCCESS && tftpState!=TFTP_STATE_FAILURE){ 
		RxPacket(rxPktBuf); 
		// ½Ã°£ Ãʰú¸é ½ÇÆÐÇϰí Áß´Ü. 
		if (GetTime()>tftpTimeout){ 
			Serial_Printf("\n\r\tTftp is failed. Try again.\n\r\n\r"); 
			tftpState=TFTP_STATE_FAILURE; 
		} 
	} 
 
	// ´ÙÀ½ tftp ½ÇÇàÀ» À§ÇØ È¯°æÀ» µÇµ¹¸². 
	protocol = NOPROTOCOL; 
	tftpState = TFTP_NONE; 
	tftpBlock = 0; 
	tftpHostPort = 0; 
	return true; 
}	// TftpStart. 
 
 
// ¿ªÇÒ : tftp°¡ ÇÊ¿ä·Î ÇÏ´Â packetÀ» ¸¸µé¾î Àü¼Û.. 
// ¸Å°³ :  
// ¹Ýȯ : ¼º°øÇϸé true, ½ÇÆÐÇϸé false. 
// ÁÖÀÇ :  
void TftpTx(char *txPktBuf) 
{ 
	char		*pktPtr = (char *)(txPktBuf+ETHER_HDR_SIZE+IP_HDR_SIZE+UDP_HDR_SIZE); 
	U16		hostPort = 0; 
	int			len = 0; 
 
//	Serial_Printf("  ",tftpState); 
//	MemSet(txPktBuf, 0, MAX_PKT_SIZE); 
	MemSet(txPktBuf-(ETHER_HDR_SIZE+IP_HDR_SIZE+UDP_HDR_SIZE), 0, MAX_PKT_SIZE);	 
	// make tftp header. 
	switch (tftpState){ 
		// tftp request packetÀ» ¸¸µë. 
		case TFTP_STATE_RRQ: 
			*((U16 *)pktPtr)++ = SWAP16(TFTP_RRQ); 
			StrCpy((char *)pktPtr, requestFile); 
			pktPtr += StrLen(requestFile) + 1; 
			StrCpy((char *)pktPtr, "octet"); 
			pktPtr += 5 + 1; 
			len = pktPtr - txPktBuf; 
			hostPort = tftpPort; 
			break; 
 
		// ¼ö½ÅÇÑ data packet¿¡ ´ëÇÑ acknowledge packetÀ» ¸¸µë. 
		case TFTP_STATE_DATA: 
			*((U16 *)pktPtr)++ = SWAP16(TFTP_ACK); 
			*((U16 *)pktPtr)++ = SWAP16(tftpBlock); 
			len = pktPtr - txPktBuf; 
			hostPort = tftpHostPort; 
			break; 
 
		// error packetÀ» ¸¸µë. 
		case TFTP_STATE_TOO_LARGE: 
			*((U16 *)pktPtr)++ = SWAP16(TFTP_ERROR); 
			*((U16 *)pktPtr)++ = SWAP16(3); 
			StrCpy((char *)pktPtr, "File too large"); 
			pktPtr += 14 + 1; 
			len = pktPtr - txPktBuf; 
			hostPort = tftpHostPort; 
 
			break; 
 
		// error packetÀ» ¸¸µë. 
		case TFTP_STATE_BAD_MAGIC: 
			*((U16 *)pktPtr)++ = SWAP16(TFTP_ERROR); 
			*((U16 *)pktPtr)++ = SWAP16(2); 
			StrCpy((char *)pktPtr, "File has bad magic"); 
			pktPtr += 18 + 1; 
			len = pktPtr - txPktBuf; 
			hostPort = tftpHostPort; 
			break; 
		default : 
			return; 
	} 
	// Ethernet, IP, UDP Header¸¦ ¸¸µë. 
	SetUdpHeader((char *)(txPktBuf+ETHER_HDR_SIZE+IP_HDR_SIZE), hostPort, tftpClientPort, len); 
	SetIPHeader((char *)(txPktBuf+ETHER_HDR_SIZE), clientIP, hostIP, UDP_HDR_SIZE+len); 
	SetEtherHeader(txPktBuf, (char *)hostEther, PROT_IP); 
 
	// tftp packet Àü¼Û. 
	TxPacket(txPktBuf, ETHER_HDR_SIZE+IP_HDR_SIZE+UDP_HDR_SIZE+len); 
	return; 
}	// TftpTx. 
 
 
// ¿ªÇÒ : tftp packetÀ» ¹Þ¾Æ ó¸®. 
// ¸Å°³ :  
// ¹Ýȯ : ¼º°øÇϸé true, ½ÇÆÐÇϸé false. 
// ÁÖÀÇ :  
bool TftpRx(char *rxPktBuf, int len){ 
	char			*pktPtr = rxPktBuf; 
	short			value; 
	U32			rlen=0;			// tftp·Î Àü¼Û¹ÞÀº dataÀÇ ±æÀÌ(Àӽà buffer). 
	 
	// handling received data. 
	value = SWAP16(*(short *)pktPtr);	// packet type. 
//	Serial_Printf("  ",value); 
	pktPtr+=2; 
	len-=2; 
	switch (value){ 
		case TFTP_RRQ : 
		case TFTP_WRQ : 
		case TFTP_ACK : 
		default: 
			break; 
		// tftp data packet. 
		case TFTP_DATA : 
			// error. check data index. 
			if (len < 2)  
			{ 
				Serial_Printf("\nLength err ");  
				return false; 
			}	 
			//Serial_Printf("\nBlockNo - 0x%x",*(U16 *)pktPtr); 
			tftpBlock = SWAP16(*(U16 *)pktPtr);	// tftp data packet¿¡¼­ block ¹øÈ£. 
			pktPtr += 2; 
			len -= 2; 
			// tftp receive ÁøÇà Ç¥½Ã. 
			if (((tftpBlock)%128)==0){	// each 64 kbyte. 
			 
				//ClearLine(); 
				rlen = (long)tftpBlock * 512; 
				Serial_Printf("\n0x%08lx bytes received.", rlen); 
			} 
 
			// request¿¡ ´ëÇÑ Ã¹¹øÂ° data packetÀ϶§ ÇÊ¿äÇÑ Á¤º¸ ¼³Á¤. 
			if (tftpState == TFTP_STATE_RRQ) 
			{ 
				tftpState = TFTP_STATE_DATA; 
				tftpLastBlock = 0; 
				if (tftpBlock != 1){ 
					tftpState = TFTP_STATE_FAILURE; 
					return false; 
				} 
			} 
			// ÀÌÀüÀÇ packetÀ» ´Ù½Ã ¹Þ¾ÒÀ» ¶§´Â ¹«½Ã. 
//			Serial_Printf("  ", tftpBlock); 
			if (tftpBlock <= tftpLastBlock) break; 
 
			tftpLastBlock = tftpBlock; 
	 
			// ¼ö½ÅÇÑ tftp packetÀÇ data ºÎºÐÀ» ÁöÁ¤ÇÑ memory ¿µ¿ª¿¡ ±â·Ï. blockÀº 512 byte ´ÜÀ§. 
			MemCpy((char *)(loadAddr+(tftpBlock-1)*512), (char *)pktPtr, len); 
 
			// TftpStart()¿¡¼­ checkÇÏ´Â tftpTimeout ½Ã°£À» °»½Å. 
			tftpTimeout = GetTime() + TFTP_TIMEOUT * HZ; 
			 
			// Acknowledge¸¦ º¸³¿. À̰ÍÀ» ¹ÞÀº ÈÄ server´Â ´ÙÀ½ blockÀÇ data¸¦ °¡Áø packetÀ» Àü¼Û. 
			TftpTx(rxPktBuf); 
 
			// ¼ö½ÅÇÑ tftp packetÀÌ dataÀÇ ¸¶Áö¸· blockÀÏ ¶§. 
			if (len < 512){ 
				// We received the whole thing.  Try to run it. 
				//ClearLine(); 
				rlen = ((long)tftpBlock-1) * 512 + len; 
				Serial_Printf("\n0x%08lx (%ld) bytes received.", rlen, rlen); 
				Serial_Printf("\nftp done.\n\n"); 
				tftpState = TFTP_STATE_SUCCESS;				 
			} 
			break; 
		// error ó¸®. 
		case TFTP_ERROR : 
			// tftp RRQ or tftp ack pakcet has some error. 
			Serial_Printf("\n\r\rTFTP error: '"); 
			Serial_Printf(pktPtr+2); 
			Serial_Printf("' ("); 
			OutputDec(SWAP16(*(U16 *)pktPtr)); 
			Serial_Printf(")\n\r"); 
			tftpState = TFTP_STATE_FAILURE; 
			break; 
	} 
	return true; 
}	// TftpRx.