summaryrefslogtreecommitdiffstats
path: root/private/ntos/tdi/st/stdrvr.c
diff options
context:
space:
mode:
authorAdam <you@example.com>2020-05-17 05:51:50 +0200
committerAdam <you@example.com>2020-05-17 05:51:50 +0200
commite611b132f9b8abe35b362e5870b74bce94a1e58e (patch)
treea5781d2ec0e085eeca33cf350cf878f2efea6fe5 /private/ntos/tdi/st/stdrvr.c
downloadNT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.gz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.bz2
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.lz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.xz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.zst
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.zip
Diffstat (limited to 'private/ntos/tdi/st/stdrvr.c')
-rw-r--r--private/ntos/tdi/st/stdrvr.c1627
1 files changed, 1627 insertions, 0 deletions
diff --git a/private/ntos/tdi/st/stdrvr.c b/private/ntos/tdi/st/stdrvr.c
new file mode 100644
index 000000000..d04fcd2a1
--- /dev/null
+++ b/private/ntos/tdi/st/stdrvr.c
@@ -0,0 +1,1627 @@
+/*++
+
+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 */