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

3456 lines
90 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:
adapter.c
Abstract:
routines for binding/unbinding to/from underlying miniport drivers
Author:
Charlie Wickham (charlwi) 24-Apr-1996.
Rajesh Sundaram (rajeshsu) 01-Aug-1998.
Environment:
Kernel Mode
Revision History:
--*/
#include "psched.h"
#pragma hdrstop
/* Defines */
/* External */
/* Static */
#define DRIVER_COUNTED_BLOCK \
{ \
++DriverRefCount; \
NdisResetEvent(&DriverUnloadEvent); \
}
#define DRIVER_COUNTED_UNBLOCK \
{ \
PS_LOCK(&DriverUnloadLock); \
if( --DriverRefCount == 0) \
NdisSetEvent(&DriverUnloadEvent); \
PS_UNLOCK(&DriverUnloadLock); \
}
/* Forward */
NDIS_STATUS
PsInitializeDeviceInstance(PADAPTER Adapter);
NDIS_STATUS
GetFrameSize(
PADAPTER Adapter
);
NDIS_STATUS
InitializeAdapter(
PADAPTER Adapter,
NDIS_HANDLE BindContext,
PNDIS_STRING MpDeviceName,
PVOID SystemSpecific1);
NDIS_STATUS
UpdateSchedulingPipe(
PADAPTER Adapter
);
VOID
DeleteAdapter(PVOID Adapter, BOOLEAN AdapterListLocked);
VOID
ClUnloadProtocol(
VOID
);
VOID
MpHalt(
IN NDIS_HANDLE MiniportAdapterContext
);
NDIS_STATUS
MpReset(
OUT PBOOLEAN AddressingReset,
IN NDIS_HANDLE MiniportAdapterContext
);
NDIS_STATUS
GetSchedulerPipeContext(
PADAPTER Adapter,
PPS_PIPE_CONTEXT *AdapterPipeContext,
PPSI_INFO *AdapterPsComponent,
PULONG ShutdownMask
);
NDIS_STATUS
FindProfile(
IN PNDIS_STRING ProfileName,
OUT PPS_PROFILE *Profile
);
NDIS_STATUS
RegisterPsComponent(
IN PPSI_INFO PsiComponentInfo,
ULONG Size,
PPS_DEBUG_INFO DebugInfo
);
NDIS_STATUS
FindSchedulingComponent(
IN PNDIS_STRING ComponentName,
OUT PPSI_INFO *Component
);
NDIS_STATUS
PsReadMiniportOIDs(
IN PADAPTER Adapter
);
VOID
CloseAllGpcVcs(
IN PADAPTER Adapter);
/* End Forward */
NTSTATUS
PsIoctl(
IN PDEVICE_OBJECT pdo,
IN PIRP pirp
)
{
PIO_STACK_LOCATION pirpSp;
ULONG ioControlCode;
PLIST_ENTRY NextAdapter;
PADAPTER Adapter;
NTSTATUS Status ;
PGPC_CLIENT_VC Vc;
PLIST_ENTRY NextVc;
PPS_WAN_LINK WanLink;
PVOID pIoBuf;
ULONG InputBufferLength;
ULONG OutputBufferLength;
USHORT Port = 0;
ULONG Ip = 0;
PTIMESTMP_REQ pTsReq = NULL;
#if DBG
KIRQL OldIrql;
KIRQL NewIrql;
OldIrql = KeGetCurrentIrql();
#endif
pirpSp = IoGetCurrentIrpStackLocation(pirp);
ioControlCode = pirpSp->Parameters.DeviceIoControl.IoControlCode;
pirp->IoStatus.Status = Status = STATUS_SUCCESS;
pirp->IoStatus.Information = 0;
/* Both input and output buffers are mapped to "SystemBuffer" in case of direct-IO */
pIoBuf = pirp->AssociatedIrp.SystemBuffer;
InputBufferLength = pirpSp->Parameters.DeviceIoControl.InputBufferLength;
OutputBufferLength = pirpSp->Parameters.DeviceIoControl.OutputBufferLength;
switch(pirpSp->MajorFunction)
{
case IRP_MJ_DEVICE_CONTROL:
switch (ioControlCode)
{
case IOCTL_PSCHED_ZAW_EVENT:
{
while(InterlockedExchange(&gZAWState, ZAW_STATE_IN_USE) != ZAW_STATE_READY)
{
//
// Some other thread is in this loop. Let's wait
//
NdisResetEvent(&gZAWEvent);
NdisWaitEvent(&gZAWEvent, 0);
}
PsReadDriverRegistryData();
//
// Handle the per adapter settings.
//
PS_LOCK(&AdapterListLock);
NextAdapter = AdapterList.Flink;
while(NextAdapter != &AdapterList)
{
Adapter = CONTAINING_RECORD(NextAdapter, ADAPTER, Linkage);
PS_LOCK_DPC(&Adapter->Lock);
if(Adapter->PsMpState != AdapterStateRunning)
{
PS_UNLOCK_DPC(&Adapter->Lock);
NextAdapter = NextAdapter->Flink;
continue;
}
REFADD(&Adapter->RefCount, 'IOTL');
PS_UNLOCK_DPC(&Adapter->Lock);
PS_UNLOCK(&AdapterListLock);
PsReadAdapterRegistryData(Adapter,
&MachineRegistryKey,
&Adapter->RegistryPath
);
//
// This will apply the effects of the following registry parameters.
//
// NonBestEffortLimit
// TimerResolution (since we update the scheduling pipe)
//
if(Adapter->MediaType != NdisMediumWan)
{
UpdateAdapterBandwidthParameters(Adapter);
//
// Set 802.1p/TOS for b/e Vc
//
Adapter->BestEffortVc.UserPriorityConforming = Adapter->UserServiceTypeBestEffort;
Adapter->BestEffortVc.UserPriorityNonConforming = Adapter->UserServiceTypeNonConforming;
Adapter->BestEffortVc.IPPrecedenceNonConforming = Adapter->IPServiceTypeBestEffortNC;
}
else
{
PS_LOCK(&Adapter->Lock);
NextVc = Adapter->WanLinkList.Flink;
while( NextVc != &Adapter->WanLinkList)
{
WanLink = CONTAINING_RECORD(NextVc, PS_WAN_LINK, Linkage);
PS_LOCK_DPC(&WanLink->Lock);
WanLink->BestEffortVc.UserPriorityConforming = Adapter->UserServiceTypeBestEffort;
WanLink->BestEffortVc.UserPriorityNonConforming = Adapter->UserServiceTypeNonConforming;
WanLink->BestEffortVc.IPPrecedenceNonConforming =
Adapter->IPServiceTypeBestEffortNC;
if(WanLink->State == WanStateOpen)
{
REFADD(&WanLink->RefCount, 'IOTL');
PS_UNLOCK_DPC(&WanLink->Lock);
PS_UNLOCK(&Adapter->Lock);
UpdateWanLinkBandwidthParameters(WanLink);
PS_LOCK(&Adapter->Lock);
NextVc = NextVc->Flink;
REFDEL(&WanLink->RefCount, TRUE, 'IOTL');
}
else
{
PS_UNLOCK_DPC(&WanLink->Lock);
NextVc = NextVc->Flink;
}
}
PS_UNLOCK(&Adapter->Lock);
}
//
// Apply the new TOS/802.1p mapping to the VCs.
//
PS_LOCK(&Adapter->Lock);
NextVc = Adapter->GpcClientVcList.Flink;
while ( NextVc != &Adapter->GpcClientVcList )
{
Vc = CONTAINING_RECORD(NextVc, GPC_CLIENT_VC, Linkage);
NextVc = NextVc->Flink;
PS_LOCK_DPC(&Vc->Lock);
if(Vc->ClVcState == CL_CALL_COMPLETE ||
Vc->ClVcState == CL_INTERNAL_CALL_COMPLETE )
{
SetTOSIEEEValues(Vc);
}
PS_UNLOCK_DPC(&Vc->Lock);
}
PS_UNLOCK(&Adapter->Lock);
PS_LOCK(&AdapterListLock);
NextAdapter = NextAdapter->Flink;
REFDEL(&Adapter->RefCount, TRUE, 'IOTL');
}
PS_UNLOCK(&AdapterListLock);
InterlockedExchange(&gZAWState, ZAW_STATE_READY);
NdisSetEvent(&gZAWEvent);
break;
}
case IOCTL_TIMESTMP_REGISTER_IN_PKT:
{
if(InputBufferLength < sizeof(TIMESTMP_REQ))
{
Status = STATUS_INVALID_PARAMETER;
break;
}
pTsReq = (PTIMESTMP_REQ)pIoBuf;
if( !AddRequest( pirpSp->FileObject,
pTsReq->SrcIp,
pTsReq->SrcPort,
pTsReq->DstIp,
pTsReq->DstPort,
pTsReq->Proto,
MARK_IN_PKT,
pTsReq->Direction) )
{
Status = STATUS_INSUFFICIENT_RESOURCES;
}
break;
}
case IOCTL_TIMESTMP_DEREGISTER_IN_PKT:
{
if(InputBufferLength < sizeof(TIMESTMP_REQ))
{
Status = STATUS_INVALID_PARAMETER;
break;
}
pTsReq = (PTIMESTMP_REQ)pIoBuf;
RemoveRequest( pirpSp->FileObject,
pTsReq->SrcIp,
pTsReq->SrcPort,
pTsReq->DstIp,
pTsReq->DstPort,
pTsReq->Proto );
break;
}
case IOCTL_TIMESTMP_REGISTER_IN_BUF:
{
if(InputBufferLength < sizeof(TIMESTMP_REQ))
{
Status = STATUS_INVALID_PARAMETER;
break;
}
pTsReq = (PTIMESTMP_REQ)pIoBuf;
if( !AddRequest( pirpSp->FileObject,
pTsReq->SrcIp,
pTsReq->SrcPort,
pTsReq->DstIp,
pTsReq->DstPort,
pTsReq->Proto,
MARK_IN_BUF,
pTsReq->Direction))
{
Status = STATUS_INSUFFICIENT_RESOURCES;
}
break;
}
case IOCTL_TIMESTMP_DEREGISTER_IN_BUF:
{
if(InputBufferLength < sizeof(TIMESTMP_REQ))
{
Status = STATUS_INVALID_PARAMETER;
break;
}
pTsReq = (PTIMESTMP_REQ)pIoBuf;
RemoveRequest( pirpSp->FileObject,
pTsReq->SrcIp,
pTsReq->SrcPort,
pTsReq->DstIp,
pTsReq->DstPort,
pTsReq->Proto );
break;
}
case IOCTL_TIMESTMP_FINISH_BUFFERING:
{
pirp->IoStatus.Information = CopyTimeStmps( pirpSp->FileObject, pIoBuf, OutputBufferLength);
break;
}
break;
}
break;
case IRP_MJ_CREATE:
break;
case IRP_MJ_CLOSE:
RemoveRequest( pirpSp->FileObject,
UL_ANY,
US_ANY,
UL_ANY,
US_ANY,
US_ANY);
break;
case IRP_MJ_CLEANUP:
break;
case IRP_MJ_READ:
break;
case IRP_MJ_SHUTDOWN:
break;
default:
Status = STATUS_NOT_SUPPORTED;
break;
}
if( Status == STATUS_SUCCESS)
{
pirp->IoStatus.Status = Status;
IoCompleteRequest(pirp, IO_NETWORK_INCREMENT);
}
else
{
pirp->IoStatus.Status = Status;
IoCompleteRequest(pirp, IO_NO_INCREMENT);
}
PsAssert( OldIrql == KeGetCurrentIrql());
return Status;
}
NDIS_STATUS
PsIoctlInit()
{
int i;
NDIS_STATUS Status;
PDRIVER_DISPATCH DispatchTable[IRP_MJ_MAXIMUM_FUNCTION+1];
for(i=0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++)
{
DispatchTable[i] = PsIoctl;
}
DispatchTable[IRP_MJ_SYSTEM_CONTROL] = WMIDispatch;
Status = NdisMRegisterDevice(MpWrapperHandle,
&PsDriverName,
&PsSymbolicName,
DispatchTable,
&PsDeviceObject,
&PsDeviceHandle);
if(Status == NDIS_STATUS_SUCCESS)
{
InitShutdownMask |= SHUTDOWN_DELETE_DEVICE;
PsDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
IoWMIRegistrationControl(PsDeviceObject, WMIREG_ACTION_REGISTER);
}
else
{
PsDeviceHandle = PsDeviceObject = 0;
}
return Status;
}
VOID
PsAddDevice()
{
//
// The first Adapter will create the DeviceObject which will enable us to receive
// irps and become a WMI data provider. The last DeviceObject will unregister from
// WMI and delete the DeviceObject.
//
MUX_ACQUIRE_MUTEX( &CreateDeviceMutex );
++AdapterCount;
if(AdapterCount == 1)
{
//
// This is the first adapter, so we create a DeviceObject
// that allows us to get irps and registers as a WMI data
// provider.
PsIoctlInit();
}
MUX_RELEASE_MUTEX( &CreateDeviceMutex);
}
NDIS_STATUS
PsInitializeDeviceInstance(PADAPTER Adapter)
{
NDIS_STATUS Status;
PsAssert(KeGetCurrentIrql() < DISPATCH_LEVEL);
PsDbgOut(DBG_INFO,
DBG_PROTOCOL,
("[PSInitializeDeviceInstance]: Adapter %08X, InitializeDeviceInstance with %ws \n",
Adapter,
Adapter->UpperBinding.Buffer));
Status = NdisIMInitializeDeviceInstanceEx(LmDriverHandle,
&Adapter->UpperBinding,
Adapter);
if (Status != NDIS_STATUS_SUCCESS)
{
PsDbgOut(DBG_FAILURE,
DBG_PROTOCOL,
("[PsInitializeDeviceInstance]: Adapter %08X, can't init PS device (%08X)\n",
Adapter,
Status));
PsAdapterWriteEventLog(
EVENT_PS_INIT_DEVICE_FAILED,
0,
&Adapter->MpDeviceName,
sizeof(Status),
&Status);
}
return Status;
}
VOID
PsDeleteDevice()
{
//
// The first Adapter will create the DeviceObject which will enable us to receive
// irps and become a WMI data provider. The last DeviceObject will unregister from
// WMI and delete the DeviceObject. In order to prevent a race condition we prevent
// any mpinitialize threads from looking at the AdapterCount. This is achieved by
// re-setting the WMIAddEvent. It is not sufficient just to do this based on
// interlocked operations on AdapterCount.
//
MUX_ACQUIRE_MUTEX( &CreateDeviceMutex );
--AdapterCount;
if(AdapterCount == 0)
{
//
// Delete the DeviceObject, since this is the last Adapter.
//
if(PsDeviceObject)
{
IoWMIRegistrationControl(PsDeviceObject, WMIREG_ACTION_DEREGISTER);
NdisMDeregisterDevice(PsDeviceHandle);
PsDeviceHandle = PsDeviceObject = 0;
}
}
MUX_RELEASE_MUTEX( &CreateDeviceMutex);
}
// No of retries to query the frame size
#define MAX_GET_FRAME_SIZE_RETRY_COUNT 3
#define WAIT_TIME_FOR_GET_FRAME_SIZE 3
VOID
ClBindToLowerMp(
OUT PNDIS_STATUS Status,
IN NDIS_HANDLE BindContext,
IN PNDIS_STRING MpDeviceName,
IN PVOID SystemSpecific1,
IN PVOID SystemSpecific2
)
/*++
Routine Description:
Bind to the underlying MP. Allocate space for an adapter structure,
initializing its fields. Try to open the adapter indicated in MpDeviceName.
Arguments:
Status : Placeholder for the driver to return a Status to NDIS.
BindContext : Handle represents NDIS's context for the bind request.
This has to be saved and returned when we call
NdisCompleteBindAdapter
SystemSpecific1 : Points to a registy path for the driver to obtain adapter
specific configuration.
MpDeviceName : DeviceName can refer to a NIC managed by an underlying NIC
driver, or it can be the name of a virtual NIC exported by
an intermediate NDIS driver that is layered between the
called intermediate driver and the NIC driver managing the
adapter to which transmit requests are directed.
SystemSpecific2 : Unused, reserved for future use.
Return Values:
None
--*/
{
PADAPTER Adapter;
NDIS_STATUS OpenAdapterStatus;
NDIS_STATUS OpenErrorStatus;
NDIS_STATUS LocalStatus;
UINT MediaIndex;
NDIS_MEDIUM MediumArray[] = {
NdisMediumFddi,
NdisMedium802_5,
NdisMedium802_3,
NdisMediumWan
};
UINT MediumArraySize = sizeof(MediumArray)/sizeof(NDIS_MEDIUM);
UINT GetFrameSizeRetryCount = 0;
PsDbgOut(DBG_INFO,
DBG_PROTOCOL | DBG_INIT,
("[ClBindToLowerMp]: MpDeviceName %ws\n", MpDeviceName->Buffer));
PS_LOCK(&DriverUnloadLock);
//
// (a) The driver can get unloaded before we complete the bind thread.
// (b) we can get bound as the driver is getting unloaded.
//
// if (a) happens, we block the driver unload and unblock when we finish the bind.
// if (b) happens, we fail the bind call.
if(gDriverState != DriverStateLoaded) {
*Status = NDIS_STATUS_FAILURE;
PS_UNLOCK(&DriverUnloadLock);
PsDbgOut(DBG_FAILURE, DBG_PROTOCOL|DBG_INIT,
("[ClBindToLowerMp]: Driver is being unloaded \n"));
return;
}
DRIVER_COUNTED_BLOCK;
PS_UNLOCK(&DriverUnloadLock);
//
// Get a new adapter context struct and initialize it with configuration
// data from the registry.
//
PsAllocatePool(Adapter, sizeof(ADAPTER), AdapterTag);
if(Adapter == NULL) {
PsAdapterWriteEventLog(
(ULONG)EVENT_PS_RESOURCE_POOL,
0,
MpDeviceName,
0,
NULL);
*Status = NDIS_STATUS_RESOURCES;
DRIVER_COUNTED_UNBLOCK;
return;
}
//
// Initialize the adapter.
//
*Status = InitializeAdapter(Adapter, BindContext, MpDeviceName, SystemSpecific1);
Adapter->ShutdownMask |= SHUTDOWN_BIND_CALLED;
if(*Status != NDIS_STATUS_SUCCESS) {
PsDeleteDevice();
REFDEL(&Adapter->RefCount, FALSE, 'NDOP');
DRIVER_COUNTED_UNBLOCK;
return;
}
NdisOpenAdapter(&OpenAdapterStatus,
&OpenErrorStatus,
&Adapter->LowerMpHandle,
&MediaIndex,
MediumArray,
MediumArraySize,
ClientProtocolHandle,
Adapter,
MpDeviceName,
0,
NULL);
if(OpenAdapterStatus == NDIS_STATUS_PENDING)
{
NdisWaitEvent(&Adapter->BlockingEvent, 0);
NdisResetEvent(&Adapter->BlockingEvent);
}
else
{
Adapter->FinalStatus = OpenAdapterStatus;
}
if(Adapter->FinalStatus == NDIS_STATUS_SUCCESS)
{
Adapter->MediaType = MediumArray[MediaIndex];
//
// Take a ref for the open
//
REFADD(&Adapter->RefCount, 'NDOP');
}
else
{
PsDbgOut(DBG_FAILURE,
DBG_PROTOCOL,
("[ClBindToLowerMp]: Adapter %08X, binding failed (Status = %08X) \n",
Adapter,
Status));
*Status = Adapter->FinalStatus;
PsAdapterWriteEventLog(
EVENT_PS_BINDING_FAILED,
0,
&Adapter->MpDeviceName,
sizeof(Adapter->FinalStatus),
&Adapter->FinalStatus);
PsDeleteDevice();
REFDEL(&Adapter->RefCount, FALSE, 'NDOP');
DRIVER_COUNTED_UNBLOCK;
return;
}
//
// Get the information pertaining to the miniport below us.
//
while(1)
{
*Status = GetFrameSize(Adapter);
if(*Status != NDIS_STATUS_SUCCESS)
{
if( GetFrameSizeRetryCount == MAX_GET_FRAME_SIZE_RETRY_COUNT)
{
goto ErrorCloseOpen;
}
else
{
GetFrameSizeRetryCount++;
DbgPrint("PSCHED: Requery FRAME_SIZE #%d\n",GetFrameSizeRetryCount);
NdisMSleep( WAIT_TIME_FOR_GET_FRAME_SIZE * 1000 * 1000);
}
}
else
{
break;
}
}
Adapter->RawLinkSpeed = (ULONG)UNSPECIFIED_RATE;
*Status = UpdateAdapterBandwidthParameters(Adapter);
if(*Status != NDIS_STATUS_SUCCESS)
{
if(*Status != NDIS_STATUS_ADAPTER_NOT_READY)
{
PsDbgOut(DBG_FAILURE,
DBG_PROTOCOL |
DBG_INIT,
("[ClBindToLowerMp]: Adapter %08X, couldn't add pipe %08X\n",
Adapter,
Status));
goto ErrorCloseOpen;
}
else
{
// The scheduling components have not registered. Let's not call NdisIMInitializeDeviceInstance.
//
*Status = NDIS_STATUS_SUCCESS;
Adapter->PsMpState = AdapterStateWaiting;
}
}
// Let's move the creation of IM device here, to see what happens.
*Status = PsInitializeDeviceInstance(Adapter);
if(*Status != NDIS_STATUS_SUCCESS)
{
goto ErrorCloseOpen;
}
// Ignore the status
PsReadMiniportOIDs(Adapter);
PsUpdateLinkSpeed(Adapter, Adapter->RawLinkSpeed,
&Adapter->RemainingBandWidth,
&Adapter->LinkSpeed,
&Adapter->NonBestEffortLimit,
&Adapter->Lock);
// This will repro the NetReady bug anywhere, anytime.
// NdisMSleep( 5 * 1000 * 1000 );
REFDEL(&Adapter->RefCount, FALSE, 'NDOP');
DRIVER_COUNTED_UNBLOCK;
return;
ErrorCloseOpen:
//
// if we have opened an underlying call manager, close it now.
//
if(Adapter->MediaType == NdisMediumWan) {
PS_LOCK(&Adapter->Lock);
if(Adapter->ShutdownMask & SHUTDOWN_CLOSE_WAN_ADDR_FAMILY){
Adapter->ShutdownMask &= ~SHUTDOWN_CLOSE_WAN_ADDR_FAMILY;
PS_UNLOCK(&Adapter->Lock);
PsDbgOut(DBG_TRACE, DBG_WAN | DBG_MINIPORT,
("[ClBindToLowerMp]: Adapter %08X Closing the WAN address family", Adapter));
LocalStatus = NdisClCloseAddressFamily(Adapter->WanCmHandle);
}
else
{
PS_UNLOCK(&Adapter->Lock);
}
}
//
// Close the open since we opened it above
//
if(Adapter->LowerMpHandle)
{
NdisCloseAdapter(&LocalStatus, Adapter->LowerMpHandle);
if(LocalStatus == NDIS_STATUS_PENDING)
{
NdisWaitEvent(&Adapter->BlockingEvent, 0);
NdisResetEvent(&Adapter->BlockingEvent);
}
REFDEL(&Adapter->RefCount, FALSE, 'NDOP');
}
PsDeleteDevice();
REFDEL(&Adapter->RefCount, FALSE, 'NDOP');
DRIVER_COUNTED_UNBLOCK;
return;
} // ClBindToLowerMp
VOID
LinkSpeedQueryComplete(
PADAPTER Adapter,
NDIS_STATUS Status
)
/*++
Routine Description:
Completion routine for link speed query during a status indication. Notify
the scheduling alg. that we have a new adapter
Arguments:
the usual...
Return Value:
None
--*/
{
PsDbgOut(DBG_INFO,
DBG_PROTOCOL,
("[LinkSpeedQueryComplete]: Adapter %08X, Status %x, Link speed %d\n",
Adapter, Status,
Adapter->LinkSpeed*100));
if ( !NT_SUCCESS( Status ))
{
Adapter->RawLinkSpeed = (ULONG)UNSPECIFIED_RATE;
PsAdapterWriteEventLog(
EVENT_PS_QUERY_OID_GEN_LINK_SPEED,
0,
&Adapter->MpDeviceName,
sizeof(Status),
&Status);
}
UpdateAdapterBandwidthParameters(Adapter);
}
VOID
PsGetLinkSpeed (
IN PADAPTER Adapter
)
{
NDIS_STATUS Status;
Status = MakeLocalNdisRequest(Adapter,
NULL,
NdisRequestLocalQueryInfo,
OID_GEN_LINK_SPEED,
&Adapter->RawLinkSpeed,
sizeof(Adapter->RawLinkSpeed),
LinkSpeedQueryComplete);
if (Status != NDIS_STATUS_PENDING)
{
LinkSpeedQueryComplete(Adapter, Status);
}
}
NDIS_STATUS
PsReadMiniportOIDs(
IN PADAPTER Adapter
)
/*++
Routine Description:
Complete the binding on the lower miniport. Initialize the
adapter structure, query the MP for certain funtionality and
initialize the associated PS miniport device
Arguments:
see the DDK
Return Values:
None
--*/
{
NDIS_STATUS Status;
PWSTR SecondaryName;
NDIS_HARDWARE_STATUS HwStatus;
NDIS_MEDIA_STATE MediaState = 0xFFFFFFFF;
NDIS_STRING PsDevName;
ULONG MacOptions;
ULONG LinkSpeed;
PsDbgOut(DBG_TRACE,
DBG_PROTOCOL,
("[PsReadMiniportOIDs]: Adapter %08X \n", Adapter));
Status = MakeLocalNdisRequest(Adapter,
NULL,
NdisRequestLocalQueryInfo,
OID_GEN_MEDIA_CONNECT_STATUS,
&MediaState,
sizeof( MediaState ),
NULL);
PsAssert(Status != NDIS_STATUS_INVALID_OID || Status != NDIS_STATUS_NOT_SUPPORTED);
if(Status == NDIS_STATUS_SUCCESS && MediaState == NdisMediaStateConnected){
Status = MakeLocalNdisRequest(Adapter,
NULL,
NdisRequestLocalQueryInfo,
OID_GEN_LINK_SPEED,
&Adapter->RawLinkSpeed,
sizeof(LinkSpeed),
NULL);
if(Status != NDIS_STATUS_SUCCESS){
PsDbgOut(DBG_INFO,
DBG_PROTOCOL,
("[PsReadMiniportOIDs]: Adapter %08X, Can't get link "
"speed - Status %08X\n", Adapter, Status));
Adapter->RawLinkSpeed = (ULONG)UNSPECIFIED_RATE;
PsAdapterWriteEventLog(
EVENT_PS_QUERY_OID_GEN_LINK_SPEED,
0,
&Adapter->MpDeviceName,
sizeof(Status),
&Status);
}
PsDbgOut(DBG_INFO,
DBG_PROTOCOL,
("[PsReadMiniportOIDs] Adapter %08X, Link speed %d\n",
Adapter,
Adapter->RawLinkSpeed*100));
}
else{
//
// We can continue, even though we don't yet have the
// link speed. We'll update it later.
//
Adapter->RawLinkSpeed = (ULONG)UNSPECIFIED_RATE;
PsDbgOut(DBG_INFO,
DBG_PROTOCOL,
("[PsReadMiniportOIDs]: Adapter %08X, Media not connected\n",
Adapter));
}
return Status;
} // PsReadMiniportOIDs
VOID
PsUpdateLinkSpeed(
PADAPTER Adapter,
ULONG RawLinkSpeed,
PULONG RemainingBandWidth,
PULONG LinkSpeed,
PULONG NonBestEffortLimit,
PPS_SPIN_LOCK Lock
)
{
ULONG NewNonBestEffortLimit;
PS_LOCK(Lock);
if(RawLinkSpeed == UNSPECIFIED_RATE)
{
//
// It is legit to have an unspecified rate - We pend
// all finite rate flows till we know the link speed.
// Indefinite rate flows will be admitted.
//
*LinkSpeed = UNSPECIFIED_RATE;
Adapter->PipeHasResources = FALSE;
}
else
{
//
// RawLinkSpeed is in 100 bps units. Convert it to 100 Bytes per second
// and then into Bytes Per Second.
//
*LinkSpeed = RawLinkSpeed / 8;
*LinkSpeed = (ULONG)(*LinkSpeed * 100);
PsDbgOut(DBG_TRACE, DBG_PROTOCOL,
("[PsUpdateLinkSpeed]: Adapter %08X, Link Speed %d \n",
Adapter, *LinkSpeed));
Adapter->PipeHasResources = TRUE;
//
// The NBE is a % of the link speed. If the link speed changes, we need to
// change this value.
//
NewNonBestEffortLimit = Adapter->ReservationLimitValue * (*LinkSpeed / 100);
PsDbgOut(DBG_INFO, DBG_PROTOCOL,
("[PsUpdateLinkSpeed]: Adapter %08X, LinkSpeed %d, NBE %d, "
" Remaining b/w = %d, New NBE = %d \n",
Adapter, *LinkSpeed, *NonBestEffortLimit,
*RemainingBandWidth, NewNonBestEffortLimit));
if(NewNonBestEffortLimit >= *NonBestEffortLimit) {
//
// The bandwidth has increased - we need not do anything with
// the flows that have already been created. Also, if RemainingBandWidth <
// NonBestEffortLimit, then some of the resources have been allocated to flows
// that were already created - We need to subtract this from the new
// RemainingBandWidth.
//
*RemainingBandWidth = NewNonBestEffortLimit - (*NonBestEffortLimit - *RemainingBandWidth);
*NonBestEffortLimit = NewNonBestEffortLimit;
}
else {
//
// Sigh. The bandwidth has decreased. We may need to delete some of the flows
//
if(*RemainingBandWidth == *NonBestEffortLimit)
{
//
// No flows were created as yet - Just update the 2 values
//
*NonBestEffortLimit = *RemainingBandWidth = NewNonBestEffortLimit;
}
else {
if((*NonBestEffortLimit - *RemainingBandWidth) <= (NewNonBestEffortLimit)) {
//
// The flows that were created are under the new limit.
//
*RemainingBandWidth = NewNonBestEffortLimit - (*NonBestEffortLimit - *RemainingBandWidth);
*NonBestEffortLimit = NewNonBestEffortLimit;
}
else
{
*RemainingBandWidth = NewNonBestEffortLimit - (*NonBestEffortLimit - *RemainingBandWidth);
*NonBestEffortLimit = NewNonBestEffortLimit;
PsAdapterWriteEventLog(
EVENT_PS_ADMISSIONCONTROL_OVERFLOW,
0,
&Adapter->MpDeviceName,
0,
NULL);
}
}
}
}
PS_UNLOCK(Lock);
}
NDIS_STATUS
UpdateAdapterBandwidthParameters(
PADAPTER Adapter
)
{
PsUpdateLinkSpeed(Adapter, Adapter->RawLinkSpeed,
&Adapter->RemainingBandWidth,
&Adapter->LinkSpeed,
&Adapter->NonBestEffortLimit,
&Adapter->Lock);
return UpdateSchedulingPipe(Adapter);
}
VOID
ClLowerMpOpenAdapterComplete(
IN PADAPTER Adapter,
IN NDIS_STATUS Status,
IN NDIS_STATUS OpenErrorStatus
)
/*++
Routine Description:
Signal that the binding on the lower miniport is complete
Arguments:
see the DDK
Return Values:
None
--*/
{
PsDbgOut(DBG_TRACE, DBG_PROTOCOL, ("[ClLowerMpOpenAdapterComplete]: Adapter %08X\n",
Adapter));
//
// stuff the final status in the Adapter block and signal
// the bind handler to continue
//
Adapter->FinalStatus = Status;
NdisSetEvent( &Adapter->BlockingEvent );
} // ClLowerMpOpenAdapterComplete
NDIS_STATUS
GetFrameSize(
PADAPTER Adapter
)
/*++
Routine Description:
This routine queries the underlying adapter to derive the total
frame size and the header size. (Total = Frame + Header)
Arguments:
Adapter - pointer to adapter context block
Return Value:
None
--*/
{
NDIS_STATUS Status;
ULONG i;
ULONG FrameSize; // doesn't include the header
//
// max amount of data w/o the MAC header
//
Status = MakeLocalNdisRequest(Adapter,
NULL,
NdisRequestLocalQueryInfo,
OID_GEN_MAXIMUM_FRAME_SIZE,
&FrameSize,
sizeof(FrameSize),
NULL);
if(Status != NDIS_STATUS_SUCCESS){
PsDbgOut(DBG_FAILURE,
DBG_PROTOCOL,
("[GetFrameSize]: Adapter %08X, Can't get frame size - Status %08X\n",
Adapter,
Status));
PsAdapterWriteEventLog(
EVENT_PS_QUERY_OID_GEN_MAXIMUM_FRAME_SIZE,
0,
&Adapter->MpDeviceName,
sizeof(Status),
&Status);
return Status;
}
//
// this one includes the header
//
Status = MakeLocalNdisRequest(Adapter,
NULL,
NdisRequestLocalQueryInfo,
OID_GEN_MAXIMUM_TOTAL_SIZE,
&Adapter->TotalSize,
sizeof(Adapter->TotalSize),
NULL);
if(Status != NDIS_STATUS_SUCCESS){
PsDbgOut(DBG_FAILURE,
DBG_PROTOCOL,
("(%08X) GetFrameSize: Can't get total size - Status %08X\n",
Adapter,
Status));
PsAdapterWriteEventLog(
EVENT_PS_QUERY_OID_GEN_MAXIMUM_TOTAL_SIZE,
0,
&Adapter->MpDeviceName,
sizeof(Status),
&Status);
return Status;
}
//
// figure the real header size
//
Adapter->HeaderSize = Adapter->TotalSize - FrameSize;
return Status;
} // GetFrameSize
NDIS_STATUS
GetSchedulerPipeContext(
PADAPTER Adapter,
PPS_PIPE_CONTEXT *AdapterPipeContext,
PPSI_INFO *AdapterPsComponent,
PULONG ShutdownMask
)
/*++
Routine Description:
Allocate the pipe context area for the scheduler.
Arguments:
Adapter - pointer to adapter context struct
Return Value:
NDIS_STATUS_SUCCESS, otherwise appropriate error value
--*/
{
ULONG Index = 0;
PPS_PROFILE ProfileConfig;
PPSI_INFO PsComponent;
ULONG ContextLength = 0;
ULONG FlowContextLength = 0;
ULONG ClassMapContextLength = 0;
PPS_PIPE_CONTEXT PipeContext, PrevContext;
ULONG PacketReservedLength = sizeof(PS_SEND_PACKET_CONTEXT);
PVOID PipeCxt;
//
// If there is no profile defined for this adapter, use defaults.
//
if(FindProfile(&Adapter->ProfileName, &ProfileConfig) == NDIS_STATUS_SUCCESS)
{
PsDbgOut(DBG_TRACE,
DBG_PROTOCOL,
("[GetSchedulerPipeContext]: Using %ws profile for adapter "
" 0x%x \n", Adapter->ProfileName.Buffer, Adapter));
//
// Need to lock here as there could be a race
// condition between the RegisterPsComponent
// Note, however there is no race condition if all
// components have registered, so we can release the lock.
//
PS_LOCK(&PsProfileLock);
if(ProfileConfig->UnregisteredAddInCnt != 0)
{
PS_UNLOCK(&PsProfileLock);
PsDbgOut(DBG_TRACE, DBG_PROTOCOL,
("[GetSchedulerPipeContext]: Adapter 0x%x is not ready\n",
Adapter));
return NDIS_STATUS_ADAPTER_NOT_READY;
}
PS_UNLOCK(&PsProfileLock);
}
else
{
PsDbgOut(DBG_TRACE,
DBG_PROTOCOL,
("[GetSchedulerPipeContext]: Profile not supplied / not found"
" using default for adapter 0x%x \n", Adapter));
ProfileConfig = &DefaultSchedulerConfig;
}
for (Index = 0; Index < ProfileConfig->ComponentCnt; Index++)
{
ContextLength +=
ProfileConfig->ComponentList[Index]->PipeContextLength;
FlowContextLength +=
ProfileConfig->ComponentList[Index]->FlowContextLength;
ClassMapContextLength +=
ProfileConfig->ComponentList[Index]->ClassMapContextLength;
PacketReservedLength += ProfileConfig->ComponentList[Index]->PacketReservedLength;
}
Adapter->FlowContextLength = FlowContextLength;
Adapter->ClassMapContextLength = ClassMapContextLength;
Adapter->PacketContextLength = PacketReservedLength;
if(AdapterPipeContext)
{
PacketReservedLength = sizeof(PS_SEND_PACKET_CONTEXT);
PsAllocatePool( PipeContext, ContextLength, PipeContextTag );
*AdapterPipeContext = PipeContext;
if ( *AdapterPipeContext == NULL ) {
return NDIS_STATUS_RESOURCES;
}
*ShutdownMask |= SHUTDOWN_FREE_PS_CONTEXT;
// Set up the context buffer
PrevContext = NULL;
for (Index = 0; Index < ProfileConfig->ComponentCnt; Index++)
{
PsComponent = ProfileConfig->ComponentList[Index];
PipeContext->NextComponentContext = (PPS_PIPE_CONTEXT)
((UINT_PTR)PipeContext + PsComponent->PipeContextLength);
PipeContext->PrevComponentContext = PrevContext;
if(Index+1 == ProfileConfig->ComponentCnt)
{
PipeContext->NextComponent = 0;
}
else
{
PipeContext->NextComponent =
ProfileConfig->ComponentList[Index + 1];
}
if (PsComponent->PacketReservedLength > 0)
{
PipeContext->PacketReservedOffset = PacketReservedLength;
PacketReservedLength +=
PsComponent->PacketReservedLength;
} else
{
PipeContext->PacketReservedOffset = 0;
}
PrevContext = PipeContext;
PipeContext = PipeContext->NextComponentContext;
}
*AdapterPsComponent = ProfileConfig->ComponentList[0];
}
return NDIS_STATUS_SUCCESS;
} // GetSchedulerPipeContext
NDIS_STATUS
UpdateWanSchedulingPipe(PPS_WAN_LINK WanLink)
{
NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
PS_PIPE_PARAMETERS PipeParameters;
PADAPTER Adapter = WanLink->Adapter;
//
// Initialize pipe parameters.
// UNSPECIFIED_RATE indicates that the link speed is currently
// unknown. This is a legitimate initialization value.
//
PS_LOCK(&Adapter->Lock);
PS_LOCK_DPC(&WanLink->Lock);
PipeParameters.Bandwidth = WanLink->LinkSpeed;
PipeParameters.MTUSize = Adapter->TotalSize;
PipeParameters.HeaderSize = Adapter->HeaderSize;
PipeParameters.Flags = Adapter->PipeFlags;
PipeParameters.MaxOutstandingSends = Adapter->MaxOutstandingSends;
PipeParameters.SDModeControlledLoad = Adapter->SDModeControlledLoad;
PipeParameters.SDModeGuaranteed = Adapter->SDModeGuaranteed;
PipeParameters.SDModeNetworkControl = Adapter->SDModeNetworkControl;
PipeParameters.SDModeQualitative = Adapter->SDModeQualitative;
PipeParameters.RegistryPath = &Adapter->RegistryPath;
PS_UNLOCK_DPC(&WanLink->Lock);
PS_UNLOCK(&Adapter->Lock);
//
// Initialize the pipe for only the first time
//
if ( !(WanLink->ShutdownMask & SHUTDOWN_DELETE_PIPE )) {
//
// Allocate and initialize the context buffer for the scheduler.
//
Status = GetSchedulerPipeContext( Adapter,
&WanLink->PsPipeContext,
&WanLink->PsComponent,
&WanLink->ShutdownMask );
if ( !NT_SUCCESS( Status ))
{
return Status;
}
WanLink->BestEffortVc.PsPipeContext = WanLink->PsPipeContext;
WanLink->BestEffortVc.PsComponent = WanLink->PsComponent;
// Need to set the pipe's media type here.. //
PipeParameters.MediaType = NdisMediumWan;
Status = (*WanLink->PsComponent->InitializePipe)(
Adapter,
&PipeParameters,
WanLink->PsPipeContext,
&PsProcs,
NULL);
if (NT_SUCCESS(Status))
{
WanLink->ShutdownMask |= SHUTDOWN_DELETE_PIPE;
}
}
else{
// Pipe's already been initialized. This is a modify
Status = (*WanLink->PsComponent->ModifyPipe)(
WanLink->PsPipeContext,
&PipeParameters);
}
return Status;
}
NDIS_STATUS
UpdateSchedulingPipe(
PADAPTER Adapter
)
/*++
Routine Description:
Initialize a scheduling pipe on the adapter. Always called with a LOCK
held.
Arguments:
Adapter - pointer to adapter context struct
Return Value:
NDIS_STATUS_SUCCESS, otherwise appropriate error value
--*/
{
NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
PS_PIPE_PARAMETERS PipeParameters;
//
// Initialize pipe parameters.
// UNSPECIFIED_RATE indicates that the link speed is currently
// unknown. This is a legitimate initialization value.
//
PS_LOCK(&Adapter->Lock);
PipeParameters.Bandwidth = Adapter->LinkSpeed;
PipeParameters.MTUSize = Adapter->TotalSize;
PipeParameters.HeaderSize = Adapter->HeaderSize;
PipeParameters.Flags = Adapter->PipeFlags;
PipeParameters.MaxOutstandingSends = Adapter->MaxOutstandingSends;
PipeParameters.SDModeControlledLoad = Adapter->SDModeControlledLoad;
PipeParameters.SDModeGuaranteed = Adapter->SDModeGuaranteed;
PipeParameters.SDModeNetworkControl = Adapter->SDModeNetworkControl;
PipeParameters.SDModeQualitative = Adapter->SDModeQualitative;
PipeParameters.RegistryPath = &Adapter->RegistryPath;
PS_UNLOCK(&Adapter->Lock);
//
// Initialize the pipe for only the first time
//
if ( !(Adapter->ShutdownMask & SHUTDOWN_DELETE_PIPE ))
{
//
// We don't run the scheduling components on the Adapter structure for NDISWAN.
// Each wanlink has its own set of scheduling components. But, we still need to compute the
// PacketPool Length and allocate the Packet Pool - Hence we have to call GetSchedulerPipeContext
//
if(Adapter->MediaType == NdisMediumWan)
{
//
// Allocate and initialize the context buffer for the scheduler.
//
Status = GetSchedulerPipeContext( Adapter,
NULL,
NULL,
NULL);
}
else
{
Status = GetSchedulerPipeContext( Adapter,
&Adapter->PsPipeContext,
&Adapter->PsComponent,
&Adapter->ShutdownMask);
}
if ( !NT_SUCCESS( Status ))
{
return Status;
}
if(Adapter->MediaType == NdisMediumWan)
{
Adapter->ShutdownMask |= SHUTDOWN_DELETE_PIPE;
PsAssert(!(Adapter->ShutdownMask & SHUTDOWN_FREE_PS_CONTEXT));
PsAssert(!Adapter->PsPipeContext);
PsAssert(!Adapter->PsComponent);
}
else
{
// Need to set the pipe's media type here.. //
PipeParameters.MediaType = Adapter->MediaType;
Status = (*Adapter->PsComponent->InitializePipe)(
Adapter,
&PipeParameters,
Adapter->PsPipeContext,
&PsProcs,
NULL);
if (NT_SUCCESS(Status)) {
Adapter->ShutdownMask |= SHUTDOWN_DELETE_PIPE;
}
else
{
return Status;
}
}
}
else
{
// Pipe's already been initialized. This is a modify
if(Adapter->MediaType != NdisMediumWan)
{
Status = (*Adapter->PsComponent->ModifyPipe)(
Adapter->PsPipeContext,
&PipeParameters);
}
}
return Status;
} // UpdateSchedulingPipe
NDIS_STATUS
MpInitialize(
OUT PNDIS_STATUS OpenErrorStatus,
OUT PUINT SelectedMediumIndex,
IN PNDIS_MEDIUM MediumArray,
IN UINT MediumArraySize,
IN NDIS_HANDLE MiniportAdapterHandle,
IN NDIS_HANDLE WrapperConfigurationContext
)
/*++
Routine Description:
Packet scheduler's device initialization routine. The list of media types is
checked to be sure it is one that we support. If so, match up the name of
the device being opened with one of the adapters to which we've bound.
Arguments:
See the DDK...
Return Values:
None
--*/
{
PADAPTER Adapter;
NDIS_STATUS Status;
BOOLEAN FakingIt = FALSE;
NDIS_STRING MpDeviceName;
//
// We're being called to initialize one of our miniport
// device instances. We triggered this by calling
// NdisIMInitializeDeviceInstance when we were asked to
// bind to the adapter below us. We provided a pointer
// to the ADAPTER struct corresponding to the actual
// adapter we opened. We can get that back now, with the
// following call.
//
Adapter = NdisIMGetDeviceContext(MiniportAdapterHandle);
PsStructAssert(Adapter);
PsDbgOut(DBG_TRACE, DBG_MINIPORT | DBG_INIT, ("[MpInitialize]: Adapter %08X \n", Adapter));
Adapter->ShutdownMask |= SHUTDOWN_MPINIT_CALLED;
//
// We assume that the faster packet APIs will be used, and initialize our per-packet pool. If we don't get a packet-stack,
// we'll initialize the NDIS packet pool and free the per-packet pool (since the NDIS packet pool will have space for a per-packet
// pool).
//
// We cannot know about the old or new packet stack API at bind time (because even if we did know our position in the packet stack, and
// initialized the old APIs, we could get a newly allocated packet from an IM above us which will have room for a packet stack).
//
Adapter->SendBlockPool = NdisCreateBlockPool((USHORT)Adapter->PacketContextLength,
FIELD_OFFSET(PS_SEND_PACKET_CONTEXT, FreeList),
NDIS_PACKET_POOL_TAG_FOR_PSCHED,
NULL);
if(!Adapter->SendBlockPool)
{
PsDbgOut(DBG_CRITICAL_ERROR,
DBG_MINIPORT | DBG_INIT,
("[MpInitialize]: Adapter %08X, Can't allocate packet pool \n",
Adapter));
Status = NDIS_STATUS_RESOURCES;
PsAdapterWriteEventLog(
EVENT_PS_RESOURCE_POOL,
0,
&Adapter->MpDeviceName,
0,
NULL);
goto MpInitializeError;
}
//
// We can also get the instance name for the corresponding
// adapter. This is the name which WMI will be using to
// refer to this instance of us.
//
Status = NdisMQueryAdapterInstanceName(&Adapter->WMIInstanceName, MiniportAdapterHandle);
if(Status != NDIS_STATUS_SUCCESS)
{
PsDbgOut(DBG_CRITICAL_ERROR,
DBG_MINIPORT | DBG_INIT,
("[MpInitialize]: Adapter %08X, Failed to get WMI instance name.\n",
Adapter,
Status));
PsAdapterWriteEventLog(
EVENT_PS_WMI_INSTANCE_NAME_FAILED,
0,
&Adapter->MpDeviceName,
sizeof(Status),
&Status);
goto MpInitializeError;
}
//
// lookup our media type in the supplied media array
//
// if we're NdisMediumWan, then we have to fake out the
// protocol and pretend that we're NdisMedium802_3, so
// fake it for now.
//
if(Adapter->MediaType == NdisMediumWan){
FakingIt = TRUE;
Adapter->MediaType = NdisMedium802_3;
}
for(--MediumArraySize ; MediumArraySize > 0;){
if(MediumArray[ MediumArraySize ] == Adapter->MediaType){
break;
}
if(MediumArraySize == 0){
break;
}
--MediumArraySize;
}
if(MediumArraySize == 0 && MediumArray[ 0 ] != Adapter->MediaType){
if(FakingIt)
{
FakingIt = FALSE;
Adapter->MediaType = NdisMediumWan;
}
PsDbgOut(DBG_CRITICAL_ERROR,
DBG_MINIPORT | DBG_INIT,
("[MpInitialize]: Adapter %08X, Unsupported Media \n",
Adapter));
Status = NDIS_STATUS_UNSUPPORTED_MEDIA;
goto MpInitializeError;
}
if(FakingIt){
FakingIt = FALSE;
Adapter->MediaType = NdisMediumWan;
}
*SelectedMediumIndex = MediumArraySize;
//
// finish the initialization process by set our attributes
//
NdisMSetAttributesEx(MiniportAdapterHandle,
Adapter,
0xFFFF,
NDIS_ATTRIBUTE_IGNORE_PACKET_TIMEOUT |
NDIS_ATTRIBUTE_IGNORE_REQUEST_TIMEOUT |
NDIS_ATTRIBUTE_DESERIALIZE |
NDIS_ATTRIBUTE_INTERMEDIATE_DRIVER |
NDIS_ATTRIBUTE_NO_HALT_ON_SUSPEND,
0);
//
// Set the default value for the device state flag as PM capable (for both miniport
// and protocol). Device is ON by default
//
Adapter->MPDeviceState = NdisDeviceStateD0;
Adapter->PTDeviceState = NdisDeviceStateD0;
Adapter->PsNdisHandle = MiniportAdapterHandle;
//
// We create the b/e VC here (rather than the bind handler) because
// this will be called only after all scheduling components have registered.
//
if(Adapter->MediaType != NdisMediumWan) {
Status = CreateBestEffortVc(Adapter,
&Adapter->BestEffortVc,
0);
if(Status != NDIS_STATUS_SUCCESS)
{
PsDbgOut(DBG_CRITICAL_ERROR, DBG_MINIPORT | DBG_INIT,
("[MpInitialize]: Adapter %08X, cannot create b/e VC ! \n",
Adapter));
goto MpInitializeError;
}
}
Adapter->PsMpState = AdapterStateRunning;
//
// This is for mpinitialize, will be deref'd on mphalt.
//
REFADD(&Adapter->RefCount, 'NDHT');
PS_LOCK(&AdapterListLock);
if(WMIInitialized && !Adapter->IfcNotification)
{
//
// WMI has been initialized correctly. i.e we can post events
// at this point.
//
Adapter->IfcNotification = TRUE;
PS_UNLOCK(&AdapterListLock);
TcIndicateInterfaceChange(Adapter, 0, NDIS_STATUS_INTERFACE_UP);
}
else
{
//
// WMI has not been initialized. Since this adapter is already on the
// list, the interface up event will be posted when IRP_MN_REGINFO
// completes.
//
PS_UNLOCK(&AdapterListLock);
}
NdisSetEvent(&Adapter->MpInitializeEvent);
return NDIS_STATUS_SUCCESS;
MpInitializeError:
Adapter->PsNdisHandle = 0;
NdisSetEvent(&Adapter->MpInitializeEvent);
return Status;
} // MpInitialize
PADAPTER
FindAdapterByWmiInstanceName(
USHORT StringLength,
PWSTR StringStart,
PPS_WAN_LINK *PsWanLink
)
/*++
Routine Description:
Find the miniport instance that matches the instance name passed in.
Arguments:
StringLength - Number of bytes / 2
StringStart - pointer to a buffer containing a wide string
PsWanLink - if this is an interface search, then the WAN link
representing the interface will be returned in this location.
If it is not an interface search or no matching WanLink is
found, NULL will be returned.
InterfaceSearch - if TRUE, this is a search for an interface. For
LAN adapters, an interface is equivalent to an adapter. For WAN
adapters, interfaces are links. Otherwise, it's a search for an
adapter.
Return Value:
pointer to ADAPTER struct, otherwise NULL
--*/
{
PLIST_ENTRY NextAdapter;
PLIST_ENTRY NextLink;
PPS_WAN_LINK WanLink;
PADAPTER AdapterInList;
*PsWanLink = NULL;
PS_LOCK(&AdapterListLock);
NextAdapter = AdapterList.Flink;
while(NextAdapter != &AdapterList){
AdapterInList = CONTAINING_RECORD(NextAdapter, ADAPTER, Linkage);
PS_LOCK_DPC(&AdapterInList->Lock);
//
// If it's closing, blow right by it.
//
if(AdapterInList->PsMpState != AdapterStateRunning)
{
PS_UNLOCK_DPC(&AdapterInList->Lock);
NextAdapter = NextAdapter->Flink;
continue;
}
if(AdapterInList->MediaType != NdisMediumWan)
{
if(StringLength == AdapterInList->WMIInstanceName.Length){
//
// At least they are of equal length.
//
if(NdisEqualMemory(StringStart,
AdapterInList->WMIInstanceName.Buffer,
StringLength)){
REFADD(&AdapterInList->RefCount, 'ADVC');
PS_UNLOCK_DPC(&AdapterInList->Lock);
PS_UNLOCK(&AdapterListLock);
return(AdapterInList);
}
}
}
else
{
if(AdapterInList->WanBindingState & WAN_ADDR_FAMILY_OPEN)
{
//
// Wan adapters are searched by the name stored with
// their links.
//
NextLink = AdapterInList->WanLinkList.Flink;
while(NextLink != &AdapterInList->WanLinkList){
WanLink = CONTAINING_RECORD(NextLink, PS_WAN_LINK, Linkage);
if(WanLink->State == WanStateOpen)
{
if(StringLength == WanLink->InstanceName.Length){
//
// At least they are of equal length.
//
if(NdisEqualMemory(StringStart,
WanLink->InstanceName.Buffer,
StringLength)){
REFADD(&AdapterInList->RefCount, 'ADVC');
REFADD(&WanLink->RefCount, 'WANV');
PS_UNLOCK_DPC(&AdapterInList->Lock);
PS_UNLOCK(&AdapterListLock);
*PsWanLink = WanLink;
return(AdapterInList);
}
}
}
NextLink = NextLink->Flink;
}
}
}
PS_UNLOCK_DPC(&AdapterInList->Lock);
NextAdapter = NextAdapter->Flink;
}
PS_UNLOCK(&AdapterListLock);
return NULL;
} // FindAdapterByWmiInstanceName
VOID
CleanUpAdapter(
IN PADAPTER Adapter)
{
NDIS_STATUS Status;
PsAssert(KeGetCurrentIrql() < DISPATCH_LEVEL);
TcIndicateInterfaceChange(Adapter, 0, NDIS_STATUS_INTERFACE_DOWN);
//
// Close all the VCs
//
CloseAllGpcVcs(Adapter);
//
// if we have opened an underlying call manager, close it now.
//
if(Adapter->MediaType == NdisMediumWan) {
PS_LOCK(&Adapter->Lock);
if(Adapter->ShutdownMask & SHUTDOWN_CLOSE_WAN_ADDR_FAMILY){
Adapter->ShutdownMask &= ~SHUTDOWN_CLOSE_WAN_ADDR_FAMILY;
PS_UNLOCK(&Adapter->Lock);
PsDbgOut(DBG_TRACE, DBG_WAN | DBG_MINIPORT,
("[CleanupAdapter]: Adapter %08X Closing the WAN address family", Adapter));
Status = NdisClCloseAddressFamily(Adapter->WanCmHandle);
}
else
{
PS_UNLOCK(&Adapter->Lock);
}
}
}
VOID
ClUnbindFromLowerMp(
OUT PNDIS_STATUS Status,
IN NDIS_HANDLE ProtocolBindingContext,
IN NDIS_HANDLE UnbindContext
)
/*++
Routine Description:
Called by NDIS to indicate that an adapter is going away.
Since this is an integrated call manager/miniport, we will
have to close the call manager with the adapter. To do so,
we must first ask the clients of our call manager part to
close us. We will have to pend until then.
Release our reference
on the adapter and set the closing flag to true to prevent any further
references from being obtained.
Arguments:
See the DDK...
Return Values:
None
--*/
{
PADAPTER Adapter = (PADAPTER)ProtocolBindingContext;
NDIS_STATUS LocalStatus;
BOOLEAN VirtualMp;
PsDbgOut(DBG_INFO,
DBG_PROTOCOL | DBG_INIT,
("[ClUnbindFromLowerMp]: Adapter %08X, %ws, UnbindContext %x \n",
Adapter,
Adapter->MpDeviceName.Buffer,
UnbindContext));
PsStructAssert( Adapter );
PsAssert(!(Adapter->ShutdownMask & SHUTDOWN_UNBIND_CALLED));
//
// If the unbind is not happening from the context of the unload, we need to Make sure that
// unload waits for this unbind to complete. We do that by setting the DriverUnloadEvent.
//
PS_LOCK(&DriverUnloadLock);
DRIVER_COUNTED_BLOCK;
PS_UNLOCK(&DriverUnloadLock);
PS_LOCK(&Adapter->Lock);
if(Adapter->PsMpState == AdapterStateWaiting)
{
VirtualMp = FALSE;
}
else
{
VirtualMp = TRUE;
}
Adapter->PsMpState = AdapterStateClosing;
Adapter->ShutdownMask |= SHUTDOWN_UNBIND_CALLED;
PsAssert(!(Adapter->ShutdownMask & SHUTDOWN_CLEANUP_ADAPTER));
if(Adapter->PendedNdisRequest)
{
PNDIS_REQUEST PendedRequest = (PNDIS_REQUEST)Adapter->PendedNdisRequest;
Adapter->PendedNdisRequest = NULL;
ClRequestComplete(Adapter, PendedRequest, NDIS_STATUS_FAILURE);
}
Adapter->ShutdownMask |= SHUTDOWN_CLEANUP_ADAPTER;
PS_UNLOCK(&Adapter->Lock);
CleanUpAdapter(Adapter);
//
// DeInitialize the device instance if we have been called in the MpInitialize handler.
//
if(Adapter->PsNdisHandle)
{
//
// Either the mpinitialize has happened or its in progress. If it is in progress,
// we need to Wait till it completes.
//
NdisWaitEvent(&Adapter->MpInitializeEvent, 0);
//
// The MpInitialize (that we could have been waiting for in the above step) could have failed :
// So we need to check this handle again.
//
if(Adapter->PsNdisHandle)
{
*Status = NdisIMDeInitializeDeviceInstance(Adapter->PsNdisHandle);
PsDbgOut(DBG_INFO,
DBG_PROTOCOL | DBG_INIT,
("[ClUnbindFromLowerMp]: Adapter %08X, deiniting device, "
"status %x\n", Adapter, *Status));
goto Done;
}
}
else
{
if(VirtualMp)
{
//
// We have never been called in MpInitialize. Try to cancel the NdisIMInitializeDeviceInstance
// call.
//
PsDbgOut(DBG_INFO,
DBG_PROTOCOL | DBG_INIT,
("[ClUnbindFromLowerMp]: Adapter %08X, calling NdisIMCancelDeviceInstance with %ws \n",
Adapter, Adapter->UpperBinding.Buffer));
*Status = NdisIMCancelInitializeDeviceInstance(LmDriverHandle, &Adapter->UpperBinding);
if(*Status != NDIS_STATUS_SUCCESS)
{
//
// An mpinitialize is in progress or is going to happen soon. Let's wait for it to
// complete.
//
PsDbgOut(DBG_INFO,
DBG_PROTOCOL | DBG_INIT,
("[ClUnbindFromLowerMp]: Adapter %08X, Waiting for MpInitialize to "
"finish (NdisIMCancelDeviceInstance failed) \n", Adapter));
NdisWaitEvent(&Adapter->MpInitializeEvent, 0);
//
// The MpInitialize (that we could have been waiting for in the above step) could have failed :
// So we need to check this handle again.
//
if(Adapter->PsNdisHandle)
{
*Status = NdisIMDeInitializeDeviceInstance(Adapter->PsNdisHandle);
PsDbgOut(DBG_INFO,
DBG_PROTOCOL | DBG_INIT,
("[ClUnbindFromLowerMp]: Adapter %08X, deiniting device, "
"status %x\n", Adapter, *Status));
goto Done;
}
}
else
{
//
// Great. We can be assured that we will never get called in the MpInitializeHandler anymore.
// Proceed to close the binding below.
//
}
}
}
//
// Close the open. We have to do this only if we don't call NdisIMDeInitializeDeviceInstance. If
// we ever call NdisIMDeInitializeDeviceInstance, then we close the open in the MpHalt handler.
//
if(Adapter->LowerMpHandle)
{
NdisCloseAdapter(Status, Adapter->LowerMpHandle);
PsDbgOut(DBG_INFO,
DBG_PROTOCOL | DBG_INIT,
("[ClUnbindFromLowerMp]: Adapter %08X, closing adapter, "
"status %x\n", Adapter, *Status));
if (*Status == NDIS_STATUS_PENDING)
{
NdisWaitEvent(&Adapter->BlockingEvent, 0);
NdisResetEvent(&Adapter->BlockingEvent);
*Status = Adapter->FinalStatus;
}
REFDEL(&Adapter->RefCount, FALSE, 'NDOP');
}
else
{
PsDbgOut(DBG_CRITICAL_ERROR,
DBG_PROTOCOL | DBG_INIT,
("[ClUnbindFromLowerMp]: Adapter %08X, unbind cannot deinit/close adpater \n",
Adapter));
*Status = NDIS_STATUS_FAILURE;
PsAssert(0);
}
Done:
PsDbgOut(DBG_INFO,
DBG_PROTOCOL | DBG_INIT,
("[ClUnbindFromLowerMp]: Exiting with Status = %08X \n", *Status));
DRIVER_COUNTED_UNBLOCK;
} // UnbindAdapter
VOID
DeleteAdapter(
PVOID Handle,
BOOLEAN AdapterListLocked
)
/*++
Routine Description:
Decrement the ref counter associated with this structure. When it goes to
zero, close the adapter, and delete the memory associated with the struct
Arguments:
Adapter - pointer to adapter context block
Return Value:
number of references remaining associated with this structure
--*/
{
PADAPTER Adapter = (PADAPTER) Handle;
Adapter->PsMpState = AdapterStateClosed;
//
// if we initialized the pipe, tell the scheduler that this pipe is going away
//
if ( Adapter->MediaType != NdisMediumWan && Adapter->ShutdownMask & SHUTDOWN_DELETE_PIPE ) {
(*Adapter->PsComponent->DeletePipe)( Adapter->PsPipeContext );
}
if ( Adapter->ShutdownMask & SHUTDOWN_FREE_PS_CONTEXT ) {
PsFreePool(Adapter->PsPipeContext);
}
if(Adapter->pDiffServMapping)
{
PsFreePool(Adapter->pDiffServMapping);
}
//
// return packet pool resources
//
if(Adapter->SendPacketPool != 0)
{
NdisFreePacketPool(Adapter->SendPacketPool);
}
if(Adapter->RecvPacketPool != 0)
{
NdisFreePacketPool(Adapter->RecvPacketPool);
}
if(Adapter->SendBlockPool)
{
NdisDestroyBlockPool(Adapter->SendBlockPool);
}
//
// free adapter lock from dispatcher DB
//
NdisFreeSpinLock(&Adapter->Lock);
//
// Free various allocations for the adapter, then the adapter
//
if(Adapter->IpNetAddressList){
PsFreePool(Adapter->IpNetAddressList);
}
if(Adapter->IpxNetAddressList){
PsFreePool(Adapter->IpxNetAddressList);
}
if(Adapter->MpDeviceName.Buffer) {
PsFreePool(Adapter->MpDeviceName.Buffer);
}
if(Adapter->UpperBinding.Buffer) {
PsFreePool(Adapter->UpperBinding.Buffer);
}
if(Adapter->RegistryPath.Buffer) {
PsFreePool(Adapter->RegistryPath.Buffer);
}
if(Adapter->WMIInstanceName.Buffer) {
//
// We should not call PsFreePool since this memory is allocated by NDIS
//
ExFreePool(Adapter->WMIInstanceName.Buffer);
}
if(Adapter->ProfileName.Buffer) {
PsFreePool(Adapter->ProfileName.Buffer);
}
if(!AdapterListLocked)
{
PS_LOCK(&AdapterListLock);
RemoveEntryList(&Adapter->Linkage);
PS_UNLOCK(&AdapterListLock);
}
else
{
RemoveEntryList(&Adapter->Linkage);
}
NdisSetEvent(&Adapter->RefEvent);
PsFreePool(Adapter);
}
VOID
ClLowerMpCloseAdapterComplete(
IN NDIS_HANDLE ProtocolBindingContext,
IN NDIS_STATUS Status
)
/*++
Routine Description:
Completion routine for NdisCloseAdapter. All that should be left is to free
the pool associated with the structure
Arguments:
See the DDK...
Return Values:
None
--*/
{
PADAPTER Adapter = (PADAPTER)ProtocolBindingContext;
PsDbgOut(DBG_TRACE,
DBG_PROTOCOL,
("[ClLowerMpCloseAdapterComplete]: Adapter %08X \n", Adapter));
PsStructAssert( Adapter );
PsAssert(Status == NDIS_STATUS_SUCCESS);
Adapter->FinalStatus = Status;
Adapter->LowerMpHandle = 0;
//
// Clean up WanLinks. This cannot be done (in CleanUpAdapter) before we call NdisCloseAdapter, because
// NDIS can unbind us in the middle of an ClStatusIndication, and can cause a race condition. Also, we
// can all PsDeleteDevice only after this (because we might want to send some status indications.
//
AskWanLinksToClose(Adapter);
PsDeleteDevice();
NdisSetEvent(&Adapter->BlockingEvent);
} // LowerMpCloseAdapterComplete
VOID
ClUnloadProtocol(
VOID
)
/*++
Routine Description:
Arguments:
None
Return Value:
None
--*/
{
}
VOID
MpHalt(
IN NDIS_HANDLE MiniportAdapterContext
)
/*++
Routine Description:
This handler is called on Memphis. It indicates that the PS MP is no more
and we should avoid calling NdisIMDeInitializeDeviceInstance...
Arguments:
See the DDK...
Return Values:
None
--*/
{
PADAPTER Adapter = (PADAPTER)MiniportAdapterContext;
ULONG Status;
PsDbgOut(DBG_TRACE, DBG_MINIPORT, ("[MpHalt]: Adapter %08X\n", Adapter));
PsStructAssert(Adapter);
PsAssert(!(Adapter->ShutdownMask & SHUTDOWN_MPHALT_CALLED));
PsAssert(!(Adapter->ShutdownMask & SHUTDOWN_PROTOCOL_UNLOAD));
PS_LOCK(&Adapter->Lock);
//
// If we ever get called in our unbind handler, we should not call
// NdisImDeInitializeDeviceInstance.
//
Adapter->ShutdownMask |= SHUTDOWN_MPHALT_CALLED;
Adapter->PsMpState = AdapterStateClosing;
if(!(Adapter->ShutdownMask & SHUTDOWN_CLEANUP_ADAPTER))
{
Adapter->ShutdownMask |= SHUTDOWN_CLEANUP_ADAPTER;
PS_UNLOCK(&Adapter->Lock);
CleanUpAdapter(Adapter);
}
else
{
PS_UNLOCK(&Adapter->Lock);
}
//
// Close the b/e VC in the mphalt call. This prevents us from taking a lock
// in the send path. We are assured that we will not get any sends after we
// get called in the mphalt handler.
//
if(Adapter->MediaType != NdisMediumWan)
{
PS_LOCK(&Adapter->Lock);
PS_LOCK_DPC(&Adapter->BestEffortVc.Lock);
InternalCloseCall(&Adapter->BestEffortVc);
}
if(Adapter->LowerMpHandle) {
NdisCloseAdapter(&Status, Adapter->LowerMpHandle);
if(Status == NDIS_STATUS_PENDING) {
NdisWaitEvent(&Adapter->BlockingEvent, 0);
NdisResetEvent(&Adapter->BlockingEvent);
Status = Adapter->FinalStatus;
}
REFDEL(&Adapter->RefCount, FALSE, 'NDOP');
}
//
// Deref for the MpInitialize
//
REFDEL(&Adapter->RefCount, FALSE, 'NDHT');
}
NDIS_STATUS
MpReset(
OUT PBOOLEAN AddressingReset,
IN NDIS_HANDLE MiniportAdapterContext
)
/*++
Routine Description:
Arguments:
See the DDK...
Return Values:
None
--*/
{
PADAPTER Adapter = (PADAPTER)MiniportAdapterContext;
PsStructAssert( Adapter );
PsDbgOut(DBG_TRACE, DBG_MINIPORT, ("[MpReset]: Adapter %08X\n", Adapter));
*AddressingReset = FALSE;
return NDIS_STATUS_SUCCESS;
}
HANDLE
GetNdisPipeHandle (
IN HANDLE PsPipeContext
)
/*++
Routine Description:
Return the NDIS handle for the adapter to the requesting scheduling component.
Arguments:
PsPipeContext - Pipe context
Return Values:
Adapter NDIS handle.
--*/
{
return ((PADAPTER)PsPipeContext)->PsNdisHandle;
} // GetNdisPipeHandle
STATIC NDIS_STATUS
FindProfile(
PNDIS_STRING ProfileName,
PPS_PROFILE *Profile
)
/*++
Routine Description:
Find the named profile in the list of profiles
Arguments
ProfileName - Name of the profile to look for.
Return Value:
NDIS_STATUS_SUCCESS if everything worked ok
e--*/
{
NDIS_STATUS Status;
PLIST_ENTRY NextComponent;
PPS_PROFILE PsiInfo;
//
// compare names until we find the right one
//
NextComponent = PsProfileList.Flink;
while ( NextComponent != &PsProfileList ) {
PsiInfo = CONTAINING_RECORD( NextComponent, PS_PROFILE, Links );
if ( ProfileName->Length == PsiInfo->ProfileName.Length ) {
if ( NdisEqualMemory(
ProfileName->Buffer,
PsiInfo->ProfileName.Buffer,
ProfileName->Length )) {
break;
}
}
NextComponent = NextComponent->Flink;
}
if ( NextComponent != &PsProfileList ) {
*Profile = PsiInfo;
Status = NDIS_STATUS_SUCCESS;
} else {
Status = NDIS_STATUS_FAILURE;
}
return Status;
} // FindProfile
NDIS_STATUS
InitializeAdapter(
PADAPTER Adapter,
PVOID BindContext,
PNDIS_STRING MpDeviceName,
PVOID SystemSpecific1)
{
NDIS_STATUS LocalStatus;
PNDIS_STRING PsParamsKey = (PNDIS_STRING) SystemSpecific1;
NdisZeroMemory(Adapter, sizeof(ADAPTER));
PS_INIT_SPIN_LOCK(&Adapter->Lock);
REFINIT(&Adapter->RefCount, Adapter, DeleteAdapter);
REFADD(&Adapter->RefCount, 'NDOP');
Adapter->PsMpState = AdapterStateInitializing;
Adapter->BindContext = BindContext;
Adapter->ShutdownMask = 0;
NdisInitializeEvent(&Adapter->BlockingEvent);
NdisResetEvent(&Adapter->BlockingEvent);
NdisInitializeEvent(&Adapter->RefEvent);
NdisResetEvent(&Adapter->RefEvent);
NdisInitializeEvent(&Adapter->LocalRequestEvent);
NdisResetEvent(&Adapter->LocalRequestEvent);
NdisInitializeEvent(&Adapter->MpInitializeEvent);
NdisResetEvent(&Adapter->MpInitializeEvent);
//
// Initialize the Lists that we are maintaining
//
InitializeListHead(&Adapter->WanLinkList);
InitializeListHead(&Adapter->GpcClientVcList);
//
// By default, Adapter comes in RSVP mode
//
Adapter->AdapterMode = AdapterModeRsvpFlow;
//
// add adapter on list of known adapters
//
NdisInterlockedInsertTailList(&AdapterList,
&Adapter->Linkage,
&AdapterListLock.Lock );
PsAddDevice();
//
// We maintain a list of network addresses enabled on
// each adapter, for IP and for IPX, separately.
//
PsAllocatePool(Adapter->IpNetAddressList,
sizeof(NETWORK_ADDRESS_LIST),
PsMiscTag);
if(!Adapter->IpNetAddressList)
{
goto ERROR_RESOURCES;
}
Adapter->IpNetAddressList->AddressCount = 0;
PsAllocatePool(Adapter->IpxNetAddressList,
sizeof(NETWORK_ADDRESS_LIST),
PsMiscTag);
if(!Adapter->IpxNetAddressList)
{
goto ERROR_RESOURCES;
}
Adapter->IpxNetAddressList->AddressCount = 0;
//
// Allocate a buffer to hold the name of the underlying
// adpater.
//
Adapter->MpDeviceName.Length = MpDeviceName->Length;
Adapter->MpDeviceName.MaximumLength = MpDeviceName->MaximumLength;
PsAllocatePool(Adapter->MpDeviceName.Buffer,
MpDeviceName->MaximumLength,
PsMiscTag);
if(Adapter->MpDeviceName.Buffer == NULL)
{
goto ERROR_RESOURCES;
}
else
{
NdisZeroMemory(
Adapter->MpDeviceName.Buffer,
Adapter->MpDeviceName.MaximumLength);
NdisMoveMemory(
Adapter->MpDeviceName.Buffer,
MpDeviceName->Buffer,
MpDeviceName->Length);
}
//
// Allocate a buffer to hold PsParams Key. This will be
// used by the adapter to read external scheduling component
// specific interface parameters when they register.
//
Adapter->RegistryPath.Length = PsParamsKey->Length;
Adapter->RegistryPath.MaximumLength = PsParamsKey->MaximumLength;
PsAllocatePool(Adapter->RegistryPath.Buffer,
Adapter->RegistryPath.MaximumLength,
PsMiscTag);
if(Adapter->RegistryPath.Buffer == NULL)
{
goto ERROR_RESOURCES;
}
else
{
NdisMoveMemory(
Adapter->RegistryPath.Buffer,
PsParamsKey->Buffer,
PsParamsKey->MaximumLength);
}
//
// Read the per adapter registry info
//
LocalStatus = PsReadAdapterRegistryDataInit(Adapter,
(PNDIS_STRING)SystemSpecific1);
LocalStatus = PsReadAdapterRegistryData(Adapter,
&MachineRegistryKey,
(PNDIS_STRING)SystemSpecific1);
if(LocalStatus != NDIS_STATUS_SUCCESS)
{
PsDbgOut(DBG_FAILURE,
DBG_PROTOCOL | DBG_INIT,
("[InitializeAdapter]: Couldn't get registry data %ws (Status = %08X) \n",
MpDeviceName->Buffer, LocalStatus));
}
return LocalStatus;
ERROR_RESOURCES:
PsAdapterWriteEventLog(
(ULONG)EVENT_PS_RESOURCE_POOL,
0,
MpDeviceName,
0,
NULL);
return NDIS_STATUS_RESOURCES;
}
NDIS_STATUS
RegisterPsComponent(
PPSI_INFO PsiComponentInfo,
ULONG Size,
PPS_DEBUG_INFO DebugInfo
)
/*++
Routine Description:
Called by an external scheduling component to register itself with the PS.
This function is exported by the PS driver. At present, all scheduling
components are internal to the PS, so this entry is not used.
Arguments:
PsiComponentInfo - pointer to component info
Return Value:
STATUS_SUCCESS if everything worked ok
--*/
{
PPSI_INFO comp;
PLIST_ENTRY NextComponent;
PPS_PROFILE PsiInfo;
UINT i;
PLIST_ENTRY NextAdapter;
PADAPTER AdapterInList;
NDIS_STATUS Status;
//
// sanitize it somewhat
//
if ( Size != sizeof( PSI_INFO ))
{
PsDbgOut(DBG_FAILURE, DBG_PROTOCOL,
("[RegisterPsComponent]: Size mismatch \n"));
return NDIS_STATUS_FAILURE;
}
if(PsiComponentInfo->Version != PS_COMPONENT_CURRENT_VERSION)
{
return NDIS_STATUS_FAILURE;
}
if(FindSchedulingComponent(&PsiComponentInfo->ComponentName, &comp) ==
NDIS_STATUS_FAILURE)
{
//
// This component was not a part of any profile in the registry
// and hence is likely to be unused.
//
PsDbgOut(DBG_FAILURE, DBG_PROTOCOL,
("[RegisterPsComponent]: Add-in component %ws is not "
" a part of any profile \n",
PsiComponentInfo->ComponentName.Buffer));
return NDIS_STATUS_FAILURE;
}
// Component has registered. See if it requires DEBUG_INFO
//
if(DebugInfo)
{
#if DBG
DebugInfo->DebugLevel = &DbgTraceLevel;
DebugInfo->DebugMask = &DbgTraceMask;
DebugInfo->LogId = LogId ++;
DebugInfo->LogTraceLevel = &LogTraceLevel;
DebugInfo->LogTraceMask = &LogTraceMask;
DebugInfo->GetCurrentTime = PsGetCurrentTime;
DebugInfo->LogString = DbugSchedString;
DebugInfo->LogSched = DbugSched;
DebugInfo->LogRec = DbugComponentSpecificRec;
#else
DebugInfo->DebugLevel = 0;
DebugInfo->LogId = 0;
DebugInfo->DebugMask = 0;
DebugInfo->LogTraceLevel = 0;
DebugInfo->LogTraceMask = 0;
DebugInfo->GetCurrentTime = 0;
DebugInfo->LogString = 0;
DebugInfo->LogSched = 0;
DebugInfo->LogRec = 0;
#endif
}
//
// We need to lock the component as we could get two "RegisterPsComponent"
// calls for the same component. We don't really need a component level
// lock as we can do with PsComponentListLock & this is not a performance
// critical piece.
//
PS_LOCK(&PsComponentListLock);
if(comp->AddIn == FALSE)
{
//
// Registering a system component! Bail out
//
PS_UNLOCK(&PsComponentListLock);
PsDbgOut(DBG_FAILURE, DBG_PROTOCOL,
("[RegisterPsComponent]: %ws is already a system"
" component \n",
PsiComponentInfo->ComponentName.Buffer));
return NDIS_STATUS_FAILURE;
}
if(comp->Registered == TRUE)
{
//
// Re-registering a component.
//
PS_UNLOCK(&PsComponentListLock);
PsDbgOut(DBG_FAILURE, DBG_PROTOCOL,
("[RegisterPsComponent]: %ws already registered\n",
PsiComponentInfo->ComponentName.Buffer));
return NDIS_STATUS_FAILURE;
}
//
// Update this component in the list.
//
//
// make sure the packet reserved area is sane so our context struct
// is aligned
//
if ( PsiComponentInfo->PacketReservedLength & 3 ) {
PsiComponentInfo->PacketReservedLength =
( PsiComponentInfo->PacketReservedLength & ~3 ) + 4;
}
//
// Update the component in the list
//
comp->PacketReservedLength = PsiComponentInfo->PacketReservedLength;
comp->PipeContextLength = PsiComponentInfo->PipeContextLength;
comp->FlowContextLength = PsiComponentInfo->FlowContextLength;
comp->ClassMapContextLength = PsiComponentInfo->ClassMapContextLength;
comp->SupportedOidsLength = PsiComponentInfo->SupportedOidsLength;
comp->SupportedOidList = PsiComponentInfo->SupportedOidList;
comp->SupportedGuidsLength = PsiComponentInfo->SupportedGuidsLength;
comp->SupportedGuidList = PsiComponentInfo->SupportedGuidList;
comp->InitializePipe = PsiComponentInfo->InitializePipe;
comp->ModifyPipe = PsiComponentInfo->ModifyPipe;
comp->DeletePipe = PsiComponentInfo->DeletePipe;
comp->CreateFlow = PsiComponentInfo->CreateFlow;
comp->ModifyFlow = PsiComponentInfo->ModifyFlow;
comp->DeleteFlow = PsiComponentInfo->DeleteFlow;
comp->EmptyFlow = PsiComponentInfo->EmptyFlow;
comp->SubmitPacket = PsiComponentInfo->SubmitPacket;
comp->SetInformation = PsiComponentInfo->SetInformation;
comp->QueryInformation = PsiComponentInfo->QueryInformation;
comp->CreateClassMap = PsiComponentInfo->CreateClassMap;
comp->DeleteClassMap = PsiComponentInfo->DeleteClassMap;
//
// Right now, only one component uses this...
// This hack is being made for characterization work
//
if (PsiComponentInfo->ReceivePacket) {
TimeStmpRecvPacket = PsiComponentInfo->ReceivePacket;
}
if (PsiComponentInfo->ReceiveIndication) {
TimeStmpRecvIndication = PsiComponentInfo->ReceiveIndication;
}
PS_UNLOCK(&PsComponentListLock);
PsDbgOut(DBG_TRACE, DBG_PROTOCOL,
("[RegisterPsComponent]: Component %ws has "
"registered \n",
PsiComponentInfo->ComponentName.Buffer));
//
// Update the ProfileList
//
NextComponent = PsProfileList.Flink;
while ( NextComponent != &PsProfileList )
{
PsiInfo = CONTAINING_RECORD( NextComponent, PS_PROFILE, Links );
//
// We have to worry only about those profiles
// that have unregistered components.
//
PS_LOCK(&PsProfileLock);
if(PsiInfo->UnregisteredAddInCnt != 0)
{
for(i=0; i<PsiInfo->ComponentCnt; i++)
{
if(PsiInfo->ComponentList[i] == comp)
{
PsiInfo->UnregisteredAddInCnt --;
break;
}
}
}
PS_UNLOCK( &PsProfileLock );
NextComponent = NextComponent->Flink;
}
// Need to walk the adapter list & see if we can
// service the waiting adapters.
PS_LOCK(&AdapterListLock);
NextAdapter = AdapterList.Flink;
while(NextAdapter != &AdapterList)
{
AdapterInList = CONTAINING_RECORD(NextAdapter, ADAPTER, Linkage);
PS_LOCK(&AdapterInList->Lock);
//
// If it's not waiting, we don't care
//
if(AdapterInList->PsMpState != AdapterStateWaiting ){
PS_UNLOCK(&AdapterInList->Lock);
NextAdapter = NextAdapter->Flink;
continue;
}
//
// If it is waiting, we can try to build the scheduling pipe.
//
PS_UNLOCK(&AdapterInList->Lock);
PS_UNLOCK(&AdapterListLock);
Status = UpdateAdapterBandwidthParameters(AdapterInList);
if(Status == NDIS_STATUS_ADAPTER_NOT_READY)
{
PsDbgOut(DBG_TRACE, DBG_PROTOCOL,
("[RegisterPsComponent]: Adapter %08X, Waiting for add-in components to register \n",
AdapterInList));
}
else
{
if(Status == NDIS_STATUS_SUCCESS)
{
PsDbgOut(DBG_TRACE, DBG_PROTOCOL,
("[RegisterPsComponent]: Adapter %08X, all add-in components have registered \n",
AdapterInList));
PsInitializeDeviceInstance(AdapterInList);
}
else
{
PsDbgOut(DBG_CRITICAL_ERROR, DBG_PROTOCOL,
("[RegisterPsComponent]: Adapter %08X, Failed to update scheduling pipe, Status %08X\n",
AdapterInList, Status));
}
}
PS_LOCK(&AdapterListLock);
NextAdapter = NextAdapter->Flink;
}
PS_UNLOCK(&AdapterListLock);
return NDIS_STATUS_SUCCESS;
} // RegisterPsComponent
NDIS_STATUS
FindSchedulingComponent(
PNDIS_STRING ComponentName,
PPSI_INFO *Component
)
/*++
Routine Description:
Find the named component in the list of external scheduling components
Arguments:
ComponentName - name of component to look for
Return Value:
NDIS_STATUS_SUCCESS if everything worked ok
--*/
{
NDIS_STATUS Status;
PLIST_ENTRY NextComponent;
PPSI_INFO PsiInfo;
//
// get the list lock and compare names until we find the right one
//
PS_LOCK( &PsComponentListLock );
NextComponent = PsComponentList.Flink;
while ( NextComponent != &PsComponentList ) {
PsiInfo = CONTAINING_RECORD( NextComponent, PSI_INFO, Links );
if ( ComponentName->Length == PsiInfo->ComponentName.Length ) {
if ( NdisEqualMemory(
ComponentName->Buffer,
PsiInfo->ComponentName.Buffer,
ComponentName->Length )) {
break;
}
}
NextComponent = NextComponent->Flink;
}
PS_UNLOCK( &PsComponentListLock );
if ( NextComponent != &PsComponentList ) {
*Component = PsiInfo;
Status = NDIS_STATUS_SUCCESS;
} else {
Status = NDIS_STATUS_FAILURE;
}
return Status;
} // FindSchedulingComponent
VOID
CloseAllGpcVcs(
PADAPTER Adapter
)
/*++
Routine Description:
Close all the VCs associated with an adapter
Return Value:
None
--*/
{
PGPC_CLIENT_VC Vc;
PLIST_ENTRY NextVc;
//
// Close all the GPC client VCs.
//
PS_LOCK(&Adapter->Lock);
NextVc = Adapter->GpcClientVcList.Flink;
while(NextVc != &Adapter->GpcClientVcList)
{
Vc = CONTAINING_RECORD(NextVc, GPC_CLIENT_VC, Linkage);
PsAssert(Vc);
PS_LOCK_DPC(&Vc->Lock);
if(Vc->ClVcState == CL_INTERNAL_CLOSE_PENDING || Vc->Flags & INTERNAL_CLOSE_REQUESTED)
{
PS_UNLOCK_DPC(&Vc->Lock);
NextVc = NextVc->Flink;
}
else
{
InternalCloseCall(Vc);
PS_LOCK(&Adapter->Lock);
//
// Sigh. We can't really get hold to the NextVc in a reliable manner. When we call
// InternalCloseCall on the Vc, it releases the Adapter Lock (since it might have to
// make calls into NDIS). Now, in this window, the next Vc could go away, and we
// could point to a stale Vc. So, we start at the head of the list.
// Note that this can never lead to a infinite loop, since we don't process the
// internal close'd VCs repeatedly.
//
NextVc = Adapter->GpcClientVcList.Flink;
}
}
PS_UNLOCK(&Adapter->Lock);
} // CloseAllGpcVcs
VOID
PsAdapterWriteEventLog(
IN NDIS_STATUS EventCode,
IN ULONG UniqueEventValue,
IN PNDIS_STRING DeviceName,
IN ULONG DataSize,
IN PVOID Data OPTIONAL
)
{
//
// The String List is the device name, and it has a \Device against it.
//
PWCHAR StringList[1];
NDIS_STRING Prefix = NDIS_STRING_CONST("\\Device\\");
if(DeviceName->Length > Prefix.Length)
{
StringList[0] = (PWCHAR) ((PUCHAR) DeviceName->Buffer + Prefix.Length);
NdisWriteEventLogEntry(PsDriverObject,
EventCode,
UniqueEventValue,
1,
&StringList,
DataSize,
Data);
}
}
/* end adapter.c */