321 lines
8.1 KiB
C
321 lines
8.1 KiB
C
|
/*++
|
|||
|
|
|||
|
Copyright (c) 1989, 1990, 1991 Microsoft Corporation
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
rcv.c
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
This module contains code which performs the following TDI services:
|
|||
|
|
|||
|
o TdiReceive
|
|||
|
o TdiReceiveDatagram
|
|||
|
|
|||
|
Author:
|
|||
|
|
|||
|
David Beaver (dbeaver) 1-July-1991
|
|||
|
|
|||
|
Environment:
|
|||
|
|
|||
|
Kernel mode
|
|||
|
|
|||
|
Revision History:
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
#include "precomp.h"
|
|||
|
#pragma hdrstop
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
NbfTdiReceive(
|
|||
|
IN PIRP Irp
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine performs the TdiReceive request for the transport provider.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Irp - I/O Request Packet for this request.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NTSTATUS - status of operation.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
NTSTATUS status;
|
|||
|
PTP_CONNECTION connection;
|
|||
|
KIRQL oldirql;
|
|||
|
PIO_STACK_LOCATION irpSp;
|
|||
|
|
|||
|
//
|
|||
|
// verify that the operation is taking place on a connection. At the same
|
|||
|
// time we do this, we reference the connection. This ensures it does not
|
|||
|
// get removed out from under us. Note also that we do the connection
|
|||
|
// lookup within a try/except clause, thus protecting ourselves against
|
|||
|
// really bogus handles
|
|||
|
//
|
|||
|
|
|||
|
irpSp = IoGetCurrentIrpStackLocation (Irp);
|
|||
|
connection = irpSp->FileObject->FsContext;
|
|||
|
|
|||
|
IF_NBFDBG (NBF_DEBUG_RCVENG) {
|
|||
|
NbfPrint2 ("NbfTdiReceive: Received IRP %lx on connection %lx\n",
|
|||
|
Irp, connection);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Check that this is really a connection.
|
|||
|
//
|
|||
|
|
|||
|
if ((irpSp->FileObject->FsContext2 == UlongToPtr(NBF_FILE_TYPE_CONTROL)) ||
|
|||
|
(connection->Size != sizeof (TP_CONNECTION)) ||
|
|||
|
(connection->Type != NBF_CONNECTION_SIGNATURE)) {
|
|||
|
#if DBG
|
|||
|
NbfPrint2 ("TdiReceive: Invalid Connection %lx Irp %lx\n", connection, Irp);
|
|||
|
#endif
|
|||
|
return STATUS_INVALID_CONNECTION;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Initialize bytes transferred here.
|
|||
|
//
|
|||
|
|
|||
|
Irp->IoStatus.Information = 0; // reset byte transfer count.
|
|||
|
|
|||
|
// This reference is removed by NbfDestroyRequest.
|
|||
|
|
|||
|
KeRaiseIrql (DISPATCH_LEVEL, &oldirql);
|
|||
|
|
|||
|
ACQUIRE_DPC_C_SPIN_LOCK (&connection->SpinLock);
|
|||
|
|
|||
|
if ((connection->Flags & CONNECTION_FLAGS_READY) == 0) {
|
|||
|
|
|||
|
RELEASE_DPC_C_SPIN_LOCK (&connection->SpinLock);
|
|||
|
|
|||
|
Irp->IoStatus.Status = connection->Status;
|
|||
|
IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
|
|||
|
|
|||
|
status = STATUS_PENDING;
|
|||
|
|
|||
|
} else {
|
|||
|
KIRQL cancelIrql;
|
|||
|
|
|||
|
//
|
|||
|
// Once the reference is in, LinkSpinLock will be valid.
|
|||
|
//
|
|||
|
|
|||
|
NbfReferenceConnection("TdiReceive request", connection, CREF_RECEIVE_IRP);
|
|||
|
RELEASE_DPC_C_SPIN_LOCK (&connection->SpinLock);
|
|||
|
|
|||
|
IoAcquireCancelSpinLock(&cancelIrql);
|
|||
|
ACQUIRE_DPC_SPIN_LOCK (connection->LinkSpinLock);
|
|||
|
|
|||
|
IRP_RECEIVE_IRP(irpSp) = Irp;
|
|||
|
IRP_RECEIVE_REFCOUNT(irpSp) = 1;
|
|||
|
|
|||
|
#if DBG
|
|||
|
NbfReceives[NbfReceivesNext].Irp = Irp;
|
|||
|
NbfReceives[NbfReceivesNext].Request = NULL;
|
|||
|
NbfReceives[NbfReceivesNext].Connection = (PVOID)connection;
|
|||
|
NbfReceivesNext = (NbfReceivesNext++) % TRACK_TDI_LIMIT;
|
|||
|
#endif
|
|||
|
|
|||
|
//
|
|||
|
// If this IRP has been cancelled, complete it now.
|
|||
|
//
|
|||
|
|
|||
|
if (Irp->Cancel) {
|
|||
|
|
|||
|
#if DBG
|
|||
|
NbfCompletedReceives[NbfCompletedReceivesNext].Irp = Irp;
|
|||
|
NbfCompletedReceives[NbfCompletedReceivesNext].Request = NULL;
|
|||
|
NbfCompletedReceives[NbfCompletedReceivesNext].Status = STATUS_CANCELLED;
|
|||
|
{
|
|||
|
ULONG i,j,k;
|
|||
|
PUCHAR va;
|
|||
|
PMDL mdl;
|
|||
|
|
|||
|
mdl = Irp->MdlAddress;
|
|||
|
|
|||
|
NbfCompletedReceives[NbfCompletedReceivesNext].Contents[0] = (UCHAR)0;
|
|||
|
|
|||
|
i = 1;
|
|||
|
while (i<TRACK_TDI_CAPTURE) {
|
|||
|
if (mdl == NULL) break;
|
|||
|
va = MmGetSystemAddressForMdl (mdl);
|
|||
|
j = MmGetMdlByteCount (mdl);
|
|||
|
|
|||
|
for (i=i,k=0;(i<TRACK_TDI_CAPTURE)&&(k<j);i++,k++) {
|
|||
|
NbfCompletedReceives[NbfCompletedReceivesNext].Contents[i] = *va++;
|
|||
|
}
|
|||
|
mdl = mdl->Next;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
NbfCompletedReceivesNext = (NbfCompletedReceivesNext++) % TRACK_TDI_LIMIT;
|
|||
|
#endif
|
|||
|
|
|||
|
//
|
|||
|
// It is safe to do this with locks held.
|
|||
|
//
|
|||
|
NbfCompleteReceiveIrp (Irp, STATUS_CANCELLED, 0);
|
|||
|
|
|||
|
RELEASE_DPC_SPIN_LOCK (connection->LinkSpinLock);
|
|||
|
IoReleaseCancelSpinLock(cancelIrql);
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
//
|
|||
|
// Insert onto the receive queue, and make the IRP
|
|||
|
// cancellable.
|
|||
|
//
|
|||
|
|
|||
|
InsertTailList (&connection->ReceiveQueue,&Irp->Tail.Overlay.ListEntry);
|
|||
|
IoSetCancelRoutine(Irp, NbfCancelReceive);
|
|||
|
|
|||
|
//
|
|||
|
// Release the cancel spinlock out of order. Since we were
|
|||
|
// already at dpc level when it was acquired, we don't
|
|||
|
// need to swap irqls.
|
|||
|
//
|
|||
|
ASSERT(cancelIrql == DISPATCH_LEVEL);
|
|||
|
IoReleaseCancelSpinLock(cancelIrql);
|
|||
|
|
|||
|
//
|
|||
|
// This call releases the link spinlock, and references the
|
|||
|
// connection first if it needs to access it after
|
|||
|
// releasing the lock.
|
|||
|
//
|
|||
|
|
|||
|
AwakenReceive (connection); // awaken if sleeping.
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
status = STATUS_PENDING;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
KeLowerIrql (oldirql);
|
|||
|
|
|||
|
return status;
|
|||
|
} /* TdiReceive */
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
NbfTdiReceiveDatagram(
|
|||
|
IN PIRP Irp
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine performs the TdiReceiveDatagram request for the transport
|
|||
|
provider. Receive datagrams just get queued up to an address, and are
|
|||
|
completed when a DATAGRAM or DATAGRAM_BROADCAST frame is received at
|
|||
|
the address.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Irp - I/O Request Packet for this request.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NTSTATUS - status of operation.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
NTSTATUS status;
|
|||
|
KIRQL oldirql;
|
|||
|
PTP_ADDRESS address;
|
|||
|
PTP_ADDRESS_FILE addressFile;
|
|||
|
PIO_STACK_LOCATION irpSp;
|
|||
|
KIRQL cancelIrql;
|
|||
|
|
|||
|
//
|
|||
|
// verify that the operation is taking place on an address. At the same
|
|||
|
// time we do this, we reference the address. This ensures it does not
|
|||
|
// get removed out from under us. Note also that we do the address
|
|||
|
// lookup within a try/except clause, thus protecting ourselves against
|
|||
|
// really bogus handles
|
|||
|
//
|
|||
|
|
|||
|
irpSp = IoGetCurrentIrpStackLocation (Irp);
|
|||
|
|
|||
|
if (irpSp->FileObject->FsContext2 != (PVOID) TDI_TRANSPORT_ADDRESS_FILE) {
|
|||
|
return STATUS_INVALID_ADDRESS;
|
|||
|
}
|
|||
|
|
|||
|
addressFile = irpSp->FileObject->FsContext;
|
|||
|
|
|||
|
status = NbfVerifyAddressObject (addressFile);
|
|||
|
|
|||
|
if (!NT_SUCCESS (status)) {
|
|||
|
return status;
|
|||
|
}
|
|||
|
|
|||
|
#if DBG
|
|||
|
if (((PTDI_REQUEST_KERNEL_RECEIVEDG)(&irpSp->Parameters))->ReceiveLength > 0) {
|
|||
|
ASSERT (Irp->MdlAddress != NULL);
|
|||
|
}
|
|||
|
#endif
|
|||
|
|
|||
|
address = addressFile->Address;
|
|||
|
|
|||
|
IoAcquireCancelSpinLock(&cancelIrql);
|
|||
|
ACQUIRE_SPIN_LOCK (&address->SpinLock,&oldirql);
|
|||
|
|
|||
|
if ((address->Flags & (ADDRESS_FLAGS_STOPPING | ADDRESS_FLAGS_CONFLICT)) != 0) {
|
|||
|
|
|||
|
RELEASE_SPIN_LOCK (&address->SpinLock,oldirql);
|
|||
|
IoReleaseCancelSpinLock(cancelIrql);
|
|||
|
|
|||
|
Irp->IoStatus.Information = 0;
|
|||
|
Irp->IoStatus.Status = (address->Flags & ADDRESS_FLAGS_STOPPING) ?
|
|||
|
STATUS_NETWORK_NAME_DELETED : STATUS_DUPLICATE_NAME;
|
|||
|
IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
//
|
|||
|
// If this IRP has been cancelled, then call the
|
|||
|
// cancel routine.
|
|||
|
//
|
|||
|
|
|||
|
if (Irp->Cancel) {
|
|||
|
|
|||
|
RELEASE_SPIN_LOCK (&address->SpinLock, oldirql);
|
|||
|
IoReleaseCancelSpinLock(cancelIrql);
|
|||
|
|
|||
|
Irp->IoStatus.Information = 0;
|
|||
|
Irp->IoStatus.Status = STATUS_CANCELLED;
|
|||
|
IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
IoSetCancelRoutine(Irp, NbfCancelReceiveDatagram);
|
|||
|
NbfReferenceAddress ("Receive datagram", address, AREF_REQUEST);
|
|||
|
InsertTailList (&addressFile->ReceiveDatagramQueue,&Irp->Tail.Overlay.ListEntry);
|
|||
|
RELEASE_SPIN_LOCK (&address->SpinLock,oldirql);
|
|||
|
IoReleaseCancelSpinLock(cancelIrql);
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
NbfDereferenceAddress ("Temp rcv datagram", address, AREF_VERIFY);
|
|||
|
|
|||
|
return STATUS_PENDING;
|
|||
|
|
|||
|
} /* TdiReceiveDatagram */
|
|||
|
|