mirror of https://github.com/lianthony/NT4.0
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.
829 lines
22 KiB
829 lines
22 KiB
/*++
|
|
|
|
Copyright (c) 1989-1993 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
ind.c
|
|
|
|
Abstract:
|
|
|
|
This module contains code which implements the indication handler
|
|
for the NT Sample transport provider.
|
|
|
|
Environment:
|
|
|
|
Kernel mode
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "st.h"
|
|
|
|
|
|
|
|
NDIS_STATUS
|
|
StReceiveIndication (
|
|
IN NDIS_HANDLE BindingContext,
|
|
IN NDIS_HANDLE ReceiveContext,
|
|
IN PVOID HeaderBuffer,
|
|
IN UINT HeaderBufferSize,
|
|
IN PVOID LookaheadBuffer,
|
|
IN UINT LookaheadBufferSize,
|
|
IN UINT PacketSize
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine receives control from the physical provider as an
|
|
indication that a frame has been received on the physical link.
|
|
This routine is time critical, so we only allocate a
|
|
buffer and copy the packet into it. We also perform minimal
|
|
validation on this packet. It gets queued to the device context
|
|
to allow for processing later.
|
|
|
|
Arguments:
|
|
|
|
BindingContext - The Adapter Binding specified at initialization time.
|
|
|
|
ReceiveContext - A magic cookie for the MAC.
|
|
|
|
HeaderBuffer - pointer to a buffer containing the packet header.
|
|
|
|
HeaderBufferSize - the size of the header.
|
|
|
|
LookaheadBuffer - pointer to a buffer containing the negotiated minimum
|
|
amount of buffer I get to look at (not including header).
|
|
|
|
LookaheadBufferSize - the size of the above. May be less than asked
|
|
for, if that's all there is.
|
|
|
|
PacketSize - Overall size of the packet (not including header).
|
|
|
|
Return Value:
|
|
|
|
NDIS_STATUS - status of operation, one of:
|
|
|
|
NDIS_STATUS_SUCCESS if packet accepted,
|
|
NDIS_STATUS_NOT_RECOGNIZED if not recognized by protocol,
|
|
NDIS_any_other_thing if I understand, but can't handle.
|
|
|
|
--*/
|
|
{
|
|
PDEVICE_CONTEXT DeviceContext;
|
|
HARDWARE_ADDRESS SourceAddressBuffer;
|
|
PHARDWARE_ADDRESS SourceAddress;
|
|
UINT RealPacketSize;
|
|
PST_HEADER StHeader;
|
|
|
|
DeviceContext = (PDEVICE_CONTEXT)BindingContext;
|
|
|
|
RealPacketSize = 0;
|
|
|
|
//
|
|
// Obtain the packet length; this may optionally adjust
|
|
// the lookahead buffer forward if the header we wish
|
|
// to remove spills over into what the MAC considers
|
|
// data. If it determines that the header is not
|
|
// valid, it keeps RealPacketSize at 0.
|
|
//
|
|
|
|
MacReturnPacketLength(
|
|
&DeviceContext->MacInfo,
|
|
HeaderBuffer,
|
|
HeaderBufferSize,
|
|
PacketSize,
|
|
&RealPacketSize
|
|
);
|
|
|
|
if (RealPacketSize < 2) {
|
|
return NDIS_STATUS_NOT_RECOGNIZED;
|
|
}
|
|
|
|
//
|
|
// We've negotiated at least a contiguous DLC header passed back in the
|
|
// lookahead buffer. Check it to see if we want this packet.
|
|
//
|
|
|
|
StHeader = (PST_HEADER)LookaheadBuffer;
|
|
|
|
if (StHeader->Signature != ST_SIGNATURE) {
|
|
return NDIS_STATUS_NOT_RECOGNIZED; // packet was processed.
|
|
}
|
|
|
|
|
|
//
|
|
// Check that the packet is not too long.
|
|
//
|
|
|
|
if (PacketSize > DeviceContext->MaxReceivePacketSize) {
|
|
#if DBG
|
|
StPrint2("StReceiveIndication: Ignoring packet length %d, max %d\n",
|
|
PacketSize, DeviceContext->MaxReceivePacketSize);
|
|
#endif
|
|
return NDIS_STATUS_NOT_RECOGNIZED;
|
|
}
|
|
|
|
MacReturnSourceAddress(
|
|
&DeviceContext->MacInfo,
|
|
HeaderBuffer,
|
|
&SourceAddressBuffer,
|
|
&SourceAddress
|
|
);
|
|
|
|
|
|
return StGeneralReceiveHandler(
|
|
DeviceContext,
|
|
ReceiveContext,
|
|
SourceAddress,
|
|
HeaderBuffer, // header
|
|
RealPacketSize, // total data length in packet
|
|
(PST_HEADER)LookaheadBuffer, // lookahead data
|
|
LookaheadBufferSize // lookahead data length
|
|
);
|
|
|
|
}
|
|
|
|
|
|
NDIS_STATUS
|
|
StGeneralReceiveHandler (
|
|
IN PDEVICE_CONTEXT DeviceContext,
|
|
IN NDIS_HANDLE ReceiveContext,
|
|
IN PHARDWARE_ADDRESS SourceAddress,
|
|
IN PVOID HeaderBuffer,
|
|
IN UINT PacketSize,
|
|
IN PST_HEADER StHeader,
|
|
IN UINT StSize
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine receives control from StReceiveIndication.
|
|
It continues the processing of indicated data.
|
|
|
|
This routine is time critical, so we only allocate a
|
|
buffer and copy the packet into it. We also perform minimal
|
|
validation on this packet. It gets queued to the device context
|
|
to allow for processing later.
|
|
|
|
Arguments:
|
|
|
|
DeviceContext - The device context of this adapter.
|
|
|
|
ReceiveContext - A magic cookie for the MAC.
|
|
|
|
SourceAddress - The source address of the packet.
|
|
|
|
HeaderBuffer - pointer to the packet header.
|
|
|
|
PacketSize - Overall size of the packet (not including header).
|
|
|
|
DlcHeader - Points to the DLC header of the packet.
|
|
|
|
DlcSize - The length of the packet indicated, starting from DlcHeader.
|
|
|
|
Return Value:
|
|
|
|
NDIS_STATUS - status of operation, one of:
|
|
|
|
NDIS_STATUS_SUCCESS if packet accepted,
|
|
NDIS_STATUS_NOT_RECOGNIZED if not recognized by protocol,
|
|
NDIS_any_other_thing if I understand, but can't handle.
|
|
|
|
--*/
|
|
{
|
|
|
|
KIRQL oldirql;
|
|
NTSTATUS Status;
|
|
NDIS_STATUS NdisStatus;
|
|
PNDIS_PACKET NdisPacket;
|
|
PNDIS_BUFFER NdisBuffer;
|
|
PSINGLE_LIST_ENTRY linkage;
|
|
UINT BytesTransferred;
|
|
PRECEIVE_PACKET_TAG ReceiveTag;
|
|
PBUFFER_TAG BufferTag;
|
|
PUCHAR SourceRouting;
|
|
UINT SourceRoutingLength;
|
|
PTP_ADDRESS DatagramAddress;
|
|
UINT NdisBufferLength;
|
|
PTP_CONNECTION Connection;
|
|
PVOID BufferPointer;
|
|
|
|
|
|
INCREMENT_COUNTER (DeviceContext, PacketsReceived);
|
|
|
|
Status = STATUS_SUCCESS; // assume no further processing required
|
|
|
|
|
|
//
|
|
// See what type of frame this is.
|
|
//
|
|
|
|
if ((StHeader->Command == ST_CMD_CONNECT) ||
|
|
(StHeader->Command == ST_CMD_DATAGRAM)) {
|
|
|
|
MacReturnSourceRouting(
|
|
&DeviceContext->MacInfo,
|
|
HeaderBuffer,
|
|
&SourceRouting,
|
|
&SourceRoutingLength);
|
|
|
|
Status = StProcessConnectionless (
|
|
DeviceContext,
|
|
SourceAddress,
|
|
StHeader,
|
|
StSize,
|
|
SourceRouting,
|
|
SourceRoutingLength,
|
|
&DatagramAddress);
|
|
|
|
} else if ((StHeader->Command == ST_CMD_INFORMATION) ||
|
|
(StHeader->Command == ST_CMD_DISCONNECT)) {
|
|
|
|
//
|
|
// If successful this adds a connection reference.
|
|
//
|
|
|
|
if (!(Connection = StFindConnection(DeviceContext, StHeader->Destination, StHeader->Source))) {
|
|
return NDIS_STATUS_NOT_RECOGNIZED;
|
|
}
|
|
|
|
|
|
if (StHeader->Command == ST_CMD_INFORMATION) {
|
|
|
|
Status = StProcessIIndicate (
|
|
Connection,
|
|
StHeader,
|
|
StSize,
|
|
PacketSize,
|
|
ReceiveContext,
|
|
(BOOLEAN)((StHeader->Flags & ST_FLAGS_LAST) != 0)
|
|
);
|
|
|
|
if (Status != STATUS_MORE_PROCESSING_REQUIRED) {
|
|
StDereferenceConnection ("Information done", Connection);
|
|
} else {
|
|
Status = STATUS_SUCCESS;
|
|
}
|
|
|
|
} else {
|
|
|
|
StStopConnection (Connection, STATUS_REMOTE_DISCONNECT);
|
|
StDereferenceConnection ("Disconnect done", Connection);
|
|
Status = STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
//
|
|
// An unrecognized frame.
|
|
//
|
|
|
|
Status = STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
//
|
|
// If the above routines return success, the packet has been processed
|
|
// and can be discarded. If they return anything else, the packet needs
|
|
// to be copied to local storage for handling in a more lesurely
|
|
// fashion.
|
|
//
|
|
|
|
if (Status != STATUS_MORE_PROCESSING_REQUIRED) {
|
|
return NDIS_STATUS_SUCCESS;
|
|
}
|
|
|
|
linkage = ExInterlockedPopEntryList(
|
|
&DeviceContext->ReceivePacketPool,
|
|
&DeviceContext->Interlock);
|
|
|
|
if (linkage != NULL) {
|
|
NdisPacket = CONTAINING_RECORD( linkage, NDIS_PACKET, ProtocolReserved[0] );
|
|
} else {
|
|
(VOID)InterlockedIncrement((PLONG)&DeviceContext->ReceivePacketExhausted);
|
|
|
|
return NDIS_STATUS_RESOURCES;
|
|
}
|
|
ReceiveTag = (PRECEIVE_PACKET_TAG)(NdisPacket->ProtocolReserved);
|
|
|
|
linkage = ExInterlockedPopEntryList(
|
|
&DeviceContext->ReceiveBufferPool,
|
|
&DeviceContext->Interlock);
|
|
|
|
if (linkage != NULL) {
|
|
BufferTag = CONTAINING_RECORD( linkage, BUFFER_TAG, Linkage);
|
|
} else {
|
|
ExInterlockedPushEntryList(
|
|
&DeviceContext->ReceivePacketPool,
|
|
(PSINGLE_LIST_ENTRY)&ReceiveTag->Linkage,
|
|
&DeviceContext->Interlock);
|
|
(VOID)InterlockedIncrement((PLONG)&DeviceContext->ReceiveBufferExhausted);
|
|
|
|
return NDIS_STATUS_RESOURCES;
|
|
}
|
|
|
|
NdisAdjustBufferLength (BufferTag->NdisBuffer, PacketSize);
|
|
NdisChainBufferAtFront (NdisPacket, (PNDIS_BUFFER)BufferTag->NdisBuffer);
|
|
|
|
//
|
|
// DatagramAddress has a reference added already.
|
|
//
|
|
|
|
BufferTag->Address = DatagramAddress;
|
|
|
|
//
|
|
// set up async return status so we can tell when it has happened;
|
|
// can never get return of NDIS_STATUS_PENDING in synch completion routine
|
|
// for NdisTransferData, so we know it has completed when this status
|
|
// changes
|
|
//
|
|
|
|
ReceiveTag->NdisStatus = NDIS_STATUS_PENDING;
|
|
ReceiveTag->PacketType = TYPE_AT_COMPLETE;
|
|
|
|
ExInterlockedInsertTailList(
|
|
&DeviceContext->ReceiveInProgress,
|
|
&ReceiveTag->Linkage,
|
|
&DeviceContext->SpinLock);
|
|
|
|
//
|
|
// receive packet is mapped at initalize
|
|
//
|
|
|
|
NdisTransferData (
|
|
&NdisStatus,
|
|
DeviceContext->NdisBindingHandle,
|
|
ReceiveContext,
|
|
0,
|
|
PacketSize,
|
|
NdisPacket,
|
|
&BytesTransferred);
|
|
|
|
//
|
|
// handle the various error codes
|
|
//
|
|
|
|
switch (NdisStatus) {
|
|
case NDIS_STATUS_SUCCESS: // received packet
|
|
ReceiveTag->NdisStatus = NDIS_STATUS_SUCCESS;
|
|
if (BytesTransferred == PacketSize) { // Did we get the entire packet?
|
|
return NDIS_STATUS_SUCCESS;
|
|
}
|
|
break;
|
|
|
|
case NDIS_STATUS_PENDING: // waiting async complete from NdisTransferData
|
|
return NDIS_STATUS_SUCCESS;
|
|
break;
|
|
|
|
default: // something broke; certainly we'll never get NdisTransferData
|
|
// asynch completion with this error status...
|
|
break;
|
|
}
|
|
|
|
//
|
|
// receive failed, for some reason; cleanup and fail return
|
|
//
|
|
|
|
|
|
ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock, &oldirql);
|
|
RemoveEntryList (&ReceiveTag->Linkage);
|
|
RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
|
|
|
|
ReceiveTag->PacketType = TYPE_AT_INDICATE;
|
|
|
|
ExInterlockedPushEntryList(
|
|
&DeviceContext->ReceivePacketPool,
|
|
(PSINGLE_LIST_ENTRY)&ReceiveTag->Linkage,
|
|
&DeviceContext->Interlock);
|
|
|
|
NdisUnchainBufferAtFront (NdisPacket, &NdisBuffer);
|
|
NdisQueryBuffer (NdisBuffer, &BufferPointer, &NdisBufferLength);
|
|
BufferTag = CONTAINING_RECORD (
|
|
BufferPointer,
|
|
BUFFER_TAG,
|
|
Buffer[0]
|
|
);
|
|
NdisAdjustBufferLength (NdisBuffer, BufferTag->Length); // reset to good value
|
|
|
|
ExInterlockedPushEntryList(
|
|
&DeviceContext->ReceiveBufferPool,
|
|
&BufferTag->Linkage,
|
|
&DeviceContext->Interlock);
|
|
|
|
if (DatagramAddress) {
|
|
StDereferenceAddress ("DG TransferData failed", DatagramAddress);
|
|
}
|
|
|
|
return NDIS_STATUS_FAILURE;
|
|
|
|
} // StReceiveIndication
|
|
|
|
|
|
|
|
VOID
|
|
StTransferDataComplete (
|
|
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 start stripping buffers from the receive queue.
|
|
|
|
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.
|
|
|
|
--*/
|
|
|
|
{
|
|
PDEVICE_CONTEXT DeviceContext;
|
|
PRECEIVE_PACKET_TAG ReceiveTag;
|
|
PTP_CONNECTION Connection;
|
|
PNDIS_BUFFER NdisBuffer;
|
|
KIRQL oldirql, cancelirql;
|
|
|
|
//
|
|
// Put the NDIS status into a place we can use in packet processing.
|
|
// Note that this complete indication may be occuring during the call
|
|
// to NdisTransferData in the receive indication.
|
|
//
|
|
|
|
ReceiveTag = (PRECEIVE_PACKET_TAG)(NdisPacket->ProtocolReserved);
|
|
|
|
//
|
|
// note that the processing below depends on having only one packet
|
|
// transfer outstanding at a time. NDIS is supposed to guarentee this.
|
|
//
|
|
|
|
switch (ReceiveTag->PacketType) {
|
|
|
|
case TYPE_AT_COMPLETE: // normal handling
|
|
ReceiveTag->NdisStatus = NdisStatus;
|
|
break;
|
|
|
|
case TYPE_AT_INDICATE:
|
|
|
|
DeviceContext = (PDEVICE_CONTEXT)BindingContext;
|
|
Connection = ReceiveTag->Connection;
|
|
|
|
//
|
|
// The transfer for this packet is complete. Was it successful??
|
|
//
|
|
|
|
if (NdisStatus != NDIS_STATUS_SUCCESS) {
|
|
|
|
ULONG DumpData[1];
|
|
DumpData[0] = BytesTransferred;
|
|
|
|
StWriteGeneralErrorLog(
|
|
DeviceContext,
|
|
EVENT_TRANSPORT_TRANSFER_DATA,
|
|
603,
|
|
NdisStatus,
|
|
NULL,
|
|
1,
|
|
DumpData);
|
|
|
|
//
|
|
// Drop the packet. BUGBUG: The driver should recover
|
|
// from this, but this transport has no way to cause
|
|
// the remote to resend.
|
|
//
|
|
|
|
}
|
|
|
|
//
|
|
// Now dereference the request to say we've got no more local
|
|
// references to the memory owned by it.
|
|
//
|
|
|
|
Connection->CurrentReceiveRequest->IoRequestPacket->IoStatus.Information += BytesTransferred;
|
|
StDereferenceRequest ("TransferData complete", Connection->CurrentReceiveRequest);
|
|
|
|
//
|
|
// see if we've completed the current receive. If so, move to the next one.
|
|
//
|
|
|
|
if (ReceiveTag->CompleteReceive) {
|
|
|
|
if (ReceiveTag->EndOfMessage) {
|
|
|
|
//
|
|
// The messages has been completely received, ack it.
|
|
//
|
|
// We set DEFERRED_ACK and DEFERRED_NOT_Q here, which
|
|
// will cause an ack to be piggybacked if any data is
|
|
// sent during the call to CompleteReceive. If this
|
|
// does not happen, then we will call AcknowledgeDataOnlyLast
|
|
// which will will send a DATA ACK or queue a request for
|
|
// a piggyback ack. We do this *after* calling CompleteReceive
|
|
// so we know that we will complete the receive back to
|
|
// the client before we ack the data, to prevent the
|
|
// next receive from being sent before this one is
|
|
// completed.
|
|
//
|
|
|
|
|
|
IoAcquireCancelSpinLock(&cancelirql);
|
|
ACQUIRE_SPIN_LOCK (&Connection->SpinLock, &oldirql);
|
|
|
|
Connection->Flags2 |= CONNECTION_FLAGS2_RC_PENDING;
|
|
|
|
} else {
|
|
|
|
//
|
|
// If there is a receive posted, make it current and
|
|
// send a receive outstanding.
|
|
//
|
|
|
|
ActivateReceive (Connection);
|
|
|
|
IoAcquireCancelSpinLock(&cancelirql);
|
|
ACQUIRE_SPIN_LOCK (&Connection->SpinLock, &oldirql);
|
|
|
|
}
|
|
|
|
//
|
|
// NOTE: This releases the cancel and connection locks.
|
|
//
|
|
|
|
CompleteReceive (Connection, ReceiveTag->EndOfMessage, oldirql, cancelirql);
|
|
|
|
}
|
|
|
|
//
|
|
// dereference the connection to say we've done the I frame processing.
|
|
// This reference was done before calling NdisTransferData.
|
|
//
|
|
|
|
if (ReceiveTag->TransferDataPended) {
|
|
StDereferenceConnection("TransferData done", Connection);
|
|
}
|
|
|
|
|
|
//
|
|
// rip all of the NDIS_BUFFERs we've used off the chain and return them.
|
|
//
|
|
|
|
if (ReceiveTag->AllocatedNdisBuffer) {
|
|
NdisUnchainBufferAtFront (NdisPacket, &NdisBuffer);
|
|
while (NdisBuffer != NULL) {
|
|
NdisFreeBuffer (NdisBuffer);
|
|
NdisUnchainBufferAtFront (NdisPacket, &NdisBuffer);
|
|
}
|
|
} else {
|
|
NdisReinitializePacket (NdisPacket);
|
|
}
|
|
|
|
|
|
ExInterlockedPushEntryList(
|
|
&DeviceContext->ReceivePacketPool,
|
|
(PSINGLE_LIST_ENTRY)&ReceiveTag->Linkage,
|
|
&DeviceContext->Interlock);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
}
|
|
|
|
return;
|
|
|
|
} /* StTransferDataComplete */
|
|
|
|
|
|
VOID
|
|
StReceiveComplete (
|
|
IN NDIS_HANDLE BindingContext
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine receives control from the physical provider as an
|
|
indication that a connection(less) frame has been received on the
|
|
physical link. We dispatch to the correct packet handler here.
|
|
|
|
Arguments:
|
|
|
|
BindingContext - The Adapter Binding specified at initialization time.
|
|
ST uses the DeviceContext for this parameter.
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
|
|
{
|
|
PDEVICE_CONTEXT DeviceContext;
|
|
NTSTATUS Status;
|
|
KIRQL oldirql, oldirql1;
|
|
PLIST_ENTRY linkage;
|
|
PNDIS_PACKET NdisPacket;
|
|
PNDIS_BUFFER NdisBuffer;
|
|
UINT NdisBufferLength;
|
|
PVOID BufferPointer;
|
|
PRECEIVE_PACKET_TAG ReceiveTag;
|
|
PBUFFER_TAG BufferTag;
|
|
PTP_ADDRESS Address;
|
|
PIRP Irp;
|
|
PIO_STACK_LOCATION IrpSp;
|
|
PTP_CONNECTION Connection;
|
|
|
|
|
|
DeviceContext = (PDEVICE_CONTEXT) BindingContext;
|
|
|
|
//
|
|
// Complete all pending receives. Do a quick check
|
|
// without the lock.
|
|
//
|
|
|
|
while (!IsListEmpty (&DeviceContext->IrpCompletionQueue)) {
|
|
|
|
linkage = ExInterlockedRemoveHeadList(
|
|
&DeviceContext->IrpCompletionQueue,
|
|
&DeviceContext->SpinLock);
|
|
|
|
if (linkage != NULL) {
|
|
|
|
Irp = CONTAINING_RECORD (linkage, IRP, Tail.Overlay.ListEntry);
|
|
IrpSp = IoGetCurrentIrpStackLocation (Irp);
|
|
|
|
Connection = (PTP_CONNECTION)IrpSp->FileObject->FsContext;
|
|
|
|
IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
|
|
|
|
ACQUIRE_SPIN_LOCK (&Connection->SpinLock, &oldirql1);
|
|
|
|
if (Connection->Flags2 & CONNECTION_FLAGS2_RC_PENDING) {
|
|
Connection->Flags2 &= ~CONNECTION_FLAGS2_RC_PENDING;
|
|
}
|
|
|
|
RELEASE_SPIN_LOCK (&Connection->SpinLock, oldirql1);
|
|
|
|
StDereferenceConnection ("receive completed", Connection);
|
|
|
|
} else {
|
|
|
|
//
|
|
// ExInterlockedRemoveHeadList returned NULL, so don't
|
|
// bother looping back.
|
|
//
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
//
|
|
// Packetize all waiting connections
|
|
//
|
|
|
|
if (!IsListEmpty(&DeviceContext->PacketizeQueue)) {
|
|
|
|
PacketizeConnections (DeviceContext);
|
|
|
|
}
|
|
|
|
|
|
//
|
|
// Get every waiting packet, in order...
|
|
//
|
|
|
|
|
|
if (!IsListEmpty (&DeviceContext->ReceiveInProgress)) {
|
|
|
|
ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock, &oldirql);
|
|
|
|
while (!IsListEmpty (&DeviceContext->ReceiveInProgress)) {
|
|
|
|
linkage = RemoveHeadList (&DeviceContext->ReceiveInProgress);
|
|
NdisPacket = CONTAINING_RECORD( linkage, NDIS_PACKET, ProtocolReserved[0]);
|
|
|
|
//
|
|
// NdisTransferData may have failed at async completion; check and
|
|
// see. If it did, then we discard this packet. If we're still waiting
|
|
// for transfer to complete, go back to sleep and hope (no guarantee!)
|
|
// we get waken up later.
|
|
//
|
|
|
|
ReceiveTag = (PRECEIVE_PACKET_TAG)(NdisPacket->ProtocolReserved);
|
|
if (ReceiveTag->NdisStatus == NDIS_STATUS_PENDING) {
|
|
InsertHeadList (&DeviceContext->ReceiveInProgress, linkage);
|
|
RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
|
|
return;
|
|
}
|
|
|
|
RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
|
|
|
|
if (ReceiveTag->NdisStatus != NDIS_STATUS_SUCCESS) {
|
|
goto FreePacket; // skip the packet, continue with while loop
|
|
}
|
|
|
|
NdisQueryPacket (NdisPacket, NULL, NULL, &NdisBuffer, NULL);
|
|
|
|
//
|
|
// Have a packet. Since I allocated the storage for it, I know it's
|
|
// virtually contiguous and can treat it that way, which I will
|
|
// henceforth.
|
|
//
|
|
|
|
NdisQueryBuffer (NdisBuffer, &BufferPointer, &NdisBufferLength);
|
|
|
|
//
|
|
// Determine what address this is for, which is stored
|
|
// in the buffer tag header.
|
|
//
|
|
|
|
BufferTag = CONTAINING_RECORD( BufferPointer, BUFFER_TAG, Buffer[0]);
|
|
Address = BufferTag->Address;
|
|
|
|
//
|
|
// Process the frame as a UI frame; only datagrams should
|
|
// be processed here. If Address is NULL then this datagram
|
|
// is not needed for any bound address and should be given
|
|
// to RAS only.
|
|
//
|
|
|
|
ASSERT (Address != NULL);
|
|
|
|
//
|
|
// Indicate it or complete posted datagrams.
|
|
//
|
|
|
|
Status = StIndicateDatagram (
|
|
DeviceContext,
|
|
Address,
|
|
BufferPointer,
|
|
NdisBufferLength);
|
|
|
|
|
|
//
|
|
// Dereference the address.
|
|
//
|
|
|
|
StDereferenceAddress ("Datagram done", Address);
|
|
|
|
//
|
|
// Finished with packet; return to pool.
|
|
//
|
|
|
|
FreePacket:;
|
|
|
|
NdisUnchainBufferAtFront (NdisPacket, &NdisBuffer);
|
|
ReceiveTag->PacketType = TYPE_AT_INDICATE;
|
|
|
|
ExInterlockedPushEntryList(
|
|
&DeviceContext->ReceivePacketPool,
|
|
(PSINGLE_LIST_ENTRY)&ReceiveTag->Linkage,
|
|
&DeviceContext->Interlock);
|
|
|
|
NdisAdjustBufferLength (NdisBuffer, BufferTag->Length);
|
|
ExInterlockedPushEntryList(
|
|
&DeviceContext->ReceiveBufferPool,
|
|
&BufferTag->Linkage,
|
|
&DeviceContext->Interlock);
|
|
|
|
ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock, &oldirql);
|
|
|
|
}
|
|
|
|
RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql);
|
|
|
|
} // if queue not empty
|
|
|
|
return;
|
|
|
|
} /* StReceiveComplete */
|
|
|