/*++ 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 */