www.pudn.com > PPPOE.rar > pppoepkt.cpp


 
//******************************************************************** 
//	ÈÕÆÚ:	2004/08/24 - 24:8:2004   22:30 
//	Ãûǰ:	tiamo 
//	ÃèÊö:	pppoe 
//********************************************************************* 
 
#include "Stdafx.h" 
 
// insert tag in packet 
VOID PacketInsertTag(USHORT ucTag,PPACKET pPacket,PUCHAR pBuffer,USHORT usLen,PUCHAR *ppOutBuffer) 
{ 
	if(ppOutBuffer) 
		*ppOutBuffer = NULL; 
 
	USHORT usCurrentLen = ntohs(pPacket->m_pFrame->m_pppFrame.m_usLen); 
	USHORT usMaxLen = pPacket->m_pFrame->m_pppFrame.m_ucCode == PPPOE_CODE_PADI ? PPPOE_MAX_DATA_SIZE : PPPOE_MAX_PADI_DATA_SIZE; 
 
	// check size 
	if(usCurrentLen + usLen + sizeof(PPP_TAG) > usMaxLen) 
	{ 
		// must have a seh frame 
		ExRaiseStatus(NDIS_STATUS_BUFFER_OVERFLOW); 
	} 
 
	// set tag 
	PPPP_TAG pTag = reinterpret_cast(pPacket->m_pucDataBuffer + usCurrentLen); 
	pTag->m_usType = ucTag; 
	pTag->m_usLen = htons(usLen); 
 
	if(ppOutBuffer) 
		*ppOutBuffer = pPacket->m_pucDataBuffer + usCurrentLen + sizeof(PPP_TAG); 
 
	// check buffer pointer first,then copy it 
	if(pBuffer) 
	{ 
		NdisMoveMemory(pTag + 1,pBuffer,usLen); 
	} 
 
	// modify len 
	pPacket->m_pFrame->m_pppFrame.m_usLen = htons(usCurrentLen + usLen + sizeof(PPP_TAG)); 
} 
 
// prepare packet for send 
VOID PreparePacketForSend(PPACKET pPacket) 
{ 
	/* 
	*				Serive	AC		Host	ACCookie	Relay		 
	*				101		102		103		104			110 
	*	PAY_LOAD  
	*	PADT 
	*	PADI:		M				O 
	*	PADO:		M		O		O		O			O 
	*	PADR:		M				O		O			O 
	*	PADS:		M				O					O 
	*/ 
 
	switch(pPacket->m_pFrame->m_pppFrame.m_ucCode) 
	{ 
		// pay load 
	case PPPOE_CODE_PAY_LOAD: 
		// PADT 
	case PPPOE_CODE_PADT: 
		break; 
 
		// PADO 
	case PPPOE_CODE_PADO: 
		// 0x102 AC name 
		PacketInsertTag(PPPOE_TAG_AC,pPacket,pPacket->m_pACName,pPacket->m_usACName,&pPacket->m_pACName); 
 
		// fall through 
 
		// PADR 
	case PPPOE_CODE_PADR: 
		// 0x104 AC cookie 
		if(pPacket->m_pFrame->m_pppFrame.m_ucCode != PPPOE_CODE_PADR || pPacket->m_usACCookie) 
			PacketInsertTag(PPPOE_TAG_AC_COOKIE,pPacket,pPacket->m_pACCookie,pPacket->m_usACCookie,&pPacket->m_pACCookie); 
 
		// fall through 
 
		// PADS 
	case PPPOE_CODE_PADS: 
		// 0x110 relay session id 
		if(pPacket->m_usRelaySessionId) 
			PacketInsertTag(PPPOE_TAG_RELAY_SESSION_ID,pPacket,pPacket->m_pRelaySessionId,pPacket->m_usRelaySessionId, 
								 &pPacket->m_pRelaySessionId); 
 
		// fall through 
 
		// PADI 
	case PPPOE_CODE_PADI:	 
		// 0x101 service name 
		PacketInsertTag(PPPOE_TAG_SERVICE,pPacket,pPacket->m_pServiceName,pPacket->m_usServiceName,&pPacket->m_pServiceName); 
 
		// 0x103 host unique 
		if(pPacket->m_usHostUnique) 
			PacketInsertTag(PPPOE_TAG_HOST_UNIQUE,pPacket,pPacket->m_pHostUnique,pPacket->m_usHostUnique, 
								 &pPacket->m_pHostUnique); 
 
		break; 
	} 
 
	// set buffer len 
	NdisAdjustBufferLength(pPacket->m_pNdisDataBuffer,ntohs(pPacket->m_pFrame->m_pppFrame.m_usLen)); 
} 
 
// build packet for send 
PPACKET BuildPacketForSend(PCHANNEL pChannel,PNDIS_PACKET pOrgPacket) 
{ 
	PPACKET pRetPacket = NULL; 
 
	NDIS_STATUS status; 
 
	__try 
	{ 
		// alloc the packet 
		pRetPacket = AllocPacket(); 
 
		pRetPacket->m_pNdisPacket = GetNdisPacketFromPool(&g_poolPacket,&pRetPacket->m_pPacketItem); 
 
		PPROTOCOL_RESERVED pResv = reinterpret_cast(pRetPacket->m_pNdisPacket->ProtocolReserved); 
 
		pResv->m_pPacket = pRetPacket; 
		pResv->m_pOrginalPacket = pOrgPacket; 
		pResv->m_pChannel = pChannel; 
 
		// packet from pool 
		pRetPacket->m_ulFlags |= PPPOE_PACKET_FROM_POOL; 
 
		// packet len 
		UINT uLen; 
		NdisQueryPacketLength(pOrgPacket,&uLen); 
 
		// get data buffer,unchain if 
		NdisUnchainBufferAtFront(pOrgPacket,&pRetPacket->m_pNdisDataBuffer); 
 
		// send complete needed 
		pRetPacket->m_ulFlags |= PPPOE_PACKET_NEED_CALL_SEND_COMPLETE; 
 
		// chain data buffer first 
		NdisChainBufferAtFront(pRetPacket->m_pNdisPacket,pRetPacket->m_pNdisDataBuffer); 
		pRetPacket->m_ulFlags |= PPPOE_PACKET_DATA_BUFFER_CHAINED; 
 
		// allocate header buffer 
		NdisAllocateBuffer(&status,&pRetPacket->m_pNdisHeaderBuffer,g_hNdisBufferPool,&pRetPacket->m_ethFrame,PPPOE_HEADER_LEN); 
 
		// chain header buffer 
		NdisChainBufferAtFront(pRetPacket->m_pNdisPacket,pRetPacket->m_pNdisHeaderBuffer); 
		pRetPacket->m_ulFlags |= (PPPOE_PACKET_HEADER_BUFFER_CHAINED | PPPOE_PACKET_HEADER_BUFFER_FROM_NDIS); 
 
		// set frame pointer,data buffer do not need to set,we will not touch it; 
		pRetPacket->m_pFrame = &pRetPacket->m_ethFrame; 
 
		// copy dst and src mac addr 
		NdisMoveMemory(pRetPacket->m_pFrame->m_dstMac,pChannel->m_macPeer,ETH_ADDR_LEN); 
 
		NdisMoveMemory(pRetPacket->m_pFrame->m_srcMac,pChannel->m_macSelf,ETH_ADDR_LEN); 
 
		// set ethernet type 
		pRetPacket->m_pFrame->m_usProtocolType = PPPOE_SESSION; 
 
		// set session id 
		pRetPacket->m_pFrame->m_pppFrame.m_usSession = htons(pChannel->m_usSessionId); 
 
		// set other 
		pRetPacket->m_pFrame->m_pppFrame.m_ucCode = PPPOE_CODE_PAY_LOAD; 
		pRetPacket->m_pFrame->m_pppFrame.m_ucType = PPPOE_TYPE; 
		pRetPacket->m_pFrame->m_pppFrame.m_ucVer = PPPOE_VER; 
		pRetPacket->m_pFrame->m_pppFrame.m_usLen = htons(static_cast(uLen)); 
 
		// prepare it 
		PreparePacketForSend(pRetPacket); 
 
		// inc send packets 
		NdisInterlockedIncrement(&pChannel->m_lSendingPackets); 
	} 
	__except(EXCEPTION_EXECUTE_HANDLER) 
	{ 
		if(pRetPacket) 
		{ 
			DereferencePacket(pRetPacket); 
 
			pRetPacket = NULL; 
		} 
	} 
 
	return pRetPacket; 
} 
 
// init packet member value 
BOOLEAN InitializePacketForRecved(PPACKET pPacket) 
{ 
	/* 
	*				Serive	AC		Host	ACCookie	Relay		 
	*				101		102		103		104			110 
	*	PAY_LOAD  
	*	PADT 
	*	PADI:		M				O					O 
	*	PADO:		M		M		O		O			O 
	*	PADR:		M				O		O			O 
	*	PADS:		M				O					 
	*/ 
 
	// check pppoe format 
	if(!CheckIsPPPoEPacket(pPacket)) 
		return FALSE; 
 
 
	// check len 
	UCHAR ucCode = pPacket->m_pFrame->m_pppFrame.m_ucCode; 
 
	// ctrl packet only check len 
	if(ucCode) 
	{ 
		PUCHAR pEnd = pPacket->m_pucDataBuffer + ntohs(pPacket->m_pFrame->m_pppFrame.m_usLen); 
		PUCHAR pCurrent = pPacket->m_pucDataBuffer; 
 
		while(pCurrent < pEnd) 
		{ 
			PPPP_TAG pTag = reinterpret_cast(pCurrent); 
			pCurrent += ntohs(pTag->m_usLen) + sizeof(PPP_TAG); 
		} 
 
		if(pCurrent != pEnd) 
			return FALSE; 
	} 
 
	// build member value 
	switch(pPacket->m_pFrame->m_pppFrame.m_ucCode) 
	{ 
	case PPPOE_CODE_PAY_LOAD: 
	case PPPOE_CODE_PADT: 
		break; 
 
		// PADO 
	case PPPOE_CODE_PADO: 
		{ 
			// get service name 
			RetrieveTag(PPPOE_TAG_SERVICE,pPacket,&pPacket->m_pServiceName,&pPacket->m_usServiceName,TRUE); 
 
			if(pPacket->m_pServiceName) 
			{ 
				// get ac name 
				RetrieveTag(PPPOE_TAG_AC,pPacket,&pPacket->m_pACName,&pPacket->m_usACName,TRUE); 
 
				if(pPacket->m_pACName) 
				{ 
					// ac cookie 
					RetrieveTag(PPPOE_TAG_AC_COOKIE,pPacket,&pPacket->m_pACCookie,&pPacket->m_usACCookie,TRUE); 
 
					// host unique 
					RetrieveTag(PPPOE_TAG_HOST_UNIQUE,pPacket,&pPacket->m_pHostUnique,&pPacket->m_usHostUnique,TRUE); 
 
					// relay session id 
					RetrieveTag(PPPOE_TAG_RELAY_SESSION_ID,pPacket,&pPacket->m_pRelaySessionId,&pPacket->m_usRelaySessionId,TRUE); 
				} 
			} 
		} 
		break; 
 
		// PADI 
	case PPPOE_CODE_PADI: 
		{ 
			// get service name 
			RetrieveTag(PPPOE_TAG_SERVICE,pPacket,&pPacket->m_pServiceName,&pPacket->m_usServiceName,TRUE); 
 
			if(pPacket->m_pServiceName) 
			{ 
				// host unique 
				RetrieveTag(PPPOE_TAG_HOST_UNIQUE,pPacket,&pPacket->m_pHostUnique,&pPacket->m_usHostUnique,TRUE); 
 
				// relay session id 
				RetrieveTag(PPPOE_TAG_RELAY_SESSION_ID,pPacket,&pPacket->m_pRelaySessionId,&pPacket->m_usRelaySessionId,TRUE); 
			} 
		} 
		break; 
 
		// PADR 
	case PPPOE_CODE_PADR: 
		{ 
			// get service name 
			RetrieveTag(PPPOE_TAG_SERVICE,pPacket,&pPacket->m_pServiceName,&pPacket->m_usServiceName,TRUE); 
 
			if(pPacket->m_pServiceName) 
			{ 
				// ac cookie 
				RetrieveTag(PPPOE_TAG_AC_COOKIE,pPacket,&pPacket->m_pACCookie,&pPacket->m_usACCookie,TRUE); 
 
				// host unique 
				RetrieveTag(PPPOE_TAG_HOST_UNIQUE,pPacket,&pPacket->m_pHostUnique,&pPacket->m_usHostUnique,TRUE); 
 
				// relay session id 
				RetrieveTag(PPPOE_TAG_RELAY_SESSION_ID,pPacket,&pPacket->m_pRelaySessionId,&pPacket->m_usRelaySessionId,TRUE); 
			} 
		} 
		break; 
 
		// PADS 
	case PPPOE_CODE_PADS: 
		{ 
			// get service name 
			RetrieveTag(PPPOE_TAG_SERVICE,pPacket,&pPacket->m_pServiceName,&pPacket->m_usServiceName,TRUE); 
 
			if(pPacket->m_pServiceName) 
			{ 
				// host unique 
				RetrieveTag(PPPOE_TAG_HOST_UNIQUE,pPacket,&pPacket->m_pHostUnique,&pPacket->m_usHostUnique,TRUE); 
			} 
		} 
		break; 
	} 
 
	// get error tag 
	RetrieveErrorTag(pPacket); 
 
	return TRUE; 
} 
 
// convert recved ndis packet 
PPACKET ConvertRecvedNdisPacket(PBIND_CONTEXT pBind,PNDIS_PACKET pNdisPacket,PBOOLEAN pNeedCallReturn) 
{ 
	*pNeedCallReturn = FALSE; 
 
	PPACKET pPacket = NULL; 
 
	PNDIS_BUFFER pFirstBuffer = NULL; 
 
	UINT nBufferCount = 0; 
	UINT nTotalLen = 0; 
 
	// query packet 
	NdisQueryPacket(pNdisPacket,NULL,&nBufferCount,&pFirstBuffer,&nTotalLen); 
 
	// check len 
	if(nTotalLen > PPPOE_MAX_ETH_FRAME_SIZE) 
		return NULL; 
 
	// get status 
	NDIS_STATUS status = NDIS_GET_PACKET_STATUS(pNdisPacket); 
 
	// we can use the buffer in the packet 
	if(status != NDIS_STATUS_RESOURCES && nBufferCount == 1) 
	{ 
		PPPPOE_FRAME pFrame; 
		UINT uLen; 
 
		// query buffer 
		NdisQueryBufferSafe(pFirstBuffer,(PVOID *)&pFrame,&uLen,NormalPagePriority); 
 
		// check return value 
		if(pFrame && uLen > PPPOE_MIN_ETH_FRAME_SIZE) 
		{ 
			// check pppoe frame 
			if(FastCheckIsPPPoEFrame(pFrame,PPPOE_MIN_ETH_FRAME_SIZE)) 
			{ 
				// check frame size 
				if((UINT)ntohs(pFrame->m_pppFrame.m_usLen) <= uLen) 
				{ 
					// reuse the buffers 
					pPacket = ReuseRecvedPacketBuffer(pBind,pNdisPacket,pFrame,nTotalLen); 
				} 
			} 
		} 
 
		if(pPacket) 
		{ 
			*pNeedCallReturn = TRUE; 
			NdisInterlockedIncrement(&pBind->m_lPacketNeedReturn); 
		} 
	} 
	else 
	{ 
		// create new packet 
		pPacket = GetSimplePacket(); 
 
		UINT uCurrentOffset = 0; 
 
		PUCHAR pFrame; 
		UINT uLen; 
 
		for(;pFirstBuffer;) 
		{	 
			// query buffer 
			NdisQueryBufferSafe(pFirstBuffer,(PVOID *)&pFrame,&uLen,NormalPagePriority); 
 
			NdisMoveMemory(pPacket->m_pucFrame + uCurrentOffset,pFrame,uLen); 
 
			uCurrentOffset += uLen; 
 
			NdisGetNextBuffer(pFirstBuffer,&pFirstBuffer); 
 
			if(uCurrentOffset < PPPOE_MIN_ETH_FRAME_SIZE) 
				continue; 
 
			if(!FastCheckIsPPPoEFrame(pPacket->m_pFrame,PPPOE_MIN_ETH_FRAME_SIZE)) 
			{ 
				uCurrentOffset = 0; 
				break; 
			} 
		} 
 
		// check the packet 
		if(uCurrentOffset < PPPOE_MIN_ETH_FRAME_SIZE || uCurrentOffset < nTotalLen) 
			DereferencePacket(pPacket); 
	} 
 
	return pPacket; 
} 
 
// fast check pppoe frame 
BOOLEAN FastCheckIsPPPoEFrame(PPPPOE_FRAME pFrame,ULONG ulSize) 
{ 
	if(ulSize != PPPOE_MIN_ETH_FRAME_SIZE) 
		return FALSE; 
 
	if(pFrame->m_usProtocolType != PPPOE_DISCOVERY && pFrame->m_usProtocolType != PPPOE_SESSION) 
		return FALSE; 
 
	return TRUE; 
} 
 
// full check pppoe packet 
BOOLEAN CheckIsPPPoEPacket(PPACKET pPacket) 
{ 
	if(pPacket->m_pFrame->m_usProtocolType != PPPOE_DISCOVERY && pPacket->m_pFrame->m_usProtocolType != PPPOE_SESSION) 
		return FALSE; 
 
	if(pPacket->m_pFrame->m_pppFrame.m_ucVer != PPPOE_VER || pPacket->m_pFrame->m_pppFrame.m_ucType != PPPOE_TYPE) 
		return FALSE; 
 
	if(ntohs(pPacket->m_pFrame->m_pppFrame.m_usLen) > PPPOE_MAX_DATA_SIZE) 
		return FALSE; 
 
	BOOLEAN bRet = FALSE; 
 
	if( pPacket->m_pFrame->m_pppFrame.m_ucCode == PPPOE_CODE_PAY_LOAD ||  
		pPacket->m_pFrame->m_pppFrame.m_ucCode == PPPOE_CODE_PADT ||  
		pPacket->m_pFrame->m_pppFrame.m_ucCode == PPPOE_CODE_PADS) 
	{ 
		bRet = pPacket->m_pFrame->m_pppFrame.m_usSession != 0; 
	} 
	else 
	{ 
		bRet = pPacket->m_pFrame->m_pppFrame.m_usSession == 0; 
	} 
 
	return bRet; 
} 
 
// reuse recved packet buffer 
PPACKET ReuseRecvedPacketBuffer(PBIND_CONTEXT pBind,PNDIS_PACKET pNdisPacket,PPPPOE_FRAME pFrame,UINT uLen) 
{ 
	PPACKET pRet = NULL; 
	__try 
	{ 
		pRet = AllocPacket(); 
 
		// unchain org buffer 
		NdisUnchainBufferAtFront(pNdisPacket,&pRet->m_pNdisReturnBuffer); 
 
		// need return 
		pRet->m_ulFlags |= PPPOE_PACKET_NEED_RETURN_PACKET; 
 
		// reuse packet 
		pRet->m_pNdisPacket = pNdisPacket; 
 
		// copy frame 
		pRet->m_pFrame = &pRet->m_ethFrame; 
 
		NdisMoveMemory(pRet->m_pFrame,pFrame,PPPOE_HEADER_LEN); 
 
		// set data buffer 
		pRet->m_pRealBuffer = pFrame + 1; 
 
		// bind context 
		pRet->m_pBindContext = pBind; 
 
		NDIS_STATUS status; 
 
		// allocate data buffer 
		NdisAllocateBuffer(&status,&pRet->m_pNdisDataBuffer,g_hNdisBufferPool,pRet->m_pucDataBuffer,uLen - PPPOE_HEADER_LEN); 
 
		if(status != NDIS_STATUS_SUCCESS) 
			ExRaiseStatus(status); 
 
		pRet->m_ulFlags |= PPPOE_PACKET_DATA_BUFFER_FROM_NDIS; 
 
		// allocate header buffer 
		NdisAllocateBuffer(&status,&pRet->m_pNdisHeaderBuffer,g_hNdisBufferPool,pRet->m_pFrame,PPPOE_HEADER_LEN); 
 
		if(status != NDIS_STATUS_SUCCESS) 
			ExRaiseStatus(status); 
 
		pRet->m_ulFlags |= PPPOE_PACKET_HEADER_BUFFER_FROM_NDIS; 
 
		// chain data buffer 
		NdisChainBufferAtFront(pRet->m_pNdisPacket,pRet->m_pNdisDataBuffer); 
		pRet->m_ulFlags |= PPPOE_PACKET_DATA_BUFFER_CHAINED; 
 
		// chain header buffer 
		NdisChainBufferAtFront(pRet->m_pNdisPacket,pRet->m_pNdisHeaderBuffer); 
		pRet->m_ulFlags |= PPPOE_PACKET_HEADER_BUFFER_CHAINED; 
	} 
	__except(EXCEPTION_EXECUTE_HANDLER) 
	{ 
		if(pRet) 
			DereferencePacket(pRet); 
 
		pRet = NULL; 
	} 
 
	return pRet; 
} 
 
// get tag from buffer 
VOID RetrieveTag(USHORT usTag,PPACKET pPacket,PUCHAR *ppBuffer,PUSHORT pBufferLen,BOOLEAN bSaveToPacket) 
{ 
	*ppBuffer = NULL; 
	*pBufferLen = 0; 
 
	// check code first 
	if(!pPacket->m_pFrame->m_pppFrame.m_ucCode) 
		return; 
 
	PUCHAR pTagBuffer = NULL; 
	USHORT usTagLen = 0; 
 
	PUCHAR pCurrent = pPacket->m_pucDataBuffer; 
	PUCHAR pEnd = pCurrent + ntohs(pPacket->m_pFrame->m_pppFrame.m_usLen); 
 
	// loop find 
	while(pCurrent < pEnd) 
	{ 
		PPPP_TAG pTag = reinterpret_cast(pCurrent); 
		if(pTag->m_usType == usTag) 
		{ 
			pTagBuffer = pCurrent + sizeof(PPP_TAG); 
			usTagLen = ntohs(pTag->m_usLen); 
			break; 
		} 
 
		pCurrent += ntohs(pTag->m_usLen) + sizeof(PPP_TAG); 
	} 
 
	// save 
	*ppBuffer = pTagBuffer; 
	*pBufferLen = usTagLen; 
 
	// save it to packet 
	if(pTagBuffer && bSaveToPacket) 
	{ 
		switch(usTag) 
		{ 
		case PPPOE_TAG_SERVICE: 
			pPacket->m_pServiceName = pTagBuffer; 
			pPacket->m_usServiceName = usTagLen; 
			break; 
 
		case PPPOE_TAG_AC: 
			pPacket->m_pACName = pTagBuffer; 
			pPacket->m_usACName = usTagLen; 
			break; 
 
		case PPPOE_TAG_AC_COOKIE: 
			pPacket->m_pACCookie = pTagBuffer; 
			pPacket->m_usACCookie = usTagLen; 
			break; 
 
		case PPPOE_TAG_HOST_UNIQUE: 
			pPacket->m_pHostUnique = pTagBuffer; 
			pPacket->m_usHostUnique = usTagLen; 
			break; 
 
		case PPPOE_TAG_RELAY_SESSION_ID: 
			pPacket->m_pRelaySessionId = pTagBuffer; 
			pPacket->m_usRelaySessionId = usTagLen; 
			break; 
 
		case PPPOE_TAG_SERVICE_NAME_ERROR: 
		case PPPOE_TAG_AC_SYSTEM_ERROR: 
		case PPPOE_TAG_GEN_ERROR: 
			pPacket->m_pError = pTagBuffer; 
			pPacket->m_usError = usTagLen; 
			pPacket->m_ulErrorTag = usTag; 
			break; 
		} 
	} 
} 
 
// get error tags 
VOID RetrieveErrorTag(PPACKET pPacket) 
{ 
	PUCHAR pBuffer; 
	USHORT usLen; 
 
	// service name error = 201 
	RetrieveTag(PPPOE_TAG_SERVICE_NAME_ERROR,pPacket,&pBuffer,&usLen,TRUE); 
	if(pBuffer) 
		pPacket->m_ulFlags |= PPPOE_PACKET_ERROR_TAG_RECV; 
 
	if(pPacket->m_ulFlags & PPPOE_PACKET_ERROR_TAG_RECV) 
		return; 
 
	// ac system error = 202 
	RetrieveTag(PPPOE_TAG_AC_SYSTEM_ERROR,pPacket,&pBuffer,&usLen,TRUE); 
	if(pBuffer) 
		pPacket->m_ulFlags |= PPPOE_PACKET_ERROR_TAG_RECV; 
 
	if(pPacket->m_ulFlags & PPPOE_PACKET_ERROR_TAG_RECV) 
		return; 
 
	// generice error = 203 
	RetrieveTag(PPPOE_TAG_GEN_ERROR,pPacket,&pBuffer,&usLen,TRUE); 
	if(pBuffer) 
		pPacket->m_ulFlags |= PPPOE_PACKET_ERROR_TAG_RECV; 
 
	if(pPacket->m_ulFlags & PPPOE_PACKET_ERROR_TAG_RECV) 
		return; 
 
	// ac cookie error = 204 
	RetrieveTag(PPPOE_TAG_AC_COOKIE_ERROR,pPacket,&pBuffer,&usLen,TRUE); 
	if(pBuffer) 
		pPacket->m_ulFlags |= PPPOE_PACKET_ERROR_TAG_RECV; 
} 
 
// get service name from buffer 
VOID RetrieveServiceName(PPACKET pPacket,PUCHAR *ppBuffer,PUSHORT pBufferLen,PUCHAR pStart,USHORT usTotalLen) 
{ 
	if(!pStart || !usTotalLen) 
	{ 
		*ppBuffer = pPacket->m_pServiceName; 
		*pBufferLen = pPacket->m_usServiceName; 
	} 
	else 
	{ 
		PUCHAR pEnd = pStart + usTotalLen; 
 
		PUCHAR pTagBuffer = NULL; 
		USHORT usTagLen = 0; 
 
		// loop find 
		while(pStart < pEnd) 
		{ 
			PPPP_TAG pTag = reinterpret_cast(pStart); 
			if(pTag->m_usType == PPPOE_TAG_SERVICE && ntohs(pTag->m_usLen) + pStart + sizeof(PPP_TAG) <= pEnd) 
			{ 
				pTagBuffer = pStart + sizeof(PPP_TAG); 
				usTagLen = ntohs(pTag->m_usLen); 
				break; 
			} 
 
			pStart += ntohs(pTag->m_usLen) + sizeof(PPP_TAG); 
		} 
 
		// save 
		*ppBuffer = pTagBuffer; 
		*pBufferLen = usTagLen; 
	} 
} 
 
// verify ac cookie 
BOOLEAN VerifyACCookie(PPACKET pPacket) 
{ 
	if(pPacket->m_usACCookie != ETH_ADDR_LEN) 
		return FALSE; 
 
	// ac cookie will be client mac address 
	return RtlCompareMemory(pPacket->m_pACCookie,pPacket->m_pFrame->m_srcMac,ETH_ADDR_LEN) == ETH_ADDR_LEN; 
} 
 
// verify service name 
BOOLEAN VerifyServiceName(PUCHAR pServiceName,USHORT usServiceNameLen,PPACKET pPacket,BOOLEAN bStrict) 
{ 
	PUCHAR pBuffer; 
	USHORT usLen; 
 
	RetrieveTag(PPPOE_TAG_SERVICE,pPacket,&pBuffer,&usLen,FALSE); 
 
	BOOLEAN bRet = FALSE; 
	if(!bStrict) 
	{ 
		bRet = RtlCompareMemory(pBuffer,pServiceName,usLen) == usLen; 
	} 
	else 
	{ 
		bRet = usLen == usServiceNameLen && pBuffer && RtlCompareMemory(pBuffer,pServiceName,usLen) == usLen; 
	} 
 
	return bRet; 
} 
 
// build a PADI to send 
PPACKET InitializePADIToSend(PUCHAR pServiceName,USHORT usServiceName,PUCHAR pHostUnique,USHORT usHostUnique) 
{ 
	static UCHAR _s_macBroadcast[6] = {0xff,0xff,0xff,0xff,0xff,0xff}; 
 
	PPACKET pRet = NULL; 
	__try 
	{ 
		pRet = GetSimplePacket(); 
 
		NdisMoveMemory(pRet->m_pFrame->m_dstMac,_s_macBroadcast,6); 
		pRet->m_pFrame->m_usProtocolType = PPPOE_DISCOVERY; 
 
		pRet->m_pFrame->m_pppFrame.m_ucVer = PPPOE_VER; 
		pRet->m_pFrame->m_pppFrame.m_ucType = PPPOE_TYPE; 
		pRet->m_pFrame->m_pppFrame.m_usSession = 0; 
		pRet->m_pFrame->m_pppFrame.m_ucCode = PPPOE_CODE_PADI; 
		pRet->m_pFrame->m_pppFrame.m_usLen = 0; 
 
		pRet->m_pServiceName = pServiceName; 
		pRet->m_usServiceName = usServiceName; 
 
		pRet->m_pHostUnique = pHostUnique; 
		pRet->m_usHostUnique = usHostUnique; 
 
		PreparePacketForSend(pRet); 
	} 
	__except(EXCEPTION_EXECUTE_HANDLER) 
	{ 
		if(pRet) 
			DereferencePacket(pRet); 
	} 
 
	return pRet; 
} 
 
// build a PADO to send 
PPACKET InitializePADOToSend(PPACKET pRecvedPacket,PUCHAR pSelfMac,PUCHAR pServiceName,USHORT usServiceName, 
							 PUCHAR pACName,USHORT usACNameLen,BOOLEAN bSetACCookie) 
{ 
	PPACKET pRet = NULL; 
	__try 
	{ 
		pRet = GetSimplePacket(); 
 
		NdisMoveMemory(pRet->m_pFrame->m_dstMac,pRecvedPacket->m_pFrame->m_srcMac,6); 
		NdisMoveMemory(pRet->m_pFrame->m_srcMac,pSelfMac,6); 
 
		pRet->m_pFrame->m_usProtocolType = PPPOE_DISCOVERY; 
 
		pRet->m_pFrame->m_pppFrame.m_ucVer = PPPOE_VER; 
		pRet->m_pFrame->m_pppFrame.m_ucType = PPPOE_TYPE; 
		pRet->m_pFrame->m_pppFrame.m_usSession = 0; 
		pRet->m_pFrame->m_pppFrame.m_ucCode = PPPOE_CODE_PADO; 
		pRet->m_pFrame->m_pppFrame.m_usLen = 0; 
 
		pRet->m_pACName = pACName; 
 
		pRet->m_usACName = usACNameLen; 
 
		pRet->m_pServiceName = pServiceName; 
 
		pRet->m_usServiceName = usServiceName; 
 
		if(bSetACCookie) 
		{ 
			pRet->m_pACCookie = pRecvedPacket->m_pFrame->m_srcMac; 
			pRet->m_usACCookie = 6; 
		} 
 
		pRet->m_pHostUnique = pRecvedPacket->m_pHostUnique; 
		pRet->m_usHostUnique = pRecvedPacket->m_usHostUnique; 
 
		pRet->m_pRelaySessionId = pRecvedPacket->m_pRelaySessionId; 
		pRet->m_usRelaySessionId = pRecvedPacket->m_usRelaySessionId; 
 
		PreparePacketForSend(pRet); 
	} 
	__except(EXCEPTION_EXECUTE_HANDLER) 
	{ 
		if(pRet) 
			DereferencePacket(pRet); 
	} 
 
	return pRet; 
} 
 
// build PADR to send 
PPACKET InitializePADRToSend(PPACKET pRecvedPacket,PUCHAR pServiceName,USHORT usServiceName,PUCHAR pHostUnique,USHORT usHostUnique) 
{ 
	PPACKET pRet = NULL; 
	__try 
	{ 
		pRet = GetSimplePacket(); 
 
		NdisMoveMemory(pRet->m_pFrame->m_dstMac,pRecvedPacket->m_pFrame->m_srcMac,6); 
		NdisMoveMemory(pRet->m_pFrame->m_srcMac,pRecvedPacket->m_pFrame->m_dstMac,6); 
 
		pRet->m_pFrame->m_usProtocolType = PPPOE_DISCOVERY; 
 
		pRet->m_pFrame->m_pppFrame.m_ucVer = PPPOE_VER; 
		pRet->m_pFrame->m_pppFrame.m_ucType = PPPOE_TYPE; 
		pRet->m_pFrame->m_pppFrame.m_usSession = 0; 
		pRet->m_pFrame->m_pppFrame.m_ucCode = PPPOE_CODE_PADR; 
		pRet->m_pFrame->m_pppFrame.m_usLen = 0; 
 
		pRet->m_pServiceName = pServiceName; 
		pRet->m_usServiceName = usServiceName; 
 
		pRet->m_pHostUnique = pHostUnique; 
		pRet->m_usHostUnique = usHostUnique; 
 
		pRet->m_pRelaySessionId = pRecvedPacket->m_pRelaySessionId; 
		pRet->m_usRelaySessionId = pRecvedPacket->m_usRelaySessionId; 
 
		pRet->m_pACCookie = pRecvedPacket->m_pACCookie; 
		pRet->m_usACCookie = pRecvedPacket->m_usACCookie; 
 
		PreparePacketForSend(pRet); 
	} 
	__except(EXCEPTION_EXECUTE_HANDLER) 
	{ 
		if(pRet) 
			DereferencePacket(pRet); 
	} 
 
	return pRet; 
} 
 
// build PADS to send 
PPACKET InitializePADSToSend(PPACKET pRecvedPacket,USHORT usSessionId) 
{ 
	PPACKET pRet = NULL; 
	__try 
	{ 
		pRet = GetSimplePacket(); 
 
		NdisMoveMemory(pRet->m_pFrame->m_dstMac,pRecvedPacket->m_pFrame->m_srcMac,6); 
		NdisMoveMemory(pRet->m_pFrame->m_srcMac,pRecvedPacket->m_pFrame->m_dstMac,6); 
 
		pRet->m_pFrame->m_usProtocolType = PPPOE_DISCOVERY; 
 
		pRet->m_pFrame->m_pppFrame.m_ucVer = PPPOE_VER; 
		pRet->m_pFrame->m_pppFrame.m_ucType = PPPOE_TYPE; 
		pRet->m_pFrame->m_pppFrame.m_usSession = htons(usSessionId); 
		pRet->m_pFrame->m_pppFrame.m_ucCode = PPPOE_CODE_PADS; 
		pRet->m_pFrame->m_pppFrame.m_usLen = 0; 
 
 
		pRet->m_pServiceName = pRecvedPacket->m_pServiceName; 
		pRet->m_usServiceName = pRecvedPacket->m_usServiceName; 
 
		pRet->m_pHostUnique = pRecvedPacket->m_pHostUnique; 
		pRet->m_usHostUnique = pRecvedPacket->m_usHostUnique; 
 
		pRet->m_pRelaySessionId = pRecvedPacket->m_pRelaySessionId; 
		pRet->m_usRelaySessionId = pRecvedPacket->m_usRelaySessionId; 
 
		PreparePacketForSend(pRet); 
	} 
	__except(EXCEPTION_EXECUTE_HANDLER) 
	{ 
		if(pRet) 
			DereferencePacket(pRet); 
	} 
 
	return pRet; 
} 
 
// build PADT to send 
PPACKET InitializePADTToSend(PUCHAR pDstAddr,PUCHAR pSrcAddr,USHORT usSession) 
{ 
	PPACKET pSendPacket = NULL; 
	__try 
	{ 
		pSendPacket = GetSimplePacket(); 
 
		NdisMoveMemory(pSendPacket->m_pFrame->m_dstMac,pDstAddr,6); 
		NdisMoveMemory(pSendPacket->m_pFrame->m_srcMac,pSrcAddr,6); 
 
		pSendPacket->m_pFrame->m_usProtocolType = PPPOE_DISCOVERY; 
 
		pSendPacket->m_pFrame->m_pppFrame.m_ucVer = PPPOE_VER; 
		pSendPacket->m_pFrame->m_pppFrame.m_ucType = PPPOE_TYPE; 
		pSendPacket->m_pFrame->m_pppFrame.m_usSession = htons(usSession); 
		pSendPacket->m_pFrame->m_pppFrame.m_ucCode = PPPOE_CODE_PADT; 
		pSendPacket->m_pFrame->m_pppFrame.m_usLen = 0; 
 
		PreparePacketForSend(pSendPacket); 
	} 
	__except(EXCEPTION_EXECUTE_HANDLER) 
	{ 
		if(pSendPacket) 
			DereferencePacket(pSendPacket); 
	} 
	return pSendPacket; 
} 
 
// send error PADS 
VOID SendPADSWithError(USHORT usTag,PBIND_CONTEXT pBind,PPACKET pRecvedPacket) 
{ 
	PPACKET pSendPacket = NULL; 
	__try 
	{ 
		pSendPacket = InitializePADSToSend(pRecvedPacket,1234); 
 
		switch(usTag) 
		{ 
		case PPPOE_TAG_SERVICE_NAME_ERROR: 
			{ 
				static CHAR error[] = "Service name error"; 
				PacketInsertTag(usTag,pSendPacket,reinterpret_cast(error),(USHORT)sizeof(error) + 2,NULL); 
			} 
			break; 
 
		case PPPOE_TAG_AC_SYSTEM_ERROR: 
			{ 
				static CHAR error[] = "AC system error"; 
				PacketInsertTag(usTag,pSendPacket,reinterpret_cast(error),(USHORT)sizeof(error) + 2,NULL); 
			} 
			break; 
 
		case PPPOE_TAG_GEN_ERROR: 
			{ 
				static CHAR error[] = "Generic error"; 
				PacketInsertTag(usTag,pSendPacket,reinterpret_cast(error),(USHORT)sizeof(error) + 2,NULL); 
			} 
			break; 
 
		case PPPOE_TAG_AC_COOKIE_ERROR: 
			{ 
				static CHAR error[] = "AC cookie error"; 
				PacketInsertTag(usTag,pSendPacket,reinterpret_cast(error),(USHORT)sizeof(error) + 2,NULL); 
			} 
			break; 
		} 
 
		PreparePacketForSend(pSendPacket); 
 
		ReferencePacket(pSendPacket); 
 
		ReferenceBind(pBind,TRUE); 
 
		SendPacket(pBind,pSendPacket); 
	} 
	__except(EXCEPTION_EXECUTE_HANDLER) 
	{ 
	} 
 
	if(pSendPacket) 
		DereferencePacket(pSendPacket); 
}