windows-nt/Source/XPSP1/NT/net/netbeui/sys/nbfpnp.c

615 lines
17 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*++
Copyright (c) 1996 Microsoft Corporation
Module Name:
nbfpnp.c
Abstract:
This module contains code which allocates and initializes all data
structures needed to activate a plug and play binding. It also informs
tdi (and thus nbf clients) of new devices and protocol addresses.
Author:
Jim McNelis (jimmcn) 1-Jan-1996
Environment:
Kernel mode
Revision History:
--*/
#include "precomp.h"
#pragma hdrstop
#ifdef RASAUTODIAL
LONG NumberOfBinds = 0;
VOID
NbfAcdBind();
VOID
NbfAcdUnbind();
#endif // RASAUTODIAL
// PnP-Power Declarations
VOID
NbfPnPEventDispatch(
IN PVOID NetPnPEvent
);
VOID
NbfPnPEventComplete(
IN PNET_PNP_EVENT NetPnPEvent,
IN NTSTATUS retVal
);
NTSTATUS
NbfPnPBindsComplete(
IN PDEVICE_CONTEXT DeviceContext,
IN PNET_PNP_EVENT NetPnPEvent
);
// PnP Handler Routines
VOID
NbfProtocolBindAdapter(
OUT PNDIS_STATUS NdisStatus,
IN NDIS_HANDLE BindContext,
IN PNDIS_STRING DeviceName,
IN PVOID SystemSpecific1,
IN PVOID SystemSpecific2
)
/*++
Routine Description:
This routine activates a transport binding and exposes the new device
and associated addresses to transport clients. This is done by reading
the registry, and performing any one time initialization of the transport
and then natching the device to bind to with the linkage information from
the registry. If we have a match for that device the bind will be
performed.
Arguments:
NdisStatus - The status of the bind.
BindContext - A context used for NdisCompleteBindAdapter() if
STATUS_PENDING is returned.
DeviceName - The name of the device that we are binding with.
SystemSpecific1 - Unused (a pointer to an NDIS_STRING to use with
NdisOpenProtocolConfiguration. This is not used by nbf
since there is no adapter specific information when
configuring the protocol via the registry. Passed to
NbfInitializeOneDeviceContext for possible future use)
SystemSpecific2 - Passed to NbfInitializeOneDeviceContext to be used
in a call to TdiRegisterNetAddress
Return Value:
None.
--*/
{
PUNICODE_STRING ExportName;
UNICODE_STRING ExportString;
ULONG i, j, k;
NTSTATUS status;
#if DBG
// We can never be called at DISPATCH or above
if (KeGetCurrentIrql() >= DISPATCH_LEVEL)
{
DbgBreakPoint();
}
#endif
IF_NBFDBG (NBF_DEBUG_PNP) {
NbfPrint1 ("ENTER NbfProtocolBindAdapter for %S\n", DeviceName->Buffer);
}
if (NbfConfig == NULL) {
//
// This allocates the CONFIG_DATA structure and returns
// it in NbfConfig.
//
status = NbfConfigureTransport(&NbfRegistryPath, &NbfConfig);
if (!NT_SUCCESS (status)) {
PANIC (" Failed to initialize transport, Nbf binding failed.\n");
*NdisStatus = NDIS_STATUS_RESOURCES;
return;
}
#if DBG
//
// Allocate the debugging tables.
//
NbfConnectionTable = (PVOID *)ExAllocatePoolWithTag(NonPagedPool,
sizeof(PVOID) *
(NbfConfig->InitConnections + 2 +
NbfConfig->InitRequests + 2 +
NbfConfig->InitUIFrames + 2 +
NbfConfig->InitPackets + 2 +
NbfConfig->InitLinks + 2 +
NbfConfig->InitAddressFiles + 2 +
NbfConfig->InitAddresses + 2),
NBF_MEM_TAG_CONNECTION_TABLE);
ASSERT (NbfConnectionTable);
NbfRequestTable = NbfConnectionTable + (NbfConfig->InitConnections + 2);
NbfUiFrameTable = NbfRequestTable + (NbfConfig->InitRequests + 2);
NbfSendPacketTable = NbfUiFrameTable + (NbfConfig->InitUIFrames + 2);
NbfLinkTable = NbfSendPacketTable + (NbfConfig->InitPackets + 2);
NbfAddressFileTable = NbfLinkTable + (NbfConfig->InitLinks + 2);
NbfAddressTable = NbfAddressFileTable +
(NbfConfig->InitAddressFiles + 2);
#endif
}
//
// Loop through all the adapters that are in the configuration
// information structure (this is the initial cache) until we
// find the one that NDIS is calling Protocol bind adapter for.
//
for (j = 0; j < NbfConfig->NumAdapters; j++ ) {
if (NdisEqualString(DeviceName, &NbfConfig->Names[j], TRUE)) {
break;
}
}
if (j < NbfConfig->NumAdapters) {
// We found the bind to export mapping in initial cache
ExportName = &NbfConfig->Names[NbfConfig->DevicesOffset + j];
}
else {
IF_NBFDBG (NBF_DEBUG_PNP) {
NbfPrint1("\nNot In Initial Cache = %08x\n\n", DeviceName->Buffer);
NbfPrint0("Bind Names in Initial Cache: \n");
for (k = 0; k < NbfConfig->NumAdapters; k++)
{
NbfPrint3("Config[%2d]: @ %08x, %75S\n",
k, &NbfConfig->Names[k],
NbfConfig->Names[k].Buffer);
}
NbfPrint0("Export Names in Initial Cache: \n");
for (k = 0; k < NbfConfig->NumAdapters; k++)
{
NbfPrint3("Config[%2d]: @ %08x, %75S\n",
k, &NbfConfig->Names[NbfConfig->DevicesOffset + k],
NbfConfig->Names[NbfConfig->DevicesOffset + k].Buffer);
}
NbfPrint0("\n\n");
}
ExportName = &ExportString;
//
// We have not found the name in the initial registry info;
// Read the registry and check if a new binding appeared...
//
*NdisStatus = NbfGetExportNameFromRegistry(&NbfRegistryPath,
DeviceName,
ExportName
);
if (!NT_SUCCESS (*NdisStatus))
{
return;
}
}
NbfInitializeOneDeviceContext(NdisStatus,
NbfDriverObject,
NbfConfig,
DeviceName,
ExportName,
SystemSpecific1,
SystemSpecific2
);
// Check if we need to de-allocate the ExportName buffer
if (ExportName == &ExportString)
{
ExFreePool(ExportName->Buffer);
}
if (*NdisStatus == NDIS_STATUS_SUCCESS) {
if (InterlockedIncrement(&NumberOfBinds) == 1) {
#ifdef RASAUTODIAL
//
// This is the first successful open.
//
#if DBG
DbgPrint("Calling NbfAcdBind()\n");
#endif
//
// Get the automatic connection driver entry points.
//
NbfAcdBind();
#endif // RASAUTODIAL
}
}
IF_NBFDBG (NBF_DEBUG_PNP) {
NbfPrint2 ("LEAVE NbfProtocolBindAdapter for %S with Status %08x\n",
DeviceName->Buffer, *NdisStatus);
}
return;
}
VOID
NbfProtocolUnbindAdapter(
OUT PNDIS_STATUS NdisStatus,
IN NDIS_HANDLE ProtocolBindContext,
IN PNDIS_HANDLE UnbindContext
)
/*++
Routine Description:
This routine deactivates a transport binding. Before it does this, it
indicates to all clients above, that the device is going away. Clients
are expected to close all open handles to the device.
Then the device is pulled out of the list of NBF devices, and all
resources reclaimed. Any connections, address files etc, that the
client has cleaned up are forcibly cleaned out at this point. Any
outstanding requests are completed (with a status). Any future
requests are automatically invalid as they use obsolete handles.
Arguments:
NdisStatus - The status of the bind.
ProtocolBindContext - the context from the openadapter call
UnbindContext - A context for async unbinds.
Return Value:
None.
--*/
{
PDEVICE_CONTEXT DeviceContext;
PTP_ADDRESS Address;
NTSTATUS status;
KIRQL oldirql;
PLIST_ENTRY p;
#if DBG
// We can never be called at DISPATCH or above
if (KeGetCurrentIrql() >= DISPATCH_LEVEL)
{
DbgBreakPoint();
}
#endif
// Get the device context for the adapter being unbound
DeviceContext = (PDEVICE_CONTEXT) ProtocolBindContext;
IF_NBFDBG (NBF_DEBUG_PNP) {
NbfPrint1 ("ENTER NbfProtocolUnbindAdapter for %S\n", DeviceContext->DeviceName);
}
// Remove creation ref if it has not already been removed,
// after telling TDI and its clients that we'r going away.
// This flag also helps prevent any more TDI indications
// of deregister addr/devobj - after the 1st one succeeds.
if (InterlockedExchange(&DeviceContext->CreateRefRemoved, TRUE) == FALSE) {
// Assume upper layers clean up by closing connections
// when we deregister all addresses and device object,
// but this can happen asynchronously, after we return
// from the (asynchronous) TdiDeregister.. calls below
// Inform TDI by deregistering the reserved netbios address
*NdisStatus = TdiDeregisterNetAddress(DeviceContext->ReservedAddressHandle);
if (!NT_SUCCESS (*NdisStatus)) {
IF_NBFDBG (NBF_DEBUG_PNP) {
NbfPrint1("No success deregistering this address,STATUS = %08X\n",*NdisStatus);
}
// this can never happen
ASSERT(FALSE);
// In case it happens, this allows a redo of the unbind
DeviceContext->CreateRefRemoved = FALSE;
return;
}
// Inform TDI (and its clients) that device is going away
*NdisStatus = TdiDeregisterDeviceObject(DeviceContext->TdiDeviceHandle);
if (!NT_SUCCESS (*NdisStatus)) {
IF_NBFDBG (NBF_DEBUG_PNP) {
NbfPrint1("No success deregistering device object,STATUS = %08X\n",*NdisStatus);
}
// This can never happen
ASSERT(FALSE);
// In case it happens, this allows a redo of the unbind
DeviceContext->CreateRefRemoved = FALSE;
return;
}
// Clear away the association with the underlying PDO object
DeviceContext->PnPContext = NULL;
// Stop all the internal timers - this'll clear timer refs
NbfStopTimerSystem(DeviceContext);
// Cleanup the Ndis Binding as it is not useful on return
// from this function - do not try to use it after this
NbfCloseNdis(DeviceContext);
// BUG BUG -- probable race condition with timer callbacks
// Do we wait for some time in case a timer func gets in ?
// Removing creation reference means that once all handles
// r closed,device will automatically be garbage-collected
NbfDereferenceDeviceContext ("Unload", DeviceContext, DCREF_CREATION);
if (InterlockedDecrement(&NumberOfBinds) == 0) {
#ifdef RASAUTODIAL
//
// This is a successful close of last adapter
//
#if DBG
DbgPrint("Calling NbfAcdUnbind()\n");
#endif
//
// Unbind from the automatic connection driver.
//
NbfAcdUnbind();
#endif // RASAUTODIAL
}
}
else {
// Ignore any duplicate Unbind Indications from NDIS layer
*NdisStatus = NDIS_STATUS_SUCCESS;
}
IF_NBFDBG (NBF_DEBUG_PNP) {
NbfPrint2 ("LEAVE NbfProtocolUnbindAdapter for %S with Status %08x\n",
DeviceContext->DeviceName, *NdisStatus);
}
return;
}
NDIS_STATUS
NbfProtocolPnPEventHandler(
IN NDIS_HANDLE ProtocolBindContext,
IN PNET_PNP_EVENT NetPnPEvent
)
/*++
Routine Description:
This routine queues a work item to invoke the actual PnP
event dispatcher. This asyncronous mechanism is to allow
NDIS to signal PnP events to other bindings in parallel.
Arguments:
ProtocolBindContext - the context from the openadapter call
NetPnPEvent - kind of PnP event and its parameters
Return Value:
STATUS_PENDING (or) an error code
--*/
{
PNET_PNP_EVENT_RESERVED NetPnPReserved;
PWORK_QUEUE_ITEM PnPWorkItem;
PnPWorkItem = (PWORK_QUEUE_ITEM)ExAllocatePoolWithTag(
NonPagedPool,
sizeof (WORK_QUEUE_ITEM),
NBF_MEM_TAG_WORK_ITEM);
if (PnPWorkItem == NULL)
{
return NDIS_STATUS_RESOURCES;
}
NetPnPReserved = (PNET_PNP_EVENT_RESERVED)NetPnPEvent->TransportReserved;
NetPnPReserved->PnPWorkItem = PnPWorkItem;
NetPnPReserved->DeviceContext = (PDEVICE_CONTEXT) ProtocolBindContext;
ExInitializeWorkItem(
PnPWorkItem,
NbfPnPEventDispatch,
NetPnPEvent);
ExQueueWorkItem(PnPWorkItem, CriticalWorkQueue);
return NDIS_STATUS_PENDING;
}
VOID
NbfPnPEventDispatch(
IN PVOID NetPnPEvent
)
/*++
Routine Description:
This routine dispatches all PnP events for the NBF transport.
The event is dispatched to the proper PnP event handler, and
the events are indicated to the transport clients using TDI.
These PnP events can trigger state changes that affect the
device behavior ( like transitioning to low power state ).
Arguments:
NetPnPEvent - kind of PnP event and its parameters
Return Value:
None
--*/
{
PNET_PNP_EVENT_RESERVED NetPnPReserved;
PDEVICE_CONTEXT DeviceContext;
UNICODE_STRING DeviceString;
PTDI_PNP_CONTEXT tdiPnPContext1;
PTDI_PNP_CONTEXT tdiPnPContext2;
NDIS_STATUS retVal;
// Retrieve the transport information block in event
NetPnPReserved = (PNET_PNP_EVENT_RESERVED)((PNET_PNP_EVENT)NetPnPEvent)->TransportReserved;
// Free the memory allocated for this work item itself
ExFreePool(NetPnPReserved->PnPWorkItem);
// Get the device context for the adapter being unbound
DeviceContext = NetPnPReserved->DeviceContext;
// In case everything goes ok, we return an NDIS_SUCCESS
retVal = STATUS_SUCCESS;
// Dispatch the PnP Event to the appropriate PnP handler
switch (((PNET_PNP_EVENT)NetPnPEvent)->NetEvent)
{
case NetEventReconfigure:
case NetEventCancelRemoveDevice:
case NetEventQueryRemoveDevice:
case NetEventQueryPower:
case NetEventSetPower:
case NetEventPnPCapabilities:
break;
case NetEventBindsComplete:
retVal = NbfPnPBindsComplete(DeviceContext, NetPnPEvent);
break;
default:
ASSERT( FALSE );
}
if ( retVal == STATUS_SUCCESS )
{
if (DeviceContext != NULL)
{
RtlInitUnicodeString(&DeviceString, DeviceContext->DeviceName);
tdiPnPContext1 = tdiPnPContext2 = NULL;
// Notify our TDI clients about this PNP event
retVal = TdiPnPPowerRequest(&DeviceString,
NetPnPEvent,
tdiPnPContext1,
tdiPnPContext2,
NbfPnPEventComplete);
}
}
if (retVal != STATUS_PENDING)
{
NdisCompletePnPEvent(retVal, (NDIS_HANDLE)DeviceContext, NetPnPEvent);
}
}
//
// PnP Complete Handler
//
VOID
NbfPnPEventComplete(
IN PNET_PNP_EVENT NetPnPEvent,
IN NTSTATUS retVal
)
{
PNET_PNP_EVENT_RESERVED NetPnPReserved;
PDEVICE_CONTEXT DeviceContext;
// Retrieve the transport information block in event
NetPnPReserved = (PNET_PNP_EVENT_RESERVED)NetPnPEvent->TransportReserved;
// Get the device context for the adapter being unbound
DeviceContext = NetPnPReserved->DeviceContext;
NdisCompletePnPEvent(retVal, (NDIS_HANDLE)DeviceContext, NetPnPEvent);
}
//
// PnP Handler Dispatches
//
NTSTATUS
NbfPnPBindsComplete(
IN PDEVICE_CONTEXT DeviceContext,
IN PNET_PNP_EVENT NetPnPEvent
)
{
NDIS_STATUS retVal;
ASSERT(DeviceContext == NULL);
retVal = TdiProviderReady(NbfProviderHandle);
ASSERT(retVal == STATUS_SUCCESS);
return retVal;
}