diff options
author | Adam <you@example.com> | 2020-05-17 05:51:50 +0200 |
---|---|---|
committer | Adam <you@example.com> | 2020-05-17 05:51:50 +0200 |
commit | e611b132f9b8abe35b362e5870b74bce94a1e58e (patch) | |
tree | a5781d2ec0e085eeca33cf350cf878f2efea6fe5 /private/ntos/tdi/st/stdrvr.c | |
download | NT4.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.c | 1627 |
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 */ |