summaryrefslogtreecommitdiffstats
path: root/private/ntos/tdi/nbf/action.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--private/ntos/tdi/nbf/action.c642
1 files changed, 642 insertions, 0 deletions
diff --git a/private/ntos/tdi/nbf/action.c b/private/ntos/tdi/nbf/action.c
new file mode 100644
index 000000000..84a51695a
--- /dev/null
+++ b/private/ntos/tdi/nbf/action.c
@@ -0,0 +1,642 @@
+/*++
+
+Copyright (c) 1989, 1990, 1991 Microsoft Corporation
+
+Module Name:
+
+ action.c
+
+Abstract:
+
+ This module contains support for the TdiAction handler.
+
+Author:
+
+ David Beaver (dbeaver) 2-July-1991
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+
+--*/
+
+
+#include "precomp.h"
+#pragma hdrstop
+
+
+typedef struct _QUERY_INDICATION {
+ UCHAR Command;
+ USHORT Data2;
+ UCHAR DestinationName[16];
+ UCHAR SourceName[16];
+} QUERY_INDICATION, *PQUERY_INDICATION;
+
+typedef struct _ACTION_QUERY_INDICATION {
+ TDI_ACTION_HEADER Header;
+ QUERY_INDICATION QueryIndication;
+} ACTION_QUERY_INDICATION, *PACTION_QUERY_INDICATION;
+
+
+typedef struct _DATAGRAM_INDICATION {
+ UCHAR DestinationName[16];
+ UCHAR SourceName[16];
+ USHORT DatagramBufferLength;
+ UCHAR DatagramBuffer[1];
+} DATAGRAM_INDICATION, *PDATAGRAM_INDICATION;
+
+typedef struct _ACTION_DATAGRAM_INDICATION {
+ TDI_ACTION_HEADER Header;
+ DATAGRAM_INDICATION DatagramIndication;
+} ACTION_DATAGRAM_INDICATION, *PACTION_DATAGRAM_INDICATION;
+
+
+#define QUERY_INDICATION_CODE 1
+#define DATAGRAM_INDICATION_CODE 2
+
+
+
+VOID
+NbfCancelAction(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+
+
+NTSTATUS
+NbfTdiAction(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine performs the TdiAction request for the transport
+ provider.
+
+Arguments:
+
+ DeviceContext - The device context for the operation
+
+ Irp - the Irp for the requested operation.
+
+Return Value:
+
+ NTSTATUS - status of operation.
+
+--*/
+
+{
+ NTSTATUS status;
+ PIO_STACK_LOCATION irpSp;
+ PTDI_ACTION_HEADER ActionHeader;
+ LARGE_INTEGER timeout = {0,0};
+ PTP_REQUEST tpRequest;
+ KIRQL oldirql, cancelirql;
+
+
+ //
+ // what type of status do we want?
+ //
+
+ irpSp = IoGetCurrentIrpStackLocation (Irp);
+
+ ActionHeader = (PTDI_ACTION_HEADER)MmGetSystemAddressForMdl (Irp->MdlAddress);
+
+
+ //
+ // Handle the requests based on the action code.
+ //
+
+ switch (ActionHeader->ActionCode) {
+
+ case QUERY_INDICATION_CODE:
+ case DATAGRAM_INDICATION_CODE:
+
+ //
+ // These two requests are sent by RAS to "MABF"
+ //
+
+ if (!RtlEqualMemory ((PVOID)(&ActionHeader->TransportId), "MABF", 4)) {
+ return STATUS_NOT_SUPPORTED;
+ }
+
+ //
+ // They should be sent on the control channel
+ //
+
+ if (irpSp->FileObject->FsContext2 != (PVOID)NBF_FILE_TYPE_CONTROL) {
+ return STATUS_NOT_SUPPORTED;
+ }
+
+
+ //
+ // Create a request to describe this.
+ //
+
+ status = NbfCreateRequest (
+ Irp, // IRP for this request.
+ DeviceContext, // context.
+ REQUEST_FLAGS_DC, // partial flags.
+ Irp->MdlAddress,
+ MmGetMdlByteCount(Irp->MdlAddress),
+ timeout,
+ &tpRequest);
+
+ if (NT_SUCCESS (status)) {
+
+ NbfReferenceDeviceContext ("Action", DeviceContext, DCREF_REQUEST);
+ tpRequest->Owner = DeviceContextType;
+ tpRequest->FrameContext = (USHORT)irpSp->FileObject->FsContext;
+
+ IoAcquireCancelSpinLock(&cancelirql);
+ ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock,&oldirql);
+
+ //
+ // Disallow these requests on a stopping device.
+ //
+
+ if (DeviceContext->State != DEVICECONTEXT_STATE_OPEN) {
+
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock,oldirql);
+ IoReleaseCancelSpinLock(cancelirql);
+ NbfCompleteRequest (tpRequest, STATUS_DEVICE_NOT_READY, 0);
+
+ } else {
+
+ if (ActionHeader->ActionCode == QUERY_INDICATION_CODE) {
+
+ InsertTailList (
+ &DeviceContext->QueryIndicationQueue,
+ &tpRequest->Linkage);
+
+ } else {
+
+ InsertTailList (
+ &DeviceContext->DatagramIndicationQueue,
+ &tpRequest->Linkage);
+
+ }
+
+ DeviceContext->IndicationQueuesInUse = TRUE;
+
+
+ //
+ // If this IRP has been cancelled, then call the
+ // cancel routine.
+ //
+
+ if (Irp->Cancel) {
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock,oldirql);
+ Irp->CancelIrql = cancelirql;
+ NbfCancelAction((PDEVICE_OBJECT)DeviceContext, Irp);
+ return STATUS_PENDING;
+ }
+
+ IoSetCancelRoutine(Irp, NbfCancelAction);
+
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock,oldirql);
+ IoReleaseCancelSpinLock(cancelirql);
+
+ }
+
+ status = STATUS_PENDING;
+
+ }
+
+ break;
+
+ default:
+
+ status = STATUS_NOT_IMPLEMENTED;
+
+ }
+
+
+ return status;
+
+}
+
+
+VOID
+NbfCancelAction(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by the I/O system to cancel an Action.
+ What is done to cancel it is specific to each action.
+
+ NOTE: This routine is called with the CancelSpinLock held and
+ is responsible for releasing it.
+
+Arguments:
+
+ DeviceObject - Pointer to the device object for this driver.
+
+ Irp - Pointer to the request packet representing the I/O request.
+
+Return Value:
+
+ none.
+
+--*/
+
+{
+ KIRQL oldirql;
+ PIO_STACK_LOCATION IrpSp;
+ PTP_REQUEST Request;
+ PLIST_ENTRY p;
+ BOOLEAN Found;
+ PTDI_ACTION_HEADER ActionHeader;
+ PLIST_ENTRY QueueHead, QueueEnd;
+
+ PDEVICE_CONTEXT DeviceContext = (PDEVICE_CONTEXT)DeviceObject;
+
+ //
+ // Get a pointer to the current stack location in the IRP. This is where
+ // the function codes and parameters are stored.
+ //
+
+ IrpSp = IoGetCurrentIrpStackLocation (Irp);
+
+ ASSERT ((IrpSp->MajorFunction == IRP_MJ_INTERNAL_DEVICE_CONTROL) &&
+ (IrpSp->MinorFunction == TDI_ACTION));
+
+ ActionHeader = (PTDI_ACTION_HEADER)MmGetSystemAddressForMdl (Irp->MdlAddress);
+
+ switch (ActionHeader->ActionCode) {
+
+ case QUERY_INDICATION_CODE:
+ case DATAGRAM_INDICATION_CODE:
+
+ //
+ // Scan through the appropriate queue, looking for this IRP.
+ // If we find it, we just remove it from the queue; there
+ // is nothing else involved in cancelling.
+ //
+
+ ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock, &oldirql);
+
+ if (ActionHeader->ActionCode == QUERY_INDICATION_CODE) {
+ QueueHead = DeviceContext->QueryIndicationQueue.Flink;
+ QueueEnd = &DeviceContext->QueryIndicationQueue;
+ } else {
+ QueueHead = DeviceContext->DatagramIndicationQueue.Flink;
+ QueueEnd = &DeviceContext->DatagramIndicationQueue;
+ }
+
+ Found = FALSE;
+ for (p = QueueHead; p != QueueEnd; p = p->Flink) {
+
+ Request = CONTAINING_RECORD (p, TP_REQUEST, Linkage);
+ if (Request->IoRequestPacket == Irp) {
+
+ //
+ // Found it, remove it from the list here.
+ //
+
+ RemoveEntryList (p);
+
+ Found = TRUE;
+ break;
+
+ }
+
+ }
+
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
+ IoReleaseCancelSpinLock (Irp->CancelIrql);
+
+ if (Found) {
+
+ NbfCompleteRequest (Request, STATUS_CANCELLED, 0);
+
+ } else {
+
+#if DBG
+ DbgPrint("NBF: Tried to cancel action %lx on %lx, not found\n",
+ Irp, DeviceContext);
+#endif
+ }
+
+ break;
+
+ default:
+
+ IoReleaseCancelSpinLock (Irp->CancelIrql);
+ break;
+
+ }
+
+
+}
+
+
+VOID
+NbfStopControlChannel(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN USHORT ChannelIdentifier
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called when an MJ_CLEANUP IRP is received
+ on a control channel. It walks the device context's list of
+ pending action requests and cancels those associated with
+ this channel (as identified by ChannelIdentifier.
+
+Arguments:
+
+ DeviceContext - Pointer to our device context.
+
+ ChannelIdentifier - The identifier for this open of the control
+ channel, which is stored in Request->FrameContext for requests
+ made on this channel.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+
+ KIRQL oldirql, cancelirql;
+ PTP_REQUEST Request;
+ PLIST_ENTRY p;
+ UINT i;
+ BOOLEAN FoundRequest;
+ PLIST_ENTRY QueueHead, QueueEnd;
+
+
+ //
+ // Scan both queues, looking for requests. Since the list
+ // may change, we scan until we find one, then remove it
+ // and complete it. We then start scanning at the beginning
+ // again. We continue until we find none on the queue that
+ // belong to this control channel.
+ //
+ // The outer loop only runs twice; the first time it
+ // processes QueryIndicationQueue, the second time
+ // DatagramIndicationQueue.
+ //
+
+ for (i = 0; i < 2; i++) {
+
+ do {
+
+ //
+ // Loop until we do not find a request on this
+ // pass through the queue.
+ //
+
+ FoundRequest = FALSE;
+
+ IoAcquireCancelSpinLock(&cancelirql);
+ ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock, &oldirql);
+
+ if (i == 0) {
+ QueueHead = DeviceContext->QueryIndicationQueue.Flink;
+ QueueEnd = &DeviceContext->QueryIndicationQueue;
+ } else {
+ QueueHead = DeviceContext->DatagramIndicationQueue.Flink;
+ QueueEnd = &DeviceContext->DatagramIndicationQueue;
+ }
+
+
+ //
+ // Scan the appropriate queue for a request on this
+ // channel.
+ //
+
+ for (p = QueueHead; p != QueueEnd; p = p->Flink) {
+
+ Request = CONTAINING_RECORD (p, TP_REQUEST, Linkage);
+ if (Request->FrameContext == ChannelIdentifier) {
+
+ //
+ // Found it, remove it from the list here.
+ //
+
+ IoSetCancelRoutine(Request->IoRequestPacket, NULL);
+ RemoveEntryList (p);
+
+ FoundRequest = TRUE;
+ break;
+
+ }
+
+ }
+
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
+ IoReleaseCancelSpinLock(cancelirql);
+
+ //
+ // If we found a request, then complete it and loop
+ // back to the top of the while loop to rescan the
+ // list. If not, then we will exit the while loop
+ // now.
+ //
+
+ if (FoundRequest) {
+
+ NbfCompleteRequest (Request, STATUS_CANCELLED, 0);
+
+ }
+
+ } while (FoundRequest);
+
+ }
+
+}
+
+
+VOID
+NbfActionQueryIndication(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PNBF_HDR_CONNECTIONLESS UiFrame
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called after a UI frame of type NAME_QUERY,
+ ADD_NAME_QUERY, or ADD_GROUP_NAME_QUERY has been processed.
+ It checks if there is a QUERY.INDICATION IRP waiting to
+ be completed, and if so completes it.
+
+Arguments:
+
+ DeviceContext - Pointer to our device context.
+
+ UiFrame - Pointer to the incoming frame. The first byte of
+ information is the first byte of the NetBIOS connectionless
+ header.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ KIRQL oldirql, cancelirql;
+ PTP_REQUEST Request;
+ PLIST_ENTRY p;
+ PMDL Mdl;
+ PACTION_QUERY_INDICATION ActionHeader;
+ PQUERY_INDICATION QueryIndication;
+
+
+ IoAcquireCancelSpinLock (&cancelirql);
+ ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock, &oldirql);
+
+ if (!IsListEmpty (&DeviceContext->QueryIndicationQueue)) {
+
+ p = RemoveHeadList (&DeviceContext->QueryIndicationQueue);
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
+
+ Request = CONTAINING_RECORD (p, TP_REQUEST, Linkage);
+ IoSetCancelRoutine(Request->IoRequestPacket,NULL);
+ IoReleaseCancelSpinLock(cancelirql);
+
+ Mdl = Request->Buffer2;
+ ActionHeader = (PACTION_QUERY_INDICATION)
+ (MmGetSystemAddressForMdl(Mdl));
+ QueryIndication = &ActionHeader->QueryIndication;
+
+ //
+ // Copy over data from frame (note that dest and source
+ // address are copied with one call).
+ //
+
+ QueryIndication->Command = UiFrame->Command;
+ RtlCopyMemory ((PUCHAR)(&QueryIndication->Data2), (PUCHAR)(&UiFrame->Data2Low), 2);
+ RtlCopyMemory ((PUCHAR)(QueryIndication->DestinationName),
+ (PUCHAR)(UiFrame->DestinationName),
+ 2 * NETBIOS_NAME_LENGTH);
+
+ NbfCompleteRequest (Request, STATUS_SUCCESS, sizeof(ACTION_QUERY_INDICATION));
+
+ } else {
+
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
+ IoReleaseCancelSpinLock(cancelirql);
+
+ }
+}
+
+
+VOID
+NbfActionDatagramIndication(
+ IN PDEVICE_CONTEXT DeviceContext,
+ IN PNBF_HDR_CONNECTIONLESS UiFrame,
+ IN ULONG Length
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called after a datagram frame has been
+ received. It checks if there is a DATAGRAM.INDICATION IRP
+ waiting to be completed, and if so completes it.
+
+Arguments:
+
+ DeviceContext - Pointer to our device context.
+
+ UiFrame - Pointer to the incoming frame. The first byte of
+ information is the first byte of the NetBIOS connectionless
+ header.
+
+ Length - The length of the frame starting at UiFrame.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ KIRQL oldirql, cancelirql;
+ PTP_REQUEST Request;
+ PLIST_ENTRY p;
+ PACTION_DATAGRAM_INDICATION ActionHeader;
+ PDATAGRAM_INDICATION DatagramIndication;
+ ULONG CopyLength;
+ PMDL Mdl;
+ NTSTATUS Status;
+
+
+ IoAcquireCancelSpinLock (&cancelirql);
+ ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock, &oldirql);
+
+ if (!IsListEmpty (&DeviceContext->DatagramIndicationQueue)) {
+
+ p = RemoveHeadList (&DeviceContext->DatagramIndicationQueue);
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
+
+ Request = CONTAINING_RECORD (p, TP_REQUEST, Linkage);
+ IoSetCancelRoutine(Request->IoRequestPacket, NULL);
+ IoReleaseCancelSpinLock(cancelirql);
+
+ Mdl = Request->Buffer2;
+ ActionHeader = (PACTION_DATAGRAM_INDICATION)
+ (MmGetSystemAddressForMdl(Mdl));
+ DatagramIndication = &ActionHeader->DatagramIndication;
+
+ //
+ // Copy over data from frame (note that dest and source
+ // address are copied with one call).
+ //
+
+ RtlCopyMemory ((PUCHAR)(DatagramIndication->DestinationName),
+ (PUCHAR)(UiFrame->DestinationName),
+ 2 * NETBIOS_NAME_LENGTH);
+
+ if ((Length-sizeof(NBF_HDR_CONNECTIONLESS)) <=
+ (ULONG)DatagramIndication->DatagramBufferLength) {
+
+ CopyLength = Length - sizeof(NBF_HDR_CONNECTIONLESS);
+ Status = STATUS_SUCCESS;
+
+ } else {
+
+ CopyLength = DatagramIndication->DatagramBufferLength;
+ Status = STATUS_BUFFER_OVERFLOW;
+
+ }
+
+
+ RtlCopyMemory(
+ (PUCHAR)DatagramIndication->DatagramBuffer,
+ ((PUCHAR)UiFrame) + sizeof(NBF_HDR_CONNECTIONLESS),
+ CopyLength);
+ DatagramIndication->DatagramBufferLength = (USHORT)CopyLength;
+
+ NbfCompleteRequest (Request, Status, CopyLength +
+ FIELD_OFFSET (ACTION_DATAGRAM_INDICATION, DatagramIndication.DatagramBuffer[0]));
+
+ } else {
+
+ RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
+ IoReleaseCancelSpinLock(cancelirql);
+
+ }
+}
+