mirror of https://github.com/tongzx/nt5src
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
3052 lines
64 KiB
3052 lines
64 KiB
/*++
|
|
|
|
Copyright (c) 1996 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
D:\nt\private\ntos\tdi\rawwan\core\ntentry.c
|
|
|
|
Abstract:
|
|
|
|
NT specific entry points for dispatching and handling TDI IRPs. Based on
|
|
TCP source.
|
|
|
|
Revision History:
|
|
|
|
Who When What
|
|
-------- -------- ----------------------------------------------
|
|
arvindm 04-21-97 Created
|
|
|
|
Notes:
|
|
|
|
--*/
|
|
|
|
#include <precomp.h>
|
|
|
|
#define _FILENUMBER 'IDTN'
|
|
|
|
|
|
|
|
#define RWAN_COMPLETE_IRP(_pIrp, _Status, _Info) \
|
|
{ \
|
|
(_pIrp)->IoStatus.Status = (NTSTATUS)(_Status); \
|
|
(_pIrp)->IoStatus.Information = (_Info); \
|
|
IoCompleteRequest(_pIrp, IO_NETWORK_INCREMENT); \
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
NTSTATUS
|
|
DriverEntry(
|
|
IN PDRIVER_OBJECT pDriverObject,
|
|
IN PUNICODE_STRING pRegistryPath
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is the "init" routine called by the system when Raw WAN
|
|
is loaded. We initialize all our global objects, fill in our
|
|
Dispatch and Unload routine addresses in the driver object.
|
|
|
|
We initialize the media/AF specific modules, and they register support
|
|
for TDI protocols, at which time we create device objects.
|
|
|
|
Arguments:
|
|
|
|
pDriverObject - Pointer to the driver object created by the system.
|
|
pRegistryPath - Pointer to our global registry path. This is ignored.
|
|
|
|
Return Value:
|
|
|
|
NT Status code: STATUS_SUCCESS if successful, error code otherwise.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
RWAN_STATUS RWanStatus;
|
|
PDEVICE_OBJECT pDeviceObject;
|
|
UNICODE_STRING DeviceName;
|
|
INT i;
|
|
|
|
RWANDEBUGP(DL_FATAL, DC_WILDCARD,
|
|
("RWanDebugLevel is %d, &RWanDebugLevel at x%x\n",
|
|
RWanDebugLevel, &RWanDebugLevel));
|
|
RWANDEBUGP(DL_FATAL, DC_WILDCARD,
|
|
("RWanDebugComp is x%x, &RWanDebugComp at x%x\n",
|
|
RWanDebugComp, &RWanDebugComp));
|
|
RWANDEBUGP(DL_FATAL, DC_WILDCARD,
|
|
("RWanGlobals at x%x\n", &RWanGlobals));
|
|
#if DBG
|
|
RWANDEBUGP(DL_FATAL, DC_WILDCARD,
|
|
("To skip everything set RWanSkipAll at x%x to 1\n", &RWanSkipAll));
|
|
|
|
if (RWanSkipAll)
|
|
{
|
|
RWANDEBUGP(DL_FATAL, DC_WILDCARD,
|
|
("Aborting DriverEntry\n"));
|
|
return (STATUS_UNSUCCESSFUL);
|
|
}
|
|
|
|
NdisAllocateSpinLock(&RWanDbgLogLock);
|
|
#if DBG_LOG_PACKETS
|
|
NdisAllocateSpinLock(&RWanDPacketLogLock);
|
|
#endif
|
|
#endif // DBG
|
|
|
|
|
|
RWanStatus = RWanInitGlobals(pDriverObject);
|
|
|
|
if (RWanStatus != RWAN_STATUS_SUCCESS)
|
|
{
|
|
return (STATUS_UNSUCCESSFUL);
|
|
}
|
|
|
|
//
|
|
// Register as an NDIS protocol.
|
|
//
|
|
RWAN_ZERO_MEM(&RWanNdisProtocolCharacteristics, sizeof(RWanNdisProtocolCharacteristics));
|
|
|
|
RWanNdisProtocolCharacteristics.MajorNdisVersion = RWAN_NDIS_MAJOR_VERSION;
|
|
RWanNdisProtocolCharacteristics.MinorNdisVersion = RWAN_NDIS_MINOR_VERSION;
|
|
RWanNdisProtocolCharacteristics.OpenAdapterCompleteHandler = RWanNdisOpenAdapterComplete;
|
|
RWanNdisProtocolCharacteristics.CloseAdapterCompleteHandler = RWanNdisCloseAdapterComplete;
|
|
RWanNdisProtocolCharacteristics.SendCompleteHandler = RWanNdisSendComplete;
|
|
RWanNdisProtocolCharacteristics.TransferDataCompleteHandler = RWanNdisTransferDataComplete;
|
|
RWanNdisProtocolCharacteristics.ResetCompleteHandler = RWanNdisResetComplete;
|
|
RWanNdisProtocolCharacteristics.RequestCompleteHandler = RWanNdisRequestComplete;
|
|
RWanNdisProtocolCharacteristics.ReceiveHandler = RWanNdisReceive;
|
|
RWanNdisProtocolCharacteristics.ReceiveCompleteHandler = RWanNdisReceiveComplete;
|
|
RWanNdisProtocolCharacteristics.StatusHandler = RWanNdisStatus;
|
|
RWanNdisProtocolCharacteristics.StatusCompleteHandler = RWanNdisStatusComplete;
|
|
NdisInitUnicodeString(
|
|
&RWanNdisProtocolCharacteristics.Name,
|
|
RWAN_NAME
|
|
);
|
|
RWanNdisProtocolCharacteristics.ReceivePacketHandler = RWanNdisReceivePacket;
|
|
RWanNdisProtocolCharacteristics.BindAdapterHandler = RWanNdisBindAdapter;
|
|
RWanNdisProtocolCharacteristics.PnPEventHandler = RWanNdisPnPEvent;
|
|
RWanNdisProtocolCharacteristics.UnbindAdapterHandler = RWanNdisUnbindAdapter;
|
|
RWanNdisProtocolCharacteristics.UnloadHandler = (UNLOAD_PROTOCOL_HANDLER)RWanUnloadProtocol;
|
|
#ifdef _PNP_POWER_
|
|
RWanNdisProtocolCharacteristics.PnpEventHandler = RWanNdisPnPEvent;
|
|
#endif // _PNP_POWER_
|
|
RWanNdisProtocolCharacteristics.CoSendCompleteHandler = RWanNdisCoSendComplete;
|
|
RWanNdisProtocolCharacteristics.CoStatusHandler = RWanNdisCoStatus;
|
|
RWanNdisProtocolCharacteristics.CoReceivePacketHandler = RWanNdisCoReceivePacket;
|
|
#if 0
|
|
RWanNdisProtocolCharacteristics.CoRequestHandler = RWanNdisCoRequest;
|
|
RWanNdisProtocolCharacteristics.CoRequestCompleteHandler = RWanNdisCoRequestComplete;
|
|
#endif
|
|
RWanNdisProtocolCharacteristics.CoAfRegisterNotifyHandler = RWanNdisAfRegisterNotify;
|
|
|
|
RWAN_ZERO_MEM(&RWanNdisClientCharacteristics, sizeof(RWanNdisClientCharacteristics));
|
|
|
|
RWanNdisClientCharacteristics.MajorVersion = RWAN_NDIS_MAJOR_VERSION;
|
|
RWanNdisClientCharacteristics.MinorVersion = RWAN_NDIS_MINOR_VERSION;
|
|
RWanNdisClientCharacteristics.ClCreateVcHandler = RWanNdisCreateVc;
|
|
RWanNdisClientCharacteristics.ClDeleteVcHandler = RWanNdisDeleteVc;
|
|
RWanNdisClientCharacteristics.ClOpenAfCompleteHandler = RWanNdisOpenAddressFamilyComplete;
|
|
RWanNdisClientCharacteristics.ClCloseAfCompleteHandler = RWanNdisCloseAddressFamilyComplete;
|
|
RWanNdisClientCharacteristics.ClRegisterSapCompleteHandler = RWanNdisRegisterSapComplete;
|
|
RWanNdisClientCharacteristics.ClDeregisterSapCompleteHandler = RWanNdisDeregisterSapComplete;
|
|
RWanNdisClientCharacteristics.ClMakeCallCompleteHandler = RWanNdisMakeCallComplete;
|
|
RWanNdisClientCharacteristics.ClModifyCallQoSCompleteHandler = RWanNdisModifyQoSComplete;
|
|
RWanNdisClientCharacteristics.ClCloseCallCompleteHandler = RWanNdisCloseCallComplete;
|
|
RWanNdisClientCharacteristics.ClAddPartyCompleteHandler = RWanNdisAddPartyComplete;
|
|
RWanNdisClientCharacteristics.ClDropPartyCompleteHandler = RWanNdisDropPartyComplete;
|
|
RWanNdisClientCharacteristics.ClIncomingCallHandler = RWanNdisIncomingCall;
|
|
RWanNdisClientCharacteristics.ClIncomingCallQoSChangeHandler = (CL_INCOMING_CALL_QOS_CHANGE_HANDLER)NULL;
|
|
RWanNdisClientCharacteristics.ClIncomingCloseCallHandler = RWanNdisIncomingCloseCall;
|
|
RWanNdisClientCharacteristics.ClIncomingDropPartyHandler = RWanNdisIncomingDropParty;
|
|
RWanNdisClientCharacteristics.ClCallConnectedHandler = RWanNdisCallConnected;
|
|
#if 1
|
|
RWanNdisClientCharacteristics.ClRequestHandler = RWanNdisCoRequest;
|
|
RWanNdisClientCharacteristics.ClRequestCompleteHandler = RWanNdisCoRequestComplete;
|
|
#endif
|
|
|
|
NdisRegisterProtocol(
|
|
&Status,
|
|
&(pRWanGlobal->ProtocolHandle),
|
|
&RWanNdisProtocolCharacteristics,
|
|
sizeof(RWanNdisProtocolCharacteristics)
|
|
);
|
|
|
|
if (Status != NDIS_STATUS_SUCCESS)
|
|
{
|
|
return (Status);
|
|
}
|
|
|
|
#if DBG
|
|
if (RWanSkipAll)
|
|
{
|
|
RWANDEBUGP(DL_FATAL, DC_WILDCARD,
|
|
("Aborting DriverEntry\n"));
|
|
|
|
NdisDeregisterProtocol(
|
|
&Status,
|
|
pRWanGlobal->ProtocolHandle
|
|
);
|
|
|
|
return (STATUS_UNSUCCESSFUL);
|
|
}
|
|
#endif // DBG
|
|
|
|
//
|
|
// Tell all media-specific modules to initialize.
|
|
//
|
|
RWanStatus = RWanInitMediaSpecific();
|
|
|
|
if (RWanStatus != RWAN_STATUS_SUCCESS)
|
|
{
|
|
NdisDeregisterProtocol(
|
|
&Status,
|
|
pRWanGlobal->ProtocolHandle
|
|
);
|
|
|
|
return (STATUS_UNSUCCESSFUL);
|
|
}
|
|
|
|
|
|
#if !BINARY_COMPATIBLE
|
|
//
|
|
// Initialize the Driver Object.
|
|
//
|
|
pDriverObject->DriverUnload = RWanUnload;
|
|
pDriverObject->FastIoDispatch = NULL;
|
|
|
|
for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++)
|
|
{
|
|
pDriverObject->MajorFunction[i] = RWanDispatch;
|
|
}
|
|
|
|
pDriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] =
|
|
RWanDispatchInternalDeviceControl;
|
|
|
|
#endif // !BINARY_COMPATIBLE
|
|
|
|
|
|
return (STATUS_SUCCESS);
|
|
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
RWanUnload(
|
|
IN PDRIVER_OBJECT pDriverObject
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is called by the system prior to unloading us. Undo everything
|
|
we did in DriverEntry.
|
|
|
|
Arguments:
|
|
|
|
pDriverObject - Pointer to the driver object representing us.
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
#if DBG
|
|
RWanDebugLevel = DL_EXTRA_LOUD;
|
|
RWanDebugComp = DC_WILDCARD;
|
|
#endif
|
|
|
|
RWANDEBUGP(DC_DISPATCH, DL_INFO,
|
|
("RWanUnload entered: RWanGlobals at x%x\n", &RWanGlobals));
|
|
|
|
RWanUnloadProtocol();
|
|
|
|
RWANDEBUGP(DC_DISPATCH, DL_INFO,
|
|
("RWanUnload exiting\n"));
|
|
}
|
|
|
|
|
|
|
|
|
|
VOID
|
|
RWanUnloadProtocol(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Unloads the Raw WAN protocol module. We unbind from all adapters,
|
|
and shut down all media specific modules.
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
NDIS_STATUS Status;
|
|
PRWAN_NDIS_ADAPTER pAdapter;
|
|
#if DBG
|
|
RWAN_IRQL EntryIrq, ExitIrq;
|
|
#endif // DBG
|
|
|
|
RWAN_GET_ENTRY_IRQL(EntryIrq);
|
|
|
|
RWAN_ACQUIRE_GLOBAL_LOCK();
|
|
|
|
if (pRWanGlobal->UnloadDone)
|
|
{
|
|
RWANDEBUGP(DL_INFO, DC_WILDCARD,
|
|
("UnloadProtocol: already done!\n"));
|
|
RWAN_RELEASE_GLOBAL_LOCK();
|
|
return;
|
|
}
|
|
|
|
pRWanGlobal->UnloadDone = TRUE;
|
|
|
|
#if 0
|
|
//
|
|
// Commented out because of an NDIS change: if we have unclosed
|
|
// adapter bindings at this time, NDIS will call our Unbind
|
|
// handler for each of these, when we call NdisDeregisterProtocol
|
|
// below.
|
|
//
|
|
|
|
while (pRWanGlobal->AdapterCount != 0)
|
|
{
|
|
RWAN_ASSERT (!RWAN_IS_LIST_EMPTY(&pRWanGlobal->AdapterList));
|
|
|
|
pAdapter = CONTAINING_RECORD(pRWanGlobal->AdapterList.Flink,
|
|
RWAN_NDIS_ADAPTER,
|
|
AdapterLink);
|
|
|
|
RWAN_STRUCT_ASSERT(pAdapter, nad);
|
|
|
|
RWAN_RELEASE_GLOBAL_LOCK();
|
|
|
|
RWanNdisUnbindAdapter(
|
|
&Status,
|
|
(NDIS_HANDLE)pAdapter,
|
|
NULL // No UnbindContext implies don't complete NdisUnbindAdapter
|
|
);
|
|
|
|
if (Status == NDIS_STATUS_PENDING)
|
|
{
|
|
//
|
|
// Wait for the unbind to complete.
|
|
//
|
|
(VOID)RWAN_WAIT_ON_EVENT_STRUCT(&pRWanGlobal->Event);
|
|
}
|
|
|
|
RWAN_ACQUIRE_GLOBAL_LOCK();
|
|
}
|
|
#endif // 0
|
|
|
|
RWAN_RELEASE_GLOBAL_LOCK();
|
|
|
|
RWAN_CHECK_EXIT_IRQL(EntryIrq, ExitIrq);
|
|
|
|
RWANDEBUGP(DL_FATAL, DC_DISPATCH,
|
|
("RWanUnloadProtocol: will deregister protocol now\n"));
|
|
|
|
NdisDeregisterProtocol(
|
|
&Status,
|
|
pRWanGlobal->ProtocolHandle
|
|
);
|
|
|
|
RWANDEBUGP(DL_FATAL, DC_DISPATCH,
|
|
("UnloadProtocol: dereg protocol done\n"));
|
|
|
|
RWanDeinitGlobals();
|
|
|
|
RWAN_CHECK_EXIT_IRQL(EntryIrq, ExitIrq);
|
|
|
|
RWanShutdownMediaSpecific();
|
|
|
|
RWAN_CHECK_EXIT_IRQL(EntryIrq, ExitIrq);
|
|
#if DBG
|
|
RWanAuditShutdown();
|
|
#endif // DBG
|
|
|
|
RWAN_CHECK_EXIT_IRQL(EntryIrq, ExitIrq);
|
|
}
|
|
|
|
|
|
|
|
|
|
NTSTATUS
|
|
RWanDispatch(
|
|
IN PDEVICE_OBJECT pDeviceObject,
|
|
IN PIRP pIrp
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
System entry point for all IRPs dispatched to Raw WAN device objects.
|
|
|
|
Arguments:
|
|
|
|
pDeviceObject - Points to a device object created by RawWan. This
|
|
device object identifies a supported Winsock 2 triple
|
|
<Address Family, Type, Proto>.
|
|
pIrp - Pointer to the IRP
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - STATUS_SUCCESS for immediate requests (such as create) that
|
|
we successfully process, STATUS_PENDING for queued IRPs, and STATUS_XXX
|
|
error codes for any failures.
|
|
|
|
--*/
|
|
{
|
|
PIO_STACK_LOCATION pIrpSp;
|
|
NTSTATUS Status;
|
|
#if DBG
|
|
RWAN_IRQL EntryIrq, ExitIrq;
|
|
#endif // DBG
|
|
|
|
RWAN_GET_ENTRY_IRQL(EntryIrq);
|
|
|
|
pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
|
|
pIrp->IoStatus.Information = 0;
|
|
|
|
RWAN_ASSERT(pIrpSp->MajorFunction != IRP_MJ_INTERNAL_DEVICE_CONTROL);
|
|
|
|
|
|
switch (pIrpSp->MajorFunction)
|
|
{
|
|
case IRP_MJ_CREATE:
|
|
|
|
Status = RWanCreate(pDeviceObject, pIrp, pIrpSp);
|
|
break;
|
|
|
|
case IRP_MJ_CLEANUP:
|
|
|
|
Status = RWanCleanup(pDeviceObject, pIrp, pIrpSp);
|
|
break;
|
|
|
|
case IRP_MJ_CLOSE:
|
|
|
|
Status = RWanClose(pDeviceObject, pIrp, pIrpSp);
|
|
break;
|
|
|
|
case IRP_MJ_DEVICE_CONTROL:
|
|
|
|
Status = TdiMapUserRequest(pDeviceObject, pIrp, pIrpSp);
|
|
//
|
|
// TBD - get rid of the call to TdiMapUserRequest - AFD will be
|
|
// fixed so that we shouldn't see TDI commands come this way.
|
|
//
|
|
|
|
if (Status == STATUS_SUCCESS)
|
|
{
|
|
if (pIrpSp->MinorFunction == TDI_ASSOCIATE_ADDRESS ||
|
|
pIrpSp->MinorFunction == TDI_DISASSOCIATE_ADDRESS)
|
|
{
|
|
return (RWanDispatchInternalDeviceControl(pDeviceObject, pIrp));
|
|
}
|
|
else
|
|
{
|
|
Status = STATUS_ACCESS_DENIED;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return (RWanDispatchPrivateDeviceControl(pIrp, pIrpSp));
|
|
}
|
|
break;
|
|
|
|
case IRP_MJ_READ:
|
|
case IRP_MJ_WRITE:
|
|
default:
|
|
|
|
RWANDEBUGP(DL_WARN, DC_DISPATCH,
|
|
("RWanDispatch: Unknown MajorFunction x%x\n", pIrpSp->MajorFunction));
|
|
Status = STATUS_INVALID_DEVICE_REQUEST;
|
|
break;
|
|
}
|
|
|
|
|
|
RWAN_ASSERT(Status != TDI_PENDING);
|
|
|
|
RWAN_COMPLETE_IRP(pIrp, Status, 0);
|
|
|
|
RWANDEBUGP(DL_VERY_LOUD, DC_DISPATCH,
|
|
("RWanDispatch: pIrp x%x, MajorFunc %d, returning Status x%x, Info %d\n",
|
|
pIrp, pIrpSp->MajorFunction, Status, pIrp->IoStatus.Information));
|
|
|
|
RWAN_CHECK_EXIT_IRQL(EntryIrq, ExitIrq);
|
|
|
|
return (Status);
|
|
}
|
|
|
|
|
|
|
|
|
|
NTSTATUS
|
|
RWanCreate(
|
|
IN PDEVICE_OBJECT pDeviceObject,
|
|
IN PIRP pIrp,
|
|
PIO_STACK_LOCATION pIrpSp
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is called when a TDI client calls CreateFile. We allocate an
|
|
ENDPOINT structure as our context for this endpoint. Based on
|
|
parameters in the IRP, this is either an Address object, Connection
|
|
object, or a Control channel.
|
|
|
|
Arguments:
|
|
|
|
pDeviceObject - Identifies the protocol being CreateFile'd
|
|
pIrp - Pointer to IRP
|
|
pIrpSp - IRP Stack location
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - STATUS_SUCCESS if we create the endpoint successfully,
|
|
STATUS_INSUFFICIENT_RESOURCES if we fail to allocate, and
|
|
STATUS_INVALID_PARAMETER if we find any parameter incorrect.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
FILE_FULL_EA_INFORMATION * pEa;
|
|
FILE_FULL_EA_INFORMATION UNALIGNED * pTargetEa;
|
|
|
|
//
|
|
// Device being accessed.
|
|
//
|
|
PRWAN_DEVICE_OBJECT pRWanDevice;
|
|
|
|
//
|
|
// Endpoint to represent this object creation.
|
|
//
|
|
PRWAN_ENDPOINT pEndpoint;
|
|
|
|
//
|
|
// TDI Request to be passed down to our TDI layer.
|
|
//
|
|
TDI_REQUEST TdiRequest;
|
|
|
|
//
|
|
// Parameters to be passed down to our TDI layer.
|
|
//
|
|
UINT Protocol;
|
|
UCHAR OptionsBuffer[3];
|
|
PUCHAR pOptions;
|
|
|
|
|
|
|
|
PAGED_CODE();
|
|
|
|
//
|
|
// Initialize.
|
|
//
|
|
pEndpoint = NULL_PRWAN_ENDPOINT;
|
|
|
|
do
|
|
{
|
|
//
|
|
// Locate the TDI Protocol being opened.
|
|
//
|
|
pRWanDevice = *(PRWAN_DEVICE_OBJECT *)(pDeviceObject->DeviceExtension);
|
|
|
|
if (pRWanDevice == NULL)
|
|
{
|
|
Status = STATUS_NO_SUCH_DEVICE;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Allocate and initialize an Endpoint to represent
|
|
// this newly created object.
|
|
//
|
|
RWAN_ALLOC_MEM(pEndpoint, RWAN_ENDPOINT, sizeof(RWAN_ENDPOINT));
|
|
|
|
if (pEndpoint == NULL_PRWAN_ENDPOINT)
|
|
{
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
break;
|
|
}
|
|
|
|
RWAN_ZERO_MEM(pEndpoint, sizeof(RWAN_ENDPOINT));
|
|
|
|
RWAN_SET_SIGNATURE(pEndpoint, nep);
|
|
|
|
pEndpoint->RefCount = 1;
|
|
pEndpoint->bCancelIrps = FALSE;
|
|
KeInitializeEvent(&pEndpoint->CleanupEvent, SynchronizationEvent, FALSE);
|
|
pEndpoint->pProtocol = pRWanDevice->pProtocol;
|
|
|
|
RWAN_EP_DBGLOG_SET_SIGNATURE(pEndpoint);
|
|
|
|
pEa = (PFILE_FULL_EA_INFORMATION)pIrp->AssociatedIrp.SystemBuffer;
|
|
|
|
//
|
|
// See if this is a Control Channel.
|
|
//
|
|
if (!pEa)
|
|
{
|
|
RWANDEBUGP(DL_LOUD, DC_DISPATCH,
|
|
("RWanCreate: pIrp x%x, File obj x%x, Control Channel\n",
|
|
pIrp, pIrpSp->FileObject));
|
|
|
|
RWAN_ASSERT(pRWanDevice->pProtocol);
|
|
|
|
pEndpoint->Handle.ControlChannel = pRWanDevice->pProtocol;
|
|
pIrpSp->FileObject->FsContext = pEndpoint;
|
|
pIrpSp->FileObject->FsContext2 = (PVOID)TDI_CONTROL_CHANNEL_FILE;
|
|
|
|
RWAN_EP_DBGLOG_ENTRY(pEndpoint, 'CCrC', 0, 0);
|
|
|
|
Status = STATUS_SUCCESS;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// See if this is an Address Object.
|
|
//
|
|
|
|
pTargetEa = RWanFindEa(
|
|
pEa,
|
|
TdiTransportAddress,
|
|
TDI_TRANSPORT_ADDRESS_LENGTH
|
|
);
|
|
|
|
if (pTargetEa != NULL)
|
|
{
|
|
RWAN_EP_DBGLOG_ENTRY(pEndpoint, 'OArC', 0, 0);
|
|
|
|
if (pTargetEa->EaValueLength < sizeof(TRANSPORT_ADDRESS))
|
|
{
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
|
|
if (!pRWanDevice->pProtocol->bAllowAddressObjects)
|
|
{
|
|
Status = STATUS_INVALID_DEVICE_REQUEST;
|
|
break;
|
|
}
|
|
|
|
Protocol = pRWanDevice->pProtocol->SockProtocol;
|
|
pOptions = OptionsBuffer;
|
|
|
|
if ((pIrpSp->Parameters.Create.ShareAccess & FILE_SHARE_READ) ||
|
|
(pIrpSp->Parameters.Create.ShareAccess & FILE_SHARE_WRITE))
|
|
{
|
|
*pOptions = TDI_ADDRESS_OPTION_REUSE;
|
|
pOptions++;
|
|
}
|
|
|
|
*pOptions = TDI_OPTION_EOL;
|
|
|
|
//
|
|
// Call our TDI entry point.
|
|
//
|
|
Status = RWanTdiOpenAddress(
|
|
&TdiRequest,
|
|
(TRANSPORT_ADDRESS UNALIGNED *)
|
|
&(pTargetEa->EaName[pTargetEa->EaNameLength + 1]),
|
|
pTargetEa->EaValueLength,
|
|
Protocol,
|
|
OptionsBuffer
|
|
);
|
|
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
pEndpoint->Handle.AddressHandle = TdiRequest.Handle.AddressHandle;
|
|
pIrpSp->FileObject->FsContext = pEndpoint;
|
|
pIrpSp->FileObject->FsContext2 = (PVOID)TDI_TRANSPORT_ADDRESS_FILE;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
//
|
|
// See if this is a Connection Object.
|
|
//
|
|
pTargetEa = RWanFindEa(
|
|
pEa,
|
|
TdiConnectionContext,
|
|
TDI_CONNECTION_CONTEXT_LENGTH
|
|
);
|
|
|
|
if (pTargetEa != NULL)
|
|
{
|
|
RWAN_EP_DBGLOG_ENTRY(pEndpoint, 'OCrC', 0, 0);
|
|
|
|
if (pTargetEa->EaValueLength < sizeof(CONNECTION_CONTEXT))
|
|
{
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
|
|
if (!pRWanDevice->pProtocol->bAllowConnObjects)
|
|
{
|
|
Status = STATUS_INVALID_DEVICE_REQUEST;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Call our TDI entry point for opening a Connection object.
|
|
//
|
|
Status = RWanTdiOpenConnection(
|
|
&TdiRequest,
|
|
*((CONNECTION_CONTEXT UNALIGNED *)
|
|
&(pTargetEa->EaName[pTargetEa->EaNameLength + 1]))
|
|
);
|
|
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
#if DBG
|
|
pEndpoint->pConnObject = RWanTdiDbgGetConnObject(
|
|
TdiRequest.Handle.ConnectionContext
|
|
);
|
|
#endif
|
|
pEndpoint->Handle.ConnectionContext = TdiRequest.Handle.ConnectionContext;
|
|
pIrpSp->FileObject->FsContext = pEndpoint;
|
|
pIrpSp->FileObject->FsContext2 = (PVOID)TDI_CONNECTION_FILE;
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
Status = STATUS_INVALID_DEVICE_REQUEST;
|
|
break;
|
|
}
|
|
while (FALSE);
|
|
|
|
|
|
if (Status != STATUS_SUCCESS)
|
|
{
|
|
//
|
|
// Clean up.
|
|
//
|
|
if (pEndpoint != NULL)
|
|
{
|
|
RWAN_FREE_MEM(pEndpoint);
|
|
pEndpoint = NULL;
|
|
}
|
|
}
|
|
|
|
RWANDEBUGP(DL_VERY_LOUD, DC_DISPATCH,
|
|
("RWanCreate: pIrp x%x, pEndpoint x%x, Status x%x\n",
|
|
pIrp, pEndpoint, Status));
|
|
|
|
return (Status);
|
|
}
|
|
|
|
|
|
|
|
|
|
NTSTATUS
|
|
RWanCleanup(
|
|
IN PDEVICE_OBJECT pDeviceObject,
|
|
IN PIRP pIrp,
|
|
IN PIO_STACK_LOCATION pIrpSp
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Called to process an MJ_CLEANUP IRP. All outstanding IRPs are cancelled
|
|
by calling the appropriate close routine for the object.
|
|
|
|
We block until all outstanding IRPs are completed.
|
|
|
|
Arguments:
|
|
|
|
pDeviceObject - Not used
|
|
pIrp - Pointer to IRP
|
|
pIrpSp - IRP Stack location
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - this is the final clean-up status.
|
|
|
|
--*/
|
|
{
|
|
RWAN_IRQL OldIrql;
|
|
PIRP pCancelIrp;
|
|
PRWAN_ENDPOINT pEndpoint;
|
|
TDI_REQUEST TdiRequest;
|
|
NTSTATUS Status;
|
|
|
|
UNREFERENCED_PARAMETER(pDeviceObject);
|
|
|
|
pEndpoint = (PRWAN_ENDPOINT) pIrpSp->FileObject->FsContext;
|
|
|
|
RWAN_STRUCT_ASSERT(pEndpoint, nep);
|
|
|
|
|
|
IoAcquireCancelSpinLock(&OldIrql);
|
|
|
|
pEndpoint->bCancelIrps = TRUE;
|
|
KeResetEvent(&(pEndpoint->CleanupEvent));
|
|
|
|
RWAN_EP_DBGLOG_ENTRY(pEndpoint, 'ealC', pIrp, pEndpoint->RefCount);
|
|
|
|
IoReleaseCancelSpinLock(OldIrql);
|
|
|
|
|
|
//
|
|
// Prepare a Close request for the TDI layer.
|
|
//
|
|
TdiRequest.RequestNotifyObject = RWanCloseObjectComplete;
|
|
TdiRequest.RequestContext = pIrp;
|
|
|
|
switch ((INT)PtrToUint(pIrpSp->FileObject->FsContext2))
|
|
{
|
|
case TDI_TRANSPORT_ADDRESS_FILE:
|
|
|
|
TdiRequest.Handle.AddressHandle = pEndpoint->Handle.AddressHandle;
|
|
Status = RWanTdiCloseAddress(&TdiRequest);
|
|
break;
|
|
|
|
case TDI_CONNECTION_FILE:
|
|
|
|
TdiRequest.Handle.ConnectionContext = pEndpoint->Handle.ConnectionContext;
|
|
Status = RWanTdiCloseConnection(&TdiRequest);
|
|
break;
|
|
|
|
case TDI_CONTROL_CHANNEL_FILE:
|
|
|
|
Status = STATUS_SUCCESS;
|
|
break;
|
|
|
|
default:
|
|
|
|
RWAN_ASSERT(FALSE);
|
|
|
|
IoAcquireCancelSpinLock(&OldIrql);
|
|
pEndpoint->bCancelIrps = FALSE;
|
|
IoReleaseCancelSpinLock(OldIrql);
|
|
|
|
return (STATUS_INVALID_PARAMETER);
|
|
}
|
|
|
|
if (Status != TDI_PENDING)
|
|
{
|
|
RWanCloseObjectComplete(pIrp, Status, 0);
|
|
}
|
|
|
|
//
|
|
// Wait until all IRPs are completed.
|
|
//
|
|
Status = KeWaitForSingleObject(
|
|
&(pEndpoint->CleanupEvent),
|
|
UserRequest,
|
|
KernelMode,
|
|
FALSE,
|
|
NULL
|
|
);
|
|
|
|
RWAN_ASSERT(NT_SUCCESS(Status));
|
|
|
|
RWANDEBUGP(DL_VERY_LOUD, DC_DISPATCH,
|
|
("RWanCleanup: pIrp x%x, Context2 %d, pEndpoint x%x, returning Status x%x\n",
|
|
pIrp,
|
|
(INT)PtrToUint(pIrpSp->FileObject->FsContext2),
|
|
pEndpoint,
|
|
pIrp->IoStatus.Status));
|
|
|
|
return (pIrp->IoStatus.Status);
|
|
}
|
|
|
|
|
|
|
|
|
|
NTSTATUS
|
|
RWanClose(
|
|
IN PDEVICE_OBJECT pDeviceObject,
|
|
IN PIRP pIrp,
|
|
IN PIO_STACK_LOCATION pIrpSp
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Called to destroy an endpoint that was created via MJ_CREATE.
|
|
We'd have already processed and completed an MJ_CLEANUP,
|
|
meaning that there would be no pending IRPs on this endpoint.
|
|
All we need to do is deallocate the endpoint.
|
|
|
|
Arguments:
|
|
|
|
pDeviceObject - Identifies the protocol (not used)
|
|
pIrp - Pointer to IRP
|
|
pIrpSp - IRP Stack location
|
|
|
|
Return Value:
|
|
|
|
NT_STATUS - always STATUS_SUCCESS
|
|
|
|
--*/
|
|
{
|
|
PRWAN_ENDPOINT pEndpoint;
|
|
KIRQL OldIrql;
|
|
|
|
UNREFERENCED_PARAMETER(pDeviceObject);
|
|
|
|
pEndpoint = (PRWAN_ENDPOINT) pIrpSp->FileObject->FsContext;
|
|
RWAN_STRUCT_ASSERT(pEndpoint, nep);
|
|
|
|
RWANDEBUGP(DL_LOUD, DC_DISPATCH,
|
|
("RWanClose: pIrp x%x, pEndpoint x%x\n", pIrp, pEndpoint));
|
|
|
|
RWAN_FREE_MEM(pEndpoint);
|
|
|
|
return (STATUS_SUCCESS);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NTSTATUS
|
|
RWanDispatchInternalDeviceControl(
|
|
IN PDEVICE_OBJECT pDeviceObject,
|
|
IN PIRP pIrp
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Called to handle MJ_DEVICE_CONTROL IRPs sent to us. These IRPs
|
|
carry TDI primitives (e.g. CONNECT, DISCONNECT, SEND, RECEIVE).
|
|
We call the appropriate TDI routine to handle the specified
|
|
primitive.
|
|
|
|
Arguments:
|
|
|
|
pDeviceObject - Identifies the protocol (Not used here)
|
|
pIrp - Pointer to IRP
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - this is STATUS_PENDING if the IRP was successfully
|
|
queued for processing, STATUS_NOT_IMPLEMENTED for unsupported
|
|
TDI commands, and STATUS_INVALID_DEVICE_REQUEST for unknown
|
|
commands.
|
|
|
|
--*/
|
|
{
|
|
PRWAN_ENDPOINT pEndpoint;
|
|
KIRQL OldIrql;
|
|
PIO_STACK_LOCATION pIrpSp;
|
|
NTSTATUS Status;
|
|
BOOLEAN bDone;
|
|
#if DBG
|
|
RWAN_IRQL EntryIrq, ExitIrq;
|
|
#endif // DBG
|
|
|
|
RWAN_GET_ENTRY_IRQL(EntryIrq);
|
|
|
|
UNREFERENCED_PARAMETER(pDeviceObject);
|
|
|
|
pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
|
|
|
|
pEndpoint = (PRWAN_ENDPOINT) pIrpSp->FileObject->FsContext;
|
|
RWAN_STRUCT_ASSERT(pEndpoint, nep);
|
|
|
|
RWANDEBUGP(DL_VERY_LOUD, DC_DISPATCH,
|
|
("RWanDispatchInternalDevCtl: pIrp x%x, pIrpSp x%x, pEndpoint x%x, Ctx2 %d\n",
|
|
pIrp, pIrpSp, pEndpoint,
|
|
(INT)PtrToUint(pIrpSp->FileObject->FsContext2)));
|
|
|
|
do
|
|
{
|
|
if (((INT)PtrToUint(pIrpSp->FileObject->FsContext2)) == TDI_CONNECTION_FILE)
|
|
{
|
|
if (pIrpSp->MinorFunction == TDI_SEND)
|
|
{
|
|
RWAN_EP_DBGLOG_ENTRY(pEndpoint, 'dneS', 0, 0);
|
|
|
|
Status = RWanSendData(pIrp, pIrpSp);
|
|
break;
|
|
}
|
|
|
|
if (pIrpSp->MinorFunction == TDI_RECEIVE)
|
|
{
|
|
RWAN_EP_DBGLOG_ENTRY(pEndpoint, 'vceR', 0, 0);
|
|
|
|
Status = RWanReceiveData(pIrp, pIrpSp);
|
|
break;
|
|
}
|
|
|
|
bDone = TRUE;
|
|
|
|
switch (pIrpSp->MinorFunction)
|
|
{
|
|
case TDI_ASSOCIATE_ADDRESS:
|
|
|
|
RWAN_EP_DBGLOG_ENTRY(pEndpoint, 'AssA', pIrp, pEndpoint->RefCount);
|
|
|
|
Status = RWanAssociateAddress(pIrp, pIrpSp);
|
|
RWAN_COMPLETE_IRP(pIrp, Status, 0);
|
|
break;
|
|
|
|
case TDI_DISASSOCIATE_ADDRESS:
|
|
|
|
RWAN_EP_DBGLOG_ENTRY(pEndpoint, 'AsiD', pIrp, pEndpoint->RefCount);
|
|
|
|
Status = RWanDisassociateAddress(pIrp, pIrpSp);
|
|
break;
|
|
|
|
case TDI_CONNECT:
|
|
|
|
RWAN_EP_DBGLOG_ENTRY(pEndpoint, 'nnoC', pIrp, pEndpoint->RefCount);
|
|
|
|
Status = RWanConnect(pIrp, pIrpSp);
|
|
break;
|
|
|
|
case TDI_DISCONNECT:
|
|
|
|
RWAN_EP_DBGLOG_ENTRY(pEndpoint, 'csiD', pIrp, pEndpoint->RefCount);
|
|
|
|
Status = RWanDisconnect(pIrp, pIrpSp);
|
|
break;
|
|
|
|
case TDI_LISTEN:
|
|
|
|
RWAN_EP_DBGLOG_ENTRY(pEndpoint, 'tsiL', pIrp, pEndpoint->RefCount);
|
|
|
|
Status = RWanListen(pIrp, pIrpSp);
|
|
break;
|
|
|
|
case TDI_ACCEPT:
|
|
|
|
RWAN_EP_DBGLOG_ENTRY(pEndpoint, 'eccA', pIrp, pEndpoint->RefCount);
|
|
|
|
Status = RWanAccept(pIrp, pIrpSp);
|
|
break;
|
|
|
|
default:
|
|
bDone = FALSE;
|
|
|
|
#if 0
|
|
// Allow TDI_QUERY_INFORMATION on Conn endpoints to fall through
|
|
RWANDEBUGP(DL_WARN, DC_DISPATCH,
|
|
("RWanDispatchInternalDevCtl: pIrp x%x, pIrpSp x%x, unknown func x%x\n",
|
|
pIrp, pIrpSp, pIrpSp->MinorFunction));
|
|
|
|
Status = STATUS_INVALID_DEVICE_REQUEST;
|
|
|
|
RWAN_COMPLETE_IRP(pIrp, Status, 0);
|
|
#else
|
|
bDone = FALSE;
|
|
#endif
|
|
break;
|
|
}
|
|
|
|
if (bDone)
|
|
{
|
|
break;
|
|
}
|
|
//
|
|
// else fall through - may be something common to all types
|
|
// of endpoints.
|
|
//
|
|
|
|
}
|
|
else if (((INT)PtrToUint(pIrpSp->FileObject->FsContext2)) == TDI_TRANSPORT_ADDRESS_FILE)
|
|
{
|
|
if (pIrpSp->MinorFunction == TDI_SET_EVENT_HANDLER)
|
|
{
|
|
RWAN_EP_DBGLOG_ENTRY(pEndpoint, 'EteS', 0, 0);
|
|
|
|
Status = RWanSetEventHandler(pIrp, pIrpSp);
|
|
|
|
RWAN_COMPLETE_IRP(pIrp, Status, 0);
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
RWAN_ASSERT(
|
|
(((INT)PtrToUint(pIrpSp->FileObject->FsContext2)) == TDI_TRANSPORT_ADDRESS_FILE)
|
|
||
|
|
(((INT)PtrToUint(pIrpSp->FileObject->FsContext2)) == TDI_CONNECTION_FILE)
|
|
||
|
|
(((INT)PtrToUint(pIrpSp->FileObject->FsContext2)) == TDI_CONTROL_CHANNEL_FILE)
|
|
);
|
|
|
|
//
|
|
// Check if this is a function common to all types of endpoints.
|
|
//
|
|
switch (pIrpSp->MinorFunction)
|
|
{
|
|
case TDI_QUERY_INFORMATION:
|
|
|
|
RWAN_EP_DBGLOG_ENTRY(pEndpoint, 'IyrQ', 0, 0);
|
|
|
|
Status = RWanQueryInformation(pIrp, pIrpSp);
|
|
break;
|
|
|
|
case TDI_SET_INFORMATION:
|
|
case TDI_ACTION:
|
|
|
|
RWANDEBUGP(DL_INFO, DC_DISPATCH,
|
|
("RWanDispatchInternalDevCtl: SET_INFO/ACTION not supported\n"));
|
|
|
|
RWAN_EP_DBGLOG_ENTRY(pEndpoint, 'IteS', 0, 0);
|
|
|
|
Status = STATUS_NOT_IMPLEMENTED;
|
|
RWAN_COMPLETE_IRP(pIrp, Status, 0);
|
|
break;
|
|
|
|
default:
|
|
|
|
Status = STATUS_INVALID_DEVICE_REQUEST;
|
|
RWAN_COMPLETE_IRP(pIrp, Status, 0);
|
|
break;
|
|
}
|
|
|
|
break;
|
|
}
|
|
while (FALSE);
|
|
|
|
RWANDEBUGP(DL_VERY_LOUD, DC_DISPATCH,
|
|
("RWanDispatchInternalDevCtl: pIrp x%x, pIrpSp x%x, Maj/Min %d/%d, Status x%x\n",
|
|
pIrp, pIrpSp, pIrpSp->MajorFunction, pIrpSp->MinorFunction, Status));
|
|
|
|
RWAN_CHECK_EXIT_IRQL(EntryIrq, ExitIrq);
|
|
return (Status);
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
RWanDispatchPrivateDeviceControl(
|
|
IN PIRP pIrp,
|
|
IN PIO_STACK_LOCATION pIrpSp
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Called to handle MJ_DEVICE_CONTROL IRPs sent to us that contain
|
|
non-TDI primitives.
|
|
|
|
Arguments:
|
|
|
|
pIrp - Pointer to IRP
|
|
pIrpSp - IRP Stack location
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - this is STATUS_PENDING if the IRP was successfully
|
|
queued for processing, STATUS_NOT_IMPLEMENTED for unsupported
|
|
commands, and STATUS_INVALID_DEVICE_REQUEST for unknown
|
|
commands.
|
|
|
|
--*/
|
|
{
|
|
PRWAN_ENDPOINT pEndpoint;
|
|
KIRQL OldIrql;
|
|
RWAN_STATUS RWanStatus;
|
|
NTSTATUS Status;
|
|
PRWAN_NDIS_AF_CHARS pAfChars;
|
|
PVOID pInputBuffer;
|
|
PVOID pOutputBuffer;
|
|
ULONG InputBufferLength;
|
|
ULONG OutputBufferLength;
|
|
|
|
PAGED_CODE();
|
|
|
|
pEndpoint = (PRWAN_ENDPOINT) pIrpSp->FileObject->FsContext;
|
|
RWAN_STRUCT_ASSERT(pEndpoint, nep);
|
|
|
|
//
|
|
// Initialize.
|
|
//
|
|
pIrp->IoStatus.Information = 0;
|
|
Status = STATUS_INVALID_DEVICE_REQUEST;
|
|
|
|
//
|
|
// Get some parameters from the IRP.
|
|
//
|
|
pInputBuffer = pIrpSp->Parameters.DeviceIoControl.Type3InputBuffer;
|
|
pOutputBuffer = pIrp->UserBuffer;
|
|
|
|
InputBufferLength = pIrpSp->Parameters.DeviceIoControl.InputBufferLength;
|
|
OutputBufferLength = pIrpSp->Parameters.DeviceIoControl.OutputBufferLength;
|
|
|
|
RWANDEBUGP(DL_INFO, DC_DISPATCH,
|
|
("PrivateDevCtl: pEndpoint x%x, CtlCode x%x, InBuf x%x/%d, OutBuf x%x/%d\n",
|
|
pEndpoint,
|
|
pIrpSp->Parameters.DeviceIoControl.IoControlCode,
|
|
pInputBuffer,
|
|
InputBufferLength,
|
|
pOutputBuffer,
|
|
OutputBufferLength));
|
|
|
|
//
|
|
// Validate the pointers we've got.
|
|
//
|
|
if (InputBufferLength)
|
|
{
|
|
try
|
|
{
|
|
if (pIrp->RequestorMode != KernelMode)
|
|
{
|
|
ProbeForRead(
|
|
pInputBuffer,
|
|
InputBufferLength,
|
|
sizeof(ULONG)
|
|
);
|
|
}
|
|
}
|
|
except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
RWAN_COMPLETE_IRP(pIrp, STATUS_INVALID_DEVICE_REQUEST, 0);
|
|
return (STATUS_INVALID_DEVICE_REQUEST);
|
|
}
|
|
}
|
|
|
|
if (OutputBufferLength)
|
|
{
|
|
try
|
|
{
|
|
if (pIrp->RequestorMode != KernelMode)
|
|
{
|
|
ProbeForWrite(
|
|
pOutputBuffer,
|
|
OutputBufferLength,
|
|
sizeof(ULONG)
|
|
);
|
|
}
|
|
}
|
|
except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
RWAN_COMPLETE_IRP(pIrp, STATUS_INVALID_DEVICE_REQUEST, 0);
|
|
return (STATUS_INVALID_DEVICE_REQUEST);
|
|
}
|
|
}
|
|
|
|
switch (pIrpSp->Parameters.DeviceIoControl.IoControlCode)
|
|
{
|
|
case IOCTL_RWAN_GENERIC_GLOBAL_QUERY:
|
|
case IOCTL_RWAN_GENERIC_GLOBAL_SET:
|
|
Status = STATUS_NOT_IMPLEMENTED;
|
|
break;
|
|
|
|
case IOCTL_RWAN_GENERIC_CONN_HANDLE_QUERY:
|
|
|
|
if (((INT)PtrToUint(pIrpSp->FileObject->FsContext2)) != TDI_CONNECTION_FILE)
|
|
{
|
|
Status = STATUS_INVALID_DEVICE_REQUEST;
|
|
break;
|
|
}
|
|
|
|
RWanStatus = RWanHandleGenericConnQryInfo(
|
|
pEndpoint->Handle.ConnectionContext,
|
|
pInputBuffer,
|
|
InputBufferLength,
|
|
pOutputBuffer,
|
|
&OutputBufferLength
|
|
);
|
|
|
|
Status = RWanToNTStatus(RWanStatus);
|
|
if (Status != STATUS_SUCCESS)
|
|
{
|
|
OutputBufferLength = 0;
|
|
}
|
|
|
|
break;
|
|
|
|
case IOCTL_RWAN_GENERIC_ADDR_HANDLE_QUERY:
|
|
case IOCTL_RWAN_GENERIC_CONN_HANDLE_SET:
|
|
Status = STATUS_NOT_IMPLEMENTED;
|
|
break;
|
|
|
|
case IOCTL_RWAN_GENERIC_ADDR_HANDLE_SET:
|
|
|
|
if (((INT)PtrToUint(pIrpSp->FileObject->FsContext2)) != TDI_TRANSPORT_ADDRESS_FILE)
|
|
{
|
|
Status = STATUS_INVALID_DEVICE_REQUEST;
|
|
break;
|
|
}
|
|
|
|
RWanStatus = RWanHandleGenericAddrSetInfo(
|
|
pEndpoint->Handle.AddressHandle,
|
|
pInputBuffer,
|
|
InputBufferLength
|
|
);
|
|
|
|
Status = RWanToNTStatus(RWanStatus);
|
|
OutputBufferLength = 0;
|
|
|
|
break;
|
|
|
|
case IOCTL_RWAN_MEDIA_SPECIFIC_GLOBAL_QUERY:
|
|
//
|
|
// Get the media-specific module's QueryInfo handler.
|
|
//
|
|
pAfChars = &(pEndpoint->pProtocol->pAfInfo->AfChars);
|
|
|
|
if (pAfChars->pAfSpQueryGlobalInfo != NULL)
|
|
{
|
|
RWanStatus = (*pAfChars->pAfSpQueryGlobalInfo)(
|
|
pEndpoint->pProtocol->pAfInfo->AfSpContext,
|
|
pInputBuffer,
|
|
InputBufferLength,
|
|
pOutputBuffer,
|
|
&OutputBufferLength
|
|
);
|
|
|
|
Status = RWanToNTStatus(RWanStatus);
|
|
if (Status != STATUS_SUCCESS)
|
|
{
|
|
OutputBufferLength = 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Status = STATUS_NOT_IMPLEMENTED;
|
|
}
|
|
break;
|
|
|
|
case IOCTL_RWAN_MEDIA_SPECIFIC_GLOBAL_SET:
|
|
//
|
|
// Get the media-specific module's SetInfo handler.
|
|
//
|
|
pAfChars = &(pEndpoint->pProtocol->pAfInfo->AfChars);
|
|
|
|
if (pAfChars->pAfSpSetGlobalInfo != NULL)
|
|
{
|
|
RWanStatus = (*pAfChars->pAfSpSetGlobalInfo)(
|
|
pEndpoint->pProtocol->pAfInfo->AfSpContext,
|
|
pInputBuffer,
|
|
InputBufferLength
|
|
);
|
|
|
|
Status = RWanToNTStatus(RWanStatus);
|
|
}
|
|
else
|
|
{
|
|
Status = STATUS_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
OutputBufferLength = 0;
|
|
break;
|
|
|
|
case IOCTL_RWAN_MEDIA_SPECIFIC_CONN_HANDLE_QUERY:
|
|
|
|
if ((INT)PtrToUint(pIrpSp->FileObject->FsContext2) != TDI_CONNECTION_FILE)
|
|
{
|
|
Status = STATUS_INVALID_DEVICE_REQUEST;
|
|
break;
|
|
}
|
|
|
|
RWanStatus = RWanHandleMediaSpecificConnQryInfo(
|
|
pEndpoint->Handle.ConnectionContext,
|
|
pInputBuffer,
|
|
InputBufferLength,
|
|
pOutputBuffer,
|
|
&OutputBufferLength
|
|
);
|
|
|
|
Status = RWanToNTStatus(RWanStatus);
|
|
|
|
break;
|
|
|
|
case IOCTL_RWAN_MEDIA_SPECIFIC_ADDR_HANDLE_QUERY:
|
|
case IOCTL_RWAN_MEDIA_SPECIFIC_CONN_HANDLE_SET:
|
|
Status = STATUS_NOT_IMPLEMENTED;
|
|
break;
|
|
|
|
case IOCTL_RWAN_MEDIA_SPECIFIC_ADDR_HANDLE_SET:
|
|
|
|
if ((INT)PtrToUint(pIrpSp->FileObject->FsContext2) != TDI_TRANSPORT_ADDRESS_FILE)
|
|
{
|
|
Status = STATUS_INVALID_DEVICE_REQUEST;
|
|
break;
|
|
}
|
|
|
|
RWanStatus = RWanHandleMediaSpecificAddrSetInfo(
|
|
pEndpoint->Handle.AddressHandle,
|
|
pInputBuffer,
|
|
InputBufferLength
|
|
);
|
|
|
|
Status = RWanToNTStatus(RWanStatus);
|
|
OutputBufferLength = 0;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
OutputBufferLength = 0;
|
|
Status = STATUS_INVALID_DEVICE_REQUEST;
|
|
break;
|
|
}
|
|
|
|
RWAN_ASSERT(Status != STATUS_PENDING);
|
|
|
|
RWAN_COMPLETE_IRP(pIrp, Status, OutputBufferLength);
|
|
return (Status);
|
|
}
|
|
|
|
|
|
|
|
FILE_FULL_EA_INFORMATION UNALIGNED *
|
|
RWanFindEa(
|
|
IN FILE_FULL_EA_INFORMATION * pStartEa,
|
|
IN CHAR * pTargetName,
|
|
IN USHORT TargetNameLength
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Searches for a target name in an Extended Attribute list
|
|
and returns it.
|
|
|
|
Arguments:
|
|
|
|
pStartEa - Start of the attribute list
|
|
pTargetName - Pointer to name to look for
|
|
TargetNameLength- Length of name
|
|
|
|
Return Value:
|
|
|
|
Pointer to attribute matching the target name, if found;
|
|
NULL otherwise.
|
|
|
|
--*/
|
|
{
|
|
FILE_FULL_EA_INFORMATION UNALIGNED * pEa;
|
|
FILE_FULL_EA_INFORMATION UNALIGNED * pNextEa;
|
|
BOOLEAN Found;
|
|
USHORT i;
|
|
|
|
PAGED_CODE();
|
|
|
|
pNextEa = pStartEa;
|
|
Found = FALSE;
|
|
|
|
do
|
|
{
|
|
pEa = pNextEa;
|
|
pNextEa = (FILE_FULL_EA_INFORMATION UNALIGNED *)
|
|
((PUCHAR)pNextEa + pNextEa->NextEntryOffset);
|
|
|
|
if (pEa->EaNameLength == TargetNameLength)
|
|
{
|
|
for (i = 0; i < TargetNameLength; i++)
|
|
{
|
|
if (pEa->EaName[i] != pTargetName[i])
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (i == TargetNameLength)
|
|
{
|
|
Found = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
while (pEa->NextEntryOffset != 0);
|
|
|
|
return (Found? pEa: NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NTSTATUS
|
|
RWanSendData(
|
|
IN PIRP pIrp,
|
|
IN PIO_STACK_LOCATION pIrpSp
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Convert an IRP containing a TDI_SEND request to a call to our TDI
|
|
dispatch routine for sends. We retain enough context to be able
|
|
to complete the IRP when the send completes.
|
|
|
|
Arguments:
|
|
|
|
pIrp - Pointer to IRP
|
|
pIrpSp - IRP Stack location
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - STATUS_PENDING if we managed to queue the send successfully,
|
|
STATUS_CANCELLED if the IRP was cancelled.
|
|
STATUS_SUCCESS if the send completed successfully, immediately.
|
|
|
|
--*/
|
|
{
|
|
PRWAN_ENDPOINT pEndpoint;
|
|
KIRQL OldIrql;
|
|
PTDI_REQUEST_KERNEL_SEND pSendRequest;
|
|
TDI_REQUEST TdiRequest;
|
|
NTSTATUS Status;
|
|
|
|
|
|
pEndpoint = (PRWAN_ENDPOINT) pIrpSp->FileObject->FsContext;
|
|
RWAN_STRUCT_ASSERT(pEndpoint, nep);
|
|
|
|
pSendRequest = (PTDI_REQUEST_KERNEL_SEND) &(pIrpSp->Parameters);
|
|
|
|
//
|
|
// Prepare a TDI Send request.
|
|
//
|
|
TdiRequest.Handle.ConnectionContext = pEndpoint->Handle.ConnectionContext;
|
|
TdiRequest.RequestNotifyObject = (PVOID) RWanDataRequestComplete;
|
|
TdiRequest.RequestContext = (PVOID) pIrp;
|
|
|
|
IoAcquireCancelSpinLock(&OldIrql);
|
|
|
|
if (!pIrp->Cancel)
|
|
{
|
|
//
|
|
// The IRP hasn't been cancelled. Set it up so that we are
|
|
// informed if it does get cancelled later.
|
|
//
|
|
IoMarkIrpPending(pIrp);
|
|
IoSetCancelRoutine(pIrp, RWanCancelRequest);
|
|
|
|
RWAN_INCR_EP_REF_CNT(pEndpoint, SendIncr); // Send ref
|
|
|
|
RWAN_EP_DBGLOG_ENTRY(pEndpoint, 'DneS', pIrp, pEndpoint->RefCount);
|
|
|
|
IoReleaseCancelSpinLock(OldIrql);
|
|
|
|
Status = RWanTdiSendData(
|
|
&TdiRequest,
|
|
(USHORT)pSendRequest->SendFlags,
|
|
pSendRequest->SendLength,
|
|
(PNDIS_BUFFER) pIrp->MdlAddress
|
|
);
|
|
|
|
if (Status != TDI_PENDING)
|
|
{
|
|
//
|
|
// The Send either completed immediately, or failed.
|
|
//
|
|
pIrpSp->Control &= ~SL_PENDING_RETURNED;
|
|
|
|
if (Status == TDI_SUCCESS)
|
|
{
|
|
//
|
|
// Examples of immediate successful completion:
|
|
// - A zero length send
|
|
//
|
|
RWanDataRequestComplete(pIrp, Status, pSendRequest->SendLength);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// The Send failed, could be a resource problem.
|
|
//
|
|
|
|
RWANDEBUGP(DL_INFO, DC_DATA_TX,
|
|
("RWanSendData: pIrp x%x, pEndpoint x%x, TDI send fail: x%x\n",
|
|
pIrp, pEndpoint, Status));
|
|
|
|
RWanDataRequestComplete(pIrp, Status, 0);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// The IRP has been cancelled before it could reach us.
|
|
//
|
|
IoReleaseCancelSpinLock(OldIrql);
|
|
|
|
Status = STATUS_CANCELLED;
|
|
RWAN_COMPLETE_IRP(pIrp, Status, 0);
|
|
}
|
|
|
|
|
|
RWANDEBUGP(DL_LOUD, DC_DATA_TX,
|
|
("RWanSendData: pIrp x%x, pEndpoint x%x, ret Status x%x\n",
|
|
pIrp, pEndpoint, Status));
|
|
|
|
return (Status);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NTSTATUS
|
|
RWanReceiveData(
|
|
IN PIRP pIrp,
|
|
IN PIO_STACK_LOCATION pIrpSp
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Convert an IRP containing a TDI_RECEIVE request to a call to our TDI
|
|
dispatch routine for receives. We retain enough context to be able
|
|
to complete the IRP when the receive completes.
|
|
|
|
The FileObject within the IRP refers to the connection endpoint.
|
|
|
|
Arguments:
|
|
|
|
pIrp - Pointer to IRP
|
|
pIrpSp - IRP Stack location
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - STATUS_PENDING if we managed to queue the receive successfully,
|
|
STATUS_CANCELLED if the IRP was cancelled.
|
|
|
|
--*/
|
|
{
|
|
PRWAN_ENDPOINT pEndpoint;
|
|
KIRQL OldIrql;
|
|
PTDI_REQUEST_KERNEL_RECEIVE pReceiveRequest;
|
|
TDI_REQUEST TdiRequest;
|
|
NTSTATUS Status;
|
|
|
|
|
|
pEndpoint = (PRWAN_ENDPOINT) pIrpSp->FileObject->FsContext;
|
|
RWAN_STRUCT_ASSERT(pEndpoint, nep);
|
|
|
|
pReceiveRequest = (PTDI_REQUEST_KERNEL_RECEIVE) &(pIrpSp->Parameters);
|
|
|
|
//
|
|
// Prepare a TDI Receive request.
|
|
//
|
|
TdiRequest.Handle.ConnectionContext = pEndpoint->Handle.ConnectionContext;
|
|
TdiRequest.RequestNotifyObject = (PVOID) RWanDataRequestComplete;
|
|
TdiRequest.RequestContext = (PVOID) pIrp;
|
|
|
|
IoAcquireCancelSpinLock(&OldIrql);
|
|
|
|
if (!pIrp->Cancel)
|
|
{
|
|
//
|
|
// The IRP hasn't been cancelled. Set it up so that we are
|
|
// informed if it does get cancelled later.
|
|
//
|
|
IoMarkIrpPending(pIrp);
|
|
IoSetCancelRoutine(pIrp, RWanCancelRequest);
|
|
|
|
RWAN_INCR_EP_REF_CNT(pEndpoint, RecvIncr); // Receive ref
|
|
|
|
RWAN_EP_DBGLOG_ENTRY(pEndpoint, 'DvcR', pIrp, pEndpoint->RefCount);
|
|
|
|
IoReleaseCancelSpinLock(OldIrql);
|
|
|
|
Status = RWanTdiReceive(
|
|
&TdiRequest,
|
|
(USHORT *) &(pReceiveRequest->ReceiveFlags),
|
|
&(pReceiveRequest->ReceiveLength),
|
|
(PNDIS_BUFFER) pIrp->MdlAddress
|
|
);
|
|
|
|
if (Status != TDI_PENDING)
|
|
{
|
|
//
|
|
// The Receive either completed immediately, or failed.
|
|
//
|
|
pIrpSp->Control &= ~SL_PENDING_RETURNED;
|
|
|
|
RWANDEBUGP(DL_WARN, DC_DATA_TX,
|
|
("RWanReceiveData: pIrp x%x, pEndpoint x%x, TDI recv didnt pend: x%x\n",
|
|
pIrp, pEndpoint, Status));
|
|
|
|
RWanDataRequestComplete(pIrp, Status, 0);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// The IRP has been cancelled before it could reach us.
|
|
//
|
|
IoReleaseCancelSpinLock(OldIrql);
|
|
|
|
Status = STATUS_CANCELLED;
|
|
|
|
RWAN_COMPLETE_IRP(pIrp, Status, 0);
|
|
}
|
|
|
|
|
|
RWANDEBUGP(DL_LOUD, DC_DATA_TX,
|
|
("RWanReceiveData: pIrp x%x, pEndpoint x%x, ret Status x%x\n",
|
|
pIrp, pEndpoint, Status));
|
|
|
|
return (Status);
|
|
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
RWanAssociateAddress(
|
|
IN PIRP pIrp,
|
|
IN PIO_STACK_LOCATION pIrpSp
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Converts a TDI_ASSOCIATE_ADDRESS IRP to a call to our AssociateAddress
|
|
entry point.
|
|
|
|
The FileObject in the IRP refers to the Connection Object, and the
|
|
AddressHandle field within the kernel request refers to the Address
|
|
Object.
|
|
|
|
Arguments:
|
|
|
|
pIrp - Pointer to IRP
|
|
pIrpSp - IRP Stack location
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - STATUS_SUCCESS if successful, STATUS_XXX error code otherwise.
|
|
|
|
--*/
|
|
{
|
|
PRWAN_ENDPOINT pConnEndpoint;
|
|
PRWAN_ENDPOINT pAddrEndpoint;
|
|
PTDI_REQUEST_KERNEL_ASSOCIATE pAssociateRequest;
|
|
TDI_REQUEST TdiRequest;
|
|
PFILE_OBJECT pFileObject;
|
|
NTSTATUS Status;
|
|
|
|
PAGED_CODE();
|
|
|
|
pConnEndpoint = (PRWAN_ENDPOINT) pIrpSp->FileObject->FsContext;
|
|
RWAN_STRUCT_ASSERT(pConnEndpoint, nep);
|
|
|
|
//
|
|
// Prepare a TDI Associate Request
|
|
//
|
|
TdiRequest.Handle.ConnectionContext = pConnEndpoint->Handle.ConnectionContext;
|
|
pAssociateRequest = (PTDI_REQUEST_KERNEL_ASSOCIATE) &(pIrpSp->Parameters);
|
|
|
|
//
|
|
// Reference the file corresponding to the Address object.
|
|
// This is just so that it doesn't go away while we're processing
|
|
// the Associate.
|
|
//
|
|
// The Address object is identified by its handle buried inside
|
|
// the Associate request.
|
|
//
|
|
Status = ObReferenceObjectByHandle(
|
|
pAssociateRequest->AddressHandle,
|
|
GENERIC_ALL,
|
|
*IoFileObjectType,
|
|
pIrp->RequestorMode,
|
|
&pFileObject,
|
|
NULL
|
|
);
|
|
|
|
if (NT_SUCCESS(Status) &&
|
|
(pFileObject->DeviceObject->DriverObject == pRWanGlobal->pDriverObject))
|
|
{
|
|
|
|
//
|
|
// Found the file object. See if it is an Address object.
|
|
//
|
|
if ((INT)PtrToUint(pFileObject->FsContext2) == TDI_TRANSPORT_ADDRESS_FILE)
|
|
{
|
|
//
|
|
// Get our endpoint representing this address object.
|
|
//
|
|
pAddrEndpoint = (PRWAN_ENDPOINT) pFileObject->FsContext;
|
|
RWAN_STRUCT_ASSERT(pAddrEndpoint, nep);
|
|
|
|
//
|
|
// Dispatch this to the TDI layer.
|
|
//
|
|
Status = RWanTdiAssociateAddress(
|
|
&TdiRequest,
|
|
pAddrEndpoint->Handle.AddressHandle
|
|
);
|
|
|
|
RWAN_ASSERT(Status != TDI_PENDING);
|
|
|
|
ObDereferenceObject(pFileObject);
|
|
|
|
}
|
|
else
|
|
{
|
|
ObDereferenceObject(pFileObject);
|
|
|
|
RWANDEBUGP(DC_ADDRESS, DL_WARN,
|
|
("RWanAssociateAddress: pIrp x%x, pConnEp x%x, bad Context2 %d\n",
|
|
pIrp, pConnEndpoint,
|
|
(INT)PtrToUint(pFileObject->FsContext2)));
|
|
|
|
Status = STATUS_INVALID_HANDLE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
RWANDEBUGP(DL_WARN, DC_ADDRESS,
|
|
("RWanAssociateAddress: pIrp x%x, pConnEp x%x, bad addr handle x%x\n",
|
|
pIrp, pConnEndpoint, pAssociateRequest->AddressHandle));
|
|
//
|
|
// Clean up properly.
|
|
//
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
ObDereferenceObject(pFileObject);
|
|
Status = STATUS_INVALID_HANDLE;
|
|
}
|
|
}
|
|
|
|
RWANDEBUGP(DL_VERY_LOUD, DC_ADDRESS,
|
|
("RWanAssociateAddress: pIrp x%x, pConnEp x%x, Addr Handle x%x, Status x%x\n",
|
|
pIrp, pConnEndpoint, pAssociateRequest->AddressHandle, Status));
|
|
|
|
return (Status);
|
|
}
|
|
|
|
|
|
|
|
|
|
NTSTATUS
|
|
RWanDisassociateAddress(
|
|
IN PIRP pIrp,
|
|
IN PIO_STACK_LOCATION pIrpSp
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Converts a TDI_DISASSOCIATE_ADDRESS IRP to a call to our DisassociateAddress
|
|
entry point.
|
|
|
|
The FileObject in the IRP refers to the Connection Object that is
|
|
to be disassociated.
|
|
|
|
Arguments:
|
|
|
|
pIrp - Pointer to IRP
|
|
pIrpSp - IRP Stack location
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
PRWAN_ENDPOINT pConnEndpoint;
|
|
TDI_REQUEST TdiRequest;
|
|
NTSTATUS Status;
|
|
|
|
PAGED_CODE();
|
|
|
|
pConnEndpoint = (PRWAN_ENDPOINT) pIrpSp->FileObject->FsContext;
|
|
RWAN_STRUCT_ASSERT(pConnEndpoint, nep);
|
|
|
|
//
|
|
// Prepare a TDI Disassociate Request
|
|
//
|
|
TdiRequest.Handle.ConnectionContext = pConnEndpoint->Handle.ConnectionContext;
|
|
TdiRequest.RequestNotifyObject = (PVOID)RWanRequestComplete;
|
|
TdiRequest.RequestContext = (PVOID)pIrp;
|
|
|
|
Status = RWanPrepareIrpForCancel(pConnEndpoint, pIrp, RWanCancelRequest);
|
|
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
Status = RWanTdiDisassociateAddress(&TdiRequest);
|
|
|
|
if (Status != TDI_PENDING)
|
|
{
|
|
RWanRequestComplete(pIrp, Status, 0);
|
|
Status = TDI_PENDING;
|
|
}
|
|
}
|
|
|
|
RWANDEBUGP(DL_VERY_LOUD, DC_ADDRESS,
|
|
("RWanDisassociateAddr: pIrp x%x, pEndp x%x, Status x%x\n",
|
|
pIrp, pConnEndpoint, Status));
|
|
|
|
return (Status);
|
|
}
|
|
|
|
|
|
|
|
|
|
NTSTATUS
|
|
RWanConnect(
|
|
IN PIRP pIrp,
|
|
IN PIO_STACK_LOCATION pIrpSp
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Convert a TDI Connect IRP to a call to our Connect entry point.
|
|
|
|
The FileObject in the IRP refers to the Connection Object on which
|
|
the outgoing call is to be placed.
|
|
|
|
Arguments:
|
|
|
|
pIrp - Pointer to IRP
|
|
pIrpSp - IRP Stack location
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - STATUS_PENDING if a call was initiated, STATUS_XXX error
|
|
code otherwise.
|
|
|
|
--*/
|
|
{
|
|
PRWAN_ENDPOINT pConnEndpoint;
|
|
TDI_REQUEST TdiRequest;
|
|
PTDI_CONNECTION_INFORMATION pRequestInformation;
|
|
PTDI_CONNECTION_INFORMATION pReturnInformation;
|
|
PTDI_REQUEST_KERNEL_CONNECT pConnectRequest;
|
|
NTSTATUS Status;
|
|
PLARGE_INTEGER pRequestTimeout;
|
|
LARGE_INTEGER MillisecondTimeout;
|
|
ULONG Remainder;
|
|
|
|
|
|
pConnEndpoint = (PRWAN_ENDPOINT) pIrpSp->FileObject->FsContext;
|
|
RWAN_STRUCT_ASSERT(pConnEndpoint, nep);
|
|
|
|
//
|
|
// Grab all parameters from the IRP.
|
|
//
|
|
pConnectRequest = (PTDI_REQUEST_KERNEL_CONNECT) &(pIrpSp->Parameters);
|
|
pRequestInformation = pConnectRequest->RequestConnectionInformation;
|
|
pReturnInformation = pConnectRequest->ReturnConnectionInformation;
|
|
|
|
//
|
|
// Prepare a TDI CONNECT Request
|
|
//
|
|
TdiRequest.Handle.ConnectionContext = pConnEndpoint->Handle.ConnectionContext;
|
|
TdiRequest.RequestNotifyObject = (PVOID)RWanRequestComplete;
|
|
TdiRequest.RequestContext = (PVOID)pIrp;
|
|
|
|
pRequestTimeout = (PLARGE_INTEGER)pConnectRequest->RequestSpecific;
|
|
|
|
if (pRequestTimeout != NULL)
|
|
{
|
|
MillisecondTimeout = RWAN_CONVERT_100NS_TO_MS(*pRequestTimeout, &Remainder);
|
|
}
|
|
else
|
|
{
|
|
MillisecondTimeout.LowPart = 0;
|
|
MillisecondTimeout.HighPart = 0;
|
|
}
|
|
|
|
Status = RWanPrepareIrpForCancel(pConnEndpoint, pIrp, RWanCancelRequest);
|
|
|
|
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
Status = RWanTdiConnect(
|
|
&TdiRequest,
|
|
((MillisecondTimeout.LowPart != 0)?
|
|
&(MillisecondTimeout.LowPart): NULL),
|
|
pRequestInformation,
|
|
pReturnInformation
|
|
);
|
|
|
|
if (Status != TDI_PENDING)
|
|
{
|
|
RWanRequestComplete(pIrp, Status, 0);
|
|
Status = STATUS_PENDING;
|
|
}
|
|
}
|
|
|
|
RWANDEBUGP(DL_LOUD, DC_CONNECT,
|
|
("RWanConnect: pIrp x%x, pEndp x%x, Status x%x\n",
|
|
pIrp, pConnEndpoint, Status));
|
|
|
|
return (Status);
|
|
}
|
|
|
|
|
|
|
|
|
|
NTSTATUS
|
|
RWanDisconnect(
|
|
IN PIRP pIrp,
|
|
IN PIO_STACK_LOCATION pIrpSp
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Convert a TDI Connect IRP to a call to our Connect entry point.
|
|
|
|
The FileObject in the IRP refers to the Connection Object hosting
|
|
the connection to be disconnected.
|
|
|
|
Arguments:
|
|
|
|
pIrp - Pointer to IRP
|
|
pIrpSp - IRP Stack location
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - STATUS_PENDING if a disconnect was initiated, STATUS_XXX error
|
|
code otherwise.
|
|
|
|
--*/
|
|
{
|
|
PRWAN_ENDPOINT pConnEndpoint;
|
|
TDI_REQUEST TdiRequest;
|
|
PTDI_CONNECTION_INFORMATION pRequestInformation;
|
|
PTDI_CONNECTION_INFORMATION pReturnInformation;
|
|
PTDI_REQUEST_KERNEL_DISCONNECT pDisconnectRequest;
|
|
NTSTATUS Status;
|
|
PLARGE_INTEGER pRequestTimeout;
|
|
LARGE_INTEGER MillisecondTimeout;
|
|
BOOLEAN bAbortiveDisconnect;
|
|
|
|
|
|
pConnEndpoint = (PRWAN_ENDPOINT) pIrpSp->FileObject->FsContext;
|
|
RWAN_STRUCT_ASSERT(pConnEndpoint, nep);
|
|
|
|
//
|
|
// Grab all parameters from the IRP.
|
|
//
|
|
pDisconnectRequest = (PTDI_REQUEST_KERNEL_DISCONNECT) &(pIrpSp->Parameters);
|
|
pRequestInformation = pDisconnectRequest->RequestConnectionInformation;
|
|
pReturnInformation = pDisconnectRequest->ReturnConnectionInformation;
|
|
|
|
//
|
|
// Prepare a TDI DISCONNECT Request
|
|
//
|
|
TdiRequest.Handle.ConnectionContext = pConnEndpoint->Handle.ConnectionContext;
|
|
TdiRequest.RequestContext = (PVOID)pIrp;
|
|
|
|
pRequestTimeout = (PLARGE_INTEGER)pDisconnectRequest->RequestSpecific;
|
|
|
|
if (pRequestTimeout != NULL)
|
|
{
|
|
ULONG Remainder;
|
|
MillisecondTimeout = RWAN_CONVERT_100NS_TO_MS(*pRequestTimeout, &Remainder);
|
|
#if 0
|
|
if ((pRequestTimeout->LowPart == -1) &&
|
|
(pRequestTimeout->HighPart == -1))
|
|
{
|
|
MillisecondTimeout.LowPart = pRequestTimeout->LowPart;
|
|
MillisecondTimeout.HighPart = 0;
|
|
}
|
|
else
|
|
{
|
|
MillisecondTimeout.QuadPart = -((*pRequestTimeout).QuadPart);
|
|
MillisecondTimeout = RWAN_CONVERT_100NS_TO_MS(MillisecondTimeout);
|
|
}
|
|
|
|
RWAN_ASSERT(MillisecondTimeout.HighPart == 0);
|
|
#endif // 0
|
|
}
|
|
else
|
|
{
|
|
MillisecondTimeout.LowPart = 0;
|
|
MillisecondTimeout.HighPart = 0;
|
|
}
|
|
|
|
if (pDisconnectRequest->RequestFlags & TDI_DISCONNECT_ABORT)
|
|
{
|
|
//
|
|
// Use non-generic completion routine for abortive disconnects,
|
|
// because they cannot be cancelled.
|
|
//
|
|
bAbortiveDisconnect = TRUE;
|
|
IoMarkIrpPending(pIrp);
|
|
TdiRequest.RequestNotifyObject = (PVOID)RWanNonCancellableRequestComplete;
|
|
|
|
Status = STATUS_SUCCESS;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Non-abortive disconnect.
|
|
//
|
|
bAbortiveDisconnect = FALSE;
|
|
Status = RWanPrepareIrpForCancel(pConnEndpoint, pIrp, RWanCancelRequest);
|
|
TdiRequest.RequestNotifyObject = (PVOID)RWanRequestComplete;
|
|
}
|
|
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
Status = RWanTdiDisconnect(
|
|
&TdiRequest,
|
|
((MillisecondTimeout.LowPart != 0)?
|
|
&(MillisecondTimeout.LowPart): NULL),
|
|
(USHORT)pDisconnectRequest->RequestFlags,
|
|
pRequestInformation,
|
|
pReturnInformation
|
|
);
|
|
|
|
if (Status != TDI_PENDING)
|
|
{
|
|
if (bAbortiveDisconnect)
|
|
{
|
|
RWanNonCancellableRequestComplete(pIrp, Status, 0);
|
|
}
|
|
else
|
|
{
|
|
RWanRequestComplete(pIrp, Status, 0);
|
|
}
|
|
Status = STATUS_PENDING;
|
|
}
|
|
}
|
|
|
|
RWANDEBUGP(DL_LOUD, DC_DISCON,
|
|
("RWanDisconnect: pIrp x%x, pEndp x%x, Abortive %d, Status x%x\n",
|
|
pIrp, pConnEndpoint, (INT)bAbortiveDisconnect, Status));
|
|
|
|
return (Status);
|
|
}
|
|
|
|
|
|
|
|
|
|
NTSTATUS
|
|
RWanListen(
|
|
IN PIRP pIrp,
|
|
IN PIO_STACK_LOCATION pIrpSp
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Convert a TDI Listen IRP to a call to our Listen entry point.
|
|
|
|
The FileObject in the IRP refers to the Connection Object on which
|
|
this Listen is posted.
|
|
|
|
Arguments:
|
|
|
|
pIrp - Pointer to IRP
|
|
pIrpSp - IRP Stack location
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - STATUS_PENDING if a Listen was initiated, STATUS_XXX error
|
|
code otherwise.
|
|
|
|
--*/
|
|
{
|
|
PRWAN_ENDPOINT pConnEndpoint;
|
|
TDI_REQUEST TdiRequest;
|
|
PTDI_CONNECTION_INFORMATION pRequestInformation;
|
|
PTDI_CONNECTION_INFORMATION pReturnInformation;
|
|
PTDI_REQUEST_KERNEL_LISTEN pListenRequest;
|
|
NTSTATUS Status;
|
|
|
|
pConnEndpoint = (PRWAN_ENDPOINT) pIrpSp->FileObject->FsContext;
|
|
RWAN_STRUCT_ASSERT(pConnEndpoint, nep);
|
|
|
|
//
|
|
// Grab all parameters from the IRP.
|
|
//
|
|
pListenRequest = (PTDI_REQUEST_KERNEL_LISTEN) &(pIrpSp->Parameters);
|
|
pRequestInformation = pListenRequest->RequestConnectionInformation;
|
|
pReturnInformation = pListenRequest->ReturnConnectionInformation;
|
|
|
|
//
|
|
// Prepare a TDI LISTEN Request
|
|
//
|
|
TdiRequest.Handle.ConnectionContext = pConnEndpoint->Handle.ConnectionContext;
|
|
TdiRequest.RequestNotifyObject = (PVOID)RWanRequestComplete;
|
|
TdiRequest.RequestContext = (PVOID)pIrp;
|
|
|
|
Status = RWanPrepareIrpForCancel(pConnEndpoint, pIrp, RWanCancelRequest);
|
|
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
Status = RWanTdiListen(
|
|
&TdiRequest,
|
|
(USHORT)pListenRequest->RequestFlags,
|
|
pRequestInformation,
|
|
pReturnInformation
|
|
);
|
|
|
|
if (Status != TDI_PENDING)
|
|
{
|
|
RWanRequestComplete(pIrp, Status, 0);
|
|
Status = STATUS_PENDING;
|
|
}
|
|
}
|
|
|
|
RWANDEBUGP(DL_LOUD, DC_CONNECT,
|
|
("RWanListen: pIrp x%x, pEndp x%x, Status x%x\n",
|
|
pIrp, pConnEndpoint, Status));
|
|
|
|
return (Status);
|
|
}
|
|
|
|
|
|
|
|
|
|
NTSTATUS
|
|
RWanAccept(
|
|
IN PIRP pIrp,
|
|
IN PIO_STACK_LOCATION pIrpSp
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Convert a TDI Accept IRP to a call to our Accept entry point.
|
|
|
|
Arguments:
|
|
|
|
pIrp - Pointer to IRP
|
|
pIrpSp - IRP Stack location
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - STATUS_PENDING if an Accept was initiated, STATUS_XXX error
|
|
code otherwise.
|
|
|
|
--*/
|
|
{
|
|
PRWAN_ENDPOINT pConnEndpoint;
|
|
TDI_REQUEST TdiRequest;
|
|
PTDI_CONNECTION_INFORMATION pRequestInformation;
|
|
PTDI_CONNECTION_INFORMATION pReturnInformation;
|
|
PTDI_REQUEST_KERNEL_ACCEPT pAcceptRequest;
|
|
NTSTATUS Status;
|
|
|
|
pConnEndpoint = (PRWAN_ENDPOINT) pIrpSp->FileObject->FsContext;
|
|
RWAN_STRUCT_ASSERT(pConnEndpoint, nep);
|
|
|
|
//
|
|
// Grab all parameters from the IRP.
|
|
//
|
|
pAcceptRequest = (PTDI_REQUEST_KERNEL_ACCEPT) &(pIrpSp->Parameters);
|
|
pRequestInformation = pAcceptRequest->RequestConnectionInformation;
|
|
pReturnInformation = pAcceptRequest->ReturnConnectionInformation;
|
|
|
|
//
|
|
// Prepare a TDI ACCEPT Request
|
|
//
|
|
TdiRequest.Handle.ConnectionContext = pConnEndpoint->Handle.ConnectionContext;
|
|
TdiRequest.RequestNotifyObject = (PVOID)RWanRequestComplete;
|
|
TdiRequest.RequestContext = (PVOID)pIrp;
|
|
|
|
Status = RWanPrepareIrpForCancel(pConnEndpoint, pIrp, RWanCancelRequest);
|
|
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
Status = RWanTdiAccept(
|
|
&TdiRequest,
|
|
pRequestInformation,
|
|
pReturnInformation
|
|
);
|
|
|
|
if (Status != TDI_PENDING)
|
|
{
|
|
RWanRequestComplete(pIrp, Status, 0);
|
|
Status = STATUS_PENDING;
|
|
}
|
|
}
|
|
|
|
RWANDEBUGP(DL_LOUD, DC_CONNECT,
|
|
("RWanAccept: pIrp x%x, pEndp x%x, Status x%x\n",
|
|
pIrp, pConnEndpoint, Status));
|
|
|
|
return (Status);
|
|
}
|
|
|
|
|
|
|
|
|
|
NTSTATUS
|
|
RWanSetEventHandler(
|
|
IN PIRP pIrp,
|
|
IN PIO_STACK_LOCATION pIrpSp
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Convert a TDI Set Event Handler IRP to a call to our set event handler
|
|
entry point.
|
|
|
|
Arguments:
|
|
|
|
pIrp - Pointer to IRP
|
|
pIrpSp - IRP Stack location
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - STATUS_SUCCESS if the request was successful, STATUS_XXX error
|
|
code otherwise.
|
|
|
|
--*/
|
|
{
|
|
PRWAN_ENDPOINT pEndpoint;
|
|
PTDI_REQUEST_KERNEL_SET_EVENT pSetEvent;
|
|
NTSTATUS Status;
|
|
|
|
PAGED_CODE();
|
|
|
|
pEndpoint = (PRWAN_ENDPOINT) pIrpSp->FileObject->FsContext;
|
|
RWAN_STRUCT_ASSERT(pEndpoint, nep);
|
|
|
|
pSetEvent = (PTDI_REQUEST_KERNEL_SET_EVENT) &(pIrpSp->Parameters);
|
|
|
|
Status = RWanTdiSetEvent(
|
|
pEndpoint->Handle.AddressHandle,
|
|
pSetEvent->EventType,
|
|
pSetEvent->EventHandler,
|
|
pSetEvent->EventContext
|
|
);
|
|
|
|
RWAN_ASSERT(Status != STATUS_PENDING);
|
|
|
|
RWANDEBUGP(DL_LOUD, DC_DISPATCH,
|
|
("RWanSetEventHandler: pIrp x%x, pEndp x%x, Type x%x, Status x%x\n",
|
|
pIrp, pEndpoint, pSetEvent->EventType, Status));
|
|
|
|
return (Status);
|
|
}
|
|
|
|
|
|
|
|
|
|
NTSTATUS
|
|
RWanQueryInformation(
|
|
IN PIRP pIrp,
|
|
IN PIO_STACK_LOCATION pIrpSp
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Converts a TDI Query Information IRP to a call to the QueryInformation
|
|
TDI entry point.
|
|
|
|
Arguments:
|
|
|
|
pIrp - Pointer to IRP
|
|
pIrpSp - IRP Stack location
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - this is STATUS_SUCCESS if the query was completed successfully,
|
|
STATUS_PENDING if it will be completed later, STATUS_XXX error code otherwise.
|
|
|
|
--*/
|
|
{
|
|
TDI_REQUEST TdiRequest;
|
|
NTSTATUS Status;
|
|
PRWAN_ENDPOINT pEndpoint;
|
|
PTDI_REQUEST_KERNEL_QUERY_INFORMATION pQueryInfo;
|
|
UINT IsConnection;
|
|
UINT DataSize;
|
|
|
|
IsConnection = FALSE;
|
|
DataSize = 0;
|
|
|
|
pEndpoint = (PRWAN_ENDPOINT) pIrpSp->FileObject->FsContext;
|
|
RWAN_STRUCT_ASSERT(pEndpoint, nep);
|
|
|
|
pQueryInfo = (PTDI_REQUEST_KERNEL_QUERY_INFORMATION) &(pIrpSp->Parameters);
|
|
|
|
TdiRequest.RequestNotifyObject = RWanDataRequestComplete;
|
|
TdiRequest.RequestContext = pIrp;
|
|
|
|
Status = STATUS_SUCCESS;
|
|
|
|
switch (pQueryInfo->QueryType)
|
|
{
|
|
case TDI_QUERY_BROADCAST_ADDRESS:
|
|
|
|
Status = STATUS_NOT_IMPLEMENTED;
|
|
break;
|
|
|
|
case TDI_QUERY_PROVIDER_INFO:
|
|
|
|
TdiRequest.Handle.ControlChannel = pEndpoint->Handle.ControlChannel;
|
|
break;
|
|
|
|
case TDI_QUERY_ADDRESS_INFO:
|
|
|
|
if (((INT)PtrToUint(pIrpSp->FileObject->FsContext2)) == TDI_CONNECTION_FILE)
|
|
{
|
|
IsConnection = TRUE;
|
|
TdiRequest.Handle.ConnectionContext = pEndpoint->Handle.ConnectionContext;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Must be an address object.
|
|
//
|
|
RWAN_ASSERT(((INT) PtrToUint(pIrpSp->FileObject->FsContext2))
|
|
== TDI_TRANSPORT_ADDRESS_FILE);
|
|
|
|
TdiRequest.Handle.AddressHandle = pEndpoint->Handle.AddressHandle;
|
|
}
|
|
break;
|
|
|
|
case TDI_QUERY_CONNECTION_INFO:
|
|
|
|
//
|
|
// Must be a connection object.
|
|
//
|
|
RWAN_ASSERT(((INT) PtrToUint(pIrpSp->FileObject->FsContext2)) == TDI_CONNECTION_FILE);
|
|
|
|
IsConnection = TRUE;
|
|
TdiRequest.Handle.ConnectionContext = pEndpoint->Handle.ConnectionContext;
|
|
break;
|
|
|
|
case TDI_QUERY_PROVIDER_STATISTICS:
|
|
|
|
//
|
|
// Must be a control channel.
|
|
//
|
|
RWAN_ASSERT(((INT) PtrToUint(pIrpSp->FileObject->FsContext2))
|
|
== TDI_CONTROL_CHANNEL_FILE);
|
|
TdiRequest.Handle.ControlChannel = pEndpoint->Handle.ControlChannel;
|
|
break;
|
|
|
|
default:
|
|
|
|
Status = STATUS_NOT_IMPLEMENTED;
|
|
break;
|
|
}
|
|
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
Status = RWanPrepareIrpForCancel(pEndpoint, pIrp, NULL);
|
|
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
DataSize = RWanGetMdlChainLength(pIrp->MdlAddress);
|
|
|
|
Status = RWanTdiQueryInformation(
|
|
&TdiRequest,
|
|
pQueryInfo->QueryType,
|
|
pIrp->MdlAddress,
|
|
&DataSize,
|
|
IsConnection
|
|
);
|
|
|
|
RWANDEBUGP(DL_LOUD, DC_DISPATCH,
|
|
("RWanQueryInformation: pIrp x%x, pEndp x%x, Type x%x, Status x%x\n",
|
|
pIrp, pEndpoint, pQueryInfo->QueryType, Status));
|
|
|
|
if (Status != TDI_PENDING)
|
|
{
|
|
RWanDataRequestComplete(pIrp, Status, DataSize);
|
|
}
|
|
|
|
return (STATUS_PENDING);
|
|
}
|
|
else
|
|
{
|
|
return (Status);
|
|
}
|
|
}
|
|
|
|
RWAN_COMPLETE_IRP(pIrp, Status, 0);
|
|
|
|
return (Status);
|
|
}
|
|
|
|
|
|
|
|
|
|
VOID
|
|
RWanCloseObjectComplete(
|
|
IN PVOID Context,
|
|
IN UINT Status,
|
|
IN UINT Unused
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is the call-back routine that processes a CloseConnection
|
|
or CloseAddress completion. This is called by the core TDI
|
|
provider. We dereference the endpoint; if it goes to 0, we
|
|
wake up the thread that's running the CLEANUP.
|
|
|
|
Arguments:
|
|
|
|
Context - A pointer to the IRP for this request.
|
|
Status - Final TDI status for the CloseConnection/CloseAddress
|
|
Unused - Not used for this completion
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
KIRQL OldIrql;
|
|
PIRP pIrp;
|
|
PIO_STACK_LOCATION pIrpSp;
|
|
PRWAN_ENDPOINT pEndpoint;
|
|
|
|
UNREFERENCED_PARAMETER(Unused);
|
|
|
|
pIrp = (PIRP)Context;
|
|
pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
|
|
pIrp->IoStatus.Status = Status;
|
|
pEndpoint = (PRWAN_ENDPOINT) pIrpSp->FileObject->FsContext;
|
|
RWAN_STRUCT_ASSERT(pEndpoint, nep);
|
|
|
|
IoAcquireCancelSpinLock(&OldIrql);
|
|
|
|
IoSetCancelRoutine(pIrp, NULL);
|
|
|
|
RWAN_DECR_EP_REF_CNT(pEndpoint, CloseComplDecr); // CloseComplete deref
|
|
|
|
RWAN_EP_DBGLOG_ENTRY(pEndpoint, 'pmCC', pIrp, pEndpoint->RefCount);
|
|
|
|
if (pEndpoint->RefCount == 0)
|
|
{
|
|
//
|
|
// The endpoint must be cleaning up.
|
|
//
|
|
|
|
RWANDEBUGP(DL_LOUD, DC_DISPATCH,
|
|
("RWanCloseObjectComplete: pIrp x%x, pEndpoint x%x ref count 0\n",
|
|
pIrp, pEndpoint));
|
|
|
|
KeSetEvent(&(pEndpoint->CleanupEvent), 0, FALSE);
|
|
}
|
|
|
|
IoReleaseCancelSpinLock(OldIrql);
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
|
|
VOID
|
|
RWanDataRequestComplete(
|
|
IN PVOID Context,
|
|
IN UINT Status,
|
|
IN UINT ByteCount
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is the call-back routine that processes a Send/Receive completion.
|
|
This is called by the core TDI provider. We complete the send/receive
|
|
IRP appropriately, and dereference our endpoint.
|
|
|
|
Arguments:
|
|
|
|
Context - A pointer to the IRP for this request.
|
|
Status - Final TDI status for send/receive
|
|
ByteCount - Actual bytes sent/received.
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
KIRQL OldIrql;
|
|
PIRP pIrp;
|
|
PIO_STACK_LOCATION pIrpSp;
|
|
PRWAN_ENDPOINT pEndpoint;
|
|
|
|
pIrp = (PIRP)Context;
|
|
pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
|
|
pEndpoint = (PRWAN_ENDPOINT) pIrpSp->FileObject->FsContext;
|
|
RWAN_STRUCT_ASSERT(pEndpoint, nep);
|
|
|
|
IoAcquireCancelSpinLock(&OldIrql);
|
|
|
|
IoSetCancelRoutine(pIrp, NULL);
|
|
|
|
RWAN_DECR_EP_REF_CNT(pEndpoint, DataReqComplDecr); // Send/Receive deref
|
|
|
|
RWAN_EP_DBGLOG_ENTRY(pEndpoint, 'CerD', pIrp, pEndpoint->RefCount);
|
|
|
|
RWANDEBUGP(DL_EXTRA_LOUD, DC_DATA_TX|DC_DATA_RX|DC_CONNECT|DC_DISCON,
|
|
("RWanDataReq compl: pIrp x%x, pEndpoint x%x, RefCnt %d, Sts x%x, ByteCnt %d\n",
|
|
pIrp, pEndpoint, pEndpoint->RefCount, Status, ByteCount));
|
|
|
|
if (pEndpoint->RefCount == 0)
|
|
{
|
|
//
|
|
// The endpoint must be cleaning up.
|
|
//
|
|
|
|
RWANDEBUGP(DL_LOUD, DC_DISPATCH,
|
|
("RWanDataRequestComplete: pIrp x%x, pEndpoint x%x ref count 0\n",
|
|
pIrp, pEndpoint));
|
|
|
|
KeSetEvent(&(pEndpoint->CleanupEvent), 0, FALSE);
|
|
}
|
|
|
|
//
|
|
// If the IRP was cancelled or we are cleaning up,
|
|
// update the completion status.
|
|
//
|
|
if (pIrp->Cancel || pEndpoint->bCancelIrps)
|
|
{
|
|
Status = (UINT)STATUS_CANCELLED;
|
|
ByteCount = 0;
|
|
}
|
|
|
|
IoReleaseCancelSpinLock(OldIrql);
|
|
|
|
RWAN_COMPLETE_IRP(pIrp, Status, ByteCount);
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
|
|
VOID
|
|
RWanRequestComplete(
|
|
IN PVOID Context,
|
|
IN UINT Status,
|
|
IN UINT Unused
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is our call-back routine for completing requests that don't
|
|
include data. IRP processing is the same as that for data, except
|
|
that the ByteCount is 0.
|
|
|
|
Arguments:
|
|
|
|
Context - A pointer to the IRP for this request.
|
|
Status - Final TDI status for the request.
|
|
Unused - Not used.
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
UNREFERENCED_PARAMETER(Unused);
|
|
|
|
RWanDataRequestComplete(Context, Status, 0);
|
|
}
|
|
|
|
|
|
|
|
|
|
VOID
|
|
RWanNonCancellableRequestComplete(
|
|
IN PVOID Context,
|
|
IN UINT Status,
|
|
IN UINT Unused
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is our call-back routine for completing requests based
|
|
on non-cancellable IRPs (e.g. Abortive Disconnect).
|
|
|
|
Arguments:
|
|
|
|
Context - A pointer to the IRP for this request.
|
|
Status - Final TDI status for the request.
|
|
Unused - Not used.
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
PIRP pIrp;
|
|
PIO_STACK_LOCATION pIrpSp;
|
|
|
|
UNREFERENCED_PARAMETER(Unused);
|
|
|
|
pIrp = (PIRP)Context;
|
|
pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
|
|
|
|
//
|
|
// Complete the IRP
|
|
//
|
|
RWAN_COMPLETE_IRP(pIrp, Status, 0);
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
|
|
VOID
|
|
RWanCancelComplete(
|
|
IN PVOID Context,
|
|
IN UINT Unused1,
|
|
IN UINT Unused2
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is called to process internal completion of an IRP cancellation.
|
|
All we need to do here is to dereference the endpoint on which this
|
|
happened.
|
|
|
|
Arguments:
|
|
|
|
Context - A pointer to the file object representing the
|
|
endpoint on which the IRP was cancelled.
|
|
Unused[1-2] - Not used
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
PFILE_OBJECT pFileObject;
|
|
PRWAN_ENDPOINT pEndpoint;
|
|
KIRQL OldIrql;
|
|
|
|
UNREFERENCED_PARAMETER(Unused1);
|
|
UNREFERENCED_PARAMETER(Unused2);
|
|
|
|
pFileObject = (PFILE_OBJECT)Context;
|
|
pEndpoint = (PRWAN_ENDPOINT)(pFileObject->FsContext);
|
|
|
|
RWAN_STRUCT_ASSERT(pEndpoint, nep);
|
|
|
|
|
|
IoAcquireCancelSpinLock(&OldIrql);
|
|
|
|
RWAN_DECR_EP_REF_CNT(pEndpoint, CancelComplDecr); // CancelComplete deref
|
|
|
|
RWAN_EP_DBGLOG_ENTRY(pEndpoint, 'CnaC', 0, pEndpoint->RefCount);
|
|
|
|
RWANDEBUGP(DL_EXTRA_LOUD, DC_DISPATCH,
|
|
("RWanCancelComplete: pEndpoint x%x, RefCount %d\n",
|
|
pEndpoint, pEndpoint->RefCount));
|
|
|
|
if (pEndpoint->RefCount == 0)
|
|
{
|
|
//
|
|
// Wake up the thread waiting for IRPs to complete
|
|
//
|
|
KeSetEvent(&(pEndpoint->CleanupEvent), 0, FALSE);
|
|
}
|
|
|
|
IoReleaseCancelSpinLock(OldIrql);
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
RWanCancelRequest(
|
|
IN PDEVICE_OBJECT pDeviceObject,
|
|
IN PIRP pIrp
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is the cancel routine we attach to IRPs that we queue. This
|
|
is supposed to cancel the IRP.
|
|
|
|
Arguments:
|
|
|
|
pDeviceObject - Pointer to the device object for this IRP
|
|
pIrp - Pointer to request packet
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
PFILE_OBJECT pFileObject;
|
|
PIO_STACK_LOCATION pIrpSp;
|
|
PRWAN_ENDPOINT pEndpoint;
|
|
NTSTATUS Status;
|
|
TDI_REQUEST TdiRequest;
|
|
UCHAR MinorFunction;
|
|
|
|
pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
|
|
pFileObject = pIrpSp->FileObject;
|
|
MinorFunction = pIrpSp->MinorFunction;
|
|
|
|
pEndpoint = (PRWAN_ENDPOINT) pFileObject->FsContext;
|
|
RWAN_STRUCT_ASSERT(pEndpoint, nep);
|
|
|
|
//
|
|
// This routine is entered with Cancel SpinLock acquired.
|
|
//
|
|
RWAN_ASSERT(pIrp->Cancel);
|
|
IoSetCancelRoutine(pIrp, NULL);
|
|
|
|
//
|
|
// Make sure that the endpoint doesn't go away when
|
|
// we release the Cancel Spinlock.
|
|
//
|
|
RWAN_INCR_EP_REF_CNT(pEndpoint, CancelIncr); // Cancel ref
|
|
|
|
RWAN_EP_DBGLOG_ENTRY(pEndpoint, 'RnaC', pIrp, pEndpoint->RefCount);
|
|
|
|
IoReleaseCancelSpinLock(pIrp->CancelIrql);
|
|
|
|
RWANDEBUGP(DL_LOUD, DC_DISPATCH,
|
|
("RWanCancelRequest: pIrp x%x, MinorFunc %d, pEndpoint x%x\n",
|
|
pIrp, MinorFunction, pEndpoint));
|
|
|
|
Status = STATUS_SUCCESS;
|
|
|
|
switch (MinorFunction)
|
|
{
|
|
case TDI_SEND:
|
|
case TDI_RECEIVE:
|
|
|
|
RWanAbortConnection(
|
|
pEndpoint->Handle.ConnectionContext
|
|
);
|
|
break;
|
|
|
|
case TDI_DISASSOCIATE_ADDRESS:
|
|
|
|
break;
|
|
|
|
case TDI_LISTEN:
|
|
|
|
//
|
|
// Initiate an Unlisten.
|
|
//
|
|
TdiRequest.Handle.ConnectionContext = pEndpoint->Handle.ConnectionContext;
|
|
TdiRequest.RequestNotifyObject = (PVOID)RWanCancelComplete;
|
|
TdiRequest.RequestContext = (PVOID)pFileObject;
|
|
|
|
Status = RWanTdiUnListen(
|
|
&TdiRequest
|
|
);
|
|
break;
|
|
|
|
default:
|
|
|
|
//
|
|
// Initiate a Disconnect.
|
|
//
|
|
TdiRequest.Handle.ConnectionContext = pEndpoint->Handle.ConnectionContext;
|
|
TdiRequest.RequestNotifyObject = (PVOID)RWanCancelComplete;
|
|
TdiRequest.RequestContext = (PVOID)pFileObject;
|
|
|
|
Status = RWanTdiDisconnect(
|
|
&TdiRequest,
|
|
NULL,
|
|
TDI_DISCONNECT_ABORT,
|
|
NULL,
|
|
NULL
|
|
);
|
|
break;
|
|
}
|
|
|
|
if (Status != TDI_PENDING)
|
|
{
|
|
RWanCancelComplete(pFileObject, 0, 0);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
|
|
NTSTATUS
|
|
RWanPrepareIrpForCancel(
|
|
IN PRWAN_ENDPOINT pEndpoint,
|
|
IN PIRP pIrp,
|
|
IN PDRIVER_CANCEL pCancelRoutine
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Check if an IRP has been cancelled. If so, complete it with the
|
|
right status. Otherwise, set it up so that the supplied cancel
|
|
routine is called if it is cancelled.
|
|
|
|
This is called for non-data IRPs that are potentially going to
|
|
pend.
|
|
|
|
Arguments:
|
|
|
|
pEndpoint - Pointer to endpoint on which this IRP arrived
|
|
pIrp - Pointer to request packet
|
|
pCancelRoutine - Cancellation routine to be tacked on to the IRP
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - this is STATUS_CANCELLED if the IRP has been cancelled
|
|
already, STATUS_SUCCESS otherwise.
|
|
|
|
--*/
|
|
{
|
|
KIRQL OldIrql;
|
|
NTSTATUS Status;
|
|
|
|
IoAcquireCancelSpinLock(&OldIrql);
|
|
|
|
RWAN_ASSERT(pIrp->CancelRoutine == NULL);
|
|
|
|
if (!pIrp->Cancel)
|
|
{
|
|
//
|
|
// This IRP hasn't been cancelled. Mark it as pending, because
|
|
// it's going to be queued (by the caller).
|
|
//
|
|
IoMarkIrpPending(pIrp);
|
|
|
|
IoSetCancelRoutine(pIrp, pCancelRoutine);
|
|
|
|
//
|
|
// Add a reference for this IRP on the endpoint.
|
|
//
|
|
RWAN_INCR_EP_REF_CNT(pEndpoint, NonDataIncr); // Non data IRP ref
|
|
|
|
RWAN_EP_DBGLOG_ENTRY(pEndpoint, 'DnoN', pIrp, pEndpoint->RefCount);
|
|
|
|
IoReleaseCancelSpinLock(OldIrql);
|
|
|
|
Status = STATUS_SUCCESS;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// The IRP has been cancelled already. Simply complete it.
|
|
//
|
|
|
|
IoReleaseCancelSpinLock(OldIrql);
|
|
|
|
Status = STATUS_CANCELLED;
|
|
RWAN_COMPLETE_IRP(pIrp, Status, 0);
|
|
|
|
}
|
|
|
|
RWANDEBUGP(DL_VERY_LOUD, DC_DISPATCH,
|
|
("RWanPrepareIrpForCancel: pIrp x%x, pEndp x%x, ret Status x%x\n",
|
|
pIrp, pEndpoint, Status));
|
|
|
|
return (Status);
|
|
}
|
|
|
|
|
|
|
|
ULONG
|
|
RWanGetMdlChainLength(
|
|
IN PMDL pMdl
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Return the total byte count of all MDLs in a chain.
|
|
|
|
Arguments:
|
|
|
|
pMdl - Points to start of MDL chain.
|
|
|
|
Return Value:
|
|
|
|
Byte count of the MDL chain.
|
|
|
|
--*/
|
|
{
|
|
ULONG Count = 0;
|
|
|
|
while (pMdl != NULL)
|
|
{
|
|
Count += MmGetMdlByteCount(pMdl);
|
|
pMdl = pMdl->Next;
|
|
}
|
|
|
|
return (Count);
|
|
}
|
|
|
|
|
|
|
|
|
|
NTSTATUS
|
|
RWanToNTStatus(
|
|
IN RWAN_STATUS RWanStatus
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Map from a Raw-WAN status code to an equivalent NT status code.
|
|
|
|
Arguments:
|
|
|
|
RWanStatus - The RAW WAN status code.
|
|
|
|
Return Value:
|
|
|
|
The NT Status code.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
|
|
switch (RWanStatus)
|
|
{
|
|
case RWAN_STATUS_SUCCESS:
|
|
Status = STATUS_SUCCESS;
|
|
break;
|
|
case RWAN_STATUS_BAD_ADDRESS:
|
|
Status = STATUS_INVALID_ADDRESS;
|
|
break;
|
|
case RWAN_STATUS_BAD_PARAMETER:
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
break;
|
|
case RWAN_STATUS_MISSING_PARAMETER:
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
break;
|
|
case RWAN_STATUS_RESOURCES:
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
break;
|
|
case RWAN_STATUS_FAILURE:
|
|
default:
|
|
Status = STATUS_UNSUCCESSFUL;
|
|
break;
|
|
}
|
|
|
|
return (Status);
|
|
|
|
}
|
|
|
|
|
|
|