You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2051 lines
61 KiB
2051 lines
61 KiB
/*++
|
|
|
|
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 */
|