diff options
author | Adam <you@example.com> | 2020-05-17 05:51:50 +0200 |
---|---|---|
committer | Adam <you@example.com> | 2020-05-17 05:51:50 +0200 |
commit | e611b132f9b8abe35b362e5870b74bce94a1e58e (patch) | |
tree | a5781d2ec0e085eeca33cf350cf878f2efea6fe5 /private/ntos/tdi/isnp/ipx/receive.c | |
download | NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.gz NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.bz2 NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.lz NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.xz NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.zst NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.zip |
Diffstat (limited to '')
-rw-r--r-- | private/ntos/tdi/isnp/ipx/receive.c | 466 |
1 files changed, 466 insertions, 0 deletions
diff --git a/private/ntos/tdi/isnp/ipx/receive.c b/private/ntos/tdi/isnp/ipx/receive.c new file mode 100644 index 000000000..ff9c68fbd --- /dev/null +++ b/private/ntos/tdi/isnp/ipx/receive.c @@ -0,0 +1,466 @@ +/*++ + +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->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) { + + REQUEST_STATUS(Request) = + TdiCopyBufferToMdl( + Reserved->ReceiveBuffer->Data, + ByteOffset + REQUEST_INFORMATION(Request), + ((PTDI_REQUEST_KERNEL_RECEIVEDG)(REQUEST_PARAMETERS(Request)))->ReceiveLength, + REQUEST_NDIS_BUFFER(Request), + 0, + &REQUEST_INFORMATION(Request)); + + } 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; + + } + + + // + // 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); + + } + + + // + // 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)); + + NdisCopyFromPacketToPacket( + Packet, // Destination + 0, // DestinationOffset + BytesToTransfer, // BytesToCopy + (PNDIS_PACKET)MacReceiveContext, // Source + ByteOffset, // SourceOffset + BytesTransferred); // BytesCopied + + *Status = NDIS_STATUS_SUCCESS; + } 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 */ + + |