/*++

Copyright (c) 1996  Microsoft Corporation

Module Name:

    cxdisp.c

Abstract:

    Dispatch routines for the Cluster Transport.

Author:

    Mike Massa (mikemas)           July 29, 1996

Revision History:

    Who         When        What
    --------    --------    ----------------------------------------------
    mikemas     07-29-96    created

Notes:

--*/

#include "precomp.h"
#pragma hdrstop
#include "cxdisp.tmh"

#include <align.h>

//
// Local Prototypes
//
NTSTATUS
CxDispatchRegisterNode(
    IN PIRP               Irp,
    IN PIO_STACK_LOCATION IrpSp
    );

NTSTATUS
CxDispatchDeregisterNode(
    IN PIRP               Irp,
    IN PIO_STACK_LOCATION IrpSp
    );

NTSTATUS
CxDispatchRegisterNetwork(
    IN PIRP               Irp,
    IN PIO_STACK_LOCATION IrpSp
    );

NTSTATUS
CxDispatchDeregisterNetwork(
    IN PIRP               Irp,
    IN PIO_STACK_LOCATION IrpSp
    );

NTSTATUS
CxDispatchRegisterInterface(
    IN PIRP               Irp,
    IN PIO_STACK_LOCATION IrpSp
    );

NTSTATUS
CxDispatchDeregisterInterface(
    IN PIRP               Irp,
    IN PIO_STACK_LOCATION IrpSp
    );

NTSTATUS
CxDispatchOnlineNodeComm(
    IN PIRP               Irp,
    IN PIO_STACK_LOCATION IrpSp
    );

NTSTATUS
CxDispatchOfflineNodeComm(
    IN PIRP               Irp,
    IN PIO_STACK_LOCATION IrpSp
    );

NTSTATUS
CxDispatchOnlineNetwork(
    IN PIRP               Irp,
    IN PIO_STACK_LOCATION IrpSp
    );

NTSTATUS
CxDispatchOfflineNetwork(
    IN PIRP               Irp,
    IN PIO_STACK_LOCATION IrpSp
    );

NTSTATUS
CxDispatchSetNetworkRestriction(
    IN PIRP               Irp,
    IN PIO_STACK_LOCATION IrpSp
    );

NTSTATUS
CxDispatchGetNetworkPriority(
    IN PIRP               Irp,
    IN PIO_STACK_LOCATION IrpSp
    );

NTSTATUS
CxDispatchSetNetworkPriority(
    IN PIRP               Irp,
    IN PIO_STACK_LOCATION IrpSp
    );

NTSTATUS
CxDispatchGetInterfacePriority(
    IN PIRP               Irp,
    IN PIO_STACK_LOCATION IrpSp
    );

NTSTATUS
CxDispatchSetInterfacePriority(
    IN PIRP               Irp,
    IN PIO_STACK_LOCATION IrpSp
    );

NTSTATUS
CxDispatchGetNodeState(
    IN PIRP               Irp,
    IN PIO_STACK_LOCATION IrpSp
    );

NTSTATUS
CxDispatchGetNetworkState(
    IN PIRP               Irp,
    IN PIO_STACK_LOCATION IrpSp
    );

NTSTATUS
CxDispatchGetInterfaceState(
    IN PIRP               Irp,
    IN PIO_STACK_LOCATION IrpSp
    );

NTSTATUS
CxDispatchIgnoreNodeState(
    IN PIRP               Irp,
    IN PIO_STACK_LOCATION IrpSp
    );

NTSTATUS
CxDispatchGetNodeMembershipState(
    IN PIRP               Irp,
    IN PIO_STACK_LOCATION IrpSp
    );

NTSTATUS
CxDispatchSetNodeMembershipState(
    IN PIRP               Irp,
    IN PIO_STACK_LOCATION IrpSp
    );

NTSTATUS
CxDispatchSendPoisonPacket(
    IN PIRP               Irp,
    IN PIO_STACK_LOCATION IrpSp
    );

NTSTATUS
CxDispatchSetOuterscreen(
    IN PIRP               Irp,
    IN PIO_STACK_LOCATION IrpSp
    );

NTSTATUS
CxDispatchRegroupFinished(
    IN PIRP               Irp,
    IN PIO_STACK_LOCATION IrpSp
    );

NTSTATUS
CxDispatchImportSecurityContext(
    IN PIRP               Irp,
    IN PIO_STACK_LOCATION IrpSp
    );

NTSTATUS
CxDispatchReserveClusnetEndpoint(
    IN PIRP               Irp,
    IN PIO_STACK_LOCATION IrpSp
    );

NTSTATUS
CxDispatchConfigureMulticast(
    IN PIRP               Irp,
    IN PIO_STACK_LOCATION IrpSp
    );

NTSTATUS
CxDispatchGetMulticastReachableSet(
    IN PIRP               Irp,
    IN PIO_STACK_LOCATION IrpSp
    );


#if DBG

NTSTATUS
CxDispatchOnlinePendingInterface(
    IN PIRP               Irp,
    IN PIO_STACK_LOCATION IrpSp
    );

NTSTATUS
CxDispatchOnlineInterface(
    IN PIRP               Irp,
    IN PIO_STACK_LOCATION IrpSp
    );

NTSTATUS
CxDispatchOfflineInterface(
    IN PIRP               Irp,
    IN PIO_STACK_LOCATION IrpSp
    );

NTSTATUS
CxDispatchFailInterface(
    IN PIRP               Irp,
    IN PIO_STACK_LOCATION IrpSp
    );

NTSTATUS
CxDispatchSendMmMsg(
    IN PIRP               Irp,
    IN PIO_STACK_LOCATION IrpSp
    );


#endif // DBG


#ifdef ALLOC_PRAGMA

#pragma alloc_text(PAGE, CxDispatchDeviceControl)
#pragma alloc_text(PAGE, CxDispatchRegisterNode)
#pragma alloc_text(PAGE, CxDispatchDeregisterNode)
#pragma alloc_text(PAGE, CxDispatchRegisterNetwork)
#pragma alloc_text(PAGE, CxDispatchDeregisterNetwork)
#pragma alloc_text(PAGE, CxDispatchRegisterInterface)
#pragma alloc_text(PAGE, CxDispatchDeregisterInterface)
#pragma alloc_text(PAGE, CxDispatchOnlineNodeComm)
#pragma alloc_text(PAGE, CxDispatchOfflineNodeComm)
#pragma alloc_text(PAGE, CxDispatchOnlineNetwork)
#pragma alloc_text(PAGE, CxDispatchOfflineNetwork)
#pragma alloc_text(PAGE, CxDispatchSetNetworkRestriction)
#pragma alloc_text(PAGE, CxDispatchGetNetworkPriority)
#pragma alloc_text(PAGE, CxDispatchSetNetworkPriority)
#pragma alloc_text(PAGE, CxDispatchGetInterfacePriority)
#pragma alloc_text(PAGE, CxDispatchSetInterfacePriority)
#pragma alloc_text(PAGE, CxDispatchGetNodeState)
#pragma alloc_text(PAGE, CxDispatchGetNetworkState)
#pragma alloc_text(PAGE, CxDispatchGetInterfaceState)
#pragma alloc_text(PAGE, CxDispatchGetNodeMembershipState)
#pragma alloc_text(PAGE, CxDispatchSetNodeMembershipState)
#pragma alloc_text(PAGE, CxDispatchSendPoisonPacket)
#pragma alloc_text(PAGE, CxDispatchSetOuterscreen)
#pragma alloc_text(PAGE, CxDispatchRegroupFinished)
#pragma alloc_text(PAGE, CxDispatchImportSecurityContext)
#pragma alloc_text(PAGE, CxDispatchReserveClusnetEndpoint)
#pragma alloc_text(PAGE, CxDispatchConfigureMulticast)
#pragma alloc_text(PAGE, CxDispatchGetMulticastReachableSet)


#if DBG

#pragma alloc_text(PAGE, CxDispatchOnlinePendingInterface)
#pragma alloc_text(PAGE, CxDispatchOnlineInterface)
#pragma alloc_text(PAGE, CxDispatchOfflineInterface)
#pragma alloc_text(PAGE, CxDispatchFailInterface)
#ifdef MM_IN_CLUSNET
#pragma alloc_text(PAGE, CxDispatchSendMmMsg)
#endif // MM_IN_CLUSNET

#endif // DBG

#endif // ALLOC_PRAGMA




NTSTATUS
CxDispatchDeviceControl(
    IN PIRP               Irp,
    IN PIO_STACK_LOCATION IrpSp
    )

/*++

Routine Description:

    Dispatch routine for device control ioctls.

Arguments:

    Irp          - Pointer to I/O request packet
    IrpSp        - Pointer to the current stack location in the Irp.

Return Value:

    NTSTATUS -- Indicates whether the request was successfully queued.

Notes:

    Any IRP for which the return value is not STATUS_PENDING will be
    completed by the calling routine.

--*/

{
    NTSTATUS              status;


    PAGED_CODE();

    switch(IrpSp->Parameters.DeviceIoControl.IoControlCode) {

        case IOCTL_CX_REGISTER_NODE:
            status = CxDispatchRegisterNode(Irp, IrpSp);
            break;

        case IOCTL_CX_DEREGISTER_NODE:
            status = CxDispatchDeregisterNode(Irp, IrpSp);
            break;

        case IOCTL_CX_REGISTER_NETWORK:
            status = CxDispatchRegisterNetwork(Irp, IrpSp);
            break;

        case IOCTL_CX_DEREGISTER_NETWORK:
            status = CxDispatchDeregisterNetwork(Irp, IrpSp);
            break;

        case IOCTL_CX_REGISTER_INTERFACE:
            status = CxDispatchRegisterInterface(Irp, IrpSp);
            break;

        case IOCTL_CX_DEREGISTER_INTERFACE:
            status = CxDispatchDeregisterInterface(Irp, IrpSp);
            break;

        case IOCTL_CX_ONLINE_NODE_COMM:
            status = CxDispatchOnlineNodeComm(Irp, IrpSp);
            break;

        case IOCTL_CX_OFFLINE_NODE_COMM:
            status = CxDispatchOfflineNodeComm(Irp, IrpSp);
            break;

        case IOCTL_CX_ONLINE_NETWORK:
            status = CxDispatchOnlineNetwork(Irp, IrpSp);
            break;

        case IOCTL_CX_OFFLINE_NETWORK:
            status = CxDispatchOfflineNetwork(Irp, IrpSp);
            break;

        case IOCTL_CX_SET_NETWORK_RESTRICTION:
            status = CxDispatchSetNetworkRestriction(Irp, IrpSp);
            break;

        case IOCTL_CX_GET_NETWORK_PRIORITY:
            status = CxDispatchGetNetworkPriority(Irp, IrpSp);
            break;

        case IOCTL_CX_SET_NETWORK_PRIORITY:
            status = CxDispatchSetNetworkPriority(Irp, IrpSp);
            break;

        case IOCTL_CX_GET_INTERFACE_PRIORITY:
            status = CxDispatchGetInterfacePriority(Irp, IrpSp);
            break;

        case IOCTL_CX_SET_INTERFACE_PRIORITY:
            status = CxDispatchSetInterfacePriority(Irp, IrpSp);
            break;

        case IOCTL_CX_GET_NODE_STATE:
            status = CxDispatchGetNodeState(Irp, IrpSp);
            break;

        case IOCTL_CX_GET_NETWORK_STATE:
            status = CxDispatchGetNetworkState(Irp, IrpSp);
            break;

        case IOCTL_CX_GET_INTERFACE_STATE:
            status = CxDispatchGetInterfaceState(Irp, IrpSp);
            break;

        case IOCTL_CX_IGNORE_NODE_STATE:
            status = CxDispatchIgnoreNodeState(Irp, IrpSp);
            break;

        case IOCTL_CX_GET_NODE_MMSTATE:
            status = CxDispatchGetNodeMembershipState(Irp, IrpSp);
            break;

        case IOCTL_CX_SET_NODE_MMSTATE:
            status = CxDispatchSetNodeMembershipState(Irp, IrpSp);
            break;

        case IOCTL_CX_SEND_POISON_PACKET:
            status = CxDispatchSendPoisonPacket(Irp, IrpSp);
            break;

        case IOCTL_CX_SET_OUTERSCREEN:
            status = CxDispatchSetOuterscreen(Irp, IrpSp);
            break;

        case IOCTL_CX_REGROUP_FINISHED:
            status = CxDispatchRegroupFinished(Irp, IrpSp);
            break;

        case IOCTL_CX_IMPORT_SECURITY_CONTEXTS:
            status = CxDispatchImportSecurityContext(Irp, IrpSp);
            break;

        case IOCTL_CX_RESERVE_ENDPOINT:
            status = CxDispatchReserveClusnetEndpoint(Irp, IrpSp);
            break;

        case IOCTL_CX_CONFIGURE_MULTICAST:
            status = CxDispatchConfigureMulticast(Irp, IrpSp);
            break;

        case IOCTL_CX_GET_MULTICAST_REACHABLE_SET:
            status = CxDispatchGetMulticastReachableSet(Irp, IrpSp);
            break;

#if DBG

        case IOCTL_CX_ONLINE_PENDING_INTERFACE:
            status = CxDispatchOnlinePendingInterface(Irp, IrpSp);
            break;

        case IOCTL_CX_ONLINE_INTERFACE:
            status = CxDispatchOnlineInterface(Irp, IrpSp);
            break;

        case IOCTL_CX_OFFLINE_INTERFACE:
            status = CxDispatchOfflineInterface(Irp, IrpSp);
            break;

        case IOCTL_CX_FAIL_INTERFACE:
            status = CxDispatchFailInterface(Irp, IrpSp);
            break;

#ifdef MM_IN_CLUSNET
        case IOCTL_CX_SEND_MM_MSG:
            status = CxDispatchSendMmMsg(Irp, IrpSp);
            break;
#endif // MM_IN_CLUSNET

#endif // DBG

        default:
            status = STATUS_INVALID_DEVICE_REQUEST;
            break;
    }

    return(status);

} // CxDispatchDeviceControl


NTSTATUS
CxDispatchRegisterNode(
    IN PIRP               Irp,
    IN PIO_STACK_LOCATION IrpSp
    )
{
    NTSTATUS               status;
    PCX_NODE_REG_REQUEST   request;
    ULONG                  requestSize;


    PAGED_CODE();

    request = (PCX_NODE_REG_REQUEST) Irp->AssociatedIrp.SystemBuffer;
    requestSize = IrpSp->Parameters.DeviceIoControl.InputBufferLength;

    if (requestSize < sizeof(CX_NODE_REG_REQUEST)) {
        return(STATUS_INVALID_PARAMETER);
    }

    status = CxRegisterNode(
                 request->Id
                 );

    return(status);

}   // CxDispatchRegisterNode


NTSTATUS
CxDispatchDeregisterNode(
    IN PIRP               Irp,
    IN PIO_STACK_LOCATION IrpSp
    )
{
    NTSTATUS                 status;
    PCX_NODE_DEREG_REQUEST   request;
    ULONG                    requestSize;


    PAGED_CODE();

    request = (PCX_NODE_DEREG_REQUEST) Irp->AssociatedIrp.SystemBuffer;
    requestSize = IrpSp->Parameters.DeviceIoControl.InputBufferLength;

    if (requestSize < sizeof(CX_NODE_DEREG_REQUEST)) {
        return(STATUS_INVALID_PARAMETER);
    }

    status = CxDeregisterNode(request->Id, Irp, IrpSp);

    return(status);

}   // CxDispatchDeregisterNode


NTSTATUS
CxDispatchRegisterNetwork(
    IN PIRP               Irp,
    IN PIO_STACK_LOCATION IrpSp
    )
{
    NTSTATUS                    status;
    PCX_NETWORK_REG_REQUEST     request;
    ULONG                       requestSize;


    PAGED_CODE();

    request = (PCX_NETWORK_REG_REQUEST) Irp->AssociatedIrp.SystemBuffer;
    requestSize = IrpSp->Parameters.DeviceIoControl.InputBufferLength;

    if (requestSize < sizeof(CX_NETWORK_REG_REQUEST)) {
        return(STATUS_INVALID_PARAMETER);
    }

    status = CxRegisterNetwork(
                 request->Id,
                 request->Priority,
                 request->Restricted
                 );

    return(status);

}   // CxDispatchRegisterNetwork


NTSTATUS
CxDispatchDeregisterNetwork(
    IN PIRP               Irp,
    IN PIO_STACK_LOCATION IrpSp
    )
{
    NTSTATUS                    status;
    PCX_NETWORK_DEREG_REQUEST   request;
    ULONG                       requestSize;


    PAGED_CODE();

    request = (PCX_NETWORK_DEREG_REQUEST) Irp->AssociatedIrp.SystemBuffer;
    requestSize = IrpSp->Parameters.DeviceIoControl.InputBufferLength;

    if (requestSize < sizeof(CX_NETWORK_DEREG_REQUEST)) {
        return(STATUS_INVALID_PARAMETER);
    }

    status = CxDeregisterNetwork(request->Id, Irp, IrpSp);

    return(status);

}   // CxDispatchDeregisterNetwork


NTSTATUS
CxDispatchRegisterInterface(
    IN PIRP               Irp,
    IN PIO_STACK_LOCATION IrpSp
    )
{
    NTSTATUS                   status;
    PCX_INTERFACE_REG_REQUEST  request;
    ULONG                      requestSize, resid;
    PCX_INTERFACE_REG_RESPONSE response;
    ULONG                      responseSize;

    PWCHAR                     adapterId;

    PAGED_CODE();

    // Verify that the request buffer has sufficient size, given the 
    // offsets and lengths.

    request = (PCX_INTERFACE_REG_REQUEST) Irp->AssociatedIrp.SystemBuffer;
    requestSize = IrpSp->Parameters.DeviceIoControl.InputBufferLength;

    if (requestSize < sizeof(CX_INTERFACE_REG_REQUEST)) {
        return(STATUS_INVALID_PARAMETER);
    }

    response = (PCX_INTERFACE_REG_RESPONSE) Irp->AssociatedIrp.SystemBuffer;
    responseSize = IrpSp->Parameters.DeviceIoControl.OutputBufferLength;

    if (responseSize < sizeof(CX_INTERFACE_REG_RESPONSE)) {
        return(STATUS_INVALID_PARAMETER);
    }

    resid = requestSize 
        - FIELD_OFFSET(CX_INTERFACE_REG_REQUEST, TdiAddress[0]);

    if (resid < request->TdiAddressLength) {
        return(STATUS_INVALID_PARAMETER);
    }

    resid -= request->TdiAddressLength;

    if (request->AdapterIdOffset
        < FIELD_OFFSET(CX_INTERFACE_REG_REQUEST, TdiAddress[0])
        + request->TdiAddressLength
        || request->AdapterIdOffset > requestSize) {
        return(STATUS_INVALID_PARAMETER);
    }

    if (resid < request->AdapterIdLength) {
        return(STATUS_INVALID_PARAMETER);
    }

    // Verify that the string offset is properly aligned
    adapterId = (PWCHAR)((PUCHAR)request + request->AdapterIdOffset);

    if (!POINTER_IS_ALIGNED(adapterId, TYPE_ALIGNMENT(WCHAR))) {
        return(STATUS_INVALID_PARAMETER);
    }

    status = CxRegisterInterface(
                 request->NodeId,
                 request->NetworkId,
                 request->Priority,
                 (PUWSTR)((PUCHAR)request + request->AdapterIdOffset),
                 request->AdapterIdLength,
                 request->TdiAddressLength,
                 (PTRANSPORT_ADDRESS) &(request->TdiAddress[0]),
                 &response->MediaStatus
                 );

    if (NT_SUCCESS(status)) {
        Irp->IoStatus.Information = sizeof(CX_INTERFACE_REG_RESPONSE);
    }

    return(status);

}   // CxDispatchRegisterInterface


NTSTATUS
CxDispatchDeregisterInterface(
    IN PIRP               Irp,
    IN PIO_STACK_LOCATION IrpSp
    )
{
    NTSTATUS                      status;
    PCX_INTERFACE_DEREG_REQUEST   request;
    ULONG                         requestSize;


    PAGED_CODE();

    request = (PCX_INTERFACE_DEREG_REQUEST) Irp->AssociatedIrp.SystemBuffer;
    requestSize = IrpSp->Parameters.DeviceIoControl.InputBufferLength;

    if (requestSize < sizeof(CX_INTERFACE_DEREG_REQUEST)) {
        return(STATUS_INVALID_PARAMETER);
    }

    status = CxDeregisterInterface(request->NodeId, request->NetworkId);

    return(status);

}   // CxDispatchDeregisterInterface


NTSTATUS
CxDispatchOnlineNodeComm(
    IN PIRP               Irp,
    IN PIO_STACK_LOCATION IrpSp
    )
{
    NTSTATUS                  status;
    PCX_ONLINE_NODE_COMM_REQUEST   request;
    ULONG                     requestSize;


    PAGED_CODE();

    request = (PCX_ONLINE_NODE_COMM_REQUEST) Irp->AssociatedIrp.SystemBuffer;
    requestSize = IrpSp->Parameters.DeviceIoControl.InputBufferLength;

    if (requestSize < sizeof(CX_ONLINE_NODE_COMM_REQUEST)) {
        return(STATUS_INVALID_PARAMETER);
    }

    status = CxOnlineNodeComm(request->Id);

    return(status);

}  // CxDispatchOnlineNodeComm


NTSTATUS
CxDispatchOfflineNodeComm(
    IN PIRP               Irp,
    IN PIO_STACK_LOCATION IrpSp
    )
{
    NTSTATUS                      status;
    PCX_OFFLINE_NODE_COMM_REQUEST      request;
    ULONG                         requestSize;


    PAGED_CODE();

    request = (PCX_OFFLINE_NODE_COMM_REQUEST) Irp->AssociatedIrp.SystemBuffer;
    requestSize = IrpSp->Parameters.DeviceIoControl.InputBufferLength;

    if (requestSize < sizeof(CX_OFFLINE_NODE_COMM_REQUEST)) {
        return(STATUS_INVALID_PARAMETER);
    }

    status = CxOfflineNodeComm(request->Id, Irp, IrpSp);

    return(status);

}  // CxDispatchOfflineNodeComm


NTSTATUS
CxDispatchOnlineNetwork(
    IN PIRP               Irp,
    IN PIO_STACK_LOCATION IrpSp
    )
{
    NTSTATUS                    status;
    PCX_ONLINE_NETWORK_REQUEST  request;
    ULONG                       requestSize;
    PTDI_ADDRESS_INFO           response;
    ULONG                       responseSize;
    ULONG                       requiredSize = sizeof(
                                                   CX_ONLINE_NETWORK_REQUEST
                                                   );
    PWCHAR                      tdiProviderName;
    PTRANSPORT_ADDRESS          tdiBindAddress;
    PWCHAR                      adapterName;


    PAGED_CODE();

    //
    // Validate the request buffer
    //

    // First validate that the request buffer size matches the offsets
    // and lengths.
    request = (PCX_ONLINE_NETWORK_REQUEST) Irp->AssociatedIrp.SystemBuffer;
    requestSize = IrpSp->Parameters.DeviceIoControl.InputBufferLength;

    if (requestSize < requiredSize) {
        return(STATUS_INVALID_PARAMETER);
    }

    // Validate that all offset length pairs are within the request
    // buffer.
    if ( ( request->TdiProviderNameOffset + request->TdiProviderNameLength
           < request->TdiProviderNameOffset
         ) ||
         ( request->TdiProviderNameOffset + request->TdiProviderNameLength
           > requestSize
         ) ||
         ( request->TdiBindAddressOffset + request->TdiBindAddressLength
           < request->TdiBindAddressOffset
         ) ||
         ( request->TdiBindAddressOffset + request->TdiBindAddressLength
           > requestSize
         ) ||
         ( request->AdapterNameOffset + request->AdapterNameLength
           < request->AdapterNameOffset
         ) ||
         ( request->AdapterNameOffset + request->AdapterNameLength
           > requestSize
         )
       ) 
    {
        return(STATUS_INVALID_PARAMETER);
    }

    // Construct pointers to the parameters.
    tdiBindAddress = (PTRANSPORT_ADDRESS)
                     ( ((PUCHAR) request) + request->TdiBindAddressOffset );

    tdiProviderName = (PWCHAR)
                      ( ((PUCHAR) request) + request->TdiProviderNameOffset );

    adapterName = (PWCHAR)
                  ( ((PUCHAR) request) + request->AdapterNameOffset );

    // Validate that the resulting pointers are properly aligned and
    // within the request buffer.
    if ( ( ((PUCHAR) tdiBindAddress) < ((PUCHAR) request) ) ||
         ( ((PUCHAR) tdiBindAddress) > ((PUCHAR) request) + requestSize ) ||
         ( !POINTER_IS_ALIGNED(tdiBindAddress, 
                               TYPE_ALIGNMENT(TRANSPORT_ADDRESS)) ) ||
         ( ((PUCHAR) tdiProviderName) < ((PUCHAR) request) ) ||
         ( ((PUCHAR) tdiProviderName) > ((PUCHAR) request) + requestSize ) ||
         ( !POINTER_IS_ALIGNED(tdiProviderName, TYPE_ALIGNMENT(WCHAR)) ) ||
         ( ((PUCHAR) adapterName) < ((PUCHAR) request) ) ||
         ( ((PUCHAR) adapterName) > ((PUCHAR) request) + requestSize ) ||
         ( !POINTER_IS_ALIGNED(adapterName, TYPE_ALIGNMENT(WCHAR)) )
        )
    {
        return(STATUS_INVALID_PARAMETER);
    }

    //
    // Validate the response buffer
    //
    response = (PTDI_ADDRESS_INFO) Irp->AssociatedIrp.SystemBuffer;
    responseSize = IrpSp->Parameters.DeviceIoControl.OutputBufferLength;

    requiredSize = FIELD_OFFSET(TDI_ADDRESS_INFO, Address) +
                   request->TdiBindAddressLength;

    if (responseSize < requiredSize) {
        return(STATUS_INVALID_PARAMETER);
    }

    status = CxOnlineNetwork(
                 request->Id,
                 tdiProviderName,
                 request->TdiProviderNameLength,
                 tdiBindAddress,
                 request->TdiBindAddressLength,
                 adapterName,
                 request->AdapterNameLength,
                 response,
                 responseSize,
                 Irp
                 );

    if (NT_SUCCESS(status)) {
        Irp->IoStatus.Information = responseSize;
    }

    return(status);

}  // CxDispatchOnlineNetwork


NTSTATUS
CxDispatchOfflineNetwork(
    IN PIRP               Irp,
    IN PIO_STACK_LOCATION IrpSp
    )
{
    NTSTATUS                      status;
    PCX_OFFLINE_NETWORK_REQUEST   request;
    ULONG                         requestSize;


    PAGED_CODE();

    request = (PCX_OFFLINE_NETWORK_REQUEST) Irp->AssociatedIrp.SystemBuffer;
    requestSize = IrpSp->Parameters.DeviceIoControl.InputBufferLength;

    if (requestSize < sizeof(CX_OFFLINE_NETWORK_REQUEST)) {
        return(STATUS_INVALID_PARAMETER);
    }

    status = CxOfflineNetwork(request->Id, Irp, IrpSp);

    return(status);

}  // CxDispatchOfflineNetwork


NTSTATUS
CxDispatchSetNetworkRestriction(
    IN PIRP               Irp,
    IN PIO_STACK_LOCATION IrpSp
    )
{
    NTSTATUS                             status;
    ULONG                                requestSize;
    PCX_SET_NETWORK_RESTRICTION_REQUEST  request;


    PAGED_CODE();

    request = (PCX_SET_NETWORK_RESTRICTION_REQUEST)
              Irp->AssociatedIrp.SystemBuffer;
    requestSize = IrpSp->Parameters.DeviceIoControl.InputBufferLength;

    if (requestSize < sizeof(CX_SET_NETWORK_RESTRICTION_REQUEST)) {
        return(STATUS_INVALID_PARAMETER);
    }

    status = CxSetNetworkRestriction(
                 request->Id,
                 request->Restricted,
                 request->NewPriority
                 );

    return(status);

}   // CxDispatchSetNetworkRestriction


NTSTATUS
CxDispatchGetNetworkPriority(
    IN PIRP               Irp,
    IN PIO_STACK_LOCATION IrpSp
    )
{
    NTSTATUS                             status;
    PCX_GET_NETWORK_PRIORITY_REQUEST     request;
    PCX_GET_NETWORK_PRIORITY_RESPONSE    response;
    ULONG                                requestSize;
    ULONG                                responseSize;


    PAGED_CODE();

    request = (PCX_GET_NETWORK_PRIORITY_REQUEST)
              Irp->AssociatedIrp.SystemBuffer;
    requestSize = IrpSp->Parameters.DeviceIoControl.InputBufferLength;

    response = (PCX_GET_NETWORK_PRIORITY_RESPONSE) request;
    responseSize = IrpSp->Parameters.DeviceIoControl.OutputBufferLength;

    if ( (requestSize < sizeof(CX_GET_NETWORK_PRIORITY_REQUEST)) ||
         (responseSize < sizeof(CX_GET_NETWORK_PRIORITY_RESPONSE))
       )
    {
        return(STATUS_INVALID_PARAMETER);
    }

    status = CxGetNetworkPriority(
                 request->Id,
                 &(response->Priority)
                 );

    if (status == STATUS_SUCCESS) {
        Irp->IoStatus.Information = sizeof(CX_GET_NETWORK_PRIORITY_RESPONSE);
    }

    return(status);

}   // CxDispatchGetNetworkPriority


NTSTATUS
CxDispatchSetNetworkPriority(
    IN PIRP               Irp,
    IN PIO_STACK_LOCATION IrpSp
    )
{
    NTSTATUS        status;
    ULONG           requestSize;
    PCX_SET_NETWORK_PRIORITY_REQUEST  request;


    PAGED_CODE();

    request = (PCX_SET_NETWORK_PRIORITY_REQUEST)
              Irp->AssociatedIrp.SystemBuffer;
    requestSize = IrpSp->Parameters.DeviceIoControl.InputBufferLength;

    if (requestSize < sizeof(CX_SET_NETWORK_PRIORITY_REQUEST)) {
        return(STATUS_INVALID_PARAMETER);
    }

    status = CxSetNetworkPriority(
                 request->Id,
                 request->Priority
                 );

    return(status);

}   // CxDispatchSetNetworkPriority


NTSTATUS
CxDispatchGetInterfacePriority(
    IN PIRP               Irp,
    IN PIO_STACK_LOCATION IrpSp
    )
{
    NTSTATUS                             status;
    PCX_GET_INTERFACE_PRIORITY_REQUEST   request;
    PCX_GET_INTERFACE_PRIORITY_RESPONSE  response;
    ULONG                                requestSize;
    ULONG                                responseSize;


    PAGED_CODE();

    request = (PCX_GET_INTERFACE_PRIORITY_REQUEST)
              Irp->AssociatedIrp.SystemBuffer;
    requestSize = IrpSp->Parameters.DeviceIoControl.InputBufferLength;

    response = (PCX_GET_INTERFACE_PRIORITY_RESPONSE) request;
    responseSize = IrpSp->Parameters.DeviceIoControl.OutputBufferLength;

    if ( (requestSize < sizeof(CX_GET_INTERFACE_PRIORITY_REQUEST)) ||
         (responseSize < sizeof(CX_GET_INTERFACE_PRIORITY_RESPONSE))
       )
    {
        return(STATUS_INVALID_PARAMETER);
    }

    status = CxGetInterfacePriority(
                 request->NodeId,
                 request->NetworkId,
                 &(response->InterfacePriority),
                 &(response->NetworkPriority)
                 );

    if (status == STATUS_SUCCESS) {
        Irp->IoStatus.Information = sizeof(CX_GET_INTERFACE_PRIORITY_RESPONSE);
    }

    return(status);

}   // CxDispatchGetInterfacePriority


NTSTATUS
CxDispatchSetInterfacePriority(
    IN PIRP               Irp,
    IN PIO_STACK_LOCATION IrpSp
    )
{
    NTSTATUS        status;
    ULONG           requestSize;
    PCX_SET_INTERFACE_PRIORITY_REQUEST  request;


    PAGED_CODE();

    request = (PCX_SET_INTERFACE_PRIORITY_REQUEST)
              Irp->AssociatedIrp.SystemBuffer;
    requestSize = IrpSp->Parameters.DeviceIoControl.InputBufferLength;

    if (requestSize < sizeof(CX_SET_INTERFACE_PRIORITY_REQUEST)) {
        return(STATUS_INVALID_PARAMETER);
    }

    status = CxSetInterfacePriority(
                 request->NodeId,
                 request->NetworkId,
                 request->Priority
                 );

    return(status);

}   // CxDispatchSetInterfacePriority


NTSTATUS
CxDispatchGetNodeState(
    IN PIRP               Irp,
    IN PIO_STACK_LOCATION IrpSp
    )
{
    NTSTATUS                             status;
    PCX_GET_NODE_STATE_REQUEST           request;
    PCX_GET_NODE_STATE_RESPONSE          response;
    ULONG                                requestSize;
    ULONG                                responseSize;


    PAGED_CODE();

    request = (PCX_GET_NODE_STATE_REQUEST)
              Irp->AssociatedIrp.SystemBuffer;
    requestSize = IrpSp->Parameters.DeviceIoControl.InputBufferLength;

    response = (PCX_GET_NODE_STATE_RESPONSE) request;
    responseSize = IrpSp->Parameters.DeviceIoControl.OutputBufferLength;

    if ( (requestSize < sizeof(CX_GET_NODE_STATE_REQUEST)) ||
         (responseSize < sizeof(CX_GET_NODE_STATE_RESPONSE))
       )
    {
        return(STATUS_INVALID_PARAMETER);
    }

    status = CxGetNodeCommState(
                 request->Id,
                 &(response->State)
                 );

    if (status == STATUS_SUCCESS) {
        Irp->IoStatus.Information = sizeof(CX_GET_NODE_STATE_RESPONSE);
    }

    return(status);

}   // CxDispatchGetNodeState


NTSTATUS
CxDispatchGetNetworkState(
    IN PIRP               Irp,
    IN PIO_STACK_LOCATION IrpSp
    )
{
    NTSTATUS                             status;
    PCX_GET_NETWORK_STATE_REQUEST        request;
    PCX_GET_NETWORK_STATE_RESPONSE       response;
    ULONG                                requestSize;
    ULONG                                responseSize;


    PAGED_CODE();

    request = (PCX_GET_NETWORK_STATE_REQUEST)
              Irp->AssociatedIrp.SystemBuffer;
    requestSize = IrpSp->Parameters.DeviceIoControl.InputBufferLength;

    response = (PCX_GET_NETWORK_STATE_RESPONSE) request;
    responseSize = IrpSp->Parameters.DeviceIoControl.OutputBufferLength;

    if ( (requestSize < sizeof(CX_GET_NETWORK_STATE_REQUEST)) ||
         (responseSize < sizeof(CX_GET_NETWORK_STATE_RESPONSE))
       )
    {
        return(STATUS_INVALID_PARAMETER);
    }

    status = CxGetNetworkState(
                 request->Id,
                 &(response->State)
                 );

    if (status == STATUS_SUCCESS) {
        Irp->IoStatus.Information = sizeof(CX_GET_NETWORK_STATE_RESPONSE);
    }

    return(status);

}   // CxDispatchGetNetworkState


NTSTATUS
CxDispatchGetInterfaceState(
    IN PIRP               Irp,
    IN PIO_STACK_LOCATION IrpSp
    )
{
    NTSTATUS                             status;
    PCX_GET_INTERFACE_STATE_REQUEST      request;
    PCX_GET_INTERFACE_STATE_RESPONSE     response;
    ULONG                                requestSize;
    ULONG                                responseSize;


    PAGED_CODE();

    request = (PCX_GET_INTERFACE_STATE_REQUEST)
              Irp->AssociatedIrp.SystemBuffer;
    requestSize = IrpSp->Parameters.DeviceIoControl.InputBufferLength;

    response = (PCX_GET_INTERFACE_STATE_RESPONSE) request;
    responseSize = IrpSp->Parameters.DeviceIoControl.OutputBufferLength;

    if ( (requestSize < sizeof(CX_GET_INTERFACE_STATE_REQUEST)) ||
         (responseSize < sizeof(CX_GET_INTERFACE_STATE_RESPONSE))
       )
    {
        return(STATUS_INVALID_PARAMETER);
    }

    status = CxGetInterfaceState(
                 request->NodeId,
                 request->NetworkId,
                 &(response->State)
                 );

    if (status == STATUS_SUCCESS) {
        Irp->IoStatus.Information = sizeof(CX_GET_INTERFACE_STATE_RESPONSE);
    }

    return(status);

}   // CxDispatchGetInterfaceState

NTSTATUS
CxDispatchIgnoreNodeState(
    IN PIRP               Irp,
    IN PIO_STACK_LOCATION IrpSp
    )
{
    PCX_ADDROBJ   addrObj = (PCX_ADDROBJ) (IrpSp->FileObject->FsContext);
    CN_IRQL       irql;


    CnAcquireLock(&(addrObj->Lock), &irql);

    IF_CNDBG(CN_DEBUG_ADDROBJ) {
        CNPRINT(("[CDP] Turning off checkstate flag on AO %p\n", addrObj));
    }

    addrObj->Flags &= ~(CX_AO_FLAG_CHECKSTATE);

    CnReleaseLock(&(addrObj->Lock), irql);

    return(STATUS_SUCCESS);

}   // CxDispatchIgnoreNodeState

NTSTATUS
CxDispatchGetNodeMembershipState(
    IN PIRP               Irp,
    IN PIO_STACK_LOCATION IrpSp
    )
{
    NTSTATUS status;
    PCX_GET_NODE_MMSTATE_REQUEST request;
    PCX_GET_NODE_MMSTATE_RESPONSE response;
    ULONG requestSize;
    ULONG responseSize;


    PAGED_CODE();

    request = (PCX_GET_NODE_MMSTATE_REQUEST)
              Irp->AssociatedIrp.SystemBuffer;
    requestSize = IrpSp->Parameters.DeviceIoControl.InputBufferLength;

    response = (PCX_GET_NODE_MMSTATE_RESPONSE) request;
    responseSize = IrpSp->Parameters.DeviceIoControl.OutputBufferLength;

    if ( (requestSize < sizeof(CX_GET_NODE_MMSTATE_REQUEST)) ||
         (responseSize < sizeof(CX_GET_NODE_MMSTATE_RESPONSE))
       )
    {
        return(STATUS_INVALID_PARAMETER);
    }

    status = CxGetNodeMembershipState( request->Id, &(response->State));

    if (status == STATUS_SUCCESS) {
        Irp->IoStatus.Information = sizeof(CX_GET_NODE_MMSTATE_RESPONSE);
    }

    return(status);

}   // CxDispatchGetNodeMembershipState

NTSTATUS
CxDispatchSetNodeMembershipState(
    IN PIRP               Irp,
    IN PIO_STACK_LOCATION IrpSp
    )
{
    NTSTATUS status;
    PCX_SET_NODE_MMSTATE_REQUEST request;
    ULONG requestSize;
    ULONG responseSize;


    PAGED_CODE();

    request = (PCX_SET_NODE_MMSTATE_REQUEST)
              Irp->AssociatedIrp.SystemBuffer;
    requestSize = IrpSp->Parameters.DeviceIoControl.InputBufferLength;

    if (requestSize < sizeof( CX_SET_NODE_MMSTATE_REQUEST ) ||
        request->State >= ClusnetNodeStateLastEntry) {

        return(STATUS_INVALID_PARAMETER);
    }

    status = CxSetNodeMembershipState( request->NodeId, request->State );

    Irp->IoStatus.Information = 0;

    return(status);

}   // CxDispatchSetNodeMembershipState

VOID
CxCompleteSendPoisonPacket(
    IN NTSTATUS  Status,
    IN ULONG     BytesSent,
    IN PVOID     Context,
    IN PVOID     MessageData
    )
{
    PIRP  irp = Context;

    CnAssert(Status != STATUS_PENDING);

    IF_CNDBG(( CN_DEBUG_IRP | CN_DEBUG_POISON ))
        CNPRINT(("[Clusnet] Completing SendPoisonPacket request for "
                 "irp %p, status %08X\n",
                 irp,
                 Status));

    //
    // The irp is completed in the CNP send completion routine.
    //

    return;

} // CxCompleteSendPoisonPacket


NTSTATUS
CxDispatchSendPoisonPacket(
    IN PIRP               Irp,
    IN PIO_STACK_LOCATION IrpSp
    )
{
    NTSTATUS                     status;
    PCX_SEND_POISON_PKT_REQUEST  request;
    ULONG                        requestSize;

    PAGED_CODE();

    request = (PCX_SEND_POISON_PKT_REQUEST) Irp->AssociatedIrp.SystemBuffer;
    requestSize = IrpSp->Parameters.DeviceIoControl.InputBufferLength;

    //
    // request size should exactly equal the size of the request struct plus
    // the data passed in
    //

    if ( requestSize != sizeof(CX_SEND_POISON_PKT_REQUEST)) {
        return(STATUS_INVALID_PARAMETER);
    }

    //
    // We will always return pending, so mark the IRP pending.
    // The IRP will be completed by CxCompleteSendPoisonPacket
    //
    IoMarkIrpPending(Irp);
    
    IF_CNDBG(( CN_DEBUG_IRP | CN_DEBUG_POISON ))
        CNPRINT(("[Clusnet] Posting SendPoisonPacket irp %p\n", Irp));

    CxSendPoisonPacket(
        request->Id,
        CxCompleteSendPoisonPacket,
        Irp,
        Irp
        );

    return(STATUS_PENDING);

} // CxDispatchSendPoisonPacket

NTSTATUS
CxDispatchSetOuterscreen(
    IN PIRP               Irp,
    IN PIO_STACK_LOCATION IrpSp
    )
{
    NTSTATUS status;
    PCX_SET_OUTERSCREEN_REQUEST request;
    ULONG requestSize;
    ULONG responseSize;


    PAGED_CODE();

    request = (PCX_SET_OUTERSCREEN_REQUEST)
              Irp->AssociatedIrp.SystemBuffer;
    requestSize = IrpSp->Parameters.DeviceIoControl.InputBufferLength;

    if ( requestSize < sizeof( CX_SET_OUTERSCREEN_REQUEST )) {

        return(STATUS_INVALID_PARAMETER);
    }

    status = CxSetOuterscreen( request->Outerscreen );

    Irp->IoStatus.Information = 0;

    return(status);

}   // CxDispatchSetOuterscreen

NTSTATUS
CxDispatchRegroupFinished(
    IN PIRP               Irp,
    IN PIO_STACK_LOCATION IrpSp
    )
{
    NTSTATUS status;
    PCX_REGROUP_FINISHED_REQUEST request;
    ULONG requestSize;
    ULONG responseSize;

    PAGED_CODE();

    request = (PCX_REGROUP_FINISHED_REQUEST)
              Irp->AssociatedIrp.SystemBuffer;
    requestSize = IrpSp->Parameters.DeviceIoControl.InputBufferLength;

    if ( requestSize < sizeof( CX_REGROUP_FINISHED_REQUEST )) {

        return(STATUS_INVALID_PARAMETER);
    }

    CxRegroupFinished( request->NewEpoch );

    Irp->IoStatus.Information = 0;

    return( STATUS_SUCCESS );

}   // CxDispatchRegroupFinished

NTSTATUS
CxDispatchImportSecurityContext(
    IN PIRP               Irp,
    IN PIO_STACK_LOCATION IrpSp
    )
{
    NTSTATUS status;
    PCX_IMPORT_SECURITY_CONTEXT_REQUEST request;
    ULONG requestSize;
    ULONG responseSize;

    PAGED_CODE();

    request = (PCX_IMPORT_SECURITY_CONTEXT_REQUEST)
              Irp->AssociatedIrp.SystemBuffer;
    requestSize = IrpSp->Parameters.DeviceIoControl.InputBufferLength;

    if ( requestSize < sizeof( CX_IMPORT_SECURITY_CONTEXT_REQUEST )) {

        return(STATUS_INVALID_PARAMETER);
    }

    status = CxImportSecurityContext(request->JoiningNodeId,
                                     request->PackageName,
                                     request->PackageNameSize,
                                     request->SignatureSize,
                                     request->ServerContext,
                                     request->ClientContext);

    Irp->IoStatus.Information = 0;

    return( status );

}   // CxDispatchImportSecurityContext

NTSTATUS
CxDispatchReserveClusnetEndpoint(
    IN PIRP               Irp,
    IN PIO_STACK_LOCATION IrpSp
    )
{
    NTSTATUS status;
    USHORT   port;
    ULONG    requestSize;

    PAGED_CODE();

    requestSize = IrpSp->Parameters.DeviceIoControl.InputBufferLength;

    if (requestSize < sizeof(USHORT)) {

        status = STATUS_INVALID_PARAMETER;
    }
    else {
        port = *((PUSHORT) Irp->AssociatedIrp.SystemBuffer);
        status = CxReserveClusnetEndpoint(port);
    }
    
    Irp->IoStatus.Information = 0;

    return (status);
}

NTSTATUS
CxDispatchConfigureMulticast(
    IN PIRP               Irp,
    IN PIO_STACK_LOCATION IrpSp
    )
{
    NTSTATUS                         status;
    PCX_CONFIGURE_MULTICAST_REQUEST  request;
    ULONG                            requestSize;
    ULONG                            requiredSize;

    PTRANSPORT_ADDRESS               tdiMcastAddress;
    PVOID                            key;
    PVOID                            salt;
    
    PAGED_CODE();

    //
    // Validate the request buffer
    //

    // First validate that the request buffer size matches the offsets
    // and lengths.
    request = (PCX_CONFIGURE_MULTICAST_REQUEST)Irp->AssociatedIrp.SystemBuffer;
    requestSize = IrpSp->Parameters.DeviceIoControl.InputBufferLength;

    //
    // The required size is based on the size and required alignment
    // of each field of data following the structure. If there is no
    // data following the structure, only the structure is required.
    //
    requiredSize = sizeof(CX_CONFIGURE_MULTICAST_REQUEST);

    //
    // Verify that the required size is present.
    //
    if (requestSize < requiredSize)
    {
        return(STATUS_INVALID_PARAMETER);
    }

    //
    // Verify that all offset length pairs are within the request size.
    //
    if ( ( request->MulticastAddress + request->MulticastAddressLength
           < request->MulticastAddress
         ) ||
         ( request->MulticastAddress + request->MulticastAddressLength
           > requestSize
         ) ||
         ( request->Key + request->KeyLength < request->Key
         ) ||
         ( request->Key + request->KeyLength > requestSize
         ) ||
         ( request->Salt + request->SaltLength < request->Salt
         ) ||
         ( request->Salt + request->SaltLength > requestSize
         )
       ) 
    {
        return(STATUS_INVALID_PARAMETER);
    }

    //
    // Construct pointers using the offsets.
    //
    tdiMcastAddress = (PTRANSPORT_ADDRESS)
                      ( ((PUCHAR) request) + request->MulticastAddress );

    key = (PVOID)( ((PUCHAR) request) + request->Key );

    salt = (PVOID)( ((PUCHAR) request) + request->Salt );

    //
    // Validate that the resulting pointers are properly aligned and
    // within the request data structure.
    //
    if ( ( ((PUCHAR) tdiMcastAddress) < ((PUCHAR) request) ) ||
         ( ((PUCHAR) tdiMcastAddress) > ((PUCHAR) request) + requestSize ) ||
         ( !POINTER_IS_ALIGNED(tdiMcastAddress, 
                               TYPE_ALIGNMENT(TRANSPORT_ADDRESS))) ||
         ( ((PUCHAR) key) < ((PUCHAR) request) ) ||
         ( ((PUCHAR) key) > ((PUCHAR) request) + requestSize ) ||
         ( !POINTER_IS_ALIGNED(key, TYPE_ALIGNMENT(PVOID))) ||
         ( ((PUCHAR) salt) < ((PUCHAR) request) ) ||
         ( ((PUCHAR) salt) > ((PUCHAR) request) + requestSize ) ||
         ( !POINTER_IS_ALIGNED(salt, TYPE_ALIGNMENT(PVOID)))
       ) 
    {
        return(STATUS_INVALID_PARAMETER);
    }

    status = CxConfigureMulticast(
                 request->NetworkId,
                 request->MulticastNetworkBrand,
                 tdiMcastAddress,
                 request->MulticastAddressLength,
                 key,
                 request->KeyLength,
                 salt,
                 request->SaltLength,
                 Irp
                 );

    // No return data.
    Irp->IoStatus.Information = 0;

    return(status);

} // CxDispatchConfigureMulticast

NTSTATUS
CxDispatchGetMulticastReachableSet(
    IN PIRP               Irp,
    IN PIO_STACK_LOCATION IrpSp
    )
{
    NTSTATUS                                  status;
    PCX_GET_MULTICAST_REACHABLE_SET_REQUEST   request;
    PCX_GET_MULTICAST_REACHABLE_SET_RESPONSE  response;
    ULONG                                     requestSize;
    ULONG                                     responseSize;

    PAGED_CODE();

    request = (PCX_GET_MULTICAST_REACHABLE_SET_REQUEST)
              Irp->AssociatedIrp.SystemBuffer;
    requestSize = IrpSp->Parameters.DeviceIoControl.InputBufferLength;

    response = (PCX_GET_MULTICAST_REACHABLE_SET_RESPONSE) request;
    responseSize = IrpSp->Parameters.DeviceIoControl.OutputBufferLength;

    if ( (requestSize < sizeof(PCX_GET_MULTICAST_REACHABLE_SET_REQUEST)) ||
         (responseSize < sizeof(PCX_GET_MULTICAST_REACHABLE_SET_RESPONSE))
       )
    {
        return(STATUS_INVALID_PARAMETER);
    }

    status = CxGetMulticastReachableSet(
                 request->Id,
                 &(response->NodeScreen)
                 );

    if (status == STATUS_SUCCESS) {
        Irp->IoStatus.Information = 
            sizeof(CX_GET_MULTICAST_REACHABLE_SET_RESPONSE);
    }

    return(status);

} // CxDispatchGetMulticastReachableSet

//
// Test IOCTLs.
//
#if DBG

NTSTATUS
CxDispatchOnlinePendingInterface(
    IN PIRP               Irp,
    IN PIO_STACK_LOCATION IrpSp
    )
{
    NTSTATUS                               status;
    PCX_ONLINE_PENDING_INTERFACE_REQUEST   request;
    ULONG                                  requestSize;


    PAGED_CODE();

    request = (PCX_ONLINE_PENDING_INTERFACE_REQUEST)
              Irp->AssociatedIrp.SystemBuffer;
    requestSize = IrpSp->Parameters.DeviceIoControl.InputBufferLength;

    if (requestSize < sizeof(CX_ONLINE_PENDING_INTERFACE_REQUEST)) {
        return(STATUS_INVALID_PARAMETER);
    }

    status = CxOnlinePendingInterface(request->NodeId, request->NetworkId);

    return(status);
}   // CxDispatchOnlinePendingInterface


NTSTATUS
CxDispatchOnlineInterface(
    IN PIRP               Irp,
    IN PIO_STACK_LOCATION IrpSp
    )
{
    NTSTATUS                               status;
    PCX_ONLINE_PENDING_INTERFACE_REQUEST   request;
    ULONG                                  requestSize;


    PAGED_CODE();

    request = (PCX_ONLINE_PENDING_INTERFACE_REQUEST)
              Irp->AssociatedIrp.SystemBuffer;
    requestSize = IrpSp->Parameters.DeviceIoControl.InputBufferLength;

    if (requestSize < sizeof(CX_ONLINE_PENDING_INTERFACE_REQUEST)) {
        return(STATUS_INVALID_PARAMETER);
    }

    status = CxOnlineInterface(request->NodeId, request->NetworkId);

    return(status);

}   // CxDispatchOnlineInterface


NTSTATUS
CxDispatchOfflineInterface(
    IN PIRP               Irp,
    IN PIO_STACK_LOCATION IrpSp
    )
{
    NTSTATUS                               status;
    PCX_ONLINE_PENDING_INTERFACE_REQUEST   request;
    ULONG                                  requestSize;


    PAGED_CODE();

    request = (PCX_ONLINE_PENDING_INTERFACE_REQUEST)
              Irp->AssociatedIrp.SystemBuffer;
    requestSize = IrpSp->Parameters.DeviceIoControl.InputBufferLength;

    if (requestSize < sizeof(CX_ONLINE_PENDING_INTERFACE_REQUEST)) {
        return(STATUS_INVALID_PARAMETER);
    }

    status = CxOfflineInterface(request->NodeId, request->NetworkId);

    return(status);

}   // CxDispatchOfflineInterface


NTSTATUS
CxDispatchFailInterface(
    IN PIRP               Irp,
    IN PIO_STACK_LOCATION IrpSp
    )
{
    NTSTATUS                               status;
    PCX_ONLINE_PENDING_INTERFACE_REQUEST   request;
    ULONG                                  requestSize;


    PAGED_CODE();

    request = (PCX_ONLINE_PENDING_INTERFACE_REQUEST)
              Irp->AssociatedIrp.SystemBuffer;
    requestSize = IrpSp->Parameters.DeviceIoControl.InputBufferLength;

    if (requestSize < sizeof(CX_ONLINE_PENDING_INTERFACE_REQUEST)) {
        return(STATUS_INVALID_PARAMETER);
    }

    status = CxFailInterface(request->NodeId, request->NetworkId);

    return(status);

}   // CxDispatchFailInterface


VOID
CxCompleteSendMmMsg(
    IN NTSTATUS  Status,
    IN ULONG     BytesSent,
    IN PVOID     Context,
    IN PVOID     MessageData
    )
{
    PIRP  irp = Context;

    CnAssert(Status != STATUS_PENDING);

    CNPRINT((
        "[Clusnet] Completing SendMmMsg irp %p, status %lx, bytes sent %u\n",
        irp,
        Status,
        BytesSent
        ));

    //
    // Complete the irp.
    //
    irp->IoStatus.Status = Status;
    irp->IoStatus.Information = 0;

    IoCompleteRequest(irp, IO_NETWORK_INCREMENT);

    return;

} // CxCompleteSendMmMsg

#ifdef MM_IN_CLUSNET

NTSTATUS
CxDispatchSendMmMsg(
    IN PIRP               Irp,
    IN PIO_STACK_LOCATION IrpSp
    )
{
    NTSTATUS                     status;
    PCX_SEND_MM_MSG_REQUEST      request;
    ULONG                        requestSize;


    PAGED_CODE();

    request = (PCX_SEND_MM_MSG_REQUEST) Irp->AssociatedIrp.SystemBuffer;
    requestSize = IrpSp->Parameters.DeviceIoControl.InputBufferLength;

    if (requestSize < sizeof(CX_SEND_MM_MSG_REQUEST)) {
        return(STATUS_INVALID_PARAMETER);
    }

    IoMarkIrpPending(Irp);

    CNPRINT(("[Clusnet] Posting SendMmMsg irp %p\n", Irp));

    status = CxSendMembershipMessage(
                 request->DestNodeId,
                 &(request->MessageData[0]),
                 CX_MM_MSG_DATA_LEN,
                 CxCompleteSendMmMsg,
                 Irp
                 );

    return(status);


} // CxDispatchSendMmMsg
#endif // MM_IN_CLUSNET

#endif // DBG