2052 lines
59 KiB
C
2052 lines
59 KiB
C
/*++
|
||
|
||
Copyright (c) 1996-1999 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
ndisreq.c
|
||
|
||
Abstract:
|
||
|
||
routines for passing NdisRequests up and down
|
||
|
||
Author:
|
||
|
||
Charlie Wickham (charlwi) 01-May-1996.
|
||
Rajesh Sundaram (rajeshsu) 01-Aug-1998.
|
||
|
||
Environment:
|
||
|
||
Kernel Mode
|
||
|
||
Revision History:
|
||
|
||
--*/
|
||
|
||
#include "psched.h"
|
||
|
||
#pragma hdrstop
|
||
|
||
/* External */
|
||
|
||
/* Static */
|
||
|
||
|
||
const UCHAR gDriverDescription[] = " (Microsoft's Packet Scheduler) ";
|
||
|
||
/* Forward */ /* Generated by Emacs 19.17.0 on Mon May 06 15:54:11 1996 */
|
||
|
||
VOID
|
||
MpQueryPnPCapabilities(
|
||
IN OUT PPS_NDIS_REQUEST PsReqBuffer,
|
||
IN OUT PADAPTER pAdapt,
|
||
OUT PNDIS_STATUS pStatus
|
||
);
|
||
|
||
NDIS_STATUS
|
||
MakeNdisRequest(
|
||
IN PADAPTER Adapter,
|
||
IN NDIS_HANDLE VcHandle,
|
||
IN NDIS_REQUEST_TYPE RequestType,
|
||
IN NDIS_OID Oid,
|
||
IN PVOID InformationBuffer,
|
||
IN ULONG InformationBufferLength,
|
||
OUT PULONG BytesReadOrWritten,
|
||
OUT PULONG BytesNeeded,
|
||
LOCAL_NDISREQUEST_COMPLETION_FUNCTION CompletionFunc
|
||
);
|
||
|
||
VOID
|
||
ClRequestComplete(
|
||
IN NDIS_HANDLE ProtocolBindingContext,
|
||
IN PNDIS_REQUEST NdisRequest,
|
||
IN NDIS_STATUS Status
|
||
);
|
||
|
||
NDIS_STATUS
|
||
MakeLocalNdisRequest(
|
||
PADAPTER Adapter,
|
||
NDIS_HANDLE VcHandle,
|
||
NDIS_REQUEST_TYPE RequestType,
|
||
NDIS_OID Oid,
|
||
PVOID Buffer,
|
||
ULONG BufferSize,
|
||
LOCAL_NDISREQUEST_COMPLETION_FUNCTION CompletionFunc OPTIONAL
|
||
);
|
||
|
||
NDIS_STATUS
|
||
RecordNetworkAddressList(
|
||
IN PADAPTER Adapter,
|
||
IN PPS_NDIS_REQUEST PsRequestBuffer
|
||
);
|
||
|
||
ULONG
|
||
GetSizeAddrList(
|
||
IN NETWORK_ADDRESS_LIST UNALIGNED *AddrList
|
||
);
|
||
|
||
/* End Forward */
|
||
|
||
NTSTATUS
|
||
DoIpIoctl(
|
||
IN PWCHAR DriverName,
|
||
IN DWORD Ioctl,
|
||
IN PVOID pvInArg,
|
||
IN DWORD dwInSize,
|
||
IN PVOID pvOutArg,
|
||
IN DWORD dwOutSize)
|
||
/*++
|
||
Routine Description:
|
||
Do an IOCTL to the stack. Used for a varity of purposes
|
||
--*/
|
||
{
|
||
NTSTATUS status;
|
||
UNICODE_STRING nameString;
|
||
OBJECT_ATTRIBUTES Atts;
|
||
IO_STATUS_BLOCK ioStatusBlock;
|
||
HANDLE Handle;
|
||
|
||
PAGED_CODE();
|
||
|
||
RtlInitUnicodeString(&nameString, DriverName);
|
||
|
||
InitializeObjectAttributes(&Atts,
|
||
&nameString,
|
||
OBJ_CASE_INSENSITIVE,
|
||
NULL,
|
||
NULL);
|
||
|
||
status = ZwCreateFile(&Handle,
|
||
SYNCHRONIZE | FILE_READ_DATA | FILE_WRITE_DATA,
|
||
&Atts,
|
||
&ioStatusBlock,
|
||
NULL,
|
||
FILE_ATTRIBUTE_NORMAL,
|
||
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||
FILE_OPEN_IF,
|
||
0,
|
||
NULL,
|
||
0);
|
||
|
||
if (!NT_SUCCESS(status))
|
||
{
|
||
return STATUS_UNSUCCESSFUL;
|
||
}
|
||
|
||
//
|
||
// Submit the request to the forwarder
|
||
//
|
||
|
||
status = ZwDeviceIoControlFile(
|
||
Handle,
|
||
NULL,
|
||
NULL,
|
||
NULL,
|
||
&ioStatusBlock,
|
||
Ioctl,
|
||
pvInArg,
|
||
dwInSize,
|
||
pvOutArg,
|
||
dwOutSize);
|
||
|
||
//
|
||
// Close the device.
|
||
//
|
||
|
||
ZwClose(Handle);
|
||
|
||
return status;
|
||
}
|
||
|
||
//
|
||
// This function uses one of the IP Addresses on the adapter to get the Interface Index of the
|
||
// adapter. This function is called when IP updates the addresses on the interface. It uses this
|
||
// address and the IpHlpAPI and obtains the InterfaceID.
|
||
//
|
||
// For WanLinks, the InterfaceID is a set of 2 ULONGS - One identifies the InterfaceIndex as above
|
||
// and the other ULONG is the remote address of the server.
|
||
//
|
||
//
|
||
|
||
VOID SetInterfaceIndex(PNDIS_WORK_ITEM pWorkItem, PVOID pWorkItemContext)
|
||
{
|
||
PPS_INTERFACE_INDEX_CONTEXT pInterfaceContext = (PPS_INTERFACE_INDEX_CONTEXT) pWorkItemContext;
|
||
PTC_INTERFACE_ID pInterfaceID;
|
||
IO_STATUS_BLOCK IoStatus;
|
||
KEVENT LocalEvent;
|
||
PIRP Irp;
|
||
IPAddrEntry *pIpAddrTbl;
|
||
ULONG k, OutBufferSize;
|
||
TCP_REQUEST_QUERY_INFORMATION_EX trqiInBuf;
|
||
TDIObjectID *ID;
|
||
DWORD Status, dwInBufLen, dwOutBufLen;
|
||
BYTE *Context;
|
||
ULONG IpAddr, IpAddrCount;
|
||
INT n;
|
||
NETWORK_ADDRESS UNALIGNED *pAddr;
|
||
IPSNMPInfo IPSnmpInfo;
|
||
|
||
PS_LOCK(&pInterfaceContext->Adapter->Lock);
|
||
|
||
if(pInterfaceContext->Adapter->MediaType == NdisMediumWan)
|
||
{
|
||
pInterfaceID = &pInterfaceContext->WanLink->InterfaceID;
|
||
pInterfaceID->LinkId = 0;
|
||
IpAddr = pInterfaceContext->WanLink->LocalIpAddress;
|
||
|
||
if(pInterfaceContext->WanLink->DialUsage != DU_CALLOUT)
|
||
pInterfaceID->LinkId = pInterfaceContext->WanLink->RemoteIpAddress;
|
||
}
|
||
else
|
||
{
|
||
pInterfaceID = &pInterfaceContext->Adapter->InterfaceID;
|
||
pInterfaceID->LinkId = 0;
|
||
pAddr = (NETWORK_ADDRESS UNALIGNED *)&pInterfaceContext->Adapter->IpNetAddressList->Address[0];
|
||
|
||
for(n=0; n<pInterfaceContext->Adapter->IpNetAddressList->AddressCount; n++)
|
||
{
|
||
NETWORK_ADDRESS_IP UNALIGNED *pIpNetAddr;
|
||
|
||
if(pAddr->AddressType == NDIS_PROTOCOL_ID_TCP_IP)
|
||
{
|
||
pIpNetAddr = (NETWORK_ADDRESS_IP UNALIGNED *)&pAddr->Address[0];
|
||
IpAddr = pIpNetAddr->in_addr;
|
||
break;
|
||
}
|
||
|
||
pAddr = (NETWORK_ADDRESS UNALIGNED *)(((PUCHAR)pAddr)
|
||
+ pAddr->AddressLength
|
||
+ FIELD_OFFSET(NETWORK_ADDRESS, Address));
|
||
}
|
||
|
||
if(n == pInterfaceContext->Adapter->IpNetAddressList->AddressCount)
|
||
{
|
||
PsDbgOut(DBG_FAILURE,
|
||
DBG_PROTOCOL,
|
||
("[SetInterfaceIndex]: No Ip Addresses \n"));
|
||
PS_UNLOCK(&pInterfaceContext->Adapter->Lock);
|
||
goto Done;
|
||
}
|
||
|
||
}
|
||
|
||
PS_UNLOCK(&pInterfaceContext->Adapter->Lock);
|
||
|
||
//
|
||
// Initialize parameters for sending the IO Request
|
||
//
|
||
|
||
ID = &(trqiInBuf.ID);
|
||
ID->toi_entity.tei_entity = CL_NL_ENTITY;
|
||
ID->toi_entity.tei_instance = 0;
|
||
ID->toi_class = INFO_CLASS_PROTOCOL;
|
||
ID->toi_type = INFO_TYPE_PROVIDER;
|
||
ID->toi_id = IP_MIB_STATS_ID;
|
||
|
||
Context = (BYTE *) &(trqiInBuf.Context[0]);
|
||
NdisZeroMemory(Context,CONTEXT_SIZE);
|
||
|
||
dwInBufLen = sizeof(TCP_REQUEST_QUERY_INFORMATION_EX);
|
||
dwOutBufLen = sizeof(IPSNMPInfo);
|
||
|
||
Status = DoIpIoctl(DD_TCP_DEVICE_NAME,
|
||
IOCTL_TCP_QUERY_INFORMATION_EX,
|
||
(PVOID) &trqiInBuf,
|
||
sizeof(TCP_REQUEST_QUERY_INFORMATION_EX),
|
||
(PVOID)&IPSnmpInfo,
|
||
dwOutBufLen);
|
||
|
||
if(NT_SUCCESS(Status))
|
||
{
|
||
|
||
//
|
||
// Allocate the output buffer and send the I/O request.
|
||
//
|
||
|
||
IpAddrCount = IPSnmpInfo.ipsi_numaddr + 10;
|
||
dwOutBufLen = IpAddrCount * sizeof(IPAddrEntry);
|
||
PsAllocatePool(pIpAddrTbl, dwOutBufLen, PsMiscTag);
|
||
|
||
if(!pIpAddrTbl)
|
||
{
|
||
PsDbgOut(DBG_FAILURE,
|
||
DBG_PROTOCOL,
|
||
("[SetInterfaceIndex]: Could not allocate memory for %d addresses \n",
|
||
IPSnmpInfo.ipsi_numaddr + 10));
|
||
|
||
goto Done;
|
||
|
||
}
|
||
|
||
NdisZeroMemory(pIpAddrTbl, dwOutBufLen);
|
||
|
||
ID->toi_type = INFO_TYPE_PROVIDER;
|
||
ID->toi_id = IP_MIB_ADDRTABLE_ENTRY_ID;
|
||
RtlZeroMemory(Context, CONTEXT_SIZE);
|
||
|
||
Status = DoIpIoctl(DD_TCP_DEVICE_NAME,
|
||
IOCTL_TCP_QUERY_INFORMATION_EX,
|
||
(PVOID) &trqiInBuf,
|
||
sizeof(TCP_REQUEST_QUERY_INFORMATION_EX),
|
||
(PVOID)pIpAddrTbl,
|
||
dwOutBufLen);
|
||
|
||
if(!NT_SUCCESS(Status))
|
||
{
|
||
|
||
PsDbgOut(DBG_FAILURE,
|
||
DBG_PROTOCOL,
|
||
("[SetInterfaceIndex]: IOCTL_TCP_QUERY_INFORMATION_EX failed with 0x%x \n", Status));
|
||
|
||
PsFreePool(pIpAddrTbl);
|
||
goto Done;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
PsDbgOut(DBG_FAILURE,
|
||
DBG_PROTOCOL,
|
||
("[SetInterfaceIndex]: DoIpIoctl failed with 0x%x \n", Status));
|
||
goto Done;
|
||
|
||
}
|
||
|
||
//
|
||
// search for the matching IP address to IpAddr
|
||
// in the table we got back from the stack
|
||
//
|
||
|
||
for (k = 0; k < IpAddrCount; k++) {
|
||
|
||
if (pIpAddrTbl[k].iae_addr == IpAddr) {
|
||
|
||
//
|
||
// found one, get the index
|
||
//
|
||
|
||
PS_LOCK(&pInterfaceContext->Adapter->Lock);
|
||
pInterfaceID->InterfaceId = pIpAddrTbl[k].iae_index;
|
||
PS_UNLOCK(&pInterfaceContext->Adapter->Lock);
|
||
break;
|
||
}
|
||
}
|
||
|
||
PsDbgOut(DBG_INFO,
|
||
DBG_PROTOCOL,
|
||
("[SetInterfaceIndex]: InterfaceID (0x%x:0x%x) \n", pInterfaceID->InterfaceId, pInterfaceID->LinkId));
|
||
|
||
PsFreePool(pIpAddrTbl);
|
||
|
||
Done:
|
||
|
||
if(pInterfaceContext->Adapter->MediaType == NdisMediumWan)
|
||
REFDEL(&pInterfaceContext->WanLink->RefCount, FALSE, 'IOTL');
|
||
|
||
REFDEL(&pInterfaceContext->Adapter->RefCount, FALSE, 'IOTL');
|
||
|
||
PsFreePool(pWorkItem);
|
||
PsFreePool(pWorkItemContext);
|
||
|
||
return;
|
||
}
|
||
|
||
VOID PsScheduleInterfaceIdWorkItem(PADAPTER Adapter, PPS_WAN_LINK WanLink)
|
||
{
|
||
PPS_INTERFACE_INDEX_CONTEXT pContext;
|
||
NDIS_STATUS WorkItemStatus;
|
||
PNDIS_WORK_ITEM pWorkItem;
|
||
|
||
PsAllocatePool(pContext, sizeof(PS_INTERFACE_INDEX_CONTEXT), PsMiscTag);
|
||
|
||
if(pContext)
|
||
{
|
||
PsAllocatePool(pWorkItem, sizeof(NDIS_WORK_ITEM), PsMiscTag);
|
||
if(pWorkItem)
|
||
{
|
||
NdisInitializeWorkItem(pWorkItem, SetInterfaceIndex, pContext);
|
||
pContext->Adapter = Adapter;
|
||
pContext->WanLink = WanLink;
|
||
|
||
//
|
||
// We have to make sure that the adapter and the wanlink are around when the WorkItem fires.
|
||
// The adapter and wanlink are valid at this point (see below), but there are no guarantees that
|
||
// they will be around when the work item fires.
|
||
//
|
||
// 1. For LAN bindings, this function is called from the ClRequestComplete thread. The NDIS
|
||
// request has not yet been completed. Hence we can never have an invalid Adapter context here.
|
||
//
|
||
// 2. For WAN links, this function is called from the WAN_LINE_UP thread. Again, the WanLink
|
||
// cannot be invalid because it is called from the context of the line-up thread.
|
||
//
|
||
|
||
if(Adapter)
|
||
{
|
||
REFADD(&Adapter->RefCount, 'IOTL');
|
||
}
|
||
|
||
if(WanLink)
|
||
{
|
||
REFADD(&WanLink->RefCount, 'IOTL');
|
||
}
|
||
|
||
if((WorkItemStatus = NdisScheduleWorkItem(pWorkItem)) != NDIS_STATUS_SUCCESS)
|
||
|
||
{
|
||
PsDbgOut(DBG_TRACE,
|
||
DBG_PROTOCOL,
|
||
("[PsScheduleInterfaceIdWorkItem]: Adapter %08X, NdisScheduleWorkItem failed 0x%x\n",
|
||
Adapter, WorkItemStatus));
|
||
|
||
if(WanLink)
|
||
REFDEL(&WanLink->RefCount, FALSE, 'IOTL');
|
||
|
||
if(Adapter)
|
||
REFDEL(&Adapter->RefCount, FALSE, 'IOTL');
|
||
|
||
PsFreePool(pContext);
|
||
PsFreePool(pWorkItem);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
PsDbgOut(DBG_TRACE,
|
||
DBG_PROTOCOL,
|
||
("[PsScheduleInterfaceIdWorkItem]: Adapter %08X, No memory to allocate Work Item \n", Adapter));
|
||
|
||
PsFreePool(pContext);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
PsDbgOut(DBG_TRACE,
|
||
DBG_PROTOCOL,
|
||
("[PsScheduleInterfaceIdWorkItem]: Adapter %08X, No memory to allocate Work Item context \n", Adapter));
|
||
|
||
}
|
||
}
|
||
|
||
|
||
NDIS_STATUS
|
||
MakeNdisRequest(
|
||
IN PADAPTER Adapter,
|
||
IN NDIS_HANDLE VcHandle,
|
||
IN NDIS_REQUEST_TYPE RequestType,
|
||
IN NDIS_OID Oid,
|
||
IN PVOID InformationBuffer,
|
||
IN ULONG InformationBufferLength,
|
||
OUT PULONG BytesReadOrWritten,
|
||
OUT PULONG BytesNeeded,
|
||
IN LOCAL_NDISREQUEST_COMPLETION_FUNCTION CompletionFunc
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
common handler for set and query information, local ndis request, and
|
||
corequest routines. An NDIS_REQUEST is built and issued to the underlying MP
|
||
|
||
Arguments:
|
||
|
||
See the DDK...
|
||
|
||
CompletionFunc - pointer to a function that gets called when the request
|
||
completion handler has been called. Only used for local requests.
|
||
|
||
RequestType also includes NdisRequestLocal{Set,Query}Info which is used
|
||
to indicate a local request meaning the request is originated by the
|
||
packet scheduler and needs no further completion
|
||
|
||
Return Values:
|
||
|
||
return the value returned to us by the underlying adapter
|
||
|
||
--*/
|
||
|
||
{
|
||
PPS_NDIS_REQUEST PsReqBuffer;
|
||
NDIS_STATUS Status;
|
||
|
||
PsAllocFromLL(&PsReqBuffer, &NdisRequestLL, NdisRequest);
|
||
|
||
if(PsReqBuffer == NULL){
|
||
|
||
if(RequestType == NdisRequestLocalQueryInfo || RequestType == NdisRequestLocalSetInfo)
|
||
{
|
||
PsFreePool(BytesReadOrWritten);
|
||
PsFreePool(BytesNeeded);
|
||
}
|
||
|
||
return NDIS_STATUS_RESOURCES;
|
||
}
|
||
else
|
||
NdisZeroMemory(&PsReqBuffer->ReqBuffer, sizeof(NDIS_REQUEST));
|
||
|
||
|
||
if(RequestType == NdisRequestSetInformation ||
|
||
RequestType == NdisRequestLocalSetInfo){
|
||
|
||
PsReqBuffer->ReqBuffer.RequestType = NdisRequestSetInformation;
|
||
PsReqBuffer->LocalRequest = ( RequestType == NdisRequestLocalSetInfo );
|
||
PsReqBuffer->ReqBuffer.DATA.SET_INFORMATION.Oid = Oid;
|
||
PsReqBuffer->ReqBuffer.DATA.SET_INFORMATION.InformationBuffer =
|
||
InformationBuffer;
|
||
PsReqBuffer->ReqBuffer.DATA.SET_INFORMATION.InformationBufferLength =
|
||
InformationBufferLength;
|
||
|
||
}
|
||
else{
|
||
|
||
PsAssert(RequestType == NdisRequestQueryInformation ||
|
||
RequestType == NdisRequestLocalQueryInfo ||
|
||
RequestType == NdisRequestQueryStatistics);
|
||
|
||
if(RequestType != NdisRequestQueryStatistics){
|
||
PsReqBuffer->ReqBuffer.RequestType = NdisRequestQueryInformation;
|
||
PsReqBuffer->LocalRequest =
|
||
(RequestType == NdisRequestLocalQueryInfo);
|
||
}
|
||
else
|
||
{
|
||
PsReqBuffer->ReqBuffer.RequestType = NdisRequestQueryStatistics;
|
||
PsReqBuffer->LocalRequest = 0;
|
||
}
|
||
|
||
PsReqBuffer->ReqBuffer.DATA.QUERY_INFORMATION.Oid = Oid;
|
||
PsReqBuffer->ReqBuffer.DATA.QUERY_INFORMATION.InformationBuffer =
|
||
InformationBuffer;
|
||
PsReqBuffer->ReqBuffer.DATA.QUERY_INFORMATION.InformationBufferLength =
|
||
InformationBufferLength;
|
||
|
||
}
|
||
|
||
//
|
||
// store the pointers to BytesReadOrWritten and BytesNeeded so they can be
|
||
// updated in the completion routine if necessary. Save the completion func
|
||
//
|
||
|
||
PsReqBuffer->BytesReadOrWritten = BytesReadOrWritten;
|
||
PsReqBuffer->BytesNeeded = BytesNeeded;
|
||
PsReqBuffer->LocalCompletionFunc = CompletionFunc;
|
||
|
||
InterlockedIncrement(&Adapter->OutstandingNdisRequests);
|
||
|
||
if(!PsReqBuffer->LocalRequest && Adapter->PTDeviceState != NdisDeviceStateD0)
|
||
{
|
||
// It's not a local request, and the device is off. So, we pend this request.
|
||
|
||
PsAssert(!VcHandle);
|
||
|
||
PsAssert(Adapter->PendedNdisRequest == 0);
|
||
|
||
Adapter->PendedNdisRequest = PsReqBuffer;
|
||
|
||
return NDIS_STATUS_PENDING;
|
||
}
|
||
|
||
if(VcHandle)
|
||
{
|
||
Status = NdisCoRequest(
|
||
Adapter->LowerMpHandle,
|
||
NULL,
|
||
VcHandle,
|
||
NULL,
|
||
(PNDIS_REQUEST) PsReqBuffer);
|
||
|
||
if(Status != NDIS_STATUS_PENDING) {
|
||
|
||
WanCoRequestComplete(Status, Adapter, NULL, NULL, (PNDIS_REQUEST)PsReqBuffer);
|
||
|
||
}
|
||
}
|
||
else
|
||
{
|
||
NdisRequest(&Status, Adapter->LowerMpHandle, (PNDIS_REQUEST)PsReqBuffer);
|
||
|
||
|
||
if(Status != NDIS_STATUS_PENDING){
|
||
|
||
ClRequestComplete((NDIS_HANDLE)Adapter,
|
||
(PNDIS_REQUEST)PsReqBuffer,
|
||
Status);
|
||
|
||
}
|
||
}
|
||
|
||
return NDIS_STATUS_PENDING;
|
||
} // MakeNdisRequest
|
||
|
||
|
||
VOID
|
||
ClRequestComplete(
|
||
IN NDIS_HANDLE ProtocolBindingContext,
|
||
IN PNDIS_REQUEST NdisRequest,
|
||
IN NDIS_STATUS Status
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Completion routine for NdisRequest. Stuff our block back on the lookaside
|
||
list and call the appropriate completion routine
|
||
|
||
Arguments:
|
||
|
||
See the DDK...
|
||
|
||
Return Values:
|
||
|
||
None
|
||
|
||
--*/
|
||
|
||
{
|
||
PADAPTER Adapter = (PADAPTER)ProtocolBindingContext;
|
||
PPS_NDIS_REQUEST PsReqBuffer;
|
||
NDIS_OID Oid;
|
||
ULONG SpaceAvailable;
|
||
PUCHAR DataStart;
|
||
ULONG Len;
|
||
ULONG i;
|
||
PVOID Data;
|
||
NDIS_STATUS OriStatus = Status;
|
||
|
||
PsReqBuffer = CONTAINING_RECORD( NdisRequest, PS_NDIS_REQUEST, ReqBuffer );
|
||
|
||
PsStructAssert(Adapter);
|
||
|
||
switch(NdisRequest->RequestType)
|
||
{
|
||
case NdisRequestQueryInformation:
|
||
*PsReqBuffer->BytesReadOrWritten = PsReqBuffer->ReqBuffer.DATA.QUERY_INFORMATION.BytesWritten;
|
||
*PsReqBuffer->BytesNeeded = PsReqBuffer->ReqBuffer.DATA.QUERY_INFORMATION.BytesNeeded;
|
||
Oid = PsReqBuffer->ReqBuffer.DATA.QUERY_INFORMATION.Oid;
|
||
Len = PsReqBuffer->ReqBuffer.DATA.QUERY_INFORMATION.InformationBufferLength;
|
||
Data = PsReqBuffer->ReqBuffer.DATA.QUERY_INFORMATION.InformationBuffer;
|
||
|
||
//
|
||
// Process the Query only OIDs here
|
||
//
|
||
switch(Oid)
|
||
{
|
||
case OID_GEN_MAXIMUM_SEND_PACKETS:
|
||
|
||
//
|
||
// see if the underlying MP supports NdisSendPackets.
|
||
// if not, fake it by saying we support one.
|
||
//
|
||
|
||
if(Status != NDIS_STATUS_SUCCESS)
|
||
{
|
||
if(Status == NDIS_STATUS_BUFFER_TOO_SHORT ||
|
||
Status == NDIS_STATUS_INVALID_LENGTH)
|
||
{
|
||
//
|
||
// The underlying MP has indicated that the buffer
|
||
// is too short. We can assume that it supports this
|
||
// OID.
|
||
}
|
||
else
|
||
{
|
||
if(Len >= 1)
|
||
{
|
||
//
|
||
// The underlying MP does not support NdisSendPackets
|
||
// We fake it here.
|
||
//
|
||
|
||
*((PULONG)PsReqBuffer->ReqBuffer.DATA.QUERY_INFORMATION.InformationBuffer)= 1;
|
||
*PsReqBuffer->BytesNeeded = 0;
|
||
*PsReqBuffer->BytesReadOrWritten = 1;
|
||
|
||
Status = NDIS_STATUS_SUCCESS;
|
||
}
|
||
else
|
||
{
|
||
//
|
||
// Buffer too short even to fake!
|
||
//
|
||
Status = NDIS_STATUS_BUFFER_TOO_SHORT;
|
||
*PsReqBuffer->BytesNeeded = 1;
|
||
*PsReqBuffer->BytesReadOrWritten = 0;
|
||
}
|
||
}
|
||
}
|
||
break;
|
||
|
||
case OID_GEN_MAC_OPTIONS:
|
||
|
||
//
|
||
// if querying mac options, add full dux option.
|
||
//
|
||
if(Status == NDIS_STATUS_SUCCESS)
|
||
{
|
||
*((PULONG)PsReqBuffer->
|
||
ReqBuffer.DATA.QUERY_INFORMATION.InformationBuffer) |=
|
||
NDIS_MAC_OPTION_FULL_DUPLEX;
|
||
|
||
//
|
||
// Remove the no-loopback bit from mac-options. In essence we are telling NDIS that we can handle loopback.
|
||
// We don't, but the interface below us does. If we do not do this, then the loopback processing happens below
|
||
// us and above us. This is wasteful at best and if netmon is running multiple packets are seen below us.
|
||
//
|
||
*(PULONG)Data &= ~NDIS_MAC_OPTION_NO_LOOPBACK;
|
||
}
|
||
break;
|
||
|
||
case OID_GEN_CO_VENDOR_DESCRIPTION:
|
||
|
||
//
|
||
// We append some keyword to the end of the Driver
|
||
// Description to indicate that packet scheduler is
|
||
// installed on this interface.
|
||
//
|
||
// Assume that the Data is a string followed by a 0
|
||
// character, and the 0 is accounted for in the
|
||
// len.
|
||
//
|
||
|
||
if(Status == NDIS_STATUS_BUFFER_TOO_SHORT ||
|
||
Status == NDIS_STATUS_INVALID_LENGTH)
|
||
{
|
||
*PsReqBuffer->BytesReadOrWritten = 0;
|
||
*PsReqBuffer->BytesNeeded +=
|
||
sizeof(gDriverDescription);
|
||
}
|
||
else
|
||
{
|
||
if(Status == NDIS_STATUS_SUCCESS)
|
||
{
|
||
//
|
||
// Setup the data pointer and length to copy the
|
||
// descrption into the information buffer
|
||
// passed to us.
|
||
//
|
||
if(Len >=
|
||
NdisRequest->DATA.QUERY_INFORMATION.BytesWritten +
|
||
sizeof(gDriverDescription))
|
||
{
|
||
PCHAR DescStr;
|
||
LONG Written = (LONG)
|
||
NdisRequest->DATA.QUERY_INFORMATION.BytesWritten;
|
||
int i;
|
||
|
||
|
||
//
|
||
// Copy the original string, excluding the '0'
|
||
// character
|
||
//
|
||
for(i=0, DescStr = (PCHAR) Data;
|
||
(*DescStr != 0) && (i < Written); DescStr++, i++)
|
||
;
|
||
*PsReqBuffer->BytesReadOrWritten = i;
|
||
|
||
//
|
||
// Append the new string
|
||
//
|
||
for(i=0; i < sizeof(gDriverDescription); i++)
|
||
{
|
||
*DescStr++ = gDriverDescription[i];
|
||
}
|
||
*PsReqBuffer->BytesReadOrWritten +=
|
||
sizeof(gDriverDescription);
|
||
|
||
*PsReqBuffer->BytesNeeded = 0;
|
||
}
|
||
else
|
||
{
|
||
*PsReqBuffer->BytesNeeded =
|
||
NdisRequest->DATA.QUERY_INFORMATION.BytesWritten +
|
||
sizeof(gDriverDescription);
|
||
*PsReqBuffer->BytesReadOrWritten = 0;
|
||
Status = NDIS_STATUS_BUFFER_TOO_SHORT;
|
||
}
|
||
}
|
||
else {
|
||
//
|
||
// Upper layer failed for some reason.
|
||
// We can still proceed to write the data
|
||
//
|
||
if(Len >= sizeof(gDriverDescription))
|
||
{
|
||
PCHAR DescStr = (PCHAR) Data;
|
||
int i;
|
||
for(i=0; i < sizeof(gDriverDescription); i++)
|
||
{
|
||
*DescStr++ = gDriverDescription[i];
|
||
}
|
||
|
||
*PsReqBuffer->BytesReadOrWritten =
|
||
sizeof(gDriverDescription);
|
||
|
||
*PsReqBuffer->BytesNeeded = 0;
|
||
|
||
Status = NDIS_STATUS_SUCCESS;
|
||
}
|
||
else {
|
||
*PsReqBuffer->BytesNeeded =
|
||
sizeof(gDriverDescription);
|
||
*PsReqBuffer->BytesReadOrWritten = 0;
|
||
Status = NDIS_STATUS_BUFFER_TOO_SHORT;
|
||
}
|
||
}
|
||
}
|
||
break;
|
||
|
||
case OID_PNP_CAPABILITIES:
|
||
if(Status == NDIS_STATUS_SUCCESS)
|
||
{
|
||
MpQueryPnPCapabilities(PsReqBuffer, Adapter, &Status);
|
||
}
|
||
break;
|
||
|
||
case OID_PNP_QUERY_POWER:
|
||
PsAssert(0);
|
||
break;
|
||
|
||
|
||
default:
|
||
break;
|
||
}
|
||
break;
|
||
|
||
case NdisRequestSetInformation:
|
||
|
||
*PsReqBuffer->BytesReadOrWritten = PsReqBuffer->ReqBuffer.DATA.SET_INFORMATION.BytesRead;
|
||
*PsReqBuffer->BytesNeeded = PsReqBuffer->ReqBuffer.DATA.SET_INFORMATION.BytesNeeded;
|
||
Oid = PsReqBuffer->ReqBuffer.DATA.SET_INFORMATION.Oid;
|
||
Len = PsReqBuffer->ReqBuffer.DATA.SET_INFORMATION.InformationBufferLength;
|
||
Data = PsReqBuffer->ReqBuffer.DATA.SET_INFORMATION.InformationBuffer;
|
||
|
||
//
|
||
// Process the "Set Only" OIDs here
|
||
//
|
||
switch(Oid)
|
||
{
|
||
case OID_WAN_PROTOCOL_TYPE:
|
||
{
|
||
if(Adapter->MediaType == NdisMediumWan)
|
||
{
|
||
if (Len > 5)
|
||
{
|
||
Adapter->ProtocolType =
|
||
(((PUCHAR)Data)[4] << 8) |
|
||
((PUCHAR)Data)[5];
|
||
|
||
}
|
||
}
|
||
|
||
break;
|
||
}
|
||
|
||
case OID_GEN_TRANSPORT_HEADER_OFFSET:
|
||
{
|
||
if(Len >= sizeof(TRANSPORT_HEADER_OFFSET) )
|
||
{
|
||
PTRANSPORT_HEADER_OFFSET pTh = (PTRANSPORT_HEADER_OFFSET) Data;
|
||
|
||
if(pTh->ProtocolType == NDIS_PROTOCOL_ID_TCP_IP)
|
||
{
|
||
Adapter->IPHeaderOffset = pTh->HeaderOffset;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
Status = NDIS_STATUS_BUFFER_TOO_SHORT;
|
||
*PsReqBuffer->BytesReadOrWritten = 0;
|
||
*PsReqBuffer->BytesNeeded = sizeof(TRANSPORT_HEADER_OFFSET);
|
||
}
|
||
|
||
break;
|
||
}
|
||
|
||
|
||
|
||
case OID_GEN_NETWORK_LAYER_ADDRESSES:
|
||
|
||
//
|
||
// Updated network addresses from a transport.
|
||
//
|
||
Status = RecordNetworkAddressList(Adapter, PsReqBuffer);
|
||
|
||
//
|
||
// Queue a work item to update the Interface ID
|
||
//
|
||
|
||
PsScheduleInterfaceIdWorkItem(Adapter, 0);
|
||
|
||
//
|
||
// Do a status indication to show that the list has
|
||
// changed.
|
||
//
|
||
|
||
TcIndicateInterfaceChange(Adapter, 0, NDIS_STATUS_INTERFACE_CHANGE);
|
||
|
||
break;
|
||
|
||
case OID_PNP_SET_POWER:
|
||
PsAssert(0);
|
||
break;
|
||
|
||
default:
|
||
break;
|
||
}
|
||
break;
|
||
|
||
case NdisRequestLocalQueryInfo:
|
||
break;
|
||
|
||
default:
|
||
|
||
PsAssert(0);
|
||
break;
|
||
}
|
||
|
||
#if DBG
|
||
switch(Oid)
|
||
{
|
||
case OID_GEN_MEDIA_CONNECT_STATUS:
|
||
|
||
PsDbgOid(DBG_TRACE,
|
||
DBG_ROUTINEOIDS,
|
||
(PsReqBuffer->ReqBuffer.RequestType == NdisRequestSetInformation)
|
||
? TRACE_OID_SET_REQUEST_COMPLETE: TRACE_OID_QUERY_REQUEST_COMPLETE,
|
||
PsReqBuffer->LocalRequest ? 1:0,
|
||
Adapter->PTDeviceState,
|
||
Adapter->MPDeviceState,
|
||
Adapter,
|
||
Oid,
|
||
OriStatus);
|
||
break;
|
||
|
||
default:
|
||
PsDbgOid(DBG_TRACE,
|
||
DBG_PROTOCOL,
|
||
(PsReqBuffer->ReqBuffer.RequestType == NdisRequestSetInformation)
|
||
? TRACE_OID_SET_REQUEST_COMPLETE: TRACE_OID_QUERY_REQUEST_COMPLETE,
|
||
PsReqBuffer->LocalRequest ? 1:0,
|
||
Adapter->PTDeviceState,
|
||
Adapter->MPDeviceState,
|
||
Adapter,
|
||
Oid,
|
||
OriStatus);
|
||
break;
|
||
}
|
||
#endif
|
||
|
||
//
|
||
// if the caller specified a local completion function, then call it now.
|
||
// this function is responsible for completing the original request
|
||
//
|
||
|
||
if(PsReqBuffer->LocalCompletionFunc){
|
||
|
||
(*PsReqBuffer->LocalCompletionFunc)(Adapter, Status);
|
||
PsFreePool(PsReqBuffer->BytesReadOrWritten);
|
||
PsFreePool(PsReqBuffer->BytesNeeded);
|
||
}
|
||
else{
|
||
|
||
//
|
||
// if this was a PS originated request and no local completion
|
||
// function was specified, then set the event to indicate that
|
||
// the request completed. Note that the event can only be used
|
||
// at lowered IRQL.
|
||
//
|
||
if(PsReqBuffer->LocalRequest)
|
||
{
|
||
Adapter->FinalStatus = Status;
|
||
NdisSetEvent( &Adapter->LocalRequestEvent);
|
||
PsFreePool(PsReqBuffer->BytesReadOrWritten);
|
||
PsFreePool(PsReqBuffer->BytesNeeded);
|
||
}
|
||
else{
|
||
|
||
Adapter->PendedNdisRequest = 0;
|
||
|
||
//
|
||
// if this is not a local request, call the
|
||
// appropriate NDIS completion routine
|
||
//
|
||
if(NdisRequest->RequestType == NdisRequestSetInformation)
|
||
{
|
||
NdisMSetInformationComplete(Adapter->PsNdisHandle, Status);
|
||
}
|
||
else
|
||
{
|
||
NdisMQueryInformationComplete(Adapter->PsNdisHandle, Status);
|
||
}
|
||
}
|
||
}
|
||
|
||
InterlockedDecrement(&Adapter->OutstandingNdisRequests);
|
||
|
||
//
|
||
// give back our ndis request buffer
|
||
//
|
||
|
||
PsFreeToLL(PsReqBuffer, &NdisRequestLL, NdisRequest);
|
||
|
||
|
||
} // ClRequestComplete
|
||
|
||
|
||
|
||
NDIS_STATUS
|
||
MakeLocalNdisRequest(
|
||
PADAPTER Adapter,
|
||
NDIS_HANDLE VcHandle,
|
||
NDIS_REQUEST_TYPE RequestType,
|
||
NDIS_OID Oid,
|
||
PVOID Buffer,
|
||
ULONG BufferSize,
|
||
LOCAL_NDISREQUEST_COMPLETION_FUNCTION CompletionFunc OPTIONAL
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Make an NdisRequest to the underlying adapter on behalf of the packet scheduler
|
||
|
||
Arguments:
|
||
|
||
Adapter and Oid should be obvious
|
||
|
||
Buffer, BufferSize - pointer to and size of location that receives the info
|
||
|
||
CompletionFunc - if non-null, then don't wait on the adapter's event. Used when we're
|
||
running at dispatch level
|
||
|
||
Return Value:
|
||
|
||
Standard NDIS_STATUS from an NdisRequest
|
||
|
||
--*/
|
||
|
||
{
|
||
NDIS_STATUS Status;
|
||
PULONG BytesRead, BytesNeeded;
|
||
|
||
|
||
PsAssert(RequestType == NdisRequestLocalQueryInfo || RequestType == NdisRequestLocalSetInfo);
|
||
|
||
//
|
||
// Need to allocate space for BytesWritten & BytesNeeded because
|
||
// we wait only for requests that do not have a Completion Function
|
||
// Hence the Completion function could be writing to a stale stack
|
||
// variable
|
||
//
|
||
|
||
PsAllocatePool(BytesNeeded, sizeof(ULONG), PsMiscTag);
|
||
|
||
if(!BytesNeeded)
|
||
{
|
||
return NDIS_STATUS_RESOURCES;
|
||
}
|
||
|
||
PsAllocatePool(BytesRead, sizeof(ULONG), PsMiscTag);
|
||
|
||
if(!BytesRead)
|
||
{
|
||
PsFreePool(BytesNeeded);
|
||
|
||
return NDIS_STATUS_RESOURCES;
|
||
}
|
||
|
||
Status = MakeNdisRequest(Adapter,
|
||
VcHandle,
|
||
RequestType,
|
||
Oid,
|
||
Buffer,
|
||
BufferSize,
|
||
BytesRead,
|
||
BytesNeeded,
|
||
CompletionFunc);
|
||
|
||
//
|
||
// only wait if no completion function has been specified
|
||
//
|
||
|
||
if ( !ARGUMENT_PRESENT( CompletionFunc ) &&
|
||
Status == NDIS_STATUS_PENDING ) {
|
||
|
||
NdisWaitEvent( &Adapter->LocalRequestEvent, 0 );
|
||
NdisResetEvent( &Adapter->LocalRequestEvent );
|
||
Status = Adapter->FinalStatus;
|
||
}
|
||
|
||
return Status;
|
||
|
||
} // MakeLocalNdisRequest
|
||
|
||
|
||
NDIS_STATUS
|
||
MpQueryInformation(
|
||
IN NDIS_HANDLE MiniportAdapterContext,
|
||
IN NDIS_OID Oid,
|
||
IN PVOID InformationBuffer,
|
||
IN ULONG InformationBufferLength,
|
||
OUT PULONG BytesWritten,
|
||
OUT PULONG BytesNeeded
|
||
)
|
||
{
|
||
|
||
PADAPTER Adapter = (PADAPTER) MiniportAdapterContext;
|
||
PVOID Data = InformationBuffer;
|
||
ULONG Len = InformationBufferLength;
|
||
|
||
PsStructAssert(Adapter);
|
||
|
||
PsAssert(Adapter->PsMpState != AdapterStateWaiting);
|
||
|
||
#if DBG
|
||
switch(Oid)
|
||
{
|
||
case OID_GEN_MEDIA_CONNECT_STATUS:
|
||
|
||
PsDbgOid(DBG_TRACE,
|
||
DBG_ROUTINEOIDS,
|
||
TRACE_OID_MP_QUERYINFORMATION,
|
||
0,
|
||
Adapter->PTDeviceState,
|
||
Adapter->MPDeviceState,
|
||
Adapter,
|
||
Oid,
|
||
0);
|
||
break;
|
||
|
||
default:
|
||
PsDbgOid(DBG_TRACE,
|
||
DBG_MINIPORT,
|
||
TRACE_OID_MP_QUERYINFORMATION,
|
||
0,
|
||
Adapter->PTDeviceState,
|
||
Adapter->MPDeviceState,
|
||
Adapter,
|
||
Oid,
|
||
0);
|
||
break;
|
||
}
|
||
#endif
|
||
|
||
if(Oid == OID_PNP_QUERY_POWER)
|
||
{
|
||
return NDIS_STATUS_SUCCESS;
|
||
}
|
||
|
||
if (Oid == OID_GEN_SUPPORTED_GUIDS)
|
||
{
|
||
//
|
||
// Do not forward this OID, otherwise we will end up with multiple
|
||
// WMI instances of private GUIDs that the underlying miniport
|
||
// supports.
|
||
//
|
||
return NDIS_STATUS_NOT_SUPPORTED;
|
||
}
|
||
|
||
if(Adapter->StandingBy == TRUE ||
|
||
Adapter->PsMpState != AdapterStateRunning ||
|
||
Adapter->MPDeviceState != NdisDeviceStateD0)
|
||
{
|
||
return NDIS_STATUS_FAILURE;
|
||
}
|
||
|
||
switch(Oid)
|
||
{
|
||
case OID_GEN_CO_DRIVER_VERSION:
|
||
//
|
||
// The NDIS version in use by the NIC driver. The high byte is
|
||
// the major version number and the low byte is the minor
|
||
// version number. We don't need to pass this down -
|
||
// Irrespective of what version the driver below uses, we
|
||
// need to return the version that we support.
|
||
//
|
||
|
||
if(Len < sizeof(USHORT))
|
||
{
|
||
*BytesNeeded = sizeof(USHORT);
|
||
|
||
return NDIS_STATUS_BUFFER_TOO_SHORT;
|
||
|
||
}
|
||
else
|
||
{
|
||
PUSHORT pData = (PUSHORT) Data;
|
||
|
||
*pData = 0x0500;
|
||
|
||
*BytesWritten = sizeof(USHORT);
|
||
|
||
return NDIS_STATUS_SUCCESS;
|
||
}
|
||
|
||
break;
|
||
/*
|
||
case OID_GEN_MAC_OPTIONS:
|
||
//
|
||
// This is to indicate to NDIS that PSched always indicates recv-up in the same context
|
||
// of its recv-from or at DPC
|
||
//
|
||
|
||
if(Len < sizeof(ULONG))
|
||
{
|
||
*BytesNeeded = sizeof(ULONG);
|
||
|
||
return NDIS_STATUS_BUFFER_TOO_SHORT;
|
||
|
||
}
|
||
else
|
||
{
|
||
PULONG pData = (PULONG) Data;
|
||
|
||
*pData |= NDIS_MAC_OPTION_RECEIVE_AT_DPC;
|
||
|
||
*BytesWritten = sizeof(ULONG);
|
||
|
||
return NDIS_STATUS_SUCCESS;
|
||
}
|
||
|
||
break;
|
||
|
||
case OID_GEN_PROTOCOL_OPTIONS:
|
||
//
|
||
// This is to indicate to NDIS that PSched always sends-down packets in the same context as the
|
||
// send-from-above came from or at IRQL = DPC
|
||
//
|
||
|
||
if(Len < sizeof(ULONG))
|
||
{
|
||
*BytesNeeded = sizeof(ULONG);
|
||
|
||
return NDIS_STATUS_BUFFER_TOO_SHORT;
|
||
|
||
}
|
||
else
|
||
{
|
||
PULONG pData = (PULONG) Data;
|
||
|
||
*pData |= NDIS_PROT_OPTION_SEND_RESTRICTED;
|
||
|
||
*BytesWritten = sizeof(ULONG);
|
||
|
||
return NDIS_STATUS_SUCCESS;
|
||
}
|
||
|
||
break;
|
||
*/
|
||
}
|
||
|
||
//
|
||
// By default, send other requests down.
|
||
//
|
||
|
||
return MakeNdisRequest(Adapter,
|
||
NULL,
|
||
NdisRequestQueryInformation,
|
||
Oid,
|
||
Data,
|
||
Len,
|
||
BytesWritten,
|
||
BytesNeeded,
|
||
NULL);
|
||
}
|
||
|
||
|
||
NDIS_STATUS
|
||
MpSetInformation(
|
||
IN NDIS_HANDLE MiniportAdapterContext,
|
||
IN NDIS_OID Oid,
|
||
IN PVOID InformationBuffer,
|
||
IN ULONG InformationBufferLength,
|
||
OUT PULONG BytesRead,
|
||
OUT PULONG BytesNeeded
|
||
)
|
||
{
|
||
PADAPTER Adapter = (PADAPTER) MiniportAdapterContext;
|
||
NDIS_STATUS Status;
|
||
|
||
PsStructAssert(Adapter);
|
||
PsAssert(Adapter->PsMpState != AdapterStateWaiting);
|
||
|
||
#if DBG
|
||
switch(Oid)
|
||
{
|
||
case OID_GEN_MEDIA_CONNECT_STATUS:
|
||
|
||
PsDbgOid(DBG_TRACE,
|
||
DBG_ROUTINEOIDS,
|
||
TRACE_OID_MP_SETINFORMATION,
|
||
0,
|
||
Adapter->PTDeviceState,
|
||
Adapter->MPDeviceState,
|
||
Adapter,
|
||
Oid,
|
||
0);
|
||
break;
|
||
|
||
default:
|
||
PsDbgOid(DBG_TRACE,
|
||
DBG_MINIPORT,
|
||
TRACE_OID_MP_SETINFORMATION,
|
||
0,
|
||
Adapter->PTDeviceState,
|
||
Adapter->MPDeviceState,
|
||
Adapter,
|
||
Oid,
|
||
0);
|
||
break;
|
||
}
|
||
#endif
|
||
|
||
switch(Oid)
|
||
{
|
||
case OID_PNP_SET_POWER:
|
||
|
||
//
|
||
// This is not transparent to us - We cannot send it down.
|
||
// Just succeed it!
|
||
//
|
||
if(InformationBufferLength >= sizeof(NDIS_DEVICE_POWER_STATE))
|
||
{
|
||
NDIS_DEVICE_POWER_STATE NewDeviceState =
|
||
(*(PNDIS_DEVICE_POWER_STATE) InformationBuffer);
|
||
|
||
//
|
||
// If the miniport is transitioning from a low power state to ON (D0), then clear the StandingBy flag
|
||
// All incoming requests will be pended until the physical miniport turns ON.
|
||
//
|
||
|
||
if(Adapter->MPDeviceState > NdisDeviceStateD0 && NewDeviceState == NdisDeviceStateD0)
|
||
{
|
||
Adapter->StandingBy = FALSE;
|
||
}
|
||
|
||
//
|
||
// Is the miniport transitioning from an On (D0) state to an Low Power State (>D0)
|
||
// If so, then set the StandingBy Flag - (Block all incoming requests)
|
||
//
|
||
|
||
if(Adapter->MPDeviceState == NdisDeviceStateD0 && NewDeviceState > NdisDeviceStateD0)
|
||
{
|
||
Adapter->StandingBy = TRUE;
|
||
}
|
||
|
||
// update the new device state.
|
||
|
||
Adapter->MPDeviceState = NewDeviceState;
|
||
Status = NDIS_STATUS_SUCCESS;
|
||
*BytesRead = sizeof(NDIS_DEVICE_POWER_STATE);
|
||
*BytesNeeded = 0;
|
||
|
||
if(IsDeviceStateOn(Adapter) == TRUE)
|
||
{
|
||
PsGetLinkSpeed(Adapter);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
Status = NDIS_STATUS_INVALID_LENGTH;
|
||
*BytesRead = 0;
|
||
*BytesNeeded = sizeof(NDIS_DEVICE_POWER_STATE);
|
||
}
|
||
|
||
return Status;
|
||
}
|
||
|
||
if(Adapter->StandingBy == TRUE ||
|
||
Adapter->PsMpState != AdapterStateRunning ||
|
||
Adapter->MPDeviceState != NdisDeviceStateD0)
|
||
{
|
||
return NDIS_STATUS_FAILURE;
|
||
}
|
||
|
||
Status = MakeNdisRequest(Adapter,
|
||
NULL,
|
||
NdisRequestSetInformation,
|
||
Oid,
|
||
InformationBuffer,
|
||
InformationBufferLength,
|
||
BytesRead,
|
||
BytesNeeded,
|
||
NULL);
|
||
|
||
return Status;
|
||
}
|
||
|
||
|
||
NDIS_STATUS
|
||
CollectNetworkAddresses(
|
||
IN PADAPTER Adapter,
|
||
IN OUT ULONG *Len,
|
||
IN PVOID Data
|
||
)
|
||
{
|
||
ULONG RequiredBufferSize = 0;
|
||
ULONG RequiredIpBufferSize;
|
||
ULONG RequiredIpxBufferSize;
|
||
NETWORK_ADDRESS_LIST UNALIGNED *NetworkAddressList;
|
||
PTC_SUPPORTED_INFO_BUFFER TcQueryBuffer;
|
||
PADDRESS_LIST_DESCRIPTOR AddressDescriptorList;
|
||
PUCHAR AddressListIndex;
|
||
NDIS_STATUS Status;
|
||
NDIS_STRING Prefix = NDIS_STRING_CONST("\\Device\\");
|
||
|
||
//
|
||
// Ip address list
|
||
//
|
||
|
||
PS_LOCK(&Adapter->Lock);
|
||
|
||
if(Adapter->IpNetAddressList){
|
||
|
||
RequiredIpBufferSize = GetSizeAddrList(Adapter->IpNetAddressList);
|
||
|
||
//
|
||
// Returned buffer size actually includes extra bytes for
|
||
// address count and type. But - when we merge the lists,
|
||
// we'll replace the separate fields. So - subtract them out.
|
||
//
|
||
|
||
RequiredIpBufferSize -= FIELD_OFFSET(NETWORK_ADDRESS_LIST, Address);
|
||
}
|
||
else{
|
||
|
||
RequiredIpBufferSize = 0;
|
||
}
|
||
|
||
RequiredBufferSize += RequiredIpBufferSize;
|
||
|
||
//
|
||
// Add space for the Ipx address list
|
||
//
|
||
|
||
if(Adapter->IpxNetAddressList){
|
||
|
||
RequiredIpxBufferSize = GetSizeAddrList(Adapter->IpxNetAddressList);
|
||
|
||
//
|
||
// Returned buffer size actually includes extra bytes for
|
||
// address count and type. But - when we merge the lists,
|
||
// we'll replace the separate fields. So - subtract them out.
|
||
//
|
||
|
||
RequiredIpxBufferSize -= FIELD_OFFSET(NETWORK_ADDRESS_LIST, Address);
|
||
}
|
||
else{
|
||
|
||
RequiredIpxBufferSize = 0;
|
||
}
|
||
|
||
RequiredBufferSize += RequiredIpxBufferSize;
|
||
|
||
//
|
||
// Add space for the address list fields
|
||
//
|
||
|
||
RequiredBufferSize += FIELD_OFFSET(NETWORK_ADDRESS_LIST, Address);
|
||
|
||
//
|
||
// Add space for TC_SUPPORTED_INFO_BUFFER
|
||
//
|
||
RequiredBufferSize = RequiredBufferSize +
|
||
FIELD_OFFSET(TC_SUPPORTED_INFO_BUFFER, AddrListDesc) +
|
||
FIELD_OFFSET(ADDRESS_LIST_DESCRIPTOR, AddressList);
|
||
|
||
if(*Len > 0){
|
||
|
||
NdisZeroMemory(Data, *Len);
|
||
}
|
||
|
||
if(*Len >= RequiredBufferSize){
|
||
|
||
TcQueryBuffer = (PTC_SUPPORTED_INFO_BUFFER) Data;
|
||
|
||
//
|
||
// Fill in the upper binding, after striping the device
|
||
//
|
||
NdisMoveMemory(TcQueryBuffer->InstanceID,
|
||
(PUCHAR) Adapter->MpDeviceName.Buffer +
|
||
Prefix.Length,
|
||
Adapter->MpDeviceName.Length - Prefix.Length);
|
||
|
||
TcQueryBuffer->InstanceIDLength = Adapter->MpDeviceName.Length - Prefix.Length;
|
||
|
||
|
||
//
|
||
// Fill in the AddressListDescriptor
|
||
//
|
||
AddressDescriptorList = &TcQueryBuffer->AddrListDesc;
|
||
|
||
AddressDescriptorList->MediaType = Adapter->MediaType;
|
||
|
||
NetworkAddressList = (NETWORK_ADDRESS_LIST UNALIGNED *)
|
||
&AddressDescriptorList->AddressList;
|
||
|
||
AddressListIndex = (PUCHAR)&NetworkAddressList->Address;
|
||
|
||
if(RequiredIpBufferSize){
|
||
|
||
NdisMoveMemory(
|
||
AddressListIndex,
|
||
(PUCHAR)(&Adapter->IpNetAddressList->Address),
|
||
RequiredIpBufferSize
|
||
);
|
||
|
||
}
|
||
|
||
AddressListIndex += RequiredIpBufferSize;
|
||
|
||
if(RequiredIpxBufferSize){
|
||
|
||
NdisMoveMemory(
|
||
AddressListIndex,
|
||
(PUCHAR)(&Adapter->IpxNetAddressList->Address),
|
||
RequiredIpxBufferSize
|
||
);
|
||
}
|
||
|
||
AddressListIndex += RequiredIpxBufferSize;
|
||
|
||
if(RequiredIpBufferSize){
|
||
|
||
NetworkAddressList->AddressCount =
|
||
Adapter->IpNetAddressList->AddressCount;
|
||
}
|
||
|
||
if(RequiredIpxBufferSize){
|
||
|
||
NetworkAddressList->AddressCount +=
|
||
Adapter->IpxNetAddressList->AddressCount;
|
||
}
|
||
|
||
NetworkAddressList->AddressType = 0;
|
||
|
||
*Len = RequiredBufferSize;
|
||
|
||
Status = NDIS_STATUS_SUCCESS;
|
||
}
|
||
else{
|
||
|
||
*Len = RequiredBufferSize;
|
||
|
||
Status = NDIS_STATUS_BUFFER_TOO_SHORT;
|
||
}
|
||
|
||
PS_UNLOCK(&Adapter->Lock);
|
||
|
||
return(Status);
|
||
}
|
||
|
||
NDIS_STATUS
|
||
CollectWanNetworkAddresses(
|
||
IN PADAPTER Adapter,
|
||
IN PPS_WAN_LINK WanLink,
|
||
IN OUT ULONG *Len,
|
||
IN PVOID Data
|
||
)
|
||
{
|
||
ULONG RequiredBufferSize = 0;
|
||
NETWORK_ADDRESS_LIST UNALIGNED *NetworkAddressList;
|
||
NETWORK_ADDRESS UNALIGNED *NetworkAddress;
|
||
PTC_SUPPORTED_INFO_BUFFER TcQueryBuffer;
|
||
PADDRESS_LIST_DESCRIPTOR AddressDescriptorList;
|
||
NETWORK_ADDRESS_IP UNALIGNED *pIp;
|
||
NDIS_STATUS Status;
|
||
NDIS_STRING Prefix = NDIS_STRING_CONST("\\Device\\");
|
||
|
||
PsAssert(Adapter->MediaType == NdisMediumWan);
|
||
|
||
//
|
||
// Ip address list
|
||
//
|
||
|
||
switch(WanLink->ProtocolType)
|
||
{
|
||
|
||
case PROTOCOL_IP:
|
||
|
||
if(WanLink->DialUsage == DU_CALLOUT) {
|
||
|
||
RequiredBufferSize = FIELD_OFFSET(NETWORK_ADDRESS_LIST, Address) +
|
||
(FIELD_OFFSET(NETWORK_ADDRESS, Address) + NETWORK_ADDRESS_LENGTH_IP);
|
||
}
|
||
else {
|
||
|
||
//
|
||
// Include room for a pair of addresses (one local, one remote). Only for Dial in
|
||
// or router-router links.
|
||
//
|
||
|
||
RequiredBufferSize = FIELD_OFFSET(NETWORK_ADDRESS_LIST, Address) +
|
||
2 * (FIELD_OFFSET(NETWORK_ADDRESS, Address) +
|
||
NETWORK_ADDRESS_LENGTH_IP);
|
||
}
|
||
|
||
break;
|
||
|
||
case PROTOCOL_IPX:
|
||
|
||
//
|
||
// Not yet supported.
|
||
//
|
||
|
||
default:
|
||
|
||
RequiredBufferSize = 0;
|
||
}
|
||
|
||
//
|
||
// Add space for TC_SUPPORTED_INFO_BUFFER
|
||
//
|
||
|
||
RequiredBufferSize = RequiredBufferSize +
|
||
FIELD_OFFSET(TC_SUPPORTED_INFO_BUFFER, AddrListDesc) +
|
||
FIELD_OFFSET(ADDRESS_LIST_DESCRIPTOR, AddressList);
|
||
|
||
if(*Len >= RequiredBufferSize)
|
||
{
|
||
TcQueryBuffer = (PTC_SUPPORTED_INFO_BUFFER) Data;
|
||
|
||
//
|
||
// Fill in the device name
|
||
//
|
||
if(WanLink->MpDeviceName.Length > Prefix.Length)
|
||
{
|
||
NdisMoveMemory(TcQueryBuffer->InstanceID,
|
||
(PUCHAR) WanLink->MpDeviceName.Buffer + Prefix.Length,
|
||
WanLink->MpDeviceName.MaximumLength - Prefix.Length);
|
||
|
||
TcQueryBuffer->InstanceIDLength = WanLink->MpDeviceName.Length - Prefix.Length;
|
||
}
|
||
else
|
||
{
|
||
//
|
||
// We have got a MpDevice name that is less than \Device. What is the point in
|
||
// stripping the \Device from this ??
|
||
//
|
||
|
||
PsDbgOut(DBG_FAILURE,
|
||
DBG_WAN,
|
||
("[CollectWanNetworkAddresses]: WanLink %08X, MpDeviceName is too small to strip \\Device \n",
|
||
WanLink));
|
||
|
||
NdisMoveMemory(TcQueryBuffer->InstanceID,
|
||
WanLink->MpDeviceName.Buffer,
|
||
WanLink->MpDeviceName.MaximumLength);
|
||
|
||
TcQueryBuffer->InstanceIDLength = WanLink->MpDeviceName.Length;
|
||
|
||
}
|
||
|
||
//
|
||
// Fill in the AddressListDescriptor
|
||
//
|
||
AddressDescriptorList = &TcQueryBuffer->AddrListDesc;
|
||
|
||
AddressDescriptorList->MediaType = NdisMediumWan;
|
||
|
||
NetworkAddressList = (NETWORK_ADDRESS_LIST UNALIGNED *)
|
||
&AddressDescriptorList->AddressList;
|
||
|
||
NetworkAddress = (NETWORK_ADDRESS UNALIGNED *)&NetworkAddressList->Address;
|
||
|
||
switch(WanLink->ProtocolType){
|
||
|
||
case PROTOCOL_IP:
|
||
|
||
NetworkAddressList->AddressType = NDIS_PROTOCOL_ID_TCP_IP;
|
||
|
||
//
|
||
// Fill in the local address
|
||
//
|
||
NetworkAddressList->AddressCount = 1;
|
||
NetworkAddress->AddressType = NDIS_PROTOCOL_ID_TCP_IP;
|
||
NetworkAddress->AddressLength = NETWORK_ADDRESS_LENGTH_IP;
|
||
pIp = (NETWORK_ADDRESS_IP UNALIGNED *)NetworkAddress->Address;
|
||
pIp->in_addr = WanLink->LocalIpAddress;
|
||
|
||
//
|
||
// Fill in the remote address only for non callout
|
||
//
|
||
|
||
if(WanLink->DialUsage != DU_CALLOUT) {
|
||
|
||
NetworkAddressList->AddressCount ++;
|
||
|
||
NetworkAddress = (NETWORK_ADDRESS UNALIGNED *)
|
||
((PCHAR)NetworkAddress +
|
||
(FIELD_OFFSET(NETWORK_ADDRESS,Address)+ NETWORK_ADDRESS_LENGTH_IP));
|
||
|
||
NetworkAddress->AddressLength = NETWORK_ADDRESS_LENGTH_IP;
|
||
NetworkAddress->AddressType = NDIS_PROTOCOL_ID_TCP_IP;
|
||
pIp = (NETWORK_ADDRESS_IP UNALIGNED *)NetworkAddress->Address;
|
||
pIp->in_addr = WanLink->RemoteIpAddress;
|
||
}
|
||
|
||
break;
|
||
|
||
case PROTOCOL_IPX:
|
||
default:
|
||
|
||
//
|
||
// Not supported, return zero addresses.
|
||
//
|
||
|
||
NetworkAddressList->AddressCount = 0;
|
||
}
|
||
|
||
*Len = RequiredBufferSize;
|
||
|
||
Status = NDIS_STATUS_SUCCESS;
|
||
}
|
||
else{
|
||
|
||
*Len = RequiredBufferSize;
|
||
|
||
Status = NDIS_STATUS_BUFFER_TOO_SHORT;
|
||
}
|
||
|
||
return(Status);
|
||
}
|
||
|
||
NDIS_STATUS
|
||
RecordNetworkAddressList(
|
||
IN PADAPTER Adapter,
|
||
IN PPS_NDIS_REQUEST PsReqBuffer
|
||
)
|
||
{
|
||
NETWORK_ADDRESS_LIST UNALIGNED *AddressList, **pListDestination;
|
||
ULONG NewListSize;
|
||
ULONG OldListSize;
|
||
|
||
PS_LOCK(&Adapter->Lock);
|
||
|
||
AddressList = (NETWORK_ADDRESS_LIST UNALIGNED *)(PsReqBuffer->ReqBuffer.
|
||
DATA.SET_INFORMATION.InformationBuffer);
|
||
|
||
//
|
||
// Handle special case of a zero count address list. This means
|
||
// that the protocol is clearing the address list.
|
||
//
|
||
|
||
if(!AddressList->AddressCount){
|
||
|
||
//
|
||
// In this case, we use the top level AddressType to
|
||
// indicate the protocol.
|
||
//
|
||
|
||
switch(AddressList->AddressType){
|
||
|
||
case NDIS_PROTOCOL_ID_TCP_IP:
|
||
|
||
pListDestination = &Adapter->IpNetAddressList;
|
||
break;
|
||
|
||
case NDIS_PROTOCOL_ID_IPX:
|
||
|
||
pListDestination = &Adapter->IpxNetAddressList;
|
||
break;
|
||
|
||
default:
|
||
|
||
//
|
||
// Only maintain IP and IPX addresses for now
|
||
//
|
||
PS_UNLOCK(&Adapter->Lock);
|
||
|
||
return NDIS_STATUS_NOT_SUPPORTED;
|
||
}
|
||
|
||
(*pListDestination)->AddressType = AddressList->AddressType;
|
||
(*pListDestination)->AddressCount = 0;
|
||
|
||
PS_UNLOCK(&Adapter->Lock);
|
||
|
||
return(NDIS_STATUS_SUCCESS);
|
||
}
|
||
|
||
//
|
||
// We can tell from the first address type ifdentifier, whether
|
||
// this buffer carries addresses from the IP transport or the
|
||
// IPX transport.
|
||
//
|
||
|
||
switch(AddressList->Address[0].AddressType){
|
||
|
||
case NDIS_PROTOCOL_ID_TCP_IP:
|
||
|
||
pListDestination = &Adapter->IpNetAddressList;
|
||
break;
|
||
|
||
case NDIS_PROTOCOL_ID_IPX:
|
||
|
||
pListDestination = &Adapter->IpxNetAddressList;
|
||
break;
|
||
|
||
default:
|
||
|
||
//
|
||
// Only maintain IP and IPX addresses for now
|
||
//
|
||
|
||
PS_UNLOCK(&Adapter->Lock);
|
||
return NDIS_STATUS_NOT_SUPPORTED;
|
||
}
|
||
|
||
NewListSize = GetSizeAddrList(AddressList);
|
||
OldListSize = GetSizeAddrList(*pListDestination);
|
||
|
||
if(NewListSize > OldListSize){
|
||
|
||
//
|
||
// Then we need a new buffer. Free the old one.
|
||
//
|
||
|
||
PsFreePool(*pListDestination);
|
||
|
||
PsAllocatePool(*pListDestination,
|
||
NewListSize,
|
||
PsMiscTag);
|
||
|
||
if(0 == *pListDestination)
|
||
{
|
||
PsDbgOut(DBG_CRITICAL_ERROR,
|
||
DBG_PROTOCOL,
|
||
("[RecordNetworkAddressList]: Adapter %08X, "
|
||
"No room for Network addresses list, failed to allocate %d bytes \n",
|
||
Adapter, NewListSize));
|
||
|
||
PS_UNLOCK(&Adapter->Lock);
|
||
PsAdapterWriteEventLog(
|
||
(ULONG)EVENT_PS_NETWORK_ADDRESS_FAIL,
|
||
0,
|
||
&Adapter->MpDeviceName,
|
||
0,
|
||
NULL);
|
||
|
||
return NDIS_STATUS_RESOURCES;
|
||
}
|
||
}
|
||
|
||
NdisMoveMemory(*pListDestination,
|
||
AddressList,
|
||
NewListSize);
|
||
|
||
PS_UNLOCK(&Adapter->Lock);
|
||
|
||
return NDIS_STATUS_SUCCESS;
|
||
}
|
||
|
||
ULONG
|
||
GetSizeAddrList(
|
||
IN NETWORK_ADDRESS_LIST UNALIGNED *AddrList
|
||
)
|
||
{
|
||
NETWORK_ADDRESS UNALIGNED *NextAddress;
|
||
LONG i;
|
||
ULONG ListSize = 0;
|
||
ULONG ElementSize = 0;
|
||
|
||
if(!AddrList->AddressCount){
|
||
|
||
return(FIELD_OFFSET(NETWORK_ADDRESS_LIST, Address));
|
||
}
|
||
|
||
NextAddress = &(AddrList->Address[0]);
|
||
|
||
for(i = 0;i < AddrList->AddressCount; i++){
|
||
|
||
//
|
||
// Each address element is the number of bytes
|
||
// indicated by AddressLength plus the size of
|
||
// a NETWORK_ADDRESS structure, minus the one
|
||
// byte used for the adress array (see struct).
|
||
//
|
||
|
||
ElementSize = FIELD_OFFSET(NETWORK_ADDRESS, Address);
|
||
ElementSize += NextAddress->AddressLength;
|
||
|
||
ListSize += ElementSize;
|
||
|
||
NextAddress = (NETWORK_ADDRESS UNALIGNED *)
|
||
((PUCHAR)NextAddress + ElementSize);
|
||
|
||
ElementSize = 0;
|
||
}
|
||
|
||
//
|
||
// Add the AddressCount size
|
||
//
|
||
|
||
ListSize += FIELD_OFFSET(NETWORK_ADDRESS_LIST, Address);
|
||
|
||
return(ListSize);
|
||
}
|
||
|
||
VOID
|
||
TcIndicateInterfaceChange(
|
||
IN PADAPTER Adapter,
|
||
IN PPS_WAN_LINK WanLink,
|
||
IN NDIS_STATUS Status
|
||
)
|
||
{
|
||
ULONG AddrLen = 0;
|
||
ULONG DataLen;
|
||
PTC_INDICATION_BUFFER Data;
|
||
|
||
PsAssert((Status == NDIS_STATUS_INTERFACE_UP) || (Status == NDIS_STATUS_INTERFACE_DOWN) ||
|
||
(Status == NDIS_STATUS_INTERFACE_CHANGE));
|
||
|
||
if(Adapter->MediaType == NdisMediumWan)
|
||
{
|
||
|
||
if(WanLink) {
|
||
|
||
CollectWanNetworkAddresses(Adapter, WanLink, &AddrLen, NULL);
|
||
|
||
DataLen = AddrLen + FIELD_OFFSET(TC_INDICATION_BUFFER, InfoBuffer);
|
||
|
||
PsAllocatePool(Data, DataLen, PsMiscTag);
|
||
|
||
if(Data){
|
||
|
||
Data->SubCode = 0;
|
||
|
||
CollectWanNetworkAddresses(Adapter, WanLink, &AddrLen, &Data->InfoBuffer);
|
||
|
||
PsTcNotify(Adapter, WanLink, Status, Data, DataLen);
|
||
|
||
PsFreePool(Data);
|
||
}
|
||
}
|
||
|
||
}
|
||
else {
|
||
|
||
|
||
CollectNetworkAddresses(Adapter, &AddrLen, NULL);
|
||
|
||
DataLen = AddrLen + FIELD_OFFSET(TC_INDICATION_BUFFER, InfoBuffer);
|
||
|
||
PsAllocatePool(Data, DataLen, PsMiscTag);
|
||
|
||
if(Data){
|
||
|
||
Data->SubCode = 0;
|
||
|
||
CollectNetworkAddresses(Adapter, &AddrLen, &Data->InfoBuffer);
|
||
|
||
PsTcNotify(Adapter, 0, Status, Data, DataLen);
|
||
|
||
PsFreePool(Data);
|
||
}
|
||
}
|
||
|
||
return;
|
||
}
|
||
|
||
VOID
|
||
MpQueryPnPCapabilities(
|
||
IN OUT PPS_NDIS_REQUEST PsReqBuffer,
|
||
IN OUT PADAPTER pAdapt,
|
||
OUT PNDIS_STATUS pStatus
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Miniport QueryInfo OID_PNP_CAPAIBILITIES:
|
||
If the Oid == Oid_PNP_CAPABILITIES, InformationBuffer is returned with all the fields
|
||
assigned NdisDeviceStateUnspecified in the NDIS_PM_WAKE_UP_CAPABILITIES structure
|
||
|
||
OID_QUERY_POWER_STATE is returned with NDIS_STATUS_SUCCESS and should never be passed below.
|
||
|
||
Arguments:
|
||
|
||
MiniportAdapterContext Pointer to the adapter structure
|
||
Oid Oid for this query
|
||
InformationBuffer Buffer for information
|
||
InformationBufferLength Size of this buffer
|
||
BytesWritten Specifies how much info is written
|
||
BytesNeeded In case the buffer is smaller than what we need, tell them how much is needed
|
||
|
||
Return Value:
|
||
|
||
Return code from the NdisRequest below.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
PNDIS_PNP_CAPABILITIES pPNPCapabilities;
|
||
PNDIS_PM_WAKE_UP_CAPABILITIES pPMstruct;
|
||
|
||
if (PsReqBuffer->ReqBuffer.DATA.QUERY_INFORMATION.InformationBufferLength
|
||
>= sizeof(NDIS_PNP_CAPABILITIES) )
|
||
{
|
||
|
||
pPNPCapabilities = (PNDIS_PNP_CAPABILITIES)
|
||
(PsReqBuffer->ReqBuffer.DATA.QUERY_INFORMATION.InformationBuffer );
|
||
|
||
//
|
||
// Setting up the buffer to be returned to the Protocol above the SampleIM
|
||
//
|
||
pPMstruct= &pPNPCapabilities->WakeUpCapabilities;
|
||
|
||
pPMstruct->MinMagicPacketWakeUp = NdisDeviceStateUnspecified;
|
||
pPMstruct->MinPatternWakeUp = NdisDeviceStateUnspecified;
|
||
pPMstruct->MinLinkChangeWakeUp = NdisDeviceStateUnspecified;
|
||
|
||
*PsReqBuffer->BytesReadOrWritten = sizeof(NDIS_PNP_CAPABILITIES );
|
||
*PsReqBuffer->BytesNeeded = 0;
|
||
|
||
|
||
//
|
||
// Setting our internal flags
|
||
// Default, device is ON
|
||
//
|
||
|
||
pAdapt->PTDeviceState = NdisDeviceStateD0;
|
||
pAdapt->MPDeviceState = NdisDeviceStateD0;
|
||
|
||
*pStatus = NDIS_STATUS_SUCCESS;
|
||
|
||
//
|
||
// We could have received some status indications when we were in DeviceState > D0.
|
||
// Now is the time to look at them again.
|
||
//
|
||
PsGetLinkSpeed(pAdapt);
|
||
}
|
||
else
|
||
{
|
||
*PsReqBuffer->BytesNeeded = sizeof(NDIS_PNP_CAPABILITIES);
|
||
|
||
*pStatus = NDIS_STATUS_RESOURCES;
|
||
}
|
||
|
||
}
|
||
|
||
|
||
#if DBG
|
||
VOID
|
||
IndicateLogThreshold(
|
||
IN PVOID Context
|
||
)
|
||
{
|
||
PADAPTER Adapter = (PADAPTER)Context;
|
||
|
||
ULONG BytesUnread = SchedtGetBytesUnread();
|
||
|
||
NdisMCoIndicateStatus(Adapter->PsNdisHandle,
|
||
NULL,
|
||
QOS_STATUS_LOG_THRESHOLD,
|
||
&BytesUnread,
|
||
sizeof(ULONG));
|
||
}
|
||
#endif
|
||
/* end ndisreq.c */
|