517 lines
13 KiB
C
517 lines
13 KiB
C
|
/*++
|
|||
|
|
|||
|
Copyright (c) 1989-1993 Microsoft Corporation
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
receive.c
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
This module contains code which performs the following TDI services:
|
|||
|
|
|||
|
o TdiReceiveDatagram
|
|||
|
|
|||
|
Environment:
|
|||
|
|
|||
|
Kernel mode
|
|||
|
|
|||
|
Revision History:
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
#include "precomp.h"
|
|||
|
#pragma hdrstop
|
|||
|
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
IpxTransferDataComplete(
|
|||
|
IN NDIS_HANDLE BindingContext,
|
|||
|
IN PNDIS_PACKET NdisPacket,
|
|||
|
IN NDIS_STATUS NdisStatus,
|
|||
|
IN UINT BytesTransferred
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine receives control from the physical provider as an
|
|||
|
indication that an NdisTransferData has completed. We use this indication
|
|||
|
to complete any pended requests to our clients.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
BindingContext - The Adapter Binding specified at initialization time.
|
|||
|
|
|||
|
NdisPacket/RequestHandle - An identifier for the request that completed.
|
|||
|
|
|||
|
NdisStatus - The completion status for the request.
|
|||
|
|
|||
|
BytesTransferred - Number of bytes actually transferred.
|
|||
|
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PADAPTER Adapter = (PADAPTER)BindingContext;
|
|||
|
PIPX_RECEIVE_RESERVED Reserved = (PIPX_RECEIVE_RESERVED)(NdisPacket->ProtocolReserved);
|
|||
|
PREQUEST Request, LastRequest;
|
|||
|
PADDRESS_FILE AddressFile;
|
|||
|
ULONG ByteOffset;
|
|||
|
PLIST_ENTRY p;
|
|||
|
PDEVICE Device;
|
|||
|
|
|||
|
|
|||
|
switch (Reserved->Identifier) {
|
|||
|
|
|||
|
case IDENTIFIER_IPX:
|
|||
|
|
|||
|
if (!Reserved->pContext) {
|
|||
|
|
|||
|
if (Reserved->SingleRequest) {
|
|||
|
|
|||
|
//
|
|||
|
// The transfer was directly into the client buffer,
|
|||
|
// so simply complete the request.
|
|||
|
//
|
|||
|
|
|||
|
Request = Reserved->SingleRequest;
|
|||
|
|
|||
|
if (NdisStatus == NDIS_STATUS_SUCCESS) {
|
|||
|
|
|||
|
IPX_DEBUG (RECEIVE, ("Transferred %d bytes\n", BytesTransferred));
|
|||
|
REQUEST_INFORMATION(Request) = BytesTransferred;
|
|||
|
REQUEST_STATUS(Request) = STATUS_SUCCESS;
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
IPX_DEBUG (RECEIVE, ("Transfer failed\n"));
|
|||
|
REQUEST_INFORMATION(Request) = 0;
|
|||
|
REQUEST_STATUS(Request) = STATUS_ADAPTER_HARDWARE_ERROR;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
LastRequest = Request;
|
|||
|
Reserved->SingleRequest = NULL;
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
//
|
|||
|
// Multiple clients requested this datagram. Save
|
|||
|
// the last one to delay queueing it for completion.
|
|||
|
//
|
|||
|
|
|||
|
LastRequest = LIST_ENTRY_TO_REQUEST (Reserved->Requests.Blink);
|
|||
|
|
|||
|
while (TRUE) {
|
|||
|
|
|||
|
p = RemoveHeadList (&Reserved->Requests);
|
|||
|
if (p == &Reserved->Requests) {
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
Request = LIST_ENTRY_TO_REQUEST(p);
|
|||
|
AddressFile = REQUEST_OPEN_CONTEXT(Request);
|
|||
|
|
|||
|
if (AddressFile->ReceiveIpxHeader) {
|
|||
|
ByteOffset = 0;
|
|||
|
} else {
|
|||
|
ByteOffset = sizeof(IPX_HEADER);
|
|||
|
}
|
|||
|
|
|||
|
if (NdisStatus == NDIS_STATUS_SUCCESS) {
|
|||
|
UINT BytesToTransfer = ((PTDI_REQUEST_KERNEL_RECEIVEDG)(REQUEST_PARAMETERS(Request)))->ReceiveLength;
|
|||
|
|
|||
|
if (BytesToTransfer == 0) {
|
|||
|
BytesToTransfer= IpxGetChainedMDLLength(REQUEST_NDIS_BUFFER(Request));
|
|||
|
}
|
|||
|
#ifdef SUNDOWN
|
|||
|
// assume offset will not exceed 2^32.
|
|||
|
// REQUEST_INFORMATION(Request) is a ULONG_PTR
|
|||
|
// we are save to cast its address to PULONG.
|
|||
|
|
|||
|
REQUEST_STATUS(Request) =
|
|||
|
TdiCopyBufferToMdl(
|
|||
|
Reserved->ReceiveBuffer->Data,
|
|||
|
(ULONG) (ByteOffset + REQUEST_INFORMATION(Request)),
|
|||
|
BytesToTransfer,
|
|||
|
REQUEST_NDIS_BUFFER(Request),
|
|||
|
0,
|
|||
|
(PULONG) &REQUEST_INFORMATION(Request));
|
|||
|
|
|||
|
#else
|
|||
|
|
|||
|
REQUEST_STATUS(Request) =
|
|||
|
TdiCopyBufferToMdl(
|
|||
|
Reserved->ReceiveBuffer->Data,
|
|||
|
ByteOffset + REQUEST_INFORMATION(Request),
|
|||
|
BytesToTransfer,
|
|||
|
REQUEST_NDIS_BUFFER(Request),
|
|||
|
0,
|
|||
|
&REQUEST_INFORMATION(Request));
|
|||
|
|
|||
|
#endif
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
REQUEST_INFORMATION(Request) = 0;
|
|||
|
REQUEST_STATUS(Request) = STATUS_ADAPTER_HARDWARE_ERROR;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
if (Request != LastRequest) {
|
|||
|
|
|||
|
IPX_INSERT_TAIL_LIST(
|
|||
|
&Adapter->RequestCompletionQueue,
|
|||
|
REQUEST_LINKAGE(Request),
|
|||
|
Adapter->DeviceLock);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Now free the receive buffer back.
|
|||
|
//
|
|||
|
|
|||
|
IPX_PUSH_ENTRY_LIST(
|
|||
|
&Adapter->ReceiveBufferList,
|
|||
|
&Reserved->ReceiveBuffer->PoolLinkage,
|
|||
|
&Adapter->Device->SListsLock);
|
|||
|
|
|||
|
Reserved->ReceiveBuffer = NULL;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
} else {
|
|||
|
//IpxPrint0("IpxTransferDataComplete: Calling PassDgToRt\n");
|
|||
|
//ByteOffset = sizeof(IPX_HEADER);
|
|||
|
ByteOffset = 0;
|
|||
|
PassDgToRt(IpxDevice, Reserved->pContext, Reserved->Index,
|
|||
|
&Reserved->ReceiveBuffer->Data[ByteOffset],
|
|||
|
BytesTransferred);
|
|||
|
|
|||
|
//
|
|||
|
// Free the memory allocated for options.
|
|||
|
//
|
|||
|
IpxFreeMemory(Reserved->pContext, sizeof(IPX_DATAGRAM_OPTIONS2),
|
|||
|
MEMORY_PACKET, "RT OPTIONS");
|
|||
|
//
|
|||
|
// Now free the receive buffer back.
|
|||
|
//
|
|||
|
|
|||
|
IPX_PUSH_ENTRY_LIST(
|
|||
|
&Adapter->ReceiveBufferList,
|
|||
|
&Reserved->ReceiveBuffer->PoolLinkage,
|
|||
|
Adapter->DeviceLock);
|
|||
|
|
|||
|
Reserved->ReceiveBuffer = NULL;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Now free the packet.
|
|||
|
//
|
|||
|
|
|||
|
NdisReinitializePacket (NdisPacket);
|
|||
|
|
|||
|
if (Reserved->OwnedByAddress) {
|
|||
|
|
|||
|
// Reserved->Address->ReceivePacketInUse = FALSE;
|
|||
|
InterlockedDecrement(&Reserved->Address->ReceivePacketInUse);
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
Device = Adapter->Device;
|
|||
|
|
|||
|
IPX_PUSH_ENTRY_LIST(
|
|||
|
&Device->ReceivePacketList,
|
|||
|
&Reserved->PoolLinkage,
|
|||
|
&Device->SListsLock);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
if (!Reserved->pContext) {
|
|||
|
//
|
|||
|
// We Delay inserting the last request (or the only one)
|
|||
|
// until after we have put the packet back, to keep the
|
|||
|
// address around if needed (the address won't go away
|
|||
|
// until the last address file does, and the address file
|
|||
|
// won't go away until the datagram is completed).
|
|||
|
//
|
|||
|
|
|||
|
IPX_INSERT_TAIL_LIST(
|
|||
|
&Adapter->RequestCompletionQueue,
|
|||
|
REQUEST_LINKAGE(LastRequest),
|
|||
|
Adapter->DeviceLock);
|
|||
|
}
|
|||
|
|
|||
|
IpxReceiveComplete ((NDIS_HANDLE)Adapter);
|
|||
|
|
|||
|
break;
|
|||
|
|
|||
|
default:
|
|||
|
|
|||
|
Device = Adapter->Device;
|
|||
|
|
|||
|
(*Device->UpperDrivers[Reserved->Identifier].TransferDataCompleteHandler)(
|
|||
|
NdisPacket,
|
|||
|
NdisStatus,
|
|||
|
BytesTransferred);
|
|||
|
|
|||
|
break;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
} /* IpxTransferDataComplete */
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
IpxTransferData(
|
|||
|
OUT PNDIS_STATUS Status,
|
|||
|
IN NDIS_HANDLE NdisBindingHandle,
|
|||
|
IN NDIS_HANDLE MacReceiveContext,
|
|||
|
IN UINT ByteOffset,
|
|||
|
IN UINT BytesToTransfer,
|
|||
|
IN OUT PNDIS_PACKET Packet,
|
|||
|
OUT PUINT BytesTransferred
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine is called by all tightly bound clients instead of NdisTransferData.
|
|||
|
If this is a loopback packet, the transfer is done directly here, else NdisTransferData
|
|||
|
is called.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Status - status of operation
|
|||
|
NdisBindingHandle - Loopback cookie or Ndis context
|
|||
|
MacReceiveContext - Loopback packet or Mac context
|
|||
|
ByteOffset - Source offset
|
|||
|
BytesToTransfer - length of the transfer desired
|
|||
|
Packet - dest packet
|
|||
|
BytesTransferred - length of successful transfer
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NTSTATUS - status of operation.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
//
|
|||
|
// If this is a loopback packet, copy the data directly
|
|||
|
//
|
|||
|
if (NdisBindingHandle == (PVOID)IPX_LOOPBACK_COOKIE) {
|
|||
|
|
|||
|
IPX_DEBUG (LOOPB, ("LoopbXfer: src: %lx, dest: %lx, bytestoxfer: %lx\n",
|
|||
|
MacReceiveContext, Packet, BytesToTransfer));
|
|||
|
|
|||
|
NdisCopyFromPacketToPacketSafe(
|
|||
|
Packet, // Destination
|
|||
|
0, // DestinationOffset
|
|||
|
BytesToTransfer, // BytesToCopy
|
|||
|
(PNDIS_PACKET)MacReceiveContext, // Source
|
|||
|
ByteOffset, // SourceOffset
|
|||
|
BytesTransferred, // BytesCopied
|
|||
|
NormalPagePriority);
|
|||
|
|
|||
|
*Status = ((*BytesTransferred == BytesToTransfer)? NDIS_STATUS_SUCCESS : NDIS_STATUS_RESOURCES);
|
|||
|
} else {
|
|||
|
NdisTransferData(
|
|||
|
Status,
|
|||
|
NdisBindingHandle,
|
|||
|
MacReceiveContext,
|
|||
|
ByteOffset,
|
|||
|
BytesToTransfer,
|
|||
|
Packet,
|
|||
|
BytesTransferred);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
IpxTdiReceiveDatagram(
|
|||
|
IN PREQUEST Request
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
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.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
|
|||
|
PADDRESS Address;
|
|||
|
PADDRESS_FILE AddressFile;
|
|||
|
IPX_DEFINE_SYNC_CONTEXT (SyncContext)
|
|||
|
IPX_DEFINE_LOCK_HANDLE (LockHandle)
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Do a quick check of the validity of the address.
|
|||
|
//
|
|||
|
|
|||
|
AddressFile = (PADDRESS_FILE)REQUEST_OPEN_CONTEXT(Request);
|
|||
|
|
|||
|
if ((AddressFile->Size != sizeof (ADDRESS_FILE)) ||
|
|||
|
(AddressFile->Type != IPX_ADDRESSFILE_SIGNATURE)) {
|
|||
|
|
|||
|
return STATUS_INVALID_HANDLE;
|
|||
|
}
|
|||
|
|
|||
|
Address = AddressFile->Address;
|
|||
|
|
|||
|
if ((Address == NULL) ||
|
|||
|
(Address->Size != sizeof (ADDRESS)) ||
|
|||
|
(Address->Type != IPX_ADDRESS_SIGNATURE)) {
|
|||
|
|
|||
|
return STATUS_INVALID_HANDLE;
|
|||
|
}
|
|||
|
|
|||
|
IPX_BEGIN_SYNC (&SyncContext);
|
|||
|
|
|||
|
IPX_GET_LOCK (&Address->Lock, &LockHandle);
|
|||
|
|
|||
|
if (AddressFile->State != ADDRESSFILE_STATE_OPEN) {
|
|||
|
|
|||
|
IPX_FREE_LOCK (&Address->Lock, LockHandle);
|
|||
|
IPX_END_SYNC (&SyncContext);
|
|||
|
return STATUS_INVALID_HANDLE;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
InsertTailList (&AddressFile->ReceiveDatagramQueue, REQUEST_LINKAGE(Request));
|
|||
|
|
|||
|
IoSetCancelRoutine (Request, IpxCancelReceiveDatagram);
|
|||
|
|
|||
|
if (Request->Cancel) {
|
|||
|
|
|||
|
(VOID)RemoveTailList (&AddressFile->ReceiveDatagramQueue);
|
|||
|
IoSetCancelRoutine (Request, (PDRIVER_CANCEL)NULL);
|
|||
|
IPX_FREE_LOCK (&Address->Lock, LockHandle);
|
|||
|
IPX_END_SYNC (&SyncContext);
|
|||
|
return STATUS_CANCELLED;
|
|||
|
}
|
|||
|
|
|||
|
IPX_DEBUG (RECEIVE, ("RDG posted on %lx\n", AddressFile));
|
|||
|
|
|||
|
IpxReferenceAddressFileLock (AddressFile, AFREF_RCV_DGRAM);
|
|||
|
|
|||
|
IPX_FREE_LOCK (&Address->Lock, LockHandle);
|
|||
|
|
|||
|
IPX_END_SYNC (&SyncContext);
|
|||
|
|
|||
|
return STATUS_PENDING;
|
|||
|
|
|||
|
} /* IpxTdiReceiveDatagram */
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
IpxCancelReceiveDatagram(
|
|||
|
IN PDEVICE_OBJECT DeviceObject,
|
|||
|
IN PIRP Irp
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine is called by the I/O system to cancel a receive
|
|||
|
datagram. The datagram is found on the address file's receive
|
|||
|
datagram queue.
|
|||
|
|
|||
|
NOTE: This routine is called with the CancelSpinLock held and
|
|||
|
is responsible for releasing it.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
DeviceObject - Pointer to the device object for this driver.
|
|||
|
|
|||
|
Irp - Pointer to the request packet representing the I/O request.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
none.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
|
|||
|
PLIST_ENTRY p;
|
|||
|
PADDRESS_FILE AddressFile;
|
|||
|
PADDRESS Address;
|
|||
|
PREQUEST Request = (PREQUEST)Irp;
|
|||
|
BOOLEAN Found;
|
|||
|
IPX_DEFINE_LOCK_HANDLE (LockHandle)
|
|||
|
|
|||
|
|
|||
|
CTEAssert ((REQUEST_MAJOR_FUNCTION(Request) == IRP_MJ_INTERNAL_DEVICE_CONTROL) &&
|
|||
|
(REQUEST_MINOR_FUNCTION(Request) == TDI_RECEIVE_DATAGRAM));
|
|||
|
|
|||
|
CTEAssert (REQUEST_OPEN_TYPE(Request) == (PVOID)TDI_TRANSPORT_ADDRESS_FILE);
|
|||
|
|
|||
|
AddressFile = (PADDRESS_FILE)REQUEST_OPEN_CONTEXT(Request);
|
|||
|
Address = AddressFile->Address;
|
|||
|
|
|||
|
Found = FALSE;
|
|||
|
|
|||
|
IPX_GET_LOCK (&Address->Lock, &LockHandle);
|
|||
|
|
|||
|
for (p = AddressFile->ReceiveDatagramQueue.Flink;
|
|||
|
p != &AddressFile->ReceiveDatagramQueue;
|
|||
|
p = p->Flink) {
|
|||
|
|
|||
|
if (LIST_ENTRY_TO_REQUEST(p) == Request) {
|
|||
|
|
|||
|
RemoveEntryList (p);
|
|||
|
Found = TRUE;
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
IPX_FREE_LOCK (&Address->Lock, LockHandle);
|
|||
|
IoReleaseCancelSpinLock (Irp->CancelIrql);
|
|||
|
|
|||
|
if (Found) {
|
|||
|
|
|||
|
IPX_DEBUG(RECEIVE, ("Cancelled datagram on %lx\n", AddressFile));
|
|||
|
|
|||
|
REQUEST_INFORMATION(Request) = 0;
|
|||
|
REQUEST_STATUS(Request) = STATUS_CANCELLED;
|
|||
|
|
|||
|
IpxCompleteRequest (Request);
|
|||
|
ASSERT( DeviceObject->DeviceExtension == IpxDevice );
|
|||
|
IpxFreeRequest(IpxDevice, Request);
|
|||
|
|
|||
|
IpxDereferenceAddressFile (AddressFile, AFREF_RCV_DGRAM);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
} /* IpxCancelReceiveDatagram */
|
|||
|
|
|||
|
|