windows-nt/Source/XPSP1/NT/net/nwlink/nb/driver.c
2020-09-26 16:20:57 +08:00

1960 lines
50 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
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
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
PDEVICE NbiDevice = NULL;
HANDLE TdiProviderHandle = NULL;
#ifdef BIND_FIX
HANDLE TdiClientHandle = NULL;
PDRIVER_OBJECT NbiDriverObject = NULL;
UNICODE_STRING NbiRegistryPath;
PEPROCESS NbiFspProcess;
UNICODE_STRING NbiBindString;
EXTERNAL_LOCK(NbiTdiRequestInterlock);
extern LIST_ENTRY NbiTdiRequestList;
WCHAR BIND_STRING_NAME[50] = L"\\Device\\NwlnkIpx";
VOID
NbiUnbindFromIpx(
);
#endif // BIND_FIX
DEFINE_LOCK_STRUCTURE(NbiGlobalPoolInterlock);
#ifdef RSRC_TIMEOUT_DBG
// RSRC_TIMEOUT_DBG is currently not defined!
ULONG NbiGlobalDebugResTimeout = 1;
LARGE_INTEGER NbiGlobalMaxResTimeout;
// the packet is allocated from ndis pool.
NB_SEND_PACKET NbiGlobalDeathPacket; // try to use this first for sends
UCHAR NbiGlobalDeathPacketHeader[100];
VOID
NbiInitDeathPacket()
{
NDIS_HANDLE PoolHandle; // poolhandle for sendpacket below when
NTSTATUS Status;
//
// if we are using ndis packets, first create packet pool for 1 packet descriptor
//
PoolHandle = (NDIS_HANDLE) NDIS_PACKET_POOL_TAG_FOR_NWLNKNB; // Dbg info for Ndis!
NdisAllocatePacketPoolEx (&Status, &PoolHandle, 1, 0, sizeof(NB_SEND_RESERVED));
if (!NT_SUCCESS(Status)){
DbgPrint("Could not allocatee death packet %lx\n", Status);
NbiGlobalDebugResTimeout = 0;
} else {
NdisSetPacketPoolProtocolId (PoolHandle, NDIS_PROTOCOL_ID_IPX);
if (NbiInitializeSendPacket(
NbiDevice,
PoolHandle,
&NbiGlobalDeathPacket,
NbiGlobalDeathPacketHeader,
NbiDevice->Bind.MacHeaderNeeded + sizeof(NB_CONNECTION)) != STATUS_SUCCESS) {
DbgPrint("Could not allocatee death packet %lx\n", Status);
NbiGlobalDebugResTimeout = 0;
//
// Also free up the pool which we allocated above.
//
NdisFreePacketPool(PoolHandle);
}
}
}
#endif //RSRC_TIMEOUT_DBG
#if DBG
ULONG NbiDebug = 0xffffffff;
ULONG NbiDebug2 = 0x00000000;
ULONG NbiMemoryDebug = 0x0002482c;
UCHAR NbiTempDebugBuffer[TEMP_BUF_LEN];
UCHAR NbiDebugMemory [NB_MEMORY_LOG_SIZE][MAX_ARGLEN];
PUCHAR NbiDebugMemoryLoc = NbiDebugMemory[0];
PUCHAR NbiDebugMemoryEnd = NbiDebugMemory[NB_MEMORY_LOG_SIZE];
DEFINE_LOCK_STRUCTURE(NbiDebugLogLock);
VOID
NbiDebugMemoryLog(
IN PUCHAR FormatString,
...
)
{
INT ArgLen;
va_list ArgumentPointer;
PUCHAR DebugMemoryLoc;
CTELockHandle LockHandle;
va_start(ArgumentPointer, FormatString);
//
// To avoid any overflows, copy this in a temp buffer first.
RtlZeroMemory (NbiTempDebugBuffer, TEMP_BUF_LEN);
ArgLen = vsprintf(NbiTempDebugBuffer, FormatString, ArgumentPointer);
va_end(ArgumentPointer);
if (ArgLen > MAX_ARGLEN)
{
ArgLen = MAX_ARGLEN;
}
CTEGetLock (&NbiDebugLogLock, &LockHandle);
DebugMemoryLoc = NbiDebugMemoryLoc;
NbiDebugMemoryLoc += MAX_ARGLEN;
if (NbiDebugMemoryLoc >= NbiDebugMemoryEnd)
{
NbiDebugMemoryLoc = NbiDebugMemory[0];
}
CTEFreeLock (&NbiDebugLogLock, LockHandle);
RtlZeroMemory (NbiDebugMemoryLoc, MAX_ARGLEN);
RtlCopyMemory( NbiDebugMemoryLoc, NbiTempDebugBuffer, ArgLen);
} /* NbiDebugMemoryLog */
DEFINE_LOCK_STRUCTURE(NbiMemoryInterlock);
MEMORY_TAG NbiMemoryTag[MEMORY_MAX];
#endif
//
// This is used only for CHK build. For
// tracking the refcount problem on connection, this
// is moved here for now.
//
DEFINE_LOCK_STRUCTURE(NbiGlobalInterlock);
#ifdef RASAUTODIAL
VOID
NbiAcdBind();
VOID
NbiAcdUnbind();
#endif
#ifdef NB_PACKET_LOG
ULONG NbiPacketLogDebug = NB_PACKET_LOG_RCV_OTHER | NB_PACKET_LOG_SEND_OTHER;
USHORT NbiPacketLogSocket = 0;
DEFINE_LOCK_STRUCTURE(NbiPacketLogLock);
NB_PACKET_LOG_ENTRY NbiPacketLog[NB_PACKET_LOG_LENGTH];
PNB_PACKET_LOG_ENTRY NbiPacketLogLoc = NbiPacketLog;
PNB_PACKET_LOG_ENTRY NbiPacketLogEnd = &NbiPacketLog[NB_PACKET_LOG_LENGTH];
VOID
NbiLogPacket(
IN BOOLEAN Send,
IN PUCHAR DestMac,
IN PUCHAR SrcMac,
IN USHORT Length,
IN PVOID NbiHeader,
IN PVOID Data
)
{
CTELockHandle LockHandle;
PNB_PACKET_LOG_ENTRY PacketLog;
LARGE_INTEGER TickCount;
ULONG DataLength;
CTEGetLock (&NbiPacketLogLock, &LockHandle);
PacketLog = NbiPacketLogLoc;
++NbiPacketLogLoc;
if (NbiPacketLogLoc >= NbiPacketLogEnd) {
NbiPacketLogLoc = NbiPacketLog;
}
*(UNALIGNED ULONG *)NbiPacketLogLoc->TimeStamp = 0x3e3d3d3d; // "===>"
CTEFreeLock (&NbiPacketLogLock, LockHandle);
RtlZeroMemory (PacketLog, sizeof(NB_PACKET_LOG_ENTRY));
PacketLog->SendReceive = Send ? '>' : '<';
KeQueryTickCount(&TickCount);
_itoa (TickCount.LowPart % 100000, PacketLog->TimeStamp, 10);
RtlCopyMemory(PacketLog->DestMac, DestMac, 6);
RtlCopyMemory(PacketLog->SrcMac, SrcMac, 6);
PacketLog->Length[0] = Length / 256;
PacketLog->Length[1] = Length % 256;
if (Length < sizeof(IPX_HEADER)) {
RtlCopyMemory(&PacketLog->NbiHeader, NbiHeader, Length);
} else {
RtlCopyMemory(&PacketLog->NbiHeader, NbiHeader, sizeof(IPX_HEADER));
}
DataLength = Length - sizeof(IPX_HEADER);
if (DataLength < 14) {
RtlCopyMemory(PacketLog->Data, Data, DataLength);
} else {
RtlCopyMemory(PacketLog->Data, Data, 14);
}
} /* NbiLogPacket */
#endif // NB_PACKET_LOG
//
// Forward declaration of various routines used in this module.
//
NTSTATUS
DriverEntry(
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath
);
VOID
NbiUnload(
IN PDRIVER_OBJECT DriverObject
);
NTSTATUS
NbiDispatchDeviceControl(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
);
NTSTATUS
NbiDispatchOpenClose(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
);
NTSTATUS
NbiDispatchInternal (
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
);
NTSTATUS
NbiDispatchPnP(
IN PDEVICE_OBJECT Device,
IN PIRP pIrp
);
VOID
NbiFreeResources (
IN PVOID Adapter
);
#ifdef ALLOC_PRAGMA
#pragma alloc_text(INIT,DriverEntry)
#endif
//
// This prevents us from having a bss section.
//
ULONG _setjmpexused = 0;
//
// These two are used in various places in the driver.
//
#if defined(_PNP_POWER)
IPX_LOCAL_TARGET BroadcastTarget = { {ITERATIVE_NIC_ID}, { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff } };
#endif _PNP_POWER
UCHAR BroadcastAddress[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
UCHAR NetbiosBroadcastName[16] = { '*', 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0 };
ULONG NbiFailLoad = FALSE;
NTSTATUS
DriverEntry(
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath
)
/*++
Routine Description:
This routine performs initialization of the Netbios ISN module.
It creates the device objects for the transport
provider and performs other driver initialization.
Arguments:
DriverObject - Pointer to driver object created by the system.
RegistryPath - The name of Netbios's node in the registry.
Return Value:
The function value is the final status from the initialization operation.
--*/
{
NTSTATUS status;
#ifdef BIND_FIX
WCHAR wcNwlnkNbClientName[60] = L"NwlnkNb";
UNICODE_STRING ucNwlnkNbClientName;
TDI_CLIENT_INTERFACE_INFO TdiClientInterface;
#else
static const NDIS_STRING ProtocolName = NDIS_STRING_CONST("Netbios/IPX Transport");
PDEVICE Device;
PIPX_HEADER IpxHeader;
CTELockHandle LockHandle;
PCONFIG Config = NULL;
WCHAR wcNwlnkNbProviderName[60] = L"\\Device\\NwlnkNb";
UNICODE_STRING ucNwlnkNbProviderName;
#endif // !BIND_FIX
//
// Initialize the Common Transport Environment.
//
if (CTEInitialize() == 0) {
NB_DEBUG (DEVICE, ("CTEInitialize() failed\n"));
NbiWriteGeneralErrorLog(
(PVOID)DriverObject,
EVENT_TRANSPORT_REGISTER_FAILED,
101,
STATUS_UNSUCCESSFUL,
NULL,
0,
NULL);
return STATUS_UNSUCCESSFUL;
}
#if DBG
CTEInitLock (&NbiGlobalInterlock);
CTEInitLock (&NbiMemoryInterlock);
{
UINT i;
for (i = 0; i < MEMORY_MAX; i++) {
NbiMemoryTag[i].Tag = i;
NbiMemoryTag[i].BytesAllocated = 0;
}
}
#endif
#ifdef NB_PACKET_LOG
CTEInitLock (&NbiPacketLogLock);
#endif
#if DBG
CTEInitLock( &NbiDebugLogLock);
#endif
#if defined(NB_OWN_PACKETS)
CTEAssert (NDIS_PACKET_SIZE == FIELD_OFFSET(NDIS_PACKET, ProtocolReserved[0]));
#endif
NB_DEBUG2 (DEVICE, ("ISN Netbios loaded\n"));
#ifdef BIND_FIX
//
// Initialize the driver object with this driver's entry points.
//
DriverObject->MajorFunction [IRP_MJ_CREATE] = NbiDispatchOpenClose;
DriverObject->MajorFunction [IRP_MJ_DEVICE_CONTROL] = NbiDispatchDeviceControl;
DriverObject->MajorFunction [IRP_MJ_INTERNAL_DEVICE_CONTROL]= NbiDispatchInternal;
DriverObject->MajorFunction [IRP_MJ_CLEANUP] = NbiDispatchOpenClose;
DriverObject->MajorFunction [IRP_MJ_CLOSE] = NbiDispatchOpenClose;
DriverObject->MajorFunction [IRP_MJ_PNP] = NbiDispatchPnP;
DriverObject->DriverUnload = NbiUnload;
NbiDevice = NULL;
NbiDriverObject = DriverObject;
RtlInitUnicodeString(&NbiBindString, BIND_STRING_NAME);
InitializeListHead(&NbiTdiRequestList);
CTEInitLock (&NbiTdiRequestInterlock);
//
// Save the registry path
//
NbiRegistryPath.Buffer = (PWCHAR) NbiAllocateMemory (RegistryPath->Length + sizeof(WCHAR),
MEMORY_CONFIG, "RegistryPathBuffer");
if (NbiRegistryPath.Buffer == NULL) {
NbiWriteResourceErrorLog ((PVOID)DriverObject, RegistryPath->Length + sizeof(WCHAR), MEMORY_CONFIG);
return STATUS_INSUFFICIENT_RESOURCES;
}
RtlCopyMemory (NbiRegistryPath.Buffer, RegistryPath->Buffer, RegistryPath->Length);
NbiRegistryPath.Buffer[RegistryPath->Length/sizeof(WCHAR)] = UNICODE_NULL;
NbiRegistryPath.Length = RegistryPath->Length;
NbiRegistryPath.MaximumLength = RegistryPath->Length + sizeof(WCHAR);
NbiFspProcess =(PEPROCESS)PsGetCurrentProcess();
//
// Make Tdi ready for pnp notifications before binding to IPX
//
TdiInitialize();
//
// Register our Handlers with TDI
//
RtlInitUnicodeString(&ucNwlnkNbClientName, wcNwlnkNbClientName);
ucNwlnkNbClientName.MaximumLength = sizeof (wcNwlnkNbClientName);
RtlZeroMemory(&TdiClientInterface, sizeof(TdiClientInterface));
TdiClientInterface.MajorTdiVersion = MAJOR_TDI_VERSION;
TdiClientInterface.MinorTdiVersion = MINOR_TDI_VERSION;
TdiClientInterface.ClientName = &ucNwlnkNbClientName;
TdiClientInterface.BindingHandler = TdiBindHandler;
if (!NT_SUCCESS(TdiRegisterPnPHandlers(&TdiClientInterface,sizeof(TdiClientInterface),&TdiClientHandle)))
{
TdiClientHandle = NULL;
DbgPrint("Nbi.DriverEntry: FAILed to Register NwlnkNb as Client!\n");
}
#else
//
// This allocates the CONFIG structure and returns
// it in Config.
//
status = NbiGetConfiguration(DriverObject, RegistryPath, &Config);
if (!NT_SUCCESS (status)) {
//
// If it failed it logged an error.
//
PANIC (" Failed to initialize transport, ISN Netbios initialization failed.\n");
return status;
}
//
// Initialize the driver object with this driver's entry points.
//
DriverObject->MajorFunction [IRP_MJ_CREATE] = NbiDispatchOpenClose;
DriverObject->MajorFunction [IRP_MJ_CLOSE] = NbiDispatchOpenClose;
DriverObject->MajorFunction [IRP_MJ_CLEANUP] = NbiDispatchOpenClose;
DriverObject->MajorFunction [IRP_MJ_INTERNAL_DEVICE_CONTROL] = NbiDispatchInternal;
DriverObject->MajorFunction [IRP_MJ_DEVICE_CONTROL] = NbiDispatchDeviceControl;
DriverObject->DriverUnload = NbiUnload;
//
// Create the device object which exports our name.
//
status = NbiCreateDevice (DriverObject, &Config->DeviceName, &Device);
if (!NT_SUCCESS (status)) {
NbiWriteGeneralErrorLog(
(PVOID)DriverObject,
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->FindNameTimeout =
((Config->Parameters[CONFIG_BROADCAST_TIMEOUT]) + (FIND_NAME_GRANULARITY/2)) /
FIND_NAME_GRANULARITY;
Device->MaxReceiveBuffers = 20; // Make it configurable?
Device->NameCache = NULL; // MP bug: IPX tries to Flush it before it's initialized!
//
// 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;
}
//
// Make Tdi ready for pnp notifications before binding to IPX
//
TdiInitialize();
// 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;
}
//
// 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 defined(_PNP_POWER)
if ( DEVICE_STATE_CLOSED == Device->State ) {
Device->State = DEVICE_STATE_LOADED;
}
#endif _PNP_POWER
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);
#endif // BIND_FIX
return STATUS_SUCCESS;
} /* DriverEntry */
VOID
NbiUnload(
IN PDRIVER_OBJECT DriverObject
)
/*++
Routine Description:
This routine unloads the sample transport driver.
It 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:
DriverObject - Pointer to driver object created by the system.
Return Value:
None. When the function returns, the driver is unloaded.
--*/
{
#ifdef BIND_FIX
UNREFERENCED_PARAMETER (DriverObject);
if (TdiClientHandle)
{
TdiDeregisterPnPHandlers (TdiClientHandle);
TdiClientHandle = NULL;
}
if (TdiProviderHandle)
{
TdiDeregisterProvider (TdiProviderHandle);
}
if (NbiBindState & NBI_BOUND_TO_IPX)
{
NbiUnbindFromIpx();
}
NbiFreeMemory (NbiRegistryPath.Buffer, NbiRegistryPath.MaximumLength,MEMORY_CONFIG,"RegistryPathBuffer");
#else
PNETBIOS_CACHE CacheName;
PDEVICE Device = NbiDevice;
PLIST_ENTRY p;
UNREFERENCED_PARAMETER (DriverObject);
#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.
//
ExDeleteResource (&Device->AddressResource);
IoDeleteDevice ((PDEVICE_OBJECT)Device);
if (TdiProviderHandle)
{
TdiDeregisterProvider (TdiProviderHandle);
}
#endif // BIND_FIX
} /* NbiUnload */
VOID
NbiFreeResources (
IN PVOID Adapter
)
/*++
Routine Description:
This routine is called by Netbios to clean up the data structures associated
with a given Device. When this routine exits, the Device
should be deleted as it no longer has any assocaited resources.
Arguments:
Device - Pointer to the Device we wish to clean up.
Return Value:
None.
--*/
{
#if 0
PLIST_ENTRY p;
PSINGLE_LIST_ENTRY s;
PTP_PACKET packet;
PNDIS_PACKET ndisPacket;
PBUFFER_TAG BufferTag;
#endif
#if 0
//
// Clean up packet pool.
//
while ( Device->PacketPool.Next != NULL ) {
s = PopEntryList( &Device->PacketPool );
packet = CONTAINING_RECORD( s, TP_PACKET, Linkage );
NbiDeallocateSendPacket (Device, packet);
}
//
// Clean up receive packet pool
//
while ( Device->ReceivePacketPool.Next != NULL) {
s = PopEntryList (&Device->ReceivePacketPool);
//
// HACK: This works because Linkage is the first field in
// ProtocolReserved for a receive packet.
//
ndisPacket = CONTAINING_RECORD (s, NDIS_PACKET, ProtocolReserved[0]);
NbiDeallocateReceivePacket (Device, ndisPacket);
}
//
// Clean up receive buffer pool.
//
while ( Device->ReceiveBufferPool.Next != NULL ) {
s = PopEntryList( &Device->ReceiveBufferPool );
BufferTag = CONTAINING_RECORD (s, BUFFER_TAG, Linkage );
NbiDeallocateReceiveBuffer (Device, BufferTag);
}
#endif
} /* NbiFreeResources */
NTSTATUS
NbiDispatchOpenClose(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
/*++
Routine Description:
This routine is the main dispatch routine for the IPXNB device driver.
It accepts an I/O Request Packet, performs the request, and then
returns with the appropriate status.
Arguments:
DeviceObject - Pointer to the device object for this driver.
Irp - Pointer to the request packet representing the I/O request.
Return Value:
The function value is the status of the operation.
--*/
{
CTELockHandle LockHandle;
PDEVICE Device = (PDEVICE)DeviceObject;
NTSTATUS Status = STATUS_UNSUCCESSFUL;
PFILE_FULL_EA_INFORMATION openType;
PADDRESS_FILE AddressFile;
PCONNECTION Connection;
PREQUEST Request;
UINT i;
NB_DEFINE_LOCK_HANDLE (LockHandle1)
NB_DEFINE_SYNC_CONTEXT (SyncContext)
#if !defined(_PNP_POWER)
if (Device->State != DEVICE_STATE_OPEN) {
Irp->IoStatus.Status = STATUS_INVALID_DEVICE_STATE;
IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
return STATUS_INVALID_DEVICE_STATE;
}
#endif !_PNP_POWER
//
// Allocate a request to track this IRP.
//
Request = NbiAllocateRequest (Device, Irp);
IF_NOT_ALLOCATED(Request) {
Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
return STATUS_INSUFFICIENT_RESOURCES;
}
//
// Make sure status information is consistent every time.
//
MARK_REQUEST_PENDING(Request);
REQUEST_STATUS(Request) = STATUS_PENDING;
REQUEST_INFORMATION(Request) = 0;
//
// Case on the function that is being performed by the requestor. If the
// operation is a valid one for this device, then make it look like it was
// successfully completed, where possible.
//
switch (REQUEST_MAJOR_FUNCTION(Request)) {
//
// The Create function opens a transport object (either address or
// connection). Access checking is performed on the specified
// address to ensure security of transport-layer addresses.
//
case IRP_MJ_CREATE:
#if defined(_PNP_POWER)
if (Device->State != DEVICE_STATE_OPEN) {
Status = STATUS_INVALID_DEVICE_STATE;
break;
}
#endif _PNP_POWER
openType = OPEN_REQUEST_EA_INFORMATION(Request);
if (openType != NULL) {
if (strncmp(openType->EaName,TdiTransportAddress,openType->EaNameLength) == 0)
{
Status = NbiOpenAddress (Device, Request);
break;
}
else if (strncmp(openType->EaName,TdiConnectionContext,openType->EaNameLength) == 0)
{
Status = NbiOpenConnection (Device, Request);
break;
}
} else {
NB_GET_LOCK (&Device->Lock, &LockHandle);
REQUEST_OPEN_CONTEXT(Request) = (PVOID)(Device->ControlChannelIdentifier);
++Device->ControlChannelIdentifier;
if (Device->ControlChannelIdentifier == 0) {
Device->ControlChannelIdentifier = 1;
}
NB_FREE_LOCK (&Device->Lock, LockHandle);
REQUEST_OPEN_TYPE(Request) = (PVOID)TDI_CONTROL_CHANNEL_FILE;
Status = STATUS_SUCCESS;
}
break;
case IRP_MJ_CLOSE:
#if defined(_PNP_POWER)
if ( (Device->State != DEVICE_STATE_OPEN) && (Device->State != DEVICE_STATE_LOADED) ) {
Status = STATUS_INVALID_DEVICE_STATE;
break;
}
#endif _PNP_POWER
//
// The Close function closes a transport endpoint, terminates
// all outstanding transport activity on the endpoint, and unbinds
// the endpoint from its transport address, if any. If this
// is the last transport endpoint bound to the address, then
// the address is removed from the provider.
//
switch ((ULONG_PTR)REQUEST_OPEN_TYPE(Request)) {
case TDI_TRANSPORT_ADDRESS_FILE:
AddressFile = (PADDRESS_FILE)REQUEST_OPEN_CONTEXT(Request);
//
// This creates a reference to AddressFile.
//
#if defined(_PNP_POWER)
Status = NbiVerifyAddressFile(AddressFile, CONFLICT_IS_OK);
#else
Status = NbiVerifyAddressFile(AddressFile);
#endif _PNP_POWER
if (!NT_SUCCESS (Status)) {
Status = STATUS_INVALID_HANDLE;
} else {
Status = NbiCloseAddressFile (Device, Request);
NbiDereferenceAddressFile (AddressFile, AFREF_VERIFY);
}
break;
case TDI_CONNECTION_FILE:
Connection = (PCONNECTION)REQUEST_OPEN_CONTEXT(Request);
//
// We don't call VerifyConnection because the I/O
// system should only give us one close and the file
// object should be valid. This helps avoid a window
// where two threads call HandleConnectionZero at the
// same time.
//
Status = NbiCloseConnection (Device, Request);
break;
case TDI_CONTROL_CHANNEL_FILE:
//
// See if it is one of the upper driver's control channels.
//
Status = STATUS_SUCCESS;
break;
default:
Status = STATUS_INVALID_HANDLE;
}
break;
case IRP_MJ_CLEANUP:
#if defined(_PNP_POWER)
if ( (Device->State != DEVICE_STATE_OPEN) && (Device->State != DEVICE_STATE_LOADED) ) {
Status = STATUS_INVALID_DEVICE_STATE;
break;
}
#endif _PNP_POWER
//
// Handle the two stage IRP for a file close operation. When the first
// stage hits, run down all activity on the object of interest. This
// do everything to it but remove the creation hold. Then, when the
// CLOSE irp hits, actually close the object.
//
switch ((ULONG_PTR)REQUEST_OPEN_TYPE(Request)) {
case TDI_TRANSPORT_ADDRESS_FILE:
AddressFile = (PADDRESS_FILE)REQUEST_OPEN_CONTEXT(Request);
#if defined(_PNP_POWER)
Status = NbiVerifyAddressFile(AddressFile, CONFLICT_IS_OK);
#else
Status = NbiVerifyAddressFile(AddressFile);
#endif _PNP_POWER
if (!NT_SUCCESS (Status)) {
Status = STATUS_INVALID_HANDLE;
} else {
NbiStopAddressFile (AddressFile, AddressFile->Address);
NbiDereferenceAddressFile (AddressFile, AFREF_VERIFY);
Status = STATUS_SUCCESS;
}
break;
case TDI_CONNECTION_FILE:
Connection = (PCONNECTION)REQUEST_OPEN_CONTEXT(Request);
Status = NbiVerifyConnection(Connection);
if (!NT_SUCCESS (Status)) {
Status = STATUS_INVALID_HANDLE;
} else {
NB_BEGIN_SYNC (&SyncContext);
NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle1);
//
// This call releases the lock.
//
NbiStopConnection(
Connection,
STATUS_INVALID_CONNECTION
NB_LOCK_HANDLE_ARG (LockHandle1));
NB_END_SYNC (&SyncContext);
NbiDereferenceConnection (Connection, CREF_VERIFY);
Status = STATUS_SUCCESS;
}
break;
case TDI_CONTROL_CHANNEL_FILE:
Status = STATUS_SUCCESS;
break;
default:
Status = STATUS_INVALID_HANDLE;
}
break;
default:
Status = STATUS_INVALID_DEVICE_REQUEST;
} /* major function switch */
if (Status != STATUS_PENDING) {
UNMARK_REQUEST_PENDING(Request);
REQUEST_STATUS(Request) = Status;
NbiCompleteRequest (Request);
NbiFreeRequest (Device, Request);
}
//
// Return the immediate status code to the caller.
//
return Status;
} /* NbiDispatchOpenClose */
NTSTATUS
NbiDispatchDeviceControl(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
/*++
Routine Description:
This routine dispatches TDI request types to different handlers based
on the minor IOCTL function code in the IRP's current stack location.
In addition to cracking the minor function code, this routine also
reaches into the IRP and passes the packetized parameters stored there
as parameters to the various TDI request handlers so that they are
not IRP-dependent.
Arguments:
DeviceObject - Pointer to the device object for this driver.
Irp - Pointer to the request packet representing the I/O request.
Return Value:
The function value is the status of the operation.
--*/
{
NTSTATUS Status;
PDEVICE Device = (PDEVICE)DeviceObject;
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation (Irp);
//
// Branch to the appropriate request handler. Preliminary checking of
// the size of the request block is performed here so that it is known
// in the handlers that the minimum input parameters are readable. It
// is *not* determined here whether variable length input fields are
// passed correctly; this is a check which must be made within each routine.
//
switch (IrpSp->Parameters.DeviceIoControl.IoControlCode) {
default:
//
// Convert the user call to the proper internal device call.
//
Status = TdiMapUserRequest (DeviceObject, Irp, IrpSp);
if (Status == STATUS_SUCCESS) {
//
// If TdiMapUserRequest returns SUCCESS then the IRP
// has been converted into an IRP_MJ_INTERNAL_DEVICE_CONTROL
// IRP, so we dispatch it as usual. The IRP will
// be completed by this call.
//
Status = NbiDispatchInternal (DeviceObject, Irp);
} else {
Irp->IoStatus.Status = Status;
IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
}
break;
}
return Status;
} /* NbiDeviceControl */
NB_TDI_DISPATCH_ROUTINE NbiDispatchInternalTable[] = {
NbiTdiAssociateAddress,
NbiTdiDisassociateAddress,
NbiTdiConnect,
NbiTdiListen,
NbiTdiAccept,
NbiTdiDisconnect,
NbiTdiSend,
NbiTdiReceive,
NbiTdiSendDatagram,
NbiTdiReceiveDatagram,
NbiTdiSetEventHandler,
NbiTdiQueryInformation,
NbiTdiSetInformation,
NbiTdiAction
};
NTSTATUS
NbiDispatchInternal(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
/*++
Routine Description:
This routine dispatches TDI request types to different handlers based
on the minor IOCTL function code in the IRP's current stack location.
In addition to cracking the minor function code, this routine also
reaches into the IRP and passes the packetized parameters stored there
as parameters to the various TDI request handlers so that they are
not IRP-dependent.
Arguments:
DeviceObject - Pointer to the device object for this driver.
Irp - Pointer to the request packet representing the I/O request.
Return Value:
The function value is the status of the operation.
--*/
{
NTSTATUS Status;
PDEVICE Device = (PDEVICE)DeviceObject;
PREQUEST Request;
UCHAR MinorFunction;
if (Device->State != DEVICE_STATE_OPEN) {
Irp->IoStatus.Status = STATUS_INVALID_DEVICE_STATE;
IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
return STATUS_INVALID_DEVICE_STATE;
}
//
// Allocate a request to track this IRP.
//
Request = NbiAllocateRequest (Device, Irp);
IF_NOT_ALLOCATED(Request) {
Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
return STATUS_INSUFFICIENT_RESOURCES;
}
//
// Make sure status information is consistent every time.
//
MARK_REQUEST_PENDING(Request);
REQUEST_STATUS(Request) = STATUS_PENDING;
REQUEST_INFORMATION(Request) = 0;
//
// Branch to the appropriate request handler.
//
MinorFunction = REQUEST_MINOR_FUNCTION(Request) - 1;
if (MinorFunction <= (TDI_ACTION-1)) {
Status = (*NbiDispatchInternalTable[MinorFunction]) (
Device,
Request);
} else {
NB_DEBUG (DRIVER, ("Unsupported minor code %d\n", MinorFunction+1));
if ((MinorFunction+1) == TDI_DISCONNECT) {
Status = STATUS_SUCCESS;
} else {
Status = STATUS_INVALID_DEVICE_REQUEST;
}
}
if (Status != STATUS_PENDING) {
UNMARK_REQUEST_PENDING(Request);
REQUEST_STATUS(Request) = Status;
NbiCompleteRequest (Request);
NbiFreeRequest (Device, Request);
}
//
// Return the immediate status code to the caller.
//
return Status;
} /* NbiDispatchInternal */
PVOID
NbipAllocateMemory(
IN ULONG BytesNeeded,
IN ULONG Tag,
IN BOOLEAN ChargeDevice
)
/*++
Routine Description:
This routine allocates memory, making sure it is within
the limit allowed by the device.
Arguments:
BytesNeeded - The number of bytes to allocated.
ChargeDevice - TRUE if the device should be charged.
Return Value:
None.
--*/
{
PVOID Memory;
PDEVICE Device = NbiDevice;
if (ChargeDevice) {
if ((Device->MemoryLimit != 0) &&
(((LONG)(Device->MemoryUsage + BytesNeeded) >
Device->MemoryLimit))) {
NbiPrint1 ("Nbi: Could not allocate %d: limit\n", BytesNeeded);
NbiWriteResourceErrorLog (Device, BytesNeeded, Tag);
return NULL;
}
}
#if ISN_NT
Memory = ExAllocatePoolWithTag (NonPagedPool, BytesNeeded, ' IBN');
#else
Memory = CTEAllocMem (BytesNeeded);
#endif
if (Memory == NULL) {
NbiPrint1("Nbi: Could not allocate %d: no pool\n", BytesNeeded);
if (ChargeDevice) {
NbiWriteResourceErrorLog (Device, BytesNeeded, Tag);
}
return NULL;
}
if (ChargeDevice) {
Device->MemoryUsage += BytesNeeded;
}
return Memory;
} /* NbipAllocateMemory */
VOID
NbipFreeMemory(
IN PVOID Memory,
IN ULONG BytesAllocated,
IN BOOLEAN ChargeDevice
)
/*++
Routine Description:
This routine frees memory allocated with NbipAllocateMemory.
Arguments:
Memory - The memory allocated.
BytesAllocated - The number of bytes to freed.
ChargeDevice - TRUE if the device should be charged.
Return Value:
None.
--*/
{
PDEVICE Device = NbiDevice;
#if ISN_NT
ExFreePool (Memory);
#else
CTEFreeMem (Memory);
#endif
if (ChargeDevice) {
Device->MemoryUsage -= BytesAllocated;
}
} /* NbipFreeMemory */
#if DBG
PVOID
NbipAllocateTaggedMemory(
IN ULONG BytesNeeded,
IN ULONG Tag,
IN PUCHAR Description
)
/*++
Routine Description:
This routine allocates memory, charging it to the device.
If it cannot allocate memory it uses the Tag and Descriptor
to log an error.
Arguments:
BytesNeeded - The number of bytes to allocated.
Tag - A unique ID used in the error log.
Description - A text description of the allocation.
Return Value:
None.
--*/
{
PVOID Memory;
UNREFERENCED_PARAMETER(Description);
Memory = NbipAllocateMemory(BytesNeeded, Tag, (BOOLEAN)(Tag != MEMORY_CONFIG));
if (Memory) {
ExInterlockedAddUlong(
&NbiMemoryTag[Tag].BytesAllocated,
BytesNeeded,
&NbiMemoryInterlock);
}
return Memory;
} /* NbipAllocateTaggedMemory */
VOID
NbipFreeTaggedMemory(
IN PVOID Memory,
IN ULONG BytesAllocated,
IN ULONG Tag,
IN PUCHAR Description
)
/*++
Routine Description:
This routine frees memory allocated with NbipAllocateTaggedMemory.
Arguments:
Memory - The memory allocated.
BytesAllocated - The number of bytes to freed.
Tag - A unique ID used in the error log.
Description - A text description of the allocation.
Return Value:
None.
--*/
{
UNREFERENCED_PARAMETER(Description);
ExInterlockedAddUlong(
&NbiMemoryTag[Tag].BytesAllocated,
(ULONG)(-(LONG)BytesAllocated),
&NbiMemoryInterlock);
NbipFreeMemory (Memory, BytesAllocated, (BOOLEAN)(Tag != MEMORY_CONFIG));
} /* NbipFreeTaggedMemory */
#endif
VOID
NbiWriteResourceErrorLog(
IN PDEVICE Device,
IN ULONG BytesNeeded,
IN ULONG UniqueErrorValue
)
/*++
Routine Description:
This routine allocates and writes an error log entry indicating
an out of resources condition.
Arguments:
Device - Pointer to the device context.
BytesNeeded - If applicable, the number of bytes that could not
be allocated.
UniqueErrorValue - Used as the UniqueErrorValue in the error log
packet.
Return Value:
None.
--*/
{
PIO_ERROR_LOG_PACKET errorLogEntry;
UCHAR EntrySize;
PUCHAR StringLoc;
ULONG TempUniqueError;
static WCHAR UniqueErrorBuffer[4] = L"000";
INT i;
EntrySize = sizeof(IO_ERROR_LOG_PACKET) +
Device->DeviceString.MaximumLength +
sizeof(UniqueErrorBuffer);
errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(
(PDEVICE_OBJECT)Device,
EntrySize
);
//
// Convert the error value into a buffer.
//
TempUniqueError = UniqueErrorValue;
for (i=1; i>=0; i--) {
UniqueErrorBuffer[i] = (WCHAR)((TempUniqueError % 10) + L'0');
TempUniqueError /= 10;
}
if (errorLogEntry != NULL) {
errorLogEntry->MajorFunctionCode = (UCHAR)-1;
errorLogEntry->RetryCount = (UCHAR)-1;
errorLogEntry->DumpDataSize = sizeof(ULONG);
errorLogEntry->NumberOfStrings = 2;
errorLogEntry->StringOffset = sizeof(IO_ERROR_LOG_PACKET);
errorLogEntry->EventCategory = 0;
errorLogEntry->ErrorCode = EVENT_TRANSPORT_RESOURCE_POOL;
errorLogEntry->UniqueErrorValue = UniqueErrorValue;
errorLogEntry->FinalStatus = STATUS_INSUFFICIENT_RESOURCES;
errorLogEntry->SequenceNumber = (ULONG)-1;
errorLogEntry->IoControlCode = 0;
errorLogEntry->DumpData[0] = BytesNeeded;
StringLoc = ((PUCHAR)errorLogEntry) + errorLogEntry->StringOffset;
RtlCopyMemory (StringLoc, Device->DeviceString.Buffer, Device->DeviceString.MaximumLength);
StringLoc += Device->DeviceString.MaximumLength;
RtlCopyMemory (StringLoc, UniqueErrorBuffer, sizeof(UniqueErrorBuffer));
IoWriteErrorLogEntry(errorLogEntry);
}
} /* NbiWriteResourceErrorLog */
VOID
NbiWriteGeneralErrorLog(
IN PDEVICE Device,
IN NTSTATUS ErrorCode,
IN ULONG UniqueErrorValue,
IN NTSTATUS FinalStatus,
IN PWSTR SecondString,
IN ULONG DumpDataCount,
IN ULONG DumpData[]
)
/*++
Routine Description:
This routine allocates and writes an error log entry indicating
a general problem as indicated by the parameters. It handles
event codes REGISTER_FAILED, BINDING_FAILED, ADAPTER_NOT_FOUND,
TRANSFER_DATA, TOO_MANY_LINKS, and BAD_PROTOCOL. All these
events have messages with one or two strings in them.
Arguments:
Device - Pointer to the device context, or this may be
a driver object instead.
ErrorCode - The transport event code.
UniqueErrorValue - Used as the UniqueErrorValue in the error log
packet.
FinalStatus - Used as the FinalStatus in the error log packet.
SecondString - If not NULL, the string to use as the %3
value in the error log packet.
DumpDataCount - The number of ULONGs of dump data.
DumpData - Dump data for the packet.
Return Value:
None.
--*/
{
PIO_ERROR_LOG_PACKET errorLogEntry;
UCHAR EntrySize;
ULONG SecondStringSize;
PUCHAR StringLoc;
static WCHAR DriverName[8] = L"NwlnkNb";
EntrySize = (UCHAR)(sizeof(IO_ERROR_LOG_PACKET) +
(DumpDataCount * sizeof(ULONG)));
if (Device->Type == IO_TYPE_DEVICE) {
EntrySize += (UCHAR)Device->DeviceString.MaximumLength;
} else {
EntrySize += sizeof(DriverName);
}
if (SecondString) {
SecondStringSize = (wcslen(SecondString)*sizeof(WCHAR)) + sizeof(UNICODE_NULL);
EntrySize += (UCHAR)SecondStringSize;
}
errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(
(PDEVICE_OBJECT)Device,
EntrySize
);
if (errorLogEntry != NULL) {
errorLogEntry->MajorFunctionCode = (UCHAR)-1;
errorLogEntry->RetryCount = (UCHAR)-1;
errorLogEntry->DumpDataSize = (USHORT)(DumpDataCount * sizeof(ULONG));
errorLogEntry->NumberOfStrings = (SecondString == NULL) ? 1 : 2;
errorLogEntry->StringOffset =
(USHORT)(sizeof(IO_ERROR_LOG_PACKET) + ((DumpDataCount-1) * sizeof(ULONG)));
errorLogEntry->EventCategory = 0;
errorLogEntry->ErrorCode = ErrorCode;
errorLogEntry->UniqueErrorValue = UniqueErrorValue;
errorLogEntry->FinalStatus = FinalStatus;
errorLogEntry->SequenceNumber = (ULONG)-1;
errorLogEntry->IoControlCode = 0;
if (DumpDataCount) {
RtlCopyMemory(errorLogEntry->DumpData, DumpData, DumpDataCount * sizeof(ULONG));
}
StringLoc = ((PUCHAR)errorLogEntry) + errorLogEntry->StringOffset;
if (Device->Type == IO_TYPE_DEVICE) {
RtlCopyMemory (StringLoc, Device->DeviceString.Buffer, Device->DeviceString.MaximumLength);
StringLoc += Device->DeviceString.MaximumLength;
} else {
RtlCopyMemory (StringLoc, DriverName, sizeof(DriverName));
StringLoc += sizeof(DriverName);
}
if (SecondString) {
RtlCopyMemory (StringLoc, SecondString, SecondStringSize);
}
IoWriteErrorLogEntry(errorLogEntry);
}
} /* NbiWriteGeneralErrorLog */
VOID
NbiWriteOidErrorLog(
IN PDEVICE Device,
IN NTSTATUS ErrorCode,
IN NTSTATUS FinalStatus,
IN PWSTR AdapterString,
IN ULONG OidValue
)
/*++
Routine Description:
This routine allocates and writes an error log entry indicating
a problem querying or setting an OID on an adapter. It handles
event codes SET_OID_FAILED and QUERY_OID_FAILED.
Arguments:
Device - Pointer to the device context.
ErrorCode - Used as the ErrorCode in the error log packet.
FinalStatus - Used as the FinalStatus in the error log packet.
AdapterString - The name of the adapter we were bound to.
OidValue - The OID which could not be set or queried.
Return Value:
None.
--*/
{
PIO_ERROR_LOG_PACKET errorLogEntry;
UCHAR EntrySize;
ULONG AdapterStringSize;
PUCHAR StringLoc;
static WCHAR OidBuffer[9] = L"00000000";
INT i;
UINT CurrentDigit;
AdapterStringSize = (wcslen(AdapterString)*sizeof(WCHAR)) + sizeof(UNICODE_NULL);
EntrySize = (UCHAR)(sizeof(IO_ERROR_LOG_PACKET) -
sizeof(ULONG) +
Device->DeviceString.MaximumLength +
AdapterStringSize +
sizeof(OidBuffer));
errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(
(PDEVICE_OBJECT)Device,
EntrySize
);
//
// Convert the OID into a buffer.
//
for (i=7; i>=0; i--) {
CurrentDigit = OidValue & 0xf;
OidValue >>= 4;
if (CurrentDigit >= 0xa) {
OidBuffer[i] = (WCHAR)(CurrentDigit - 0xa + L'A');
} else {
OidBuffer[i] = (WCHAR)(CurrentDigit + L'0');
}
}
if (errorLogEntry != NULL) {
errorLogEntry->MajorFunctionCode = (UCHAR)-1;
errorLogEntry->RetryCount = (UCHAR)-1;
errorLogEntry->DumpDataSize = 0;
errorLogEntry->NumberOfStrings = 3;
errorLogEntry->StringOffset = sizeof(IO_ERROR_LOG_PACKET) - sizeof(ULONG);
errorLogEntry->EventCategory = 0;
errorLogEntry->ErrorCode = ErrorCode;
errorLogEntry->UniqueErrorValue = 0;
errorLogEntry->FinalStatus = FinalStatus;
errorLogEntry->SequenceNumber = (ULONG)-1;
errorLogEntry->IoControlCode = 0;
StringLoc = ((PUCHAR)errorLogEntry) + errorLogEntry->StringOffset;
RtlCopyMemory (StringLoc, Device->DeviceString.Buffer, Device->DeviceString.MaximumLength);
StringLoc += Device->DeviceString.MaximumLength;
RtlCopyMemory (StringLoc, OidBuffer, sizeof(OidBuffer));
StringLoc += sizeof(OidBuffer);
RtlCopyMemory (StringLoc, AdapterString, AdapterStringSize);
IoWriteErrorLogEntry(errorLogEntry);
}
} /* NbiWriteOidErrorLog */
//----------------------------------------------------------------------------
NTSTATUS
NbiDispatchPnP(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP pIrp
)
{
PVOID PDOInfo = NULL;
PIO_STACK_LOCATION pIrpSp;
PREQUEST Request;
PCONNECTION Connection;
PDEVICE_RELATIONS pDeviceRelations = NULL;
PVOID pnpDeviceContext = NULL;
PDEVICE Device = (PDEVICE)DeviceObject;
NTSTATUS Status = STATUS_INVALID_DEVICE_REQUEST;
Request = NbiAllocateRequest (Device, pIrp);
Connection = (PCONNECTION)REQUEST_OPEN_CONTEXT(Request); // This references the connection.
pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
switch (pIrpSp->MinorFunction)
{
case IRP_MN_QUERY_DEVICE_RELATIONS:
{
if (pIrpSp->Parameters.QueryDeviceRelations.Type == TargetDeviceRelation)
{
//
// Check for a valid Connection file type and Connection Context itself
//
if ((REQUEST_OPEN_TYPE(Request) == (PVOID)TDI_CONNECTION_FILE) &&
(NT_SUCCESS (NbiVerifyConnection (Connection))))
{
if (pDeviceRelations = (PDEVICE_RELATIONS) NbipAllocateMemory (sizeof (DEVICE_RELATIONS),
MEMORY_QUERY,
FALSE))
{
Status = (*Device->Bind.QueryHandler) (IPX_QUERY_DEVICE_RELATION,
&Connection->LocalTarget.NicHandle,
&pnpDeviceContext,
sizeof (PVOID),
NULL);
if (STATUS_SUCCESS == Status)
{
CTEAssert (pnpDeviceContext);
ObReferenceObject (pnpDeviceContext);
//
// TargetDeviceRelation allows exactly one PDO. fill it up.
//
pDeviceRelations->Count = 1;
pDeviceRelations->Objects[0] = pnpDeviceContext;
//
// invoker of this irp will free the information buffer.
//
}
else
{
NbipFreeMemory (pDeviceRelations, sizeof (DEVICE_RELATIONS), FALSE);
pDeviceRelations = NULL;
}
}
else
{
Status = STATUS_INSUFFICIENT_RESOURCES;
}
NbiDereferenceConnection (Connection, CREF_VERIFY);
}
else if (REQUEST_OPEN_TYPE(Request) == (PVOID)TDI_TRANSPORT_ADDRESS_FILE)
{
Status = STATUS_UNSUCCESSFUL;
}
}
break;
}
default:
{
break;
}
}
REQUEST_STATUS(Request) = Status;
REQUEST_INFORMATION(Request) = (ULONG_PTR) pDeviceRelations;
NbiCompleteRequest (Request);
NbiFreeRequest (Device, Request);
return Status;
}