mirror of
https://github.com/reactos/reactos.git
synced 2024-12-29 10:35:28 +00:00
27fcfe66a2
Spinlocks are not reentrant (and this is done a lot), using them forces us to have an horrible hack in the kernel, which unschedules threads which are at DISPATCH_LEVEL thus allowing another thread to take ownership of the spinlock while the unscheduled thread should already hold it. CORE-6473
1804 lines
51 KiB
C
1804 lines
51 KiB
C
/*
|
|
* COPYRIGHT: See COPYING in the top level directory
|
|
* PROJECT: ReactOS TCP/IP protocol driver
|
|
* FILE: tcpip/dispatch.h
|
|
* PURPOSE: TDI dispatch routines
|
|
* PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
|
|
* REVISIONS:
|
|
* CSH 01/08-2000 Created
|
|
* TODO: Validate device object in all dispatch routines
|
|
*/
|
|
|
|
#include "precomp.h"
|
|
|
|
#include <datagram.h>
|
|
#include <pseh/pseh2.h>
|
|
|
|
typedef struct _QUERY_HW_WORK_ITEM {
|
|
PIO_WORKITEM WorkItem;
|
|
PIRP Irp;
|
|
PIO_STACK_LOCATION IrpSp;
|
|
PIP_INTERFACE Interface;
|
|
LARGE_INTEGER StartTime;
|
|
ULONG RemoteIP;
|
|
} QUERY_HW_WORK_ITEM, *PQUERY_HW_WORK_ITEM;
|
|
|
|
NTSTATUS IRPFinish( PIRP Irp, NTSTATUS Status ) {
|
|
KIRQL OldIrql;
|
|
|
|
if (Status != STATUS_PENDING) {
|
|
Irp->IoStatus.Status = Status;
|
|
IoAcquireCancelSpinLock(&OldIrql);
|
|
(void)IoSetCancelRoutine( Irp, NULL );
|
|
IoReleaseCancelSpinLock(OldIrql);
|
|
|
|
IoCompleteRequest( Irp, IO_NETWORK_INCREMENT );
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS DispPrepareIrpForCancel(
|
|
PTRANSPORT_CONTEXT Context,
|
|
PIRP Irp,
|
|
PDRIVER_CANCEL CancelRoutine)
|
|
/*
|
|
* FUNCTION: Prepare an IRP for cancellation
|
|
* ARGUMENTS:
|
|
* Context = Pointer to context information
|
|
* Irp = Pointer to an I/O request packet
|
|
* CancelRoutine = Routine to be called when I/O request is cancelled
|
|
* RETURNS:
|
|
* Status of operation
|
|
*/
|
|
{
|
|
KIRQL OldIrql;
|
|
PIO_STACK_LOCATION IrpSp;
|
|
PTRANSPORT_CONTEXT TransContext;
|
|
|
|
TI_DbgPrint(DEBUG_IRP, ("Called.\n"));
|
|
|
|
IrpSp = IoGetCurrentIrpStackLocation(Irp);
|
|
TransContext = (PTRANSPORT_CONTEXT)IrpSp->FileObject->FsContext;
|
|
|
|
IoAcquireCancelSpinLock(&OldIrql);
|
|
|
|
if (!Irp->Cancel && !TransContext->CancelIrps) {
|
|
(void)IoSetCancelRoutine(Irp, CancelRoutine);
|
|
IoReleaseCancelSpinLock(OldIrql);
|
|
|
|
TI_DbgPrint(DEBUG_IRP, ("Leaving (IRP at 0x%X can now be cancelled).\n", Irp));
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
/* IRP has already been cancelled */
|
|
|
|
IoReleaseCancelSpinLock(OldIrql);
|
|
|
|
Irp->IoStatus.Status = STATUS_CANCELLED;
|
|
Irp->IoStatus.Information = 0;
|
|
|
|
TI_DbgPrint(DEBUG_IRP, ("Leaving (IRP was already cancelled).\n"));
|
|
|
|
return Irp->IoStatus.Status;
|
|
}
|
|
|
|
VOID DispDataRequestComplete(
|
|
PVOID Context,
|
|
NTSTATUS Status,
|
|
ULONG Count)
|
|
/*
|
|
* FUNCTION: Completes a send/receive IRP
|
|
* ARGUMENTS:
|
|
* Context = Pointer to context information (IRP)
|
|
* Status = Status of the request
|
|
* Count = Number of bytes sent or received
|
|
*/
|
|
{
|
|
PIRP Irp = Context;
|
|
|
|
TI_DbgPrint(DEBUG_IRP, ("Called for irp %x (%x, %d).\n",
|
|
Irp, Status, Count));
|
|
|
|
Irp->IoStatus.Status = Status;
|
|
Irp->IoStatus.Information = Count;
|
|
|
|
TI_DbgPrint(MID_TRACE, ("Irp->IoStatus.Status = %x\n",
|
|
Irp->IoStatus.Status));
|
|
TI_DbgPrint(MID_TRACE, ("Irp->IoStatus.Information = %d\n",
|
|
Irp->IoStatus.Information));
|
|
TI_DbgPrint(DEBUG_IRP, ("Completing IRP at (0x%X).\n", Irp));
|
|
|
|
IRPFinish(Irp, Status);
|
|
|
|
TI_DbgPrint(DEBUG_IRP, ("Done Completing IRP\n"));
|
|
}
|
|
|
|
VOID NTAPI DispCancelRequest(
|
|
PDEVICE_OBJECT Device,
|
|
PIRP Irp)
|
|
/*
|
|
* FUNCTION: Cancels an IRP
|
|
* ARGUMENTS:
|
|
* Device = Pointer to device object
|
|
* Irp = Pointer to an I/O request packet
|
|
*/
|
|
{
|
|
PIO_STACK_LOCATION IrpSp;
|
|
PTRANSPORT_CONTEXT TranContext;
|
|
PFILE_OBJECT FileObject;
|
|
UCHAR MinorFunction;
|
|
PCONNECTION_ENDPOINT Connection;
|
|
BOOLEAN DequeuedIrp = TRUE;
|
|
|
|
IoReleaseCancelSpinLock(Irp->CancelIrql);
|
|
|
|
TI_DbgPrint(DEBUG_IRP, ("Called.\n"));
|
|
|
|
IrpSp = IoGetCurrentIrpStackLocation(Irp);
|
|
FileObject = IrpSp->FileObject;
|
|
TranContext = (PTRANSPORT_CONTEXT)FileObject->FsContext;
|
|
MinorFunction = IrpSp->MinorFunction;
|
|
|
|
TI_DbgPrint(DEBUG_IRP, ("IRP at (0x%X) MinorFunction (0x%X) IrpSp (0x%X).\n", Irp, MinorFunction, IrpSp));
|
|
|
|
Irp->IoStatus.Status = STATUS_CANCELLED;
|
|
Irp->IoStatus.Information = 0;
|
|
|
|
#if DBG
|
|
if (!Irp->Cancel)
|
|
TI_DbgPrint(MIN_TRACE, ("Irp->Cancel is FALSE, should be TRUE.\n"));
|
|
#endif
|
|
|
|
/* Try canceling the request */
|
|
switch(MinorFunction) {
|
|
case TDI_SEND:
|
|
case TDI_RECEIVE:
|
|
DequeuedIrp = TCPRemoveIRP( TranContext->Handle.ConnectionContext, Irp );
|
|
break;
|
|
|
|
case TDI_SEND_DATAGRAM:
|
|
if (FileObject->FsContext2 != (PVOID)TDI_TRANSPORT_ADDRESS_FILE) {
|
|
TI_DbgPrint(MIN_TRACE, ("TDI_SEND_DATAGRAM, but no address file.\n"));
|
|
break;
|
|
}
|
|
|
|
DequeuedIrp = DGRemoveIRP(TranContext->Handle.AddressHandle, Irp);
|
|
break;
|
|
|
|
case TDI_RECEIVE_DATAGRAM:
|
|
if (FileObject->FsContext2 != (PVOID)TDI_TRANSPORT_ADDRESS_FILE) {
|
|
TI_DbgPrint(MIN_TRACE, ("TDI_RECEIVE_DATAGRAM, but no address file.\n"));
|
|
break;
|
|
}
|
|
|
|
DequeuedIrp = DGRemoveIRP(TranContext->Handle.AddressHandle, Irp);
|
|
break;
|
|
|
|
case TDI_CONNECT:
|
|
DequeuedIrp = TCPRemoveIRP(TranContext->Handle.ConnectionContext, Irp);
|
|
break;
|
|
|
|
case TDI_DISCONNECT:
|
|
Connection = (PCONNECTION_ENDPOINT)TranContext->Handle.ConnectionContext;
|
|
|
|
DequeuedIrp = TCPRemoveIRP(TranContext->Handle.ConnectionContext, Irp);
|
|
if (DequeuedIrp)
|
|
{
|
|
if (KeCancelTimer(&Connection->DisconnectTimer))
|
|
{
|
|
DereferenceObject(Connection);
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
TI_DbgPrint(MIN_TRACE, ("Unknown IRP. MinorFunction (0x%X).\n", MinorFunction));
|
|
ASSERT(FALSE);
|
|
break;
|
|
}
|
|
|
|
if (DequeuedIrp)
|
|
IRPFinish(Irp, STATUS_CANCELLED);
|
|
|
|
TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));
|
|
}
|
|
|
|
|
|
VOID NTAPI DispCancelListenRequest(
|
|
PDEVICE_OBJECT Device,
|
|
PIRP Irp)
|
|
/*
|
|
* FUNCTION: Cancels a listen IRP
|
|
* ARGUMENTS:
|
|
* Device = Pointer to device object
|
|
* Irp = Pointer to an I/O request packet
|
|
*/
|
|
{
|
|
PIO_STACK_LOCATION IrpSp;
|
|
PTRANSPORT_CONTEXT TranContext;
|
|
PFILE_OBJECT FileObject;
|
|
PCONNECTION_ENDPOINT Connection;
|
|
|
|
IoReleaseCancelSpinLock(Irp->CancelIrql);
|
|
|
|
TI_DbgPrint(DEBUG_IRP, ("Called.\n"));
|
|
|
|
IrpSp = IoGetCurrentIrpStackLocation(Irp);
|
|
FileObject = IrpSp->FileObject;
|
|
TranContext = (PTRANSPORT_CONTEXT)FileObject->FsContext;
|
|
ASSERT( TDI_LISTEN == IrpSp->MinorFunction);
|
|
|
|
TI_DbgPrint(DEBUG_IRP, ("IRP at (0x%X).\n", Irp));
|
|
|
|
#if DBG
|
|
if (!Irp->Cancel)
|
|
TI_DbgPrint(MIN_TRACE, ("Irp->Cancel is FALSE, should be TRUE.\n"));
|
|
#endif
|
|
|
|
/* Try canceling the request */
|
|
Connection = (PCONNECTION_ENDPOINT)TranContext->Handle.ConnectionContext;
|
|
|
|
if (TCPAbortListenForSocket(Connection->AddressFile->Listener,
|
|
Connection))
|
|
{
|
|
Irp->IoStatus.Information = 0;
|
|
IRPFinish(Irp, STATUS_CANCELLED);
|
|
}
|
|
|
|
TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));
|
|
}
|
|
|
|
|
|
NTSTATUS DispTdiAccept(
|
|
PIRP Irp)
|
|
/*
|
|
* FUNCTION: TDI_ACCEPT handler
|
|
* ARGUMENTS:
|
|
* Irp = Pointer to an I/O request packet
|
|
* RETURNS:
|
|
* Status of operation
|
|
*/
|
|
{
|
|
TI_DbgPrint(DEBUG_IRP, ("Called.\n"));
|
|
|
|
return STATUS_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
|
|
NTSTATUS DispTdiAssociateAddress(
|
|
PIRP Irp)
|
|
/*
|
|
* FUNCTION: TDI_ASSOCIATE_ADDRESS handler
|
|
* ARGUMENTS:
|
|
* Irp = Pointer to an I/O request packet
|
|
* RETURNS:
|
|
* Status of operation
|
|
*/
|
|
{
|
|
PTDI_REQUEST_KERNEL_ASSOCIATE Parameters;
|
|
PTRANSPORT_CONTEXT TranContext;
|
|
PIO_STACK_LOCATION IrpSp;
|
|
PCONNECTION_ENDPOINT Connection, LastConnection;
|
|
PFILE_OBJECT FileObject;
|
|
PADDRESS_FILE AddrFile = NULL;
|
|
NTSTATUS Status;
|
|
|
|
TI_DbgPrint(DEBUG_IRP, ("Called.\n"));
|
|
|
|
IrpSp = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
/* Get associated connection endpoint file object. Quit if none exists */
|
|
|
|
TranContext = IrpSp->FileObject->FsContext;
|
|
if (!TranContext) {
|
|
TI_DbgPrint(MID_TRACE, ("Bad transport context.\n"));
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
Connection = (PCONNECTION_ENDPOINT)TranContext->Handle.ConnectionContext;
|
|
if (!Connection) {
|
|
TI_DbgPrint(MID_TRACE, ("No connection endpoint file object.\n"));
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
Parameters = (PTDI_REQUEST_KERNEL_ASSOCIATE)&IrpSp->Parameters;
|
|
|
|
Status = ObReferenceObjectByHandle(
|
|
Parameters->AddressHandle,
|
|
0,
|
|
*IoFileObjectType,
|
|
KernelMode,
|
|
(PVOID*)&FileObject,
|
|
NULL);
|
|
if (!NT_SUCCESS(Status)) {
|
|
TI_DbgPrint(MID_TRACE, ("Bad address file object handle (0x%X): %x.\n",
|
|
Parameters->AddressHandle, Status));
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
LockObject(Connection);
|
|
|
|
if (Connection->AddressFile) {
|
|
ObDereferenceObject(FileObject);
|
|
UnlockObject(Connection);
|
|
TI_DbgPrint(MID_TRACE, ("An address file is already associated.\n"));
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
if (FileObject->FsContext2 != (PVOID)TDI_TRANSPORT_ADDRESS_FILE) {
|
|
ObDereferenceObject(FileObject);
|
|
UnlockObject(Connection);
|
|
TI_DbgPrint(MID_TRACE, ("Bad address file object. Magic (0x%X).\n",
|
|
FileObject->FsContext2));
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
/* Get associated address file object. Quit if none exists */
|
|
|
|
TranContext = FileObject->FsContext;
|
|
if (!TranContext) {
|
|
ObDereferenceObject(FileObject);
|
|
UnlockObject(Connection);
|
|
TI_DbgPrint(MID_TRACE, ("Bad transport context.\n"));
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
AddrFile = (PADDRESS_FILE)TranContext->Handle.AddressHandle;
|
|
if (!AddrFile) {
|
|
UnlockObject(Connection);
|
|
ObDereferenceObject(FileObject);
|
|
TI_DbgPrint(MID_TRACE, ("No address file object.\n"));
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
LockObject(AddrFile);
|
|
|
|
ReferenceObject(AddrFile);
|
|
Connection->AddressFile = AddrFile;
|
|
|
|
/* Add connection endpoint to the address file */
|
|
ReferenceObject(Connection);
|
|
if (AddrFile->Connection == NULL)
|
|
AddrFile->Connection = Connection;
|
|
else
|
|
{
|
|
LastConnection = AddrFile->Connection;
|
|
while (LastConnection->Next != NULL)
|
|
LastConnection = LastConnection->Next;
|
|
LastConnection->Next = Connection;
|
|
}
|
|
|
|
ObDereferenceObject(FileObject);
|
|
|
|
UnlockObject(AddrFile);
|
|
UnlockObject(Connection);
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
NTSTATUS DispTdiConnect(
|
|
PIRP Irp)
|
|
/*
|
|
* FUNCTION: TDI_CONNECT handler
|
|
* ARGUMENTS:
|
|
* Irp = Pointer to an I/O request packet
|
|
* RETURNS:
|
|
* Status of operation
|
|
*/
|
|
{
|
|
PCONNECTION_ENDPOINT Connection;
|
|
PTDI_REQUEST_KERNEL Parameters;
|
|
PTRANSPORT_CONTEXT TranContext;
|
|
PIO_STACK_LOCATION IrpSp;
|
|
NTSTATUS Status;
|
|
|
|
TI_DbgPrint(DEBUG_IRP, ("Called.\n"));
|
|
|
|
IrpSp = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
IoMarkIrpPending(Irp);
|
|
|
|
/* Get associated connection endpoint file object. Quit if none exists */
|
|
|
|
TranContext = IrpSp->FileObject->FsContext;
|
|
if (!TranContext) {
|
|
TI_DbgPrint(MID_TRACE, ("Bad transport context.\n"));
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
goto done;
|
|
}
|
|
|
|
Connection = (PCONNECTION_ENDPOINT)TranContext->Handle.ConnectionContext;
|
|
if (!Connection) {
|
|
TI_DbgPrint(MID_TRACE, ("No connection endpoint file object.\n"));
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
goto done;
|
|
}
|
|
|
|
Parameters = (PTDI_REQUEST_KERNEL)&IrpSp->Parameters;
|
|
|
|
Status = DispPrepareIrpForCancel(TranContext->Handle.ConnectionContext,
|
|
Irp,
|
|
DispCancelRequest);
|
|
|
|
if (NT_SUCCESS(Status)) {
|
|
Status = TCPConnect(
|
|
TranContext->Handle.ConnectionContext,
|
|
Parameters->RequestConnectionInformation,
|
|
Parameters->ReturnConnectionInformation,
|
|
DispDataRequestComplete,
|
|
Irp );
|
|
}
|
|
|
|
done:
|
|
if (Status != STATUS_PENDING) {
|
|
DispDataRequestComplete(Irp, Status, 0);
|
|
}
|
|
|
|
TI_DbgPrint(MAX_TRACE, ("TCP Connect returned %08x\n", Status));
|
|
|
|
return STATUS_PENDING;
|
|
}
|
|
|
|
|
|
NTSTATUS DispTdiDisassociateAddress(
|
|
PIRP Irp)
|
|
/*
|
|
* FUNCTION: TDI_DISASSOCIATE_ADDRESS handler
|
|
* ARGUMENTS:
|
|
* Irp = Pointer to an I/O request packet
|
|
* RETURNS:
|
|
* Status of operation
|
|
*/
|
|
{
|
|
PCONNECTION_ENDPOINT Connection;
|
|
PTRANSPORT_CONTEXT TranContext;
|
|
PIO_STACK_LOCATION IrpSp;
|
|
|
|
TI_DbgPrint(DEBUG_IRP, ("Called.\n"));
|
|
|
|
IrpSp = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
/* Get associated connection endpoint file object. Quit if none exists */
|
|
|
|
TranContext = IrpSp->FileObject->FsContext;
|
|
if (!TranContext) {
|
|
TI_DbgPrint(MID_TRACE, ("Bad transport context.\n"));
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
Connection = (PCONNECTION_ENDPOINT)TranContext->Handle.ConnectionContext;
|
|
if (!Connection) {
|
|
TI_DbgPrint(MID_TRACE, ("No connection endpoint file object.\n"));
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
/* NO-OP because we need the address to deallocate the port when the connection closes */
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
NTSTATUS DispTdiDisconnect(
|
|
PIRP Irp)
|
|
/*
|
|
* FUNCTION: TDI_DISCONNECT handler
|
|
* ARGUMENTS:
|
|
* Irp = Pointer to an I/O request packet
|
|
* RETURNS:
|
|
* Status of operation
|
|
*/
|
|
{
|
|
NTSTATUS Status;
|
|
PTDI_REQUEST_KERNEL_DISCONNECT DisReq;
|
|
PCONNECTION_ENDPOINT Connection;
|
|
PTRANSPORT_CONTEXT TranContext;
|
|
PIO_STACK_LOCATION IrpSp;
|
|
|
|
TI_DbgPrint(DEBUG_IRP, ("Called.\n"));
|
|
|
|
IrpSp = IoGetCurrentIrpStackLocation(Irp);
|
|
DisReq = (PTDI_REQUEST_KERNEL_DISCONNECT)&IrpSp->Parameters;
|
|
|
|
IoMarkIrpPending(Irp);
|
|
|
|
/* Get associated connection endpoint file object. Quit if none exists */
|
|
|
|
TranContext = IrpSp->FileObject->FsContext;
|
|
if (!TranContext) {
|
|
TI_DbgPrint(MID_TRACE, ("Bad transport context.\n"));
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
goto done;
|
|
}
|
|
|
|
Connection = (PCONNECTION_ENDPOINT)TranContext->Handle.ConnectionContext;
|
|
if (!Connection) {
|
|
TI_DbgPrint(MID_TRACE, ("No connection endpoint file object.\n"));
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
goto done;
|
|
}
|
|
|
|
Status = DispPrepareIrpForCancel
|
|
(TranContext->Handle.ConnectionContext,
|
|
Irp,
|
|
(PDRIVER_CANCEL)DispCancelRequest);
|
|
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
Status = TCPDisconnect(TranContext->Handle.ConnectionContext,
|
|
DisReq->RequestFlags,
|
|
DisReq->RequestSpecific,
|
|
DisReq->RequestConnectionInformation,
|
|
DisReq->ReturnConnectionInformation,
|
|
DispDataRequestComplete,
|
|
Irp);
|
|
}
|
|
|
|
done:
|
|
if (Status != STATUS_PENDING) {
|
|
DispDataRequestComplete(Irp, Status, 0);
|
|
}
|
|
|
|
TI_DbgPrint(MAX_TRACE, ("TCP Disconnect returned %08x\n", Status));
|
|
|
|
return STATUS_PENDING;
|
|
}
|
|
|
|
|
|
NTSTATUS DispTdiListen(
|
|
PIRP Irp)
|
|
/*
|
|
* FUNCTION: TDI_LISTEN handler
|
|
* ARGUMENTS:
|
|
* Irp = Pointer to an I/O request packet
|
|
* RETURNS:
|
|
* Status of operation
|
|
*/
|
|
{
|
|
PCONNECTION_ENDPOINT Connection;
|
|
PTDI_REQUEST_KERNEL Parameters;
|
|
PTRANSPORT_CONTEXT TranContext;
|
|
PIO_STACK_LOCATION IrpSp;
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
|
|
TI_DbgPrint(DEBUG_IRP, ("Called.\n"));
|
|
|
|
IrpSp = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
IoMarkIrpPending(Irp);
|
|
|
|
/* Get associated connection endpoint file object. Quit if none exists */
|
|
|
|
TranContext = IrpSp->FileObject->FsContext;
|
|
if (TranContext == NULL)
|
|
{
|
|
TI_DbgPrint(MID_TRACE, ("Bad transport context.\n"));
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
goto done;
|
|
}
|
|
|
|
Connection = (PCONNECTION_ENDPOINT)TranContext->Handle.ConnectionContext;
|
|
if (Connection == NULL)
|
|
{
|
|
TI_DbgPrint(MID_TRACE, ("No connection endpoint file object.\n"));
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
goto done;
|
|
}
|
|
|
|
Parameters = (PTDI_REQUEST_KERNEL)&IrpSp->Parameters;
|
|
|
|
Status = DispPrepareIrpForCancel
|
|
(TranContext->Handle.ConnectionContext,
|
|
Irp,
|
|
(PDRIVER_CANCEL)DispCancelListenRequest);
|
|
|
|
LockObject(Connection);
|
|
|
|
if (Connection->AddressFile == NULL)
|
|
{
|
|
TI_DbgPrint(MID_TRACE, ("No associated address file\n"));
|
|
UnlockObject(Connection);
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
goto done;
|
|
}
|
|
|
|
LockObject(Connection->AddressFile);
|
|
|
|
/* Listening will require us to create a listening socket and store it in
|
|
* the address file. It will be signalled, and attempt to complete an irp
|
|
* when a new connection arrives. */
|
|
/* The important thing to note here is that the irp we'll complete belongs
|
|
* to the socket to be accepted onto, not the listener */
|
|
if( NT_SUCCESS(Status) && !Connection->AddressFile->Listener ) {
|
|
Connection->AddressFile->Listener =
|
|
TCPAllocateConnectionEndpoint( NULL );
|
|
|
|
if( !Connection->AddressFile->Listener )
|
|
Status = STATUS_NO_MEMORY;
|
|
|
|
if( NT_SUCCESS(Status) ) {
|
|
ReferenceObject(Connection->AddressFile);
|
|
Connection->AddressFile->Listener->AddressFile =
|
|
Connection->AddressFile;
|
|
|
|
Status = TCPSocket( Connection->AddressFile->Listener,
|
|
Connection->AddressFile->Family,
|
|
SOCK_STREAM,
|
|
Connection->AddressFile->Protocol );
|
|
}
|
|
|
|
if( NT_SUCCESS(Status) ) {
|
|
ReferenceObject(Connection->AddressFile->Listener);
|
|
Status = TCPListen( Connection->AddressFile->Listener, 1024 );
|
|
/* BACKLOG */
|
|
}
|
|
}
|
|
|
|
if( NT_SUCCESS(Status) ) {
|
|
Status = TCPAccept
|
|
( (PTDI_REQUEST)Parameters,
|
|
Connection->AddressFile->Listener,
|
|
Connection,
|
|
DispDataRequestComplete,
|
|
Irp );
|
|
}
|
|
|
|
UnlockObject(Connection->AddressFile);
|
|
UnlockObject(Connection);
|
|
|
|
done:
|
|
if (Status != STATUS_PENDING) {
|
|
DispDataRequestComplete(Irp, Status, 0);
|
|
}
|
|
|
|
TI_DbgPrint(MID_TRACE,("Leaving %x\n", Status));
|
|
|
|
return STATUS_PENDING;
|
|
}
|
|
|
|
|
|
NTSTATUS DispTdiQueryInformation(
|
|
PDEVICE_OBJECT DeviceObject,
|
|
PIRP Irp)
|
|
/*
|
|
* FUNCTION: TDI_QUERY_INFORMATION handler
|
|
* ARGUMENTS:
|
|
* DeviceObject = Pointer to device object structure
|
|
* Irp = Pointer to an I/O request packet
|
|
* RETURNS:
|
|
* Status of operation
|
|
*/
|
|
{
|
|
PTDI_REQUEST_KERNEL_QUERY_INFORMATION Parameters;
|
|
PTRANSPORT_CONTEXT TranContext;
|
|
PIO_STACK_LOCATION IrpSp;
|
|
|
|
TI_DbgPrint(DEBUG_IRP, ("Called.\n"));
|
|
|
|
IrpSp = IoGetCurrentIrpStackLocation(Irp);
|
|
Parameters = (PTDI_REQUEST_KERNEL_QUERY_INFORMATION)&IrpSp->Parameters;
|
|
|
|
TranContext = IrpSp->FileObject->FsContext;
|
|
if (!TranContext) {
|
|
TI_DbgPrint(MID_TRACE, ("Bad transport context.\n"));
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
switch (Parameters->QueryType)
|
|
{
|
|
case TDI_QUERY_ADDRESS_INFO:
|
|
{
|
|
PTDI_ADDRESS_INFO AddressInfo;
|
|
PADDRESS_FILE AddrFile;
|
|
PTA_IP_ADDRESS Address;
|
|
PCONNECTION_ENDPOINT Endpoint = NULL;
|
|
|
|
|
|
if (MmGetMdlByteCount(Irp->MdlAddress) <
|
|
(FIELD_OFFSET(TDI_ADDRESS_INFO, Address.Address[0].Address) +
|
|
sizeof(TDI_ADDRESS_IP))) {
|
|
TI_DbgPrint(MID_TRACE, ("MDL buffer too small.\n"));
|
|
return STATUS_BUFFER_TOO_SMALL;
|
|
}
|
|
|
|
AddressInfo = (PTDI_ADDRESS_INFO)MmGetSystemAddressForMdl(Irp->MdlAddress);
|
|
Address = (PTA_IP_ADDRESS)&AddressInfo->Address;
|
|
|
|
switch ((ULONG_PTR)IrpSp->FileObject->FsContext2) {
|
|
case TDI_TRANSPORT_ADDRESS_FILE:
|
|
AddrFile = (PADDRESS_FILE)TranContext->Handle.AddressHandle;
|
|
if (AddrFile == NULL)
|
|
{
|
|
TI_DbgPrint(MIN_TRACE, ("FIXME: No address file object.\n"));
|
|
ASSERT(AddrFile != NULL);
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
Address->TAAddressCount = 1;
|
|
Address->Address[0].AddressLength = TDI_ADDRESS_LENGTH_IP;
|
|
Address->Address[0].AddressType = TDI_ADDRESS_TYPE_IP;
|
|
Address->Address[0].Address[0].sin_port = AddrFile->Port;
|
|
Address->Address[0].Address[0].in_addr = AddrFile->Address.Address.IPv4Address;
|
|
RtlZeroMemory(
|
|
&Address->Address[0].Address[0].sin_zero,
|
|
sizeof(Address->Address[0].Address[0].sin_zero));
|
|
return STATUS_SUCCESS;
|
|
|
|
case TDI_CONNECTION_FILE:
|
|
Endpoint =
|
|
(PCONNECTION_ENDPOINT)TranContext->Handle.ConnectionContext;
|
|
if (Endpoint == NULL || Endpoint->AddressFile == NULL)
|
|
{
|
|
TI_DbgPrint(MIN_TRACE, ("FIXME: No connection endpoint file object.\n"));
|
|
ASSERT(Endpoint != NULL && Endpoint->AddressFile != NULL);
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
Address->TAAddressCount = 1;
|
|
Address->Address[0].AddressLength = TDI_ADDRESS_LENGTH_IP;
|
|
Address->Address[0].AddressType = TDI_ADDRESS_TYPE_IP;
|
|
Address->Address[0].Address[0].sin_port = Endpoint->AddressFile->Port;
|
|
Address->Address[0].Address[0].in_addr = Endpoint->AddressFile->Address.Address.IPv4Address;
|
|
RtlZeroMemory(
|
|
&Address->Address[0].Address[0].sin_zero,
|
|
sizeof(Address->Address[0].Address[0].sin_zero));
|
|
return STATUS_SUCCESS;
|
|
|
|
default:
|
|
TI_DbgPrint(MIN_TRACE, ("Invalid transport context\n"));
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
}
|
|
|
|
case TDI_QUERY_CONNECTION_INFO:
|
|
{
|
|
PTDI_CONNECTION_INFO ConnectionInfo;
|
|
//PCONNECTION_ENDPOINT Endpoint;
|
|
|
|
if (MmGetMdlByteCount(Irp->MdlAddress) < sizeof(*ConnectionInfo)) {
|
|
TI_DbgPrint(MID_TRACE, ("MDL buffer too small.\n"));
|
|
return STATUS_BUFFER_TOO_SMALL;
|
|
}
|
|
|
|
ConnectionInfo = (PTDI_CONNECTION_INFO)
|
|
MmGetSystemAddressForMdl(Irp->MdlAddress);
|
|
|
|
switch ((ULONG_PTR)IrpSp->FileObject->FsContext2) {
|
|
case TDI_CONNECTION_FILE:
|
|
//Endpoint = (PCONNECTION_ENDPOINT)TranContext->Handle.ConnectionContext;
|
|
RtlZeroMemory(ConnectionInfo, sizeof(*ConnectionInfo));
|
|
return STATUS_SUCCESS;
|
|
|
|
default:
|
|
TI_DbgPrint(MIN_TRACE, ("Invalid transport context\n"));
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
}
|
|
|
|
case TDI_QUERY_MAX_DATAGRAM_INFO:
|
|
{
|
|
PTDI_MAX_DATAGRAM_INFO MaxDatagramInfo;
|
|
|
|
if (MmGetMdlByteCount(Irp->MdlAddress) < sizeof(*MaxDatagramInfo)) {
|
|
TI_DbgPrint(MID_TRACE, ("MDL buffer too small.\n"));
|
|
return STATUS_BUFFER_TOO_SMALL;
|
|
}
|
|
|
|
MaxDatagramInfo = (PTDI_MAX_DATAGRAM_INFO)
|
|
MmGetSystemAddressForMdl(Irp->MdlAddress);
|
|
|
|
MaxDatagramInfo->MaxDatagramSize = 0xFFFF;
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
}
|
|
|
|
return STATUS_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
|
|
NTSTATUS DispTdiReceive(
|
|
PIRP Irp)
|
|
/*
|
|
* FUNCTION: TDI_RECEIVE handler
|
|
* ARGUMENTS:
|
|
* Irp = Pointer to an I/O request packet
|
|
* RETURNS:
|
|
* Status of operation
|
|
*/
|
|
{
|
|
PIO_STACK_LOCATION IrpSp;
|
|
PTDI_REQUEST_KERNEL_RECEIVE ReceiveInfo;
|
|
PTRANSPORT_CONTEXT TranContext;
|
|
NTSTATUS Status;
|
|
ULONG BytesReceived = 0;
|
|
|
|
TI_DbgPrint(DEBUG_IRP, ("Called.\n"));
|
|
|
|
IrpSp = IoGetCurrentIrpStackLocation(Irp);
|
|
ReceiveInfo = (PTDI_REQUEST_KERNEL_RECEIVE)&(IrpSp->Parameters);
|
|
|
|
IoMarkIrpPending(Irp);
|
|
|
|
TranContext = IrpSp->FileObject->FsContext;
|
|
if (TranContext == NULL)
|
|
{
|
|
TI_DbgPrint(MID_TRACE, ("Bad transport context.\n"));
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
goto done;
|
|
}
|
|
|
|
if (TranContext->Handle.ConnectionContext == NULL)
|
|
{
|
|
TI_DbgPrint(MID_TRACE, ("No connection endpoint file object.\n"));
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
goto done;
|
|
}
|
|
|
|
/* Initialize a receive request */
|
|
Status = DispPrepareIrpForCancel
|
|
(TranContext->Handle.ConnectionContext,
|
|
Irp,
|
|
(PDRIVER_CANCEL)DispCancelRequest);
|
|
|
|
TI_DbgPrint(MID_TRACE,("TCPIP<<< Got an MDL: %x\n", Irp->MdlAddress));
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
Status = TCPReceiveData(
|
|
TranContext->Handle.ConnectionContext,
|
|
(PNDIS_BUFFER)Irp->MdlAddress,
|
|
ReceiveInfo->ReceiveLength,
|
|
&BytesReceived,
|
|
ReceiveInfo->ReceiveFlags,
|
|
DispDataRequestComplete,
|
|
Irp);
|
|
}
|
|
|
|
done:
|
|
if (Status != STATUS_PENDING) {
|
|
DispDataRequestComplete(Irp, Status, BytesReceived);
|
|
}
|
|
|
|
TI_DbgPrint(DEBUG_IRP, ("Leaving. Status is (0x%X)\n", Status));
|
|
|
|
return STATUS_PENDING;
|
|
}
|
|
|
|
|
|
NTSTATUS DispTdiReceiveDatagram(
|
|
PIRP Irp)
|
|
/*
|
|
* FUNCTION: TDI_RECEIVE_DATAGRAM handler
|
|
* ARGUMENTS:
|
|
* Irp = Pointer to an I/O request packet
|
|
* RETURNS:
|
|
* Status of operation
|
|
*/
|
|
{
|
|
PIO_STACK_LOCATION IrpSp;
|
|
PTDI_REQUEST_KERNEL_RECEIVEDG DgramInfo;
|
|
PTRANSPORT_CONTEXT TranContext;
|
|
TDI_REQUEST Request;
|
|
NTSTATUS Status;
|
|
ULONG BytesReceived = 0;
|
|
|
|
TI_DbgPrint(DEBUG_IRP, ("Called.\n"));
|
|
|
|
IrpSp = IoGetCurrentIrpStackLocation(Irp);
|
|
DgramInfo = (PTDI_REQUEST_KERNEL_RECEIVEDG)&(IrpSp->Parameters);
|
|
|
|
IoMarkIrpPending(Irp);
|
|
|
|
TranContext = IrpSp->FileObject->FsContext;
|
|
if (TranContext == NULL)
|
|
{
|
|
TI_DbgPrint(MID_TRACE, ("Bad transport context.\n"));
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
goto done;
|
|
}
|
|
|
|
/* Initialize a receive request */
|
|
Request.Handle.AddressHandle = TranContext->Handle.AddressHandle;
|
|
Request.RequestNotifyObject = DispDataRequestComplete;
|
|
Request.RequestContext = Irp;
|
|
|
|
Status = DispPrepareIrpForCancel(
|
|
IrpSp->FileObject->FsContext,
|
|
Irp,
|
|
(PDRIVER_CANCEL)DispCancelRequest);
|
|
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
PVOID DataBuffer;
|
|
UINT BufferSize;
|
|
|
|
NdisQueryBuffer( (PNDIS_BUFFER)Irp->MdlAddress,
|
|
&DataBuffer,
|
|
&BufferSize );
|
|
|
|
Status = DGReceiveDatagram(
|
|
Request.Handle.AddressHandle,
|
|
DgramInfo->ReceiveDatagramInformation,
|
|
DataBuffer,
|
|
DgramInfo->ReceiveLength,
|
|
DgramInfo->ReceiveFlags,
|
|
DgramInfo->ReturnDatagramInformation,
|
|
&BytesReceived,
|
|
(PDATAGRAM_COMPLETION_ROUTINE)DispDataRequestComplete,
|
|
Irp,
|
|
Irp);
|
|
}
|
|
|
|
done:
|
|
if (Status != STATUS_PENDING) {
|
|
DispDataRequestComplete(Irp, Status, BytesReceived);
|
|
}
|
|
|
|
TI_DbgPrint(DEBUG_IRP, ("Leaving. Status is (0x%X)\n", Status));
|
|
|
|
return STATUS_PENDING;
|
|
}
|
|
|
|
|
|
NTSTATUS DispTdiSend(
|
|
PIRP Irp)
|
|
/*
|
|
* FUNCTION: TDI_SEND handler
|
|
* ARGUMENTS:
|
|
* Irp = Pointer to an I/O request packet
|
|
* RETURNS:
|
|
* Status of operation
|
|
*/
|
|
{
|
|
PIO_STACK_LOCATION IrpSp;
|
|
PTDI_REQUEST_KERNEL_SEND SendInfo;
|
|
PTRANSPORT_CONTEXT TranContext;
|
|
NTSTATUS Status;
|
|
ULONG BytesSent = 0;
|
|
|
|
TI_DbgPrint(DEBUG_IRP, ("Called.\n"));
|
|
|
|
IrpSp = IoGetCurrentIrpStackLocation(Irp);
|
|
SendInfo = (PTDI_REQUEST_KERNEL_SEND)&(IrpSp->Parameters);
|
|
|
|
IoMarkIrpPending(Irp);
|
|
|
|
TranContext = IrpSp->FileObject->FsContext;
|
|
if (TranContext == NULL)
|
|
{
|
|
TI_DbgPrint(MID_TRACE, ("Bad transport context.\n"));
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
goto done;
|
|
}
|
|
|
|
if (TranContext->Handle.ConnectionContext == NULL)
|
|
{
|
|
TI_DbgPrint(MID_TRACE, ("No connection endpoint file object.\n"));
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
goto done;
|
|
}
|
|
|
|
Status = DispPrepareIrpForCancel(
|
|
IrpSp->FileObject->FsContext,
|
|
Irp,
|
|
(PDRIVER_CANCEL)DispCancelRequest);
|
|
|
|
TI_DbgPrint(MID_TRACE,("TCPIP<<< Got an MDL: %x\n", Irp->MdlAddress));
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
PVOID Data;
|
|
UINT Len;
|
|
|
|
NdisQueryBuffer( Irp->MdlAddress, &Data, &Len );
|
|
|
|
TI_DbgPrint(MID_TRACE,("About to TCPSendData\n"));
|
|
Status = TCPSendData(
|
|
TranContext->Handle.ConnectionContext,
|
|
Data,
|
|
SendInfo->SendLength,
|
|
&BytesSent,
|
|
SendInfo->SendFlags,
|
|
DispDataRequestComplete,
|
|
Irp);
|
|
}
|
|
|
|
done:
|
|
if (Status != STATUS_PENDING) {
|
|
DispDataRequestComplete(Irp, Status, BytesSent);
|
|
}
|
|
|
|
TI_DbgPrint(DEBUG_IRP, ("Leaving. Status is (0x%X)\n", Status));
|
|
|
|
return STATUS_PENDING;
|
|
}
|
|
|
|
|
|
NTSTATUS DispTdiSendDatagram(
|
|
PIRP Irp)
|
|
/*
|
|
* FUNCTION: TDI_SEND_DATAGRAM handler
|
|
* ARGUMENTS:
|
|
* Irp = Pointer to an I/O request packet
|
|
* RETURNS:
|
|
* Status of operation
|
|
*/
|
|
{
|
|
PIO_STACK_LOCATION IrpSp;
|
|
TDI_REQUEST Request;
|
|
PTDI_REQUEST_KERNEL_SENDDG DgramInfo;
|
|
PTRANSPORT_CONTEXT TranContext;
|
|
NTSTATUS Status;
|
|
|
|
TI_DbgPrint(DEBUG_IRP, ("Called.\n"));
|
|
|
|
IrpSp = IoGetCurrentIrpStackLocation(Irp);
|
|
DgramInfo = (PTDI_REQUEST_KERNEL_SENDDG)&(IrpSp->Parameters);
|
|
|
|
IoMarkIrpPending(Irp);
|
|
|
|
TranContext = IrpSp->FileObject->FsContext;
|
|
if (TranContext == NULL)
|
|
{
|
|
TI_DbgPrint(MID_TRACE, ("Bad transport context.\n"));
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
goto done;
|
|
}
|
|
|
|
/* Initialize a send request */
|
|
Request.Handle.AddressHandle = TranContext->Handle.AddressHandle;
|
|
Request.RequestNotifyObject = DispDataRequestComplete;
|
|
Request.RequestContext = Irp;
|
|
|
|
Status = DispPrepareIrpForCancel(
|
|
IrpSp->FileObject->FsContext,
|
|
Irp,
|
|
(PDRIVER_CANCEL)DispCancelRequest);
|
|
|
|
if (NT_SUCCESS(Status)) {
|
|
PVOID DataBuffer;
|
|
UINT BufferSize;
|
|
|
|
TI_DbgPrint(MID_TRACE,("About to query buffer %x\n", Irp->MdlAddress));
|
|
|
|
NdisQueryBuffer( (PNDIS_BUFFER)Irp->MdlAddress,
|
|
&DataBuffer,
|
|
&BufferSize );
|
|
|
|
/* FIXME: DgramInfo->SendDatagramInformation->RemoteAddress
|
|
must be of type PTDI_ADDRESS_IP */
|
|
TI_DbgPrint(MID_TRACE,
|
|
("About to call send routine %x\n",
|
|
(*((PADDRESS_FILE)Request.Handle.AddressHandle)->Send)));
|
|
|
|
if( (*((PADDRESS_FILE)Request.Handle.AddressHandle)->Send != NULL) )
|
|
{
|
|
ULONG DataUsed = 0;
|
|
Status = (*((PADDRESS_FILE)Request.Handle.AddressHandle)->Send)(
|
|
Request.Handle.AddressHandle,
|
|
DgramInfo->SendDatagramInformation,
|
|
DataBuffer,
|
|
BufferSize,
|
|
&DataUsed);
|
|
Irp->IoStatus.Information = DataUsed;
|
|
}
|
|
else {
|
|
Status = STATUS_UNSUCCESSFUL;
|
|
ASSERT(FALSE);
|
|
}
|
|
}
|
|
|
|
done:
|
|
if (Status != STATUS_PENDING) {
|
|
DispDataRequestComplete(Irp, Status, Irp->IoStatus.Information);
|
|
}
|
|
|
|
TI_DbgPrint(DEBUG_IRP, ("Leaving.\n"));
|
|
|
|
return STATUS_PENDING;
|
|
}
|
|
|
|
|
|
NTSTATUS DispTdiSetEventHandler(PIRP Irp)
|
|
/*
|
|
* FUNCTION: TDI_SET_EVENT_HANDER handler
|
|
* ARGUMENTS:
|
|
* Irp = Pointer to a I/O request packet
|
|
* RETURNS:
|
|
* Status of operation
|
|
*/
|
|
{
|
|
PTDI_REQUEST_KERNEL_SET_EVENT Parameters;
|
|
PTRANSPORT_CONTEXT TranContext;
|
|
PIO_STACK_LOCATION IrpSp;
|
|
PADDRESS_FILE AddrFile;
|
|
NTSTATUS Status;
|
|
|
|
TI_DbgPrint(DEBUG_IRP, ("Called.\n"));
|
|
|
|
IrpSp = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
/* Get associated address file object. Quit if none exists */
|
|
|
|
TranContext = IrpSp->FileObject->FsContext;
|
|
if (!TranContext) {
|
|
TI_DbgPrint(MIN_TRACE, ("Bad transport context.\n"));
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
AddrFile = (PADDRESS_FILE)TranContext->Handle.AddressHandle;
|
|
if (!AddrFile) {
|
|
TI_DbgPrint(MIN_TRACE, ("No address file object.\n"));
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
Parameters = (PTDI_REQUEST_KERNEL_SET_EVENT)&IrpSp->Parameters;
|
|
Status = STATUS_SUCCESS;
|
|
|
|
LockObject(AddrFile);
|
|
|
|
/* Set the event handler. if an event handler is associated with
|
|
a specific event, it's flag (RegisteredXxxHandler) is TRUE.
|
|
If an event handler is not used it's flag is FALSE */
|
|
switch (Parameters->EventType) {
|
|
case TDI_EVENT_CONNECT:
|
|
if (!Parameters->EventHandler) {
|
|
AddrFile->ConnectHandlerContext = NULL;
|
|
AddrFile->RegisteredConnectHandler = FALSE;
|
|
} else {
|
|
AddrFile->ConnectHandler =
|
|
(PTDI_IND_CONNECT)Parameters->EventHandler;
|
|
AddrFile->ConnectHandlerContext = Parameters->EventContext;
|
|
AddrFile->RegisteredConnectHandler = TRUE;
|
|
}
|
|
break;
|
|
|
|
case TDI_EVENT_DISCONNECT:
|
|
if (!Parameters->EventHandler) {
|
|
AddrFile->DisconnectHandlerContext = NULL;
|
|
AddrFile->RegisteredDisconnectHandler = FALSE;
|
|
} else {
|
|
AddrFile->DisconnectHandler =
|
|
(PTDI_IND_DISCONNECT)Parameters->EventHandler;
|
|
AddrFile->DisconnectHandlerContext = Parameters->EventContext;
|
|
AddrFile->RegisteredDisconnectHandler = TRUE;
|
|
}
|
|
break;
|
|
|
|
case TDI_EVENT_ERROR:
|
|
if (Parameters->EventHandler == NULL) {
|
|
AddrFile->ErrorHandlerContext = NULL;
|
|
AddrFile->RegisteredErrorHandler = FALSE;
|
|
} else {
|
|
AddrFile->ErrorHandler =
|
|
(PTDI_IND_ERROR)Parameters->EventHandler;
|
|
AddrFile->ErrorHandlerContext = Parameters->EventContext;
|
|
AddrFile->RegisteredErrorHandler = TRUE;
|
|
}
|
|
break;
|
|
|
|
case TDI_EVENT_RECEIVE:
|
|
if (Parameters->EventHandler == NULL) {
|
|
AddrFile->ReceiveHandlerContext = NULL;
|
|
AddrFile->RegisteredReceiveHandler = FALSE;
|
|
} else {
|
|
AddrFile->ReceiveHandler =
|
|
(PTDI_IND_RECEIVE)Parameters->EventHandler;
|
|
AddrFile->ReceiveHandlerContext = Parameters->EventContext;
|
|
AddrFile->RegisteredReceiveHandler = TRUE;
|
|
}
|
|
break;
|
|
|
|
case TDI_EVENT_RECEIVE_DATAGRAM:
|
|
if (Parameters->EventHandler == NULL) {
|
|
AddrFile->ReceiveDatagramHandlerContext = NULL;
|
|
AddrFile->RegisteredReceiveDatagramHandler = FALSE;
|
|
} else {
|
|
AddrFile->ReceiveDatagramHandler =
|
|
(PTDI_IND_RECEIVE_DATAGRAM)Parameters->EventHandler;
|
|
AddrFile->ReceiveDatagramHandlerContext = Parameters->EventContext;
|
|
AddrFile->RegisteredReceiveDatagramHandler = TRUE;
|
|
}
|
|
break;
|
|
|
|
case TDI_EVENT_RECEIVE_EXPEDITED:
|
|
if (Parameters->EventHandler == NULL) {
|
|
AddrFile->ExpeditedReceiveHandlerContext = NULL;
|
|
AddrFile->RegisteredExpeditedReceiveHandler = FALSE;
|
|
} else {
|
|
AddrFile->ExpeditedReceiveHandler =
|
|
(PTDI_IND_RECEIVE_EXPEDITED)Parameters->EventHandler;
|
|
AddrFile->ExpeditedReceiveHandlerContext = Parameters->EventContext;
|
|
AddrFile->RegisteredExpeditedReceiveHandler = TRUE;
|
|
}
|
|
break;
|
|
|
|
case TDI_EVENT_CHAINED_RECEIVE:
|
|
if (Parameters->EventHandler == NULL) {
|
|
AddrFile->ChainedReceiveHandlerContext = NULL;
|
|
AddrFile->RegisteredChainedReceiveHandler = FALSE;
|
|
} else {
|
|
AddrFile->ChainedReceiveHandler =
|
|
(PTDI_IND_CHAINED_RECEIVE)Parameters->EventHandler;
|
|
AddrFile->ChainedReceiveHandlerContext = Parameters->EventContext;
|
|
AddrFile->RegisteredChainedReceiveHandler = TRUE;
|
|
}
|
|
break;
|
|
|
|
case TDI_EVENT_CHAINED_RECEIVE_DATAGRAM:
|
|
if (Parameters->EventHandler == NULL) {
|
|
AddrFile->ChainedReceiveDatagramHandlerContext = NULL;
|
|
AddrFile->RegisteredChainedReceiveDatagramHandler = FALSE;
|
|
} else {
|
|
AddrFile->ChainedReceiveDatagramHandler =
|
|
(PTDI_IND_CHAINED_RECEIVE_DATAGRAM)Parameters->EventHandler;
|
|
AddrFile->ChainedReceiveDatagramHandlerContext = Parameters->EventContext;
|
|
AddrFile->RegisteredChainedReceiveDatagramHandler = TRUE;
|
|
}
|
|
break;
|
|
|
|
case TDI_EVENT_CHAINED_RECEIVE_EXPEDITED:
|
|
if (Parameters->EventHandler == NULL) {
|
|
AddrFile->ChainedReceiveExpeditedHandlerContext = NULL;
|
|
AddrFile->RegisteredChainedReceiveExpeditedHandler = FALSE;
|
|
} else {
|
|
AddrFile->ChainedReceiveExpeditedHandler =
|
|
(PTDI_IND_CHAINED_RECEIVE_EXPEDITED)Parameters->EventHandler;
|
|
AddrFile->ChainedReceiveExpeditedHandlerContext = Parameters->EventContext;
|
|
AddrFile->RegisteredChainedReceiveExpeditedHandler = TRUE;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
TI_DbgPrint(MIN_TRACE, ("Unknown event type (0x%X).\n",
|
|
Parameters->EventType));
|
|
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
UnlockObject(AddrFile);
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
NTSTATUS DispTdiSetInformation(
|
|
PIRP Irp)
|
|
/*
|
|
* FUNCTION: TDI_SET_INFORMATION handler
|
|
* ARGUMENTS:
|
|
* Irp = Pointer to an I/O request packet
|
|
* RETURNS:
|
|
* Status of operation
|
|
*/
|
|
{
|
|
TI_DbgPrint(DEBUG_IRP, ("Called.\n"));
|
|
|
|
return STATUS_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
|
|
VOID DispTdiQueryInformationExComplete(
|
|
PVOID Context,
|
|
ULONG Status,
|
|
UINT ByteCount)
|
|
/*
|
|
* FUNCTION: Completes a TDI QueryInformationEx request
|
|
* ARGUMENTS:
|
|
* Context = Pointer to the IRP for the request
|
|
* Status = TDI status of the request
|
|
* ByteCount = Number of bytes returned in output buffer
|
|
*/
|
|
{
|
|
PTI_QUERY_CONTEXT QueryContext;
|
|
|
|
QueryContext = (PTI_QUERY_CONTEXT)Context;
|
|
if (NT_SUCCESS(Status)) {
|
|
CopyBufferToBufferChain(
|
|
QueryContext->InputMdl,
|
|
FIELD_OFFSET(TCP_REQUEST_QUERY_INFORMATION_EX, Context),
|
|
(PCHAR)&QueryContext->QueryInfo.Context,
|
|
CONTEXT_SIZE);
|
|
}
|
|
|
|
MmUnlockPages(QueryContext->InputMdl);
|
|
IoFreeMdl(QueryContext->InputMdl);
|
|
if( QueryContext->OutputMdl ) {
|
|
MmUnlockPages(QueryContext->OutputMdl);
|
|
IoFreeMdl(QueryContext->OutputMdl);
|
|
}
|
|
|
|
QueryContext->Irp->IoStatus.Information = ByteCount;
|
|
QueryContext->Irp->IoStatus.Status = Status;
|
|
|
|
ExFreePoolWithTag(QueryContext, QUERY_CONTEXT_TAG);
|
|
}
|
|
|
|
|
|
NTSTATUS DispTdiQueryInformationEx(
|
|
PIRP Irp,
|
|
PIO_STACK_LOCATION IrpSp)
|
|
/*
|
|
* FUNCTION: TDI QueryInformationEx handler
|
|
* ARGUMENTS:
|
|
* Irp = Pointer to I/O request packet
|
|
* IrpSp = Pointer to current stack location of Irp
|
|
* RETURNS:
|
|
* Status of operation
|
|
*/
|
|
{
|
|
PTCP_REQUEST_QUERY_INFORMATION_EX InputBuffer;
|
|
PTRANSPORT_CONTEXT TranContext;
|
|
PTI_QUERY_CONTEXT QueryContext;
|
|
PVOID OutputBuffer;
|
|
TDI_REQUEST Request;
|
|
UINT Size;
|
|
UINT InputBufferLength;
|
|
UINT OutputBufferLength;
|
|
BOOLEAN InputMdlLocked = FALSE;
|
|
BOOLEAN OutputMdlLocked = FALSE;
|
|
PMDL InputMdl = NULL;
|
|
PMDL OutputMdl = NULL;
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
|
|
TI_DbgPrint(DEBUG_IRP, ("Called.\n"));
|
|
|
|
TranContext = (PTRANSPORT_CONTEXT)IrpSp->FileObject->FsContext;
|
|
|
|
switch ((ULONG_PTR)IrpSp->FileObject->FsContext2) {
|
|
case TDI_TRANSPORT_ADDRESS_FILE:
|
|
Request.Handle.AddressHandle = TranContext->Handle.AddressHandle;
|
|
break;
|
|
|
|
case TDI_CONNECTION_FILE:
|
|
Request.Handle.ConnectionContext = TranContext->Handle.ConnectionContext;
|
|
break;
|
|
|
|
case TDI_CONTROL_CHANNEL_FILE:
|
|
Request.Handle.ControlChannel = TranContext->Handle.ControlChannel;
|
|
break;
|
|
|
|
default:
|
|
TI_DbgPrint(MIN_TRACE, ("Invalid transport context\n"));
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
InputBufferLength = IrpSp->Parameters.DeviceIoControl.InputBufferLength;
|
|
OutputBufferLength = IrpSp->Parameters.DeviceIoControl.OutputBufferLength;
|
|
|
|
/* Validate parameters */
|
|
if ((InputBufferLength == sizeof(TCP_REQUEST_QUERY_INFORMATION_EX)) &&
|
|
(OutputBufferLength != 0)) {
|
|
|
|
InputBuffer = (PTCP_REQUEST_QUERY_INFORMATION_EX)
|
|
IrpSp->Parameters.DeviceIoControl.Type3InputBuffer;
|
|
OutputBuffer = Irp->UserBuffer;
|
|
|
|
QueryContext = ExAllocatePoolWithTag(NonPagedPool, sizeof(TI_QUERY_CONTEXT), QUERY_CONTEXT_TAG);
|
|
if (QueryContext) {
|
|
_SEH2_TRY {
|
|
InputMdl = IoAllocateMdl(InputBuffer,
|
|
sizeof(TCP_REQUEST_QUERY_INFORMATION_EX),
|
|
FALSE, TRUE, NULL);
|
|
|
|
OutputMdl = IoAllocateMdl(OutputBuffer,
|
|
OutputBufferLength, FALSE, TRUE, NULL);
|
|
|
|
if (InputMdl && OutputMdl) {
|
|
|
|
MmProbeAndLockPages(InputMdl, Irp->RequestorMode,
|
|
IoModifyAccess);
|
|
|
|
InputMdlLocked = TRUE;
|
|
|
|
MmProbeAndLockPages(OutputMdl, Irp->RequestorMode,
|
|
IoWriteAccess);
|
|
|
|
OutputMdlLocked = TRUE;
|
|
|
|
RtlCopyMemory(&QueryContext->QueryInfo,
|
|
InputBuffer, sizeof(TCP_REQUEST_QUERY_INFORMATION_EX));
|
|
} else
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
} _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
|
|
Status = _SEH2_GetExceptionCode();
|
|
} _SEH2_END;
|
|
|
|
if (NT_SUCCESS(Status)) {
|
|
Size = MmGetMdlByteCount(OutputMdl);
|
|
|
|
QueryContext->Irp = Irp;
|
|
QueryContext->InputMdl = InputMdl;
|
|
QueryContext->OutputMdl = OutputMdl;
|
|
|
|
Request.RequestNotifyObject = DispTdiQueryInformationExComplete;
|
|
Request.RequestContext = QueryContext;
|
|
Status = InfoTdiQueryInformationEx(&Request,
|
|
&QueryContext->QueryInfo.ID, OutputMdl,
|
|
&Size, &QueryContext->QueryInfo.Context);
|
|
DispTdiQueryInformationExComplete(QueryContext, Status, Size);
|
|
|
|
TI_DbgPrint(MAX_TRACE, ("Leaving. Status = (0x%X)\n", Status));
|
|
|
|
return Status;
|
|
}
|
|
|
|
/* An error occurred if we get here */
|
|
|
|
if (InputMdl) {
|
|
if (InputMdlLocked)
|
|
MmUnlockPages(InputMdl);
|
|
IoFreeMdl(InputMdl);
|
|
}
|
|
|
|
if (OutputMdl) {
|
|
if (OutputMdlLocked)
|
|
MmUnlockPages(OutputMdl);
|
|
IoFreeMdl(OutputMdl);
|
|
}
|
|
|
|
ExFreePoolWithTag(QueryContext, QUERY_CONTEXT_TAG);
|
|
} else
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
} else if( InputBufferLength ==
|
|
sizeof(TCP_REQUEST_QUERY_INFORMATION_EX) ) {
|
|
/* Handle the case where the user is probing the buffer for length */
|
|
TI_DbgPrint(MAX_TRACE, ("InputBufferLength %d OutputBufferLength %d\n",
|
|
InputBufferLength, OutputBufferLength));
|
|
InputBuffer = (PTCP_REQUEST_QUERY_INFORMATION_EX)
|
|
IrpSp->Parameters.DeviceIoControl.Type3InputBuffer;
|
|
|
|
Size = 0;
|
|
|
|
QueryContext = ExAllocatePoolWithTag(NonPagedPool, sizeof(TI_QUERY_CONTEXT), QUERY_CONTEXT_TAG);
|
|
if (!QueryContext) return STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
_SEH2_TRY {
|
|
InputMdl = IoAllocateMdl(InputBuffer,
|
|
sizeof(TCP_REQUEST_QUERY_INFORMATION_EX),
|
|
FALSE, TRUE, NULL);
|
|
|
|
MmProbeAndLockPages(InputMdl, Irp->RequestorMode,
|
|
IoModifyAccess);
|
|
|
|
InputMdlLocked = TRUE;
|
|
Status = STATUS_SUCCESS;
|
|
} _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
|
|
TI_DbgPrint(MAX_TRACE, ("Failed to acquire client buffer\n"));
|
|
Status = _SEH2_GetExceptionCode();
|
|
} _SEH2_END;
|
|
|
|
if( !NT_SUCCESS(Status) || !InputMdl ) {
|
|
if( InputMdl ) IoFreeMdl( InputMdl );
|
|
ExFreePoolWithTag(QueryContext, QUERY_CONTEXT_TAG);
|
|
return Status;
|
|
}
|
|
|
|
RtlCopyMemory(&QueryContext->QueryInfo,
|
|
InputBuffer, sizeof(TCP_REQUEST_QUERY_INFORMATION_EX));
|
|
|
|
QueryContext->Irp = Irp;
|
|
QueryContext->InputMdl = InputMdl;
|
|
QueryContext->OutputMdl = NULL;
|
|
|
|
Request.RequestNotifyObject = DispTdiQueryInformationExComplete;
|
|
Request.RequestContext = QueryContext;
|
|
Status = InfoTdiQueryInformationEx(&Request,
|
|
&QueryContext->QueryInfo.ID,
|
|
NULL,
|
|
&Size,
|
|
&QueryContext->QueryInfo.Context);
|
|
DispTdiQueryInformationExComplete(QueryContext, Status, Size);
|
|
TI_DbgPrint(MAX_TRACE, ("Leaving. Status = (0x%X)\n", Status));
|
|
} else Status = STATUS_INVALID_PARAMETER;
|
|
|
|
TI_DbgPrint(MIN_TRACE, ("Leaving. Status = (0x%X)\n", Status));
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
NTSTATUS DispTdiSetInformationEx(
|
|
PIRP Irp,
|
|
PIO_STACK_LOCATION IrpSp)
|
|
/*
|
|
* FUNCTION: TDI SetInformationEx handler
|
|
* ARGUMENTS:
|
|
* Irp = Pointer to I/O request packet
|
|
* IrpSp = Pointer to current stack location of Irp
|
|
* RETURNS:
|
|
* Status of operation
|
|
*/
|
|
{
|
|
PTRANSPORT_CONTEXT TranContext;
|
|
PTCP_REQUEST_SET_INFORMATION_EX Info;
|
|
TDI_REQUEST Request;
|
|
TDI_STATUS Status;
|
|
|
|
TI_DbgPrint(DEBUG_IRP, ("Called.\n"));
|
|
|
|
TranContext = (PTRANSPORT_CONTEXT)IrpSp->FileObject->FsContext;
|
|
Info = (PTCP_REQUEST_SET_INFORMATION_EX)Irp->AssociatedIrp.SystemBuffer;
|
|
|
|
switch ((ULONG_PTR)IrpSp->FileObject->FsContext2) {
|
|
case TDI_TRANSPORT_ADDRESS_FILE:
|
|
Request.Handle.AddressHandle = TranContext->Handle.AddressHandle;
|
|
break;
|
|
|
|
case TDI_CONNECTION_FILE:
|
|
Request.Handle.ConnectionContext = TranContext->Handle.ConnectionContext;
|
|
break;
|
|
|
|
case TDI_CONTROL_CHANNEL_FILE:
|
|
Request.Handle.ControlChannel = TranContext->Handle.ControlChannel;
|
|
break;
|
|
|
|
default:
|
|
Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
|
|
Irp->IoStatus.Information = 0;
|
|
|
|
TI_DbgPrint(DEBUG_IRP, ("Completing IRP at (0x%X).\n", Irp));
|
|
|
|
return Irp->IoStatus.Status;
|
|
}
|
|
|
|
Request.RequestNotifyObject = NULL;
|
|
Request.RequestContext = NULL;
|
|
|
|
Status = InfoTdiSetInformationEx(&Request, &Info->ID,
|
|
&Info->Buffer, Info->BufferSize);
|
|
|
|
return Status;
|
|
}
|
|
|
|
/* TODO: Support multiple addresses per interface.
|
|
* For now just set the nte context to the interface index.
|
|
*
|
|
* Later on, create an NTE context and NTE instance
|
|
*/
|
|
|
|
NTSTATUS DispTdiSetIPAddress( PIRP Irp, PIO_STACK_LOCATION IrpSp ) {
|
|
NTSTATUS Status = STATUS_DEVICE_DOES_NOT_EXIST;
|
|
PIP_SET_ADDRESS IpAddrChange =
|
|
(PIP_SET_ADDRESS)Irp->AssociatedIrp.SystemBuffer;
|
|
IF_LIST_ITER(IF);
|
|
|
|
TI_DbgPrint(MID_TRACE,("Setting IP Address for adapter %d\n",
|
|
IpAddrChange->NteIndex));
|
|
|
|
ForEachInterface(IF) {
|
|
TI_DbgPrint(MID_TRACE,("Looking at adapter %d\n", IF->Index));
|
|
|
|
if( IF->Unicast.Address.IPv4Address == IpAddrChange->Address ) {
|
|
Status = STATUS_DUPLICATE_OBJECTID;
|
|
break;
|
|
}
|
|
if( IF->Index == IpAddrChange->NteIndex ) {
|
|
IPRemoveInterfaceRoute( IF );
|
|
|
|
IF->Unicast.Type = IP_ADDRESS_V4;
|
|
IF->Unicast.Address.IPv4Address = IpAddrChange->Address;
|
|
|
|
IF->Netmask.Type = IP_ADDRESS_V4;
|
|
IF->Netmask.Address.IPv4Address = IpAddrChange->Netmask;
|
|
|
|
IF->Broadcast.Type = IP_ADDRESS_V4;
|
|
IF->Broadcast.Address.IPv4Address =
|
|
IF->Unicast.Address.IPv4Address |
|
|
~IF->Netmask.Address.IPv4Address;
|
|
|
|
TI_DbgPrint(MID_TRACE,("New Unicast Address: %x\n",
|
|
IF->Unicast.Address.IPv4Address));
|
|
TI_DbgPrint(MID_TRACE,("New Netmask : %x\n",
|
|
IF->Netmask.Address.IPv4Address));
|
|
|
|
IPAddInterfaceRoute( IF );
|
|
|
|
IpAddrChange->Address = IF->Index;
|
|
Status = STATUS_SUCCESS;
|
|
Irp->IoStatus.Information = IF->Index;
|
|
break;
|
|
}
|
|
} EndFor(IF);
|
|
|
|
Irp->IoStatus.Status = Status;
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS DispTdiDeleteIPAddress( PIRP Irp, PIO_STACK_LOCATION IrpSp ) {
|
|
NTSTATUS Status = STATUS_UNSUCCESSFUL;
|
|
PUSHORT NteIndex = Irp->AssociatedIrp.SystemBuffer;
|
|
IF_LIST_ITER(IF);
|
|
|
|
ForEachInterface(IF) {
|
|
if( IF->Index == *NteIndex ) {
|
|
IPRemoveInterfaceRoute( IF );
|
|
IF->Unicast.Type = IP_ADDRESS_V4;
|
|
IF->Unicast.Address.IPv4Address = 0;
|
|
|
|
IF->Netmask.Type = IP_ADDRESS_V4;
|
|
IF->Netmask.Address.IPv4Address = 0;
|
|
|
|
IF->Broadcast.Type = IP_ADDRESS_V4;
|
|
IF->Broadcast.Address.IPv4Address = 0;
|
|
|
|
Status = STATUS_SUCCESS;
|
|
}
|
|
} EndFor(IF);
|
|
|
|
Irp->IoStatus.Status = Status;
|
|
return Status;
|
|
}
|
|
|
|
VOID NTAPI
|
|
WaitForHwAddress ( PDEVICE_OBJECT DeviceObject, PVOID Context) {
|
|
PQUERY_HW_WORK_ITEM WorkItem = (PQUERY_HW_WORK_ITEM)Context;
|
|
LARGE_INTEGER Now;
|
|
LARGE_INTEGER Wait;
|
|
IP_ADDRESS Remote;
|
|
PIRP Irp;
|
|
PNEIGHBOR_CACHE_ENTRY NCE = NULL;
|
|
NTSTATUS Status = STATUS_UNSUCCESSFUL;
|
|
|
|
IoFreeWorkItem(WorkItem->WorkItem);
|
|
Irp = WorkItem->Irp;
|
|
AddrInitIPv4(&Remote, WorkItem->RemoteIP);
|
|
KeQuerySystemTime(&Now);
|
|
while (Now.QuadPart - WorkItem->StartTime.QuadPart < 10000 * 1000 && !Irp->Cancel) {
|
|
NCE = NBLocateNeighbor(&Remote, WorkItem->Interface);
|
|
if (NCE && !(NCE->State & NUD_INCOMPLETE)) {
|
|
break;
|
|
}
|
|
|
|
NCE = NULL;
|
|
Wait.QuadPart = -10000;
|
|
KeDelayExecutionThread(KernelMode, FALSE, &Wait);
|
|
KeQuerySystemTime(&Now);
|
|
}
|
|
|
|
if (NCE) {
|
|
PVOID OutputBuffer;
|
|
|
|
if (NCE->LinkAddressLength > WorkItem->IrpSp->Parameters.DeviceIoControl.OutputBufferLength) {
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
} else {
|
|
OutputBuffer = Irp->AssociatedIrp.SystemBuffer;
|
|
RtlCopyMemory(OutputBuffer, NCE->LinkAddress, NCE->LinkAddressLength);
|
|
Irp->IoStatus.Information = NCE->LinkAddressLength;
|
|
Status = STATUS_SUCCESS;
|
|
}
|
|
}
|
|
|
|
ExFreePoolWithTag(WorkItem, QUERY_CONTEXT_TAG);
|
|
if (Irp->Flags & IRP_SYNCHRONOUS_API) {
|
|
Irp->IoStatus.Status = Status;
|
|
} else {
|
|
IRPFinish(Irp, Status);
|
|
}
|
|
}
|
|
|
|
NTSTATUS DispTdiQueryIpHwAddress( PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp ) {
|
|
NTSTATUS Status;
|
|
PULONG IPs;
|
|
IP_ADDRESS Remote, Local;
|
|
PNEIGHBOR_CACHE_ENTRY NCE;
|
|
PIP_INTERFACE Interface;
|
|
PQUERY_HW_WORK_ITEM WorkItem;
|
|
|
|
Irp->IoStatus.Information = 0;
|
|
|
|
if (IrpSp->Parameters.DeviceIoControl.InputBufferLength < 2 * sizeof(ULONG) ||
|
|
IrpSp->Parameters.DeviceIoControl.OutputBufferLength == 0) {
|
|
Status = STATUS_INVALID_BUFFER_SIZE;
|
|
goto Exit;
|
|
}
|
|
|
|
IPs = (PULONG)Irp->AssociatedIrp.SystemBuffer;
|
|
AddrInitIPv4(&Remote, IPs[0]);
|
|
AddrInitIPv4(&Local, IPs[1]);
|
|
|
|
if (AddrIsUnspecified(&Remote)) {
|
|
Status = STATUS_UNSUCCESSFUL;
|
|
goto Exit;
|
|
}
|
|
|
|
Interface = AddrLocateInterface(&Remote);
|
|
if (Interface) {
|
|
PVOID OutputBuffer;
|
|
|
|
if (Interface->AddressLength > IrpSp->Parameters.DeviceIoControl.OutputBufferLength) {
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto Exit;
|
|
}
|
|
|
|
OutputBuffer = Irp->AssociatedIrp.SystemBuffer;
|
|
RtlCopyMemory(OutputBuffer, Interface->Address, Interface->AddressLength);
|
|
Irp->IoStatus.Information = Interface->AddressLength;
|
|
Status = STATUS_SUCCESS;
|
|
goto Exit;
|
|
}
|
|
|
|
if (AddrIsUnspecified(&Local)) {
|
|
NCE = RouteGetRouteToDestination(&Remote);
|
|
if (NCE == NULL) {
|
|
Status = STATUS_NETWORK_UNREACHABLE;
|
|
goto Exit;
|
|
}
|
|
|
|
Interface = NCE->Interface;
|
|
}
|
|
else {
|
|
Interface = AddrLocateInterface(&Local);
|
|
if (Interface == NULL) {
|
|
Interface = GetDefaultInterface();
|
|
if (Interface == NULL) {
|
|
Status = STATUS_NETWORK_UNREACHABLE;
|
|
goto Exit;
|
|
}
|
|
}
|
|
}
|
|
|
|
WorkItem = ExAllocatePoolWithTag(PagedPool, sizeof(QUERY_HW_WORK_ITEM), QUERY_CONTEXT_TAG);
|
|
if (WorkItem == NULL) {
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto Exit;
|
|
}
|
|
|
|
WorkItem->WorkItem = IoAllocateWorkItem(DeviceObject);
|
|
if (WorkItem->WorkItem == NULL) {
|
|
ExFreePoolWithTag(WorkItem, QUERY_CONTEXT_TAG);
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto Exit;
|
|
}
|
|
|
|
WorkItem->Irp = Irp;
|
|
WorkItem->IrpSp = IrpSp;
|
|
WorkItem->Interface = Interface;
|
|
WorkItem->RemoteIP = IPs[0];
|
|
KeQuerySystemTime(&WorkItem->StartTime);
|
|
|
|
NCE = NBLocateNeighbor(&Remote, Interface);
|
|
if (NCE != NULL) {
|
|
if (NCE->LinkAddressLength > IrpSp->Parameters.DeviceIoControl.OutputBufferLength) {
|
|
IoFreeWorkItem(WorkItem->WorkItem);
|
|
ExFreePoolWithTag(WorkItem, QUERY_CONTEXT_TAG);
|
|
Status = STATUS_INVALID_BUFFER_SIZE;
|
|
goto Exit;
|
|
}
|
|
|
|
if (!(NCE->State & NUD_INCOMPLETE)) {
|
|
PVOID LinkAddress = ExAllocatePoolWithTag(PagedPool, NCE->LinkAddressLength, QUERY_CONTEXT_TAG);
|
|
if (LinkAddress == NULL) {
|
|
IoFreeWorkItem(WorkItem->WorkItem);
|
|
ExFreePoolWithTag(WorkItem, QUERY_CONTEXT_TAG);
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto Exit;
|
|
}
|
|
memset(LinkAddress, 0xff, NCE->LinkAddressLength);
|
|
NBUpdateNeighbor(NCE, LinkAddress, NUD_INCOMPLETE);
|
|
ExFreePoolWithTag(LinkAddress, QUERY_CONTEXT_TAG);
|
|
}
|
|
}
|
|
|
|
if (!ARPTransmit(&Remote, NULL, Interface)) {
|
|
IoFreeWorkItem(WorkItem->WorkItem);
|
|
ExFreePoolWithTag(WorkItem, QUERY_CONTEXT_TAG);
|
|
Status = STATUS_UNSUCCESSFUL;
|
|
goto Exit;
|
|
}
|
|
|
|
if (Irp->Flags & IRP_SYNCHRONOUS_API) {
|
|
WaitForHwAddress(DeviceObject, WorkItem);
|
|
Status = Irp->IoStatus.Status;
|
|
} else {
|
|
IoMarkIrpPending(Irp);
|
|
IoQueueWorkItem(WorkItem->WorkItem, WaitForHwAddress, DelayedWorkQueue, WorkItem);
|
|
Status = STATUS_PENDING;
|
|
}
|
|
|
|
Exit:
|
|
return Status;
|
|
}
|
|
|
|
/* EOF */
|