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


 
//******************************************************************** 
//	ÈÕÆÚ:	2004/08/25 - 25:8:2004   1:44 
//	Ãûǰ:	tiamo 
//	ÃèÊö:	miniport 
//********************************************************************* 
 
#include "Stdafx.h" 
 
#pragma alloc_text(PAGE,miniportInitialize) 
#pragma alloc_text(PAGE,miniportHalt) 
 
// miniport init 
NDIS_STATUS miniportInitialize(PNDIS_STATUS pOpenErrorStatus,PUINT puSelectedMediumIndex,PNDIS_MEDIUM pMediumArray, 
							   UINT uMediumArraySize,NDIS_HANDLE hAdapterHandle,NDIS_HANDLE hConfigurationContext) 
{ 
	PAGED_CODE(); 
 
	NDIS_STATUS status = NDIS_STATUS_SUCCESS; 
 
	__try 
	{ 
		// select cowan medium 
		UINT i; 
		for(i = 0; i < uMediumArraySize; i ++) 
		{ 
			if(pMediumArray[i] == NdisMediumCoWan) 
			{ 
				*puSelectedMediumIndex = i; 
				break; 
			} 
		} 
 
		// check 
		if(i == uMediumArraySize) 
		{ 
			DebugError(("unable to select cowan medium.\n")); 
			ExRaiseStatus(status = NDIS_STATUS_UNSUPPORTED_MEDIA); 
		} 
 
		// allocate adapter 
		g_pAdapter = CreateAdapter(); 
 
		// init adapter 
		status = InitializeAdapter(g_pAdapter,hAdapterHandle,hConfigurationContext); 
 
		if(status != NDIS_STATUS_SUCCESS) 
		{ 
			DebugError(("unable to init adapter.\n")); 
			ExRaiseStatus(status); 
		} 
 
		// register address family 
		CO_ADDRESS_FAMILY mcmAf; 
		mcmAf.AddressFamily = CO_ADDRESS_FAMILY_TAPI_PROXY; 
		mcmAf.MajorVersion = NDIS_MAJOR_VERSION; 
		mcmAf.MinorVersion = NDIS_MINOR_VERSION; 
 
		NDIS_CALL_MANAGER_CHARACTERISTICS mcmChar; 
		NdisZeroMemory(&mcmChar,sizeof(mcmChar)); 
		mcmChar.MajorVersion = NDIS_MAJOR_VERSION; 
		mcmChar.MinorVersion = NDIS_MINOR_VERSION; 
 
		mcmChar.CmActivateVcCompleteHandler = (CM_ACTIVATE_VC_COMPLETE_HANDLER)mcmActivateVcComplete; 
		mcmChar.CmCloseAfHandler = (CM_CLOSE_AF_HANDLER)mcmCloseAf; 
		mcmChar.CmCloseCallHandler = (CM_CLOSE_CALL_HANDLER)mcmCloseCall; 
		mcmChar.CmCreateVcHandler = (CO_CREATE_VC_HANDLER)mcmCreateVc; 
		mcmChar.CmDeactivateVcCompleteHandler = (CM_DEACTIVATE_VC_COMPLETE_HANDLER)mcmDeactivateVcComplete; 
		mcmChar.CmDeleteVcHandler = (CO_DELETE_VC_HANDLER)mcmDeleteVc; 
		mcmChar.CmDeregisterSapHandler = (CM_DEREG_SAP_HANDLER)mcmDeregisterSap; 
		mcmChar.CmIncomingCallCompleteHandler = (CM_INCOMING_CALL_COMPLETE_HANDLER)mcmIncomingCallComplete; 
		mcmChar.CmMakeCallHandler = (CM_MAKE_CALL_HANDLER)mcmMakeCall; 
		mcmChar.CmModifyCallQoSHandler = (CM_MODIFY_CALL_QOS_HANDLER)mcmModifyCallQos; 
		mcmChar.CmOpenAfHandler = (CM_OPEN_AF_HANDLER)mcmOpenAf; 
		mcmChar.CmRegisterSapHandler = (CM_REG_SAP_HANDLER)mcmRegisterSap; 
		mcmChar.CmRequestCompleteHandler = (CO_REQUEST_COMPLETE_HANDLER)mcmRequestComplete; 
		mcmChar.CmRequestHandler= (CO_REQUEST_HANDLER)mcmRequest; 
 
		status = NdisMCmRegisterAddressFamily(hAdapterHandle,&mcmAf,&mcmChar,sizeof(mcmChar)); 
		if(status != NDIS_STATUS_SUCCESS) 
		{ 
			DebugError(("register af error 0x%x.\n",status)); 
			ExRaiseStatus(status); 
		} 
 
		NdisMSetAttributesEx(hAdapterHandle,g_pAdapter,0, 
							 NDIS_ATTRIBUTE_IGNORE_PACKET_TIMEOUT	| 
							 NDIS_ATTRIBUTE_IGNORE_REQUEST_TIMEOUT	| 
							 NDIS_ATTRIBUTE_DESERIALIZE				| 
							 NDIS_ATTRIBUTE_NO_HALT_ON_SUSPEND, 
							 NdisInterfaceInternal); 
	} 
	__except(EXCEPTION_EXECUTE_HANDLER) 
	{ 
		miniportHalt(g_pAdapter); 
 
		if(status == NDIS_STATUS_SUCCESS) 
			status = NDIS_STATUS_FAILURE; 
	} 
 
	return status; 
} 
 
// miniport halt 
VOID miniportHalt(PADAPTER pAdapter) 
{ 
	PAGED_CODE(); 
 
	ASSERT(pAdapter == g_pAdapter); 
 
	ShutdownAdapter(pAdapter); 
} 
 
// reset 
NDIS_STATUS miniportReset(PBOOLEAN pbAddressingReset,PADAPTER pAdapter) 
{ 
	return NDIS_STATUS_NOT_RESETTABLE; 
} 
 
// send packet 
VOID miniportCoSendPackets(PCHANNEL pChannel,PPNDIS_PACKET pPacketArray,UINT uNumberOfPackets) 
{ 
	UINT i = 0; 
	__try 
	{ 
		for(; i < uNumberOfPackets; i ++) 
		{ 
			// build packet 
			PPACKET pPacket = BuildPacketForSend(pChannel,pPacketArray[i]); 
 
			// reference the packet,ref = 2 
			ReferencePacket(pPacket); 
		 
			// ref bind,protocol's send complete will deref the bind 
			ReferenceBind(pChannel->m_pBindContext,TRUE); 
 
			// send it 
			SendPacket(pChannel->m_pBindContext,pPacket); 
 
			// deref packet,ref = 1, the protocol's send complete routine will deref the packet 
			DereferencePacket(pPacket); 
		} 
	} 
	__except(EXCEPTION_EXECUTE_HANDLER) 
	{ 
		// ndis say that we must call send complete for every packet 
		for( ;i < uNumberOfPackets; i ++) 
		{ 
			NdisMCoSendComplete(NDIS_STATUS_FAILURE,pChannel->m_hNdisVcHandle,pPacketArray[i]); 
		} 
	} 
} 
 
// return packet,which we indicate to upper,just ref the packet 
VOID miniportReturnPacket(PADAPTER pAdapter,PNDIS_PACKET pNdisPacket) 
{ 
	ASSERT(pAdapter && pAdapter == g_pAdapter && pAdapter->m_ulSig == ADAPTER_SIG); 
 
	PMINIPORT_RESERVED pResv = reinterpret_cast(pNdisPacket->MiniportReservedEx); 
 
	ASSERT(pResv && pResv->m_pChannel && pResv->m_pPacket && pResv->m_pChannel->m_ulSig == CHANNEL_SIG); 
 
	NdisInterlockedDecrement(&pResv->m_pChannel->m_lPendingReturnPackets); 
 
	DereferencePacket(pResv->m_pPacket); 
} 
 
// miniport corequest 
NDIS_STATUS miniportCoRequest(PADAPTER pAdapter,PCHANNEL pChannel,PNDIS_REQUEST pNdisRequest) 
{ 
	ASSERT(pAdapter && pAdapter == g_pAdapter && pAdapter->m_ulSig == ADAPTER_SIG); 
 
	NDIS_STATUS status; 
 
	switch(pNdisRequest->RequestType) 
	{ 
	case NdisRequestQueryInformation: 
	case NdisRequestQueryStatistics: 
		status = QueryRequest(pChannel,pNdisRequest->DATA.QUERY_INFORMATION.Oid, 
							  pNdisRequest->DATA.QUERY_INFORMATION.InformationBuffer, 
							  pNdisRequest->DATA.QUERY_INFORMATION.InformationBufferLength, 
							  &pNdisRequest->DATA.QUERY_INFORMATION.BytesWritten, 
							  &pNdisRequest->DATA.QUERY_INFORMATION.BytesNeeded); 
		break; 
 
	case NdisRequestSetInformation: 
		status = SetRequest(pChannel,pNdisRequest->DATA.QUERY_INFORMATION.Oid, 
							pNdisRequest->DATA.SET_INFORMATION.InformationBuffer, 
							pNdisRequest->DATA.SET_INFORMATION.InformationBufferLength, 
							&pNdisRequest->DATA.SET_INFORMATION.BytesRead, 
							&pNdisRequest->DATA.SET_INFORMATION.BytesNeeded); 
 
		break; 
 
	default: 
		status = NDIS_STATUS_NOT_SUPPORTED; 
		break; 
	} 
 
	return status; 
} 
 
// miniport coactivate vc 
NDIS_STATUS miniportCoActivateVc(PCHANNEL pChannel,PCO_CALL_PARAMETERS pCallParameters) 
{ 
	return NDIS_STATUS_SUCCESS; 
} 
 
// miniport codeactivate vc 
NDIS_STATUS miniportCoDeactivateVc(PCHANNEL pChannel) 
{ 
	return NDIS_STATUS_SUCCESS; 
} 
 
namespace 
{ 
	NDIS_OID _s_supported[] =  
	{ 
		OID_GEN_CO_SUPPORTED_LIST, 
		OID_GEN_CO_HARDWARE_STATUS, 
		OID_GEN_CO_MEDIA_SUPPORTED, 
		OID_GEN_CO_MEDIA_IN_USE, 
		OID_GEN_CO_LINK_SPEED, 
		OID_GEN_CO_VENDOR_ID, 
		OID_GEN_CO_VENDOR_DESCRIPTION, 
		OID_GEN_CO_DRIVER_VERSION, 
		OID_GEN_CO_PROTOCOL_OPTIONS, 
		OID_GEN_CO_MAC_OPTIONS, 
		OID_GEN_CO_MEDIA_CONNECT_STATUS, 
		OID_GEN_CO_VENDOR_DRIVER_VERSION, 
		OID_GEN_CO_SUPPORTED_GUIDS, 
 
		OID_CO_TAPI_CM_CAPS, 
		OID_CO_TAPI_LINE_CAPS, 
		OID_CO_TAPI_ADDRESS_CAPS, 
 
		OID_802_3_PERMANENT_ADDRESS, 
		OID_802_3_CURRENT_ADDRESS, 
 
		OID_WAN_PERMANENT_ADDRESS, 
		OID_WAN_CURRENT_ADDRESS, 
		OID_WAN_MEDIUM_SUBTYPE, 
 
		OID_WAN_CO_GET_INFO, 
		OID_WAN_CO_SET_LINK_INFO, 
		OID_WAN_CO_GET_LINK_INFO, 
 
		OID_WAN_LINE_COUNT, 
 
		OID_PNP_CAPABILITIES, 
		OID_PNP_SET_POWER, 
		OID_PNP_QUERY_POWER, 
	}; 
 
	WCHAR _s_address_name[] = L" Address 00"; 
	WCHAR _s_vendor_desc[] = L"tiamo PPPoE Miniport Driver CoNdis edition for windows"; 
	UCHAR _s_vendor_id[4] = {0x00,0x40,0x46,0x0}; 
	UCHAR _s_address[ETH_ADDR_LEN] = {0x00,0x40,0x46,0x00,0x00,0x01}; 
} 
 
// query request 
NDIS_STATUS QueryRequest(PCHANNEL pChannel,NDIS_OID oid,PVOID pBuffer,UINT uBufferLen,PUINT puWritten,PUINT puNeeded) 
{ 
	NDIS_STATUS status = NDIS_STATUS_SUCCESS; 
 
	UINT uNeeded = 0; 
	PVOID pTempBuffer = NULL; 
	ULONG ulValue = 0; 
 
	NDIS_CO_LINK_SPEED linkSpeed; 
	NDIS_PNP_CAPABILITIES PnpCapabilities; 
 
	switch(oid) 
	{ 
	case OID_GEN_CO_SUPPORTED_LIST: 
		pTempBuffer = _s_supported; 
		uNeeded = sizeof(_s_supported); 
		break; 
 
	case OID_GEN_CO_SUPPORTED_GUIDS: 
		uNeeded = 0; 
		break; 
 
	case OID_GEN_CO_HARDWARE_STATUS: 
		ulValue = NdisHardwareStatusReady; 
		pTempBuffer = &ulValue; 
		uNeeded = sizeof(ulValue); 
		break; 
 
	case OID_GEN_CO_MEDIA_SUPPORTED: 
	case OID_GEN_CO_MEDIA_IN_USE: 
		ulValue = NdisMediumCoWan; 
		pTempBuffer = &ulValue; 
		uNeeded = sizeof(ulValue); 
		break; 
 
	case OID_GEN_CO_LINK_SPEED: 
		if(pChannel) 
			linkSpeed.Inbound = linkSpeed.Outbound = pChannel->m_ulLinkSpeed; 
		else 
			linkSpeed.Inbound = linkSpeed.Outbound = 1000000; 
 
		pTempBuffer = &linkSpeed; 
		uNeeded = sizeof(linkSpeed); 
		DebugInfo(("get link speed %d,pChannel = 0x%x\n",linkSpeed.Inbound,pChannel)); 
		break; 
 
	case OID_GEN_CO_VENDOR_ID: 
		pTempBuffer = _s_vendor_id; 
		uNeeded = sizeof(_s_vendor_id); 
		break; 
 
	case OID_GEN_CO_VENDOR_DESCRIPTION: 
		pTempBuffer = _s_vendor_desc; 
		uNeeded = sizeof(_s_vendor_desc); 
		break; 
 
	case OID_GEN_CO_DRIVER_VERSION: 
		ulValue = (NDIS_MAJOR_VERSION << 8) | NDIS_MINOR_VERSION; 
		pTempBuffer = &ulValue; 
		uNeeded = sizeof(ulValue); 
		break; 
 
	case OID_GEN_CO_MAC_OPTIONS: 
		ulValue = 0; 
		pTempBuffer = &ulValue; 
		uNeeded = sizeof(ulValue); 
		break; 
 
	case OID_GEN_CO_MEDIA_CONNECT_STATUS: 
		ulValue = NdisMediaStateConnected; 
		pTempBuffer = &ulValue; 
		uNeeded = sizeof(ulValue); 
		break; 
 
	case OID_GEN_CO_VENDOR_DRIVER_VERSION: 
		ulValue = 1 << 8; 
		pTempBuffer = &ulValue; 
		uNeeded = sizeof(ulValue); 
		break; 
 
	case OID_CO_TAPI_CM_CAPS: 
		{ 
			PCO_TAPI_CM_CAPS pCallManagerCaps = static_cast(pBuffer); 
			uNeeded = sizeof(CO_TAPI_CM_CAPS); 
 
			if(uNeeded <= uBufferLen) 
			{ 
				pCallManagerCaps->ulCoTapiVersion = CO_TAPI_VERSION; 
				pCallManagerCaps->ulFlags = 0; 
				pCallManagerCaps->ulNumLines = g_pAdapter->m_ulNumChannels; 
			} 
 
			DebugInfo(("get call manager caps len = %d,version = 0x%x,lines = 0x%x\n",uBufferLen,CO_TAPI_VERSION, 
						g_pAdapter->m_ulNumChannels)); 
		} 
		break; 
 
	case OID_CO_TAPI_LINE_CAPS: 
		{ 
			PCO_TAPI_LINE_CAPS pLineCaps = static_cast(pBuffer); 
			uNeeded = sizeof(CO_TAPI_LINE_CAPS); 
 
			if(uNeeded <= uBufferLen && pLineCaps->ulLineID < g_pAdapter->m_ulNumChannels) 
			{ 
				*puWritten = uNeeded; 
 
				NdisZeroMemory(pLineCaps, uNeeded); 
 
				pLineCaps->LineDevCaps.ulTotalSize = uBufferLen - sizeof(CO_TAPI_LINE_CAPS) + sizeof(LINE_DEV_CAPS);; 
 
				pLineCaps->ulFlags = 0; 
 
				PCHANNEL pChannel = g_pAdapter->m_ppChannels[pLineCaps->ulLineID]; 
 
				pLineCaps->LineDevCaps.ulNeededSize = pLineCaps->LineDevCaps.ulUsedSize = sizeof(LINE_DEV_CAPS); 
				pLineCaps->LineDevCaps.ulPermanentLineID = pChannel->m_ulLineId;				// id 
				pLineCaps->LineDevCaps.ulStringFormat = STRINGFORMAT_UNICODE;					// unicode string 
				pLineCaps->LineDevCaps.ulAddressModes = LINEADDRESSMODE_ADDRESSID;				// address id 
				pLineCaps->LineDevCaps.ulNumAddresses = 1;										// only one address per channel 
				pLineCaps->LineDevCaps.ulBearerModes = pChannel->m_ulBearerMode;				// bearer mode 
				pLineCaps->LineDevCaps.ulMaxRate = pChannel->m_ulLinkSpeed;						// link speed 
				pLineCaps->LineDevCaps.ulMediaModes = pChannel->m_ulMediaMode;					// media mode 
				pLineCaps->LineDevCaps.ulDevCapFlags = LINEDEVCAPFLAGS_CLOSEDROP;				// dev cap 
				pLineCaps->LineDevCaps.ulMaxNumActiveCalls = 1;									// only one call 
				pLineCaps->LineDevCaps.ulAnswerMode = LINEANSWERMODE_DROP;						// drop this when answer another 
				pLineCaps->LineDevCaps.ulRingModes = 1;											// one ring 
				pLineCaps->LineDevCaps.ulLineStates = LINEDEVSTATE_RINGING | LINEDEVSTATE_CONNECTED | LINEDEVSTATE_DISCONNECTED | 
													  LINEDEVSTATE_OPEN | LINEDEVSTATE_CLOSE; 
 
				pLineCaps->LineDevCaps.ulLineFeatures = LINEFEATURE_MAKECALL;					// can make call 
 
				UINT uInfoOffset = sizeof(pLineCaps->LineDevCaps); 
				UINT uInfoLength = sizeof(_s_vendor_desc); 
 
				pLineCaps->LineDevCaps.ulNeededSize += uInfoLength; 
				uNeeded += uInfoOffset; 
				if(pLineCaps->LineDevCaps.ulNeededSize <= pLineCaps->LineDevCaps.ulTotalSize) 
				{ 
					pLineCaps->LineDevCaps.ulProviderInfoSize = uInfoLength;					// provider info 
					pLineCaps->LineDevCaps.ulProviderInfoOffset = uInfoOffset; 
 
					NdisMoveMemory(reinterpret_cast(&pLineCaps->LineDevCaps) + uInfoOffset, _s_vendor_desc,uInfoLength); 
					pLineCaps->LineDevCaps.ulUsedSize += uInfoLength; 
					uInfoOffset += uInfoLength; 
				} 
			} 
 
			DebugInfo(("get line caps,len = %d,line id = %d,bearer mode = 0x%x,media mode = 0x%x,speed = %d\n", 
						uBufferLen,pLineCaps->ulLineID,pLineCaps->LineDevCaps.ulBearerModes,pLineCaps->LineDevCaps.ulMediaModes, 
						pLineCaps->LineDevCaps.ulMaxRate)); 
		} 
		break; 
 
	case OID_CO_TAPI_ADDRESS_CAPS: 
		{ 
			PCO_TAPI_ADDRESS_CAPS pAddressCaps = static_cast(pBuffer); 
 
			uNeeded = sizeof(CO_TAPI_ADDRESS_CAPS); 
			if(uNeeded <= uBufferLen && pAddressCaps->ulLineID < g_pAdapter->m_ulNumChannels) 
			{ 
				NdisZeroMemory(pAddressCaps,uNeeded); 
 
				pAddressCaps->LineAddressCaps.ulTotalSize = uBufferLen - sizeof(CO_TAPI_ADDRESS_CAPS) + sizeof(LINE_ADDRESS_CAPS); 
 
				pAddressCaps->ulFlags = 0; 
 
				PCHANNEL pChannel = g_pAdapter->m_ppChannels[pAddressCaps->ulLineID]; 
 
				*puWritten = uNeeded; 
 
				pAddressCaps->LineAddressCaps.ulNeededSize = pAddressCaps->LineAddressCaps.ulUsedSize = sizeof(LINE_ADDRESS_CAPS); 
 
				pAddressCaps->LineAddressCaps.ulLineDeviceID = pChannel->m_ulLineId; 
 
				pAddressCaps->LineAddressCaps.ulAddressSharing = LINEADDRESSSHARING_PRIVATE; 
				pAddressCaps->LineAddressCaps.ulAddressStates = 0; 
 
				pAddressCaps->LineAddressCaps.ulCallStates = LINECALLSTATE_IDLE | LINECALLSTATE_DIALING | LINECALLSTATE_OFFERING | 
															 LINECALLSTATE_CONNECTED | LINECALLSTATE_DISCONNECTED; 
 
				pAddressCaps->LineAddressCaps.ulDialToneModes = LINEDIALTONEMODE_NORMAL; 
				pAddressCaps->LineAddressCaps.ulDisconnectModes = LINEDISCONNECTMODE_NORMAL | LINEDISCONNECTMODE_UNKNOWN |  
																  LINEDISCONNECTMODE_BUSY | LINEDISCONNECTMODE_NOANSWER; 
 
				pAddressCaps->LineAddressCaps.ulMaxNumActiveCalls = 1; 
				pAddressCaps->LineAddressCaps.ulAddrCapFlags = LINEADDRCAPFLAGS_DIALED; 
				pAddressCaps->LineAddressCaps.ulCallFeatures = LINECALLFEATURE_ACCEPT | LINECALLFEATURE_ANSWER |  
															   LINECALLFEATURE_DROP; 
 
				pAddressCaps->LineAddressCaps.ulAddressFeatures = LINEADDRFEATURE_MAKECALL; 
 
				UINT InfoOffset = sizeof(pAddressCaps->LineAddressCaps); 
				UINT InfoLength = sizeof(_s_address_name); 
 
				pAddressCaps->LineAddressCaps.ulNeededSize += InfoLength; 
				uNeeded += InfoLength; 
				if(pAddressCaps->LineAddressCaps.ulNeededSize <= pAddressCaps->LineAddressCaps.ulTotalSize) 
				{ 
					pAddressCaps->LineAddressCaps.ulAddressSize = InfoLength; 
					pAddressCaps->LineAddressCaps.ulAddressOffset = InfoOffset; 
					PWCHAR pBuffer = reinterpret_cast(&pAddressCaps->LineAddressCaps) + InfoOffset / 2; 
 
					NdisMoveMemory(pBuffer,_s_address_name,InfoLength); 
 
					pBuffer[(InfoLength - 4) / 2] = static_cast(pAddressCaps->ulAddressID) + L'0'; 
 
					pAddressCaps->LineAddressCaps.ulUsedSize += InfoLength; 
					InfoOffset += InfoLength; 
 
					DebugInfo(("get addr caps,len = %d,line id = %d,addr id = %d,name = %ls\n", 
								uBufferLen,pAddressCaps->ulLineID,pAddressCaps->ulAddressID,pBuffer)); 
				} 
			} 
		} 
		break; 
 
	case OID_802_3_PERMANENT_ADDRESS: 
	case OID_802_3_CURRENT_ADDRESS: 
	case OID_WAN_PERMANENT_ADDRESS: 
	case OID_WAN_CURRENT_ADDRESS: 
		pTempBuffer = _s_address; 
		uNeeded = sizeof(_s_address); 
		DebugInfo(("get eth address 0x%02x-0x%02x-0x%02x-0x%02x-0x%02x-0x%02x\n", 
					_s_address[0],_s_address[1],_s_address[2],_s_address[3],_s_address[4],_s_address[5])); 
		break; 
 
	case OID_WAN_MEDIUM_SUBTYPE: 
		//ulValue = NdisWanMediumIsdn; 
		ulValue = NdisWanMediumPppoe; 
		pTempBuffer = &ulValue; 
		uNeeded = sizeof(ulValue); 
		break; 
 
	case OID_WAN_CO_GET_INFO: 
		{ 
			PNDIS_WAN_CO_INFO pInfo = &g_pAdapter->m_wanCoInfo; 
			pTempBuffer = pInfo; 
			uNeeded = sizeof(g_pAdapter->m_wanCoInfo); 
 
			DebugInfo(("wan co get info len = %d,DesiredACCM = %d,FramingBits = %d,MaxFrameSize = %d,MaxSendWindow = %d\n", 
						uBufferLen,pInfo->DesiredACCM,pInfo->FramingBits,pInfo->MaxFrameSize,pInfo->MaxSendWindow)); 
		} 
		break; 
 
	case OID_WAN_CO_GET_LINK_INFO: 
		if(!pChannel) 
		{ 
			uNeeded = 0; 
			status = NDIS_STATUS_INVALID_DATA; 
		} 
		else 
		{ 
			PNDIS_WAN_CO_GET_LINK_INFO pInfo = &pChannel->m_wanCoLinkInfo; 
			pTempBuffer = pInfo; 
			uNeeded = sizeof(NDIS_WAN_CO_GET_LINK_INFO); 
 
			DebugInfo(( "get link info size = %d,MaxRecvFrame = %d,MaxSendFrame = %d,RecvACCM = %d,RecvCompressionBits = %d," 
						"RecvFramingBits = %d,SendACCM= %d,SendCompressionBits = %d,SendFramingBits = %d,pChannel = 0x%x\n", 
						uBufferLen,pInfo->MaxRecvFrameSize,pInfo->MaxSendFrameSize, 
					    pInfo->RecvACCM,pInfo->RecvCompressionBits,pInfo->RecvFramingBits,pInfo->SendACCM, 
					    pInfo->SendCompressionBits,pInfo->SendFramingBits,pChannel)); 
		} 
		break; 
 
	case OID_WAN_LINE_COUNT: 
		ulValue = g_pAdapter->m_ulNumChannels; 
		pTempBuffer = &ulValue; 
		uNeeded = sizeof(ulValue); 
		break; 
 
	case OID_PNP_CAPABILITIES: 
		PnpCapabilities.WakeUpCapabilities.MinMagicPacketWakeUp = NdisDeviceStateUnspecified; 
		PnpCapabilities.WakeUpCapabilities.MinPatternWakeUp = NdisDeviceStateUnspecified; 
		PnpCapabilities.WakeUpCapabilities.MinLinkChangeWakeUp = NdisDeviceStateUnspecified; 
		pTempBuffer = &PnpCapabilities; 
		uNeeded = sizeof(PnpCapabilities); 
		break; 
 
	case OID_PNP_QUERY_POWER: 
		break; 
 
	default: 
		status = NDIS_STATUS_INVALID_OID; 
		break; 
	} 
 
	if(uNeeded > uBufferLen) 
	{ 
		*puNeeded = uNeeded; 
		*puWritten = 0; 
		status = NDIS_STATUS_INVALID_LENGTH; 
	} 
	else 
	{ 
		if(pTempBuffer) 
		{ 
			NdisMoveMemory(pBuffer,pTempBuffer,uNeeded); 
		} 
 
		*puNeeded = *puWritten = uNeeded; 
	} 
 
	return status; 
} 
 
// set quest DISPATCH_LEVEL 
NDIS_STATUS SetRequest(PCHANNEL pChannel,NDIS_OID oid,PVOID pBuffer,UINT uBufferLen,PUINT puRead,PUINT puNeeded) 
{ 
	NDIS_STATUS status = NDIS_STATUS_SUCCESS; 
 
	*puRead = *puNeeded = 0; 
	switch(oid) 
	{ 
	case OID_GEN_CURRENT_LOOKAHEAD: 
		DebugInfo(("set current lookahead.do nothing,total packet is lookahead buffer.\n")); 
		*puRead = *puNeeded = sizeof(ULONG); 
		break; 
 
	case OID_WAN_CO_SET_LINK_INFO: 
		{ 
			PNDIS_WAN_CO_SET_LINK_INFO pInfo = static_cast(pBuffer); 
 
			DebugInfo(( "set link info size = %d,MaxRecvFrame = %d,MaxSendFrame = %d,RecvACCM = %d,RecvCompressionBits = %d," 
						"RecvFramingBits = %d,SendACCM= %d,SendCompressionBits = %d,SendFramingBits = %d,pChannel = 0x%x\n", 
						uBufferLen,pInfo->MaxRecvFrameSize,pInfo->MaxSendFrameSize, 
					    pInfo->RecvACCM,pInfo->RecvCompressionBits,pInfo->RecvFramingBits,pInfo->SendACCM, 
					    pInfo->SendCompressionBits,pInfo->SendFramingBits,pChannel)); 
 
			if(uBufferLen >= sizeof(NDIS_WAN_CO_SET_LINK_INFO)) 
			{ 
				if(pChannel) 
				{ 
					NdisMoveMemory(&pChannel->m_wanCoLinkInfo,pBuffer,sizeof(NDIS_WAN_CO_SET_LINK_INFO)); 
					*puRead = sizeof(NDIS_WAN_CO_SET_LINK_INFO); 
				} 
			} 
		} 
 
		*puNeeded = sizeof(NDIS_WAN_CO_SET_LINK_INFO); 
		break; 
 
	case OID_PNP_SET_POWER: 
	case OID_GEN_CO_PROTOCOL_OPTIONS: 
		break; 
 
	default: 
		status = NDIS_STATUS_INVALID_OID; 
		break; 
	} 
 
	return status; 
} 
 
// send packet 
NDIS_STATUS SendPacket(PBIND_CONTEXT pBind,PPACKET pPacket) 
{ 
	NDIS_STATUS status; 
 
	pPacket->m_pBindContext = pBind; 
 
	NdisSend(&status,pBind->m_pOpenBlock,pPacket->m_pNdisPacket); 
 
	if(status != NDIS_STATUS_PENDING) 
	{ 
		protocolSendComplete(pBind,pPacket->m_pNdisPacket,status); 
	} 
 
	return status; 
} 
 
// broadcast packet 
BOOLEAN BroadcastPacket(PPACKET pPacket) 
{ 
	BOOLEAN bRet = FALSE; 
 
	NdisAcquireSpinLock(&g_lockBind); 
 
	PLIST_ENTRY pEntry = g_ltBindsHead.Flink; 
	for(; pEntry != &g_ltBindsHead; pEntry = pEntry->Flink) 
	{ 
		bRet = TRUE; 
		PBIND_CONTEXT pBind = CONTAINING_RECORD(pEntry,BIND_CONTEXT,m_ltBindAnchor); 
 
		PPACKET pPacketClone = ClonePacket(pPacket); 
		if(pPacketClone) 
		{ 
			NdisMoveMemory(pPacketClone->m_pFrame->m_srcMac,pBind->m_macAddress,ETH_ADDR_LEN); 
 
			ReferenceBind(pBind,TRUE); 
 
			ReferencePacket(pPacketClone); 
 
			SendPacket(pBind,pPacketClone); 
 
			DereferencePacket(pPacketClone); 
		} 
	} 
 
	NdisReleaseSpinLock(&g_lockBind); 
 
	return bRet; 
}