|
|
/*++
Copyright (c) 1989-1993 Microsoft Corporation
Module Name:
driver.c
Abstract:
This module contains the DriverEntry and other initialization code for the Netbios module of the ISN transport.
Author:
Adam Barr (adamba) 16-November-1993
Environment:
Kernel mode
Revision History:
--*/
#include "precomp.h"
#pragma hdrstop
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE,NbiBind)
#endif
//
// local functions.
//
NTSTATUS NbiPnPNotification( IN IPX_PNP_OPCODE OpCode, IN PVOID PnPData );
extern HANDLE TdiProviderHandle; BOOLEAN fNbiTdiProviderReady = FALSE;
#ifdef BIND_FIX
extern PDRIVER_OBJECT NbiDriverObject; extern UNICODE_STRING NbiRegistryPath; extern PEPROCESS NbiFspProcess;
DEFINE_LOCK_STRUCTURE(NbiTdiRequestInterlock); ULONG NbiBindState = 0; extern UNICODE_STRING NbiBindString; BOOLEAN fNbiTdiRequestQueued = FALSE;
typedef struct{ WORK_QUEUE_ITEM WorkItem; LIST_ENTRY NbiRequestLinkage; ULONG Data; } NBI_TDI_REQUEST_CONTEXT;
LIST_ENTRY NbiTdiRequestList;
#ifdef RASAUTODIAL
VOID NbiAcdBind();
VOID NbiAcdUnbind(); #endif
#endif // BIND_FIX
NTSTATUS NbiBind( IN PDEVICE Device, IN PCONFIG Config )
/*++
Routine Description:
This routine binds the Netbios module of ISN to the IPX module, which provides the NDIS binding services.
Arguments:
Device - Pointer to the Netbios device.
Config - Pointer to the configuration information.
Return Value:
The function value is the final status from the initialization operation.
--*/
{ NTSTATUS Status; IO_STATUS_BLOCK IoStatusBlock; OBJECT_ATTRIBUTES ObjectAttributes; /* union {
IPX_INTERNAL_BIND_INPUT Input; IPX_INTERNAL_BIND_OUTPUT Output; } Bind; */ InitializeObjectAttributes( &ObjectAttributes, &Config->BindName, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
Status = ZwCreateFile( &Device->BindHandle, SYNCHRONIZE | GENERIC_READ, &ObjectAttributes, &IoStatusBlock, NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_OPEN, FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0L);
if (!NT_SUCCESS(Status)) {
NB_DEBUG (BIND, ("Could not open IPX (%ws) %lx\n", Config->BindName.Buffer, Status)); NbiWriteGeneralErrorLog( Device, EVENT_TRANSPORT_ADAPTER_NOT_FOUND, 1, Status, Config->BindName.Buffer, 0, NULL); return Status; }
//
// Fill in our bind data.
//
Device->BindInput.Version = ISN_VERSION; Device->BindInput.Identifier = IDENTIFIER_NB; Device->BindInput.BroadcastEnable = TRUE; Device->BindInput.LookaheadRequired = 192; Device->BindInput.ProtocolOptions = 0; Device->BindInput.ReceiveHandler = NbiReceive; Device->BindInput.ReceiveCompleteHandler = NbiReceiveComplete; Device->BindInput.StatusHandler = NbiStatus; Device->BindInput.SendCompleteHandler = NbiSendComplete; Device->BindInput.TransferDataCompleteHandler = NbiTransferDataComplete; Device->BindInput.FindRouteCompleteHandler = NbiFindRouteComplete; Device->BindInput.LineUpHandler = NbiLineUp; Device->BindInput.LineDownHandler = NbiLineDown; Device->BindInput.ScheduleRouteHandler = NULL; Device->BindInput.PnPHandler = NbiPnPNotification;
Status = ZwDeviceIoControlFile( Device->BindHandle, // HANDLE to File
NULL, // HANDLE to Event
NULL, // ApcRoutine
NULL, // ApcContext
&IoStatusBlock, // IO_STATUS_BLOCK
IOCTL_IPX_INTERNAL_BIND, // IoControlCode
&Device->BindInput, // Input Buffer
sizeof(Device->BindInput), // Input Buffer Length
&Device->Bind, // OutputBuffer
sizeof(Device->Bind)); // OutputBufferLength
//
// We open synchronous, so this shouldn't happen.
//
CTEAssert (Status != STATUS_PENDING);
//
// Save the bind data.
//
if (Status == STATUS_SUCCESS) {
NB_DEBUG2 (BIND, ("Successfully bound to IPX (%ws)\n", Config->BindName.Buffer)); } else {
NB_DEBUG (BIND, ("Could not bind to IPX (%ws) %lx\n", Config->BindName.Buffer, Status)); NbiWriteGeneralErrorLog( Device, EVENT_TRANSPORT_BINDING_FAILED, 1, Status, Config->BindName.Buffer, 0, NULL); ZwClose(Device->BindHandle); }
return Status;
} /* NbiBind */
VOID NbiUnbind( IN PDEVICE Device )
/*++
Routine Description:
This function closes the binding between the Netbios over IPX module and the IPX module previously established by NbiBind.
Arguments:
Device - The netbios device object.
Return Value:
None.
--*/
{ ZwClose (Device->BindHandle); } /* NbiUnbind */
#ifdef BIND_FIX
NTSTATUS NbiBindToIpx( ) { NTSTATUS status; PDEVICE Device; PIPX_HEADER IpxHeader; CTELockHandle LockHandle; WCHAR wcNwlnkNbProviderName[60] = L"\\Device\\NwlnkNb"; UNICODE_STRING ucNwlnkNbProviderName; PCONFIG Config = NULL;
//
// This allocates the CONFIG structure and returns
// it in Config.
//
status = NbiGetConfiguration(NbiDriverObject, &NbiRegistryPath, &Config); if (!NT_SUCCESS (status)) {
//
// If it failed it logged an error.
//
PANIC (" Failed to initialize transport, ISN Netbios initialization failed.\n"); return status; }
//
// Create the device object which exports our name.
//
status = NbiCreateDevice (NbiDriverObject, &Config->DeviceName, &Device); if (!NT_SUCCESS (status)) { NbiWriteGeneralErrorLog( (PVOID)NbiDriverObject, EVENT_IPX_CREATE_DEVICE, 801, status, NULL, 0, NULL);
NbiFreeConfiguration(Config); return status; }
NbiDevice = Device;
//
// Initialize the global pool interlock
//
CTEInitLock (&NbiGlobalPoolInterlock);
//
// Save the relevant configuration parameters.
//
Device->AckDelayTime = (Config->Parameters[CONFIG_ACK_DELAY_TIME] / SHORT_TIMER_DELTA) + 1; Device->AckWindow = Config->Parameters[CONFIG_ACK_WINDOW]; Device->AckWindowThreshold = Config->Parameters[CONFIG_ACK_WINDOW_THRESHOLD]; Device->EnablePiggyBackAck = Config->Parameters[CONFIG_ENABLE_PIGGYBACK_ACK]; Device->Extensions = Config->Parameters[CONFIG_EXTENSIONS]; Device->RcvWindowMax = Config->Parameters[CONFIG_RCV_WINDOW_MAX]; Device->BroadcastCount = Config->Parameters[CONFIG_BROADCAST_COUNT]; Device->BroadcastTimeout = Config->Parameters[CONFIG_BROADCAST_TIMEOUT]; Device->ConnectionCount = Config->Parameters[CONFIG_CONNECTION_COUNT]; Device->ConnectionTimeout = Config->Parameters[CONFIG_CONNECTION_TIMEOUT] * 500; Device->InitPackets = Config->Parameters[CONFIG_INIT_PACKETS]; Device->MaxPackets = Config->Parameters[CONFIG_MAX_PACKETS]; Device->InitialRetransmissionTime = Config->Parameters[CONFIG_INIT_RETRANSMIT_TIME]; Device->Internet = Config->Parameters[CONFIG_INTERNET]; Device->KeepAliveCount = Config->Parameters[CONFIG_KEEP_ALIVE_COUNT]; Device->KeepAliveTimeout = Config->Parameters[CONFIG_KEEP_ALIVE_TIMEOUT]; Device->RetransmitMax = Config->Parameters[CONFIG_RETRANSMIT_MAX]; Device->RouterMtu = Config->Parameters[CONFIG_ROUTER_MTU]; Device->MaxReceiveBuffers = 20; // Make it configurable?
Device->NameCache = NULL; // MP bug: IPX tries to Flush it before it's initialized!
Device->FindNameTimeout = ((Config->Parameters[CONFIG_BROADCAST_TIMEOUT]) + (FIND_NAME_GRANULARITY/2)) / FIND_NAME_GRANULARITY; //
// Initialize the BindReady Event to False
//
KeInitializeEvent (&Device->BindReadyEvent, NotificationEvent, FALSE);
//
// Create Hash Table to store netbios cache entries
// For server create a big table, for workstation a small one
//
if (MmIsThisAnNtAsSystem()) { status = CreateNetbiosCacheTable( &Device->NameCache, NB_NETBIOS_CACHE_TABLE_LARGE ); } else { status = CreateNetbiosCacheTable( &Device->NameCache, NB_NETBIOS_CACHE_TABLE_SMALL ); }
if (!NT_SUCCESS (status)) { //
// If it failed it logged an error.
//
NbiFreeConfiguration(Config); NbiDereferenceDevice (Device, DREF_LOADED); return status; }
// Initialize the timer system. This should be done before
// binding to ipx because we should have timers intialized
// before ipx calls our pnp indications.
NbiInitializeTimers (Device);
//
// Register us as a provider with Tdi
//
RtlInitUnicodeString(&ucNwlnkNbProviderName, wcNwlnkNbProviderName); ucNwlnkNbProviderName.MaximumLength = sizeof (wcNwlnkNbProviderName); if (!NT_SUCCESS (TdiRegisterProvider (&ucNwlnkNbProviderName, &TdiProviderHandle))) { TdiProviderHandle = NULL; DbgPrint("Nbi.DriverEntry: FAILed to Register NwlnkNb as Provider!\n"); }
//
// Now bind to IPX via the internal interface.
//
status = NbiBind (Device, Config); if (!NT_SUCCESS (status)) {
//
// If it failed it logged an error.
//
if (TdiProviderHandle) { TdiDeregisterProvider (TdiProviderHandle); } NbiFreeConfiguration(Config); NbiDereferenceDevice (Device, DREF_LOADED); return status; }
#ifdef RSRC_TIMEOUT_DBG
NbiInitDeathPacket(); // NbiGlobalMaxResTimeout.QuadPart = 50; // 1*1000*10000;
NbiGlobalMaxResTimeout.QuadPart = 20*60*1000; NbiGlobalMaxResTimeout.QuadPart *= 10000; #endif // RSRC_TIMEOUT_DBG
NB_GET_LOCK (&Device->Lock, &LockHandle);
//
// Allocate our initial connectionless packet pool.
//
NbiAllocateSendPool (Device);
//
// Allocate our initial receive packet pool.
//
NbiAllocateReceivePool (Device);
//
// Allocate our initial receive buffer pool.
//
//
if ( DEVICE_STATE_CLOSED == Device->State ) { Device->State = DEVICE_STATE_LOADED; }
NB_FREE_LOCK (&Device->Lock, LockHandle);
//
// Fill in the default connnectionless header.
//
IpxHeader = &Device->ConnectionlessHeader; IpxHeader->CheckSum = 0xffff; IpxHeader->PacketLength[0] = 0; IpxHeader->PacketLength[1] = 0; IpxHeader->TransportControl = 0; IpxHeader->PacketType = 0; *(UNALIGNED ULONG *)(IpxHeader->DestinationNetwork) = 0; RtlCopyMemory(IpxHeader->DestinationNode, BroadcastAddress, 6); IpxHeader->DestinationSocket = NB_SOCKET; IpxHeader->SourceSocket = NB_SOCKET;
#ifdef RASAUTODIAL
//
// Get the automatic connection
// driver entry points.
//
NbiAcdBind(); #endif
NbiFreeConfiguration(Config);
NbiBindState |= NBI_BOUND_TO_IPX; Device->DeviceObject.Flags &= ~DO_DEVICE_INITIALIZING;
KeSetEvent(&Device->BindReadyEvent, 0, FALSE);
return STATUS_SUCCESS; }
VOID NbiUnbindFromIpx( )
/*++
Routine Description:
This unbinds from any NDIS drivers that are open and frees all resources associated with the transport. The I/O system will not call us until nobody above has Netbios open.
Arguments:
Return Value:
None.
--*/
{ PDEVICE Device = NbiDevice;
NbiBindState &= (~NBI_BOUND_TO_IPX);
#ifdef RASAUTODIAL
//
// Unbind from the
// automatic connection driver.
//
NbiAcdUnbind(); #endif
Device->State = DEVICE_STATE_STOPPING;
//
// Cancel the long timer.
//
if (CTEStopTimer (&Device->LongTimer)) { NbiDereferenceDevice (Device, DREF_LONG_TIMER); }
//
// Unbind from the IPX driver.
//
NbiUnbind (Device);
//
// This event will get set when the reference count
// drops to 0.
//
KeInitializeEvent (&Device->UnloadEvent, NotificationEvent, FALSE); Device->UnloadWaiting = TRUE;
//
// Remove the reference for us being loaded.
//
NbiDereferenceDevice (Device, DREF_LOADED);
//
// Wait for our count to drop to zero.
//
KeWaitForSingleObject (&Device->UnloadEvent, Executive, KernelMode, TRUE, (PLARGE_INTEGER)NULL);
//
// Free the cache of netbios names.
//
DestroyNetbiosCacheTable (Device->NameCache);
//
// Do the cleanup that has to happen at IRQL 0.
//
ExDeleteResourceLite (&Device->AddressResource); IoDeleteDevice ((PDEVICE_OBJECT)Device); }
UCHAR AdapterName[NB_NETBIOS_NAME_SIZE];
VOID NbiNotifyTdiClients( IN PWORK_QUEUE_ITEM WorkItem ) { NTSTATUS Status; TA_NETBIOS_ADDRESS PermAddress; HANDLE TdiRegistrationHandle, NetAddressRegistrationHandle; CTELockHandle LockHandle; PLIST_ENTRY p; PDEVICE Device = NbiDevice; NBI_TDI_REQUEST_CONTEXT *pNbiTdiRequest = (NBI_TDI_REQUEST_CONTEXT *) WorkItem; ULONG RequestFlag; BOOLEAN fRegisterWithTdi, fDeregisterWithTdi;
do { RequestFlag = pNbiTdiRequest->Data; fRegisterWithTdi = fDeregisterWithTdi = FALSE;
switch (RequestFlag) { case NBI_IPX_REGISTER: { if (NbiBindState & TDI_HAS_NOTIFIED) { fRegisterWithTdi = TRUE; } NbiBindState |= IPX_HAS_DEVICES;
break; } case NBI_TDI_REGISTER: { if (NbiBindState & IPX_HAS_DEVICES) { fRegisterWithTdi = TRUE; } NbiBindState |= TDI_HAS_NOTIFIED;
break; }
case NBI_TDI_DEREGISTER: { fDeregisterWithTdi = TRUE; NbiBindState &= (~TDI_HAS_NOTIFIED);
break; } case NBI_IPX_DEREGISTER: { fDeregisterWithTdi = TRUE; NbiBindState &= (~IPX_HAS_DEVICES);
break; } default: { break; } }
if (fRegisterWithTdi) { NB_GET_LOCK (&Device->Lock, &LockHandle); Device->State = DEVICE_STATE_OPEN; NB_FREE_LOCK (&Device->Lock, LockHandle);
if (!(Device->TdiRegistrationHandle)) { Status = TdiRegisterDeviceObject (&Device->DeviceString, &Device->TdiRegistrationHandle); if (!NT_SUCCESS(Status)) { Device->TdiRegistrationHandle = NULL; DbgPrint ("Nbi.NbiNotifyTdiClients: ERROR -- TdiRegisterDeviceObject = <%x>\n", Status); } }
//
// If there is already an address Registered, Deregister it (since Adapter address could change)
//
if (Device->NetAddressRegistrationHandle) { DbgPrint ("Nbi!NbiNotifyTdiClients[REGISTER]: NetAddress exists! Calling TdiDeregisterNetAddress\n"); Status = TdiDeregisterNetAddress (Device->NetAddressRegistrationHandle); Device->NetAddressRegistrationHandle = NULL; } //
// Register the permanent NetAddress!
//
PermAddress.Address[0].AddressLength = sizeof(TDI_ADDRESS_NETBIOS); PermAddress.Address[0].AddressType = TDI_ADDRESS_TYPE_NETBIOS; PermAddress.Address[0].Address[0].NetbiosNameType = TDI_ADDRESS_NETBIOS_TYPE_UNIQUE; CTEMemCopy (PermAddress.Address[0].Address[0].NetbiosName, AdapterName, NB_NETBIOS_NAME_SIZE);
if (!NT_SUCCESS(Status = TdiRegisterNetAddress((PTA_ADDRESS) PermAddress.Address, &Device->DeviceString, NULL, &Device->NetAddressRegistrationHandle)) ) { Device->NetAddressRegistrationHandle = NULL; DbgPrint ("Nbi.NbiNotifyTdiClients[REGISTER]: ERROR -- TdiRegisterNetAddress=<%x>\n",Status); } } else if (fDeregisterWithTdi) { NB_GET_LOCK (&Device->Lock, &LockHandle);
TdiRegistrationHandle = Device->TdiRegistrationHandle; Device->TdiRegistrationHandle = NULL; NetAddressRegistrationHandle = Device->NetAddressRegistrationHandle; Device->NetAddressRegistrationHandle = NULL;
Device->State = DEVICE_STATE_LOADED;
NB_FREE_LOCK (&Device->Lock, LockHandle);
//
// DeRegister the NetAddress!
//
if (NetAddressRegistrationHandle) { if (!NT_SUCCESS (Status = TdiDeregisterNetAddress (NetAddressRegistrationHandle))) { DbgPrint ("NwlnkNb.NbiPnPNotification: ERROR -- TdiDeregisterNetAddress=<%x>\n", Status); } } //
// Deregister the Device
//
if (TdiRegistrationHandle) { if (!NT_SUCCESS (Status = TdiDeregisterDeviceObject(TdiRegistrationHandle))) { DbgPrint ("NwlnkNb.NbiPnPNotification: ERROR -- TdiDeregisterDeviceObject=<%x>\n",Status); } } }
NbiFreeMemory (pNbiTdiRequest, sizeof(NBI_TDI_REQUEST_CONTEXT), MEMORY_WORK_ITEM, "TdiRequest");
CTEGetLock (&NbiTdiRequestInterlock, &LockHandle);
if (IsListEmpty(&NbiTdiRequestList)) { fNbiTdiRequestQueued = FALSE; CTEFreeLock (&NbiTdiRequestInterlock, LockHandle); break; }
p = RemoveHeadList (&NbiTdiRequestList); CTEFreeLock (&NbiTdiRequestInterlock, LockHandle);
pNbiTdiRequest = CONTAINING_RECORD (p, NBI_TDI_REQUEST_CONTEXT, NbiRequestLinkage); } while (1); }
NTSTATUS NbiQueueTdiRequest( enum eTDI_ACTION RequestFlag ) { NBI_TDI_REQUEST_CONTEXT *pNbiTdiRequest; CTELockHandle LockHandle; NTSTATUS Status = STATUS_SUCCESS;
CTEGetLock (&NbiTdiRequestInterlock, &LockHandle);
if (pNbiTdiRequest = NbiAllocateMemory (sizeof(NBI_TDI_REQUEST_CONTEXT), MEMORY_WORK_ITEM, "TdiRequest")) { pNbiTdiRequest->Data = RequestFlag;
if (fNbiTdiRequestQueued) { InsertTailList (&NbiTdiRequestList, &pNbiTdiRequest->NbiRequestLinkage); } else { fNbiTdiRequestQueued = TRUE; ExInitializeWorkItem (&pNbiTdiRequest->WorkItem, NbiNotifyTdiClients, (PVOID)pNbiTdiRequest); ExQueueWorkItem (&pNbiTdiRequest->WorkItem, DelayedWorkQueue); } } else { NB_DEBUG( DEVICE, ("Cannt schdule work item to Notify Tdi clients\n")); Status = STATUS_INSUFFICIENT_RESOURCES; }
CTEFreeLock (&NbiTdiRequestInterlock, LockHandle);
return (Status); }
VOID TdiBindHandler( TDI_PNP_OPCODE PnPOpCode, PUNICODE_STRING pDeviceName, PWSTR MultiSZBindList) { NTSTATUS Status; BOOLEAN Attached;
if ((!pDeviceName) || (RtlCompareUnicodeString(pDeviceName, &NbiBindString, TRUE))) { return; }
switch (PnPOpCode) { case (TDI_PNP_OP_ADD): { if (!(NbiBindState & NBI_BOUND_TO_IPX)) { if (PsGetCurrentProcess() != NbiFspProcess) { KeAttachProcess((PRKPROCESS)NbiFspProcess); Attached = TRUE; } else { Attached = FALSE; }
Status = NbiBindToIpx();
if (Attached) { KeDetachProcess(); } } NbiQueueTdiRequest ((ULONG) NBI_TDI_REGISTER);
break; }
case (TDI_PNP_OP_DEL): { if (NbiBindState & NBI_BOUND_TO_IPX) { NbiQueueTdiRequest ((ULONG) NBI_TDI_DEREGISTER); }
break; }
default: { break; } } } #endif // BIND_FIX
VOID NbiStatus( IN USHORT NicId, IN NDIS_STATUS GeneralStatus, IN PVOID StatusBuffer, IN UINT StatusBufferLength )
/*++
Routine Description:
This function receives a status indication from IPX, corresponding to a status indication from an underlying NDIS driver.
Arguments:
NicId - The NIC ID of the underlying adapter.
GeneralStatus - The general status code.
StatusBuffer - The status buffer.
StatusBufferLength - The length of the status buffer.
Return Value:
None.
--*/
{
} /* NbiStatus */
VOID NbiLineUp( IN USHORT NicId, IN PIPX_LINE_INFO LineInfo, IN NDIS_MEDIUM DeviceType, IN PVOID ConfigurationData )
/*++
Routine Description:
This function receives line up indications from IPX, indicating that the specified adapter is now up with the characteristics shown.
Arguments:
NicId - The NIC ID of the underlying adapter.
LineInfo - Information about the adapter's medium.
DeviceType - The type of the adapter.
ConfigurationData - IPX-specific configuration data.
Return Value:
None.
--*/
{ PIPXCP_CONFIGURATION Configuration = (PIPXCP_CONFIGURATION)ConfigurationData; } /* NbiLineUp */
VOID NbiLineDown( IN USHORT NicId, IN ULONG_PTR FwdAdapterContext )
/*++
Routine Description:
This function receives line down indications from IPX, indicating that the specified adapter is no longer up.
Arguments:
NicId - The NIC ID of the underlying adapter.
Return Value:
None.
--*/
{ } /* NbiLineDown */
NTSTATUS NbiPnPNotification( IN IPX_PNP_OPCODE OpCode, IN PVOID PnPData )
/*++
Routine Description:
This function receives the notification about PnP events from IPX.
Arguments:
OpCode - Type of the PnP event
PnPData - Data associated with this event.
Return Value:
None.
--*/
{
CTELockHandle LockHandle; PADAPTER_ADDRESS AdapterAddress; USHORT MaximumNicId = 0; PDEVICE Device = NbiDevice; NTSTATUS Status = STATUS_SUCCESS; PNET_PNP_EVENT NetPnpEvent = (PNET_PNP_EVENT) PnPData; IPX_PNP_INFO UNALIGNED *PnPInfo = (IPX_PNP_INFO UNALIGNED *)PnPData;
NB_DEBUG2( DEVICE, ("Received a pnp notification, opcode %d\n",OpCode ));
#ifdef BIND_FIX
if (!(NbiBindState & NBI_BOUND_TO_IPX)) { KeWaitForSingleObject (&Device->BindReadyEvent, // Object to wait on.
Executive, // Reason for waiting
KernelMode, // Processor mode
FALSE, // Alertable
NULL); // Timeout
} #endif // BIND_FIX
switch( OpCode ) { case IPX_PNP_ADD_DEVICE : { BOOLEAN ReallocReceiveBuffers = FALSE;
NB_GET_LOCK( &Device->Lock, &LockHandle );
if ( PnPInfo->NewReservedAddress ) {
*(UNALIGNED ULONG *)Device->Bind.Network = PnPInfo->NetworkAddress; RtlCopyMemory( Device->Bind.Node, PnPInfo->NodeAddress, 6);
*(UNALIGNED ULONG *)Device->ConnectionlessHeader.SourceNetwork = *(UNALIGNED ULONG *)Device->Bind.Network; RtlCopyMemory(Device->ConnectionlessHeader.SourceNode, Device->Bind.Node, 6); }
if ( PnPInfo->FirstORLastDevice ) { // Comment out the ASSERTS until Ting can check in his fix!
// CTEAssert( PnPInfo->NewReservedAddress );
// CTEAssert( Device->State != DEVICE_STATE_OPEN );
// CTEAssert( !Device->MaximumNicId );
//
// we must do this while we still have the device lock.
//
if ( !Device->LongTimerRunning ) { Device->LongTimerRunning = TRUE; NbiReferenceDevice (Device, DREF_LONG_TIMER);
CTEStartTimer( &Device->LongTimer, LONG_TIMER_DELTA, NbiLongTimeout, (PVOID)Device); }
Device->Bind.LineInfo.MaximumSendSize = PnPInfo->LineInfo.MaximumSendSize; Device->Bind.LineInfo.MaximumPacketSize = PnPInfo->LineInfo.MaximumSendSize; ReallocReceiveBuffers = TRUE; } else { if ( PnPInfo->LineInfo.MaximumPacketSize > Device->CurMaxReceiveBufferSize ) { Device->Bind.LineInfo.MaximumPacketSize = PnPInfo->LineInfo.MaximumSendSize; ReallocReceiveBuffers = TRUE; } //
// MaxSendSize could become smaller.
//
Device->Bind.LineInfo.MaximumSendSize = PnPInfo->LineInfo.MaximumSendSize; }
Device->MaximumNicId++;
//
//
RtlZeroMemory(AdapterName, 10); RtlCopyMemory(&AdapterName[10], PnPInfo->NodeAddress, 6); AdapterAddress = NbiCreateAdapterAddress (PnPInfo->NodeAddress);
//
// And finally remove all the failed cache entries since we might
// find those routes using this new adapter
//
FlushFailedNetbiosCacheEntries(Device->NameCache);
NB_FREE_LOCK( &Device->Lock, LockHandle );
if ( ReallocReceiveBuffers ) { PWORK_QUEUE_ITEM WorkItem;
WorkItem = NbiAllocateMemory( sizeof(WORK_QUEUE_ITEM), MEMORY_WORK_ITEM, "Alloc Rcv Buffer work item");
if ( WorkItem ) { ExInitializeWorkItem( WorkItem, NbiReAllocateReceiveBufferPool, (PVOID) WorkItem ); ExQueueWorkItem( WorkItem, DelayedWorkQueue ); } else { NB_DEBUG( DEVICE, ("Cannt schdule work item to realloc receive buffer pool\n")); } }
//
// Notify the TDI clients about the device creation
//
if (PnPInfo->FirstORLastDevice) { NbiQueueTdiRequest ((ULONG) NBI_IPX_REGISTER);
if ((TdiProviderHandle) && (!fNbiTdiProviderReady)) { fNbiTdiProviderReady = TRUE; TdiProviderReady (TdiProviderHandle); } }
break; } case IPX_PNP_DELETE_DEVICE : {
PLIST_ENTRY p; PNETBIOS_CACHE CacheName; USHORT i,j,NetworksRemoved;
NB_GET_LOCK( &Device->Lock, &LockHandle );
CTEAssert (Device->MaximumNicId); Device->MaximumNicId--;
//
// MaximumSendSize could change if the card with the smallest send size just
// got removed. MaximumPacketSize could only become smaller and we ignore that
// since we dont need to(want to) realloc ReceiveBuffers.
//
Device->Bind.LineInfo.MaximumSendSize = PnPInfo->LineInfo.MaximumSendSize;
//
// Flush all the cache entries that are using this NicId in the local
// target.
//
RemoveInvalidRoutesFromNetbiosCacheTable( Device->NameCache, &PnPInfo->NicHandle );
NbiDestroyAdapterAddress (NULL, PnPInfo->NodeAddress);
//
// inform tdi clients about the device deletion
//
if (PnPInfo->FirstORLastDevice) { Device->State = DEVICE_STATE_LOADED; // Set this now even though it will be set again later
NB_FREE_LOCK (&Device->Lock, LockHandle);
NbiQueueTdiRequest ((ULONG) NBI_IPX_DEREGISTER); } else { NB_FREE_LOCK (&Device->Lock, LockHandle); }
break; }
case IPX_PNP_ADDRESS_CHANGE: { PADDRESS Address; BOOLEAN ReservedNameClosing = FALSE;
CTEAssert( PnPInfo->NewReservedAddress );
NB_GET_LOCK( &Device->Lock, &LockHandle ); *(UNALIGNED ULONG *)Device->Bind.Network = PnPInfo->NetworkAddress; RtlCopyMemory( Device->Bind.Node, PnPInfo->NodeAddress, 6);
*(UNALIGNED ULONG *)Device->ConnectionlessHeader.SourceNetwork = *(UNALIGNED ULONG *)Device->Bind.Network; RtlCopyMemory(Device->ConnectionlessHeader.SourceNode, Device->Bind.Node, 6);
NB_FREE_LOCK( &Device->Lock, LockHandle );
break; } case IPX_PNP_TRANSLATE_DEVICE: break; case IPX_PNP_TRANSLATE_ADDRESS: break;
case IPX_PNP_QUERY_POWER: case IPX_PNP_QUERY_REMOVE:
//
// IPX wants to know if we can power off or remove an apapter.
// We DONT look if there are any open connections before deciding.
// We merely ask our TDI Clients, if they are OK with it, so are we.
//
// Via TDI to our Clients.
Status = TdiPnPPowerRequest( &Device->DeviceString, NetPnpEvent, NULL, NULL, Device->Bind.PnPCompleteHandler ); break;
case IPX_PNP_SET_POWER: case IPX_PNP_CANCEL_REMOVE:
//
// IPX is telling us that the power is going off.
// We tell our TDI Clients about it.
//
Status = TdiPnPPowerRequest( &Device->DeviceString, NetPnpEvent, NULL, NULL, Device->Bind.PnPCompleteHandler );
break;
default: CTEAssert( FALSE ); }
return Status;
} /* NbiPnPNotification */
|