summaryrefslogtreecommitdiffstats
path: root/private/ntos/ndis/lsl/mlidsend.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--private/ntos/ndis/lsl/mlidsend.c875
1 files changed, 875 insertions, 0 deletions
diff --git a/private/ntos/ndis/lsl/mlidsend.c b/private/ntos/ndis/lsl/mlidsend.c
new file mode 100644
index 000000000..611707835
--- /dev/null
+++ b/private/ntos/ndis/lsl/mlidsend.c
@@ -0,0 +1,875 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ mlidsend.c
+
+Abstract:
+
+ This file contains all routines for sending packets.
+
+Author:
+
+ Sean Selitrennikoff (SeanSe) 3-8-93
+
+Environment:
+
+ Kernel Mode.
+
+Revision History:
+
+--*/
+
+#include <ndis.h>
+#include "lsl.h"
+#include "frames.h"
+#include "mlid.h"
+#include "ndismlid.h"
+
+VOID
+NdisMlidBuildMediaHeader(
+ PMLID_STRUCT Mlid,
+ PMLID_RESERVED Reserved,
+ UINT32 FrameLength,
+ PUINT8 DestinationAddress,
+ PUINT8 ProtocolID
+ );
+
+
+VOID
+SendPackets(
+ PMLID_STRUCT Mlid
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called whenever there is a need to send a packet. It will
+ take as many Send ECBs from the Mlid as possible and convert them into NDIS_PACKETS
+ and submit them to the NDIS_MAC.
+
+ NOTE: This must be called with Mlid->StageOpen = TRUE;
+ NOTE: This must be called with Mlid->InSendPacket = FALSE;
+ NOTE: Called with Mlid->MlidSpinLock held!!
+
+Arguments:
+
+ Mlid - Pointer to the MLID_STRUCT to service.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PNDIS_PACKET NdisSendPacket;
+ PNDIS_BUFFER NdisBuffer;
+ PMLID_RESERVED Reserved;
+ UINT32 i;
+ BOOLEAN HeldEvents = FALSE;
+ NDIS_STATUS NdisStatus;
+
+ PECB SendECB;
+
+ ASSERT(Mlid->StageOpen == TRUE);
+ ASSERT(Mlid->InSendPacket == FALSE);
+
+ //
+ // While there any sends queued
+ //
+ while (Mlid->FirstPendingSend) {
+
+ //
+ // If there are no NDIS_PACKETs avaiable, then close stage and exit.
+ //
+ NdisAllocatePacket(
+ &NdisStatus,
+ &NdisSendPacket,
+ Mlid->SendPacketPool
+ );
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+
+ Mlid->StageOpen = FALSE;
+ break;
+
+ }
+
+ Reserved = PMLID_RESERVED_FROM_PNDIS_PACKET(NdisSendPacket);
+
+ //
+ // Initialize NDIS_PACKET
+ //
+ NdisReinitializePacket(NdisSendPacket);
+
+ SendECB = Mlid->FirstPendingSend;
+
+ //
+ // Convert ECB fragment list into an MDL chain
+ //
+ for (i = 0; i < SendECB->ECB_FragmentCount; i++) {
+
+ NdisAllocateBuffer(
+ &NdisStatus,
+ &NdisBuffer,
+ Mlid->SendBufferPool,
+ SendECB->ECB_Fragment[i].FragmentAddress,
+ SendECB->ECB_Fragment[i].FragmentLength
+ );
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+
+ goto Fail1;
+
+ }
+
+ NdisChainBufferAtBack(
+ NdisSendPacket,
+ NdisBuffer
+ );
+
+ }
+
+ //
+ // Build the media header
+ //
+ NdisMlidBuildMediaHeader(Mlid,
+ Reserved,
+ SendECB->ECB_DataLength,
+ SendECB->ECB_ImmediateAddress,
+ SendECB->ECB_ProtocolID
+ );
+
+ //
+ // Link media header into front of MDL chain
+ //
+ NdisAllocateBuffer(
+ &NdisStatus,
+ &NdisBuffer,
+ Mlid->SendBufferPool,
+ Reserved->MediaHeader,
+ Reserved->MediaHeaderLength
+ );
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+
+ goto Fail1;
+
+ }
+
+ NdisChainBufferAtFront(
+ NdisSendPacket,
+ NdisBuffer
+ );
+
+ //
+ // Remove Send ECB from Send Queue
+ //
+ Mlid->FirstPendingSend = SendECB->ECB_NextLink;
+
+ if (Mlid->LastPendingSend == SendECB) {
+
+ Mlid->LastPendingSend = NULL;
+
+ } else {
+
+ SendECB->ECB_NextLink->ECB_PreviousLink = NULL;
+
+ }
+
+ //
+ // Store ECB in reserved section
+ //
+ Reserved->SendECB = SendECB;
+
+ //
+ // Release MlidSpinLock
+ //
+ NdisReleaseSpinLock(&(Mlid->MlidSpinLock));
+
+ //
+ // Submit to NDIS_MAC
+ //
+ NdisSend(
+ &NdisStatus,
+ Mlid->NdisBindingHandle,
+ NdisSendPacket
+ );
+
+ //
+ // Acquire MlidSpinLock
+ //
+ NdisAcquireSpinLock(&(Mlid->MlidSpinLock));
+
+ //
+ // If not pending, then
+ //
+ if (NdisStatus != NDIS_STATUS_PENDING) {
+
+ //
+ // Return resources to Mlid
+ //
+ NdisUnchainBufferAtFront(
+ NdisSendPacket,
+ &NdisBuffer
+ );
+
+ while (NdisBuffer != NULL) {
+
+ NdisFreeBuffer(NdisBuffer);
+
+ NdisUnchainBufferAtFront(
+ NdisSendPacket,
+ &NdisBuffer
+ );
+
+ }
+
+ NdisFreePacket(NdisSendPacket);
+
+ //
+ // Store completion status in ECB
+ //
+
+ if (NdisStatus == NDIS_STATUS_SUCCESS) {
+
+ SendECB->ECB_Status = (UINT16)SUCCESSFUL;
+
+ } else {
+
+ SendECB->ECB_Status = (UINT16)FAIL;
+
+ }
+
+ //
+ // Release MlidSpinLock
+ //
+ NdisReleaseSpinLock(&(Mlid->MlidSpinLock));
+
+ //
+ // put ECB on LSLEventQueue
+ //
+ (*(Mlid->LSLFunctionList->SupportAPIArray[HoldEvent_INDEX]))(
+ SendECB
+ );
+
+ //
+ // Acquire MlidSpinLock
+ //
+ NdisAcquireSpinLock(&(Mlid->MlidSpinLock));
+
+ //
+ // Set flag to service events
+ //
+ HeldEvents = TRUE;
+
+ }
+
+ }
+
+ //
+ // Call LSL_ServiceEvents if necessary
+ //
+ if (HeldEvents) {
+ (*(Mlid->LSLFunctionList->SupportAPIArray[ServiceEvents_INDEX]))(
+ );
+
+ }
+
+ return;
+
+Fail1:
+
+ //
+ // Unchain all NDIS_BUFFERs from packet
+ //
+
+ NdisUnchainBufferAtFront(
+ NdisSendPacket,
+ &NdisBuffer
+ );
+
+ while (NdisBuffer != NULL) {
+
+ NdisFreeBuffer(NdisBuffer);
+
+ NdisUnchainBufferAtFront(
+ NdisSendPacket,
+ &NdisBuffer
+ );
+
+ }
+
+ //
+ // Return NDIS_PACKET
+ //
+ NdisFreePacket(NdisSendPacket);
+
+ //
+ // Close stage
+ //
+ Mlid->StageOpen = FALSE;
+
+ return;
+}
+
+
+VOID
+ReturnSendPacketResources(
+ PNDIS_PACKET Packet
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to return the MLID resources allocated for a sent NDIS_PACKET.
+ This includes the entire MDL chain itself and the NDIS_PACKET.
+
+ NOTE: Called with Mlid->MlidSpinLock held!!
+
+Arguments:
+
+ Packet - Pointer to the NDIS_PACKET to free.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PNDIS_BUFFER NdisBuffer;
+
+ //
+ // Unchain all NDIS_BUFFERs from packet
+ //
+
+ NdisUnchainBufferAtFront(
+ Packet,
+ &NdisBuffer
+ );
+
+ while (NdisBuffer != NULL) {
+
+ NdisFreeBuffer(NdisBuffer);
+
+ NdisUnchainBufferAtFront(
+ Packet,
+ &NdisBuffer
+ );
+
+ }
+
+ //
+ // Return NDIS_PACKET
+ //
+ NdisFreePacket(Packet);
+
+}
+
+
+VOID
+NdisMlidBuildMediaHeader(
+ PMLID_STRUCT Mlid,
+ PMLID_RESERVED Reserved,
+ UINT32 FrameLength,
+ PUINT8 DestinationAddress,
+ PUINT8 ProtocolID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine assembles a packet header for the MLID and ProtocolID given into
+ the given reserved section.
+
+ NOTE: Called with Mlid->MlidSpinLock held!!
+
+Arguments:
+
+ Mlid - Pointer to MLID
+
+ Reserved - Pointer to a reserved section with memory to hold the header.
+
+ FrameLength - Length of the Data portion of the frame.
+
+ DestinationAddress - The address that the packet will be addresses to.
+
+ ProtocolID - The ID that has DSAP and other information in it.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PUINT8 SourceRoutingInfo;
+ UINT32 SourceRoutingLength;
+ UINT32 DataLength = FrameLength;
+ PUINT8 CurrentPlace = Reserved->MediaHeader;
+
+ //
+ // Switch on media type
+ //
+ switch (Mlid->NdisMlidMedium) {
+
+ case NdisMedium802_5:
+
+ if (Mlid->ConfigTable.MLIDCFG_SourceRouting != NULL) {
+
+ //
+ // Get any source routing information
+ //*\\ Get SR Info. Are parameters correct?
+ SourceRoutingInfo = (*((PLSL_SR_FUNCTION)(Mlid->ConfigTable.MLIDCFG_SourceRouting)))
+ ( Mlid->BoardNumber,
+ &SourceRoutingLength,
+ DestinationAddress
+ );
+
+ }
+
+ //
+ // Set AC field
+ //
+ *CurrentPlace = 0x10;
+ CurrentPlace++;
+
+ //
+ // Set FC field
+ //
+ *CurrentPlace = 0x40;
+ CurrentPlace++;
+
+ //
+ // Set DestinationAddress
+ //
+ RtlCopyMemory(CurrentPlace, DestinationAddress, 6);
+ CurrentPlace += 6;
+
+ //
+ // Set SourceAddress
+ //
+ RtlCopyMemory(CurrentPlace, Mlid->ConfigTable.MLIDCFG_NodeAddress, 6);
+ CurrentPlace += 6;
+
+ //
+ // Copy SourceRoutingInfo
+ //
+ RtlCopyMemory(CurrentPlace, SourceRoutingInfo, SourceRoutingLength);
+ CurrentPlace += SourceRoutingLength;
+
+ //
+ // Switch on frame type
+ //
+ switch (Mlid->ConfigTable.MLIDCFG_FrameID) {
+
+ //
+ // TR - 802.2
+ //
+ case TOKEN_RING_802_2_FRAME_ID:
+
+ //
+ // Set DSAP, SSAP and Control
+ //
+ if (ProtocolID[0] < 2) {
+
+ *CurrentPlace = ProtocolID[5];
+ CurrentPlace++;
+ *CurrentPlace = ProtocolID[5];
+ CurrentPlace++;
+ *CurrentPlace = 0x03;
+ CurrentPlace++;
+
+ } else if (ProtocolID[0] == 2) {
+
+ //
+ // Type I header
+ //
+
+ *CurrentPlace = ProtocolID[3];
+ CurrentPlace++;
+ *CurrentPlace = ProtocolID[4];
+ CurrentPlace++;
+ *CurrentPlace = ProtocolID[5];
+ CurrentPlace++;
+
+ } else {
+
+ //
+ // Type II header
+ //
+
+ *CurrentPlace = ProtocolID[2];
+ CurrentPlace++;
+ *CurrentPlace = ProtocolID[3];
+ CurrentPlace++;
+ *CurrentPlace = ProtocolID[4];
+ CurrentPlace++;
+ *CurrentPlace = ProtocolID[5];
+ CurrentPlace++;
+
+ }
+
+ break;
+
+ //
+ // TR - SNAP
+ //
+ case TOKEN_RING_SNAP_FRAME_ID:
+
+ //
+ // Set DSAP, SSAP and Control
+ //
+ *CurrentPlace = 0xAA;
+ CurrentPlace++;
+ *CurrentPlace = 0xAA;
+ CurrentPlace++;
+ *CurrentPlace = 0x03;
+ CurrentPlace++;
+
+ //
+ // Copy in ProtocolID
+ //
+ RtlCopyMemory(CurrentPlace, &(ProtocolID[1]), 5);
+ CurrentPlace += 5;
+
+ break;
+
+ default:
+
+ //
+ // Should never happen
+ //
+ ASSERT(0);
+ break;
+ }
+ break;
+
+
+ case NdisMedium802_3:
+
+ //
+ // Set DestinationAddress
+ //
+ RtlCopyMemory(CurrentPlace, DestinationAddress, 6);
+ CurrentPlace += 6;
+
+ //
+ // Set SourceAddress
+ //
+ RtlCopyMemory(CurrentPlace, Mlid->ConfigTable.MLIDCFG_NodeAddress, 6);
+ CurrentPlace += 6;
+
+ FrameLength += 12;
+
+ //
+ // Switch on frame type
+ //
+ switch (Mlid->ConfigTable.MLIDCFG_FrameID) {
+
+ //
+ // Ethernet 802.2
+ //
+ case ETHERNET_802_2_FRAME_ID:
+
+ FrameLength += 5;
+
+ //
+ // Set FrameLength
+ //
+ *CurrentPlace = (UINT8)((FrameLength >> 8) & 0xFF);
+ CurrentPlace++;
+ *CurrentPlace = (UINT8)(FrameLength & 0xFF);
+ CurrentPlace++;
+
+ //
+ // Set DSAP, SSAP and Control
+ //
+ if (ProtocolID[0] < 2) {
+
+ *CurrentPlace = ProtocolID[5];
+ CurrentPlace++;
+ *CurrentPlace = ProtocolID[5];
+ CurrentPlace++;
+ *CurrentPlace = 0x03;
+ CurrentPlace++;
+
+ } else if (ProtocolID[0] == 2) {
+
+ //
+ // Type I header
+ //
+
+ *CurrentPlace = ProtocolID[3];
+ CurrentPlace++;
+ *CurrentPlace = ProtocolID[4];
+ CurrentPlace++;
+ *CurrentPlace = ProtocolID[5];
+ CurrentPlace++;
+
+ } else {
+
+ //
+ // Type II header
+ //
+
+ *CurrentPlace = ProtocolID[2];
+ CurrentPlace++;
+ *CurrentPlace = ProtocolID[3];
+ CurrentPlace++;
+ *CurrentPlace = ProtocolID[4];
+ CurrentPlace++;
+ *CurrentPlace = ProtocolID[5];
+ CurrentPlace++;
+
+ }
+
+ break;
+
+ //
+ // Ethernet SNAP
+ //
+ case ETHERNET_SNAP_FRAME_ID:
+
+ FrameLength += 10;
+
+ //
+ // Set FrameLength
+ //
+ *CurrentPlace = (UINT8)((FrameLength >> 8) & 0xFF);
+ CurrentPlace++;
+ *CurrentPlace = (UINT8)(FrameLength & 0xFF);
+ CurrentPlace++;
+
+ //
+ // Set DSAP, SSAP and Control
+ //
+ *CurrentPlace = 0xAA;
+ CurrentPlace++;
+ *CurrentPlace = 0xAA;
+ CurrentPlace++;
+ *CurrentPlace = 0x03;
+ CurrentPlace++;
+
+ //
+ // Copy in ProtocolID
+ //
+ RtlCopyMemory(CurrentPlace, &(ProtocolID[1]), 5);
+ CurrentPlace += 5;
+
+ break;
+
+ //
+ // Ethernet Raw 802.3
+ //
+ case ETHERNET_802_3_FRAME_ID:
+
+ FrameLength += 2;
+
+ //
+ // Set FrameLength
+ //
+ *CurrentPlace = (UINT8)((FrameLength >> 8) & 0xFF);
+ CurrentPlace++;
+ *CurrentPlace = (UINT8)(FrameLength & 0xFF);
+ CurrentPlace++;
+
+ break;
+
+
+ //
+ // Ethernet II
+ //
+ case ETHERNET_II_FRAME_ID:
+
+ FrameLength += 2;
+
+ //
+ // Set FrameType
+ //*\\ Is this right? - Ethernet II, where is FrameType stored in ProtocolID?
+ *CurrentPlace = (UINT8)ProtocolID[4];
+ CurrentPlace++;
+ *CurrentPlace = (UINT8)ProtocolID[5];
+ CurrentPlace++;
+
+ break;
+
+
+ default:
+
+ //
+ // Should never happen
+ //
+ ASSERT(0);
+ break;
+
+ }
+
+ break;
+
+
+ case NdisMediumFddi:
+
+ //
+ // Set FCByte
+ //
+ *CurrentPlace = 0x57;
+ CurrentPlace ++;
+
+ //
+ // Set DestinationAddress
+ //
+ RtlCopyMemory(CurrentPlace, DestinationAddress, 6);
+ CurrentPlace += 6;
+
+ //
+ // Set SourceAddress
+ //
+ RtlCopyMemory(CurrentPlace, Mlid->ConfigTable.MLIDCFG_NodeAddress, 6);
+ CurrentPlace += 6;
+
+ FrameLength += 13;
+
+ //
+ // Switch on frame type
+ //
+ switch (Mlid->ConfigTable.MLIDCFG_FrameID) {
+
+ //
+ // FDDI 802.2
+ //
+ case FDDI_802_2_FRAME_ID:
+
+ if (ProtocolID[0] > 2) {
+
+ //
+ // Type II header
+ //
+ FrameLength += 6;
+
+ } else {
+
+ //
+ // Type I header
+ //
+ FrameLength += 5;
+ }
+
+ //
+ // Set FrameLength
+ //
+ *CurrentPlace = (UINT8)((FrameLength >> 8) & 0xFF);
+ CurrentPlace++;
+ *CurrentPlace = (UINT8)(FrameLength & 0xFF);
+ CurrentPlace++;
+
+ //
+ // Set DSAP, SSAP and Control
+ //
+ if (ProtocolID[0] < 2) {
+
+ *CurrentPlace = ProtocolID[5];
+ CurrentPlace++;
+ *CurrentPlace = ProtocolID[5];
+ CurrentPlace++;
+ *CurrentPlace = 0x03;
+ CurrentPlace++;
+
+ } else if (ProtocolID[0] == 2) {
+
+ //
+ // Type I header
+ //
+
+ *CurrentPlace = ProtocolID[3];
+ CurrentPlace++;
+ *CurrentPlace = ProtocolID[4];
+ CurrentPlace++;
+ *CurrentPlace = ProtocolID[5];
+ CurrentPlace++;
+
+ } else {
+
+ //
+ // Type II header
+ //
+
+ *CurrentPlace = ProtocolID[2];
+ CurrentPlace++;
+ *CurrentPlace = ProtocolID[3];
+ CurrentPlace++;
+ *CurrentPlace = ProtocolID[4];
+ CurrentPlace++;
+ *CurrentPlace = ProtocolID[5];
+ CurrentPlace++;
+
+ }
+
+ break;
+
+ //
+ // Fddi SNAP
+ //
+ case FDDI_SNAP_FRAME_ID:
+
+ FrameLength += 10;
+
+ //
+ // Set FrameLength
+ //
+ *CurrentPlace = (UINT8)((FrameLength >> 8) & 0xFF);
+ CurrentPlace++;
+ *CurrentPlace = (UINT8)(FrameLength & 0xFF);
+ CurrentPlace++;
+
+ //
+ // Set DSAP, SSAP and Control
+ //
+ *CurrentPlace = 0xAA;
+ CurrentPlace++;
+ *CurrentPlace = 0xAA;
+ CurrentPlace++;
+ *CurrentPlace = 0x03;
+ CurrentPlace++;
+
+ //
+ // Copy in ProtocolID
+ //
+ RtlCopyMemory(CurrentPlace, &(ProtocolID[1]), 5);
+ CurrentPlace += 5;
+
+ break;
+
+ default:
+
+ //
+ // Should never happen
+ //
+ ASSERT(0);
+ break;
+
+ }
+
+ break;
+
+
+ default:
+
+ //
+ // Should never happen
+ //
+ ASSERT(0);
+ break;
+
+ }
+
+ Reserved->MediaHeaderLength = FrameLength - DataLength;
+
+}