mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1293 lines
25 KiB
1293 lines
25 KiB
/*++
|
|
|
|
Copyright (c) 1990-1995 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
miniport.c
|
|
|
|
Abstract:
|
|
|
|
NDIS miniport wrapper functions
|
|
|
|
Author:
|
|
|
|
Sean Selitrennikoff (SeanSe) 05-Oct-93
|
|
Jameel Hyder (JameelH) Re-organization 01-Jun-95
|
|
|
|
Environment:
|
|
|
|
Kernel mode, FSD
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include <precomp.h>
|
|
#pragma hdrstop
|
|
|
|
//
|
|
// Define the module number for debug code.
|
|
//
|
|
#define MODULE_NUMBER MODULE_MININT
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
//
|
|
// HALT / CLOSE CODE
|
|
//
|
|
/////////////////////////////////////////////////////////////////////
|
|
|
|
BOOLEAN
|
|
ndisMKillOpen(
|
|
PNDIS_OPEN_BLOCK OldOpenP
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Closes an open. Used when NdisCloseAdapter is called, and also
|
|
for internally generated closes.
|
|
|
|
Arguments:
|
|
|
|
OldOpenP - The open to be closed.
|
|
|
|
Return Value:
|
|
|
|
TRUE if the open finished, FALSE if it pended.
|
|
|
|
--*/
|
|
|
|
{
|
|
PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)(OldOpenP->AdapterHandle);
|
|
PNDIS_M_OPEN_BLOCK MiniportOpen;
|
|
BOOLEAN LocalLock, rc = TRUE;
|
|
NDIS_STATUS Status;
|
|
KIRQL OldIrql;
|
|
|
|
//
|
|
// Find the Miniport open block
|
|
//
|
|
|
|
for (MiniportOpen = Miniport->OpenQueue;
|
|
MiniportOpen != NULL;
|
|
MiniportOpen = MiniportOpen->MiniportNextOpen)
|
|
{
|
|
if (MiniportOpen->FakeOpen == OldOpenP)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
ASSERT(MiniportOpen != NULL);
|
|
RAISE_IRQL_TO_DISPATCH(&OldIrql);
|
|
|
|
do
|
|
{
|
|
NDIS_ACQUIRE_SPIN_LOCK_DPC(&MiniportOpen->SpinLock);
|
|
|
|
if (MiniportOpen->Flags & fMINIPORT_OPEN_PMODE)
|
|
{
|
|
Miniport->PmodeOpens --;
|
|
}
|
|
|
|
//
|
|
// See if this open is already closing.
|
|
//
|
|
if (MINIPORT_TEST_FLAG(MiniportOpen, fMINIPORT_OPEN_CLOSING))
|
|
{
|
|
NDIS_RELEASE_SPIN_LOCK_DPC(&MiniportOpen->SpinLock);
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Indicate to others that this open is closing.
|
|
//
|
|
MINIPORT_SET_FLAG(MiniportOpen, fMINIPORT_OPEN_CLOSING);
|
|
NDIS_RELEASE_SPIN_LOCK_DPC(&MiniportOpen->SpinLock);
|
|
|
|
NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
|
|
LOCK_MINIPORT(Miniport, LocalLock);
|
|
|
|
//
|
|
// Remove us from the filter package
|
|
//
|
|
switch (Miniport->MediaType)
|
|
{
|
|
case NdisMediumArcnet878_2:
|
|
if (!MINIPORT_TEST_FLAG(MiniportOpen,
|
|
fMINIPORT_OPEN_USING_ETH_ENCAPSULATION))
|
|
{
|
|
Status = ArcDeleteFilterOpenAdapter(Miniport->ArcDB,
|
|
MiniportOpen->FilterHandle,
|
|
NULL);
|
|
break;
|
|
}
|
|
|
|
//
|
|
// If we're using encapsulation then we
|
|
// didn't open an arcnet filter but rather
|
|
// an ethernet filter.
|
|
//
|
|
|
|
case NdisMedium802_3:
|
|
Status = EthDeleteFilterOpenAdapter(Miniport->EthDB,
|
|
MiniportOpen->FilterHandle,
|
|
NULL);
|
|
break;
|
|
|
|
case NdisMedium802_5:
|
|
Status = TrDeleteFilterOpenAdapter(Miniport->TrDB,
|
|
MiniportOpen->FilterHandle,
|
|
NULL);
|
|
break;
|
|
|
|
case NdisMediumFddi:
|
|
Status = FddiDeleteFilterOpenAdapter(Miniport->FddiDB,
|
|
MiniportOpen->FilterHandle,
|
|
NULL);
|
|
break;
|
|
|
|
case NdisMediumAtm:
|
|
//
|
|
// there is no filter database for ATM medium so we have to handle
|
|
// this differently. Specifically we do not need to know of there
|
|
// is an indication occuring now or not since the indication
|
|
// routine checks if the reference count goes to zero and it
|
|
// also checks the Closing flag. In addition if there is an active
|
|
// indication going on, then there must be an open connection
|
|
// which has the ref count above zero. Since a close on the
|
|
// connection will not run during a receive indication (because
|
|
// the miniport is locked), there should be no special code
|
|
// required for this case.
|
|
//
|
|
Status = NDIS_STATUS_SUCCESS;
|
|
break;
|
|
}
|
|
|
|
if (Status != NDIS_STATUS_CLOSING_INDICATING)
|
|
{
|
|
//
|
|
// Otherwise the close action routine will fix this up.
|
|
//
|
|
DBGPRINT(DBG_COMP_OPEN, DBG_LEVEL_INFO,
|
|
("- Open 0x%x Reference 0x%x\n", MiniportOpen, MiniportOpen->References));
|
|
|
|
MiniportOpen->References--;
|
|
|
|
//
|
|
// If the status that was returned from the filter library
|
|
// was NDIS_STATUS_PENDING then we need to do some set information
|
|
// calls to clean up the opens filter & address settings....
|
|
//
|
|
switch (Miniport->MediaType)
|
|
{
|
|
case NdisMedium802_3:
|
|
case NdisMedium802_5:
|
|
case NdisMediumFddi:
|
|
case NdisMediumArcnet878_2:
|
|
ndisMRestoreFilterSettings(Miniport, MiniportOpen);
|
|
break;
|
|
}
|
|
}
|
|
|
|
UNLOCK_MINIPORT(Miniport, LocalLock);
|
|
|
|
DBGPRINT(DBG_COMP_OPEN, DBG_LEVEL_INFO,
|
|
("!=0 Open 0x%x References 0x%x\n", MiniportOpen, MiniportOpen->References));
|
|
|
|
if (MiniportOpen->References != 0)
|
|
{
|
|
//
|
|
// Wait for close to complete, reference count will drop to 0.
|
|
//
|
|
NDISM_DEFER_PROCESS_DEFERRED(Miniport);
|
|
|
|
rc = FALSE;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Free Vc datastructures are queued to be reused, but when the
|
|
// Open closes we must clean up these free Vcs
|
|
//
|
|
ndisMCoFreeResources(MiniportOpen);
|
|
|
|
//
|
|
// This sends an IRP_MJ_CLOSE IRP.
|
|
//
|
|
ObDereferenceObject(OldOpenP->FileObject);
|
|
|
|
//
|
|
// Remove us from the adapter and protocol open queues.
|
|
//
|
|
ndisDeQueueOpenOnProtocol(OldOpenP, OldOpenP->ProtocolHandle);
|
|
ndisDeQueueOpenOnMiniport(MiniportOpen, MiniportOpen->MiniportHandle);
|
|
|
|
ndisDereferenceProtocol(OldOpenP->ProtocolHandle);
|
|
ndisDereferenceMiniport(MiniportOpen->MiniportHandle);
|
|
|
|
NdisFreeSpinLock(&MiniportOpen->SpinLock);
|
|
FREE_POOL(MiniportOpen);
|
|
FREE_POOL(OldOpenP);
|
|
}
|
|
|
|
NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
|
|
} while (FALSE);
|
|
|
|
LOWER_IRQL(OldIrql);
|
|
return rc;
|
|
}
|
|
|
|
|
|
VOID
|
|
ndisMFinishClose(
|
|
PNDIS_MINIPORT_BLOCK Miniport,
|
|
PNDIS_M_OPEN_BLOCK Open
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Finishes off a close adapter call.
|
|
|
|
CALLED WITH LOCK HELD!!
|
|
|
|
Arguments:
|
|
|
|
Miniport - The mini-port the open is queued on.
|
|
|
|
Open - The open to close
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
|
|
--*/
|
|
{
|
|
//
|
|
// free any memory allocated to Vcs
|
|
//
|
|
ndisMCoFreeResources(Open);
|
|
|
|
ASSERT(MINIPORT_TEST_FLAG(Open, fMINIPORT_OPEN_CLOSING));
|
|
|
|
NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
|
|
|
|
(Open->ProtocolHandle->ProtocolCharacteristics.CloseAdapterCompleteHandler) (
|
|
Open->ProtocolBindingContext,
|
|
NDIS_STATUS_SUCCESS);
|
|
|
|
NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
|
|
|
|
ndisDeQueueOpenOnProtocol(Open->FakeOpen, Open->ProtocolHandle);
|
|
ndisDeQueueOpenOnMiniport(Open, Open->MiniportHandle);
|
|
FREE_POOL(Open->FakeOpen);
|
|
|
|
ndisDereferenceMiniport(Open->MiniportHandle);
|
|
ndisDereferenceProtocol(Open->ProtocolHandle);
|
|
|
|
NdisFreeSpinLock(&Open->SpinLock);
|
|
|
|
//
|
|
// This sends an IRP_MJ_CLOSE IRP.
|
|
//
|
|
|
|
ObDereferenceObject(Open->FileObject);
|
|
|
|
FREE_POOL(Open);
|
|
}
|
|
|
|
|
|
VOID
|
|
ndisDeQueueOpenOnMiniport(
|
|
IN PNDIS_M_OPEN_BLOCK OpenP,
|
|
IN PNDIS_MINIPORT_BLOCK Miniport
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Detaches an open block from the list of opens for a Miniport.
|
|
|
|
Arguments:
|
|
|
|
OpenP - The open block to be dequeued.
|
|
Miniport - The Miniport block to dequeue it from.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
KIRQL OldIrql;
|
|
|
|
NDIS_ACQUIRE_SPIN_LOCK(&Miniport->Ref.SpinLock, &OldIrql);
|
|
|
|
//
|
|
// Find the open on the queue, and remove it.
|
|
//
|
|
|
|
if (Miniport->OpenQueue == OpenP)
|
|
{
|
|
Miniport->OpenQueue = OpenP->MiniportNextOpen;
|
|
}
|
|
else
|
|
{
|
|
PNDIS_M_OPEN_BLOCK PP = Miniport->OpenQueue;
|
|
|
|
while (PP->MiniportNextOpen != OpenP)
|
|
{
|
|
PP = PP->MiniportNextOpen;
|
|
}
|
|
|
|
PP->MiniportNextOpen = PP->MiniportNextOpen->MiniportNextOpen;
|
|
}
|
|
|
|
NDIS_RELEASE_SPIN_LOCK(&Miniport->Ref.SpinLock, OldIrql);
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
ndisQueueMiniportOnDriver(
|
|
IN PNDIS_MINIPORT_BLOCK Miniport,
|
|
IN PNDIS_M_DRIVER_BLOCK MiniBlock
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Adds an mini-port to a list of mini-port for a driver.
|
|
|
|
Arguments:
|
|
|
|
Miniport - The mini-port block to queue.
|
|
MiniBlock - The driver block to queue it to.
|
|
|
|
Return Value:
|
|
|
|
FALSE if the driver is closing.
|
|
TRUE otherwise.
|
|
|
|
--*/
|
|
|
|
{
|
|
KIRQL OldIrql;
|
|
|
|
NDIS_ACQUIRE_SPIN_LOCK(&MiniBlock->Ref.SpinLock, &OldIrql);
|
|
|
|
DBGPRINT(DBG_COMP_CONFIG, DBG_LEVEL_INFO,
|
|
("Enter queue mini-port on driver\n"));
|
|
DBGPRINT(DBG_COMP_CONFIG, DBG_LEVEL_INFO,
|
|
("queue mini-port 0x%x\n", Miniport));
|
|
DBGPRINT(DBG_COMP_CONFIG, DBG_LEVEL_INFO,
|
|
("driver 0x%x\n", MiniBlock));
|
|
|
|
//
|
|
// Make sure the driver is not closing.
|
|
//
|
|
|
|
if (MiniBlock->Ref.Closing)
|
|
{
|
|
DBGPRINT(DBG_COMP_CONFIG, DBG_LEVEL_INFO,
|
|
("Exit queue mini-port on driver\n"));
|
|
|
|
NDIS_RELEASE_SPIN_LOCK(&MiniBlock->Ref.SpinLock, OldIrql);
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Add this adapter at the head of the queue
|
|
//
|
|
|
|
Miniport->NextMiniport = MiniBlock->MiniportQueue;
|
|
MiniBlock->MiniportQueue = Miniport;
|
|
|
|
DBGPRINT(DBG_COMP_CONFIG, DBG_LEVEL_INFO,
|
|
("Exit queue mini-port on driver\n"));
|
|
|
|
NDIS_RELEASE_SPIN_LOCK(&MiniBlock->Ref.SpinLock, OldIrql);
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
VOID
|
|
ndisDequeueMiniportOnDriver(
|
|
PNDIS_MINIPORT_BLOCK Miniport,
|
|
PNDIS_M_DRIVER_BLOCK MiniBlock
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Removes an mini-port from a list of mini-port for a driver.
|
|
|
|
Arguments:
|
|
|
|
Miniport - The mini-port block to dequeue.
|
|
MiniBlock - The driver block to dequeue it from.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
PNDIS_MINIPORT_BLOCK *ppQ;
|
|
KIRQL OldIrql;
|
|
|
|
NDIS_ACQUIRE_SPIN_LOCK(&MiniBlock->Ref.SpinLock, &OldIrql);
|
|
|
|
DBGPRINT(DBG_COMP_UNLOAD, DBG_LEVEL_INFO,
|
|
("Dequeue on driver\n"));
|
|
DBGPRINT(DBG_COMP_UNLOAD, DBG_LEVEL_INFO,
|
|
("dequeue mini-port 0x%x\n", Miniport));
|
|
DBGPRINT(DBG_COMP_UNLOAD, DBG_LEVEL_INFO,
|
|
("driver 0x%x\n", MiniBlock));
|
|
|
|
//
|
|
// Find the driver on the queue, and remove it.
|
|
//
|
|
for (ppQ = &MiniBlock->MiniportQueue;
|
|
*ppQ != NULL;
|
|
ppQ = &(*ppQ)->NextMiniport)
|
|
{
|
|
if (*ppQ == Miniport)
|
|
{
|
|
*ppQ = Miniport->NextMiniport;
|
|
break;
|
|
}
|
|
}
|
|
|
|
ASSERT(*ppQ == Miniport->NextMiniport);
|
|
|
|
NDIS_RELEASE_SPIN_LOCK(&MiniBlock->Ref.SpinLock, OldIrql);
|
|
|
|
if (MiniBlock->Unloading && (MiniBlock->MiniportQueue == (PNDIS_MINIPORT_BLOCK)NULL))
|
|
{
|
|
SET_EVENT(&MiniBlock->MiniportsRemovedEvent);
|
|
}
|
|
|
|
DBGPRINT(DBG_COMP_UNLOAD, DBG_LEVEL_INFO,
|
|
("Exit dequeue mini-port on driver\n"));
|
|
}
|
|
|
|
|
|
VOID
|
|
ndisDereferenceDriver(
|
|
PNDIS_M_DRIVER_BLOCK MiniBlock
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Removes a reference from the mini-port driver, deleting it if the count goes to 0.
|
|
|
|
Arguments:
|
|
|
|
Miniport - The mini-port block to dereference.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
KIRQL OldIrql;
|
|
|
|
if (NdisDereferenceRef(&(MiniBlock)->Ref))
|
|
{
|
|
//
|
|
// Remove it from the global list.
|
|
//
|
|
|
|
ACQUIRE_SPIN_LOCK(&ndisDriverListLock, &OldIrql);
|
|
|
|
if (ndisMiniDriverList == MiniBlock)
|
|
{
|
|
ndisMiniDriverList = MiniBlock->NextDriver;
|
|
}
|
|
else
|
|
{
|
|
PNDIS_M_DRIVER_BLOCK TmpDriver = ndisMiniDriverList;
|
|
|
|
while(TmpDriver->NextDriver != MiniBlock)
|
|
{
|
|
TmpDriver = TmpDriver->NextDriver;
|
|
}
|
|
|
|
TmpDriver->NextDriver = TmpDriver->NextDriver->NextDriver;
|
|
}
|
|
|
|
RELEASE_SPIN_LOCK(&ndisDriverListLock, OldIrql);
|
|
|
|
FREE_POOL(MiniBlock);
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
ndisDereferenceMiniport(
|
|
PNDIS_MINIPORT_BLOCK Miniport
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Removes a reference from the mini-port driver, deleting it if the count goes to 0.
|
|
|
|
Arguments:
|
|
|
|
Miniport - The mini-port block to dereference.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
PSINGLE_LIST_ENTRY Link;
|
|
PNDIS_MINIPORT_WORK_ITEM WorkItem;
|
|
UINT c;
|
|
BOOLEAN TimerQueued;
|
|
|
|
if (NdisDereferenceRef(&(Miniport)->Ref))
|
|
{
|
|
if (Miniport->EthDB)
|
|
{
|
|
EthDeleteFilter(Miniport->EthDB);
|
|
}
|
|
|
|
if (Miniport->TrDB)
|
|
{
|
|
TrDeleteFilter(Miniport->TrDB);
|
|
}
|
|
|
|
if (Miniport->FddiDB)
|
|
{
|
|
FddiDeleteFilter(Miniport->FddiDB);
|
|
}
|
|
|
|
if (Miniport->ArcDB)
|
|
{
|
|
ArcDeleteFilter(Miniport->ArcDB);
|
|
}
|
|
|
|
if (Miniport->Resources)
|
|
{
|
|
ndisMReleaseResources(Miniport);
|
|
}
|
|
|
|
if (((PNDIS_WRAPPER_CONTEXT)Miniport->WrapperContext)->AssignedSlotResources != NULL)
|
|
{
|
|
FREE_POOL(((PNDIS_WRAPPER_CONTEXT)Miniport->WrapperContext)->AssignedSlotResources);
|
|
}
|
|
|
|
//
|
|
// Do we need to acquire the work queue lock?
|
|
//
|
|
if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_FULL_DUPLEX))
|
|
{
|
|
ACQUIRE_SPIN_LOCK_DPC(&Miniport->WorkLock);
|
|
}
|
|
|
|
//
|
|
// Free work items
|
|
//
|
|
while (Miniport->WorkItemFreeQueue.Next != NULL)
|
|
{
|
|
Link = PopEntryList(&Miniport->WorkItemFreeQueue);
|
|
WorkItem = CONTAINING_RECORD(Link, NDIS_MINIPORT_WORK_ITEM, Link);
|
|
FREE_POOL(WorkItem);
|
|
}
|
|
|
|
//
|
|
// Free the work items that are currently on the work queue.
|
|
//
|
|
for (c = 0; c < NUMBER_OF_WORK_ITEM_TYPES; c++)
|
|
{
|
|
//
|
|
// Free all work items on the current queue.
|
|
//
|
|
while (Miniport->WorkQueue[c].Next != NULL)
|
|
{
|
|
Link = PopEntryList(&Miniport->WorkQueue[c]);
|
|
WorkItem = CONTAINING_RECORD(Link, NDIS_MINIPORT_WORK_ITEM, Link);
|
|
FREE_POOL(WorkItem);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Free the single workitem list.
|
|
//
|
|
for (c = 0; c < NUMBER_OF_SINGLE_WORK_ITEMS; c++)
|
|
{
|
|
//
|
|
// Is there a work item here?
|
|
//
|
|
Link = PopEntryList(&Miniport->SingleWorkItems[c]);
|
|
if (Link != NULL)
|
|
{
|
|
WorkItem = CONTAINING_RECORD(Link, NDIS_MINIPORT_WORK_ITEM, Link);
|
|
FREE_POOL(WorkItem);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Do we need to release the work queue lock?
|
|
//
|
|
if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_FULL_DUPLEX))
|
|
{
|
|
RELEASE_SPIN_LOCK_DPC(&Miniport->WorkLock);
|
|
NdisFreeSpinLock(&Miniport->SendLock);
|
|
}
|
|
|
|
//
|
|
// Did we allocate an array of packets?
|
|
//
|
|
if (MINIPORT_TEST_SEND_FLAG(Miniport, fMINIPORT_SEND_PACKET_ARRAY))
|
|
{
|
|
FREE_POOL(Miniport->PacketArray);
|
|
}
|
|
|
|
//
|
|
// Cancel the timer from firing.
|
|
//
|
|
NdisCancelTimer(Miniport->DeferredTimer, &TimerQueued);
|
|
if (TimerQueued)
|
|
{
|
|
NdisStallExecution(NDIS_MINIPORT_DEFERRED_TIMEOUT);
|
|
}
|
|
|
|
//
|
|
// Free the memory allocated for the timer.
|
|
//
|
|
FREE_POOL(Miniport->DeferredTimer);
|
|
|
|
//
|
|
// Is there an arcnet lookahead buffer allocated?
|
|
//
|
|
if (Miniport->ArcnetLookaheadBuffer != NULL)
|
|
{
|
|
FREE_POOL(Miniport->ArcnetLookaheadBuffer);
|
|
}
|
|
|
|
//
|
|
// Delete the global db entry
|
|
//
|
|
if (Miniport->BusId != 0)
|
|
{
|
|
ndisDeleteGlobalDb(Miniport->BusType,
|
|
Miniport->BusId,
|
|
Miniport->BusNumber,
|
|
Miniport->SlotNumber);
|
|
}
|
|
|
|
if (Miniport->FakeMac != NULL)
|
|
{
|
|
FREE_POOL(Miniport->FakeMac);
|
|
}
|
|
|
|
MiniportDereferencePackage();
|
|
if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_IS_CO))
|
|
{
|
|
CoDereferencePackage();
|
|
}
|
|
|
|
ndisDequeueMiniportOnDriver(Miniport, Miniport->DriverHandle);
|
|
ndisDereferenceDriver(Miniport->DriverHandle);
|
|
NdisMDeregisterAdapterShutdownHandler(Miniport);
|
|
IoUnregisterShutdownNotification(Miniport->DeviceObject);
|
|
IoDeleteDevice(Miniport->DeviceObject);
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
ndisMHaltMiniport(
|
|
PNDIS_MINIPORT_BLOCK Miniport
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Does all the clean up for a mini-port.
|
|
|
|
Arguments:
|
|
|
|
Miniport - pointer to the mini-port to halt
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
BOOLEAN LocalLock;
|
|
KIRQL OldIrql;
|
|
BOOLEAN Canceled;
|
|
|
|
NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
|
|
|
|
LOCK_MINIPORT(Miniport, LocalLock);
|
|
while (!LocalLock)
|
|
{
|
|
//
|
|
// This can only happen on an MP system. We must now
|
|
// wait for the other processor to exit the mini-port.
|
|
//
|
|
|
|
NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
|
|
|
|
NdisStallExecution(1000);
|
|
|
|
NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
|
|
LOCK_MINIPORT(Miniport, LocalLock);
|
|
}
|
|
|
|
//
|
|
// We can now release safely
|
|
//
|
|
NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
|
|
|
|
NdisCancelTimer(&Miniport->WakeUpDpcTimer, &Canceled);
|
|
if (!Canceled)
|
|
{
|
|
NdisStallExecution(500000);
|
|
}
|
|
|
|
(Miniport->DriverHandle->MiniportCharacteristics.HaltHandler)(
|
|
Miniport->MiniportAdapterContext);
|
|
|
|
NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
|
|
|
|
ndisMAbortPacketsAndRequests(Miniport);
|
|
|
|
NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
|
|
|
|
//
|
|
// If a shutdown handler was registered then deregister it.
|
|
//
|
|
|
|
NdisMDeregisterAdapterShutdownHandler(Miniport);
|
|
|
|
ndisDereferenceMiniport(Miniport);
|
|
}
|
|
|
|
VOID
|
|
ndisMUnload(
|
|
IN PDRIVER_OBJECT DriverObject
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is called when a driver is supposed to unload. Ndis
|
|
converts this into a set of calls to MiniportHalt() for each
|
|
adapter that the driver has open.
|
|
|
|
Arguments:
|
|
|
|
DriverObject - the driver object for the mac that is to unload.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
PNDIS_M_DRIVER_BLOCK MiniBlock;
|
|
PNDIS_MINIPORT_BLOCK Miniport, NextMiniport;
|
|
KIRQL OldIrql;
|
|
|
|
DBGPRINT(DBG_COMP_UNLOAD, DBG_LEVEL_INFO,
|
|
("Enter unload\n"));
|
|
|
|
//
|
|
// Search for the driver
|
|
//
|
|
|
|
ACQUIRE_SPIN_LOCK(&ndisDriverListLock, &OldIrql);
|
|
|
|
MiniBlock = ndisMiniDriverList;
|
|
|
|
while (MiniBlock != (PNDIS_M_DRIVER_BLOCK)NULL)
|
|
{
|
|
if (MiniBlock->NdisDriverInfo->NdisWrapperDriver == DriverObject)
|
|
{
|
|
break;
|
|
}
|
|
|
|
MiniBlock = MiniBlock->NextDriver;
|
|
}
|
|
|
|
RELEASE_SPIN_LOCK(&ndisDriverListLock, OldIrql);
|
|
|
|
if (MiniBlock == (PNDIS_M_DRIVER_BLOCK)NULL)
|
|
{
|
|
//
|
|
// It is already gone. Just return.
|
|
//
|
|
|
|
DBGPRINT(DBG_COMP_UNLOAD, DBG_LEVEL_INFO,
|
|
("Exit unload\n"));
|
|
|
|
return;
|
|
}
|
|
|
|
MiniBlock->Unloading = TRUE;
|
|
|
|
DBGPRINT(DBG_COMP_UNLOAD, DBG_LEVEL_INFO,
|
|
("Halting mini-port\n"));
|
|
|
|
//
|
|
// Now call MiniportHalt() for each Miniport.
|
|
//
|
|
|
|
Miniport = MiniBlock->MiniportQueue;
|
|
|
|
while (Miniport != (PNDIS_MINIPORT_BLOCK)NULL)
|
|
{
|
|
NextMiniport = Miniport->NextMiniport; // since queue may change
|
|
|
|
NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
|
|
|
|
DBGPRINT(DBG_COMP_UNLOAD, DBG_LEVEL_INFO,
|
|
("Enter shutdown\n"));
|
|
|
|
MINIPORT_SET_FLAG(Miniport, fMINIPORT_HALTING);
|
|
MINIPORT_SET_SEND_FLAG(Miniport, fMINIPORT_SEND_HALTING);
|
|
|
|
//
|
|
// Queue the halt work item.
|
|
//
|
|
NDISM_QUEUE_WORK_ITEM(Miniport, NdisWorkItemHalt, NULL, NULL);
|
|
|
|
MINIPORT_CLEAR_FLAG(Miniport, fMINIPORT_NORMAL_INTERRUPTS);
|
|
|
|
NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
|
|
|
|
ndisMHaltMiniport(Miniport);
|
|
|
|
Miniport = NextMiniport;
|
|
}
|
|
|
|
//
|
|
// Wait for all adapters to be gonzo.
|
|
//
|
|
WAIT_FOR_OBJECT(&MiniBlock->MiniportsRemovedEvent, NULL);
|
|
|
|
RESET_EVENT(&MiniBlock->MiniportsRemovedEvent);
|
|
|
|
//
|
|
// Now remove the last reference (this will remove it from the list)
|
|
//
|
|
|
|
ASSERT(MiniBlock->Ref.ReferenceCount == 1);
|
|
|
|
ndisDereferenceDriver(MiniBlock);
|
|
|
|
DBGPRINT(DBG_COMP_UNLOAD, DBG_LEVEL_INFO, ("Exit unload\n"));
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
ndisMShutdown(
|
|
PDEVICE_OBJECT DeviceObject,
|
|
PIRP Irp
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
The "shutdown handler" for the SHUTDOWN Irp. Will call the Ndis
|
|
shutdown routine, if one is registered.
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - The adapter's device object.
|
|
Irp - The IRP.
|
|
|
|
Return Value:
|
|
|
|
Always STATUS_SUCCESS.
|
|
|
|
--*/
|
|
|
|
{
|
|
PNDIS_WRAPPER_CONTEXT WrapperContext = (PNDIS_WRAPPER_CONTEXT)DeviceObject->DeviceExtension;
|
|
PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)(WrapperContext + 1);
|
|
KIRQL OldIrql;
|
|
BOOLEAN LocalLock;
|
|
|
|
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
|
|
("==>ndisMShutdown\n"));
|
|
|
|
NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
|
|
|
|
//
|
|
// Mark the miniport as halting and NOT using normal interrupts.
|
|
//
|
|
MINIPORT_SET_FLAG(Miniport, fMINIPORT_HALTING);
|
|
MINIPORT_SET_SEND_FLAG(Miniport, fMINIPORT_SEND_HALTING);
|
|
|
|
//
|
|
// Queue a halt work item.
|
|
//
|
|
NDISM_QUEUE_WORK_ITEM(Miniport, NdisWorkItemHalt, NULL, NULL);
|
|
|
|
MINIPORT_CLEAR_FLAG(Miniport, fMINIPORT_NORMAL_INTERRUPTS);
|
|
|
|
if (WrapperContext->ShutdownHandler != NULL)
|
|
{
|
|
LOCK_MINIPORT(Miniport, LocalLock);
|
|
while (!LocalLock)
|
|
{
|
|
//
|
|
// This can only happen on an MP system. We must now
|
|
// wait for the other processor to exit the mini-port.
|
|
//
|
|
NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
|
|
|
|
NdisStallExecution(1000);
|
|
|
|
NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
|
|
LOCK_MINIPORT(Miniport, LocalLock);
|
|
}
|
|
|
|
NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
|
|
|
|
//
|
|
// Call the shutdown routine.
|
|
//
|
|
|
|
if (WrapperContext->ShutdownHandler != NULL)
|
|
{
|
|
WrapperContext->ShutdownHandler(WrapperContext->ShutdownContext);
|
|
}
|
|
|
|
UNLOCK_MINIPORT(Miniport, LocalLock);
|
|
}
|
|
else
|
|
{
|
|
NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
|
|
}
|
|
|
|
Irp->IoStatus.Status = STATUS_SUCCESS;
|
|
|
|
IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
|
|
|
|
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_INFO,
|
|
("<==ndisMShutdown\n"));
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
//
|
|
// PLUG-N-PLAY CODE
|
|
//
|
|
/////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
NDIS_STATUS
|
|
ndisUnloadMiniport(
|
|
IN PNDIS_MINIPORT_BLOCK Miniport
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Unbind all protocols from this miniport and finally unload it.
|
|
|
|
Arguments:
|
|
|
|
Miniport - The Miniport to unload.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
KIRQL OldIrql;
|
|
PNDIS_M_OPEN_BLOCK Open;
|
|
NDIS_BIND_CONTEXT UnbindContext;
|
|
NDIS_STATUS UnbindStatus;
|
|
|
|
NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
|
|
|
|
// Start off by stopping all activity on this miniport
|
|
// MINIPORT_SET_FLAG(Miniport, fMINIPORT_HALTING);
|
|
|
|
//
|
|
// Walk the list of open bindings on this miniport and ask the protocols to
|
|
// unbind from them. For down-level protocols, DEVICE A WAY TO HANDLE THEM.
|
|
//
|
|
next:
|
|
for (Open = Miniport->OpenQueue;
|
|
Open != NULL;
|
|
Open = Open->MiniportNextOpen)
|
|
{
|
|
if (!MINIPORT_TEST_FLAG(Open, (fMINIPORT_OPEN_CLOSING | fMINIPORT_UNLOADING)) &&
|
|
(Open->ProtocolHandle->ProtocolCharacteristics.UnbindAdapterHandler != NULL))
|
|
{
|
|
MINIPORT_SET_FLAG(Open, fMINIPORT_UNLOADING);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (Open != NULL)
|
|
{
|
|
NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
|
|
|
|
INITIALIZE_EVENT(&UnbindContext.Event);
|
|
|
|
WAIT_FOR_OBJECT(&Open->ProtocolHandle->Mutex, NULL);
|
|
(*Open->ProtocolHandle->ProtocolCharacteristics.UnbindAdapterHandler)(
|
|
&UnbindStatus,
|
|
Open->ProtocolBindingContext,
|
|
&UnbindContext);
|
|
|
|
if (UnbindStatus == NDIS_STATUS_PENDING)
|
|
{
|
|
WAIT_FOR_OBJECT(&UnbindContext.Event, NULL);
|
|
}
|
|
|
|
RELEASE_MUTEX(&Open->ProtocolHandle->Mutex);
|
|
|
|
if (UnbindStatus == NDIS_STATUS_PENDING)
|
|
{
|
|
WAIT_FOR_OBJECT(&UnbindContext.Event, NULL);
|
|
}
|
|
|
|
NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
|
|
|
|
goto next;
|
|
}
|
|
|
|
NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
|
|
|
|
//
|
|
// The halt handler must be called when the last reference
|
|
// on the driver block goes away
|
|
//
|
|
return NDIS_STATUS_SUCCESS;
|
|
}
|
|
|
|
NDIS_STATUS
|
|
ndisTranslateMiniportName(
|
|
IN PNDIS_MINIPORT_BLOCK Miniport,
|
|
IN PUCHAR Buffer,
|
|
IN UINT BufferLength,
|
|
OUT PUINT AmountCopied
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Calls the PnP protocols to enumerate PnP ids for the given miniport.
|
|
|
|
Arguments:
|
|
|
|
Miniport - The Miniport in question.
|
|
Buffer, BufferLength - Buffer for a list of PnP Ids.
|
|
AmountCopied - How much buffer was used up.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
KIRQL OldIrql;
|
|
PNDIS_M_OPEN_BLOCK Open, NextOpen;
|
|
NDIS_STATUS Status;
|
|
UINT AmtCopied = 0, TotalAmtCopied = 0;
|
|
|
|
NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
|
|
|
|
//
|
|
// Walk the list of open bindings on this miniport and ask the
|
|
// protocols to enumerate the PnP ids for that binding
|
|
//
|
|
for (Open = Miniport->OpenQueue;
|
|
Open != NULL;
|
|
Open = NextOpen)
|
|
{
|
|
NextOpen = Open->MiniportNextOpen;
|
|
|
|
if (!MINIPORT_TEST_FLAG(Open, (fMINIPORT_OPEN_CLOSING | fMINIPORT_UNLOADING)) &&
|
|
(Open->ProtocolHandle->ProtocolCharacteristics.TranslateHandler != NULL))
|
|
{
|
|
// Reference this open block
|
|
if (TotalAmtCopied < BufferLength)
|
|
{
|
|
Open->References ++;
|
|
NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
|
|
|
|
(*Open->ProtocolHandle->ProtocolCharacteristics.TranslateHandler)(
|
|
&Status,
|
|
Open->ProtocolBindingContext,
|
|
(PNET_PNP_ID)(Buffer + TotalAmtCopied),
|
|
BufferLength - TotalAmtCopied,
|
|
&AmtCopied);
|
|
|
|
NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
|
|
|
|
if (Status == NDIS_STATUS_SUCCESS)
|
|
{
|
|
TotalAmtCopied += AmtCopied;
|
|
}
|
|
|
|
Open->References --;
|
|
if (Open->References == 0)
|
|
{
|
|
NextOpen = Open->MiniportNextOpen;
|
|
ndisMFinishClose(Miniport, Open);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
*AmountCopied = TotalAmtCopied;
|
|
|
|
return NDIS_STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
VOID
|
|
NdisMSetPeriodicTimer(
|
|
IN PNDIS_MINIPORT_TIMER Timer,
|
|
IN UINT MillisecondsPeriod
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Sets up a periodic timer.
|
|
|
|
Arguments:
|
|
|
|
Timer - The timer to Set.
|
|
|
|
MillisecondsPeriod - The timer will fire once every so often.
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
LARGE_INTEGER FireUpTime;
|
|
|
|
FireUpTime.QuadPart = Int32x32To64((LONG)MillisecondsPeriod, -10000);
|
|
|
|
//
|
|
// Set the timer
|
|
//
|
|
SET_PERIODIC_TIMER(&Timer->Timer, FireUpTime, MillisecondsPeriod, &Timer->Dpc);
|
|
}
|
|
|
|
|
|
VOID
|
|
NdisMSleep(
|
|
IN ULONG MicrosecondsToSleep
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Blocks the caller for specified duration of time. Callable at Irql < DISPATCH_LEVEL.
|
|
|
|
Arguments:
|
|
|
|
MicrosecondsToSleep - The caller will be blocked for this much time.
|
|
|
|
Return Value:
|
|
|
|
NONE
|
|
|
|
--*/
|
|
{
|
|
KTIMER SleepTimer;
|
|
LARGE_INTEGER TimerValue;
|
|
|
|
ASSERT (KeGetCurrentIrql() == LOW_LEVEL);
|
|
|
|
INITIALIZE_TIMER_EX(&SleepTimer, SynchronizationTimer);
|
|
|
|
TimerValue.QuadPart = Int32x32To64(MicrosecondsToSleep, -10);
|
|
SET_TIMER(&SleepTimer, TimerValue, NULL);
|
|
|
|
WAIT_FOR_OBJECT(&SleepTimer, NULL);
|
|
}
|
|
|
|
VOID
|
|
ndisMReleaseResources(
|
|
IN PNDIS_MINIPORT_BLOCK Miniport
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
PCM_RESOURCE_LIST Resources;
|
|
BOOLEAN Conflict;
|
|
NTSTATUS NtStatus;
|
|
|
|
Resources = (PCM_RESOURCE_LIST)ALLOC_FROM_POOL(
|
|
sizeof(CM_RESOURCE_LIST) +
|
|
sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR),
|
|
NDIS_TAG_RSRC_LIST);
|
|
if (NULL == Resources)
|
|
{
|
|
return;
|
|
}
|
|
|
|
MoveMemory(
|
|
Resources,
|
|
Miniport->Resources,
|
|
sizeof(CM_RESOURCE_LIST) +
|
|
sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR));
|
|
|
|
//
|
|
// Clear count
|
|
//
|
|
Resources->List->PartialResourceList.Count = 0;
|
|
|
|
//
|
|
// Make the call
|
|
//
|
|
NtStatus = IoReportResourceUsage(
|
|
NULL,
|
|
Miniport->DriverHandle->NdisDriverInfo->NdisWrapperDriver,
|
|
NULL,
|
|
0,
|
|
Miniport->DeviceObject,
|
|
Resources,
|
|
sizeof(CM_RESOURCE_LIST) +
|
|
sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR),
|
|
TRUE,
|
|
&Conflict);
|
|
|
|
FREE_POOL(Resources);
|
|
FREE_POOL(Miniport->Resources);
|
|
Miniport->Resources = NULL;
|
|
}
|