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

📄 tftp.c

📁 windows mobile 5 下的底层驱动包
💻 C
📖 第 1 页 / 共 2 页
字号:
//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft end-user
// license agreement (EULA) under which you licensed this SOFTWARE PRODUCT.
// If you did not accept the terms of the EULA, you are not authorized to use
// this source code. For a copy of the EULA, please see the LICENSE.RTF on your
// install media.
//
/*++
THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
PARTICULAR PURPOSE.

Module Name:  
    tftp.c
Abstract:  

    This contains the TFTP client routines for the bootloader.
    For the most part, these operate on top of the udp.c module.
	There are some global data structures that are shared with
	the tftpd.c module.
    
Functions:


Notes: 

--*/
#include <windows.h>
#include <udp.h>
#include <tftp.h>


// These are the UDP port numbers that are used for the TFTP servers on the Odo and Host sides
UINT16 wOdoWellKnownServerPort, wHostWellKnownServerPort;
TFtpLinkRec TFtpLinks[MAX_TFTP_LINKS];	// Data records for each of the possible TFTP links
UINT16 nNumTFtpLinksInUse;				// The number of active TFTP links

BYTE TFTPFrameBuffer[MAX_TFTP_DATA + UDP_DATA_FRAME_OFFSET];

void EbootInitTFtp( UINT16 wOdoWKSP, UINT16 wHostWKSP ) {

	int i;

	for( i = 0; i < MAX_TFTP_LINKS; i++ )
		TFtpLinks[i].State = TFTP_STATE_IDLE;

	wOdoWellKnownServerPort = wOdoWKSP;
	wHostWellKnownServerPort = wHostWKSP;

	nNumTFtpLinksInUse = 0;

}


// This routine handles the multiplexing of all active TFTP links.	It returns 0 if there was no valid link formed,
//	or 1 of there was.
WORD EbootTFtpReceiver( EDBG_ADDR *pMyAddr, BYTE *pFrameBuffer, UINT16 wDestPort, UINT16 wSrcPort, UINT16 *pwUDPData, UINT16 cwUDPDataLength ) {

	int i;
    UINT16 iLinkSlot = MAX_TFTP_LINKS;

	// Check to see if this is for a link that is currently in use
	for( i = 0; i < MAX_TFTP_LINKS; i++ ) {
		// Here I don't compare the destination (Odo) port, only the source (host) because
		//	this could be a repeat open packet, which we don't want to cause a second link.
		//	This could happen if a second open packet comes because we will have changed the
		//	destination port with the acknowledge.
		if (TFtpLinks[i].State != TFTP_STATE_IDLE && wSrcPort == TFtpLinks[i].DestAddr.wPort
			&& wDestPort == TFtpLinks[i].SrcAddr.wPort) {
			iLinkSlot = i;
			break;
		}
		else if (TFtpLinks[i].State == TFTP_STATE_IDLE)
			iLinkSlot = i;
	}

	// If we broke out of the loop early, then the packet is for a link that is already open
	if (i < MAX_TFTP_LINKS) {
		// iLinkSlot is the index of the link this packet belongs too
		TFtpStateMachine( wSrcPort, iLinkSlot, pwUDPData, cwUDPDataLength );
	}
	// Check to see if someone is trying to start a new connection, 
	// If so, guarantee that there are always TFTP_TX_LINKS link(s) available to transmit information
	else if (wDestPort == wOdoWellKnownServerPort && MAX_TFTP_LINKS - nNumTFtpLinksInUse > TFTP_TX_LINKS) {

		// iLinkSlot is the index of a link that is in the IDLE state, giving the number of a free link
		//	slot that can be used, the wDestTID and the TFTP Message
		TFtpdFormNewLink( pMyAddr, pFrameBuffer, iLinkSlot, pwUDPData );
		return 1;
	}
	else {

        for( i = 0; i < MAX_TFTP_LINKS; i++ ) {
            EdbgOutputDebugString("TFTP link[%u]: State:%u, DestAddr.wPort: %u, SrcAddr.wPort: %u\n",
                               i,TFtpLinks[i].State, ntohs(TFtpLinks[i].DestAddr.wPort),
                               ntohs(TFtpLinks[i].SrcAddr.wPort));
            }
		EdbgOutputDebugString("TftpReceiver, port: 0x%X, wkp: 0x%X\n\r",wDestPort,wOdoWellKnownServerPort);
    }

	return 0;

} // TFtpReceiver()



// This routine will go through and check all the links to perform retransmits and eventual timeouts.
// It uses the same retransmit strategy as DHCP, which is an exponential back off.	It starts with 
//	4 seconds, then 8, 16 ... up to the last retry at 64 seconds for MAX_RETRIES = 5.
void TFTPRetransmit( void ) {

	DWORD dwCurrentTime;
	int i;

	dwCurrentTime = OEMEthGetSecs();
	for( i = 0; i < MAX_TFTP_LINKS; i++ )
		if (TFtpLinks[i].State != TFTP_STATE_IDLE &&
			dwCurrentTime - TFtpLinks[i].tLastTransmit >= (4UL << TFtpLinks[i].cwRetries)) {
			// If there are still retries left, try again
			if (TFtpLinks[i].cwRetries <= MAX_RETRIES) {
				if (!EbootSendUDP(TFTPFrameBuffer, &(TFtpLinks[i].DestAddr), &(TFtpLinks[i].SrcAddr), TFtpLinks[i].Buffer, TFtpLinks[i].cwMsgLen ))
					EdbgOutputDebugString( "TFTPRetransmit()::Error On SendUDP() Call\r\n" );
				TFtpLinks[i].tLastTransmit = dwCurrentTime;
				TFtpLinks[i].cwRetries++;
			}
			// Otherwise, the link should be timed out, so send an error packet and then discard the link
			else
				TFtpKillLink( (UINT16)i, TFTP_ERROR_UNDEFINED, "Linked Timed Out By Odo" );
			EdbgOutputDebugString( "TFTPRetransmit() Slot %u, wDestTID %u, Retry %u\r\n",
				i, TFtpLinks[i].DestAddr.wPort, TFtpLinks[i].cwRetries );
		} // If it's time to do a retry at sending the packet
}



// This will format the pBuffer to be a TFTP Error message of the ErrorCode type and with
//	the human readable error message.
void TFtpKillLink( UINT16 iLinkSlot, TFtpErrors ErrorCode, char *pszErrorMessage ) {

	if (TFtpLinks[iLinkSlot].State == TFTP_STATE_IDLE)
		return;

	// Only send a packet if the error was generated on this end.  If it was generated by the host
	//	then we need not send anything back.
	if (ErrorCode != TFTP_ERROR_HOSTERROR) {
		// Put in the code for an error packet
		*((UINT16 *)(TFtpLinks[iLinkSlot].Buffer)) = htons(5);
		// Put in the type of error
		*((UINT16 *)(TFtpLinks[iLinkSlot].Buffer) + 1) = htons(ErrorCode);
		// Put in the error message itself
		strcpy( TFtpLinks[iLinkSlot].Buffer + 4, pszErrorMessage );
		TFtpLinks[iLinkSlot].cwMsgLen = 4 + strlen( pszErrorMessage ) + 1;

		EbootSendUDP(TFTPFrameBuffer, &(TFtpLinks[iLinkSlot].DestAddr), &(TFtpLinks[iLinkSlot].SrcAddr),
                     TFtpLinks[iLinkSlot].Buffer, TFtpLinks[iLinkSlot].cwMsgLen );
	}

	// If there is a callback function, inform it that the link is now dead
	if (TFtpLinks[iLinkSlot].pfCallBack != NULL) {
		TFtpdCallBack( iLinkSlot, TFTPD_DESTROY );
		TFtpLinks[iLinkSlot].State = TFTP_STATE_IDLE;
		nNumTFtpLinksInUse--;
	}
	// If this was an Odo client link, then we won't be able to inform the process of the error until it
	//	calls TFtpRead() or TFtpWrite() so transition to the TFTP_STATE_ERROR state until one of those
	//	routines is called
	else
		TFtpLinks[iLinkSlot].State = TFTP_STATE_ERROR;
}



// This routine will look at the current state of the link and at the data that is available and will
//	advance the link to the next state.	 This may entail sending an acknowledge packet, requesting data
//	from a server process, closing the link, etc.
void TFtpStateMachine( WORD wSrcPort, UINT16 iLinkSlot, UINT16 *pwMsg, UINT16 cwMsgLen ) {

	// If this is an error packet, kill the link right now
	if (ntohs(*pwMsg) == 5) {
		TFtpKillLink( iLinkSlot, TFTP_ERROR_HOSTERROR, NULL );
		EdbgOutputDebugString( "TFTP Error Received From Host %X - %s\n", *(pwMsg + 1), pwMsg + 2 );
		return;
	}

	switch( TFtpLinks[iLinkSlot].State ) {
		case TFTP_STATE_IDLE:
			// We shouldn't get called if the packet was for a link that's in the TFTP_STATE_IDLE state
			break;
		case TFTP_STATE_OPEN:
			// We will only get in this state if this is an H2OLink that we initiated, we're waiting
			//	for the host's write acknowledge packet
			if (ntohs(*pwMsg) == 4 && ntohs(*(pwMsg+1)) == 0)
				TFtpLinks[iLinkSlot].State = TFTP_STATE_XFER_BUSY;
			break;
		case TFTP_STATE_XFER_BUSY:
			// We are either waiting for the data to be taken out of the buffer by a read, or to be
			//	placed there by a write.  When one of those things happens, they will cause either an
			//	acknowledge or new data to be sent.	 For now, just ignore this packet.
			break;
		case TFTP_STATE_XFER_WAIT:
			if (TFtpLinks[iLinkSlot].DataDir == H2OLink) {
				// If this is the data packet we've been waiting for
				if (ntohs(*pwMsg) == 3) {
					if ((USHORT)(ntohs(*(pwMsg+1))) == (USHORT)(TFtpLinks[iLinkSlot].wBlockNumber+1)) {
						// If this was a brand new link we have to copy the dest TID off of the first packet
						if (TFtpLinks[iLinkSlot].wBlockNumber == 0)

⌨️ 快捷键说明

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