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

2205 lines
60 KiB
C

/*++
Copyright (c) 1990-1995 Microsoft Corporation
Module Name:
protocol.c
Abstract:
NDIS wrapper functions used by protocol modules
Author:
Adam Barr (adamba) 11-Jul-1990
Environment:
Kernel mode, FSD
Revision History:
26-Feb-1991 JohnsonA Added Debugging Code
10-Jul-1991 JohnsonA Implement revised Ndis Specs
01-Jun-1995 JameelH Re-organization/optimization
--*/
#define GLOBALS
#include <precomp.h>
#pragma hdrstop
#include <stdarg.h>
//
// Define the module number for debug code.
//
#define MODULE_NUMBER MODULE_PROTOCOL
//
// Requests used by protocol modules
//
//
VOID
NdisRegisterProtocol(
OUT PNDIS_STATUS pStatus,
OUT PNDIS_HANDLE NdisProtocolHandle,
IN PNDIS_PROTOCOL_CHARACTERISTICS ProtocolCharacteristics,
IN UINT CharacteristicsLength
)
/*++
Routine Description:
Register an NDIS protocol.
Arguments:
Status - Returns the final status.
NdisProtocolHandle - Returns a handle referring to this protocol.
ProtocolCharacteritics - The NDIS_PROTOCOL_CHARACTERISTICS table.
CharacteristicsLength - The length of ProtocolCharacteristics.
Return Value:
None.
Comments:
Called at passive level
--*/
{
PNDIS_PROTOCOL_BLOCK Protocol;
NDIS_STATUS Status;
KIRQL OldIrql;
USHORT size;
DBGPRINT_RAW(DBG_COMP_PROTOCOL, DBG_LEVEL_INFO,
("==>NdisRegisterProtocol\n"));
DBGPRINT_RAW(DBG_COMP_PROTOCOL, DBG_LEVEL_INFO,
(" Protocol: "));
DBGPRINT_UNICODE(DBG_COMP_PROTOCOL, DBG_LEVEL_INFO,
&ProtocolCharacteristics->Name);
DBGPRINT_RAW(DBG_COMP_PROTOCOL, DBG_LEVEL_INFO,
("\n"));
PnPReferencePackage();
ProtocolReferencePackage();
IF_DBG(DBG_COMP_PROTOCOL, DBG_LEVEL_ERR)
{
BOOLEAN f = FALSE;
if (DbgIsNull(ProtocolCharacteristics->OpenAdapterCompleteHandler))
{
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
("RegisterProtocol: OpenAdapterCompleteHandler Null\n"));
f = TRUE;
}
if (DbgIsNull(ProtocolCharacteristics->CloseAdapterCompleteHandler))
{
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
("RegisterProtocol: CloseAdapterCompleteHandler Null\n"));
f = TRUE;
}
if (DbgIsNull(ProtocolCharacteristics->SendCompleteHandler))
{
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
("RegisterProtocol: SendCompleteHandler Null\n"));
f = TRUE;
}
if (DbgIsNull(ProtocolCharacteristics->TransferDataCompleteHandler))
{
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
("RegisterProtocol: TransferDataCompleteHandler Null\n"));
f = TRUE;
}
if (DbgIsNull(ProtocolCharacteristics->ResetCompleteHandler))
{
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
("RegisterProtocol: ResetCompleteHandler Null\n"));
f = TRUE;
}
if (DbgIsNull(ProtocolCharacteristics->RequestCompleteHandler))
{
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
("RegisterProtocol: RequestCompleteHandler Null\n"));
f = TRUE;
}
if (DbgIsNull(ProtocolCharacteristics->ReceiveHandler))
{
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
("RegisterProtocol: ReceiveHandler Null\n"));
f = TRUE;
}
if (DbgIsNull(ProtocolCharacteristics->ReceiveCompleteHandler))
{
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
("RegisterProtocol: ReceiveCompleteHandler Null\n"));
f = TRUE;
}
if (DbgIsNull(ProtocolCharacteristics->StatusHandler))
{
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
("RegisterProtocol: StatusHandler Null\n"));
f = TRUE;
}
if (DbgIsNull(ProtocolCharacteristics->StatusCompleteHandler))
{
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
("RegisterProtocol: StatusCompleteHandler Null\n"));
f = TRUE;
}
if (f)
DBGBREAK(DBG_COMP_ALL, DBG_LEVEL_ERR);
}
do
{
//
// Check version numbers and CharacteristicsLength.
//
size = 0; // Used to indicate bad version below
if (ProtocolCharacteristics->MajorNdisVersion < 4)
{
DbgPrint("Ndis: NdisRegisterProtocol Ndis 3.0 protocols are not supported.\n");
}
else if ((ProtocolCharacteristics->MajorNdisVersion == 4) &&
(ProtocolCharacteristics->MinorNdisVersion == 0))
{
size = sizeof(NDIS40_PROTOCOL_CHARACTERISTICS);
}
else if ((ProtocolCharacteristics->MajorNdisVersion == 5) &&
(ProtocolCharacteristics->MinorNdisVersion <= 1))
{
size = sizeof(NDIS50_PROTOCOL_CHARACTERISTICS);
}
//
// Check that this is an NDIS 4.0/5.0/5.1 protocol.
//
if (size == 0)
{
Status = NDIS_STATUS_BAD_VERSION;
break;
}
if ((ProtocolCharacteristics->BindAdapterHandler == NULL) ||
(ProtocolCharacteristics->UnbindAdapterHandler == NULL))
{
DbgPrint("Ndis: NdisRegisterProtocol protocol does not have Bind/UnbindAdapterHandler and it is not supported.\n");
Status = NDIS_STATUS_BAD_VERSION;
break;
}
//
// Check that CharacteristicsLength is enough.
//
if (CharacteristicsLength < size)
{
Status = NDIS_STATUS_BAD_CHARACTERISTICS;
break;
}
//
// Allocate memory for the NDIS protocol block.
//
Protocol = (PNDIS_PROTOCOL_BLOCK)ALLOC_FROM_POOL(sizeof(NDIS_PROTOCOL_BLOCK) +
ProtocolCharacteristics->Name.Length + sizeof(WCHAR),
NDIS_TAG_PROT_BLK);
if (Protocol == (PNDIS_PROTOCOL_BLOCK)NULL)
{
Status = NDIS_STATUS_RESOURCES;
break;
}
ZeroMemory(Protocol, sizeof(NDIS_PROTOCOL_BLOCK) + sizeof(WCHAR) + ProtocolCharacteristics->Name.Length);
INITIALIZE_MUTEX(&Protocol->Mutex);
//
// Copy over the characteristics table.
//
CopyMemory(&Protocol->ProtocolCharacteristics,
ProtocolCharacteristics,
size);
// Upcase the name in the characteristics table before saving it.
Protocol->ProtocolCharacteristics.Name.Buffer = (PWCHAR)((PUCHAR)Protocol +
sizeof(NDIS_PROTOCOL_BLOCK));
Protocol->ProtocolCharacteristics.Name.Length = ProtocolCharacteristics->Name.Length;
Protocol->ProtocolCharacteristics.Name.MaximumLength = ProtocolCharacteristics->Name.Length;
RtlUpcaseUnicodeString(&Protocol->ProtocolCharacteristics.Name,
&ProtocolCharacteristics->Name,
FALSE);
//
// No opens for this protocol yet.
//
Protocol->OpenQueue = (PNDIS_OPEN_BLOCK)NULL;
ndisInitializeRef(&Protocol->Ref);
*NdisProtocolHandle = (NDIS_HANDLE)Protocol;
Status = NDIS_STATUS_SUCCESS;
//
// Link the protocol into the list.
//
ACQUIRE_SPIN_LOCK(&ndisProtocolListLock, &OldIrql);
Protocol->NextProtocol = ndisProtocolList;
ndisProtocolList = Protocol;
RELEASE_SPIN_LOCK(&ndisProtocolListLock, OldIrql);
REF_NDIS_DRIVER_OBJECT();
if (ndisReferenceProtocol(Protocol))
{
//
// Start a worker thread to notify the protocol of any existing drivers
//
INITIALIZE_WORK_ITEM(&Protocol->WorkItem, ndisCheckProtocolBindings, Protocol);
QUEUE_WORK_ITEM(&Protocol->WorkItem, CriticalWorkQueue);
}
} while (FALSE);
*pStatus = Status;
if (Status != NDIS_STATUS_SUCCESS)
{
ProtocolDereferencePackage();
}
PnPDereferencePackage();
DBGPRINT_RAW(DBG_COMP_PROTOCOL, DBG_LEVEL_INFO,
("<==NdisRegisterProtocol\n"));
}
VOID
NdisDeregisterProtocol(
OUT PNDIS_STATUS Status,
IN NDIS_HANDLE NdisProtocolHandle
)
/*++
Routine Description:
Deregisters an NDIS protocol.
Arguments:
Status - Returns the final status.
NdisProtocolHandle - The handle returned by NdisRegisterProtocol.
Return Value:
None.
Note:
This will kill all the opens for this protocol.
Called at PASSIVE level
--*/
{
PNDIS_PROTOCOL_BLOCK Protocol = (PNDIS_PROTOCOL_BLOCK)NdisProtocolHandle;
KEVENT DeregEvent;
PNDIS_PROTOCOL_BLOCK tProtocol;
KIRQL OldIrql;
DBGPRINT_RAW(DBG_COMP_PROTOCOL, DBG_LEVEL_INFO,
("==>NdisDeregisterProtocol\n"));
DBGPRINT_RAW(DBG_COMP_PROTOCOL, DBG_LEVEL_INFO,
(" Protocol: "));
DBGPRINT_UNICODE(DBG_COMP_PROTOCOL, DBG_LEVEL_INFO,
&Protocol->ProtocolCharacteristics.Name);
DBGPRINT_RAW(DBG_COMP_PROTOCOL, DBG_LEVEL_INFO,
("\n"));
IF_DBG(DBG_COMP_PROTOCOL, DBG_LEVEL_ERR)
{
if (DbgIsNull(NdisProtocolHandle))
{
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
("DeregisterProtocol: Null Handle\n"));
DBGBREAK(DBG_COMP_ALL, DBG_LEVEL_ERR);
}
if (!DbgIsNonPaged(NdisProtocolHandle))
{
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
("DeregisterProtocol: Handle not in NonPaged Memory\n"));
DBGBREAK(DBG_COMP_ALL, DBG_LEVEL_ERR);
}
}
//
// first to check if the protcol exist. some buggy drivers deregister
// even though registeration did not go through
//
PnPReferencePackage();
ACQUIRE_SPIN_LOCK(&ndisProtocolListLock, &OldIrql);
for (tProtocol = ndisProtocolList;
tProtocol != NULL;
tProtocol = tProtocol->NextProtocol)
{
if (tProtocol == Protocol)
{
break;
}
}
RELEASE_SPIN_LOCK(&ndisProtocolListLock, OldIrql);
PnPDereferencePackage();
ASSERT(tProtocol == Protocol);
if (tProtocol == NULL)
{
//
// if a driver is so broken to send a bogus handle to deregister
// better not bother to fail the call. they can mess up even more
//
*Status = NDIS_STATUS_SUCCESS;
return;
}
do
{
//
// If the protocol is already closing, return.
//
if (!ndisCloseRef(&Protocol->Ref))
{
DBGPRINT(DBG_COMP_PROTOCOL, DBG_LEVEL_INFO,
("<==NdisDeregisterProtocol\n"));
*Status = NDIS_STATUS_FAILURE;
break;
}
if (Protocol->AssociatedMiniDriver)
{
Protocol->AssociatedMiniDriver->AssociatedProtocol = NULL;
Protocol->AssociatedMiniDriver = NULL;
}
INITIALIZE_EVENT(&DeregEvent);
Protocol->DeregEvent = &DeregEvent;
ndisCloseAllBindingsOnProtocol(Protocol);
ndisDereferenceProtocol(Protocol);
WAIT_FOR_PROTOCOL(Protocol, &DeregEvent);
*Status = NDIS_STATUS_SUCCESS;
} while (FALSE);
ProtocolDereferencePackage();
DBGPRINT_RAW(DBG_COMP_PROTOCOL, DBG_LEVEL_INFO,
("<==NdisDeregisterProtocol, Status %lx\n", *Status));
}
VOID
NdisOpenAdapter(
OUT PNDIS_STATUS Status,
OUT PNDIS_STATUS OpenErrorStatus,
OUT PNDIS_HANDLE NdisBindingHandle,
OUT PUINT SelectedMediumIndex,
IN PNDIS_MEDIUM MediumArray,
IN UINT MediumArraySize,
IN NDIS_HANDLE NdisProtocolHandle,
IN NDIS_HANDLE ProtocolBindingContext,
IN PNDIS_STRING AdapterName,
IN UINT OpenOptions,
IN PSTRING AddressingInformation OPTIONAL
)
/*++
Routine Description:
Opens a connection between a protocol and an adapter (Miniport).
Arguments:
Status - Returns the final status.
NdisBindingHandle - Returns a handle referring to this open.
SelectedMediumIndex - Index in MediumArray of the medium type that
the MAC wishes to be viewed as.
MediumArray - Array of medium types which a protocol supports.
MediumArraySize - Number of elements in MediumArray.
NdisProtocolHandle - The handle returned by NdisRegisterProtocol.
ProtocolBindingContext - A context for indications.
AdapterName - The name of the adapter to open.
OpenOptions - bit mask.
AddressingInformation - Information passed to MacOpenAdapter.
Return Value:
None.
Note:
Called at PASSIVE level
--*/
{
PNDIS_OPEN_BLOCK NewOpenP = NULL;
PNDIS_PROTOCOL_BLOCK Protocol;
PNDIS_MINIPORT_BLOCK Miniport;
PWORK_QUEUE_ITEM pWorkItem;
PNDIS_POST_OPEN_PROCESSING PostOpen = NULL;
PNDIS_STRING BindDeviceName, RootDeviceName;
KIRQL OldIrql;
BOOLEAN UsingEncapsulation = FALSE;
BOOLEAN DerefProtocol = FALSE;
BOOLEAN DeQueueFromGlobalList = FALSE;
ULONG i, SizeOpen;
//
// Allocate memory for the NDIS open block.
//
DBGPRINT_RAW(DBG_COMP_BIND, DBG_LEVEL_INFO,
("==>NdisOpenAdapter\n"));
DBGPRINT_RAW(DBG_COMP_BIND, DBG_LEVEL_INFO,
(" Protocol: "));
DBGPRINT_UNICODE(DBG_COMP_BIND, DBG_LEVEL_INFO,
&((PNDIS_PROTOCOL_BLOCK)NdisProtocolHandle)->ProtocolCharacteristics.Name);
DBGPRINT_RAW(DBG_COMP_BIND, DBG_LEVEL_INFO,
(" is opening Adapter: "));
DBGPRINT_UNICODE(DBG_COMP_BIND, DBG_LEVEL_INFO,
AdapterName);
DBGPRINT_RAW(DBG_COMP_BIND, DBG_LEVEL_INFO,
("\n"));
IF_DBG(DBG_COMP_CONFIG, DBG_LEVEL_ERR)
{
BOOLEAN f = FALSE;
if (DbgIsNull(NdisProtocolHandle))
{
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
("OpenAdapter: Null ProtocolHandle\n"));
f = TRUE;
}
if (!DbgIsNonPaged(NdisProtocolHandle))
{
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
("OpenAdapter: ProtocolHandle not in NonPaged Memory\n"));
f = TRUE;
}
if (DbgIsNull(ProtocolBindingContext))
{
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
("OpenAdapter: Null Context\n"));
f = TRUE;
}
if (!DbgIsNonPaged(ProtocolBindingContext))
{
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
("OpenAdapter: Context not in NonPaged Memory\n"));
f = TRUE;
}
if (f)
DBGBREAK(DBG_COMP_CONFIG, DBG_LEVEL_ERR);
}
PnPReferencePackage();
do
{
*NdisBindingHandle = NULL;
ASSERT (NdisProtocolHandle != NULL);
Protocol = (PNDIS_PROTOCOL_BLOCK)NdisProtocolHandle;
//
// Increment the protocol's reference count.
//
if (!ndisReferenceProtocol(Protocol))
{
//
// The protocol is closing.
//
*Status = NDIS_STATUS_CLOSING;
break;
}
DerefProtocol = TRUE;
if ((BindDeviceName = Protocol->BindDeviceName) != NULL)
{
//
// This is a PnP transport. We know what we want.
//
RootDeviceName = Protocol->RootDeviceName;
Miniport = Protocol->BindingAdapter;
ASSERT(Miniport != NULL);
}
else
{
BOOLEAN fTester;
//
// This is a legacy transport and it has not come via a Bind upto the protocol.
// Or it can be a IP arp module who wants to defeat this whole scheme.
// Find the root of the filter chain. Sigh !!!
//
fTester = ((Protocol->ProtocolCharacteristics.Flags & NDIS_PROTOCOL_TESTER) != 0);
ndisFindRootDevice(AdapterName,
fTester,
&BindDeviceName,
&RootDeviceName,
&Miniport);
}
if (Miniport == NULL)
{
*Status = NDIS_STATUS_ADAPTER_NOT_FOUND;
break;
}
SizeOpen = MINIPORT_TEST_FLAG(Miniport, fMINIPORT_IS_CO) ?
sizeof(NDIS_OPEN_BLOCK) : (sizeof(NDIS_OPEN_BLOCK) - sizeof(struct _NDIS_OPEN_CO));
NewOpenP = (PNDIS_OPEN_BLOCK)ALLOC_FROM_POOL(SizeOpen, NDIS_TAG_M_OPEN_BLK);
if (NewOpenP == (PNDIS_OPEN_BLOCK)NULL)
{
*Status = NDIS_STATUS_RESOURCES;
break;
}
ZeroMemory(NewOpenP, SizeOpen);
//
// queue the open on the global list
//
ACQUIRE_SPIN_LOCK(&ndisGlobalOpenListLock, &OldIrql);
NewOpenP->NextGlobalOpen = ndisGlobalOpenList;
ndisGlobalOpenList = NewOpenP;
DeQueueFromGlobalList = TRUE;
RELEASE_SPIN_LOCK(&ndisGlobalOpenListLock, OldIrql);
//
// Set the name in the Open to the name passed, not the name opened !!!
//
NewOpenP->BindDeviceName = BindDeviceName;
NewOpenP->RootDeviceName = RootDeviceName;
NewOpenP->MiniportHandle = Miniport;
NewOpenP->ProtocolHandle = Protocol;
NewOpenP->ProtocolBindingContext = ProtocolBindingContext;
//
// set this now just in case we end up calling the protocol for this binding
// before returning from NdisOpenAdapter
//
*NdisBindingHandle = NewOpenP;
//
//
// Is this the ndiswan miniport wrapper?
//
if ((Miniport->MacOptions & NDISWAN_OPTIONS) == NDISWAN_OPTIONS)
{
//
// Yup. We want the binding to think that this is an ndiswan link.
//
for (i = 0; i < MediumArraySize; i++)
{
if (MediumArray[i] == NdisMediumWan)
{
break;
}
}
}
else
{
//
// Select the medium to use
//
for (i = 0; i < MediumArraySize; i++)
{
if (MediumArray[i] == Miniport->MediaType)
{
break;
}
}
}
if (i == MediumArraySize)
{
//
// Check for ethernet encapsulation on Arcnet as
// a possible combination.
//
#if ARCNET
if (Miniport->MediaType == NdisMediumArcnet878_2)
{
for (i = 0; i < MediumArraySize; i++)
{
if (MediumArray[i] == NdisMedium802_3)
{
break;
}
}
if (i == MediumArraySize)
{
*Status = NDIS_STATUS_UNSUPPORTED_MEDIA;
break;
}
UsingEncapsulation = TRUE;
}
else
#endif
{
*Status = NDIS_STATUS_UNSUPPORTED_MEDIA;
break;
}
}
*SelectedMediumIndex = i;
NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
//
// Lock the miniport in case it is not serialized
//
if (!MINIPORT_TEST_FLAG(Miniport, fMINIPORT_DESERIALIZE))
{
BLOCK_LOCK_MINIPORT_DPC_L(Miniport);
}
ndisMOpenAdapter(Status,
NewOpenP,
UsingEncapsulation);
if (*Status == NDIS_STATUS_SUCCESS)
{
//
// If the media is disconnected, swap handlers
//
if (!MINIPORT_TEST_FLAG(Miniport, fMINIPORT_MEDIA_CONNECTED))
{
ndisMSwapOpenHandlers(Miniport,
NDIS_STATUS_NO_CABLE,
fMINIPORT_STATE_MEDIA_DISCONNECTED);
}
if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_IS_CO) &&
(NewOpenP->ProtocolHandle->ProtocolCharacteristics.CoAfRegisterNotifyHandler != NULL))
{
PostOpen = (PNDIS_POST_OPEN_PROCESSING)ALLOC_FROM_POOL(sizeof(NDIS_POST_OPEN_PROCESSING), NDIS_TAG_WORK_ITEM);
if (PostOpen != NULL)
{
OPEN_INCREMENT_AF_NOTIFICATION(NewOpenP);
PostOpen->Open = NewOpenP;
//
// Prepare a work item to send AF notifications.
// Don't queue it yet.
//
INITIALIZE_WORK_ITEM(&PostOpen->WorkItem,
ndisMFinishQueuedPendingOpen,
PostOpen);
}
}
}
if (!MINIPORT_TEST_FLAG(Miniport, fMINIPORT_DESERIALIZE))
{
//
// Unlock the miniport.
//
UNLOCK_MINIPORT_L(Miniport);
}
NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
if (*Status != NDIS_STATUS_SUCCESS)
{
break;
}
//
// For SWENUM miniports, reference it so it won't go away
//
if (MINIPORT_PNP_TEST_FLAG(Miniport, fMINIPORT_SWENUM))
{
PBUS_INTERFACE_REFERENCE BusInterface;
BusInterface = (PBUS_INTERFACE_REFERENCE)(Miniport->BusInterface);
ASSERT(BusInterface != NULL);
if (BusInterface)
{
BusInterface->ReferenceDeviceObject(BusInterface->Interface.Context);
}
}
if (PostOpen != NULL)
{
//
// Complete the Open before queueing AF notifications
//
(((PNDIS_PROTOCOL_BLOCK)NewOpenP->ProtocolHandle)->ProtocolCharacteristics.OpenAdapterCompleteHandler)(
NewOpenP->ProtocolBindingContext,
*Status,
*Status);
QUEUE_WORK_ITEM(&PostOpen->WorkItem, DelayedWorkQueue);
*Status = NDIS_STATUS_PENDING;
}
} while (FALSE);
if ((*Status != NDIS_STATUS_SUCCESS) && (*Status != NDIS_STATUS_PENDING))
{
if (DerefProtocol)
{
ndisDereferenceProtocol(Protocol);
}
if (DeQueueFromGlobalList)
{
ndisRemoveOpenFromGlobalList(NewOpenP);
}
if (NewOpenP != NULL)
{
FREE_POOL(NewOpenP);
}
*NdisBindingHandle = NULL;
}
PnPDereferencePackage();
DBGPRINT_RAW(DBG_COMP_BIND, DBG_LEVEL_INFO,
("<==NdisOpenAdapter\n"));
}
VOID
NdisCloseAdapter(
OUT PNDIS_STATUS Status,
IN NDIS_HANDLE NdisBindingHandle
)
/*++
Routine Description:
Closes a connection between a protocol and an adapter (MAC).
Arguments:
Status - Returns the final status.
NdisBindingHandle - The handle returned by NdisOpenAdapter.
Return Value:
None.
Note:
Called at PASSIVE level
--*/
{
PNDIS_OPEN_BLOCK Open = ((PNDIS_OPEN_BLOCK)NdisBindingHandle);
PNDIS_OPEN_BLOCK tOpen;
PNDIS_MINIPORT_BLOCK Miniport;
KIRQL OldIrql;
PnPReferencePackage();
//
// find the open on global open list
//
ACQUIRE_SPIN_LOCK(&ndisGlobalOpenListLock, &OldIrql);
for (tOpen = ndisGlobalOpenList; tOpen != NULL; tOpen = tOpen->NextGlobalOpen)
{
if (tOpen == Open)
{
break;
}
}
RELEASE_SPIN_LOCK(&ndisGlobalOpenListLock, OldIrql);
#if DBG
if (tOpen)
{
DBGPRINT_RAW(DBG_COMP_BIND, DBG_LEVEL_INFO,
("==>NdisCloseAdapter\n"));
DBGPRINT_RAW(DBG_COMP_BIND, DBG_LEVEL_INFO,
(" Protocol: "));
DBGPRINT_UNICODE(DBG_COMP_BIND, DBG_LEVEL_INFO,
&Open->ProtocolHandle->ProtocolCharacteristics.Name);
DBGPRINT_RAW(DBG_COMP_BIND, DBG_LEVEL_INFO,
(" is closing Adapter: "));
DBGPRINT_UNICODE(DBG_COMP_BIND, DBG_LEVEL_INFO,
&Open->MiniportHandle->MiniportName);
DBGPRINT_RAW(DBG_COMP_BIND, DBG_LEVEL_INFO,
("\n"));
}
#endif
IF_DBG(DBG_COMP_CONFIG, DBG_LEVEL_ERR)
{
if (DbgIsNull(NdisBindingHandle))
{
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
("OpenAdapter: Null BindingHandle\n"));
DBGBREAK(DBG_COMP_CONFIG, DBG_LEVEL_ERR);
}
if (!DbgIsNonPaged(NdisBindingHandle))
{
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
("OpenAdapter: BindingHandle not in NonPaged Memory\n"));
DBGBREAK(DBG_COMP_CONFIG, DBG_LEVEL_ERR);
}
}
do
{
if (tOpen == NULL)
{
*Status = NDIS_STATUS_SUCCESS;
PnPDereferencePackage();
break;
}
Miniport = Open->MiniportHandle;
ASSERT(Miniport != NULL);
//
// For SWENUM miniports, dereference it
//
if (MINIPORT_PNP_TEST_FLAG(Miniport, fMINIPORT_SWENUM))
{
PBUS_INTERFACE_REFERENCE BusInterface;
BusInterface = (PBUS_INTERFACE_REFERENCE)(Miniport->BusInterface);
ASSERT(BusInterface != NULL);
if (BusInterface)
{
BusInterface->DereferenceDeviceObject(BusInterface->Interface.Context);
}
}
//
// This returns TRUE if it finished synchronously.
//
if (ndisMKillOpen(Open))
{
*Status = NDIS_STATUS_SUCCESS;
PnPDereferencePackage();
}
else
{
//
// will complete later. ndisMQueuedFinishClose routine will dereference
// the PnP package. we need to have the pnp package referenced because
// a couple of routines called during completing the close, run at DPC
// ex. ndisMFinishClose, ndisDeQueueOpenOnProtocol and ndisDeQueueOpenOnMiniport
// and they are in pnp package
//
*Status = NDIS_STATUS_PENDING;
}
} while (FALSE);
DBGPRINT_RAW(DBG_COMP_BIND, DBG_LEVEL_INFO,
("<==NdisCloseAdapter\n"));
}
VOID
NdisSetProtocolFilter(
OUT PNDIS_STATUS Status,
IN NDIS_HANDLE NdisBindingHandle,
IN RECEIVE_HANDLER ReceiveHandler,
IN RECEIVE_PACKET_HANDLER ReceivePacketHandler,
IN NDIS_MEDIUM Medium,
IN UINT Offset,
IN UINT Size,
IN PUCHAR Pattern
)
/*++
Routine Description:
Sets a protocol filter.
Arguments:
Status Returns the final status.
NdisProtocolHandle The handle returned by NdisRegisterProtocol.
ReceiveHandler This will be invoked instead of the default receivehandler
when the pattern match happens.
ReceivePacketHandler This will be invoked instead of the default receivepackethandler
when the pattern match happens.
Size Size of pattern
Pattern This must match
Return Value:
None.
Note:
--*/
{
*Status = NDIS_STATUS_NOT_SUPPORTED;
}
VOID
NdisGetDriverHandle(
IN NDIS_HANDLE NdisBindingHandle,
OUT PNDIS_HANDLE NdisDriverHandle
)
/*++
Routine Description:
This routine will return the driver handle for the miniport identified by a binding
Arguments:
NdisBindingHandle
NdisDriverHandle: on return from this function, this will be set to the driver handle
Return Value:
None.
Note:
--*/
{
PNDIS_OPEN_BLOCK OpenBlock = (PNDIS_OPEN_BLOCK)NdisBindingHandle;
DBGPRINT_RAW(DBG_COMP_BIND, DBG_LEVEL_INFO,
("==>NdisGetDriverHandle\n"));
*NdisDriverHandle = OpenBlock->MiniportHandle->DriverHandle;
DBGPRINT_RAW(DBG_COMP_BIND, DBG_LEVEL_INFO,
("<==NdisGetDriverHandle\n"));
}
VOID
NdisReEnumerateProtocolBindings(
IN NDIS_HANDLE NdisProtocolHandle
)
/*++
Routine Description:
Arguments:
Return Value:
None.
Note:
--*/
{
if (ndisReferenceProtocol((PNDIS_PROTOCOL_BLOCK)NdisProtocolHandle))
{
ndisCheckProtocolBindings((PNDIS_PROTOCOL_BLOCK)NdisProtocolHandle);
}
else
{
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
("NdisReEnumerateProtocolBindings: Reference failed for %Z\n",
&((PNDIS_PROTOCOL_BLOCK)NdisProtocolHandle)->ProtocolCharacteristics.Name));
}
}
NTSTATUS
FASTCALL
ndisReferenceProtocolByName(
IN PUNICODE_STRING ProtocolName,
IN OUT PNDIS_PROTOCOL_BLOCK *Protocol,
IN BOOLEAN fPartialMatch
)
/*++
Routine Description:
Arguments:
Return Value:
None.
Note:
--*/
{
KIRQL OldIrql;
UNICODE_STRING UpcaseProtocol;
PNDIS_PROTOCOL_BLOCK TmpProtocol;
NTSTATUS Status = STATUS_OBJECT_NAME_NOT_FOUND, NtStatus;
DBGPRINT_RAW(DBG_COMP_PROTOCOL, DBG_LEVEL_INFO,
("==>ndisReferenceProtocolByName\n"));
DBGPRINT_RAW(DBG_COMP_PROTOCOL, DBG_LEVEL_INFO,
(" Protocol: "));
DBGPRINT_UNICODE(DBG_COMP_PROTOCOL, DBG_LEVEL_INFO,
ProtocolName);
DBGPRINT_RAW(DBG_COMP_PROTOCOL, DBG_LEVEL_INFO,
("\n"));
do
{
UpcaseProtocol.Length = ProtocolName->Length;
UpcaseProtocol.MaximumLength = ProtocolName->Length + sizeof(WCHAR);
UpcaseProtocol.Buffer = ALLOC_FROM_POOL(UpcaseProtocol.MaximumLength, NDIS_TAG_STRING);
if (UpcaseProtocol.Buffer == NULL)
{
//
// return null if we fail
//
*Protocol = NULL;
Status = STATUS_INSUFFICIENT_RESOURCES;
break;
}
NtStatus = RtlUpcaseUnicodeString(&UpcaseProtocol, ProtocolName, FALSE);
ASSERT (NT_SUCCESS(NtStatus));
ACQUIRE_SPIN_LOCK(&ndisProtocolListLock, &OldIrql);
for (TmpProtocol = (*Protocol == NULL) ? ndisProtocolList : (*Protocol)->NextProtocol;
TmpProtocol != NULL;
TmpProtocol = TmpProtocol->NextProtocol)
{
if ((fPartialMatch && (TmpProtocol != *Protocol) &&
NDIS_PARTIAL_MATCH_UNICODE_STRING(&UpcaseProtocol, &TmpProtocol->ProtocolCharacteristics.Name)) ||
(!fPartialMatch &&
NDIS_EQUAL_UNICODE_STRING(&UpcaseProtocol, &TmpProtocol->ProtocolCharacteristics.Name)))
{
if (ndisReferenceProtocol(TmpProtocol))
{
Status = STATUS_SUCCESS;
}
else
{
TmpProtocol = NULL;
}
break;
}
}
RELEASE_SPIN_LOCK(&ndisProtocolListLock, OldIrql);
*Protocol = TmpProtocol;
FREE_POOL(UpcaseProtocol.Buffer);
} while (FALSE);
DBGPRINT_RAW(DBG_COMP_PROTOCOL, DBG_LEVEL_INFO,
("<==ndisReferenceProtocolByName\n"));
return Status;
}
VOID
FASTCALL
ndisDereferenceProtocol(
IN PNDIS_PROTOCOL_BLOCK Protocol
)
/*++
Routine Description:
Arguments:
Return Value:
None.
Note:
--*/
{
BOOLEAN rc;
DBGPRINT_RAW(DBG_COMP_PROTOCOL, DBG_LEVEL_INFO,
("==>ndisDereferenceProtocol\n"));
DBGPRINT_RAW(DBG_COMP_PROTOCOL, DBG_LEVEL_INFO,
(" Protocol: "));
DBGPRINT_UNICODE(DBG_COMP_PROTOCOL, DBG_LEVEL_INFO,
&Protocol->ProtocolCharacteristics.Name);
DBGPRINT_RAW(DBG_COMP_PROTOCOL, DBG_LEVEL_INFO,
(", RefCount: %ld\n", Protocol->Ref.ReferenceCount -1 ));
rc = ndisDereferenceRef(&Protocol->Ref);
if (rc)
{
KIRQL OldIrql;
PNDIS_PROTOCOL_BLOCK *pProtocol;
ACQUIRE_SPIN_LOCK(&ndisProtocolListLock, &OldIrql);
for (pProtocol = &ndisProtocolList;
*pProtocol != NULL;
pProtocol = &(*pProtocol)->NextProtocol)
{
if (*pProtocol == Protocol)
{
*pProtocol = Protocol->NextProtocol;
DEREF_NDIS_DRIVER_OBJECT();
break;
}
}
ASSERT (*pProtocol == Protocol->NextProtocol);
ASSERT (Protocol->OpenQueue == NULL);
RELEASE_SPIN_LOCK(&ndisProtocolListLock, OldIrql);
if (Protocol->DeregEvent != NULL)
SET_EVENT(Protocol->DeregEvent);
FREE_POOL(Protocol);
}
DBGPRINT_RAW(DBG_COMP_PROTOCOL, DBG_LEVEL_INFO,
("<==ndisDereferenceProtocol\n"));
}
VOID
ndisCheckProtocolBindings(
IN PNDIS_PROTOCOL_BLOCK Protocol
)
/*++
Routine Description:
Arguments:
Return Value:
None.
Note:
--*/
{
KIRQL OldIrql;
PNDIS_M_DRIVER_BLOCK MiniBlock, NextMiniBlock;
DBGPRINT_RAW(DBG_COMP_PROTOCOL, DBG_LEVEL_INFO,
("==>ndisCheckProtocolBindings\n"));
DBGPRINT_RAW(DBG_COMP_PROTOCOL, DBG_LEVEL_INFO,
(" Protocol: "));
DBGPRINT_UNICODE(DBG_COMP_PROTOCOL, DBG_LEVEL_INFO,
&Protocol->ProtocolCharacteristics.Name);
DBGPRINT_RAW(DBG_COMP_PROTOCOL, DBG_LEVEL_INFO,
("\n"));
//
// Check again if reference is allowed i.e. if the protocol called NdisDeregisterProtocol
// before this thread had a chance to run.
//
if (!ndisReferenceProtocol(Protocol))
{
ndisDereferenceProtocol(Protocol);
return;
}
PnPReferencePackage();
ACQUIRE_SPIN_LOCK(&ndisMiniDriverListLock, &OldIrql);
//
// First walk the list of miniports
//
for (MiniBlock = ndisMiniDriverList;
MiniBlock != NULL;
MiniBlock = NextMiniBlock)
{
PNDIS_MINIPORT_BLOCK Miniport, NM;
NextMiniBlock = MiniBlock->NextDriver;
if (ndisReferenceDriver(MiniBlock))
{
RELEASE_SPIN_LOCK(&ndisMiniDriverListLock, OldIrql);
ACQUIRE_SPIN_LOCK(&MiniBlock->Ref.SpinLock, &OldIrql);
for (Miniport = MiniBlock->MiniportQueue;
Miniport != NULL;
Miniport = NM)
{
NM = Miniport->NextMiniport;
if (!MINIPORT_PNP_TEST_FLAG(Miniport, fMINIPORT_ORPHANED) &&
MINIPORT_INCREMENT_REF(Miniport))
{
RELEASE_SPIN_LOCK(&MiniBlock->Ref.SpinLock, OldIrql);
ndisCheckAdapterBindings(Miniport, Protocol);
NM = Miniport->NextMiniport;
MINIPORT_DECREMENT_REF(Miniport);
ACQUIRE_SPIN_LOCK(&MiniBlock->Ref.SpinLock, &OldIrql);
}
}
RELEASE_SPIN_LOCK(&MiniBlock->Ref.SpinLock, OldIrql);
ACQUIRE_SPIN_LOCK(&ndisMiniDriverListLock, &OldIrql);
NextMiniBlock = MiniBlock->NextDriver;
ndisDereferenceDriver(MiniBlock, TRUE);
}
}
RELEASE_SPIN_LOCK(&ndisMiniDriverListLock, OldIrql);
//
// Now inform this protocol that we are done for now
//
if (Protocol->ProtocolCharacteristics.PnPEventHandler != NULL)
{
NET_PNP_EVENT NetPnpEvent;
KEVENT Event;
NDIS_STATUS Status;
INITIALIZE_EVENT(&Event);
NdisZeroMemory(&NetPnpEvent, sizeof(NetPnpEvent));
NetPnpEvent.NetEvent = NetEventBindsComplete;
//
// Initialize and save the local event with the PnP event.
//
PNDIS_PNP_EVENT_RESERVED_FROM_NET_PNP_EVENT(&NetPnpEvent)->pEvent = &Event;
WAIT_FOR_PROTO_MUTEX(Protocol);
//
// Indicate the event to the protocol.
//
Status = (Protocol->ProtocolCharacteristics.PnPEventHandler)(NULL, &NetPnpEvent);
if (NDIS_STATUS_PENDING == Status)
{
//
// Wait for completion.
//
WAIT_FOR_PROTOCOL(Protocol, &Event);
}
RELEASE_PROT_MUTEX(Protocol);
}
//
// Dereference twice - one for reference by caller and one for reference at the beginning
// of this routine.
//
ndisDereferenceProtocol(Protocol);
ndisDereferenceProtocol(Protocol);
PnPDereferencePackage();
DBGPRINT_RAW(DBG_COMP_PROTOCOL, DBG_LEVEL_INFO,
("<==ndisCheckProtocolBindings\n"));
}
VOID
NdisOpenProtocolConfiguration(
OUT PNDIS_STATUS Status,
OUT PNDIS_HANDLE ConfigurationHandle,
IN PNDIS_STRING ProtocolSection
)
/*++
Routine Description:
Arguments:
Return Value:
None.
Note:
--*/
{
PNDIS_CONFIGURATION_HANDLE HandleToReturn;
PNDIS_WRAPPER_CONFIGURATION_HANDLE ConfigHandle;
UINT Size;
#define PQueryTable ConfigHandle->ParametersQueryTable
DBGPRINT_RAW(DBG_COMP_PROTOCOL, DBG_LEVEL_INFO,
("==>NdisOpenProtocolConfiguration\n"));
do
{
//
// Allocate the space for configuration handle
//
Size = sizeof(NDIS_CONFIGURATION_HANDLE) +
sizeof(NDIS_WRAPPER_CONFIGURATION_HANDLE) +
ProtocolSection->MaximumLength + sizeof(WCHAR);
HandleToReturn = ALLOC_FROM_POOL(Size, NDIS_TAG_PROTOCOL_CONFIGURATION);
*Status = (HandleToReturn != NULL) ? NDIS_STATUS_SUCCESS : NDIS_STATUS_RESOURCES;
if (*Status != NDIS_STATUS_SUCCESS)
{
*ConfigurationHandle = (NDIS_HANDLE)NULL;
break;
}
ZeroMemory(HandleToReturn, Size);
ConfigHandle = (PNDIS_WRAPPER_CONFIGURATION_HANDLE)((PUCHAR)HandleToReturn + sizeof(NDIS_CONFIGURATION_HANDLE));
HandleToReturn->KeyQueryTable = ConfigHandle->ParametersQueryTable;
HandleToReturn->ParameterList = NULL;
PQueryTable[0].QueryRoutine = NULL;
PQueryTable[0].Flags = RTL_QUERY_REGISTRY_SUBKEY;
PQueryTable[0].Name = L"";
//
// 1.
// Call ndisSaveParameter for a parameter, which will allocate storage for it.
//
PQueryTable[1].QueryRoutine = ndisSaveParameters;
PQueryTable[1].Flags = RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_NOEXPAND;
PQueryTable[1].DefaultType = REG_NONE;
//
// PQueryTable[0].Name and PQueryTable[0].EntryContext
// are filled in inside ReadConfiguration, in preparation
// for the callback.
//
// PQueryTable[0].Name = KeywordBuffer;
// PQueryTable[0].EntryContext = ParameterValue;
//
// 2.
// Stop
//
PQueryTable[2].QueryRoutine = NULL;
PQueryTable[2].Flags = 0;
PQueryTable[2].Name = NULL;
//
// NOTE: Some fields in ParametersQueryTable[3] are used to store information for later retrieval.
//
PQueryTable[3].QueryRoutine = NULL;
PQueryTable[3].Name = (PWSTR)((PUCHAR)HandleToReturn +
sizeof(NDIS_CONFIGURATION_HANDLE) +
sizeof(NDIS_WRAPPER_CONFIGURATION_HANDLE));
CopyMemory(PQueryTable[3].Name, ProtocolSection->Buffer, ProtocolSection->Length);
PQueryTable[3].EntryContext = NULL;
PQueryTable[3].DefaultData = NULL;
*ConfigurationHandle = (NDIS_HANDLE)HandleToReturn;
*Status = NDIS_STATUS_SUCCESS;
} while (FALSE);
DBGPRINT_RAW(DBG_COMP_PROTOCOL, DBG_LEVEL_INFO,
("<==NdisOpenProtocolConfiguration\n"));
}
BOOLEAN
FASTCALL
ndisQueueOpenOnProtocol(
IN PNDIS_OPEN_BLOCK OpenP,
IN PNDIS_PROTOCOL_BLOCK Protocol
)
/*++
Routine Description:
Attaches an open block to the list of opens for a protocol.
Arguments:
OpenP - The open block to be queued.
Protocol - The protocol block to queue it to.
NOTE: can be called at raised IRQL.
Return Value:
TRUE if the operation is successful.
FALSE if the protocol is closing.
--*/
{
KIRQL OldIrql;
BOOLEAN rc;
DBGPRINT_RAW(DBG_COMP_BIND, DBG_LEVEL_INFO,
("==>ndisQueueOpenOnProtocol\n"));
DBGPRINT_RAW(DBG_COMP_BIND, DBG_LEVEL_INFO,
(" Protocol: "));
DBGPRINT_UNICODE(DBG_COMP_BIND, DBG_LEVEL_INFO,
&Protocol->ProtocolCharacteristics.Name);
DBGPRINT_RAW(DBG_COMP_BIND, DBG_LEVEL_INFO,
("\n"));
IF_DBG(DBG_COMP_PROTOCOL, DBG_LEVEL_ERR)
{
BOOLEAN f = FALSE;
if (DbgIsNull(OpenP))
{
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
("ndisQueueOpenOnProtocol: Null Open Block\n"));
f = TRUE;
}
if (!DbgIsNonPaged(OpenP))
{
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
("ndisQueueOpenOnProtocol: Open Block not in NonPaged Memory\n"));
f = TRUE;
}
if (DbgIsNull(Protocol))
{
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
("ndisQueueOpenOnProtocol: Null Protocol Block\n"));
f = TRUE;
}
if (!DbgIsNonPaged(Protocol))
{
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
("ndisQueueOpenOnProtocol: Protocol Block not in NonPaged Memory\n"));
f = TRUE;
}
if (f)
DBGBREAK(DBG_COMP_ALL, DBG_LEVEL_ERR);
}
do
{
//
// we can not reference the package here because this routine can
// be called at raised IRQL.
// make sure the PNP package has been referenced already
//
ASSERT(ndisPkgs[NPNP_PKG].ReferenceCount > 0);
ACQUIRE_SPIN_LOCK(&Protocol->Ref.SpinLock, &OldIrql);
//
// Make sure the protocol is not closing.
//
if (Protocol->Ref.Closing)
{
rc = FALSE;
break;
}
//
// Attach this open at the head of the queue.
//
OpenP->ProtocolNextOpen = Protocol->OpenQueue;
Protocol->OpenQueue = OpenP;
rc = TRUE;
} while (FALSE);
RELEASE_SPIN_LOCK(&Protocol->Ref.SpinLock, OldIrql);
DBGPRINT_RAW(DBG_COMP_BIND, DBG_LEVEL_INFO,
("<==ndisQueueOpenOnProtocol\n"));
return rc;
}
VOID
FASTCALL
ndisDeQueueOpenOnProtocol(
IN PNDIS_OPEN_BLOCK OpenP,
IN PNDIS_PROTOCOL_BLOCK Protocol
)
/*++
Routine Description:
Detaches an open block from the list of opens for a protocol.
Arguments:
OpenP - The open block to be dequeued.
Protocol - The protocol block to dequeue it from.
NOTE: can be called at raised IRQL
Return Value:
None.
--*/
{
KIRQL OldIrql;
DBGPRINT_RAW(DBG_COMP_BIND, DBG_LEVEL_INFO,
("==>ndisDeQueueOpenOnProtocol\n"));
DBGPRINT_RAW(DBG_COMP_BIND, DBG_LEVEL_INFO,
(" Protocol: "));
DBGPRINT_UNICODE(DBG_COMP_BIND, DBG_LEVEL_INFO,
&Protocol->ProtocolCharacteristics.Name);
DBGPRINT_RAW(DBG_COMP_BIND, DBG_LEVEL_INFO,
("\n"));
IF_DBG(DBG_COMP_PROTOCOL, DBG_LEVEL_ERR)
{
BOOLEAN f = FALSE;
if (DbgIsNull(OpenP))
{
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
("ndisDeQueueOpenOnProtocol: Null Open Block\n"));
f = TRUE;
}
if (!DbgIsNonPaged(OpenP))
{
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
("ndisDeQueueOpenOnProtocol: Open Block not in NonPaged Memory\n"));
f = TRUE;
}
if (DbgIsNull(Protocol))
{
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
("ndisDeQueueOpenOnProtocol: Null Protocol Block\n"));
f = TRUE;
}
if (!DbgIsNonPaged(Protocol))
{
DBGPRINT(DBG_COMP_ALL, DBG_LEVEL_ERR,
("ndisDeQueueOpenOnProtocol: Protocol Block not in NonPaged Memory\n"));
f = TRUE;
}
if (f)
DBGBREAK(DBG_COMP_ALL, DBG_LEVEL_ERR);
}
//
// we can not reference the package here because this routine can
// be claled at raised IRQL.
// make sure the PNP package has been referenced already
//
ASSERT(ndisPkgs[NPNP_PKG].ReferenceCount > 0);
ACQUIRE_SPIN_LOCK(&Protocol->Ref.SpinLock, &OldIrql);
//
// Find the open on the queue, and remove it.
//
if (OpenP == (PNDIS_OPEN_BLOCK)(Protocol->OpenQueue))
{
Protocol->OpenQueue = OpenP->ProtocolNextOpen;
}
else
{
PNDIS_OPEN_BLOCK PP = Protocol->OpenQueue;
while ((PP != NULL) && (OpenP != (PNDIS_OPEN_BLOCK)(PP->ProtocolNextOpen)))
{
PP = PP->ProtocolNextOpen;
}
if (PP == NULL)
{
#if TRACK_MOPEN_REFCOUNTS
DbgPrint("Ndis:ndisDeQueueOpenOnProtocol Open %p is -not- on Protocol %p\n", OpenP, Protocol);
DbgBreakPoint();
#endif
}
else
{
PP->ProtocolNextOpen = PP->ProtocolNextOpen->ProtocolNextOpen;
}
}
RELEASE_SPIN_LOCK(&Protocol->Ref.SpinLock, OldIrql);
DBGPRINT_RAW(DBG_COMP_BIND, DBG_LEVEL_INFO,
("<==ndisDeQueueOpenOnProtocol\n"));
}
NDIS_STATUS
NdisWriteEventLogEntry(
IN PVOID LogHandle,
IN NDIS_STATUS EventCode,
IN ULONG UniqueEventValue,
IN USHORT NumStrings,
IN PVOID StringsList OPTIONAL,
IN ULONG DataSize,
IN PVOID Data OPTIONAL
)
/*++
Routine Description:
This function allocates an I/O error log record, fills it in and writes it
to the I/O error log on behalf of a NDIS Protocol.
Arguments:
LogHandle - Pointer to the driver object logging this event.
EventCode - Identifies the error message.
UniqueEventValue - Identifies this instance of a given error message.
NumStrings - Number of unicode strings in strings list.
DataSize - Number of bytes of data.
Strings - Array of pointers to unicode strings (PWCHAR).
Data - Binary dump data for this message, each piece being
aligned on word boundaries.
Return Value:
NDIS_STATUS_SUCCESS - The error was successfully logged.
NDIS_STATUS_BUFFER_TOO_SHORT - The error data was too large to be logged.
NDIS_STATUS_RESOURCES - Unable to allocate memory.
Notes:
This code is paged and may not be called at raised IRQL.
--*/
{
PIO_ERROR_LOG_PACKET ErrorLogEntry;
ULONG PaddedDataSize;
ULONG PacketSize;
ULONG TotalStringsSize = 0;
USHORT i;
PWCHAR *Strings;
PWCHAR Tmp;
NDIS_STATUS Status;
DBGPRINT_RAW(DBG_COMP_CONFIG, DBG_LEVEL_INFO,
("==>NdisWriteEventLogEntry\n"));
do
{
Strings = (PWCHAR *)StringsList;
//
// Sum up the length of the strings
//
for (i = 0; i < NumStrings; i++)
{
PWCHAR currentString;
ULONG stringSize;
stringSize = sizeof(UNICODE_NULL);
currentString = Strings[i];
while (*currentString++ != UNICODE_NULL)
{
stringSize += sizeof(WCHAR);
}
TotalStringsSize += stringSize;
}
if (DataSize % sizeof(ULONG))
{
PaddedDataSize = DataSize + (sizeof(ULONG) - (DataSize % sizeof(ULONG)));
}
else
{
PaddedDataSize = DataSize;
}
PacketSize = TotalStringsSize + PaddedDataSize;
if (PacketSize > NDIS_MAX_EVENT_LOG_DATA_SIZE)
{
Status = NDIS_STATUS_BUFFER_TOO_SHORT; // Too much error data
break;
}
//
// Now add in the size of the log packet, but subtract 4 from the data
// since the packet struct contains a ULONG for data.
//
if (PacketSize > sizeof(ULONG))
{
PacketSize += sizeof(IO_ERROR_LOG_PACKET) - sizeof(ULONG);
}
else
{
PacketSize += sizeof(IO_ERROR_LOG_PACKET);
}
ASSERT(PacketSize <= ERROR_LOG_MAXIMUM_SIZE);
ErrorLogEntry = (PIO_ERROR_LOG_PACKET) IoAllocateErrorLogEntry((PDRIVER_OBJECT)LogHandle,
(UCHAR) PacketSize);
if (ErrorLogEntry == NULL)
{
Status = NDIS_STATUS_RESOURCES;
break;
}
//
// Fill in the necessary log packet fields.
//
ErrorLogEntry->UniqueErrorValue = UniqueEventValue;
ErrorLogEntry->ErrorCode = EventCode;
ErrorLogEntry->NumberOfStrings = NumStrings;
ErrorLogEntry->StringOffset = (USHORT) (sizeof(IO_ERROR_LOG_PACKET) + PaddedDataSize - sizeof(ULONG));
ErrorLogEntry->DumpDataSize = (USHORT) PaddedDataSize;
//
// Copy the Dump Data to the packet
//
if (DataSize > 0)
{
RtlMoveMemory((PVOID) ErrorLogEntry->DumpData,
Data,
DataSize);
}
//
// Copy the strings to the packet.
//
Tmp = (PWCHAR)((PUCHAR)ErrorLogEntry + ErrorLogEntry->StringOffset);
for (i = 0; i < NumStrings; i++)
{
PWCHAR wchPtr = Strings[i];
while( (*Tmp++ = *wchPtr++) != UNICODE_NULL)
NOTHING;
}
IoWriteErrorLogEntry(ErrorLogEntry);
Status = NDIS_STATUS_SUCCESS;
} while (FALSE);
DBGPRINT_RAW(DBG_COMP_CONFIG, DBG_LEVEL_INFO,
("<==NdisWriteEventLogEntry\n"));
return Status;
}
#if DBG
BOOLEAN
ndisReferenceProtocol(
IN PNDIS_PROTOCOL_BLOCK Protocol
)
{
BOOLEAN rc;
DBGPRINT_RAW(DBG_COMP_PROTOCOL, DBG_LEVEL_INFO,
("==>ndisReferenceProtocol\n"));
rc = ndisReferenceRef(&Protocol->Ref);
DBGPRINT_RAW(DBG_COMP_PROTOCOL, DBG_LEVEL_INFO,
(" Protocol: "));
DBGPRINT_UNICODE(DBG_COMP_PROTOCOL, DBG_LEVEL_INFO,
&Protocol->ProtocolCharacteristics.Name);
DBGPRINT_RAW(DBG_COMP_PROTOCOL, DBG_LEVEL_INFO,
(", RefCount: %ld\n", Protocol->Ref.ReferenceCount));
DBGPRINT_RAW(DBG_COMP_PROTOCOL, DBG_LEVEL_INFO,
("<==ndisReferenceProtocol\n"));
return rc;
}
#endif
NDIS_STATUS
NdisQueryBindInstanceName(
OUT PNDIS_STRING pAdapterInstanceName,
IN NDIS_HANDLE BindingContext
)
{
PNDIS_BIND_CONTEXT BindContext = (NDIS_HANDLE)BindingContext;
PNDIS_MINIPORT_BLOCK Miniport;
USHORT cbSize;
PVOID ptmp = NULL;
NDIS_STATUS Status = NDIS_STATUS_FAILURE;
NTSTATUS NtStatus;
PNDIS_STRING pAdapterName;
DBGPRINT(DBG_COMP_BIND, DBG_LEVEL_INFO,
("==>NdisQueryBindInstanceName\n"));
Miniport = BindContext->Miniport;
pAdapterName = Miniport->pAdapterInstanceName;
//
// If we failed to create the adapter instance name then fail the call.
//
if (NULL != pAdapterName)
{
//
// Allocate storage for the copy of the adapter instance name.
//
cbSize = pAdapterName->MaximumLength;
//
// Allocate storage for the new string.
//
ptmp = ALLOC_FROM_POOL(cbSize, NDIS_TAG_NAME_BUF);
if (NULL != ptmp)
{
RtlZeroMemory(ptmp, cbSize);
pAdapterInstanceName->Buffer = ptmp;
pAdapterInstanceName->Length = 0;
pAdapterInstanceName->MaximumLength = cbSize;
NtStatus = RtlAppendUnicodeStringToString(pAdapterInstanceName, pAdapterName);
if (NT_SUCCESS(NtStatus))
{
Status = NDIS_STATUS_SUCCESS;
}
}
else
{
Status = NDIS_STATUS_RESOURCES;
}
}
if (NDIS_STATUS_SUCCESS != Status)
{
if (NULL != ptmp)
{
FREE_POOL(ptmp);
}
}
DBGPRINT(DBG_COMP_BIND, DBG_LEVEL_INFO,
("<==NdisQueryBindInstanceName: 0x%x\n", Status));
return(Status);
}
NDIS_STATUS
NdisQueryAdapterInstanceName(
OUT PNDIS_STRING pAdapterInstanceName,
IN NDIS_HANDLE NdisBindingHandle
)
{
PNDIS_OPEN_BLOCK pOpen = (PNDIS_OPEN_BLOCK)NdisBindingHandle;
PNDIS_MINIPORT_BLOCK Miniport= (PNDIS_MINIPORT_BLOCK)pOpen->MiniportHandle;
USHORT cbSize;
PVOID ptmp = NULL;
NDIS_STATUS Status = NDIS_STATUS_FAILURE;
NTSTATUS NtStatus;
PNDIS_STRING pAdapterName;
DBGPRINT(DBG_COMP_BIND, DBG_LEVEL_INFO,
("==>NdisQueryAdapterInstanceName\n"));
pAdapterName = Miniport->pAdapterInstanceName;
//
// If we failed to create the adapter instance name then fail the call.
//
if (NULL != pAdapterName)
{
//
// Allocate storage for the copy of the adapter instance name.
//
cbSize = pAdapterName->MaximumLength;
//
// Allocate storage for the new string.
//
ptmp = ALLOC_FROM_POOL(cbSize, NDIS_TAG_NAME_BUF);
if (NULL != ptmp)
{
RtlZeroMemory(ptmp, cbSize);
pAdapterInstanceName->Buffer = ptmp;
pAdapterInstanceName->Length = 0;
pAdapterInstanceName->MaximumLength = cbSize;
NtStatus = RtlAppendUnicodeStringToString(pAdapterInstanceName, pAdapterName);
if (NT_SUCCESS(NtStatus))
{
Status = NDIS_STATUS_SUCCESS;
}
}
else
{
Status = NDIS_STATUS_RESOURCES;
}
}
if (NDIS_STATUS_SUCCESS != Status)
{
if (NULL != ptmp)
{
FREE_POOL(ptmp);
}
}
DBGPRINT(DBG_COMP_BIND, DBG_LEVEL_INFO,
("<==NdisQueryAdapterInstanceName: 0x%x\n", Status));
return(Status);
}
NDIS_STATUS
ndisCloseAllBindingsOnProtocol(
PNDIS_PROTOCOL_BLOCK Protocol
)
{
PNDIS_OPEN_BLOCK Open, TmpOpen;
KIRQL OldIrql;
NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
BOOLEAN MoreOpen = TRUE;
DBGPRINT_RAW(DBG_COMP_PROTOCOL, DBG_LEVEL_INFO,
("==>ndisCloseAllBindingsOnProtocol: Protocol %p\n", Protocol));
PnPReferencePackage();
//
// loop through all opens on the protocol and find the first one that is
// not already tagged as getting unbound
//
ACQUIRE_SPIN_LOCK(&Protocol->Ref.SpinLock, &OldIrql);
next:
for (Open = Protocol->OpenQueue;
Open != NULL;
Open = Open->ProtocolNextOpen)
{
ACQUIRE_SPIN_LOCK_DPC(&Open->SpinLock);
if (!MINIPORT_TEST_FLAG(Open, (fMINIPORT_OPEN_CLOSING | fMINIPORT_OPEN_PROCESSING)))
{
MINIPORT_SET_FLAG(Open, fMINIPORT_OPEN_PROCESSING);
if (!MINIPORT_TEST_FLAG(Open, fMINIPORT_OPEN_UNBINDING))
{
MINIPORT_SET_FLAG(Open, fMINIPORT_OPEN_UNBINDING | fMINIPORT_OPEN_DONT_FREE);
RELEASE_SPIN_LOCK_DPC(&Open->SpinLock);
break;
}
#if DBG
else
{
DBGPRINT_RAW(DBG_COMP_PROTOCOL, DBG_LEVEL_INFO,
("ndisCloseAllBindingsOnProtocol: Open %p is already Closing, Flags %lx\n",
Open, Open->Flags));
}
#endif
}
RELEASE_SPIN_LOCK_DPC(&Open->SpinLock);
}
if (Open)
{
//
// close the adapter
//
RELEASE_SPIN_LOCK(&Protocol->Ref.SpinLock, OldIrql);
Status = ndisUnbindProtocol(Open, FALSE);
ASSERT(Status == NDIS_STATUS_SUCCESS);
ACQUIRE_SPIN_LOCK(&Protocol->Ref.SpinLock, &OldIrql);
goto next;
}
//
// if we reached the end of the list but there are still some opens
// that are not marked for closing (can happen if we skip an open only because of
// processign flag being set) release the spinlocks, give whoever set the
// processing flag time to release the open. then go back and try again
// ultimately, all opens should either be marked for Unbinding or be gone
// by themselves
//
for (TmpOpen = Protocol->OpenQueue;
TmpOpen != NULL;
TmpOpen = TmpOpen->ProtocolNextOpen)
{
if (!MINIPORT_TEST_FLAG(TmpOpen, fMINIPORT_OPEN_UNBINDING))
break;
}
if (TmpOpen != NULL)
{
RELEASE_SPIN_LOCK(&Protocol->Ref.SpinLock, OldIrql);
NDIS_INTERNAL_STALL(50);
ACQUIRE_SPIN_LOCK(&Protocol->Ref.SpinLock, &OldIrql);
goto next;
}
RELEASE_SPIN_LOCK(&Protocol->Ref.SpinLock, OldIrql);
PnPDereferencePackage();
DBGPRINT_RAW(DBG_COMP_PROTOCOL, DBG_LEVEL_INFO,
("<==ndisCloseAllBindingsOnProtocol: Protocol %p, Status %lx\n", Protocol, Status));
return Status;
}
VOID
NdisSetPacketCancelId(
IN PNDIS_PACKET Packet,
IN PVOID CancelId
)
{
NDIS_SET_PACKET_CANCEL_ID(Packet, CancelId);
return;
}
PVOID
NdisGetPacketCancelId(
IN PNDIS_PACKET Packet
)
{
return NDIS_GET_PACKET_CANCEL_ID(Packet);
}
VOID
NdisCancelSendPackets(
IN NDIS_HANDLE NdisBindingHandle,
IN PVOID CancelId
)
{
PNDIS_OPEN_BLOCK Open = (PNDIS_OPEN_BLOCK)NdisBindingHandle;
KIRQL OldIrql;
ASSERT(CancelId != NULL);
//
// call Miniport's CancelSendPackets handler
//
if (!MINIPORT_TEST_FLAG(Open->MiniportHandle, fMINIPORT_DESERIALIZE))
{
//
// for serialized miniports, check our send queue and cancel the packets
//
NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Open->MiniportHandle, &OldIrql);
ndisMAbortPackets(Open->MiniportHandle, Open, CancelId);
NDIS_RELEASE_MINIPORT_SPIN_LOCK(Open->MiniportHandle, OldIrql);
}
else if (Open->CancelSendPacketsHandler != NULL)
{
Open->CancelSendPacketsHandler(Open->MiniportAdapterContext, CancelId);
}
return;
}
NDIS_STATUS
NdisQueryPendingIOCount(
IN PVOID NdisBindingHandle,
IN OUT PULONG IoCount
)
{
PNDIS_OPEN_BLOCK Open = (PNDIS_OPEN_BLOCK)NdisBindingHandle;
PNDIS_MINIPORT_BLOCK Miniport = Open->MiniportHandle;
ULONG RefCount;
NDIS_STATUS Status;
KIRQL OldIrql;
ACQUIRE_SPIN_LOCK(&Open->SpinLock, &OldIrql);
if (MINIPORT_TEST_FLAG(Open, fMINIPORT_OPEN_CLOSING))
{
RefCount = 0;
Status = NDIS_STATUS_CLOSING;
}
else
{
RefCount = Open->References - Open->AfReferences -1;
Status = NDIS_STATUS_SUCCESS;
}
*IoCount = RefCount;
RELEASE_SPIN_LOCK(&Open->SpinLock, OldIrql);
return Status;
}
UCHAR
NdisGeneratePartialCancelId(
VOID
)
{
return (UCHAR)(InterlockedIncrement(&ndisCancelId) & 0xFF);
}