1628 lines
40 KiB
C
1628 lines
40 KiB
C
/*++
|
||
|
||
Copyright (c) 1989-1993 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
stdrvr.c
|
||
|
||
Abstract:
|
||
|
||
This module contains code which defines the NT Sample
|
||
transport provider's device object.
|
||
|
||
Environment:
|
||
|
||
Kernel mode
|
||
|
||
Revision History:
|
||
|
||
|
||
--*/
|
||
|
||
#include "st.h"
|
||
|
||
|
||
//
|
||
// This is a list of all the device contexts that ST owns,
|
||
// used while unloading.
|
||
//
|
||
|
||
LIST_ENTRY StDeviceList = {0,0}; // initialized for real at runtime.
|
||
|
||
|
||
|
||
//
|
||
// Forward declaration of various routines used in this module.
|
||
//
|
||
|
||
NTSTATUS
|
||
DriverEntry(
|
||
IN PDRIVER_OBJECT DriverObject,
|
||
IN PUNICODE_STRING RegistryPath
|
||
);
|
||
|
||
VOID
|
||
StUnload(
|
||
IN PDRIVER_OBJECT DriverObject
|
||
);
|
||
|
||
NTSTATUS
|
||
StConfigureTransport (
|
||
IN PUNICODE_STRING RegistryPath,
|
||
IN PCONFIG_DATA * ConfigData
|
||
);
|
||
|
||
VOID
|
||
StFreeConfigurationInfo (
|
||
IN PCONFIG_DATA ConfigurationInfo
|
||
);
|
||
|
||
NTSTATUS
|
||
StDeviceControl(
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp,
|
||
IN PIO_STACK_LOCATION IrpSp
|
||
);
|
||
|
||
NTSTATUS
|
||
StOpenAddress(
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp,
|
||
IN PIO_STACK_LOCATION IrpSp
|
||
);
|
||
|
||
NTSTATUS
|
||
StCloseAddress(
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp,
|
||
IN PIO_STACK_LOCATION IrpSp
|
||
);
|
||
|
||
NTSTATUS
|
||
StOpenConnection(
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp,
|
||
IN PIO_STACK_LOCATION IrpSp
|
||
);
|
||
|
||
NTSTATUS
|
||
StCloseConnection(
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp,
|
||
IN PIO_STACK_LOCATION IrpSp
|
||
);
|
||
|
||
NTSTATUS
|
||
StTdiAccept(
|
||
IN PIRP Irp
|
||
);
|
||
|
||
NTSTATUS
|
||
StTdiConnect(
|
||
IN PIRP Irp
|
||
);
|
||
|
||
NTSTATUS
|
||
StTdiDisconnect(
|
||
IN PIRP Irp
|
||
);
|
||
|
||
NTSTATUS
|
||
StTdiDisassociateAddress (
|
||
IN PIRP Irp
|
||
);
|
||
|
||
NTSTATUS
|
||
StTdiAssociateAddress(
|
||
IN PIRP Irp
|
||
);
|
||
|
||
NTSTATUS
|
||
StTdiListen(
|
||
IN PIRP Irp
|
||
);
|
||
|
||
NTSTATUS
|
||
StTdiQueryInformation(
|
||
IN PDEVICE_CONTEXT DeviceContext,
|
||
IN PIRP Irp
|
||
);
|
||
|
||
NTSTATUS
|
||
StTdiReceive(
|
||
IN PIRP Irp
|
||
);
|
||
|
||
NTSTATUS
|
||
StTdiReceiveDatagram(
|
||
IN PIRP Irp
|
||
);
|
||
|
||
NTSTATUS
|
||
StTdiSend(
|
||
IN PIRP Irp
|
||
);
|
||
|
||
NTSTATUS
|
||
StTdiSendDatagram(
|
||
IN PIRP Irp
|
||
);
|
||
|
||
NTSTATUS
|
||
StTdiSetEventHandler(
|
||
IN PIRP Irp
|
||
);
|
||
|
||
NTSTATUS
|
||
StTdiSetInformation(
|
||
IN PIRP Irp
|
||
);
|
||
|
||
VOID
|
||
StDeallocateResources(
|
||
IN PDEVICE_CONTEXT DeviceContext
|
||
);
|
||
|
||
#ifdef ALLOC_PRAGMA
|
||
#pragma alloc_text(INIT,DriverEntry)
|
||
#endif
|
||
|
||
|
||
|
||
NTSTATUS
|
||
DriverEntry(
|
||
IN PDRIVER_OBJECT DriverObject,
|
||
IN PUNICODE_STRING RegistryPath
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine performs initialization of the sample
|
||
transport driver. 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 ST's node in the registry.
|
||
|
||
Return Value:
|
||
|
||
The function value is the final status from the initialization operation.
|
||
|
||
--*/
|
||
|
||
{
|
||
ULONG i, j;
|
||
STRING nameString;
|
||
PDEVICE_CONTEXT DeviceContext;
|
||
PTP_REQUEST Request;
|
||
PTP_CONNECTION Connection;
|
||
PTP_ADDRESS_FILE AddressFile;
|
||
PTP_ADDRESS Address;
|
||
PTP_PACKET Packet;
|
||
PNDIS_PACKET NdisPacket;
|
||
PRECEIVE_PACKET_TAG ReceiveTag;
|
||
PBUFFER_TAG BufferTag;
|
||
NTSTATUS status;
|
||
UINT SuccessfulOpens;
|
||
UINT MaxUserData;
|
||
|
||
PCONFIG_DATA StConfig = NULL;
|
||
|
||
|
||
ASSERT (sizeof (SHORT) == 2);
|
||
|
||
//
|
||
// This allocates the CONFIG_DATA structure and returns
|
||
// it in StConfig.
|
||
//
|
||
|
||
status = StConfigureTransport(RegistryPath, &StConfig);
|
||
|
||
if (!NT_SUCCESS (status)) {
|
||
PANIC (" Failed to initialize transport, St initialization failed.\n");
|
||
return STATUS_INSUFFICIENT_RESOURCES;
|
||
}
|
||
|
||
//
|
||
// make ourselves known to the NDIS wrapper.
|
||
//
|
||
|
||
RtlInitString( &nameString, ST_DEVICE_NAME );
|
||
|
||
status = StRegisterProtocol (&nameString);
|
||
|
||
if (!NT_SUCCESS (status)) {
|
||
|
||
StFreeConfigurationInfo(StConfig);
|
||
PANIC ("StInitialize: RegisterProtocol failed!\n");
|
||
|
||
StWriteGeneralErrorLog(
|
||
(PVOID)DriverObject,
|
||
EVENT_TRANSPORT_REGISTER_FAILED,
|
||
607,
|
||
status,
|
||
NULL,
|
||
0,
|
||
NULL);
|
||
|
||
return STATUS_INSUFFICIENT_RESOURCES;
|
||
|
||
}
|
||
|
||
|
||
//
|
||
// Initialize the driver object with this driver's entry points.
|
||
//
|
||
|
||
DriverObject->MajorFunction [IRP_MJ_CREATE] = StDispatchOpenClose;
|
||
DriverObject->MajorFunction [IRP_MJ_CLOSE] = StDispatchOpenClose;
|
||
DriverObject->MajorFunction [IRP_MJ_CLEANUP] = StDispatchOpenClose;
|
||
DriverObject->MajorFunction [IRP_MJ_INTERNAL_DEVICE_CONTROL] = StDispatchInternal;
|
||
DriverObject->MajorFunction [IRP_MJ_DEVICE_CONTROL] = StDispatch;
|
||
|
||
DriverObject->DriverUnload = StUnload;
|
||
|
||
//
|
||
// Initialize the global list of devices.
|
||
//
|
||
|
||
InitializeListHead (&StDeviceList);
|
||
|
||
SuccessfulOpens = 0;
|
||
|
||
for (j=0;j<StConfig->NumAdapters;j++ ) {
|
||
|
||
|
||
//
|
||
// Loop through all the adapters that are in the configuration
|
||
// information structure. Allocate a device object for each
|
||
// one that we find.
|
||
//
|
||
|
||
status = StCreateDeviceContext (DriverObject, &StConfig->Names[StConfig->DevicesOffset+j], &DeviceContext);
|
||
|
||
if (!NT_SUCCESS (status)) {
|
||
continue;
|
||
}
|
||
|
||
//
|
||
// Initialize our counter that records memory usage.
|
||
//
|
||
|
||
DeviceContext->MemoryUsage = 0;
|
||
DeviceContext->MemoryLimit = StConfig->MaxMemoryUsage;
|
||
|
||
//
|
||
// Now fire up NDIS so this adapter talks
|
||
//
|
||
|
||
status = StInitializeNdis (DeviceContext,
|
||
StConfig,
|
||
j);
|
||
|
||
if (!NT_SUCCESS (status)) {
|
||
|
||
//
|
||
// Log an error.
|
||
//
|
||
|
||
StWriteGeneralErrorLog(
|
||
DeviceContext,
|
||
EVENT_TRANSPORT_BINDING_FAILED,
|
||
601,
|
||
status,
|
||
StConfig->Names[j].Buffer,
|
||
0,
|
||
NULL);
|
||
|
||
StDereferenceDeviceContext ("Initialize NDIS failed", DeviceContext);
|
||
continue;
|
||
|
||
}
|
||
|
||
|
||
//
|
||
// Initialize our provider information structure; since it
|
||
// doesn't change, we just keep it around and copy it to
|
||
// whoever requests it.
|
||
//
|
||
|
||
|
||
MacReturnMaxDataSize(
|
||
&DeviceContext->MacInfo,
|
||
NULL,
|
||
0,
|
||
DeviceContext->MaxSendPacketSize,
|
||
&MaxUserData);
|
||
|
||
DeviceContext->Information.Version = 0x0100;
|
||
DeviceContext->Information.MaxSendSize = 0x1fffe; // 128k - 2
|
||
DeviceContext->Information.MaxConnectionUserData = 0;
|
||
DeviceContext->Information.MaxDatagramSize = MaxUserData - sizeof(ST_HEADER);
|
||
DeviceContext->Information.ServiceFlags = ST_SERVICE_FLAGS;
|
||
DeviceContext->Information.MinimumLookaheadData = 128;
|
||
DeviceContext->Information.MaximumLookaheadData =
|
||
DeviceContext->MaxReceivePacketSize - sizeof(ST_HEADER);
|
||
DeviceContext->Information.NumberOfResources = ST_TDI_RESOURCES;
|
||
KeQuerySystemTime (&DeviceContext->Information.StartTime);
|
||
|
||
|
||
//
|
||
// Allocate various structures we will need.
|
||
//
|
||
|
||
|
||
//
|
||
// The TP_PACKET structure has a CHAR[1] field at the end
|
||
// which we expand upon to include all the headers needed;
|
||
// the size of the MAC header depends on what the adapter
|
||
// told us about its max header size.
|
||
//
|
||
|
||
DeviceContext->PacketHeaderLength =
|
||
DeviceContext->MacInfo.MaxHeaderLength +
|
||
sizeof (ST_HEADER);
|
||
|
||
DeviceContext->PacketLength =
|
||
FIELD_OFFSET(TP_PACKET, Header[0]) +
|
||
DeviceContext->PacketHeaderLength;
|
||
|
||
|
||
//
|
||
// The BUFFER_TAG structure has a CHAR[1] field at the end
|
||
// which we expand upong to include all the frame data.
|
||
//
|
||
|
||
DeviceContext->ReceiveBufferLength =
|
||
DeviceContext->MaxReceivePacketSize +
|
||
FIELD_OFFSET(BUFFER_TAG, Buffer[0]);
|
||
|
||
|
||
for (i=0; i<StConfig->InitRequests; i++) {
|
||
|
||
StAllocateRequest (DeviceContext, &Request);
|
||
|
||
if (Request == NULL) {
|
||
PANIC ("StInitialize: insufficient memory to allocate requests.\n");
|
||
status = STATUS_INSUFFICIENT_RESOURCES;
|
||
goto cleanup;
|
||
}
|
||
|
||
InsertTailList (&DeviceContext->RequestPool, &Request->Linkage);
|
||
}
|
||
|
||
DeviceContext->RequestInitAllocated = StConfig->InitRequests;
|
||
DeviceContext->RequestMaxAllocated = StConfig->MaxRequests;
|
||
|
||
|
||
for (i=0; i<StConfig->InitConnections; i++) {
|
||
|
||
StAllocateConnection (DeviceContext, &Connection);
|
||
|
||
if (Connection == NULL) {
|
||
PANIC ("StInitialize: insufficient memory to allocate connections.\n");
|
||
status = STATUS_INSUFFICIENT_RESOURCES;
|
||
goto cleanup;
|
||
}
|
||
|
||
InsertTailList (&DeviceContext->ConnectionPool, &Connection->LinkList);
|
||
}
|
||
|
||
DeviceContext->ConnectionInitAllocated = StConfig->InitConnections;
|
||
DeviceContext->ConnectionMaxAllocated = StConfig->MaxConnections;
|
||
|
||
|
||
for (i=0; i<StConfig->InitAddressFiles; i++) {
|
||
|
||
StAllocateAddressFile (DeviceContext, &AddressFile);
|
||
|
||
if (AddressFile == NULL) {
|
||
PANIC ("StInitialize: insufficient memory to allocate Address Files.\n");
|
||
status = STATUS_INSUFFICIENT_RESOURCES;
|
||
goto cleanup;
|
||
}
|
||
|
||
InsertTailList (&DeviceContext->AddressFilePool, &AddressFile->Linkage);
|
||
}
|
||
|
||
DeviceContext->AddressFileInitAllocated = StConfig->InitAddressFiles;
|
||
DeviceContext->AddressFileMaxAllocated = StConfig->MaxAddressFiles;
|
||
|
||
|
||
for (i=0; i<StConfig->InitAddresses; i++) {
|
||
|
||
StAllocateAddress (DeviceContext, &Address);
|
||
if (Address == NULL) {
|
||
PANIC ("StInitialize: insufficient memory to allocate addresses.\n");
|
||
status = STATUS_INSUFFICIENT_RESOURCES;
|
||
goto cleanup;
|
||
}
|
||
|
||
InsertTailList (&DeviceContext->AddressPool, &Address->Linkage);
|
||
}
|
||
|
||
DeviceContext->AddressInitAllocated = StConfig->InitAddresses;
|
||
DeviceContext->AddressMaxAllocated = StConfig->MaxAddresses;
|
||
|
||
|
||
for (i=0; i<StConfig->InitPackets; i++) {
|
||
|
||
StAllocateSendPacket (DeviceContext, &Packet);
|
||
if (Packet == NULL) {
|
||
PANIC ("StInitialize: insufficient memory to allocate packets.\n");
|
||
status = STATUS_INSUFFICIENT_RESOURCES;
|
||
goto cleanup;
|
||
}
|
||
|
||
PushEntryList (&DeviceContext->PacketPool, (PSINGLE_LIST_ENTRY)&Packet->Linkage);
|
||
}
|
||
|
||
DeviceContext->PacketInitAllocated = StConfig->InitPackets;
|
||
|
||
|
||
for (i=0; i<StConfig->InitReceivePackets; i++) {
|
||
|
||
StAllocateReceivePacket (DeviceContext, &NdisPacket);
|
||
|
||
if (NdisPacket == NULL) {
|
||
PANIC ("StInitialize: insufficient memory to allocate packet MDLs.\n");
|
||
status = STATUS_INSUFFICIENT_RESOURCES;
|
||
goto cleanup;
|
||
}
|
||
|
||
ReceiveTag = (PRECEIVE_PACKET_TAG)NdisPacket->ProtocolReserved;
|
||
PushEntryList (&DeviceContext->ReceivePacketPool, (PSINGLE_LIST_ENTRY)&ReceiveTag->Linkage);
|
||
|
||
}
|
||
|
||
DeviceContext->ReceivePacketInitAllocated = StConfig->InitReceivePackets;
|
||
|
||
|
||
for (i=0; i<StConfig->InitReceiveBuffers; i++) {
|
||
|
||
StAllocateReceiveBuffer (DeviceContext, &BufferTag);
|
||
|
||
if (BufferTag == NULL) {
|
||
PANIC ("StInitialize: Unable to allocate receive packet.\n");
|
||
status = STATUS_INSUFFICIENT_RESOURCES;
|
||
goto cleanup;
|
||
}
|
||
|
||
PushEntryList (&DeviceContext->ReceiveBufferPool, &BufferTag->Linkage);
|
||
|
||
}
|
||
|
||
DeviceContext->ReceiveBufferInitAllocated = StConfig->InitReceiveBuffers;
|
||
|
||
|
||
//
|
||
// Now link the device into the global list.
|
||
//
|
||
|
||
InsertTailList (&StDeviceList, &DeviceContext->Linkage);
|
||
|
||
DeviceContext->State = DEVICECONTEXT_STATE_OPEN;
|
||
|
||
++SuccessfulOpens;
|
||
|
||
continue;
|
||
|
||
cleanup:
|
||
|
||
StWriteResourceErrorLog (DeviceContext, DeviceContext->MemoryUsage, 501);
|
||
|
||
//
|
||
// Cleanup whatever device context we were initializing
|
||
// when we failed.
|
||
//
|
||
|
||
StFreeResources (DeviceContext);
|
||
StCloseNdis (DeviceContext);
|
||
StDereferenceDeviceContext ("Load failed", DeviceContext);
|
||
|
||
}
|
||
|
||
StFreeConfigurationInfo(StConfig);
|
||
|
||
return ((SuccessfulOpens > 0) ? STATUS_SUCCESS : STATUS_DEVICE_DOES_NOT_EXIST);
|
||
|
||
}
|
||
|
||
VOID
|
||
StUnload(
|
||
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 ST open.
|
||
|
||
Arguments:
|
||
|
||
DriverObject - Pointer to driver object created by the system.
|
||
|
||
Return Value:
|
||
|
||
None. When the function returns, the driver is unloaded.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
PDEVICE_CONTEXT DeviceContext;
|
||
PLIST_ENTRY p;
|
||
|
||
|
||
UNREFERENCED_PARAMETER (DriverObject);
|
||
|
||
//
|
||
// Walk the list of device contexts.
|
||
//
|
||
|
||
while (!IsListEmpty (&StDeviceList)) {
|
||
|
||
p = RemoveHeadList (&StDeviceList);
|
||
DeviceContext = CONTAINING_RECORD (p, DEVICE_CONTEXT, Linkage);
|
||
|
||
//
|
||
// Remove all the storage associated with the device.
|
||
//
|
||
|
||
StFreeResources (DeviceContext);
|
||
|
||
//
|
||
// Free the packet pools, etc. and close the
|
||
// adapter.
|
||
//
|
||
|
||
StCloseNdis (DeviceContext);
|
||
|
||
//
|
||
// And remove the creation reference from the device
|
||
// context.
|
||
//
|
||
|
||
StDereferenceDeviceContext ("Unload", DeviceContext);
|
||
|
||
}
|
||
|
||
|
||
//
|
||
// Finally, remove ourselves as an NDIS protocol.
|
||
//
|
||
|
||
StDeregisterProtocol();
|
||
|
||
return;
|
||
|
||
}
|
||
|
||
|
||
VOID
|
||
StFreeResources (
|
||
IN PDEVICE_CONTEXT DeviceContext
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is called by ST to clean up the data structures associated
|
||
with a given DeviceContext. When this routine exits, the DeviceContext
|
||
should be deleted as it no longer has any assocaited resources.
|
||
|
||
Arguments:
|
||
|
||
DeviceContext - Pointer to the DeviceContext we wish to clean up.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
{
|
||
PLIST_ENTRY p;
|
||
PSINGLE_LIST_ENTRY s;
|
||
PTP_PACKET packet;
|
||
PTP_ADDRESS address;
|
||
PTP_CONNECTION connection;
|
||
PTP_REQUEST request;
|
||
PTP_ADDRESS_FILE addressFile;
|
||
PNDIS_PACKET ndisPacket;
|
||
PBUFFER_TAG BufferTag;
|
||
|
||
|
||
//
|
||
// Clean up packet pool.
|
||
//
|
||
|
||
while ( DeviceContext->PacketPool.Next != NULL ) {
|
||
s = PopEntryList( &DeviceContext->PacketPool );
|
||
packet = CONTAINING_RECORD( s, TP_PACKET, Linkage );
|
||
|
||
StDeallocateSendPacket (DeviceContext, packet);
|
||
}
|
||
|
||
//
|
||
// Clean up address pool.
|
||
//
|
||
|
||
while ( !IsListEmpty (&DeviceContext->AddressPool) ) {
|
||
p = RemoveHeadList (&DeviceContext->AddressPool);
|
||
address = CONTAINING_RECORD (p, TP_ADDRESS, Linkage);
|
||
|
||
StDeallocateAddress (DeviceContext, address);
|
||
}
|
||
|
||
//
|
||
// Clean up address file pool.
|
||
//
|
||
|
||
while ( !IsListEmpty (&DeviceContext->AddressFilePool) ) {
|
||
p = RemoveHeadList (&DeviceContext->AddressFilePool);
|
||
addressFile = CONTAINING_RECORD (p, TP_ADDRESS_FILE, Linkage);
|
||
|
||
StDeallocateAddressFile (DeviceContext, addressFile);
|
||
}
|
||
|
||
//
|
||
// Clean up connection pool.
|
||
//
|
||
|
||
while ( !IsListEmpty (&DeviceContext->ConnectionPool) ) {
|
||
p = RemoveHeadList (&DeviceContext->ConnectionPool);
|
||
connection = CONTAINING_RECORD (p, TP_CONNECTION, LinkList);
|
||
|
||
StDeallocateConnection (DeviceContext, connection);
|
||
}
|
||
|
||
//
|
||
// Clean up request pool.
|
||
//
|
||
|
||
while ( !IsListEmpty( &DeviceContext->RequestPool ) ) {
|
||
p = RemoveHeadList( &DeviceContext->RequestPool );
|
||
request = CONTAINING_RECORD (p, TP_REQUEST, Linkage );
|
||
|
||
StDeallocateRequest (DeviceContext, request);
|
||
}
|
||
|
||
//
|
||
// Clean up receive packet pool
|
||
//
|
||
|
||
while ( DeviceContext->ReceivePacketPool.Next != NULL) {
|
||
s = PopEntryList (&DeviceContext->ReceivePacketPool);
|
||
|
||
//
|
||
// HACK: This works because Linkage is the first field in
|
||
// ProtocolReserved for a receive packet.
|
||
//
|
||
|
||
ndisPacket = CONTAINING_RECORD (s, NDIS_PACKET, ProtocolReserved[0]);
|
||
|
||
StDeallocateReceivePacket (DeviceContext, ndisPacket);
|
||
}
|
||
|
||
|
||
//
|
||
// Clean up receive buffer pool.
|
||
//
|
||
|
||
while ( DeviceContext->ReceiveBufferPool.Next != NULL ) {
|
||
s = PopEntryList( &DeviceContext->ReceiveBufferPool );
|
||
BufferTag = CONTAINING_RECORD (s, BUFFER_TAG, Linkage );
|
||
|
||
StDeallocateReceiveBuffer (DeviceContext, BufferTag);
|
||
}
|
||
|
||
|
||
return;
|
||
|
||
} /* StFreeResources */
|
||
|
||
|
||
NTSTATUS
|
||
StDispatch(
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is the main dispatch routine for the ST 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.
|
||
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS Status;
|
||
PIO_STACK_LOCATION IrpSp;
|
||
PDEVICE_CONTEXT DeviceContext;
|
||
|
||
//
|
||
// Check to see if ST has been initialized; if not, don't allow any use.
|
||
// Note that this only covers any user mode code use; kernel TDI clients
|
||
// will fail on their creation of an endpoint.
|
||
//
|
||
|
||
DeviceContext = (PDEVICE_CONTEXT)DeviceObject;
|
||
if (DeviceContext->State != DEVICECONTEXT_STATE_OPEN) {
|
||
Irp->IoStatus.Status = STATUS_INVALID_DEVICE_STATE;
|
||
IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
|
||
return STATUS_INVALID_DEVICE_STATE;
|
||
}
|
||
|
||
//
|
||
// Make sure status information is consistent every time.
|
||
//
|
||
|
||
IoMarkIrpPending (Irp);
|
||
Irp->IoStatus.Status = STATUS_PENDING;
|
||
Irp->IoStatus.Information = 0;
|
||
|
||
//
|
||
// Get a pointer to the current stack location in the IRP. This is where
|
||
// the function codes and parameters are stored.
|
||
//
|
||
|
||
IrpSp = IoGetCurrentIrpStackLocation (Irp);
|
||
|
||
//
|
||
// 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 (IrpSp->MajorFunction) {
|
||
|
||
case IRP_MJ_DEVICE_CONTROL:
|
||
Status = StDeviceControl (DeviceObject, Irp, IrpSp);
|
||
break;
|
||
|
||
default:
|
||
Status = STATUS_INVALID_DEVICE_REQUEST;
|
||
|
||
} /* major function switch */
|
||
|
||
if (Status != STATUS_PENDING) {
|
||
IrpSp->Control &= ~SL_PENDING_RETURNED;
|
||
Irp->IoStatus.Status = Status;
|
||
IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
|
||
}
|
||
|
||
//
|
||
// Return the immediate status code to the caller.
|
||
//
|
||
|
||
return Status;
|
||
} /* StDispatch */
|
||
|
||
|
||
NTSTATUS
|
||
StDispatchOpenClose(
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is the main dispatch routine for the ST 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.
|
||
|
||
--*/
|
||
|
||
{
|
||
KIRQL oldirql;
|
||
PDEVICE_CONTEXT DeviceContext;
|
||
NTSTATUS Status;
|
||
PIO_STACK_LOCATION IrpSp;
|
||
PFILE_FULL_EA_INFORMATION openType;
|
||
USHORT i;
|
||
BOOLEAN found;
|
||
PTP_ADDRESS_FILE AddressFile;
|
||
PTP_CONNECTION Connection;
|
||
|
||
//
|
||
// Check to see if ST has been initialized; if not, don't allow any use.
|
||
// Note that this only covers any user mode code use; kernel TDI clients
|
||
// will fail on their creation of an endpoint.
|
||
//
|
||
|
||
DeviceContext = (PDEVICE_CONTEXT)DeviceObject;
|
||
if (DeviceContext->State != DEVICECONTEXT_STATE_OPEN) {
|
||
Irp->IoStatus.Status = STATUS_INVALID_DEVICE_STATE;
|
||
IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
|
||
return STATUS_INVALID_DEVICE_STATE;
|
||
}
|
||
|
||
//
|
||
// Make sure status information is consistent every time.
|
||
//
|
||
|
||
IoMarkIrpPending (Irp);
|
||
Irp->IoStatus.Status = STATUS_PENDING;
|
||
Irp->IoStatus.Information = 0;
|
||
|
||
//
|
||
// Get a pointer to the current stack location in the IRP. This is where
|
||
// the function codes and parameters are stored.
|
||
//
|
||
|
||
IrpSp = IoGetCurrentIrpStackLocation (Irp);
|
||
|
||
//
|
||
// 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 (IrpSp->MajorFunction) {
|
||
|
||
//
|
||
// 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:
|
||
|
||
openType =
|
||
(PFILE_FULL_EA_INFORMATION)Irp->AssociatedIrp.SystemBuffer;
|
||
|
||
if (openType != NULL) {
|
||
|
||
found = TRUE;
|
||
|
||
for (i=0;i<(USHORT)openType->EaNameLength;i++) {
|
||
if (openType->EaName[i] == TdiTransportAddress[i]) {
|
||
continue;
|
||
} else {
|
||
found = FALSE;
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (found) {
|
||
Status = StOpenAddress (DeviceObject, Irp, IrpSp);
|
||
break;
|
||
}
|
||
|
||
//
|
||
// Connection?
|
||
//
|
||
|
||
found = TRUE;
|
||
|
||
for (i=0;i<(USHORT)openType->EaNameLength;i++) {
|
||
if (openType->EaName[i] == TdiConnectionContext[i]) {
|
||
continue;
|
||
} else {
|
||
found = FALSE;
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (found) {
|
||
Status = StOpenConnection (DeviceObject, Irp, IrpSp);
|
||
break;
|
||
}
|
||
|
||
} else {
|
||
|
||
ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock, &oldirql);
|
||
|
||
IrpSp->FileObject->FsContext = (PVOID)(DeviceContext->ControlChannelIdentifier);
|
||
++DeviceContext->ControlChannelIdentifier;
|
||
if (DeviceContext->ControlChannelIdentifier == 0) {
|
||
DeviceContext->ControlChannelIdentifier = 1;
|
||
}
|
||
|
||
RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
|
||
|
||
IrpSp->FileObject->FsContext2 = (PVOID)ST_FILE_TYPE_CONTROL;
|
||
Status = STATUS_SUCCESS;
|
||
}
|
||
|
||
break;
|
||
|
||
case IRP_MJ_CLOSE:
|
||
|
||
//
|
||
// 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)IrpSp->FileObject->FsContext2) {
|
||
case TDI_TRANSPORT_ADDRESS_FILE:
|
||
AddressFile = (PTP_ADDRESS_FILE)IrpSp->FileObject->FsContext;
|
||
|
||
//
|
||
// This creates a reference to AddressFile->Address
|
||
// which is removed by StCloseAddress.
|
||
//
|
||
|
||
Status = StVerifyAddressObject(AddressFile);
|
||
|
||
if (!NT_SUCCESS (Status)) {
|
||
Status = STATUS_INVALID_HANDLE;
|
||
} else {
|
||
Status = StCloseAddress (DeviceObject, Irp, IrpSp);
|
||
}
|
||
|
||
break;
|
||
|
||
case TDI_CONNECTION_FILE:
|
||
|
||
//
|
||
// This is a connection
|
||
//
|
||
|
||
Connection = (PTP_CONNECTION)IrpSp->FileObject->FsContext;
|
||
Status = StVerifyConnectionObject (Connection);
|
||
if (NT_SUCCESS (Status)) {
|
||
|
||
Status = StCloseConnection (DeviceObject, Irp, IrpSp);
|
||
StDereferenceConnection ("Temporary Use",Connection);
|
||
|
||
}
|
||
|
||
break;
|
||
|
||
case ST_FILE_TYPE_CONTROL:
|
||
|
||
//
|
||
// this always succeeds
|
||
//
|
||
|
||
Status = STATUS_SUCCESS;
|
||
break;
|
||
|
||
default:
|
||
Status = STATUS_INVALID_HANDLE;
|
||
}
|
||
|
||
break;
|
||
|
||
case IRP_MJ_CLEANUP:
|
||
|
||
//
|
||
// 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)IrpSp->FileObject->FsContext2) {
|
||
case TDI_TRANSPORT_ADDRESS_FILE:
|
||
AddressFile = (PTP_ADDRESS_FILE)IrpSp->FileObject->FsContext;
|
||
Status = StVerifyAddressObject(AddressFile);
|
||
if (!NT_SUCCESS (Status)) {
|
||
|
||
Status = STATUS_INVALID_HANDLE;
|
||
|
||
} else {
|
||
|
||
StStopAddressFile (AddressFile, AddressFile->Address);
|
||
StDereferenceAddress ("IRP_MJ_CLEANUP", AddressFile->Address);
|
||
Status = STATUS_SUCCESS;
|
||
}
|
||
|
||
break;
|
||
|
||
case TDI_CONNECTION_FILE:
|
||
|
||
Connection = (PTP_CONNECTION)IrpSp->FileObject->FsContext;
|
||
Status = StVerifyConnectionObject (Connection);
|
||
if (NT_SUCCESS (Status)) {
|
||
StStopConnection (Connection, STATUS_LOCAL_DISCONNECT);
|
||
Status = STATUS_SUCCESS;
|
||
StDereferenceConnection ("Temporary Use",Connection);
|
||
}
|
||
|
||
break;
|
||
|
||
case ST_FILE_TYPE_CONTROL:
|
||
|
||
Status = STATUS_SUCCESS;
|
||
break;
|
||
|
||
default:
|
||
Status = STATUS_INVALID_HANDLE;
|
||
}
|
||
|
||
break;
|
||
|
||
default:
|
||
Status = STATUS_INVALID_DEVICE_REQUEST;
|
||
|
||
} /* major function switch */
|
||
|
||
if (Status != STATUS_PENDING) {
|
||
IrpSp->Control &= ~SL_PENDING_RETURNED;
|
||
Irp->IoStatus.Status = Status;
|
||
IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
|
||
}
|
||
|
||
|
||
//
|
||
// Return the immediate status code to the caller.
|
||
//
|
||
|
||
return Status;
|
||
} /* StDispatchOpenClose */
|
||
|
||
|
||
NTSTATUS
|
||
StDeviceControl(
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp,
|
||
IN PIO_STACK_LOCATION IrpSp
|
||
)
|
||
|
||
/*++
|
||
|
||
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.
|
||
|
||
IrpSp - Pointer to current IRP stack frame.
|
||
|
||
Return Value:
|
||
|
||
The function value is the status of the operation.
|
||
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS Status;
|
||
PDEVICE_CONTEXT DeviceContext = (PDEVICE_CONTEXT)DeviceObject;
|
||
|
||
|
||
//
|
||
// 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.
|
||
//
|
||
// StDispatchInternal expects to complete the IRP,
|
||
// so we change Status to PENDING so we don't.
|
||
//
|
||
|
||
(VOID)StDispatchInternal (DeviceObject, Irp);
|
||
Status = STATUS_PENDING;
|
||
|
||
}
|
||
}
|
||
|
||
return Status;
|
||
} /* StDeviceControl */
|
||
|
||
|
||
NTSTATUS
|
||
StDispatchInternal (
|
||
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_CONTEXT DeviceContext;
|
||
PIO_STACK_LOCATION IrpSp;
|
||
|
||
|
||
//
|
||
// Get a pointer to the current stack location in the IRP. This is where
|
||
// the function codes and parameters are stored.
|
||
//
|
||
|
||
IrpSp = IoGetCurrentIrpStackLocation (Irp);
|
||
|
||
DeviceContext = (PDEVICE_CONTEXT)DeviceObject;
|
||
|
||
|
||
if (DeviceContext->State != DEVICECONTEXT_STATE_OPEN) {
|
||
Irp->IoStatus.Status = STATUS_INVALID_DEVICE_STATE;
|
||
IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
|
||
return STATUS_INVALID_DEVICE_STATE;
|
||
}
|
||
|
||
|
||
//
|
||
// Make sure status information is consistent every time.
|
||
//
|
||
|
||
IoMarkIrpPending (Irp);
|
||
Irp->IoStatus.Status = STATUS_PENDING;
|
||
Irp->IoStatus.Information = 0;
|
||
|
||
|
||
//
|
||
// 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->MinorFunction) {
|
||
|
||
case TDI_ACCEPT:
|
||
Status = StTdiAccept (Irp);
|
||
break;
|
||
|
||
case TDI_ACTION:
|
||
Status = STATUS_SUCCESS;
|
||
break;
|
||
|
||
case TDI_ASSOCIATE_ADDRESS:
|
||
Status = StTdiAssociateAddress (Irp);
|
||
break;
|
||
|
||
case TDI_DISASSOCIATE_ADDRESS:
|
||
Status = StTdiDisassociateAddress (Irp);
|
||
break;
|
||
|
||
case TDI_CONNECT:
|
||
Status = StTdiConnect (Irp);
|
||
break;
|
||
|
||
case TDI_DISCONNECT:
|
||
Status = StTdiDisconnect (Irp);
|
||
break;
|
||
|
||
case TDI_LISTEN:
|
||
Status = StTdiListen (Irp);
|
||
break;
|
||
|
||
case TDI_QUERY_INFORMATION:
|
||
Status = StTdiQueryInformation (DeviceContext, Irp);
|
||
break;
|
||
|
||
case TDI_RECEIVE:
|
||
Status = StTdiReceive (Irp);
|
||
break;
|
||
|
||
case TDI_RECEIVE_DATAGRAM:
|
||
Status = StTdiReceiveDatagram (Irp);
|
||
break;
|
||
|
||
case TDI_SEND:
|
||
Status = StTdiSend (Irp);
|
||
break;
|
||
|
||
case TDI_SEND_DATAGRAM:
|
||
Status = StTdiSendDatagram (Irp);
|
||
break;
|
||
|
||
case TDI_SET_EVENT_HANDLER:
|
||
|
||
//
|
||
// Because this request will enable direct callouts from the
|
||
// transport provider at DISPATCH_LEVEL to a client-specified
|
||
// routine, this request is only valid in kernel mode, denying
|
||
// access to this request in user mode.
|
||
//
|
||
|
||
Status = StTdiSetEventHandler (Irp);
|
||
break;
|
||
|
||
case TDI_SET_INFORMATION:
|
||
Status = StTdiSetInformation (Irp);
|
||
break;
|
||
|
||
|
||
//
|
||
// Something we don't know about was submitted.
|
||
//
|
||
|
||
default:
|
||
Status = STATUS_INVALID_DEVICE_REQUEST;
|
||
}
|
||
|
||
if (Status != STATUS_PENDING) {
|
||
IrpSp->Control &= ~SL_PENDING_RETURNED;
|
||
Irp->IoStatus.Status = Status;
|
||
IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
|
||
}
|
||
|
||
|
||
//
|
||
// Return the immediate status code to the caller.
|
||
//
|
||
|
||
return Status;
|
||
|
||
} /* StDispatchInternal */
|
||
|
||
|
||
VOID
|
||
StWriteResourceErrorLog(
|
||
IN PDEVICE_CONTEXT DeviceContext,
|
||
IN ULONG BytesNeeded,
|
||
IN ULONG UniqueErrorValue
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine allocates and writes an error log entry indicating
|
||
an out of resources condition.
|
||
|
||
Arguments:
|
||
|
||
DeviceContext - 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";
|
||
UINT i;
|
||
|
||
|
||
EntrySize = sizeof(IO_ERROR_LOG_PACKET) +
|
||
DeviceContext->DeviceNameLength +
|
||
sizeof(UniqueErrorBuffer);
|
||
|
||
errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(
|
||
(PDEVICE_OBJECT)DeviceContext,
|
||
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, DeviceContext->DeviceName, DeviceContext->DeviceNameLength);
|
||
|
||
StringLoc += DeviceContext->DeviceNameLength;
|
||
RtlCopyMemory (StringLoc, UniqueErrorBuffer, sizeof(UniqueErrorBuffer));
|
||
|
||
IoWriteErrorLogEntry(errorLogEntry);
|
||
|
||
}
|
||
|
||
} /* StWriteResourceErrorLog */
|
||
|
||
|
||
VOID
|
||
StWriteGeneralErrorLog(
|
||
IN PDEVICE_CONTEXT DeviceContext,
|
||
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:
|
||
|
||
DeviceContext - 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[3] = L"St";
|
||
|
||
EntrySize = sizeof(IO_ERROR_LOG_PACKET) +
|
||
(DumpDataCount * sizeof(ULONG));
|
||
|
||
if (DeviceContext->Type == IO_TYPE_DEVICE) {
|
||
EntrySize += (UCHAR)DeviceContext->DeviceNameLength;
|
||
} 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)DeviceContext,
|
||
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 =
|
||
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 (DeviceContext->Type == IO_TYPE_DEVICE) {
|
||
RtlCopyMemory (StringLoc, DeviceContext->DeviceName, DeviceContext->DeviceNameLength);
|
||
StringLoc += DeviceContext->DeviceNameLength;
|
||
} else {
|
||
RtlCopyMemory (StringLoc, DriverName, sizeof(DriverName));
|
||
StringLoc += sizeof(DriverName);
|
||
}
|
||
if (SecondString) {
|
||
RtlCopyMemory (StringLoc, SecondString, SecondStringSize);
|
||
}
|
||
|
||
IoWriteErrorLogEntry(errorLogEntry);
|
||
|
||
}
|
||
|
||
} /* StWriteGeneralErrorLog */
|
||
|
||
|
||
VOID
|
||
StWriteOidErrorLog(
|
||
IN PDEVICE_CONTEXT DeviceContext,
|
||
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:
|
||
|
||
DeviceContext - 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";
|
||
UINT i;
|
||
UINT CurrentDigit;
|
||
|
||
AdapterStringSize = (wcslen(AdapterString)*sizeof(WCHAR)) + sizeof(UNICODE_NULL);
|
||
EntrySize = sizeof(IO_ERROR_LOG_PACKET) -
|
||
sizeof(ULONG) +
|
||
DeviceContext->DeviceNameLength +
|
||
AdapterStringSize +
|
||
sizeof(OidBuffer);
|
||
|
||
errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(
|
||
(PDEVICE_OBJECT)DeviceContext,
|
||
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, DeviceContext->DeviceName, DeviceContext->DeviceNameLength);
|
||
StringLoc += DeviceContext->DeviceNameLength;
|
||
|
||
RtlCopyMemory (StringLoc, OidBuffer, sizeof(OidBuffer));
|
||
StringLoc += sizeof(OidBuffer);
|
||
|
||
RtlCopyMemory (StringLoc, AdapterString, AdapterStringSize);
|
||
|
||
IoWriteErrorLogEntry(errorLogEntry);
|
||
|
||
}
|
||
|
||
} /* StWriteOidErrorLog */
|