NT4/private/ntos/ndis/lsl/mlidrcv.c
2020-09-30 17:12:29 +02:00

590 lines
14 KiB
C
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
Copyright (c) 1990 Microsoft Corporation
Module Name:
mlidrcv.c
Abstract:
This file contains all routines for receiving 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"
UINT32
ReceiveGetFrameType(
PMLID_STRUCT Mlid,
PUINT8 MediaHeader,
PUINT8 DataBuffer
)
/*++
Routine Description:
This routine returns the ODI FrameID of the MediaHeader and DataBuffer supplied.
It examines them to make a determination.
NOTE: This routine assumes that MediaHeader and DataBuffer have sufficient
bytes to make a determination.
NOTE: Called with Mlid->MlidSpinLock held!!
Arguments:
Mlid - Pointer to MLID struct that this came in on.
MediaHeader - Pointer to the raw media header as defined by NDIS 3.0
MediaHeaderLength - Length of the media header.
DataBuffer - Pointer to the rest of the packet.
FrameLength - Length of the NDIS 3.0 data portion of the packet.
Return Value:
ODI FrameID.
--*/
{
//
// Switch on media type
//
switch (Mlid->NdisMlidMedium) {
case NdisMedium802_5:
//
// Find frame type
//
if ((DataBuffer[0] == 0xAA) &&
(DataBuffer[1] == 0xAA) &&
(DataBuffer[2] == 0x03)) {
return(TOKEN_RING_SNAP_FRAME_ID);
}
return(TOKEN_RING_802_2_FRAME_ID);
break;
case NdisMedium802_3:
if (*((USHORT UNALIGNED *)(&(MediaHeader[13]))) > 1500) {
return(ETHERNET_II_FRAME_ID);
}
if ((DataBuffer[0] == 0xFF) && (DataBuffer[1] == 0xFF)) {
return(ETHERNET_802_3_FRAME_ID);
}
if ((DataBuffer[0] == 0xAA) &&
(DataBuffer[1] == 0xAA) &&
(DataBuffer[2] == 0x03)) {
return(ETHERNET_SNAP_FRAME_ID);
}
return(ETHERNET_802_2_FRAME_ID);
break;
case NdisMediumFddi:
//
// Check for short addresses (unsupported)
//
if ((MediaHeader[0] & 0x40) == 0) {
return((UINT32)-1);
}
//
// Find frame type
//
if ((DataBuffer[0] == 0xAA) &&
(DataBuffer[1] == 0xAA) &&
(DataBuffer[2] == 0x03)) {
return(FDDI_SNAP_FRAME_ID);
}
return(FDDI_802_2_FRAME_ID);
break;
default:
//
// Should never happen
//
ASSERT(0);
break;
}
}
VOID
ReceiveGetProtocolID(
PMLID_STRUCT Mlid,
PLOOKAHEAD OdiLookAhead,
UINT32 FrameID
)
/*++
Routine Description:
This routine sets the ProtocolID field in the lookahead structure. It examines
the lookahead structure media header and data pointer, so these must be filled in.
NOTE: Called with Mlid->MlidSpinLock held!!
Arguments:
Mlid - Pointer to the MLID which received the packet.
OdiLookAhead - Pointer to a partially filled in lookahead structure.
FrameID - Frame ID of the received frame.
Return Value:
None.
--*/
{
PUINT8 DSAPArea;
RtlZeroMemory(OdiLookAhead->LkAhd_ProtocolID, 6);
switch (FrameID) {
case ETHERNET_II_FRAME_ID:
OdiLookAhead->LkAhd_ProtocolID[4] = OdiLookAhead->LkAhd_MediaHeaderPtr[12];
OdiLookAhead->LkAhd_ProtocolID[5] = OdiLookAhead->LkAhd_MediaHeaderPtr[13];
break;
case ETHERNET_802_3_FRAME_ID:
break;
case ETHERNET_SNAP_FRAME_ID:
RtlCopyMemory(&(OdiLookAhead->LkAhd_ProtocolID[1]),
&(OdiLookAhead->LkAhd_MediaHeaderPtr[17]),
5
);
break;
case ETHERNET_802_2_FRAME_ID:
if (OdiLookAhead->LkAhd_MediaHeaderPtr[16] != 0x03) {
//
// A Type II frame
//
OdiLookAhead->LkAhd_ProtocolID[0] = 0x3;
OdiLookAhead->LkAhd_ProtocolID[2] = OdiLookAhead->LkAhd_MediaHeaderPtr[14];
OdiLookAhead->LkAhd_ProtocolID[3] = OdiLookAhead->LkAhd_MediaHeaderPtr[15];
OdiLookAhead->LkAhd_ProtocolID[4] = OdiLookAhead->LkAhd_MediaHeaderPtr[16];
OdiLookAhead->LkAhd_ProtocolID[5] = OdiLookAhead->LkAhd_MediaHeaderPtr[17];
} else {
//
// A Type I frame
//
if (OdiLookAhead->LkAhd_MediaHeaderPtr[14] !=
OdiLookAhead->LkAhd_MediaHeaderPtr[15]) {
OdiLookAhead->LkAhd_ProtocolID[0] = 0x2;
OdiLookAhead->LkAhd_ProtocolID[3] = OdiLookAhead->LkAhd_MediaHeaderPtr[14];
OdiLookAhead->LkAhd_ProtocolID[4] = OdiLookAhead->LkAhd_MediaHeaderPtr[15];
OdiLookAhead->LkAhd_ProtocolID[5] = OdiLookAhead->LkAhd_MediaHeaderPtr[16];
} else {
OdiLookAhead->LkAhd_ProtocolID[5] = OdiLookAhead->LkAhd_MediaHeaderPtr[14];
}
}
break;
case TOKEN_RING_SNAP_FRAME_ID:
if (OdiLookAhead->LkAhd_MediaHeaderPtr[8] & 0x80) {
//
// Skip Source Routining info
//
DSAPArea = OdiLookAhead->LkAhd_MediaHeaderPtr +
14 +
(OdiLookAhead->LkAhd_MediaHeaderPtr[14] & 0x0F);
} else{
DSAPArea = OdiLookAhead->LkAhd_MediaHeaderPtr + 14;
}
RtlCopyMemory(&(OdiLookAhead->LkAhd_ProtocolID[1]),
DSAPArea + 3,
5
);
break;
case TOKEN_RING_802_2_FRAME_ID:
if (OdiLookAhead->LkAhd_MediaHeaderPtr[8] & 0x80) {
//
// Skip Source Routining info
//
DSAPArea = OdiLookAhead->LkAhd_MediaHeaderPtr +
14 +
(OdiLookAhead->LkAhd_MediaHeaderPtr[14] & 0x0F);
} else {
DSAPArea = OdiLookAhead->LkAhd_MediaHeaderPtr + 14;
}
if (DSAPArea[2] != 0x03) {
//
// A Type II frame
//
OdiLookAhead->LkAhd_ProtocolID[0] = 0x3;
OdiLookAhead->LkAhd_ProtocolID[2] = DSAPArea[0];
OdiLookAhead->LkAhd_ProtocolID[3] = DSAPArea[1];
OdiLookAhead->LkAhd_ProtocolID[4] = DSAPArea[2];
OdiLookAhead->LkAhd_ProtocolID[5] = DSAPArea[3];
} else {
//
// A Type I frame
//
if (DSAPArea[0] != DSAPArea[1]) {
OdiLookAhead->LkAhd_ProtocolID[0] = 0x2;
OdiLookAhead->LkAhd_ProtocolID[3] = DSAPArea[0];
OdiLookAhead->LkAhd_ProtocolID[4] = DSAPArea[1];
OdiLookAhead->LkAhd_ProtocolID[5] = DSAPArea[2];
} else {
OdiLookAhead->LkAhd_ProtocolID[5] = DSAPArea[0];
}
}
break;
case FDDI_SNAP_FRAME_ID:
RtlCopyMemory(&(OdiLookAhead->LkAhd_ProtocolID[1]),
&(OdiLookAhead->LkAhd_MediaHeaderPtr[18]),
5
);
break;
case FDDI_802_2_FRAME_ID:
if (OdiLookAhead->LkAhd_MediaHeaderPtr[17] != 0x03) {
//
// A Type II frame
//
OdiLookAhead->LkAhd_ProtocolID[0] = 0x3;
OdiLookAhead->LkAhd_ProtocolID[2] = OdiLookAhead->LkAhd_MediaHeaderPtr[15];
OdiLookAhead->LkAhd_ProtocolID[3] = OdiLookAhead->LkAhd_MediaHeaderPtr[16];
OdiLookAhead->LkAhd_ProtocolID[4] = OdiLookAhead->LkAhd_MediaHeaderPtr[17];
OdiLookAhead->LkAhd_ProtocolID[5] = OdiLookAhead->LkAhd_MediaHeaderPtr[18];
} else {
//
// A Type I frame
//
if (OdiLookAhead->LkAhd_MediaHeaderPtr[15] !=
OdiLookAhead->LkAhd_MediaHeaderPtr[16]) {
OdiLookAhead->LkAhd_ProtocolID[0] = 0x2;
OdiLookAhead->LkAhd_ProtocolID[3] = OdiLookAhead->LkAhd_MediaHeaderPtr[15];
OdiLookAhead->LkAhd_ProtocolID[4] = OdiLookAhead->LkAhd_MediaHeaderPtr[16];
OdiLookAhead->LkAhd_ProtocolID[5] = OdiLookAhead->LkAhd_MediaHeaderPtr[17];
} else {
OdiLookAhead->LkAhd_ProtocolID[5] = OdiLookAhead->LkAhd_MediaHeaderPtr[15];
}
}
break;
}
}
VOID
ReceiveSetDestinationType(
PMLID_STRUCT Mlid,
PLOOKAHEAD OdiLookAhead
)
/*++
Routine Description:
This routine sets the DestType field in the lookahead structure. It examines
the lookahead structure media header and data pointer, so these must be filled in.
NOTE: Require the ImmediateAddress field to be filled with the source address.
NOTE: Called with Mlid->MlidSpinLock held!!
Arguments:
Mlid - Pointer to MLID receiving the packet.
OdiLookAhead - Pointer to a partially filled in lookahead structure.
Return Value:
None.
--*/
{
BOOLEAN Result;
if (OdiLookAhead->LkAhd_PktAttr != 0) {
OdiLookAhead->LkAhd_DestType = 0x20; // Global Error
return;
}
OdiLookAhead->LkAhd_DestType = 0x0;
switch (Mlid->NdisMlidMedium) {
case NdisMedium802_3:
//*\\ Does not support setting MulticastRemote bit in DestType. Is this OK?
if (ETH_IS_BROADCAST(OdiLookAhead->LkAhd_ImmediateAddress)) {
OdiLookAhead->LkAhd_DestType = 0x3; // Broadcast
return;
}
if (ETH_IS_MULTICAST(OdiLookAhead->LkAhd_ImmediateAddress)) {
OdiLookAhead->LkAhd_DestType = 0x1; // Multicast
return;
}
COMPARE_NETWORK_ADDRESSES(OdiLookAhead->LkAhd_ImmediateAddress,
Mlid->ConfigTable.MLIDCFG_NodeAddress,
&Result);
if (Result) {
OdiLookAhead->LkAhd_DestType = 0x80; // Direct
return;
}
OdiLookAhead->LkAhd_DestType = 0x4; // Directed to another station
break;
case NdisMedium802_5:
//
// First check for SR Info
//
if (OdiLookAhead->LkAhd_ImmediateAddress[0] & 0x80) {
//
// Yes
//
if (Mlid->ConfigTable.MLIDCFG_SourceRouting == NULL) {
//
// Set bit and exit
//
OdiLookAhead->LkAhd_DestType = 0x10; // No Source Routing
return;
}
}
TR_IS_BROADCAST(OdiLookAhead->LkAhd_ImmediateAddress, &Result);
if (Result == TRUE) {
OdiLookAhead->LkAhd_DestType = 0x3; // Broadcast
return;
}
TR_IS_GROUP(OdiLookAhead->LkAhd_ImmediateAddress, &Result);
if (Result == TRUE) {
OdiLookAhead->LkAhd_DestType = 0x1; // Multicast
return;
}
TR_IS_FUNCTIONAL(OdiLookAhead->LkAhd_ImmediateAddress, &Result);
if (Result == TRUE) {
OdiLookAhead->LkAhd_DestType = 0x1; // Multicast
return;
}
COMPARE_NETWORK_ADDRESSES(OdiLookAhead->LkAhd_ImmediateAddress,
Mlid->ConfigTable.MLIDCFG_NodeAddress,
&Result);
if (Result) {
OdiLookAhead->LkAhd_DestType = 0x80; // Direct
return;
}
OdiLookAhead->LkAhd_DestType = 0x4; // Directed to another station
break;
case NdisMediumFddi:
if (ETH_IS_BROADCAST(OdiLookAhead->LkAhd_ImmediateAddress)) {
OdiLookAhead->LkAhd_DestType = 0x3; // Broadcast
return;
}
if (ETH_IS_MULTICAST(OdiLookAhead->LkAhd_ImmediateAddress)) {
OdiLookAhead->LkAhd_DestType = 0x1; // Multicast
return;
}
COMPARE_NETWORK_ADDRESSES(OdiLookAhead->LkAhd_ImmediateAddress,
Mlid->ConfigTable.MLIDCFG_NodeAddress,
&Result);
if (Result) {
OdiLookAhead->LkAhd_DestType = 0x80; // Direct
return;
}
OdiLookAhead->LkAhd_DestType = 0x4; // Directed to another station
break;
}
}
NDIS_STATUS
BuildReceiveBufferChain(
PMLID_STRUCT Mlid,
PNDIS_PACKET NdisReceivePacket,
PECB ReceiveECB
)
/*++
Routine Description:
This routine builds an MDL chain describing the ECB fragment list
and attaches it to the NDIS_PACKET.
NOTE: Called with Mlid->MlidSpinLock held!!
Arguments:
Mlid - Owning Mlid.
Packet - Pointer to the NDIS_PACKET to free.
Return Value:
None.
--*/
{
UINT32 i;
PNDIS_BUFFER NdisBuffer;
NDIS_STATUS NdisStatus;
//
// Convert ECB fragment list into an MDL chain
//
for (i = 0; i < ReceiveECB->ECB_FragmentCount; i++) {
NdisAllocateBuffer(
&NdisStatus,
&NdisBuffer,
Mlid->ReceiveBufferPool,
ReceiveECB->ECB_Fragment[i].FragmentAddress,
ReceiveECB->ECB_Fragment[i].FragmentLength
);
if (NdisStatus != NDIS_STATUS_SUCCESS) {
//
// Unchain all NDIS_BUFFERs from packet
//
NdisUnchainBufferAtFront(
NdisReceivePacket,
&NdisBuffer
);
while (NdisBuffer != NULL) {
NdisFreeBuffer(NdisBuffer);
NdisUnchainBufferAtFront(
NdisReceivePacket,
&NdisBuffer
);
}
return(NDIS_STATUS_RESOURCES);
}
NdisChainBufferAtBack(
NdisReceivePacket,
NdisBuffer
);
}
return(NDIS_STATUS_SUCCESS);
}