diff options
Diffstat (limited to 'private/ntos/nbt/nt/ntutil.c')
-rw-r--r-- | private/ntos/nbt/nt/ntutil.c | 2103 |
1 files changed, 2103 insertions, 0 deletions
diff --git a/private/ntos/nbt/nt/ntutil.c b/private/ntos/nbt/nt/ntutil.c new file mode 100644 index 000000000..4a5f200b8 --- /dev/null +++ b/private/ntos/nbt/nt/ntutil.c @@ -0,0 +1,2103 @@ +/*++ + +Copyright (c) 1989-1993 Microsoft Corporation + +Module Name: + + Ntutil.c + +Abstract: + + This file contains a number of utility and support routines that are + NT specific. + + +Author: + + Jim Stewart (Jimst) 10-2-92 + +Revision History: + +--*/ + +#include "nbtprocs.h" +#include "stdio.h" +#include <ntddtcp.h> +#undef uint // undef to avoid a warning where tdiinfo.h redefines it +#include <tdiinfo.h> +#include <ipinfo.h> + +NTSTATUS +CreateControlObject( + tNBTCONFIG *pConfig); + +NTSTATUS +IfNotAnyLowerConnections( + IN tDEVICECONTEXT *pDeviceContext + ); +NTSTATUS +NbtProcessDhcpRequest( + tDEVICECONTEXT *pDeviceContext); +VOID +GetExtendedAttributes( + tDEVICECONTEXT *pDeviceContext + ); + +PSTRM_PROCESSOR_LOG LogAlloc ; +PSTRM_PROCESSOR_LOG LogFree ; + + +//******************* Pageable Routine Declarations **************** +#ifdef ALLOC_PRAGMA +#ifdef _PNP_POWER +#pragma CTEMakePageable(PAGE, NbtCreateDeviceObject) +#else // _PNP_POWER +#pragma CTEMakePageable(INIT, NbtCreateDeviceObject) +#endif // _PNP_POWER +#pragma CTEMakePageable(PAGE, CreateControlObject) +#pragma CTEMakePageable(PAGE, NbtInitConnQ) +#pragma CTEMakePageable(PAGE, NbtProcessDhcpRequest) +#pragma CTEMakePageable(PAGE, NbtCreateAddressObjects) +#pragma CTEMakePageable(PAGE, GetExtendedAttributes) +#pragma CTEMakePageable(PAGE, ConvertToUlong) +#pragma CTEMakePageable(PAGE, NbtInitMdlQ) +#pragma CTEMakePageable(PAGE, NTZwCloseFile) +#pragma CTEMakePageable(PAGE, NTReReadRegistry) +#pragma CTEMakePageable(PAGE, SaveClientSecurity) +#endif +//******************* Pageable Routine Declarations **************** + +ulong +GetUnique32BitValue( + void + ) + +/*++ + +Routine Description: + + Returns a reasonably unique 32-bit number based on the system clock. + In NT, we take the current system time, convert it to milliseconds, + and return the low 32 bits. + +Arguments: + + None. + +Return Value: + + A reasonably unique 32-bit value. + +--*/ + +{ + LARGE_INTEGER ntTime, tmpTime; + + KeQuerySystemTime(&ntTime); + + tmpTime = CTEConvert100nsToMilliseconds(ntTime); + + return(tmpTime.LowPart); +} + +//---------------------------------------------------------------------------- +NTSTATUS +NbtCreateDeviceObject( + PDRIVER_OBJECT DriverObject, + tNBTCONFIG *pConfig, + PUNICODE_STRING pucBindName, + PUNICODE_STRING pucExportName, + tADDRARRAY *pAddrs, + PUNICODE_STRING pucRegistryPath, +#ifndef _IO_DELETE_DEVICE_SUPPORTED + BOOLEAN fReuse, +#endif + tDEVICECONTEXT **ppDeviceContext + ) + +/*++ + +Routine Description: + + This routine initializes a Driver Object from the device object passed + in and the name of the driver object passed in. After the Driver Object + has been created, clients can "Open" the driver by that name. + +Arguments: + + +Return Value: + + status - the outcome + +--*/ + +{ + + NTSTATUS status; + PDEVICE_OBJECT DeviceObject = NULL; + tDEVICECONTEXT *pDeviceContext; + ULONG LinkOffset; + ULONG ulIpAddress; + ULONG ulSubnetMask; +#ifdef _PNP_POWER + PUCHAR Buffer; +#endif // _PNP_POWER +#ifndef _IO_DELETE_DEVICE_SUPPORTED + BOOLEAN fIsItReused=FALSE; +#endif + CTELockHandle OldIrq1; + + CTEPagedCode(); + +#ifndef _IO_DELETE_DEVICE_SUPPORTED + // + // If we can re-use some of the earlier devices, so be it.... + // This will go away when base supports IoDeleteDevice properly. + // + if (fReuse) { + LIST_ENTRY *pEntry; + + CTESpinLock(&NbtConfig, OldIrq1); + if (!IsListEmpty(&NbtConfig.FreeDevCtx)) { + pEntry = RemoveHeadList( &NbtConfig.FreeDevCtx); + + DeviceObject = (PDEVICE_OBJECT) CONTAINING_RECORD( pEntry, + tDEVICECONTEXT, + FreeLinkage); + + KdPrint(("Re-using device @ %lx, bind: %ws\n", DeviceObject, ((tDEVICECONTEXT *)DeviceObject)->BindName.Buffer)); + + // + // Re-use the name and update the value returned to the user - we shd decrement + // the global ptr too, but we might hit some other (valid) device the next time on. + // + pucBindName->MaximumLength = ((tDEVICECONTEXT *)DeviceObject)->BindName.MaximumLength; + RtlCopyUnicodeString(pucBindName, &((tDEVICECONTEXT *)DeviceObject)->BindName); + + pucExportName->MaximumLength = ((tDEVICECONTEXT *)DeviceObject)->ExportName.MaximumLength; + RtlCopyUnicodeString(pucExportName, &((tDEVICECONTEXT *)DeviceObject)->ExportName); + CTEMemFree( pDeviceContext->ExportName.Buffer ); + + CTESpinFree(&NbtConfig, OldIrq1); + + fIsItReused = TRUE; +#ifdef _PNP_POWER + Buffer = NbtAllocMem(pucExportName->MaximumLength+pucBindName->MaximumLength,NBT_TAG('w')); + + if ( Buffer == NULL ) + { + return STATUS_INSUFFICIENT_RESOURCES ; + } +#endif // _PNP_POWER + goto Reuse; + } + + fIsItReused = FALSE; + CTESpinFree(&NbtConfig, OldIrq1); + } +#endif + +#ifdef _PNP_POWER + Buffer = NbtAllocMem(pucExportName->MaximumLength+pucBindName->MaximumLength,NBT_TAG('w')); + + if ( Buffer == NULL ) + { + return STATUS_INSUFFICIENT_RESOURCES ; + } +#endif // _PNP_POWER + + + status = IoCreateDevice( + DriverObject, // Driver Object + sizeof(tDEVICECONTEXT) - sizeof(DRIVER_OBJECT), //Device Extension + pucExportName, // Device Name + FILE_DEVICE_NBT, // Device type 0x32 for now... + 0, //Device Characteristics + FALSE, //Exclusive + &DeviceObject ); + + if (!NT_SUCCESS( status )) + { + KdPrint(("Failed to create the Export Device, status=%X\n",status)); + *ppDeviceContext = NULL; +#ifdef _PNP_POWER + CTEMemFree ( Buffer ); +#endif // _PNP_POWER + return status; + } + +#ifndef _IO_DELETE_DEVICE_SUPPORTED +Reuse: +#endif + + *ppDeviceContext = pDeviceContext = (tDEVICECONTEXT *)DeviceObject; + + // + // zero out the data structure, beyond the OS specific part + // + LinkOffset = (ULONG)(&((tDEVICECONTEXT *)0)->Linkage); + CTEZeroMemory(&pDeviceContext->Linkage,sizeof(tDEVICECONTEXT) - LinkOffset); + +#ifdef _PNP_POWER + pDeviceContext->ExportName.MaximumLength = pucExportName->MaximumLength; + pDeviceContext->ExportName.Buffer = (PWSTR)Buffer; + + RtlCopyUnicodeString(&pDeviceContext->ExportName,pucExportName); + + pDeviceContext->BindName.MaximumLength = pucBindName->MaximumLength; + pDeviceContext->BindName.Buffer = (PWSTR)(Buffer+pucExportName->MaximumLength); + RtlCopyUnicodeString(&pDeviceContext->BindName,pucBindName); +#endif // _PNP_POWER + + // initialize the pDeviceContext data structure. There is one of + // these data structured tied to each "device" that NBT exports + // to higher layers (i.e. one for each network adapter that it + // binds to. + // The initialization sets the forward link equal to the back link equal + // to the list head + InitializeListHead(&pDeviceContext->UpConnectionInUse); + InitializeListHead(&pDeviceContext->LowerConnection); + InitializeListHead(&pDeviceContext->LowerConnFreeHead); + + // put a verifier value into the structure so that we can check that + // we are operating on the right data when the OS passes a device context + // to NBT + pDeviceContext->Verify = NBT_VERIFY_DEVCONTEXT; + + // setup the spin lock); + CTEInitLock(&pDeviceContext->SpinLock); + + pDeviceContext->LockNumber = DEVICE_LOCK; + // + // for a Bnode pAddrs is NULL + // + if (pAddrs) + { + pDeviceContext->lNameServerAddress = pAddrs->NameServerAddress; + pDeviceContext->lBackupServer = pAddrs->BackupServer; + // + // if the node type is set to Bnode by default then switch to Hnode if + // there are any WINS servers configured. + // + if ((NodeType & DEFAULT_NODE_TYPE) && + (pAddrs->NameServerAddress || pAddrs->BackupServer)) + { + NodeType = MSNODE | (NodeType & PROXY_NODE); + } + } + + // + // We need to acquire this lock since we can have multiple devices + // being added simultaneously and hence we will need to have a unique + // Adapter Number for each device + // + CTESpinLock(&NbtConfig.JointLock,OldIrq1); + // keep a bit mask around to keep track of this adapter number so we can + // quickly find if a given name is registered on a particular adapter, + // by a corresponding bit set in the tNAMEADDR - local hash table + // entry + // + pDeviceContext->AdapterNumber = (CTEULONGLONG)1 << NbtConfig.AdapterCount; + NbtConfig.AdapterCount++; + + // add this new device context on to the List in the configuration + // data structure + InsertTailList(&pConfig->DeviceContexts,&pDeviceContext->Linkage); + + if (NbtConfig.AdapterCount > 1) + { + NbtConfig.MultiHomed = TRUE; + } + CTESpinFree(&NbtConfig.JointLock,OldIrq1); + + // increase the stack size of our device object, over that of the transport + // so that clients create Irps large enough + // to pass on to the transport below. + // In theory, we should just add 1 here, to account for out presence in the + // driver chain. + + status = NbtTdiOpenControl(pDeviceContext); + if (NT_SUCCESS(status)) + { + DeviceObject->StackSize = pDeviceContext->pControlDeviceObject->StackSize + 1; + } + else + { + IF_DBG(NBT_DEBUG_NTUTIL) + KdPrint(("Nbt!NbtTdiOpenControl returned status=%X\n",status)); + return(status); + } + + + // + // An instance number is assigned to each device so that the service which + // creates logical devices in Nbt can re-use these devices in case it fails + // to destroy them in a prev. instance. + // + pDeviceContext->InstanceNumber = GetUnique32BitValue(); + + // + // To create the address objects for this device we need an address for + // TCP port 139 (session services, UDP Port 138 (datagram services) + // and UDP Port 137 (name services). The IP addresses to use for these + // port number must be found by "groveling" the registry..i.e. looking + // under each adapter in the registry for a /parameters/tcpip section + // and then pulling the IP address out of that + // + status = GetIPFromRegistry( + pucRegistryPath, + pucBindName, + &ulIpAddress, + &ulSubnetMask, + FALSE); + +#ifdef _PNP_POWER +#ifdef NOTYET_PNP + if ( status == STATUS_INVALID_ADDRESS ) + { + // + // This one doesn't have a valid static address. Try DHCP. + // + status = GetIPFromRegistry( + pucRegistryPath, + pucBindName, + &ulIpAddress, + &ulSubnetMask, + TRUE); + } +#endif NOTYET_PNP +#endif // _PNP_POWER + + if (!NT_SUCCESS(status)) + { + IF_DBG(NBT_DEBUG_NTUTIL) + KdPrint(("Nbt!GetIPFromRegistry returned status=%X\n",status)); + return(status); + } + +#ifdef _PNP_POWER + + // + // Now, we create all devices up-front (in driverentry); so no need to open the addresses etc. + // + return(status); +#endif + + // get the ip address out of the registry and open the required address + // objects with the underlying transport provider + status = NbtCreateAddressObjects( + ulIpAddress, + ulSubnetMask, + pDeviceContext); + + if (!NT_SUCCESS(status)) + { + NbtLogEvent(EVENT_NBT_CREATE_ADDRESS,status); + + KdPrint(("Failed to create the Address Object, status=%X\n",status)); + + return(status); + } + + // + // Add the "permanent" name to the local name table. This is the IP + // address of the node padded out to 16 bytes with zeros. + // + status = NbtAddPermanentName(pDeviceContext); + + // this call must converse with the transport underneath to create + // connections and associate them with the session address object + status = NbtInitConnQ( + &pDeviceContext->LowerConnFreeHead, + sizeof(tLOWERCONNECTION), + NBT_NUM_INITIAL_CONNECTIONS, + pDeviceContext); + + if (!NT_SUCCESS(status)) + { + // NEED TO PUT CODE IN HERE TO RELEASE THE DEVICE OBJECT CREATED + // ABOVE AND LOG AN ERROR... + + NbtLogEvent(EVENT_NBT_CREATE_CONNECTION,status); + + KdPrint(("Failed to create the Connection Queue, status=%X\n",status)); + + return(status); + } + + return(STATUS_SUCCESS); +} + +#ifndef _IO_DELETE_DEVICE_SUPPORTED +/******************************************************************* + + NAME: NbtMarkHandlesAsStale + + SYNOPSIS: Marks all open handles on this device as stale + + ENTRY: DeviceContext ptr + + NOTE: Should be called with NbtConfig.JointLock held. + + HISTORY: + SanjayAn 11-Sept.-1996 Created + +********************************************************************/ +VOID +NbtMarkHandlesAsStale ( + IN tDEVICECONTEXT * pDeviceContext + ) +{ + CTELockHandle OldIrq1; + CTELockHandle OldIrq2; + CTELockHandle OldIrq3; + CTELockHandle OldIrq4; + PLIST_ENTRY pEntry; + PLIST_ENTRY pEntry1; + PLIST_ENTRY pEntry2; + PLIST_ENTRY pHead; + PLIST_ENTRY pHead1; + PLIST_ENTRY pHead2; + tADDRESSELE *pAddressEle; + tCONNECTELE *pConnEle; + tCLIENTELE *pClient; + + // go through the list of addresses, then the list of clients on each + // address and then the list of connection that are in use and those that + // are currently Listening. + // + pHead = &NbtConfig.AddressHead; + pEntry = pHead->Flink; + while (pEntry != pHead) + { + pAddressEle = CONTAINING_RECORD(pEntry,tADDRESSELE,Linkage); + + CTESpinLock(pAddressEle,OldIrq2); + + if (pAddressEle->pDeviceContext != pDeviceContext) { + CTESpinFree(pAddressEle,OldIrq2); + pEntry = pEntry->Flink; + continue; + } + + pHead1 = &pAddressEle->ClientHead; + pEntry1 = pHead1->Flink; + while (pEntry1 != pHead1) + { + pClient = CONTAINING_RECORD(pEntry1,tCLIENTELE,Linkage); + pEntry1 = pEntry1->Flink; + + CTESpinLock(pClient,OldIrq3); + + ASSERT(pClient->pDeviceContext == pDeviceContext); + + // + // Mark ClientEle as down so only a close is valid on it. + // + pClient->Verify = NBT_VERIFY_CLIENT_DOWN; + + pHead2 = &pClient->ConnectActive; + pEntry2 = pHead2->Flink; + while (pEntry2 != pHead2) + { + // + // Mark ConnEle as down so only a close is valid on it. + // + pConnEle = CONTAINING_RECORD(pEntry2,tCONNECTELE,Linkage); + + CTESpinLock(pConnEle,OldIrq4); + + ASSERT(pConnEle->pDeviceContext == pDeviceContext); + + pConnEle->Verify = NBT_VERIFY_CONNECTION_DOWN; + + CTESpinFree(pConnEle,OldIrq4); + + pEntry2 = pEntry2->Flink; + } + + pHead2 = &pClient->ConnectActive; + pEntry2 = pHead2->Flink; + while (pEntry2 != pHead2) + { + tLISTENREQUESTS *pListenReq; + + // + // Mark ConnEle as down so only a close is valid on it. + // + pListenReq = CONTAINING_RECORD(pEntry2,tLISTENREQUESTS,Linkage); + pConnEle = (tCONNECTELE *)pListenReq->pConnectEle; + + CTESpinLock(pConnEle,OldIrq4); + + ASSERT(pConnEle->pDeviceContext == pDeviceContext); + + pConnEle->Verify = NBT_VERIFY_CONNECTION_DOWN; + + CTESpinFree(pConnEle,OldIrq4); + + pEntry2 = pEntry2->Flink; + } + CTESpinFree(pClient,OldIrq3); + } + CTESpinFree(pAddressEle,OldIrq2); + pEntry = pEntry->Flink; + } +} +#endif + +/******************************************************************* + + NAME: NbtDestroyDeviceObject + + SYNOPSIS: Destroys the specified device + + ENTRY: pBuffer - name of the device/ device ptr + + HISTORY: + SanjayAn 11-Sept.-1996 Created + +********************************************************************/ + +NTSTATUS +NbtDestroyDeviceObject( +#if 0 + IN PVOID pBuffer +#endif + IN tDEVICECONTEXT * pDeviceContext + ) +{ + LIST_ENTRY * pEntry; + LIST_ENTRY * pHead; + tDEVICECONTEXT * pTmpDeviceContext; + tDEVICECONTEXT * pNextDeviceContext; + tCLIENTELE * pClientEle; + tADDRESSELE * pAddress; + tNAMEADDR * pNameAddr; + tCONNECTELE * pConnEle; + tLOWERCONNECTION * pLowerConn; + tTIMERQENTRY * pTimer; + COMPLETIONCLIENT pClientCompletion; + PVOID Context; + tDGRAM_SEND_TRACKING * pTracker; + CTELockHandle OldIrq; + CTELockHandle OldIrq1; + CTELockHandle OldIrq2; + int i; + tNBTCONFIG *pConfig = &NbtConfig; + WCHAR Buffer[MAX_PATH]; + UNICODE_STRING ucExportName; + PUNICODE_STRING pucExportName; + +#if 0 + tDEVICECONTEXT * pDeviceContext; + + ucExportName.MaximumLength = sizeof(Buffer); + ucExportName.Buffer = Buffer; + pucExportName = &ucExportName; + + RtlInitUnicodeString(pucExportName, &((PNETBT_ADD_DEL_IF)pBuffer)->IfName[0]); + + // + // Find which device is going away + // Also, find out a device object that is still active: we need that info + // to update some of the address ele's. + // + pDeviceContext = NULL; + pNextDeviceContext = NULL; + + for ( pEntry = pConfig->DeviceContexts.Flink; + pEntry != &pConfig->DeviceContexts; + pEntry = pEntry->Flink ) + { + pTmpDeviceContext = CONTAINING_RECORD( pEntry, tDEVICECONTEXT, Linkage); + if ( !RtlCompareUnicodeString ( + &pTmpDeviceContext->ExportName, + pucExportName, + FALSE)) + pDeviceContext = pTmpDeviceContext; + else + pNextDeviceContext = pTmpDeviceContext; + } +#endif + + if (pDeviceContext == NULL) + return STATUS_INVALID_PARAMETER; + + if (pDeviceContext->IpAddress != 0) { + (VOID)NbtNewDhcpAddress(pDeviceContext,0,0); + } + + CTESpinLock(&NbtConfig.JointLock,OldIrq); + CTESpinLock(pDeviceContext,OldIrq1); + + if ( --NbtConfig.AdapterCount == 1) + NbtConfig.MultiHomed = FALSE; + + ASSERT(IsListEmpty(&pDeviceContext->LowerConnFreeHead)); + + // + // walk through all names and see if any is being registered on this + // device context: if so, stop and complete it! + // + for (i=0;i < NbtConfig.pLocalHashTbl->lNumBuckets ;i++ ) + { + pHead = &NbtConfig.pLocalHashTbl->Bucket[i]; + pEntry = pHead->Flink; + while (pEntry != pHead) + { + pNameAddr = CONTAINING_RECORD(pEntry,tNAMEADDR,Linkage); + pEntry = pEntry->Flink; + + if (pNameAddr->NameTypeState & STATE_RESOLVING) + { + pTimer = pNameAddr->pTimer; + + // + // if the name registration was started for this name on this device + // context, stop the timer. (Completion routine will take care of + // doing registration on other device contexts if applicable) + // + if (pTimer) + { + pTracker = pTimer->Context; + ASSERT(pTracker->pDeviceContext->Verify == NBT_VERIFY_DEVCONTEXT); + if (pTracker->pDeviceContext == pDeviceContext) + { + ASSERT(pTracker->pNameAddr == pNameAddr); + + pNameAddr->pTimer = NULL; + + StopTimer(pTimer,&pClientCompletion,&Context); + + if (pClientCompletion) + { + (*pClientCompletion)(Context,STATUS_NETWORK_NAME_DELETED); + } + + KdPrint(("DestroyDeviceObject: stopped name reg timer")) ; + } + } + + } + } + } + + // + // close all the TDI handles + // + CTESpinFree(pDeviceContext,OldIrq1); + CTESpinFree(&NbtConfig.JointLock,OldIrq); + + CloseAddressesWithTransport(pDeviceContext); + + CTESpinLock(&NbtConfig.JointLock,OldIrq); + CTESpinLock(pDeviceContext,OldIrq1); + + while (!IsListEmpty(&pDeviceContext->LowerConnection)) + { + pEntry = RemoveHeadList(&pDeviceContext->LowerConnection); + pLowerConn = CONTAINING_RECORD(pEntry,tLOWERCONNECTION,Linkage); + CTEMemFree( pLowerConn ); + } + + RemoveEntryList( &pDeviceContext->Linkage); + +#ifndef _IO_DELETE_DEVICE_SUPPORTED + // + // IoDeleteDevice on a device with open handles is not supported currently. + // Until the base guys support this feature, we hack Netbt to never call IoDeleteDevice; + // instead we mark it as down and re-use the block on a later open. + // We also mark all open handles as invalid so we fail any request directed at them. + // + CTESpinFree(pDeviceContext,OldIrq1); + NbtMarkHandlesAsStale(pDeviceContext); + CTESpinLock(pDeviceContext,OldIrq1); +#endif + + // + // Walk through the AddressHead list. If any addresses exist and they + // point to old device context, put the next device context. Also, update + // adapter mask to reflect that this device context is now gone. + // + KdPrint(("DestroyDeviceObject: setting AddrEle,NameAddr fields\r\n")); + pHead = pEntry = &NbtConfig.AddressHead; + while ((pEntry = pEntry->Flink) != pHead) + { + pAddress = CONTAINING_RECORD(pEntry,tADDRESSELE,Linkage); + ASSERT (pAddress->Verify == NBT_VERIFY_ADDRESS); + if (pAddress->pDeviceContext == pDeviceContext) + { + if (!IsListEmpty(&pConfig->DeviceContexts)) { + pAddress->pDeviceContext = CONTAINING_RECORD( pConfig->DeviceContexts.Flink, tDEVICECONTEXT, Linkage); + } else { + pAddress->pDeviceContext = NULL; + } + } + + // + // Release the name on this adapter; but dont release on other adapters + // + // only release the name on the net if it was not in conflict first + // This prevents name releases going out for names that were not actually + // claimed. Also, quick add names are not released on the net either. + // + if (!(pNameAddr->NameTypeState & (STATE_CONFLICT | NAMETYPE_QUICK)) && + (pAddress->pNameAddr->Name[0] != '*') && + (pNameAddr->AdapterMask & pDeviceContext->AdapterNumber)) + { + CTESpinFree(pDeviceContext,OldIrq1); + CTESpinFree(&NbtConfig.JointLock,OldIrq); + + (VOID)ReleaseNameOnNet(pAddress->pNameAddr, + NbtConfig.pScope, + pAddress, + NameReleaseDoneOnDynIf, // name released on dynamic if + NodeType, + pDeviceContext); + + CTESpinLock(&NbtConfig.JointLock,OldIrq); + CTESpinLock(pDeviceContext,OldIrq1); + } + } + + // + // Mark in the device extension that this is not a valid device. Default is FALSE... + // + InterlockedIncrement(&pDeviceContext->IsDestroyed); + +#ifndef _IO_DELETE_DEVICE_SUPPORTED + // + // Chain the device on the free list + // + ExInterlockedInsertTailList(&NbtConfig.FreeDevCtx, + &pDeviceContext->FreeLinkage, + &NbtConfig.SpinLock); + + CTESpinFree(pDeviceContext,OldIrq1); + CTESpinFree(&NbtConfig.JointLock,OldIrq); +#else + + CTEMemFree( pDeviceContext->ExportName.Buffer ); + CTESpinFree(pDeviceContext,OldIrq1); + CTESpinFree(&NbtConfig.JointLock,OldIrq); + IoDeleteDevice((PDEVICE_OBJECT)pDeviceContext); + +#endif + + KdPrint(("DestroyDeviceObject: deleted @ %lx\n", pDeviceContext)); + + return STATUS_SUCCESS; +} + +//---------------------------------------------------------------------------- +NTSTATUS +CreateControlObject( + tNBTCONFIG *pConfig) + +/*++ + +Routine Description: + + This routine allocates memory for the provider info block, tacks it + onto the global configuration and sets default values for each item. + +Arguments: + + +Return Value: + + + NTSTATUS + +--*/ + +{ + tCONTROLOBJECT *pControl; + + + CTEPagedCode(); + pControl = (tCONTROLOBJECT *)ExAllocatePool( + NonPagedPool, + sizeof(tCONTROLOBJECT)); + if (!pControl) + { + return(STATUS_INSUFFICIENT_RESOURCES); + } + + pControl->Verify = NBT_VERIFY_CONTROL; + + // setup the spin lock); + CTEInitLock(&pControl->SpinLock); + + pControl->ProviderInfo.Version = 1; + pControl->ProviderInfo.MaxSendSize = 0; + pControl->ProviderInfo.MaxConnectionUserData = 0; + + // we need to get these values from the transport underneath...*TODO* + // since the RDR uses this value + pControl->ProviderInfo.MaxDatagramSize = 0; + + pControl->ProviderInfo.ServiceFlags = 0; +/* pControl->ProviderInfo.TransmittedTsdus = 0; + pControl->ProviderInfo.ReceivedTsdus = 0; + pControl->ProviderInfo.TransmissionErrors = 0; + pControl->ProviderInfo.ReceiveErrors = 0; +*/ + pControl->ProviderInfo.MinimumLookaheadData = 0; + pControl->ProviderInfo.MaximumLookaheadData = 0; +/* pControl->ProviderInfo.DiscardedFrames = 0; + pControl->ProviderInfo.OversizeTsdusReceived = 0; + pControl->ProviderInfo.UndersizeTsdusReceived = 0; + pControl->ProviderInfo.MulticastTsdusReceived = 0; + pControl->ProviderInfo.BroadcastTsdusReceived = 0; + pControl->ProviderInfo.MulticastTsdusTransmitted = 0; + pControl->ProviderInfo.BroadcastTsdusTransmitted = 0; + pControl->ProviderInfo.SendTimeouts = 0; + pControl->ProviderInfo.ReceiveTimeouts = 0; + pControl->ProviderInfo.ConnectionIndicationsReceived = 0; + pControl->ProviderInfo.ConnectionIndicationsAccepted = 0; + pControl->ProviderInfo.ConnectionsInitiated = 0; + pControl->ProviderInfo.ConnectionsAccepted = 0; +*/ + // put a ptr to this info into the pConfig so we can locate it + // when we want to cleanup + pConfig->pControlObj = pControl; + + /* KEEP THIS STUFF HERE SINCE WE MAY NEED TO ALSO CREATE PROVIDER STATS!! + *TODO* + DeviceList[i].ProviderStats.Version = 2; + DeviceList[i].ProviderStats.OpenConnections = 0; + DeviceList[i].ProviderStats.ConnectionsAfterNoRetry = 0; + DeviceList[i].ProviderStats.ConnectionsAfterRetry = 0; + DeviceList[i].ProviderStats.LocalDisconnects = 0; + DeviceList[i].ProviderStats.RemoteDisconnects = 0; + DeviceList[i].ProviderStats.LinkFailures = 0; + DeviceList[i].ProviderStats.AdapterFailures = 0; + DeviceList[i].ProviderStats.SessionTimeouts = 0; + DeviceList[i].ProviderStats.CancelledConnections = 0; + DeviceList[i].ProviderStats.RemoteResourceFailures = 0; + DeviceList[i].ProviderStats.LocalResourceFailures = 0; + DeviceList[i].ProviderStats.NotFoundFailures = 0; + DeviceList[i].ProviderStats.NoListenFailures = 0; + + DeviceList[i].ProviderStats.DatagramsSent = 0; + DeviceList[i].ProviderStats.DatagramBytesSent.HighPart = 0; + DeviceList[i].ProviderStats.DatagramBytesSent.LowPart = 0; + + DeviceList[i].ProviderStats.DatagramsReceived = 0; + DeviceList[i].ProviderStats.DatagramBytesReceived.HighPart = 0; + DeviceList[i].ProviderStats.DatagramBytesReceived.LowPart = 0; + + DeviceList[i].ProviderStats.PacketsSent = 0; + DeviceList[i].ProviderStats.PacketsReceived = 0; + + DeviceList[i].ProviderStats.DataFramesSent = 0; + DeviceList[i].ProviderStats.DataFrameBytesSent.HighPart = 0; + DeviceList[i].ProviderStats.DataFrameBytesSent.LowPart = 0; + + DeviceList[i].ProviderStats.DataFramesReceived = 0; + DeviceList[i].ProviderStats.DataFrameBytesReceived.HighPart = 0; + DeviceList[i].ProviderStats.DataFrameBytesReceived.LowPart = 0; + + DeviceList[i].ProviderStats.DataFramesResent = 0; + DeviceList[i].ProviderStats.DataFrameBytesResent.HighPart = 0; + DeviceList[i].ProviderStats.DataFrameBytesResent.LowPart = 0; + + DeviceList[i].ProviderStats.DataFramesRejected = 0; + DeviceList[i].ProviderStats.DataFrameBytesRejected.HighPart = 0; + DeviceList[i].ProviderStats.DataFrameBytesRejected.LowPart = 0; + + DeviceList[i].ProviderStats.ResponseTimerExpirations = 0; + DeviceList[i].ProviderStats.AckTimerExpirations = 0; + DeviceList[i].ProviderStats.MaximumSendWindow = 0; + DeviceList[i].ProviderStats.AverageSendWindow = 0; + DeviceList[i].ProviderStats.PiggybackAckQueued = 0; + DeviceList[i].ProviderStats.PiggybackAckTimeouts = 0; + + DeviceList[i].ProviderStats.WastedPacketSpace.HighPart = 0; + DeviceList[i].ProviderStats.WastedPacketSpace.LowPart = 0; + DeviceList[i].ProviderStats.WastedSpacePackets = 0; + DeviceList[i].ProviderStats.NumberOfResources = 0; + */ + return(STATUS_SUCCESS); + +} + + +//---------------------------------------------------------------------------- +NTSTATUS +IfNotAnyLowerConnections( + IN tDEVICECONTEXT *pDeviceContext + ) +/*++ + +Routine Description: + + This routine checks each device context to see if there are any open + connections, and returns SUCCESS if there are. If the DoDisable flag + is set the list head of free lower connections is returned and the + list in the Nbtconfig structure is made empty. + +Arguments: + +Return Value: + + none + +--*/ + +{ + CTELockHandle OldIrq; + + CTESpinLock(pDeviceContext,OldIrq); + if (!IsListEmpty(&pDeviceContext->LowerConnection)) + { + CTESpinFree(pDeviceContext,OldIrq); + return(STATUS_UNSUCCESSFUL); + } + CTESpinFree(pDeviceContext,OldIrq); + return(STATUS_SUCCESS); +} +//---------------------------------------------------------------------------- +NTSTATUS +CloseAddressesWithTransport( + IN tDEVICECONTEXT *pDeviceContext + ) +/*++ + +Routine Description: + + This routine checks each device context to see if there are any open + connections, and returns SUCCESS if there are. + +Arguments: + +Return Value: + + none + +--*/ + +{ + BOOLEAN Attached; + CTELockHandle OldIrq; + PFILE_OBJECT pNSFileObject, pSFileObject, pDGFileObject; + + CTEAttachFsp(&Attached); + + // + // Check for the existence of Objects under SpinLock and + // then Close them outside of the SpinLock + // + CTESpinLock(&NbtConfig.JointLock,OldIrq); + + if (pNSFileObject = pDeviceContext->pNameServerFileObject) + { + pDeviceContext->pNameServerFileObject = NULL; + } + if (pSFileObject = pDeviceContext->pSessionFileObject) + { + pDeviceContext->pSessionFileObject = NULL; + } + if (pDGFileObject = pDeviceContext->pDgramFileObject) + { + pDeviceContext->pDgramFileObject = NULL; + } + + CTESpinFree(&NbtConfig.JointLock,OldIrq); + + // + // Now close all the necessary objects as appropriate + // + if (pNSFileObject) + { + ObDereferenceObject((PVOID *)pNSFileObject); + ZwClose(pDeviceContext->hNameServer); + } + if (pSFileObject) + { + ObDereferenceObject((PVOID *)pSFileObject); + ZwClose(pDeviceContext->hSession); + } + if (pDGFileObject) + { + ObDereferenceObject((PVOID *)pDGFileObject); + ZwClose(pDeviceContext->hDgram); + } + + CTEDetachFsp(Attached); + return(STATUS_SUCCESS); +} + +//---------------------------------------------------------------------------- +NTSTATUS +NbtCreateAddressObjects( + IN ULONG IpAddress, + IN ULONG SubnetMask, + OUT tDEVICECONTEXT *pDeviceContext) + +/*++ + +Routine Description: + + This routine gets the ip address and subnet mask out of the registry + to calcuate the broadcast address. It then creates the address objects + with the transport. + +Arguments: + + pucRegistryPath - path to NBT config info in registry + pucBindName - name of the service to bind to. + pDeviceContext - ptr to the device context... place to store IP addr + and Broadcast address permanently + +Return Value: + + none + +--*/ + +{ + NTSTATUS status; + ULONG ValueMask; + UCHAR IpAddrByte; + + CTEPagedCode(); + // + // to get the broadcast address combine the IP address with the subnet mask + // to yield a value with 1's in the "local" portion and the IP address + // in the network portion + // + ValueMask = (SubnetMask & IpAddress) | (~SubnetMask & -1); + + IF_DBG(NBT_DEBUG_NTUTIL) + KdPrint(("Broadcastaddress = %X\n",ValueMask)); + + // + // the registry can be configured to set the subnet broadcast address to + // -1 rather than use the actual subnet broadcast address. This code + // checks for that and sets the broadcast address accordingly. + // + if (!NbtConfig.UseRegistryBcastAddr) + { + pDeviceContext->BroadcastAddress = ValueMask; + } + else + { + pDeviceContext->BroadcastAddress = NbtConfig.RegistryBcastAddr; + } + + pDeviceContext->IpAddress = IpAddress; + + pDeviceContext->SubnetMask = SubnetMask; + // + // get the network number by checking the top bits in the ip address, + // looking for 0 or 10 or 110 or 1110 + // + IpAddrByte = ((PUCHAR)&IpAddress)[3]; + if ((IpAddrByte & 0x80) == 0) + { + // class A address - one byte netid + IpAddress &= 0xFF000000; + } + else + if ((IpAddrByte & 0xC0) ==0x80) + { + // class B address - two byte netid + IpAddress &= 0xFFFF0000; + } + else + if ((IpAddrByte & 0xE0) ==0xC0) + { + // class C address - three byte netid + IpAddress &= 0xFFFFFF00; + } + + + pDeviceContext->NetMask = IpAddress; + + + // now create the address objects. + + // open the Ip Address for inbound Datagrams. + status = NbtTdiOpenAddress( + &pDeviceContext->hDgram, + &pDeviceContext->pDgramDeviceObject, + &pDeviceContext->pDgramFileObject, + pDeviceContext, + (USHORT)NBT_DATAGRAM_UDP_PORT, + pDeviceContext->IpAddress, + 0); // not a TCP port + + if (NT_SUCCESS(status)) + { + // open the Nameservice UDP port .. + status = NbtTdiOpenAddress( + &pDeviceContext->hNameServer, + &pDeviceContext->pNameServerDeviceObject, + &pDeviceContext->pNameServerFileObject, + pDeviceContext, + (USHORT)NBT_NAMESERVICE_UDP_PORT, + pDeviceContext->IpAddress, + 0); // not a TCP port + + if (NT_SUCCESS(status)) + { + IF_DBG(NBT_DEBUG_NTUTIL) + KdPrint(("Nbt: Open Session port %X\n",pDeviceContext)); + + // Open the TCP port for Session Services + status = NbtTdiOpenAddress( + &pDeviceContext->hSession, + &pDeviceContext->pSessionDeviceObject, + &pDeviceContext->pSessionFileObject, + pDeviceContext, + (USHORT)NBT_SESSION_TCP_PORT, + pDeviceContext->IpAddress, + TCP_FLAG | SESSION_FLAG); // TCP port + + if (NT_SUCCESS(status)) + { + // + // This will get the MAC address for a RAS connection + // which is zero until there really is a connection to + // the RAS server + // + GetExtendedAttributes(pDeviceContext); + return(status); + } + + IF_DBG(NBT_DEBUG_NTUTIL) + KdPrint(("Unable to Open Session address with TDI, status = %X\n",status)); + + // + // Ensure that the Object pointers are NULLed out! + // + pDeviceContext->pSessionFileObject = NULL; + + ObDereferenceObject(pDeviceContext->pNameServerFileObject); + pDeviceContext->pNameServerFileObject = NULL; + NTZwCloseFile(pDeviceContext->hNameServer); + + } + ObDereferenceObject(pDeviceContext->pDgramFileObject); + pDeviceContext->pDgramFileObject = NULL; + NTZwCloseFile(pDeviceContext->hDgram); + + IF_DBG(NBT_DEBUG_NTUTIL) + KdPrint(("Unable to Open NameServer port with TDI, status = %X\n",status)); + } + + return(status); +} + +//---------------------------------------------------------------------------- +VOID +GetExtendedAttributes( + tDEVICECONTEXT *pDeviceContext + ) +/*++ + +Routine Description: + + This routine converts a unicode dotted decimal to a ULONG + +Arguments: + + +Return Value: + + none + +--*/ + +{ + NTSTATUS status; + TCP_REQUEST_QUERY_INFORMATION_EX QueryReq; + UCHAR pBuffer[256]; + IO_STATUS_BLOCK IoStatus; + ULONG BufferSize = 256; + HANDLE event; + IO_STATUS_BLOCK IoStatusBlock; + NTSTATUS Status; + OBJECT_ATTRIBUTES ObjectAttributes; + PWSTR pName=L"Tcp"; + PFILE_FULL_EA_INFORMATION EaBuffer; + UNICODE_STRING DeviceName; + BOOLEAN Attached = FALSE; + HANDLE hTcp; + + CTEPagedCode(); + + // + // Open a control channel to TCP for this IOCTL. + // + // NOTE: We cannot use the hControl in the DeviceContext since that was created in the context + // of the system process (address arrival from TCP/IP). Here, we are in the context of the service + // process (Ioctl down from DHCP) and so we need to open another control channel. + // + // NOTE: We still need to maintain the earlier call to create a control channel since that is + // used to submit TDI requests down to TCP/IP. + // + + // copy device name into the unicode string + Status = CreateDeviceString(pName,&DeviceName); + if (!NT_SUCCESS(Status)) + { + return; + } + InitializeObjectAttributes ( + &ObjectAttributes, + &DeviceName, + 0, + NULL, + NULL); + + IF_DBG(NBT_DEBUG_TDIADDR) + KdPrint(("tcp device to open = %ws\n",DeviceName.Buffer)); + + EaBuffer = NULL; + + Status = ZwCreateFile ( + &hTcp, + GENERIC_READ | GENERIC_WRITE, + &ObjectAttributes, // object attributes. + &IoStatusBlock, // returned status information. + NULL, // block size (unused). + FILE_ATTRIBUTE_NORMAL, // file attributes. + 0, + FILE_CREATE, + 0, // create options. + (PVOID)EaBuffer, // EA buffer. + 0); // Ea length + + + CTEMemFree(DeviceName.Buffer); + + IF_DBG(NBT_DEBUG_TDIADDR) + KdPrint( ("OpenControl CreateFile Status:%X, IoStatus:%X\n", Status, IoStatusBlock.Status)); + + if ( NT_SUCCESS( Status )) + { + // + // Initialize the TDI information buffers. + // + // + // pass in the ipaddress as the first ULONG of the context array + // + *(ULONG *)QueryReq.Context = htonl(pDeviceContext->IpAddress); + + QueryReq.ID.toi_entity.tei_entity = CL_NL_ENTITY; + QueryReq.ID.toi_entity.tei_instance = 0; + QueryReq.ID.toi_class = INFO_CLASS_PROTOCOL; + QueryReq.ID.toi_type = INFO_TYPE_PROVIDER; + QueryReq.ID.toi_id = IP_INTFC_INFO_ID; + + status = ZwCreateEvent( + &event, + EVENT_ALL_ACCESS, + NULL, + SynchronizationEvent, + FALSE + ); + + if ( !NT_SUCCESS(status) ) + { + return; + + } + + // + // Make the actual TDI call + // + + status = ZwDeviceIoControlFile( + hTcp, + event, + NULL, + NULL, + &IoStatus, + IOCTL_TCP_QUERY_INFORMATION_EX, + &QueryReq, + sizeof(TCP_REQUEST_QUERY_INFORMATION_EX), + pBuffer, + BufferSize + ); + + // + // If the call pended and we were supposed to wait for completion, + // then wait. + // + + if ( status == STATUS_PENDING ) + { + status = KeWaitForSingleObject( event, Executive, KernelMode, FALSE, NULL ); + + ASSERT( NT_SUCCESS(status) ); + } + + if ( NT_SUCCESS(status) ) + { + ULONG Length; + + pDeviceContext->PointToPoint = ((((IPInterfaceInfo *)pBuffer)->iii_flags & IP_INTFC_FLAG_P2P) != 0); + + // + // get the length of the mac address in case is is less than + // 6 bytes + // + Length = (((IPInterfaceInfo *)pBuffer)->iii_addrlength < sizeof(tMAC_ADDRESS)) + ? ((IPInterfaceInfo *)pBuffer)->iii_addrlength : sizeof(tMAC_ADDRESS); + + CTEZeroMemory(pDeviceContext->MacAddress.Address,sizeof(tMAC_ADDRESS)); + CTEMemCopy(&pDeviceContext->MacAddress.Address[0], + ((IPInterfaceInfo *)pBuffer)->iii_addr, + Length); + + } + + status = ZwClose( event ); + ASSERT( NT_SUCCESS(status) ); + + status = IoStatus.Status; + + // + // Close the handle to TCP since we dont need it anymore; all TDI requests go thru the + // Control handle in the DeviceContext. + // + status = ZwClose( hTcp ); + ASSERT( NT_SUCCESS(status) ); + } + else + { + KdPrint(("Nbt:Failed to Open the control connection to the transport, status1 = %X\n", + Status)); + + } + + return; +} + + +//---------------------------------------------------------------------------- +NTSTATUS +ConvertToUlong( + IN PUNICODE_STRING pucAddress, + OUT ULONG *pulValue) + +/*++ + +Routine Description: + + This routine converts a unicode dotted decimal to a ULONG + +Arguments: + + +Return Value: + + none + +--*/ + +{ + NTSTATUS status; + OEM_STRING OemAddress; + + // create integer from unicode string + + CTEPagedCode(); + status = RtlUnicodeStringToAnsiString(&OemAddress, pucAddress, TRUE); + if (!NT_SUCCESS(status)) + { + return(status); + } + + status = ConvertDottedDecimalToUlong(OemAddress.Buffer,pulValue); + + RtlFreeAnsiString(&OemAddress); + + if (!NT_SUCCESS(status)) + { + IF_DBG(NBT_DEBUG_NTUTIL) + KdPrint(("ERR: Bad Dotted Decimal Ip Address(must be <=255 with 4 dots) = %ws\n", + pucAddress->Buffer)); + + return(status); + } + + return(STATUS_SUCCESS); + + +} + + + +//---------------------------------------------------------------------------- +VOID +NbtGetMdl( + PMDL *ppMdl, + enum eBUFFER_TYPES eBuffType) + +/*++ + +Routine Description: + + This routine allocates an Mdl. + +Arguments: + + ppListHead - a ptr to a ptr to the list head to add buffer to + iNumBuffers - the number of buffers to add to the queue + +Return Value: + + none + +--*/ + +{ + PMDL pMdl; + ULONG lBufferSize; + PVOID pBuffer; + + if (NbtConfig.iCurrentNumBuff[eBuffType] + >= NbtConfig.iMaxNumBuff[eBuffType]) + { + *ppMdl = NULL; + return; + } + + lBufferSize = NbtConfig.iBufferSize[eBuffType]; + + pBuffer = NbtAllocMem((USHORT)lBufferSize,NBT_TAG('g')); + + if (!pBuffer) + { + *ppMdl = NULL; + return; + } + + // allocate a MDL to hold the session hdr + pMdl = IoAllocateMdl( + (PVOID)pBuffer, + lBufferSize, + FALSE, // want this to be a Primary buffer - the first in the chain + FALSE, + NULL); + + *ppMdl = pMdl; + + if (!pMdl) + { + CTEMemFree(pBuffer); + return; + } + + // fill in part of the session hdr since it is always the same + if (eBuffType == eNBT_FREE_SESSION_MDLS) + { + ((tSESSIONHDR *)pBuffer)->Flags = NBT_SESSION_FLAGS; + ((tSESSIONHDR *)pBuffer)->Type = NBT_SESSION_MESSAGE; + } + else + if (eBuffType == eNBT_DGRAM_MDLS) + { + ((tDGRAMHDR *)pBuffer)->Flags = FIRST_DGRAM | (NbtConfig.PduNodeType >> 10); + ((tDGRAMHDR *)pBuffer)->PckOffset = 0; // not fragmented + + } + + // map the Mdl properly to fill in the pages portion of the MDL + MmBuildMdlForNonPagedPool(pMdl); + + NbtConfig.iCurrentNumBuff[eBuffType]++; + +} + +//---------------------------------------------------------------------------- +NTSTATUS +NbtInitMdlQ( + PSINGLE_LIST_ENTRY pListHead, + enum eBUFFER_TYPES eBuffType) + +/*++ + +Routine Description: + + This routine allocates Mdls for use later. + +Arguments: + + ppListHead - a ptr to a ptr to the list head to add buffer to + iNumBuffers - the number of buffers to add to the queue + +Return Value: + + none + +--*/ + +{ + int i; + PMDL pMdl; + + + CTEPagedCode(); + // Initialize the list head, so the last element always points to NULL + pListHead->Next = NULL; + + // create a small number first and then lis the list grow with time + for (i=0;i < NBT_INITIAL_NUM ;i++ ) + { + + NbtGetMdl(&pMdl,eBuffType); + if (!pMdl) + { + KdPrint(("NBT:Unable to allocate MDL at initialization time!!\n"));\ + return(STATUS_INSUFFICIENT_RESOURCES); + } + + // put on free list + PushEntryList(pListHead,(PSINGLE_LIST_ENTRY)pMdl); + + } + + return(STATUS_SUCCESS); +} +//---------------------------------------------------------------------------- +NTSTATUS +NTZwCloseFile( + IN HANDLE Handle + ) + +/*++ +Routine Description: + + This Routine handles closing a handle with NT within the context of NBT's + file system process. + +Arguments: + + pIrp - a ptr to an IRP + +Return Value: + + NTSTATUS - status of the request + +--*/ + +{ + NTSTATUS status; + BOOLEAN Attached = FALSE; + + CTEPagedCode(); + // + // Attach to NBT's FSP (file system process) to free the handle since + // the handle is only valid in that process. + // + if (PsGetCurrentProcess() != NbtFspProcess) + { + KeAttachProcess(&NbtFspProcess->Pcb); + Attached = TRUE; + } + + status = ZwClose(Handle); + + if (Attached) + { + // + // go back to the original process + // + KeDetachProcess(); + } + + return(status); +} +//---------------------------------------------------------------------------- +NTSTATUS +NTReReadRegistry( + IN tDEVICECONTEXT *pDeviceContext + ) + +/*++ +Routine Description: + + This Routine re-reads the registry values when DHCP issues the Ioctl + to do so. + +Arguments: + + pIrp - a ptr to an IRP + +Return Value: + + NTSTATUS - status of the request + +--*/ + +{ + NTSTATUS status; + tADDRARRAY *pAddrArray=NULL; + tADDRARRAY *pAddr; + tDEVICES *pBindDevices=NULL; + tDEVICES *pExportDevices=NULL; + PLIST_ENTRY pHead; + PLIST_ENTRY pEntry; + tDEVICECONTEXT *pDevContext; + + CTEPagedCode(); + + CTEExAcquireResourceExclusive(&NbtConfig.Resource,TRUE); + + // + // BUGBUG [WishList]: We look at the whole registry in NbtAddressAdd too. + // + status = NbtReadRegistry( + &NbtConfig.pRegistry, + NULL, // Null Driver Object + &NbtConfig, + &pBindDevices, + &pExportDevices, + &pAddrArray); + + if (pAddrArray) + { + ULONG i; +#if DBG + { + BOOLEAN fFound=FALSE; + + // + // Loop thru the devicecontexts in the Config struct to ensure that this DeviceContext + // is actually valid. + // + // BUGBUG[WishList]:Would be good to have signatures in the structures. + // + pAddr = pAddrArray; + pHead = &NbtConfig.DeviceContexts; + pEntry = pHead; + while ((pEntry = pEntry->Flink) != pHead) + { + pDevContext = CONTAINING_RECORD(pEntry,tDEVICECONTEXT,Linkage); + if (pDevContext == pDeviceContext) + { + fFound = TRUE; + break; + } + } + + ASSERT(fFound == TRUE); + } +#endif + + // + // Figure out the Address entry by matching the BindDevice names against the + // name in the DeviceContext passed in. + // + for (i=0; i<NbtConfig.uNumDevices; i++) { + + if (RtlCompareUnicodeString(&pDeviceContext->BindName, + &pBindDevices->Names[i], + FALSE) == 0) { + // + // We found a match + // + pDeviceContext->lNameServerAddress = pAddrArray[i].NameServerAddress; + pDeviceContext->lBackupServer = pAddrArray[i].BackupServer; + + // + // if the node type is set to Bnode by default then switch to Hnode if + // there are any WINS servers configured. + // + if ((NodeType & DEFAULT_NODE_TYPE) && + (pAddrArray[i].NameServerAddress || pAddrArray[i].BackupServer)) + { + NodeType = MSNODE | (NodeType & PROXY); + } + + IF_DBG(NBT_DEBUG_NAMESRV) + KdPrint(("NBT:Found BindName: %lx, AddrArray: %lx, i: %lx\n", pBindDevices, pAddrArray, i)); + + break; + } + } + +#if DBG + if (i == NbtConfig.uNumDevices) { + KdPrint(("Nbt:Unable to find the entry corresp. to device %lx in the registry. BindDevices: %lx\n", + pDeviceContext, pBindDevices)); + DbgBreakPoint(); + } +#endif + } + + // + // Free Allocated memory + // + if (pBindDevices) + { + CTEMemFree(pBindDevices->RegistrySpace); + CTEMemFree((PVOID)pBindDevices); + } + if (pExportDevices) + { + CTEMemFree(pExportDevices->RegistrySpace); + CTEMemFree((PVOID)pExportDevices); + } + if (pAddrArray) + { + CTEMemFree((PVOID)pAddrArray); + } + + CTEExReleaseResource(&NbtConfig.Resource); + + if (pDeviceContext->IpAddress) + { + // + // Add the "permanent" name to the local name table. This is the IP + // address of the node padded out to 16 bytes with zeros. + // + status = NbtAddPermanentName(pDeviceContext); + + if (!(NodeType & BNODE)) + { + // Probably the Ip address just changed and Dhcp is informing us + // of a new Wins Server addresses, so refresh all the names to the + // new wins server + // + ReRegisterLocalNames(); + } + else + { + // + // no need to refresh + // on a Bnode + // + LockedStopTimer(&NbtConfig.pRefreshTimer); + } + } + + return(STATUS_SUCCESS); +} + + +//---------------------------------------------------------------------------- +NTSTATUS +NbtLogEvent( + IN ULONG EventCode, + IN NTSTATUS Status + ) + +/*++ + +Routine Description: + + This function allocates an I/O error log record, fills it in and writes it + to the I/O error log. + + +Arguments: + + EventCode - Identifies the error message. + Status - The status value to log: this value is put into the + data portion of the log message. + + +Return Value: + + STATUS_SUCCESS - The error was successfully logged.. + STATUS_BUFER_OVERFLOW - The error data was too large to be logged. + STATUS_INSUFFICIENT_RESOURCES - Unable to allocate memory. + + +--*/ + +{ + PIO_ERROR_LOG_PACKET ErrorLogEntry; + PVOID LoggingObject; + + LoggingObject = NbtConfig.DriverObject; + + ErrorLogEntry = IoAllocateErrorLogEntry(LoggingObject,sizeof(IO_ERROR_LOG_PACKET)); + + if (ErrorLogEntry == NULL) + { + IF_DBG(NBT_DEBUG_NAMESRV) + KdPrint(("Nbt:Unalbe to allocate Error Packet for Error logging\n")); + + return(STATUS_INSUFFICIENT_RESOURCES); + } + + // + // Fill in the necessary log packet fields. + // + ErrorLogEntry->UniqueErrorValue = 0; + ErrorLogEntry->ErrorCode = EventCode; + ErrorLogEntry->NumberOfStrings = 0; + ErrorLogEntry->StringOffset = 0; + ErrorLogEntry->DumpDataSize = (USHORT)sizeof(ULONG); + ErrorLogEntry->DumpData[0] = Status; + + IoWriteErrorLogEntry(ErrorLogEntry); + + return(STATUS_SUCCESS); +} +#ifdef DBGMEMNBT +VOID +PadEntry( + char *EntryPtr + ) +{ + char *Limit; + + // + // pad remainder of entry + // + Limit = EntryPtr + LOGWIDTH - 1; + ASSERT(LOGWIDTH >= (strlen(EntryPtr) + 1)); + for (EntryPtr += strlen(EntryPtr); + EntryPtr != Limit; + EntryPtr++ + ) { + *EntryPtr = ' '; + } + *EntryPtr = '\0'; +} +//---------------------------------------------------------------------------- +PVOID +CTEAllocMemDebug( + IN ULONG Size, + IN PVOID pBuffer, + IN UCHAR *File, + IN ULONG Line + ) + +/*++ + +Routine Description: + + This function logs getting and freeing memory. + +Arguments: + + +Return Value: + + +--*/ + +{ + CCHAR CurrProc; + UCHAR LockFree; + UCHAR *EntryPtr; + char *Limit; + PUCHAR pFile; + PVOID pMem; + PSTRM_PROCESSOR_LOG Log ; + + + if (!pBuffer) + { + if (!LogAlloc) + { + LogAlloc = ExAllocatePool(NonPagedPool,sizeof(STRM_PROCESSOR_LOG)); + LogAlloc->Index = 0; + } + Log = LogAlloc; + pMem = ExAllocatePool(NonPagedPool,Size); + } + else + { + if (!LogFree) + { + LogFree = ExAllocatePool(NonPagedPool,sizeof(STRM_PROCESSOR_LOG)); + LogFree->Index = 0; + } + Log = LogFree; + pMem = pBuffer; + ExFreePool(pBuffer); + } + + EntryPtr = Log->Log[Log->Index]; + + pFile = strrchr(File,'\\'); + + sprintf(EntryPtr,"%s %d %X",pFile, Line,pMem); + + PadEntry(EntryPtr); + + if (++(Log->Index) >= LOGSIZE) + { + Log->Index = 0; + } + // + // Mark next entry so we know where the log for this processor ends + // + EntryPtr = Log->Log[Log->Index]; + sprintf(EntryPtr, "*** Last Entry"); + + return(pMem); + +} +#endif + +#if DBG +//---------------------------------------------------------------------------- +VOID +AcquireSpinLockDebug( + IN PKSPIN_LOCK pSpinLock, + IN PKIRQL pOldIrq, + IN UCHAR LockNumber + ) + +/*++ + +Routine Description: + + This function gets the spin lock, and then sets the mask in Nbtconfig, per + processor. + + +Arguments: + + +Return Value: + + +--*/ + +{ + CCHAR CurrProc; + UCHAR LockFree; + + CTEGetLock(pSpinLock,pOldIrq); + + CurrProc = (CCHAR)KeGetCurrentProcessorNumber(); + NbtConfig.CurrProc = CurrProc; + + LockFree = (LockNumber > (UCHAR)NbtConfig.CurrentLockNumber[CurrProc]); + if (!LockFree) + { + KdPrint(("CurrProc = %X, CurrentLockNum = %X DataSTructLock = %X\n", + CurrProc,NbtConfig.CurrentLockNumber[CurrProc],LockNumber)); + } \ + + ASSERTMSG("Possible DeadLock, Getting SpinLock at a lower level\n",LockFree); + NbtConfig.CurrentLockNumber[CurrProc]|= LockNumber; + +} + +//---------------------------------------------------------------------------- +VOID +FreeSpinLockDebug( + IN PKSPIN_LOCK pSpinLock, + IN KIRQL OldIrq, + IN UCHAR LockNumber + ) + +/*++ + +Routine Description: + + This function clears the spin lock from the mask in Nbtconfig, per + processor and then releases the spin lock. + + +Arguments: + + +Return Value: + none + +--*/ + +{ + CCHAR CurrProc; + + CurrProc = (CCHAR)KeGetCurrentProcessorNumber(); + + NbtConfig.CurrentLockNumber[CurrProc] &= ~LockNumber; + CTEFreeLock(pSpinLock,OldIrq); + +} +//---------------------------------------------------------------------------- +VOID +AcquireSpinLockAtDpcDebug( + IN PKSPIN_LOCK pSpinLock, + IN UCHAR LockNumber + ) + +/*++ + +Routine Description: + + This function gets the spin lock, and then sets the mask in Nbtconfig, per + processor. + + +Arguments: + + +Return Value: + + +--*/ + +{ + CCHAR CurrProc; + UCHAR LockFree; + + CTEGetLockAtDPC(pSpinLock, 0); + + CurrProc = (CCHAR)KeGetCurrentProcessorNumber(); + NbtConfig.CurrProc = CurrProc; + + LockFree = (LockNumber > (UCHAR)NbtConfig.CurrentLockNumber[CurrProc]); + if (!LockFree) + { + KdPrint(("CurrProc = %X, CurrentLockNum = %X DataSTructLock = %X\n", + CurrProc,NbtConfig.CurrentLockNumber[CurrProc],LockNumber)); + } \ + + ASSERTMSG("Possible DeadLock, Getting SpinLock at a lower level\n",LockFree); + NbtConfig.CurrentLockNumber[CurrProc]|= LockNumber; + +} + +//---------------------------------------------------------------------------- +VOID +FreeSpinLockAtDpcDebug( + IN PKSPIN_LOCK pSpinLock, + IN UCHAR LockNumber + ) + +/*++ + +Routine Description: + + This function clears the spin lock from the mask in Nbtconfig, per + processor and then releases the spin lock. + + +Arguments: + + +Return Value: + none + +--*/ + +{ + CCHAR CurrProc; + + CurrProc = (CCHAR)KeGetCurrentProcessorNumber(); + + NbtConfig.CurrentLockNumber[CurrProc] &= ~LockNumber; + CTEFreeLockFromDPC(pSpinLock, 0); + +} +#endif //if Dbg + |