Windows NT 4.0 source code leak
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.
 
 
 
 
 
 

340 lines
7.2 KiB

/*++
Copyright (c) 1992 Microsoft Corporation
Module Name:
send.c
Abstract:
This file contains the code for putting a packet through the
staged allocation for transmission.
This is a process of
1) Calculating the what would need to be done to the
packet so that the packet can be transmitted on the hardware.
2) Potentially allocating adapter buffers and copying user data
to those buffers so that the packet data is transmitted under
the hardware constraints.
3) Allocating enough hardware ring entries so that the packet
can be transmitted.
4) Relinquish those ring entries to the hardware.
Author:
Johnson R. Apacible (JohnsonA) 9-June-1991
Environment:
Kernel Mode - Or whatever is the equivalent on OS/2 and DOS.
Revision History:
--*/
#include <ndis.h>
//
// So we can trace things...
//
#define STATIC
#include <efilter.h>
#include <elnkhw.h>
#include <elnksw.h>
NDIS_STATUS
ElnkSend(
IN NDIS_HANDLE MacBindingHandle,
IN PNDIS_PACKET Packet
)
/*++
Routine Description:
The ElnkSend request instructs a MAC to transmit a packet through
the adapter onto the medium.
Arguments:
MacBindingHandle - The context value returned by the MAC when the
adapter was opened. In reality, it is a pointer to ELNK_OPEN.
Packet - A pointer to a descriptor for the packet that is to be
transmitted.
Return Value:
The function value is the status of the operation.
--*/
{
//
// Holds the status that should be returned to the caller.
//
NDIS_STATUS StatusToReturn = NDIS_STATUS_PENDING;
//
// Pointer to the adapter.
//
PELNK_ADAPTER Adapter;
if ELNKDEBUG DPrint2("ElnkSend Packet = %x\n",Packet);
Adapter = PELNK_ADAPTER_FROM_BINDING_HANDLE(MacBindingHandle);
NdisAcquireSpinLock(&Adapter->Lock);
Adapter->References++;
if (!Adapter->ResetInProgress) {
PELNK_OPEN Open;
Open = PELNK_OPEN_FROM_BINDING_HANDLE(MacBindingHandle);
if (!Open->BindingShuttingDown) {
UINT TotalPacketSize;
//
// Increment the references on the open while we are
// accessing it in the interface.
//
Open->References++;
NdisReleaseSpinLock(&Adapter->Lock);
//
// It is reasonable to do a quick check and fail if the packet
// is larger than the maximum an ethernet can handle.
//
NdisQueryPacket(
Packet,
NULL,
NULL,
NULL,
&TotalPacketSize
);
NdisAcquireSpinLock(&Adapter->Lock);
if ((!TotalPacketSize) ||
(TotalPacketSize > MAXIMUM_ETHERNET_PACKET_SIZE)) {
Open->References--;
StatusToReturn = NDIS_STATUS_RESOURCES;
} else {
PELNK_RESERVED Reserved = PELNK_RESERVED_FROM_PACKET(Packet);
PNDIS_BUFFER FirstBuffer;
PUCHAR BufferVA;
UINT Length;
//
// Set Reserved->Loopback.
//
NdisQueryPacket(Packet, NULL, NULL, &FirstBuffer, NULL);
//
// Get VA of first buffer
//
NdisQueryBuffer(
FirstBuffer,
(PVOID *)&BufferVA,
&Length
);
if (Open->ProtOptionFlags & NDIS_PROT_OPTION_NO_LOOPBACK){
Reserved->Loopback = FALSE;
} else {
Reserved->Loopback = EthShouldAddressLoopBack(Adapter->FilterDB, BufferVA);
}
Reserved->MacBindingHandle = MacBindingHandle;
//
// Put on the stage queue.
//
if (!Adapter->LastStagePacket) {
Adapter->FirstStagePacket = Packet;
} else {
PELNK_RESERVED_FROM_PACKET(Adapter->LastStagePacket)->Next = Packet;
}
Adapter->LastStagePacket = Packet;
Reserved->Next = NULL;
Adapter->TransmitsQueued++;
//
// Only try to push it through the stage queues
// if somebody else isn't already doing it and
// there is some hope of moving some packets
// ahead.
//
while (!Adapter->AlreadyProcessingStage &&
Adapter->FirstStagePacket &&
Adapter->StageOpen
) {
ElnkStagedAllocation(Adapter);
}
}
//
// We leave the reference for the pending send.
//
} else {
StatusToReturn = NDIS_STATUS_CLOSING;
}
} else {
StatusToReturn = NDIS_STATUS_RESET_IN_PROGRESS;
}
ELNK_DO_DEFERRED(Adapter);
return StatusToReturn;
}
VOID
ElnkStagedAllocation(
IN PELNK_ADAPTER Adapter
)
/*++
Routine Description:
This routine attempts to take a packet through a stage of allocation.
Arguments:
Adapter - The adapter that the packets are coming through.
Return Value:
None.
--*/
{
UINT CbIndex;
PNDIS_PACKET FirstPacket = Adapter->FirstStagePacket;
if ELNKDEBUG DPrint1("StagedAllocation\n");
//
// For each stage, we check to see that it is open,
// that somebody else isn't already processing,
// and that there is some work from the previous
// stage to do.
//
ASSERT (Adapter->StageOpen &&
!Adapter->AlreadyProcessingStage &&
Adapter->FirstStagePacket);
//
// If we successfully acquire a command block, this
// is the index to it.
//
Adapter->AlreadyProcessingStage = TRUE;
//
// We look to see if there is an available Command Block.
// If there isn't then stage 2 will close.
//
IF_LOG('p');
if (ElnkAcquireCommandBlock(
Adapter,
&CbIndex
)) {
IF_LOG('a');
//
// Remove from queue
//
Adapter->FirstStagePacket = PELNK_RESERVED_FROM_PACKET(FirstPacket)->Next;
if (!Adapter->FirstStagePacket) {
Adapter->LastStagePacket = NULL;
}
NdisReleaseSpinLock(&Adapter->Lock);
//
// We have a command block. Assign all packet
// buffers to the command block.
//
ElnkAssignPacketToCommandBlock(
Adapter,
FirstPacket,
CbIndex
);
//
// We need exclusive access to the Command Queue so
// that we can move this packet on to the next stage.
//
NdisAcquireSpinLock(&Adapter->Lock);
ElnkPutPacketOnFinishTrans(
Adapter,
FirstPacket
);
ElnkSubmitCommandBlock(
Adapter,
CbIndex
);
Adapter->AlreadyProcessingStage = FALSE;
} else {
Adapter->AlreadyProcessingStage = FALSE;
Adapter->StageOpen = FALSE;
IF_LOG('P');
return;
}
IF_LOG('P');
}