windows-nt/Source/XPSP1/NT/net/qos/psched/sys/ndisreq.c
2020-09-26 16:20:57 +08:00

2052 lines
59 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
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 */