/*++

Copyright (c) 1989  Microsoft Corporation

Module Name:

    dispatch.c

Abstract:

    This module contains the dispatch routines for AFD.

Author:

    David Treadwell (davidtr)    21-Feb-1992

Revision History:

--*/

#include "afdp.h"

#ifdef ALLOC_PRAGMA
#pragma alloc_text( PAGEAFD, AfdDispatch )
#pragma alloc_text( PAGEAFD, AfdDispatchDeviceControl )
#endif


NTSTATUS
AfdDispatch (
    IN PDEVICE_OBJECT DeviceObject,
    IN PIRP Irp
    )

/*++

Routine Description:

    This is the dispatch routine for AFD.

Arguments:

    DeviceObject - Pointer to device object for target device

    Irp - Pointer to I/O request packet

Return Value:

    NTSTATUS -- Indicates whether the request was successfully queued.

--*/

{
    PIO_STACK_LOCATION irpSp;
    NTSTATUS status;
#if DBG
    KIRQL currentIrql;

    currentIrql = KeGetCurrentIrql( );
#endif

    irpSp = IoGetCurrentIrpStackLocation( Irp );

    switch ( irpSp->MajorFunction ) {

    case IRP_MJ_WRITE:

        //
        // Make the IRP look like a send IRP.
        //

        ASSERT( FIELD_OFFSET( IO_STACK_LOCATION, Parameters.Write.Length ) ==
                FIELD_OFFSET( IO_STACK_LOCATION, Parameters.DeviceIoControl.OutputBufferLength ) );
        ASSERT( FIELD_OFFSET( IO_STACK_LOCATION, Parameters.Write.Key ) ==
                FIELD_OFFSET( IO_STACK_LOCATION, Parameters.DeviceIoControl.InputBufferLength ) );
        irpSp->Parameters.Write.Key = 0;

        if (IS_SAN_ENDPOINT ((PAFD_ENDPOINT)irpSp->FileObject->FsContext)) {
            status = AfdSanRedirectRequest (Irp, irpSp);
        }
        else {
			status = AfdSend( Irp, irpSp );
		}

        ASSERT( KeGetCurrentIrql( ) == currentIrql );

        return status;

    case IRP_MJ_READ:

        //
        // Make the IRP look like a receive IRP.
        //

        ASSERT( FIELD_OFFSET( IO_STACK_LOCATION, Parameters.Read.Length ) ==
                FIELD_OFFSET( IO_STACK_LOCATION, Parameters.DeviceIoControl.OutputBufferLength ) );
        ASSERT( FIELD_OFFSET( IO_STACK_LOCATION, Parameters.Read.Key ) ==
                FIELD_OFFSET( IO_STACK_LOCATION, Parameters.DeviceIoControl.InputBufferLength ) );
        irpSp->Parameters.Read.Key = 0;

        if (IS_SAN_ENDPOINT ((PAFD_ENDPOINT)irpSp->FileObject->FsContext)) {
            status = AfdSanRedirectRequest (Irp, irpSp);
        }
        else {
			status = AfdReceive( Irp, irpSp );
		}

        ASSERT( KeGetCurrentIrql( ) == currentIrql );

        return status;

    case IRP_MJ_CREATE:

        status = AfdCreate( Irp, irpSp );

        ASSERT( KeGetCurrentIrql( ) == currentIrql );

        Irp->IoStatus.Status = status;
        IoCompleteRequest( Irp, AfdPriorityBoost );

        return status;

    case IRP_MJ_CLEANUP:

        status = AfdCleanup( Irp, irpSp );

        Irp->IoStatus.Status = status;
        IoCompleteRequest( Irp, AfdPriorityBoost );

        ASSERT( KeGetCurrentIrql( ) == currentIrql );

        return status;

    case IRP_MJ_CLOSE:

        status = AfdClose( Irp, irpSp );

        Irp->IoStatus.Status = status;
        IoCompleteRequest( Irp, AfdPriorityBoost );

        ASSERT( KeGetCurrentIrql( ) == currentIrql );

        return status;
    case IRP_MJ_PNP:
        status = AfdPnpPower (Irp, irpSp );

        ASSERT( KeGetCurrentIrql( ) == currentIrql );

        return status;
    case IRP_MJ_DEVICE_CONTROL:

        return AfdDispatchDeviceControl( DeviceObject, Irp );

        //
		// SAN support.
        // Return special error code to let IO manager use default security.
        // (needed to support ObOpenObjectByPointer).
        //
    case IRP_MJ_QUERY_SECURITY:
    case IRP_MJ_SET_SECURITY:
        Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
        IoCompleteRequest( Irp, AfdPriorityBoost );
        return STATUS_INVALID_DEVICE_REQUEST;

    default:
        KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_INFO_LEVEL,
                    "AfdDispatch: Invalid major function %lx\n",
                    irpSp->MajorFunction ));
        Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED;
        IoCompleteRequest( Irp, AfdPriorityBoost );

        return STATUS_NOT_IMPLEMENTED;
    }

} // AfdDispatch


NTSTATUS
AfdDispatchDeviceControl (
    IN PDEVICE_OBJECT DeviceObject,
    IN PIRP Irp
    )

/*++

Routine Description:

    This is the dispatch routine for AFD IOCTLs.

Arguments:

    DeviceObject - Pointer to device object for target device

    Irp - Pointer to I/O request packet

Return Value:

    NTSTATUS -- Indicates whether the request was successfully queued.

--*/

{
    ULONG code;
    ULONG request;
    NTSTATUS status;
    PAFD_IRP_CALL irpProc;
    PIO_STACK_LOCATION  IrpSp = IoGetCurrentIrpStackLocation (Irp);
#if DBG
    KIRQL currentIrql;

    currentIrql = KeGetCurrentIrql( );
#endif
    UNREFERENCED_PARAMETER (DeviceObject);


    //
    // Extract the IOCTL control code and process the request.
    //

    code = IrpSp->Parameters.DeviceIoControl.IoControlCode;
    request = _AFD_REQUEST(code);

    if( request < AFD_NUM_IOCTLS && AfdIoctlTable[request] == code ) {

        //
        // Helps in debugging.
        //
        IrpSp->MinorFunction = (UCHAR)request;

        //
        // Try IRP dispatch first
        //
        irpProc = AfdIrpCallDispatch[request];
        if (irpProc!=NULL) {
            status = (*irpProc)(Irp, IrpSp);

            ASSERT( KeGetCurrentIrql( ) == currentIrql );

            return status;
        }
    }
//
// This is currently not used by helper dlls.
// Commented out because of security concerns
//
#if 0
    else if (request==AFD_TRANSPORT_IOCTL) {
        //
        // This is a "special" used to pass request
        // to transport driver using socket handle in
        // order to facilitate proper completion 
        // on sockets associated with completion port.
        // It accepts and properly handles all methods.
        //
        status = AfdDoTransportIoctl (Irp, IrpSp);
        ASSERT( KeGetCurrentIrql() == currentIrql );
        return status;
    }
#endif

    //
    // If we made it this far, then the ioctl is invalid.
    //

    KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_WARNING_LEVEL,
                "AfdDispatchDeviceControl: invalid IOCTL %08lX\n",
                code
                ));

    Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
    IoCompleteRequest( Irp, AfdPriorityBoost );

    return STATUS_INVALID_DEVICE_REQUEST;

} // AfdDispatchDeviceControl

NTSTATUS
FASTCALL
AfdDispatchImmediateIrp(
    IN PIRP Irp,
    IN PIO_STACK_LOCATION IrpSp
    )
{
    PAFD_IMMEDIATE_CALL immProc;
    ULONG code;
    ULONG request;
    NTSTATUS status;
#if DBG
    KIRQL currentIrql;

    currentIrql = KeGetCurrentIrql( );
#endif

    code = IrpSp->Parameters.DeviceIoControl.IoControlCode;
    request = _AFD_REQUEST(code);

    immProc = AfdImmediateCallDispatch[request];
    if (immProc!=NULL) {
        //
        // Must be METHOD_NEITHER for the below code to be
        // valid.
        //
        ASSERT ( (code & 3) == METHOD_NEITHER );
#if DBG
        if (Irp->RequestorMode!=KernelMode) {
            KdPrintEx(( DPFLTR_WSOCKTRANSPORT_ID, DPFLTR_WARNING_LEVEL,
                        "AfdDispatchDeviceControl: "
                        "User mode application somehow bypassed fast io dispatch\n"));
        }
#endif
        status = (*immProc) (
                    IrpSp->FileObject,
                    code,
                    Irp->RequestorMode,
                    IrpSp->Parameters.DeviceIoControl.Type3InputBuffer,
                    IrpSp->Parameters.DeviceIoControl.InputBufferLength,
                    Irp->UserBuffer,
                    IrpSp->Parameters.DeviceIoControl.OutputBufferLength,
                    &Irp->IoStatus.Information
                    );

        ASSERT( KeGetCurrentIrql( ) == currentIrql );

    }
    else {
        ASSERT (!"Missing IOCTL in dispatch table!!!");
        status = STATUS_INVALID_DEVICE_REQUEST;
    }

    Irp->IoStatus.Status = status;
    IoCompleteRequest( Irp, AfdPriorityBoost );
    return status;
}