|
|
/*++
Copyright (c) 1999 Microsoft Corporation
Module Name:
nbtmgmt.c
Abstract:
Routines for managing NBT interfaces.
Author:
David Dion (daviddio) December 9, 1999
Revision History:
Who When What -------- -------- ---------------------------------------------- daviddio 12-09-99 created
Notes:
--*/
#include "clusnet.h"
#include "nbtmgmt.tmh"
//
// Types
//
typedef struct _NBT_IF { LIST_ENTRY Linkage; ULONG InstanceNumber; PFILE_OBJECT FileObject; WCHAR IfName[1]; } NBT_IF, *PNBT_IF;
//
// Data
//
LIST_ENTRY NbtIfList = {NULL,NULL}; KSPIN_LOCK NbtIfListLock = 0;
//
// Local function prototypes
//
NTSTATUS NbtIfOpenDevice( IN LPWSTR DeviceName, OUT PFILE_OBJECT *FileObject );
NTSTATUS NbtIfIssueDeviceControl( IN PFILE_OBJECT FileObject, IN ULONG IoControlCode, IN PVOID InputBuffer, IN ULONG InputBufferLength, IN PVOID OutputBuffer, IN ULONG OutputBufferLength );
PNBT_IF NbtFindIf( IN LPWSTR DeviceName, IN ULONG Length );
#ifdef ALLOC_PRAGMA
#pragma alloc_text(INIT, NbtIfLoad)
#pragma alloc_text(PAGE, NbtIfOpenDevice)
#pragma alloc_text(PAGE, NbtIfIssueDeviceControl)
#endif // ALLOC_PRAGMA
NTSTATUS NbtIfIssueDeviceControl( IN PFILE_OBJECT FileObject, IN ULONG IoControlCode, IN PVOID InputBuffer, IN ULONG InputBufferLength, IN PVOID OutputBuffer, IN ULONG OutputBufferLength )
/*++
Routine Description:
Arguments:
Return Value:
NTSTATUS -- Indicates the status of the request.
--*/
{ NTSTATUS status = STATUS_SUCCESS; IO_STATUS_BLOCK iosb; KEVENT event; PIRP irp;
PAGED_CODE();
KeInitializeEvent(&event, SynchronizationEvent, FALSE);
irp = IoBuildDeviceIoControlRequest( IoControlCode, IoGetRelatedDeviceObject(FileObject), InputBuffer, InputBufferLength, OutputBuffer, OutputBufferLength, FALSE, &event, &iosb );
if (irp != NULL) {
status = IoCallDriver( IoGetRelatedDeviceObject(FileObject), irp );
if (status == STATUS_PENDING) {
status = KeWaitForSingleObject( &event, Executive, KernelMode, FALSE, NULL ); CnAssert(status == STATUS_SUCCESS);
status = iosb.Status; } } else {
status = STATUS_INSUFFICIENT_RESOURCES; IF_CNDBG(CN_DEBUG_NTE) { CNPRINT(( "[Clusnet] Failed to build NBT request irp, status %lx\n", status )); } CnTrace(NTEMGMT_DETAIL, NbtIfIrpAllocFailed, "[Clusnet] Failed to build NBT request irp, status %!status!.", status // LOGSTATUS
); }
return(status);
} // NbtIfIssueDeviceControl
NTSTATUS NbtIfOpenDevice( IN LPWSTR DeviceName, OUT PFILE_OBJECT *FileObject )
{ UNICODE_STRING nameString; OBJECT_ATTRIBUTES objectAttributes; IO_STATUS_BLOCK iosb; HANDLE handle; NTSTATUS status;
*FileObject = (PFILE_OBJECT) NULL;
//
// Open the NBT device.
//
RtlInitUnicodeString(&nameString, DeviceName);
InitializeObjectAttributes( &objectAttributes, &nameString, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, (HANDLE) NULL, (PSECURITY_DESCRIPTOR) NULL );
status = ZwCreateFile( &handle, SYNCHRONIZE | FILE_READ_DATA | FILE_WRITE_DATA, &objectAttributes, &iosb, NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_OPEN_IF, 0, NULL, 0 );
if (NT_SUCCESS(status)) {
// Get a pointer to the corresponding file object. The file
// object pointer is used to issue ioctls to the device.
status = ObReferenceObjectByHandle( handle, 0, NULL, KernelMode, FileObject, NULL );
if (!NT_SUCCESS(status)) { *FileObject = (PFILE_OBJECT) NULL; CnTrace(NTEMGMT_DETAIL, NbtIfObDerefFailed, "[Clusnet] Failed to deref NBT device handle %p " "for device %ls, status %!status!.", handle, DeviceName, // LOGWSTR
status // LOGSTATUS
); IF_CNDBG(CN_DEBUG_INIT) { CNPRINT(("[Clusnet] Failed to deref NBT device handle %p " "for device %S, status %lx\n", handle, DeviceName, status)); } }
ZwClose(handle);
} else { CnTrace(NTEMGMT_DETAIL, NbtIfOpenDeviceFailed, "[Clusnet] Failed to open NBT device %ls, status %!status!.", DeviceName, // LOGWSTR
status // LOGSTATUS
); IF_CNDBG(CN_DEBUG_INIT) { CNPRINT(("[Clusnet] Failed to open NBT device %S, status %lx\n", DeviceName, status)); } }
return(status);
} // NbtIfOpenDevice
PNBT_IF NbtFindIf( LPWSTR DeviceName, ULONG Length ) { PNBT_IF nbtif; PLIST_ENTRY entry;
for ( entry = NbtIfList.Flink; entry != &NbtIfList; entry = entry->Flink ) { nbtif = CONTAINING_RECORD(entry, NBT_IF, Linkage);
if (RtlCompareMemory( &nbtif->IfName[0], DeviceName, Length - sizeof(UNICODE_NULL) ) == Length - sizeof(UNICODE_NULL)) { return(nbtif); } }
return(NULL);
} // NbtFindIf
//
// Public Routines
//
NTSTATUS NbtIfLoad( VOID ) { IF_CNDBG(CN_DEBUG_INIT) { CNPRINT(("[Clusnet] NBT support loading.\n")); }
KeInitializeSpinLock(&NbtIfListLock); InitializeListHead(&NbtIfList);
return(STATUS_SUCCESS);
} // NbtIfLoad
VOID NbtIfShutdown( VOID ) { NTSTATUS status; KIRQL irql; PLIST_ENTRY entry; PNBT_IF nbtif; LIST_ENTRY deletelist;
IF_CNDBG(CN_DEBUG_INIT) { CNPRINT(("[Clusnet] Destroying all cluster NBT interfaces...\n")); }
KeAcquireSpinLock( &NbtIfListLock, &irql );
//
// Move the contents of NbtIfList to the delete list
//
if (!IsListEmpty( &NbtIfList )) { RtlCopyMemory( &deletelist, &NbtIfList, sizeof(NbtIfList) ); deletelist.Flink->Blink = &deletelist; deletelist.Blink->Flink = &deletelist; InitializeListHead( &NbtIfList ); } else { InitializeListHead( &deletelist ); }
KeReleaseSpinLock( &NbtIfListLock, irql );
while (!IsListEmpty( &deletelist )) {
entry = RemoveHeadList( &deletelist );
nbtif = CONTAINING_RECORD( entry, NBT_IF, Linkage );
status = NbtIfIssueDeviceControl( nbtif->FileObject, IOCTL_NETBT_DELETE_INTERFACE, NULL, // request
0, // request size
NULL, // response
0 // response size
);
if (status != STATUS_SUCCESS) { LPWSTR deviceName = (LPWSTR) &nbtif->IfName[0];
CnTrace(NTEMGMT_DETAIL, NbtIfDeleteFailed, "[Clusnet] Failed to delete NBT interface %ls " "file object %p, status %!status!.", deviceName, // LOGWSTR
nbtif->FileObject, status // LOGSTATUS
);
IF_CNDBG(CN_DEBUG_NTE) { CNPRINT(("[Clusnet] Failed to delete NBT interface %S " "file object %p, status %lx\n", deviceName, nbtif->FileObject, status )); } } else {
LPWSTR deviceName = (LPWSTR) &nbtif->IfName[0];
CnTrace(NTEMGMT_DETAIL, NbtIfDeleted, "[Clusnet] Delete NBT interface %ls.", deviceName // LOGWSTR
);
IF_CNDBG(CN_DEBUG_NTE) { CNPRINT(("[Clusnet] Deleted NBT interface %S.\n", deviceName )); } }
// Release the reference that was taken when the NBT device
// was created.
ObDereferenceObject(nbtif->FileObject);
CnFreePool(nbtif); }
CnTrace(NTEMGMT_DETAIL, NbtIfShutdownIfsDeleted, "[Clusnet] All cluster NBT interfaces destroyed." );
IF_CNDBG(CN_DEBUG_INIT) { CNPRINT(("[Clusnet] All cluster NBT interfaces destroyed.\n")); }
return;
} // NbtIfShutdown
NTSTATUS NbtAddIf( IN PNETBT_ADD_DEL_IF Request, IN ULONG RequestSize, OUT PNETBT_ADD_DEL_IF Response, IN OUT PULONG ResponseSize ) { NTSTATUS status; PFILE_OBJECT requestFileObject; PFILE_OBJECT responseFileObject; PNBT_IF nbtif; KIRQL irql;
CnTrace(NTEMGMT_DETAIL, NbtIfAdding, "[Clusnet] Creating new NBT interface for NBT device %ls.", Request->IfName // LOGWSTR
);
IF_CNDBG(CN_DEBUG_NTE) { CNPRINT(( "[Clusnet] Creating new NBT interface for NBT device %S...\n", Request->IfName )); }
//
// Open the NBT device specified in the request. This corresponds
// to a particular TCP/IP interface.
//
status = NbtIfOpenDevice( Request->IfName, &requestFileObject );
if (NT_SUCCESS(status)) {
//
// Allocate a record for the NBT interface
//
nbtif = CnAllocatePool( FIELD_OFFSET( NBT_IF, IfName[0] ) + Response->Length ); if (nbtif != NULL) {
//
// Issue an ioctl to create a new NBT interface.
// The response contains the name of the new NBT
// interface device object.
//
status = NbtIfIssueDeviceControl( requestFileObject, IOCTL_NETBT_ADD_INTERFACE, NULL, 0, Response, *ResponseSize ); if (NT_SUCCESS(status) && NT_SUCCESS(Response->Status)) {
//
// Open the new NBT interface device object.
//
status = NbtIfOpenDevice( (LPWSTR) Response->IfName, &responseFileObject );
if (NT_SUCCESS(status)) {
LPWSTR deviceName = (LPWSTR) &Response->IfName[0]; //
// Store the interface name, instance, and
// file object corresponding to the new NBT
// interface device object.
//
RtlZeroMemory( nbtif, FIELD_OFFSET( NBT_IF, IfName[0] ) + Response->Length );
RtlCopyMemory( &nbtif->IfName[0], deviceName, Response->Length );
nbtif->InstanceNumber = Response->InstanceNumber; nbtif->FileObject = responseFileObject;
KeAcquireSpinLock(&NbtIfListLock, &irql);
InsertTailList(&NbtIfList, &(nbtif->Linkage));
KeReleaseSpinLock(&NbtIfListLock, irql); CnTrace(NTEMGMT_DETAIL, NbtIfAdded, "[Clusnet] Created new NBT interface device %ls.", deviceName // LOGWSTR
);
IF_CNDBG(CN_DEBUG_NTE) { CNPRINT(( "[Clusnet] Created new NBT interface " "device %S.\n", deviceName )); }
} else {
CnTrace(NTEMGMT_DETAIL, NbtIfAddOpenNewFailed, "[Clusnet] Failed to open NBT device for new " "interface %ls, status %!status!.", Request->IfName, // LOGWSTR
status // LOGSTATUS
);
IF_CNDBG(CN_DEBUG_NTE) { CNPRINT(( "[Clusnet] Failed to open NBT device for " "new interface %S: %x\n", Request->IfName, status )); }
CnFreePool(nbtif); } } else { CnTrace(NTEMGMT_DETAIL, NbtIfAddFailed, "[Clusnet] Failed to add NBT interface for " "NBT device %ls, status %!status!, %!status!.", Request->IfName, // LOGWSTR
status, // LOGSTATUS
Response->Status // LOGSTATUS
);
IF_CNDBG(CN_DEBUG_NTE) { CNPRINT(( "[Clusnet] Failed to add NBT interface " "for NBT device %S: %x, %x\n", Request->IfName, status, Response->Status )); }
CnFreePool(nbtif); } } else { status = STATUS_INSUFFICIENT_RESOURCES; CnTrace(NTEMGMT_DETAIL, NbtIfAddAllocFailed, "[Clusnet] Failed to allocate record for NBT " "interface %ls, status %!status!.", Request->IfName, // LOGWSTR
status // LOGSTATUS
); }
//
// Release reference on NBT device object corresponding
// to TCP/IP interface.
//
ObDereferenceObject(requestFileObject);
} else { CnTrace(NTEMGMT_DETAIL, NbtIfAddOpenFailed, "[Clusnet] Failed to open NBT device %ls for add, " "status %!status!.", Request->IfName, // LOGWSTR
status // LOGSTATUS
); IF_CNDBG(CN_DEBUG_NTE) { CNPRINT(( "[Clusnet] Failed to open NBT device %S: %x\n", Request->IfName, status )); } }
return(status);
} // NbtAddIf
NTSTATUS NbtDeleteIf( IN PNETBT_ADD_DEL_IF Request, IN ULONG RequestSize ) { NTSTATUS status; PNBT_IF nbtif; KIRQL irql; ULONG responseSize = 0;
CnTrace(NTEMGMT_DETAIL, NbtIfDeleting, "[Clusnet] Deleting NBT interface %ls.", Request->IfName // LOGWSTR
);
IF_CNDBG(CN_DEBUG_NTE) { CNPRINT(( "[Clusnet] Attempting to delete NBT interface %S...\n", (LPWSTR) &Request->IfName[0] )); }
KeAcquireSpinLock(&NbtIfListLock, &irql);
nbtif = NbtFindIf( (LPWSTR) &Request->IfName[0], Request->Length );
if (nbtif != NULL) { RemoveEntryList(&(nbtif->Linkage));
KeReleaseSpinLock(&NbtIfListLock, irql);
status = NbtIfIssueDeviceControl( nbtif->FileObject, IOCTL_NETBT_DELETE_INTERFACE, NULL, // request
0, // request size
NULL, // response
0 // response size
);
if (status != STATUS_SUCCESS) { LPWSTR deviceName = (LPWSTR) &nbtif->IfName[0];
CnTrace(NTEMGMT_DETAIL, NbtIfDeleteFailed, "[Clusnet] Failed to delete NBT interface %ls " "file object %p, status %!status!.", deviceName, // LOGWSTR
nbtif->FileObject, status // LOGSTATUS
);
IF_CNDBG(CN_DEBUG_NTE) { CNPRINT(("[Clusnet] Failed to delete NBT interface %S " "file object %p, status %lx\n", deviceName, nbtif->FileObject, status )); } } else {
LPWSTR deviceName = (LPWSTR) &nbtif->IfName[0];
CnTrace(NTEMGMT_DETAIL, NbtIfDeleted, "[Clusnet] Delete NBT interface %ls.", deviceName // LOGWSTR
);
IF_CNDBG(CN_DEBUG_NTE) { CNPRINT(("[Clusnet] Deleted NBT interface %S.\n", deviceName )); } }
// Release the reference that was taken when the NBT device
// was created.
ObDereferenceObject(nbtif->FileObject);
CnFreePool(nbtif);
} else { KeReleaseSpinLock(&NbtIfListLock, irql); CnTrace(NTEMGMT_DETAIL, NbtIfDeleteNotFound, "[Clusnet] NBT interface %ls does not exist.", Request->IfName // LOGWSTR
);
IF_CNDBG(CN_DEBUG_NTE) { CNPRINT(("[Clusnet] NBT interface %S does not exist.\n", (LPWSTR) &Request->IfName[0])); } status = STATUS_UNSUCCESSFUL; }
return (status);
} // NbtDeleteIf
|