590 lines
14 KiB
C
590 lines
14 KiB
C
/*++
|
||
|
||
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);
|
||
|
||
}
|
||
|