Source code of Windows XP (NT5)
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.
 
 
 
 
 
 

4972 lines
100 KiB

/*++
Copyright (c) 1997 FORE Systems, Inc.
Copyright (c) 1997 Microsoft Corporation
Module Name:
elanpkt.c
Abstract:
Revision History:
Notes:
--*/
#include <precomp.h>
#pragma hdrstop
VOID
AtmLaneSendConfigureRequest(
IN PATMLANE_ELAN pElan
)
/*++
Routine Description:
Send an LE_CONFIGURE_REQUEST for the given ELAN to the LECS.
It is assumed that caller holds a lock on the ELAN structure
and it will be released here.
Arguments:
pElan - Pointer to ATMLANE elan structure
Return Value:
None
--*/
{
PATMLANE_ATM_ENTRY pAtmEntry;
PATMLANE_VC pVc;
PNDIS_PACKET pNdisPacket;
PNDIS_BUFFER pNdisBuffer;
PUCHAR pPkt;
LANE_CONTROL_FRAME UNALIGNED * pCf;
ULONG ulTemp;
NDIS_STATUS Status;
ULONG rc;
DBGP((3, "SendConfigureRequest: Elan %x\n", pElan));
//
// Initialize
//
pNdisPacket = (PNDIS_PACKET)NULL;
pNdisBuffer = (PNDIS_BUFFER)NULL;
Status = NDIS_STATUS_SUCCESS;
pVc = NULL_PATMLANE_VC;
do
{
ACQUIRE_ELAN_ATM_LIST_LOCK(pElan);
pAtmEntry = pElan->pLecsAtmEntry;
if (pAtmEntry == NULL_PATMLANE_ATM_ENTRY)
{
RELEASE_ELAN_ATM_LIST_LOCK(pElan);
Status = NDIS_STATUS_FAILURE;
break;
}
ACQUIRE_ATM_ENTRY_LOCK_DPC(pAtmEntry);
pVc = pAtmEntry->pVcList;
if (pVc == NULL_PATMLANE_VC)
{
RELEASE_ATM_ENTRY_LOCK_DPC(pAtmEntry);
RELEASE_ELAN_ATM_LIST_LOCK(pElan);
break;
}
//
// Reference the VC to keep it around
//
ACQUIRE_VC_LOCK_DPC(pVc);
AtmLaneReferenceVc(pVc, "temp");
RELEASE_VC_LOCK_DPC(pVc);
RELEASE_ATM_ENTRY_LOCK_DPC(pAtmEntry);
RELEASE_ELAN_ATM_LIST_LOCK(pElan);
//
// Allocate the Ndis packet header.
//
pNdisPacket = AtmLaneAllocProtoPacket(pElan);
if ((PNDIS_PACKET)NULL == pNdisPacket)
{
DBGP((0, "SendConfigureRequest: allocate packet failed\n"));
Status = NDIS_STATUS_RESOURCES;
break;
}
//
// Allocate the protocol buffer
//
pNdisBuffer = AtmLaneAllocateProtoBuffer(
pElan,
pElan->ProtocolBufSize,
&(pPkt)
);
if ((PNDIS_BUFFER)NULL == pNdisBuffer)
{
DBGP((0, "SendConfigureRequest: allocate proto buffer failed\n"));
Status = NDIS_STATUS_RESOURCES;
break;
}
//
// Fill in the packet with LE_CONFIGURE_REQUEST
//
NdisZeroMemory(pPkt, pElan->ProtocolBufSize);
pCf = (PLANE_CONTROL_FRAME)pPkt;
pCf->Marker = LANE_CONTROL_MARKER;
pCf->Protocol = LANE_PROTOCOL;
pCf->Version = LANE_VERSION;
pCf->OpCode = LANE_CONFIGURE_REQUEST;
ulTemp = NdisInterlockedIncrement(&pElan->TransactionId);
pCf->Tid = SWAPULONG(ulTemp);
pCf->SourceMacAddress.Type = LANE_MACADDRTYPE_MACADDR;
if (pElan->LanType == LANE_LANTYPE_TR)
{
NdisMoveMemory(
&pCf->SourceMacAddress.Byte,
&pElan->MacAddressTr,
sizeof(MAC_ADDRESS)
);
}
else
{
NdisMoveMemory(
&pCf->SourceMacAddress.Byte,
&pElan->MacAddressEth,
sizeof(MAC_ADDRESS)
);
}
NdisMoveMemory(
&pCf->SourceAtmAddr,
&pElan->AtmAddress.Address,
ATM_ADDRESS_LENGTH
);
DBGP((4, "%d: sending Config Req, Elan %x has LanType %d, CfgLanType %d\n",
pElan->ElanNumber,
pElan,
pElan->LanType,
pElan->CfgLanType));
pCf->LanType = LANE_LANTYPE_UNSPEC;
pCf->MaxFrameSize = (UCHAR) pElan->CfgMaxFrameSizeCode;
pCf->ElanNameSize = pElan->ElanNameSize;
NdisMoveMemory(
&pCf->ElanName,
pElan->ElanName,
LANE_ELANNAME_SIZE_MAX
);
//
// Link the ndis buffer to the ndis packet
//
NdisChainBufferAtFront(pNdisPacket, pNdisBuffer);
//
// Reacquire VC lock and if VC still connected send packet
//
ACQUIRE_VC_LOCK(pVc);
if (IS_FLAG_SET(
pVc->Flags,
VC_CALL_STATE_MASK,
VC_CALL_STATE_ACTIVE))
{
AtmLaneSendPacketOnVc(pVc, pNdisPacket, FALSE);
//
// VC lock released in above
//
}
else
{
Status = NDIS_STATUS_FAILURE;
RELEASE_VC_LOCK(pVc);
}
}
while (FALSE);
//
// Remove temp VC reference
//
if (pVc != NULL_PATMLANE_VC)
{
ACQUIRE_VC_LOCK(pVc);
rc = AtmLaneDereferenceVc(pVc, "temp");
if (rc > 0)
{
RELEASE_VC_LOCK(pVc);
}
//
// else VC is gone
//
}
//
// Cleanup if failure
//
if (Status != NDIS_STATUS_SUCCESS)
{
if (pNdisPacket != (PNDIS_PACKET)NULL)
{
AtmLaneFreeProtoPacket(pElan, pNdisPacket);
}
if (pNdisBuffer != (PNDIS_BUFFER)NULL)
{
AtmLaneFreeProtoBuffer(pElan, pNdisBuffer);
}
}
TRACEOUT(SendConfigureRequest);
return;
}
VOID
AtmLaneSendJoinRequest(
IN PATMLANE_ELAN pElan
)
/*++
Routine Description:
Send an LE_JOIN_REQUEST for the given ELAN to the LES.
It is assumed that caller holds a lock on the ELAN structure
and it will be released here.
Arguments:
pElan - Pointer to ATMLANE elan structure
Return Value:
None
--*/
{
PATMLANE_ATM_ENTRY pAtmEntry;
PATMLANE_VC pVc;
PNDIS_PACKET pNdisPacket;
PNDIS_BUFFER pNdisBuffer;
PUCHAR pPkt;
LANE_CONTROL_FRAME UNALIGNED * pCf;
ULONG ulTemp;
NDIS_STATUS Status;
ULONG rc;
TRACEIN(SendJoinRequest);
DBGP((3, "SendJoinRequest: Elan %x\n", pElan));
//
// Initialize
//
pNdisPacket = (PNDIS_PACKET)NULL;
pNdisBuffer = (PNDIS_BUFFER)NULL;
Status = NDIS_STATUS_SUCCESS;
pVc = NULL_PATMLANE_VC;
do
{
ACQUIRE_ELAN_ATM_LIST_LOCK(pElan);
pAtmEntry = pElan->pLesAtmEntry;
if (pAtmEntry == NULL_PATMLANE_ATM_ENTRY)
{
RELEASE_ELAN_ATM_LIST_LOCK(pElan);
Status = NDIS_STATUS_FAILURE;
break;
}
ACQUIRE_ATM_ENTRY_LOCK_DPC(pAtmEntry);
pVc = pAtmEntry->pVcList;
if (pVc == NULL_PATMLANE_VC)
{
RELEASE_ATM_ENTRY_LOCK_DPC(pAtmEntry);
RELEASE_ELAN_ATM_LIST_LOCK(pElan);
break;
}
//
// Reference the VC to keep it around
//
ACQUIRE_VC_LOCK_DPC(pVc);
AtmLaneReferenceVc(pVc, "temp");
RELEASE_VC_LOCK_DPC(pVc);
RELEASE_ATM_ENTRY_LOCK_DPC(pAtmEntry);
RELEASE_ELAN_ATM_LIST_LOCK(pElan);
//
// Allocate the Ndis packet header.
//
pNdisPacket = AtmLaneAllocProtoPacket(pElan);
if ((PNDIS_PACKET)NULL == pNdisPacket)
{
DBGP((0, "SendJoinRequest: allocate packet failed\n"));
Status = NDIS_STATUS_RESOURCES;
break;
}
//
// Allocate the protocol buffer
//
pNdisBuffer = AtmLaneAllocateProtoBuffer(
pElan,
pElan->ProtocolBufSize,
&(pPkt)
);
if ((PNDIS_BUFFER)NULL == pNdisBuffer)
{
DBGP((0, "SendJoinRequest: allocate proto buffer failed\n"));
Status = NDIS_STATUS_RESOURCES;
break;
}
//
// Fill in the packet with LE_JOIN_REQUEST
//
NdisZeroMemory(pPkt, pElan->ProtocolBufSize);
pCf = (PLANE_CONTROL_FRAME)pPkt;
pCf->Marker = LANE_CONTROL_MARKER;
pCf->Protocol = LANE_PROTOCOL;
pCf->Version = LANE_VERSION;
pCf->OpCode = LANE_JOIN_REQUEST;
ulTemp = NdisInterlockedIncrement(&pElan->TransactionId);
pCf->Tid = SWAPULONG(ulTemp);
pCf->SourceMacAddress.Type = LANE_MACADDRTYPE_MACADDR;
if (pElan->LanType == LANE_LANTYPE_TR)
{
NdisMoveMemory(
&pCf->SourceMacAddress.Byte,
&pElan->MacAddressTr,
sizeof(MAC_ADDRESS)
);
}
else
{
DBGP((0, "%d Send Join with MAC addr: %s\n",
pElan->ElanNumber,
MacAddrToString(&pElan->MacAddressEth)));
NdisMoveMemory(
&pCf->SourceMacAddress.Byte,
&pElan->MacAddressEth,
sizeof(MAC_ADDRESS)
);
}
NdisMoveMemory(
&pCf->SourceAtmAddr,
&pElan->AtmAddress.Address,
ATM_ADDRESS_LENGTH
);
pCf->LanType = pElan->LanType;
pCf->MaxFrameSize = pElan->MaxFrameSizeCode;
pCf->ElanNameSize = pElan->ElanNameSize;
NdisMoveMemory(
&pCf->ElanName,
pElan->ElanName,
LANE_ELANNAME_SIZE_MAX
);
//
// Link the ndis buffer to the ndis packet
//
NdisChainBufferAtFront(pNdisPacket, pNdisBuffer);
//
// Reacquire VC lock and if VC still connected send packet
//
ACQUIRE_VC_LOCK(pVc);
if (IS_FLAG_SET(
pVc->Flags,
VC_CALL_STATE_MASK,
VC_CALL_STATE_ACTIVE))
{
AtmLaneSendPacketOnVc(pVc, pNdisPacket, FALSE);
//
// VC lock released in above
//
}
else
{
Status = NDIS_STATUS_FAILURE;
RELEASE_VC_LOCK(pVc);
}
}
while (FALSE);
//
// Remove temp VC reference
//
if (pVc != NULL_PATMLANE_VC)
{
ACQUIRE_VC_LOCK(pVc);
rc = AtmLaneDereferenceVc(pVc, "temp");
if (rc > 0)
{
RELEASE_VC_LOCK(pVc);
}
//
// else VC is gone
//
}
//
// Cleanup if failure
//
if (Status != NDIS_STATUS_SUCCESS)
{
if (pNdisPacket != (PNDIS_PACKET)NULL)
{
AtmLaneFreeProtoPacket(pElan, pNdisPacket);
}
if (pNdisBuffer != (PNDIS_BUFFER)NULL)
{
AtmLaneFreeProtoBuffer(pElan, pNdisBuffer);
}
}
TRACEOUT(SendJoinRequest);
return;
}
VOID
AtmLaneSendArpRequest(
IN PATMLANE_ELAN pElan,
IN PATMLANE_MAC_ENTRY pMacEntry LOCKIN NOLOCKOUT
)
/*++
Routine Description:
Send an LE_ARP_REQUEST for a particular Mac Entry to the LES.
Arguments:
pElan - Pointer to ATMLANE elan structure
pMacEntry - Pointer to ATMLANE Mac Entry for which
to send the LE_ARP_REQUEST.
Return Value:
None
--*/
{
PATMLANE_ATM_ENTRY pAtmEntry;
PATMLANE_VC pVc;
PNDIS_PACKET pNdisPacket;
PNDIS_BUFFER pNdisBuffer;
PUCHAR pPkt;
LANE_CONTROL_FRAME UNALIGNED * pCf;
ULONG ulTemp;
NDIS_STATUS Status;
ULONG rc;
BOOLEAN MacEntryLockReleased;
TRACEIN(SendArpRequest);
DBGP((3, "SendArpRequest: Elan %x MacEntry %x\n",
pElan, pMacEntry));
//
// Initialize
//
pNdisPacket = (PNDIS_PACKET)NULL;
pNdisBuffer = (PNDIS_BUFFER)NULL;
Status = NDIS_STATUS_SUCCESS;
pVc = NULL_PATMLANE_VC;
MacEntryLockReleased = FALSE;
do
{
ACQUIRE_ELAN_ATM_LIST_LOCK(pElan);
pAtmEntry = pElan->pLesAtmEntry;
if (pAtmEntry == NULL_PATMLANE_ATM_ENTRY)
{
RELEASE_ELAN_ATM_LIST_LOCK(pElan);
Status = NDIS_STATUS_FAILURE;
break;
}
ACQUIRE_ATM_ENTRY_LOCK_DPC(pAtmEntry);
pVc = pAtmEntry->pVcList;
if (pVc == NULL_PATMLANE_VC)
{
RELEASE_ATM_ENTRY_LOCK_DPC(pAtmEntry);
RELEASE_ELAN_ATM_LIST_LOCK(pElan);
break;
}
//
// Reference the VC to keep it around
//
ACQUIRE_VC_LOCK_DPC(pVc);
AtmLaneReferenceVc(pVc, "temp");
RELEASE_VC_LOCK_DPC(pVc);
RELEASE_ATM_ENTRY_LOCK_DPC(pAtmEntry);
RELEASE_ELAN_ATM_LIST_LOCK(pElan);
//
// Allocate the Ndis packet header.
//
pNdisPacket = AtmLaneAllocProtoPacket(pElan);
if ((PNDIS_PACKET)NULL == pNdisPacket)
{
DBGP((0, "SendArpRequest: allocate packet failed\n"));
Status = NDIS_STATUS_RESOURCES;
break;
}
//
// Allocate the protocol buffer
//
pNdisBuffer = AtmLaneAllocateProtoBuffer(
pElan,
pElan->ProtocolBufSize,
&(pPkt)
);
if ((PNDIS_BUFFER)NULL == pNdisBuffer)
{
DBGP((0, "SendArpRequest: allocate proto buffer failed\n"));
Status = NDIS_STATUS_RESOURCES;
break;
}
//
// Fill in the packet with LE_ARP_REQUEST
//
NdisZeroMemory(pPkt, pElan->ProtocolBufSize);
pCf = (PLANE_CONTROL_FRAME)pPkt;
pCf->Marker = LANE_CONTROL_MARKER;
pCf->Protocol = LANE_PROTOCOL;
pCf->Version = LANE_VERSION;
pCf->OpCode = LANE_ARP_REQUEST;
ulTemp = NdisInterlockedIncrement(&pElan->TransactionId);
pCf->Tid = SWAPULONG(ulTemp);
pCf->LecId = pElan->LecId; // already swapped
//
// Leave SourceMacAddress zero (not present).
// TargetMacAddress is what we are looking for!
//
pCf->TargetMacAddress.Type = (USHORT) pMacEntry->MacAddrType;
NdisMoveMemory(
&pCf->TargetMacAddress.Byte,
&pMacEntry->MacAddress,
sizeof(MAC_ADDRESS)
);
//
// SourceAtmAddr is the Elan's
//
NdisMoveMemory(
&pCf->SourceAtmAddr,
&pElan->AtmAddress.Address,
ATM_ADDRESS_LENGTH
);
//
// Store swapped Tid in MacEntry for later matching!
//
pMacEntry->ArpTid = SWAPULONG(ulTemp);
RELEASE_MAC_ENTRY_LOCK(pMacEntry);
MacEntryLockReleased = TRUE;
//
// Link the ndis buffer to the ndis packet
//
NdisChainBufferAtFront(pNdisPacket, pNdisBuffer);
//
// Reacquire VC lock and if VC still connected send packet
//
ACQUIRE_VC_LOCK(pVc);
if (IS_FLAG_SET(
pVc->Flags,
VC_CALL_STATE_MASK,
VC_CALL_STATE_ACTIVE))
{
DBGP((2, "SendArpRequest: %s Sending ARP Request: Atm Entry %x pVc %x\n",
MacAddrToString(&pMacEntry->MacAddress), pAtmEntry, pVc));
AtmLaneSendPacketOnVc(pVc, pNdisPacket, FALSE);
//
// VC lock released in above
//
}
else
{
Status = NDIS_STATUS_FAILURE;
RELEASE_VC_LOCK(pVc);
}
}
while (FALSE);
if (!MacEntryLockReleased)
{
RELEASE_MAC_ENTRY_LOCK(pMacEntry);
}
//
// Remove temp VC reference
//
if (pVc != NULL_PATMLANE_VC)
{
ACQUIRE_VC_LOCK(pVc);
rc = AtmLaneDereferenceVc(pVc, "temp");
if (rc > 0)
{
RELEASE_VC_LOCK(pVc);
}
//
// else VC is gone
//
}
//
// Cleanup if failure
//
if (Status != NDIS_STATUS_SUCCESS)
{
if (pNdisPacket != (PNDIS_PACKET)NULL)
{
AtmLaneFreeProtoPacket(pElan, pNdisPacket);
}
if (pNdisBuffer != (PNDIS_BUFFER)NULL)
{
AtmLaneFreeProtoBuffer(pElan, pNdisBuffer);
}
}
TRACEOUT(SendArpRequest);
return;
}
VOID
AtmLaneSendReadyQuery(
IN PATMLANE_ELAN pElan,
IN PATMLANE_VC pVc LOCKIN NOLOCKOUT
)
/*++
Routine Description:
Sends a READY_QUERY frame on the VC.
It is assumed that caller holds a lock on the VC structure
and it will be released here.
Arguments:
pElan - Pointer to ATMLANE elan structure
pVc - Pointer to the ATMLANE VC structure
on which to send the frame.
Return Value:
None
--*/
{
PNDIS_PACKET pNdisPacket;
PNDIS_BUFFER pNdisBuffer;
ULONG TotalLength;
ULONG BufferLength;
PLANE_READY_FRAME pQueryRf;
NDIS_STATUS Status;
TRACEIN(SendReadyQuery);
//
// Initialize
//
pNdisPacket = (PNDIS_PACKET)NULL;
pNdisBuffer = (PNDIS_BUFFER)NULL;
Status = NDIS_STATUS_SUCCESS;
do
{
//
// Allocate the Ndis packet header.
//
pNdisPacket = AtmLaneAllocProtoPacket(pElan);
if ((PNDIS_PACKET)NULL == pNdisPacket)
{
DBGP((0, "SendReadyQuery: allocate packet failed\n"));
Status = NDIS_STATUS_RESOURCES;
break;
}
//
// Allocate the protocol buffer
//
pNdisBuffer = AtmLaneAllocateProtoBuffer(
pElan,
sizeof(LANE_READY_FRAME),
&((PUCHAR)(pQueryRf))
);
if ((PNDIS_BUFFER)NULL == pNdisBuffer)
{
DBGP((0, "SendReadyQuery: allocate proto buffer failed\n"));
Status = NDIS_STATUS_RESOURCES;
break;
}
//
// Fill in Indication
//
pQueryRf->Marker = LANE_CONTROL_MARKER;
pQueryRf->Protocol = LANE_PROTOCOL;
pQueryRf->Version = LANE_VERSION;
pQueryRf->OpCode = LANE_READY_QUERY;
//
// Link the ndis buffer to the ndis packet
//
NdisChainBufferAtFront(pNdisPacket, pNdisBuffer);
//
// Send it
//
DBGP((2, "SendReadyQuery: pVc %x sending READY QUERY\n", pVc));
AtmLaneSendPacketOnVc(pVc, pNdisPacket, FALSE);
//
// VC lock released in above
//
break;
}
while (FALSE);
//
// Cleanup if failure
//
if (Status != NDIS_STATUS_SUCCESS)
{
RELEASE_VC_LOCK(pVc);
if (pNdisPacket != (PNDIS_PACKET)NULL)
{
AtmLaneFreeProtoPacket(pElan, pNdisPacket);
}
if (pNdisBuffer != (PNDIS_BUFFER)NULL)
{
AtmLaneFreeProtoBuffer(pElan, pNdisBuffer);
}
}
TRACEOUT(SendReadyQuery);
return;
}
VOID
AtmLaneSendReadyIndication(
IN PATMLANE_ELAN pElan,
IN PATMLANE_VC pVc LOCKIN NOLOCKOUT
)
/*++
Routine Description:
Sends a ready indication frame on the VC.
It is assumed that caller holds a lock on the VC structure
and it will be released here.
Arguments:
pElan - Pointer to ATMLANE elan structure
pVc - Pointer to the ATMLANE VC structure
on which to send the frame.
Return Value:
None
--*/
{
ULONG TotalLength;
ULONG BufferLength;
PLANE_READY_FRAME pIndRf;
PNDIS_PACKET pNdisPacket;
PNDIS_BUFFER pNdisBuffer;
NDIS_STATUS Status;
TRACEIN(SendReadyIndication);
//
// Initialize
//
pNdisPacket = (PNDIS_PACKET)NULL;
pNdisBuffer = (PNDIS_BUFFER)NULL;
Status = NDIS_STATUS_SUCCESS;
do
{
//
// Allocate the Ndis packet header.
//
pNdisPacket = AtmLaneAllocProtoPacket(pElan);
if ((PNDIS_PACKET)NULL == pNdisPacket)
{
DBGP((0, "SendReadyIndication: allocate packet failed\n"));
Status = NDIS_STATUS_RESOURCES;
break;
}
//
// Allocate the protocol buffer
//
pNdisBuffer = AtmLaneAllocateProtoBuffer(
pElan,
sizeof(LANE_READY_FRAME),
&((PUCHAR)(pIndRf))
);
if ((PNDIS_BUFFER)NULL == pNdisBuffer)
{
DBGP((0, "SendReadyIndication: allocate proto buffer failed\n"));
Status = NDIS_STATUS_RESOURCES;
break;
}
//
// Fill in Indication
//
pIndRf->Marker = LANE_CONTROL_MARKER;
pIndRf->Protocol = LANE_PROTOCOL;
pIndRf->Version = LANE_VERSION;
pIndRf->OpCode = LANE_READY_IND;
//
// Link the ndis buffer to the ndis packet
//
NdisChainBufferAtFront(pNdisPacket, pNdisBuffer);
//
// Send it
//
DBGP((2, "SendReadyIndication: pVc %x sending READY INDICATION\n", pVc));
AtmLaneSendPacketOnVc(pVc, pNdisPacket, FALSE);
//
// VC lock released in above
//
break;
}
while (FALSE);
//
// Cleanup if failure
//
if (Status != NDIS_STATUS_SUCCESS)
{
RELEASE_VC_LOCK(pVc);
if (pNdisPacket != (PNDIS_PACKET)NULL)
{
AtmLaneFreeProtoPacket(pElan, pNdisPacket);
}
if (pNdisBuffer != (PNDIS_BUFFER)NULL)
{
AtmLaneFreeProtoBuffer(pElan, pNdisBuffer);
}
}
TRACEOUT(SendReadyIndication);
return;
}
VOID
AtmLaneSendFlushRequest(
IN PATMLANE_ELAN pElan,
IN PATMLANE_MAC_ENTRY pMacEntry LOCKIN NOLOCKOUT,
IN PATMLANE_ATM_ENTRY pAtmEntry
)
/*++
Routine Description:
Sends a flush request to the BUS for a particular MAC Entry
using the destination ATM address in the specified ATM Entry.
Arguments:
pElan - Pointer to ATMLANE Elan structure
pMacEntry - Pointer to ATMLANE Mac entry structure
pAtmEntry - Pointer to ATMLANE Atm entry structure
Return Value:
None
--*/
{
PATMLANE_ATM_ENTRY pBusAtmEntry;
PATMLANE_VC pVc;
ULONG TotalLength;
ULONG BufferLength;
ULONG ulTemp;
PLANE_CONTROL_FRAME pCf;
PNDIS_PACKET pNdisPacket;
PNDIS_BUFFER pNdisBuffer;
NDIS_STATUS Status;
ULONG rc;
BOOLEAN MacEntryLockReleased;
TRACEIN(SendFlushRequest);
//
// Initialize
//
pNdisPacket = (PNDIS_PACKET)NULL;
pNdisBuffer = (PNDIS_BUFFER)NULL;
Status = NDIS_STATUS_SUCCESS;
pVc = NULL_PATMLANE_VC;
MacEntryLockReleased = FALSE;
do
{
ACQUIRE_ELAN_ATM_LIST_LOCK(pElan);
pBusAtmEntry = pElan->pBusAtmEntry;
if (pBusAtmEntry == NULL_PATMLANE_ATM_ENTRY)
{
RELEASE_ELAN_ATM_LIST_LOCK(pElan);
Status = NDIS_STATUS_FAILURE;
break;
}
ACQUIRE_ATM_ENTRY_LOCK_DPC(pBusAtmEntry);
pVc = pBusAtmEntry->pVcList;
if (pVc == NULL_PATMLANE_VC)
{
RELEASE_ATM_ENTRY_LOCK_DPC(pBusAtmEntry);
RELEASE_ELAN_ATM_LIST_LOCK(pElan);
break;
}
//
// Reference the VC to keep it around
//
ACQUIRE_VC_LOCK_DPC(pVc);
AtmLaneReferenceVc(pVc, "temp");
RELEASE_VC_LOCK_DPC(pVc);
RELEASE_ATM_ENTRY_LOCK_DPC(pBusAtmEntry);
RELEASE_ELAN_ATM_LIST_LOCK(pElan);
//
// Allocate the Ndis packet header.
//
pNdisPacket = AtmLaneAllocProtoPacket(pElan);
if ((PNDIS_PACKET)NULL == pNdisPacket)
{
DBGP((0, "SendFlushRequest: allocate packet failed\n"));
Status = NDIS_STATUS_RESOURCES;
break;
}
//
// Allocate the protocol buffer
//
pNdisBuffer = AtmLaneAllocateProtoBuffer(
pElan,
sizeof(LANE_CONTROL_FRAME),
&((PUCHAR)(pCf))
);
if ((PNDIS_BUFFER)NULL == pNdisBuffer)
{
DBGP((0, "SendFlushRequest: allocate proto buffer failed\n"));
Status = NDIS_STATUS_RESOURCES;
break;
}
//
// Fill in Flush Request
//
NdisZeroMemory((PUCHAR)pCf, sizeof(LANE_CONTROL_FRAME));
pCf->Marker = LANE_CONTROL_MARKER;
pCf->Protocol = LANE_PROTOCOL;
pCf->Version = LANE_VERSION;
pCf->OpCode = LANE_FLUSH_REQUEST;
ulTemp = NdisInterlockedIncrement(&pElan->TransactionId);
pCf->Tid = SWAPULONG(ulTemp);
pCf->LecId = pElan->LecId; // already swapped
NdisMoveMemory(
&pCf->SourceAtmAddr,
&pElan->AtmAddress.Address,
ATM_ADDRESS_LENGTH
);
NdisMoveMemory(
&pCf->TargetAtmAddr,
&pAtmEntry->AtmAddress.Address,
ATM_ADDRESS_LENGTH
);
//
// Store swapped Tid in MacEntry for later matching!
//
pMacEntry->FlushTid = SWAPULONG(ulTemp);
RELEASE_MAC_ENTRY_LOCK(pMacEntry);
MacEntryLockReleased = TRUE;
//
// Link the ndis buffer to the ndis packet
//
NdisChainBufferAtFront(pNdisPacket, pNdisBuffer);
//
// Reacquire VC lock and if VC still connected send packet
//
ACQUIRE_VC_LOCK(pVc);
if (IS_FLAG_SET(
pVc->Flags,
VC_CALL_STATE_MASK,
VC_CALL_STATE_ACTIVE))
{
DBGP((2, "SendFlushRequest: sending FLUSH REQUEST for MacEntry %x\n", pMacEntry));
AtmLaneSendPacketOnVc(pVc, pNdisPacket, FALSE);
//
// VC lock released in above
//
}
else
{
Status = NDIS_STATUS_FAILURE;
RELEASE_VC_LOCK(pVc);
}
break;
}
while (FALSE);
if (!MacEntryLockReleased)
{
RELEASE_MAC_ENTRY_LOCK(pMacEntry);
}
//
// Remove temp VC reference
//
if (pVc != NULL_PATMLANE_VC)
{
ACQUIRE_VC_LOCK(pVc);
rc = AtmLaneDereferenceVc(pVc, "temp");
if (rc > 0)
{
RELEASE_VC_LOCK(pVc);
}
//
// else VC is gone
//
}
//
// Cleanup if failure
//
if (Status != NDIS_STATUS_SUCCESS)
{
if (pNdisPacket != (PNDIS_PACKET)NULL)
{
AtmLaneFreeProtoPacket(pElan, pNdisPacket);
}
if (pNdisBuffer != (PNDIS_BUFFER)NULL)
{
AtmLaneFreeProtoBuffer(pElan, pNdisBuffer);
}
}
TRACEOUT(SendFlushRequest);
return;
}
VOID
AtmLaneConfigureResponseHandler(
IN PATMLANE_ELAN pElan,
IN PATMLANE_VC pVc,
IN PNDIS_PACKET pNdisPacket
)
/*++
Routine Description:
Handles incoming packets from the Configuration Direct VC.
Arguments:
pElan - Pointer to ATMLANE Elan structure
pVc - Pointer to ATMLANE Vc structure
pNdisPacket - Pointer to the Ndis Packet
Return Value:
None
--*/
{
PNDIS_BUFFER pNdisBuffer;
ULONG TotalLength;
ULONG BufferLength;
PLANE_CONTROL_FRAME pCf;
ULONG NumTlvs;
ULONG UNALIGNED * pType;
PUCHAR pLength;
USHORT UNALIGNED * pUShort;
ULONG UNALIGNED * pULong;
NDIS_STATUS EventCode;
USHORT NumStrings;
PWCHAR StringList[2];
BOOLEAN FreeString[2];
TRACEIN(ConfigureResponseHandler);
do
{
//
// Get initial buffer and total length of packet
//
NdisGetFirstBufferFromPacket(
pNdisPacket,
&pNdisBuffer,
(PVOID *)&pCf,
&BufferLength,
&TotalLength);
//
// Packet must be at least the size of a control frame.
// Could be larger with optional TLVs.
//
if (TotalLength < sizeof(LANE_CONTROL_FRAME))
{
DBGP((0,
"ConfigureResponseHandler: Received runt control frame (%d)\n",
TotalLength));
break;
}
//
// If buffer is not at least the size of a control frame
// we currently will not deal with it.
//
if (BufferLength < sizeof(LANE_CONTROL_FRAME))
{
DBGP((0, "ConfigureResponseHandler: Control frame is fragmented\n"));
break;
}
//
// Verify that this is really a configure reponse
//
if (pCf->Marker != LANE_CONTROL_MARKER ||
pCf->Protocol != LANE_PROTOCOL ||
pCf->Version != LANE_VERSION ||
pCf->OpCode != LANE_CONFIGURE_RESPONSE)
{
DBGP((0, "ConfigureResponseHandler: Not a configure response\n"));
//DbgPrintHexDump(0, (PUCHAR)pCf, BufferLength);
break;
}
//
// Check for successful configure status
//
if (pCf->Status != LANE_STATUS_SUCCESS)
{
//
// Failure
//
DBGP((0,
"ConfigureResponseHandler: Unsuccessful Status 0x%x (%d)\n",
SWAPUSHORT(pCf->Status), SWAPUSHORT(pCf->Status)));
//
// Setup to log event
//
StringList[0] = NULL;
FreeString[0] = FALSE;
StringList[1] = NULL;
FreeString[1] = FALSE;
switch (pCf->Status)
{
case LANE_STATUS_VERSNOSUPP:
EventCode = EVENT_ATMLANE_CFGREQ_FAIL_VERSNOSUPP;
StringList[0] = pElan->CfgElanName.Buffer;
NumStrings = 1;
break;
case LANE_STATUS_REQPARMINVAL:
EventCode = EVENT_ATMLANE_CFGREQ_FAIL_REQPARMINVAL;
StringList[0] = pElan->CfgElanName.Buffer;
NumStrings = 1;
break;
case LANE_STATUS_INSUFFRES:
EventCode = EVENT_ATMLANE_CFGREQ_FAIL_INSUFFRES;
StringList[0] = pElan->CfgElanName.Buffer;
NumStrings = 1;
break;
case LANE_STATUS_NOACCESS:
EventCode = EVENT_ATMLANE_CFGREQ_FAIL_NOACCESS;
StringList[0] = pElan->CfgElanName.Buffer;
NumStrings = 1;
break;
case LANE_STATUS_REQIDINVAL:
EventCode = EVENT_ATMLANE_CFGREQ_FAIL_REQIDINVAL;
StringList[0] = pElan->CfgElanName.Buffer;
NumStrings = 1;
break;
case LANE_STATUS_LANDESTINVAL:
EventCode = EVENT_ATMLANE_CFGREQ_FAIL_LANDESTINVAL;
StringList[0] = pElan->CfgElanName.Buffer;
if (pElan->LanType == LANE_LANTYPE_ETH)
{
StringList[1] = AtmLaneMacAddrToString(&pElan->MacAddressEth);
FreeString[1] = TRUE;
}
else
{
StringList[1] = AtmLaneMacAddrToString(&pElan->MacAddressTr);
FreeString[1] = TRUE;
}
NumStrings = 2;
break;
case LANE_STATUS_ATMADDRINVAL:
EventCode = EVENT_ATMLANE_CFGREQ_FAIL_ATMADDRINVAL;
StringList[0] = pElan->CfgElanName.Buffer;
StringList[1] = AtmLaneAtmAddrToString(&pElan->AtmAddress);
FreeString[1] = TRUE;
NumStrings = 2;
break;
case LANE_STATUS_NOCONF:
EventCode = EVENT_ATMLANE_CFGREQ_FAIL_NOCONF;
StringList[0] = pElan->CfgElanName.Buffer;
NumStrings = 1;
break;
case LANE_STATUS_CONFERROR:
EventCode = EVENT_ATMLANE_CFGREQ_FAIL_CONFERROR;
StringList[0] = pElan->CfgElanName.Buffer;
NumStrings = 1;
break;
case LANE_STATUS_INSUFFINFO:
default:
EventCode = EVENT_ATMLANE_CFGREQ_FAIL_INSUFFINFO;
StringList[0] = pElan->CfgElanName.Buffer;
NumStrings = 1;
break;
}
//
// If not repeated event on this ELAN write the event to log
//
if (pElan->LastEventCode != EventCode)
{
pElan->LastEventCode = EventCode;
(VOID) NdisWriteEventLogEntry(
pAtmLaneGlobalInfo->pDriverObject,
EventCode, 0, NumStrings, StringList, 0, NULL);
}
//
// Free any strings allocated
//
if (FreeString[0] && StringList[0] != NULL)
{
FREE_MEM(StringList[0]);
}
if (FreeString[1] && StringList[1] != NULL)
{
FREE_MEM(StringList[1]);
}
//
// Notify event handler of failure
//
ACQUIRE_ELAN_LOCK(pElan);
AtmLaneQueueElanEvent(pElan, ELAN_EVENT_CONFIGURE_RESPONSE, NDIS_STATUS_FAILURE);
RELEASE_ELAN_LOCK(pElan);
break;
}
//
// Successful Configure Response
//
//
// Extract the required Elan parameters
//
ACQUIRE_ELAN_LOCK(pElan);
pElan->LanType = pCf->LanType;
DBGP((1, "%d LanType = %x\n", pElan->ElanNumber, pElan->LanType));
if (pElan->LanType == LANE_LANTYPE_UNSPEC)
{
DBGP((1, "Defaulting to LanType 1 (Ethernet/802.3)\n"));
pElan->LanType = LANE_LANTYPE_ETH;
}
pElan->MaxFrameSizeCode = pCf->MaxFrameSize;
DBGP((1, "%d MaxFrameSizeCode = %x\n", pElan->ElanNumber, pElan->MaxFrameSizeCode));
if (pElan->MaxFrameSizeCode == LANE_MAXFRAMESIZE_CODE_UNSPEC)
{
DBGP((1, "Defaulting to MaxFrameSizeCode 1 (1516)\n"));
pElan->MaxFrameSizeCode = LANE_MAXFRAMESIZE_CODE_1516;
}
switch (pElan->MaxFrameSizeCode)
{
case LANE_MAXFRAMESIZE_CODE_18190:
pElan->MaxFrameSize = 18190;
break;
case LANE_MAXFRAMESIZE_CODE_9234:
pElan->MaxFrameSize = 9234;
break;
case LANE_MAXFRAMESIZE_CODE_4544:
pElan->MaxFrameSize = 4544;
break;
case LANE_MAXFRAMESIZE_CODE_1516:
case LANE_MAXFRAMESIZE_CODE_UNSPEC:
default:
pElan->MaxFrameSize = 1516;
break;
}
if (pElan->LanType == LANE_LANTYPE_ETH)
{
pElan->MinFrameSize = LANE_MIN_ETHPACKET;
}
else
{
pElan->MinFrameSize = LANE_MIN_TRPACKET;
}
NdisZeroMemory(
pElan->ElanName,
LANE_ELANNAME_SIZE_MAX);
NdisMoveMemory(
pElan->ElanName,
pCf->ElanName,
pCf->ElanNameSize);
pElan->ElanNameSize = pCf->ElanNameSize;
pElan->LesAddress.AddressType = ATM_NSAP;
pElan->LesAddress.NumberOfDigits = ATM_ADDRESS_LENGTH;
NdisMoveMemory(
pElan->LesAddress.Address,
&pCf->TargetAtmAddr,
ATM_ADDRESS_LENGTH);
DBGP((1, "%d LES ATMAddr: %s\n",
pElan->ElanNumber,
AtmAddrToString(pElan->LesAddress.Address)));
//
// Check for TLVs
//
if (pCf->NumTlvs > 0)
{
DBGP((2, "ConfigureReponseHandler: NumTlvs is %d\n", pCf->NumTlvs));
NumTlvs = pCf->NumTlvs;
pType = (ULONG UNALIGNED *)
(((PUCHAR)pCf) + sizeof(LANE_CONTROL_FRAME));
while (NumTlvs--)
{
pLength = (PUCHAR)pType + sizeof(*pType);
pUShort = (USHORT UNALIGNED *)
(((PUCHAR)pLength) + sizeof(*pLength));
pULong = (ULONG UNALIGNED *)
(((PUCHAR)pLength) + sizeof(*pLength));
switch (*pType)
{
case LANE_CFG_CONTROL_TIMEOUT: // C7
pElan->ControlTimeout = SWAPUSHORT(*pUShort);
if (pElan->ControlTimeout < LANE_C7_MIN ||
pElan->ControlTimeout > LANE_C7_MAX)
pElan->ControlTimeout = LANE_C7_DEF;
DBGP((1, "%d Control Time-out %d\n",
pElan->ElanNumber,
pElan->ControlTimeout));
break;
case LANE_CFG_UNK_FRAME_COUNT: // C10
pElan->MaxUnkFrameCount = SWAPUSHORT(*pUShort);
if (pElan->MaxUnkFrameCount < LANE_C10_MIN ||
pElan->MaxUnkFrameCount > LANE_C10_MAX)
pElan->MaxUnkFrameCount = LANE_C10_DEF;
DBGP((1, "%d Maximum Unknown Frame Count %d\n",
pElan->ElanNumber,
pElan->MaxUnkFrameCount));
break;
case LANE_CFG_UNK_FRAME_TIME: // C11
pElan->MaxUnkFrameTime = SWAPUSHORT(*pUShort);
if (pElan->MaxUnkFrameTime < LANE_C11_MIN ||
pElan->MaxUnkFrameTime > LANE_C11_MAX)
pElan->MaxUnkFrameTime = LANE_C11_DEF;
DBGP((1, "%d Maximum Unknown Frame Time %d\n",
pElan->ElanNumber,
pElan->MaxUnkFrameTime));
break;
case LANE_CFG_VCC_TIMEOUT: // C12
pElan->VccTimeout = SWAPULONG(*pULong);
if (pElan->VccTimeout < LANE_C12_MIN)
pElan->VccTimeout = LANE_C12_DEF;
DBGP((1, "%d VCC Timeout Period %d\n",
pElan->ElanNumber,
pElan->VccTimeout));
break;
case LANE_CFG_MAX_RETRY_COUNT: // C13
pElan->MaxRetryCount = SWAPUSHORT(*pUShort);
if (/* pElan->MaxRetryCount < LANE_C13_MIN || */
pElan->MaxRetryCount > LANE_C13_MAX)
pElan->MaxRetryCount = LANE_C13_DEF;
DBGP((1, "%d Maximum Retry Count %d\n",
pElan->ElanNumber,
pElan->MaxRetryCount));
break;
case LANE_CFG_AGING_TIME: // C17
pElan->AgingTime = SWAPULONG(*pULong);
if (pElan->AgingTime < LANE_C17_MIN ||
pElan->AgingTime > LANE_C17_MAX)
pElan->AgingTime = LANE_C17_DEF;
DBGP((1, "%d Aging Time %d\n",
pElan->ElanNumber,
pElan->AgingTime));
break;
case LANE_CFG_FWD_DELAY_TIME: // C18
pElan->ForwardDelayTime = SWAPUSHORT(*pUShort);
if (pElan->ForwardDelayTime < LANE_C18_MIN ||
pElan->ForwardDelayTime > LANE_C18_MAX)
pElan->ForwardDelayTime = LANE_C18_DEF;
DBGP((1, "%d Forward Delay Time %d\n",
pElan->ElanNumber,
pElan->ForwardDelayTime));
break;
case LANE_CFG_ARP_RESP_TIME: // C20
pElan->ArpResponseTime = SWAPUSHORT(*pUShort);
if (pElan->ArpResponseTime < LANE_C20_MIN ||
pElan->ArpResponseTime > LANE_C20_MAX)
pElan->ArpResponseTime = LANE_C20_DEF;
DBGP((1, "%d Arp Response Time %d\n",
pElan->ElanNumber,
pElan->ArpResponseTime));
break;
case LANE_CFG_FLUSH_TIMEOUT: // C21
pElan->FlushTimeout = SWAPUSHORT(*pUShort);
if (pElan->FlushTimeout < LANE_C21_MIN ||
pElan->FlushTimeout > LANE_C21_MAX)
pElan->FlushTimeout = LANE_C21_DEF;
DBGP((1, "%d Flush Time-out %d\n",
pElan->ElanNumber,
pElan->FlushTimeout));
break;
case LANE_CFG_PATH_SWITCH_DELAY: // C22
pElan->PathSwitchingDelay = SWAPUSHORT(*pUShort);
if (pElan->PathSwitchingDelay < LANE_C22_MIN ||
pElan->PathSwitchingDelay > LANE_C22_MAX)
pElan->PathSwitchingDelay = LANE_C22_DEF;
DBGP((1, "%d Path Switching Delay %d\n",
pElan->ElanNumber,
pElan->PathSwitchingDelay));
break;
case LANE_CFG_LOCAL_SEGMENT_ID: // C23
pElan->LocalSegmentId = SWAPUSHORT(*pUShort);
DBGP((1, "%d Local Segment ID %d\n",
pElan->ElanNumber,
pElan->LocalSegmentId));
break;
case LANE_CFG_MCAST_VCC_TYPE: // C24
pElan->McastSendVcType = SWAPUSHORT(*pUShort);
DBGP((1, "%d Mcast Send VCC Type %d\n",
pElan->ElanNumber,
pElan->McastSendVcType));
break;
case LANE_CFG_MCAST_VCC_AVG: // C25
pElan->McastSendVcAvgRate = SWAPULONG(*pULong);
DBGP((1, "%d Mcast Send VCC AvgRate %d\n",
pElan->ElanNumber,
pElan->McastSendVcAvgRate));
break;
case LANE_CFG_MCAST_VCC_PEAK: // C26
pElan->McastSendVcPeakRate = SWAPULONG(*pULong);
DBGP((1, "%d Mcast Send VCC PeakRate %d\n",
pElan->ElanNumber,
pElan->McastSendVcPeakRate));
break;
case LANE_CFG_CONN_COMPL_TIMER: // C28
pElan->ConnComplTimer = SWAPUSHORT(*pUShort);
if (pElan->ConnComplTimer < LANE_C28_MIN ||
pElan->ConnComplTimer > LANE_C28_MAX)
pElan->ConnComplTimer = LANE_C28_DEF;
DBGP((1, "%d Connection Completion Timer %d\n",
pElan->ElanNumber,
pElan->ConnComplTimer));
break;
}
pType = (ULONG UNALIGNED *)
(((PUCHAR)pType) + sizeof(pType) +
sizeof(*pLength) + *pLength);
} // while (NumTlvs--)
//
// Recalc the bus rate limiter parameters
//
pElan->LimitTime = pElan->MaxUnkFrameTime * 1000;
pElan->IncrTime = pElan->LimitTime / pElan->MaxUnkFrameCount;
}
//
// Notify event handler of success
//
AtmLaneQueueElanEvent(pElan, ELAN_EVENT_CONFIGURE_RESPONSE, NDIS_STATUS_SUCCESS);
RELEASE_ELAN_LOCK(pElan);
}
while (FALSE);
TRACEOUT(ConfigureResponsehandler);
return;
}
VOID
AtmLaneControlPacketHandler(
IN PATMLANE_ELAN pElan,
IN PATMLANE_VC pVc,
IN PNDIS_PACKET pNdisPacket
)
/*++
Routine Description:
Handles incoming packets from the control VC(s) to/from the LES.
Arguments:
pElan - Pointer to ATMLANE Elan structure
pVc - Pointer to ATMLANE Vc structure
pNdisPacket - Pointer to the Ndis Packet
Return Value:
None
--*/
{
PNDIS_BUFFER pNdisBuffer;
ULONG TotalLength;
ULONG BufferLength;
PLANE_CONTROL_FRAME pCf;
NDIS_STATUS Status;
TRACEIN(ControlPacketHandler);
do
{
//
// Get initial buffer and total length of packet
//
NdisGetFirstBufferFromPacket(
pNdisPacket,
&pNdisBuffer,
(PVOID *)&pCf,
&BufferLength,
&TotalLength);
//
// Packet must be at least the size of a control frame.
//
if (TotalLength < sizeof(LANE_CONTROL_FRAME))
{
DBGP((0,
"ConPacketHandler: Received runt control frame (%d)\n",
TotalLength));
break;
}
//
// If buffer is not at least the size of a control frame
// we currently will not deal with it.
//
if (BufferLength < sizeof(LANE_CONTROL_FRAME))
{
DBGP((0, "ConfigureResponseHandler: Control frame is fragmented\n"));
break;
}
//
// Verify that this is really a control packet
//
if (pCf->Marker != LANE_CONTROL_MARKER ||
pCf->Protocol != LANE_PROTOCOL ||
pCf->Version != LANE_VERSION)
{
DBGP((0, "ControlPacketHandler: Not a control packet!\n"));
//DbgPrintHexDump(0, (PUCHAR)pCf, BufferLength);
break;
}
//
// Now handle by type of control packet
//
switch (pCf->OpCode)
{
case LANE_JOIN_RESPONSE:
DBGP((2, "ControlPacketHandler: Join Response\n"));
AtmLaneJoinResponseHandler(pElan, pCf);
break;
case LANE_ARP_RESPONSE:
DBGP((2, "ControlPacketHandler: ARP Response\n"));
AtmLaneArpResponseHandler(pElan, pCf);
break;
case LANE_ARP_REQUEST:
DBGP((1, "ControlPacketHandler: ARP Request\n"));
AtmLaneArpRequestHandler(pElan, pCf);
break;
case LANE_TOPOLOGY_REQUEST:
DBGP((1, "ControlPacketHandler: TOPOLOGY Request\n"));
AtmLaneTopologyRequestHandler(pElan, pCf);
break;
case LANE_NARP_REQUEST:
DBGP((2, "ControlPacketHandler: NARP Request\n"));
// ignore these
break;
case LANE_FLUSH_RESPONSE:
DBGP((2, "ControlPacketHandler: FLUSH Response\n"));
AtmLaneFlushResponseHandler(pElan, pCf);
break;
default:
DBGP((0, "ControlPacketHandler: Unexpected OpCode %x!\n",
pCf->OpCode));
//DbgPrintHexDump(0, (PUCHAR)pCf, BufferLength);
break;
} // switch (pCf->OpCode)
break;
}
while (FALSE);
TRACEOUT(ControlPackethandler);
return;
}
VOID
AtmLaneJoinResponseHandler(
IN PATMLANE_ELAN pElan,
IN PLANE_CONTROL_FRAME pCf
)
/*++
Routine Description:
Handles incoming Join Response packets from the LES.
Arguments:
pElan - Pointer to ATMLANE Elan structure
pCf - Pointer to LANE Control Frame
Return Value:
None
--*/
{
PWCHAR StringList[2];
BOOLEAN FreeString[2];
NDIS_STATUS EventCode;
USHORT NumStrings;
TRACEIN(JoinResponseHandler);
ACQUIRE_ELAN_LOCK(pElan);
if (ELAN_STATE_JOIN == pElan->State)
{
//
// Only handle join response in JOIN state!
//
if (LANE_STATUS_SUCCESS == pCf->Status)
{
//
// Success.
//
// Extract the info we need
//
pElan->LecId = pCf->LecId; // leave in network byte order
DBGP((2,
"ControlPacketHandler: LECID %x\n",
SWAPUSHORT(pElan->LecId)));
AtmLaneQueueElanEvent(pElan, ELAN_EVENT_JOIN_RESPONSE, NDIS_STATUS_SUCCESS);
}
else
{
//
// Failure
//
DBGP((0,
"ControlPacketHandler: Unsuccessful Status (%d)\n",
pCf->Status));
//
// Setup to write error to event log
//
StringList[0] = NULL;
FreeString[0] = FALSE;
StringList[1] = NULL;
FreeString[1] = FALSE;
switch (pCf->Status)
{
case LANE_STATUS_VERSNOSUPP:
EventCode = EVENT_ATMLANE_JOINREQ_FAIL_VERSNOSUPP;
StringList[0] = pElan->CfgElanName.Buffer;
NumStrings = 1;
break;
case LANE_STATUS_DUPLANDEST:
EventCode = EVENT_ATMLANE_JOINREQ_FAIL_DUPLANDEST;
StringList[0] = pElan->CfgElanName.Buffer;
if (pElan->LanType == LANE_LANTYPE_ETH)
{
StringList[1] = AtmLaneMacAddrToString(&pElan->MacAddressEth);
FreeString[1] = TRUE;
}
else
{
StringList[1] = AtmLaneMacAddrToString(&pElan->MacAddressTr);
FreeString[1] = TRUE;
}
NumStrings = 2;
break;
case LANE_STATUS_DUPATMADDR:
EventCode = EVENT_ATMLANE_JOINREQ_FAIL_DUPATMADDR;
StringList[0] = pElan->CfgElanName.Buffer;
StringList[1] = AtmLaneAtmAddrToString(&pElan->AtmAddress);
FreeString[1] = TRUE;
NumStrings = 2;
break;
case LANE_STATUS_INSUFFRES:
EventCode = EVENT_ATMLANE_JOINREQ_FAIL_INSUFFRES;
StringList[0] = pElan->CfgElanName.Buffer;
NumStrings = 1;
break;
case LANE_STATUS_NOACCESS:
EventCode = EVENT_ATMLANE_JOINREQ_FAIL_NOACCESS;
StringList[0] = pElan->CfgElanName.Buffer;
NumStrings = 1;
break;
case LANE_STATUS_REQIDINVAL:
EventCode = EVENT_ATMLANE_JOINREQ_FAIL_REQIDINVAL;
StringList[0] = pElan->CfgElanName.Buffer;
NumStrings = 1;
break;
case LANE_STATUS_LANDESTINVAL:
EventCode = EVENT_ATMLANE_JOINREQ_FAIL_LANDESTINVAL;
StringList[0] = pElan->CfgElanName.Buffer;
if (pElan->LanType == LANE_LANTYPE_ETH)
{
StringList[1] = AtmLaneMacAddrToString(&pElan->MacAddressEth);
FreeString[1] = TRUE;
}
else
{
StringList[1] = AtmLaneMacAddrToString(&pElan->MacAddressTr);
FreeString[1] = TRUE;
}
NumStrings = 2;
break;
case LANE_STATUS_ATMADDRINVAL:
EventCode = EVENT_ATMLANE_JOINREQ_FAIL_ATMADDRINVAL;
StringList[0] = pElan->CfgElanName.Buffer;
StringList[1] = AtmLaneAtmAddrToString(&pElan->AtmAddress);
FreeString[1] = TRUE;
NumStrings = 2;
break;
case LANE_STATUS_REQPARMINVAL:
default:
EventCode = EVENT_ATMLANE_JOINREQ_FAIL_REQPARMINVAL;
StringList[0] = pElan->CfgElanName.Buffer;
NumStrings = 1;
break;
}
//
// If not repeated event on this ELAN write the event to log
//
if (pElan->LastEventCode != EventCode)
{
pElan->LastEventCode = EventCode;
(VOID) NdisWriteEventLogEntry(
pAtmLaneGlobalInfo->pDriverObject,
EventCode, 0, NumStrings, StringList, 0, NULL);
}
//
// Free any strings allocated
//
if (FreeString[0] && StringList[0] != NULL)
{
FREE_MEM(StringList[0]);
}
if (FreeString[1] && StringList[1] != NULL)
{
FREE_MEM(StringList[1]);
}
AtmLaneQueueElanEvent(pElan, ELAN_EVENT_JOIN_RESPONSE, NDIS_STATUS_FAILURE);
}
}
else
{
//
// else bad elan state - ignore packet
//
DBGP((0,
"ControlPacketHandler: Elan state wrong - Ignoring packet\n",
pCf->Status));
}
RELEASE_ELAN_LOCK(pElan);
TRACEOUT(JoinResponseHandler);
return;
}
VOID
AtmLaneReadyQueryHandler(
IN PATMLANE_ELAN pElan,
IN PATMLANE_VC pVc,
IN PNDIS_PACKET pQueryNdisPacket
)
/*++
Routine Description:
Handles incoming READY_QUERY packets from peers.
Arguments:
pElan - Pointer to ATMLANE Elan structure
pVc - Pointer to ATMLANE VC for this packet
pQueryNdisPacket - Pointer to the Ndis Packet
Return Value:
None
--*/
{
PNDIS_BUFFER pNdisBuffer;
ULONG TotalLength;
ULONG BufferLength;
PLANE_READY_FRAME pQueryRf;
PLANE_READY_FRAME pIndRf;
PNDIS_PACKET pIndNdisPacket;
TRACEIN(ReadyQueryHandler);
do
{
//
// Get initial buffer and total length of packet
//
NdisGetFirstBufferFromPacket(
pQueryNdisPacket,
&pNdisBuffer,
&pQueryRf,
&BufferLength,
&TotalLength);
//
// Packet must be at least the size of a READY frame.
//
if (TotalLength < sizeof(LANE_READY_FRAME))
{
DBGP((0,
"ReadyQueryHandler: Received runt ready frame (%d)\n",
TotalLength));
break;
}
//
// If buffer is not at least the size of a ready frame
// we currently will not deal with it.
//
if (BufferLength < sizeof(LANE_READY_FRAME))
{
DBGP((0, "ReadyQueryHandler: Control frame is fragmented\n"));
break;
}
//
// Verify that this is really a ready query
//
if (pQueryRf->Marker != LANE_CONTROL_MARKER ||
pQueryRf->Protocol != LANE_PROTOCOL ||
pQueryRf->Version != LANE_VERSION ||
pQueryRf->OpCode != LANE_READY_QUERY)
{
DBGP((0, "ReadyQueryHandler: Not a ready query\n"));
//DbgPrintHexDump(0, (PUCHAR)pQueryRf, BufferLength);
break;
}
//
// Send Ready Indication back on VC
//
ACQUIRE_VC_LOCK(pVc);
AtmLaneSendReadyIndication(pElan, pVc);
//
// VC lock released in above
//
break;
}
while (FALSE);
TRACEOUT(ReadyQueryHandler);
return;
}
VOID
AtmLaneFlushRequestHandler(
IN PATMLANE_ELAN pElan,
IN PNDIS_PACKET pRequestNdisPacket
)
/*++
Routine Description:
Handles incoming FLUSH_REQUEST packets from peers.
Arguments:
pElan - Pointer to ATMLANE Elan structure
pRequestNdisPacket - Pointer to the Ndis Packet
Return Value:
None
--*/
{
PATMLANE_ATM_ENTRY pAtmEntry;
PATMLANE_VC pVc;
PNDIS_BUFFER pRequestNdisBuffer;
PNDIS_PACKET pResponseNdisPacket;
PNDIS_BUFFER pResponseNdisBuffer;
ULONG TotalLength;
ULONG BufferLength;
PLANE_CONTROL_FRAME pRequestCf;
PLANE_CONTROL_FRAME pResponseCf;
NDIS_STATUS Status;
ULONG rc;
TRACEIN(FlushRequestHandler);
//
// Initialize
//
pResponseNdisPacket = (PNDIS_PACKET)NULL;
pResponseNdisBuffer = (PNDIS_BUFFER)NULL;
Status = NDIS_STATUS_SUCCESS;
pVc = NULL_PATMLANE_VC;
do
{
ACQUIRE_ELAN_ATM_LIST_LOCK(pElan);
pAtmEntry = pElan->pLesAtmEntry;
if (pAtmEntry == NULL_PATMLANE_ATM_ENTRY)
{
RELEASE_ELAN_ATM_LIST_LOCK(pElan);
Status = NDIS_STATUS_FAILURE;
break;
}
ACQUIRE_ATM_ENTRY_LOCK_DPC(pAtmEntry);
pVc = pAtmEntry->pVcList;
if (pVc == NULL_PATMLANE_VC)
{
RELEASE_ATM_ENTRY_LOCK_DPC(pAtmEntry);
RELEASE_ELAN_ATM_LIST_LOCK(pElan);
break;
}
//
// Reference the VC to keep it around
//
ACQUIRE_VC_LOCK_DPC(pVc);
AtmLaneReferenceVc(pVc, "temp");
RELEASE_VC_LOCK_DPC(pVc);
RELEASE_ATM_ENTRY_LOCK_DPC(pAtmEntry);
RELEASE_ELAN_ATM_LIST_LOCK(pElan);
//
// Get initial buffer and total length of packet
//
NdisGetFirstBufferFromPacket(
pRequestNdisPacket,
&pRequestNdisBuffer,
(PVOID *)&pRequestCf,
&BufferLength,
&TotalLength);
//
// Packet must be at least the size of a control frame.
//
if (TotalLength < sizeof(LANE_CONTROL_FRAME))
{
DBGP((0,
"FlushRequestHandler: Received runt control frame (%d)\n",
TotalLength));
Status = NDIS_STATUS_FAILURE;
break;
}
//
// If buffer is not at least the size of a control frame
// we currently will not deal with it.
//
if (BufferLength < sizeof(LANE_CONTROL_FRAME))
{
DBGP((0, "FlushRequestHandler: Control frame is fragmented\n"));
Status = NDIS_STATUS_FAILURE;
break;
}
//
// Verify that this is really a flush request
//
if (pRequestCf->Marker != LANE_CONTROL_MARKER ||
pRequestCf->Protocol != LANE_PROTOCOL ||
pRequestCf->Version != LANE_VERSION ||
pRequestCf->OpCode != LANE_FLUSH_REQUEST)
{
DBGP((0, "FlushRequestHandler: Not a flush request\n"));
//DbgPrintHexDump(0, (PUCHAR)pRequestCf, BufferLength);
Status = NDIS_STATUS_FAILURE;
break;
}
//
// See if it is really destined for us
//
if (!ATM_ADDR_EQUAL(pRequestCf->TargetAtmAddr, pElan->AtmAddress.Address))
{
DBGP((1, "FlushRequestHandler: bad target addr, discarding, Vc %x\n", pVc));
Status = NDIS_STATUS_FAILURE;
break;
}
//
// Turn packet around and send it to the LES
//
do
{
//
// Allocate the Ndis packet header.
//
pResponseNdisPacket = AtmLaneAllocProtoPacket(pElan);
if ((PNDIS_PACKET)NULL == pResponseNdisPacket)
{
DBGP((0, "FlushRequestHandler: allocate packet failed\n"));
Status = NDIS_STATUS_RESOURCES;
break;
}
//
// Allocate the protocol buffer
//
pResponseNdisBuffer = AtmLaneAllocateProtoBuffer(
pElan,
pElan->ProtocolBufSize,
&((PUCHAR)(pResponseCf))
);
if ((PNDIS_BUFFER)NULL == pResponseNdisBuffer)
{
DBGP((0, "FlushRequestHandler: allocate proto buffer failed\n"));
Status = NDIS_STATUS_RESOURCES;
break;
}
//
// Copy in the request packet
//
NdisMoveMemory(
pResponseCf,
pRequestCf,
sizeof(LANE_CONTROL_FRAME)
);
//
// Change to a response opcode
//
pResponseCf->OpCode = LANE_FLUSH_RESPONSE;
//
// Link the ndis buffer to the ndis packet
//
NdisChainBufferAtFront(pResponseNdisPacket, pResponseNdisBuffer);
//
// Reacquire VC lock and if VC still connected send packet
//
ACQUIRE_VC_LOCK(pVc);
if (IS_FLAG_SET(
pVc->Flags,
VC_CALL_STATE_MASK,
VC_CALL_STATE_ACTIVE))
{
DBGP((2, "FlushRequestHandler: Sent FLUSH RESPONSE\n"));
AtmLaneSendPacketOnVc(pVc, pResponseNdisPacket, FALSE);
//
// VC lock released in above
//
}
else
{
Status = NDIS_STATUS_FAILURE;
RELEASE_VC_LOCK(pVc);
}
break;
}
while (FALSE);
break;
}
while (FALSE);
//
// Remove temp VC reference
//
if (pVc != NULL_PATMLANE_VC)
{
ACQUIRE_VC_LOCK(pVc);
rc = AtmLaneDereferenceVc(pVc, "temp");
if (rc > 0)
{
RELEASE_VC_LOCK(pVc);
}
//
// else VC is gone
//
}
//
// Cleanup if failure
//
if (Status != NDIS_STATUS_SUCCESS)
{
if (pResponseNdisPacket != (PNDIS_PACKET)NULL)
{
AtmLaneFreeProtoPacket(pElan, pResponseNdisPacket);
}
if (pResponseNdisBuffer != (PNDIS_BUFFER)NULL)
{
AtmLaneFreeProtoBuffer(pElan, pResponseNdisBuffer);
}
}
TRACEOUT(FlushRequestHandler);
return;
}
VOID
AtmLaneArpRequestHandler(
IN PATMLANE_ELAN pElan,
IN PLANE_CONTROL_FRAME pRequestCf
)
/*++
Routine Description:
Handles incoming Arp Request packets from the LES.
Arguments:
pRequestCf - Pointer to ARP Request Frame
Return Value:
None
--*/
{
PATMLANE_ATM_ENTRY pAtmEntry;
PATMLANE_VC pVc;
PNDIS_PACKET pResponseNdisPacket;
PNDIS_BUFFER pResponseNdisBuffer;
ULONG TotalLength;
ULONG BufferLength;
PLANE_CONTROL_FRAME pResponseCf;
NDIS_STATUS Status;
ULONG rc;
PMAC_ADDRESS pMacAddress;
TRACEIN(ArpRequestHandler);
//
// Initialize
//
pResponseNdisPacket = (PNDIS_PACKET)NULL;
pResponseNdisBuffer = (PNDIS_BUFFER)NULL;
Status = NDIS_STATUS_SUCCESS;
pVc = NULL_PATMLANE_VC;
pMacAddress = (PMAC_ADDRESS)pRequestCf->TargetMacAddress.Byte;
do
{
DBGP((2, "%d Arp Request for MAC %s\n",
pElan->ElanNumber, MacAddrToString(pMacAddress)));
//
// If not looking for our MAC address then done.
//
if (pElan->LanType == LANE_LANTYPE_TR)
{
if (!MAC_ADDR_EQUAL(pMacAddress, &pElan->MacAddressTr))
{
break;
}
}
else
{
if (!MAC_ADDR_EQUAL(pMacAddress, &pElan->MacAddressEth))
{
break;
}
}
DBGP((1, "%d ARP REQUEST\n", pElan->ElanNumber));
//
// Get the LES Vc
//
ACQUIRE_ELAN_ATM_LIST_LOCK(pElan);
pAtmEntry = pElan->pLesAtmEntry;
if (pAtmEntry == NULL_PATMLANE_ATM_ENTRY)
{
RELEASE_ELAN_ATM_LIST_LOCK(pElan);
DBGP((0, "%d ARP REQUEST before we have an LES entry\n", pElan->ElanNumber));
Status = NDIS_STATUS_FAILURE;
break;
}
ACQUIRE_ATM_ENTRY_LOCK_DPC(pAtmEntry);
pVc = pAtmEntry->pVcList;
if (pVc == NULL_PATMLANE_VC)
{
RELEASE_ATM_ENTRY_LOCK_DPC(pAtmEntry);
RELEASE_ELAN_ATM_LIST_LOCK(pElan);
DBGP((0, "%d ARP REQUEST with no VC to LES\n", pElan->ElanNumber));
break;
}
//
// Reference the VC to keep it around
//
ACQUIRE_VC_LOCK_DPC(pVc);
AtmLaneReferenceVc(pVc, "temp");
RELEASE_VC_LOCK_DPC(pVc);
RELEASE_ATM_ENTRY_LOCK_DPC(pAtmEntry);
RELEASE_ELAN_ATM_LIST_LOCK(pElan);
//
// Send Arp Response to the LES
//
do
{
//
// Allocate the Ndis packet header.
//
pResponseNdisPacket = AtmLaneAllocProtoPacket(pElan);
if ((PNDIS_PACKET)NULL == pResponseNdisPacket)
{
DBGP((0, "ArpRequestHandler: allocate packet failed\n"));
Status = NDIS_STATUS_RESOURCES;
break;
}
//
// Allocate the protocol buffer
//
pResponseNdisBuffer = AtmLaneAllocateProtoBuffer(
pElan,
pElan->ProtocolBufSize,
&((PUCHAR)(pResponseCf))
);
if ((PNDIS_BUFFER)NULL == pResponseNdisBuffer)
{
DBGP((0, "ArpRequestHandler: allocate proto buffer failed\n"));
Status = NDIS_STATUS_RESOURCES;
break;
}
//
// Copy in the request packet
//
NdisMoveMemory(
pResponseCf,
pRequestCf,
sizeof(LANE_CONTROL_FRAME)
);
//
// Change to a response opcode
//
pResponseCf->OpCode = LANE_ARP_RESPONSE;
//
// Fill in our ATM Address
//
NdisMoveMemory(
&pResponseCf->TargetAtmAddr,
&pElan->AtmAddress.Address,
ATM_ADDRESS_LENGTH
);
//
// Link the ndis buffer to the ndis packet
//
NdisChainBufferAtFront(pResponseNdisPacket, pResponseNdisBuffer);
//
// Reacquire VC lock and if VC still connected send packet
//
ACQUIRE_VC_LOCK(pVc);
if (IS_FLAG_SET(
pVc->Flags,
VC_CALL_STATE_MASK,
VC_CALL_STATE_ACTIVE))
{
DBGP((2, "ArpRequestHandler: Sent ARP RESPONSE\n"));
AtmLaneSendPacketOnVc(pVc, pResponseNdisPacket, FALSE);
//
// VC lock released in above
//
}
else
{
Status = NDIS_STATUS_FAILURE;
RELEASE_VC_LOCK(pVc);
}
break;
}
while (FALSE);
break;
}
while (FALSE);
//
// Remove temp VC reference
//
if (pVc != NULL_PATMLANE_VC)
{
ACQUIRE_VC_LOCK(pVc);
rc = AtmLaneDereferenceVc(pVc, "temp");
if (rc > 0)
{
RELEASE_VC_LOCK(pVc);
}
//
// else VC is gone
//
}
//
// Cleanup if failure
//
if (Status != NDIS_STATUS_SUCCESS)
{
if (pResponseNdisPacket != (PNDIS_PACKET)NULL)
{
AtmLaneFreeProtoPacket(pElan, pResponseNdisPacket);
}
if (pResponseNdisBuffer != (PNDIS_BUFFER)NULL)
{
AtmLaneFreeProtoBuffer(pElan, pResponseNdisBuffer);
}
}
TRACEOUT(ArpRequestHandler);
return;
}
VOID
AtmLaneArpResponseHandler(
IN PATMLANE_ELAN pElan,
IN PLANE_CONTROL_FRAME pCf
)
/*++
Routine Description:
Handle an LE_ARP Response frame.
The MAC Entry should already exist and the Tid in the
ARP frame should match the one in the MAC Entry.
If either is not true then the information is ignored.
An ATM Entry is created or and existing one is found.
The MAC Entry is linked to it and appropriate actions
are taken based on the MAC Entry state.
Arguments:
pElan - Pointer to ATMLANE Elan
pMacAddress - MAC Address
pAtmAddress - ATM Address
Return Value:
None.
--*/
{
PATMLANE_MAC_ENTRY pMacEntry;
PATMLANE_ATM_ENTRY pAtmEntry;
PMAC_ADDRESS pMacAddress;
PUCHAR pAtmAddress;
BOOLEAN WasRunning;
BOOLEAN bFound;
ULONG MacAddrType;
ULONG rc;
TRACEIN(ArpResponseHandler);
//
// Initialize
//
pMacEntry = NULL_PATMLANE_MAC_ENTRY;
pAtmEntry = NULL_PATMLANE_ATM_ENTRY;
MacAddrType = pCf->TargetMacAddress.Type;
pMacAddress = (PMAC_ADDRESS)pCf->TargetMacAddress.Byte;
pAtmAddress = pCf->TargetAtmAddr;
do
{
//
// Check Status
//
if (pCf->Status != LANE_STATUS_SUCCESS)
{
DBGP((0,
"ArpResponseHandler: Unsuccessful Status (%d) for %s\n",
pCf->Status,
MacAddrToString(pMacAddress)));
break;
}
//
// Get an existing MAC Entry
//
ACQUIRE_ELAN_MAC_TABLE_LOCK(pElan);
pMacEntry = AtmLaneSearchForMacAddress(
pElan,
MacAddrType,
pMacAddress,
FALSE
);
RELEASE_ELAN_MAC_TABLE_LOCK(pElan);
if (pMacEntry == NULL_PATMLANE_MAC_ENTRY)
{
DBGP((0, "ArpResponseHandler: non-existing MAC %s\n",
MacAddrToString(pMacAddress)));
break;
}
ACQUIRE_MAC_ENTRY_LOCK(pMacEntry);
//
// Verify that Tid matches
//
if (pMacEntry->ArpTid != pCf->Tid)
{
DBGP((0, "ArpResponseHandler: invalid Tid for MAC %s\n",
MacAddrToString(pMacAddress)));
RELEASE_MAC_ENTRY_LOCK(pMacEntry);
break;
}
DBGP((1, "%d Resolved %s to %s\n",
pElan->ElanNumber,
MacAddrToString(pMacAddress),
AtmAddrToString(pAtmAddress)));
//
// Get an existing or create new ATM Entry
//
pAtmEntry = AtmLaneSearchForAtmAddress(
pElan,
pAtmAddress,
(((pMacEntry->Flags & MAC_ENTRY_BROADCAST) != 0)
? ATM_ENTRY_TYPE_BUS
: ATM_ENTRY_TYPE_PEER),
TRUE
);
if (pAtmEntry == NULL_PATMLANE_ATM_ENTRY)
{
//
// resource problem - ARP timeout will clean up MAC Entry
//
RELEASE_MAC_ENTRY_LOCK(pMacEntry);
break;
}
//
// Got both entries.
//
// If the MAC Entry is linked to a different
// ATM Entry, unlink it from the old entry.
//
if ((pMacEntry->pAtmEntry != NULL_PATMLANE_ATM_ENTRY) &&
(pMacEntry->pAtmEntry != pAtmEntry))
{
DBGP((0,
"LearnMacToAtm: MacEntry %x moving from ATM Entry %x to ATM Entry %x\n",
pMacEntry, pMacEntry->pAtmEntry, pAtmEntry));
SET_FLAG(
pMacEntry->Flags,
MAC_ENTRY_STATE_MASK,
MAC_ENTRY_NEW);
bFound = AtmLaneUnlinkMacEntryFromAtmEntry(pMacEntry);
pMacEntry->pAtmEntry = NULL_PATMLANE_ATM_ENTRY;
if (bFound)
{
rc = AtmLaneDereferenceMacEntry(pMacEntry, "atm");
if (rc == 0)
{
//
// The MAC entry is gone. Let the next outgoing packet
// cause a new entry to be created.
//
break;
}
}
}
if (IS_FLAG_SET(
pMacEntry->Flags,
MAC_ENTRY_STATE_MASK,
MAC_ENTRY_ARPING))
{
//
// MAC Entry is in ARPING state
//
ASSERT(pMacEntry->pAtmEntry == NULL_PATMLANE_ATM_ENTRY);
//
// Link MAC Entry and ATM Entry together
//
ACQUIRE_ATM_ENTRY_LOCK_DPC(pAtmEntry);
#if DBG1
{
PATMLANE_MAC_ENTRY pTmpMacEntry;
ULONG Count = 0;
for (pTmpMacEntry = pAtmEntry->pMacEntryList;
pTmpMacEntry != NULL;
pTmpMacEntry = pTmpMacEntry->pNextToAtm)
{
if (pTmpMacEntry == pMacEntry)
{
DBGP((0, "LearnMacToAtm: pMacEntry %x already in list for pAtmEntry %x\n",
pTmpMacEntry, pAtmEntry));
DbgBreakPoint();
}
Count++;
if (Count > 5000)
{
DBGP((0, "Loop in list on pAtmEntry %x\n", pAtmEntry));
DbgBreakPoint();
break;
}
}
}
#endif // DBG
pMacEntry->pAtmEntry = pAtmEntry;
AtmLaneReferenceAtmEntry(pAtmEntry, "mac");
pMacEntry->pNextToAtm = pAtmEntry->pMacEntryList;
pAtmEntry->pMacEntryList = pMacEntry;
RELEASE_ATM_ENTRY_LOCK_DPC(pAtmEntry);
AtmLaneReferenceMacEntry(pMacEntry, "atm");
DBGP((1, "%d Linked1 MAC %x to ATM %x\n",
pAtmEntry->pElan->ElanNumber,
pMacEntry,
pAtmEntry));
//
// Cancel ARP timer
//
WasRunning = AtmLaneStopTimer(&(pMacEntry->Timer), pElan);
if (WasRunning)
{
rc = AtmLaneDereferenceMacEntry(pMacEntry, "timer");
ASSERT(rc > 0);
}
//
// Transition to RESOLVED state
//
SET_FLAG(
pMacEntry->Flags,
MAC_ENTRY_STATE_MASK,
MAC_ENTRY_RESOLVED);
//
// Handle special case for broadcast address.
//
if ((pMacEntry->Flags & MAC_ENTRY_BROADCAST) != 0)
{
RELEASE_MAC_ENTRY_LOCK(pMacEntry);
//
// Cache the AtmEntry in the Elan
//
ACQUIRE_ELAN_ATM_LIST_LOCK(pElan);
pElan->pBusAtmEntry = pAtmEntry;
RELEASE_ELAN_ATM_LIST_LOCK(pElan);
//
// Copy the Atm Address into the AtmEntry
//
pAtmEntry->AtmAddress.AddressType = ATM_NSAP;
pAtmEntry->AtmAddress.NumberOfDigits = ATM_ADDRESS_LENGTH;
NdisMoveMemory(
pAtmEntry->AtmAddress.Address,
pAtmAddress,
ATM_ADDRESS_LENGTH
);
//
// Signal the event to the state machine
//
AtmLaneQueueElanEvent(pElan, ELAN_EVENT_ARP_RESPONSE, NDIS_STATUS_SUCCESS);
//
// Event handler will initiate the call to the bus
//
break; // done
}
//
// Not broadcast address.
//
// Start the Aging timer.
// Use Elan AgingTime if TopologyChange is inactive.
// Use Elan ForwardDelayTime if TopologyChange is active.
//
AtmLaneReferenceMacEntry(pMacEntry, "timer");
AtmLaneStartTimer(
pElan,
&pMacEntry->Timer,
AtmLaneMacEntryAgingTimeout,
pElan->TopologyChange?pElan->ForwardDelayTime:pElan->AgingTime,
(PVOID)pMacEntry
);
//
// If ATM Entry not connected and a call not in progress
// then start a call
//
ACQUIRE_ATM_ENTRY_LOCK(pAtmEntry);
if (!IS_FLAG_SET(
pAtmEntry->Flags,
ATM_ENTRY_STATE_MASK,
ATM_ENTRY_CONNECTED))
{
if ((pAtmEntry->Flags & ATM_ENTRY_CALLINPROGRESS) == 0)
{
//
// Mark ATM entry with call in progress
//
pAtmEntry->Flags |= ATM_ENTRY_CALLINPROGRESS;
//
// Release the MAC lock and reacquire ATM lock
//
RELEASE_ATM_ENTRY_LOCK(pAtmEntry);
RELEASE_MAC_ENTRY_LOCK(pMacEntry);
ACQUIRE_ATM_ENTRY_LOCK(pAtmEntry);
AtmLaneMakeCall(pElan, pAtmEntry, FALSE);
//
// ATM Entry released in above
//
}
else
{
//
// Call already in progress
//
RELEASE_ATM_ENTRY_LOCK(pAtmEntry);
RELEASE_MAC_ENTRY_LOCK(pMacEntry);
}
break; // done
}
//
// ATM Entry is connected
//
RELEASE_ATM_ENTRY_LOCK(pAtmEntry);
//
// Transition to FLUSHING state
//
SET_FLAG(
pMacEntry->Flags,
MAC_ENTRY_STATE_MASK,
MAC_ENTRY_FLUSHING);
//
// Start flushing
//
pMacEntry->RetriesLeft = 0;
AtmLaneReferenceMacEntry(pMacEntry, "timer");
AtmLaneStartTimer(
pElan,
&pMacEntry->FlushTimer,
AtmLaneFlushTimeout,
pElan->FlushTimeout,
(PVOID)pMacEntry
);
AtmLaneSendFlushRequest(pElan, pMacEntry, pAtmEntry);
//
// MAC Entry released in above
//
break; // done
}
if (IS_FLAG_SET(
pMacEntry->Flags,
MAC_ENTRY_STATE_MASK,
MAC_ENTRY_AGED))
{
//
// MAC Entry is being revalidated
//
//
// Cancel ARP timer
//
WasRunning = AtmLaneStopTimer(&(pMacEntry->Timer), pElan);
if (WasRunning)
{
rc = AtmLaneDereferenceMacEntry(pMacEntry, "timer");
ASSERT(rc > 0);
}
//
// Start the Aging timer up again
//
AtmLaneReferenceMacEntry(pMacEntry, "timer");
AtmLaneStartTimer(
pElan,
&pMacEntry->Timer,
AtmLaneMacEntryAgingTimeout,
pElan->TopologyChange?pElan->ForwardDelayTime:pElan->AgingTime,
(PVOID)pMacEntry
);
//
// Check if MAC Entry is switching to new ATM Entry
if (pMacEntry->pAtmEntry == NULL_PATMLANE_ATM_ENTRY)
{
//
// Link MAC Entry and new ATM Entry together
//
ACQUIRE_ATM_ENTRY_LOCK_DPC(pAtmEntry);
#if DBG1
{
PATMLANE_MAC_ENTRY pTmpMacEntry;
ULONG Count = 0;
for (pTmpMacEntry = pAtmEntry->pMacEntryList;
pTmpMacEntry != NULL;
pTmpMacEntry = pTmpMacEntry->pNextToAtm)
{
if (pTmpMacEntry == pMacEntry)
{
DBGP((0, "RespHandler: pMacEntry %x already in list for pAtmEntry %x\n",
pTmpMacEntry, pAtmEntry));
DbgBreakPoint();
}
Count++;
if (Count > 5000)
{
DBGP((0, "RespHandler: Loop in list on pAtmEntry %x\n", pAtmEntry));
DbgBreakPoint();
break;
}
}
}
#endif // DBG
pMacEntry->pAtmEntry = pAtmEntry;
AtmLaneReferenceAtmEntry(pAtmEntry, "mac");
pMacEntry->pNextToAtm = pAtmEntry->pMacEntryList;
pAtmEntry->pMacEntryList = pMacEntry;
RELEASE_ATM_ENTRY_LOCK_DPC(pAtmEntry);
AtmLaneReferenceMacEntry(pMacEntry, "atm");
DBGP((1, "%d Linked2 MAC %x to ATM %x\n",
pAtmEntry->pElan->ElanNumber,
pMacEntry,
pAtmEntry));
//
// Transition back to resolved state
//
SET_FLAG(
pMacEntry->Flags,
MAC_ENTRY_STATE_MASK,
MAC_ENTRY_RESOLVED);
}
//
// If ATM Entry not connected and a call not in progress
// then start a call
//
ACQUIRE_ATM_ENTRY_LOCK(pAtmEntry);
if (!IS_FLAG_SET(
pAtmEntry->Flags,
ATM_ENTRY_STATE_MASK,
ATM_ENTRY_CONNECTED))
{
if ((pAtmEntry->Flags & ATM_ENTRY_CALLINPROGRESS) == 0)
{
//
// Mark ATM entry with call in progress
//
pAtmEntry->Flags |= ATM_ENTRY_CALLINPROGRESS;
//
// Release the MAC lock and reacquire ATM lock
//
RELEASE_ATM_ENTRY_LOCK(pAtmEntry);
RELEASE_MAC_ENTRY_LOCK(pMacEntry);
ACQUIRE_ATM_ENTRY_LOCK(pAtmEntry);
AtmLaneMakeCall(pElan, pAtmEntry, FALSE);
//
// ATM Entry released in above
//
}
else
{
//
// Call already in progress
//
RELEASE_ATM_ENTRY_LOCK(pAtmEntry);
RELEASE_MAC_ENTRY_LOCK(pMacEntry);
}
break; // done
}
RELEASE_ATM_ENTRY_LOCK(pAtmEntry);
//
// MAC Entry is now either still AGED or
// transitioned to RESOLVED state.
//
ASSERT((pMacEntry->Flags & (MAC_ENTRY_AGED | MAC_ENTRY_RESOLVED)) != 0);
if (IS_FLAG_SET(
pMacEntry->Flags,
MAC_ENTRY_STATE_MASK,
MAC_ENTRY_RESOLVED))
{
//
// MAC entry must have moved to new, connected ATM Entry
// Do the flush
//
SET_FLAG(
pMacEntry->Flags,
MAC_ENTRY_STATE_MASK,
MAC_ENTRY_FLUSHING);
pMacEntry->RetriesLeft = 0;
AtmLaneReferenceMacEntry(pMacEntry, "timer");
AtmLaneStartTimer(
pElan,
&pMacEntry->FlushTimer,
AtmLaneFlushTimeout,
pElan->FlushTimeout,
(PVOID)pMacEntry
);
AtmLaneSendFlushRequest(pElan, pMacEntry, pAtmEntry);
//
// MAC Entry released in above
//
break; // done
}
//
// MAC Entry can just transition back to ACTIVE
//
SET_FLAG(
pMacEntry->Flags,
MAC_ENTRY_STATE_MASK,
MAC_ENTRY_ACTIVE);
RELEASE_MAC_ENTRY_LOCK(pMacEntry);
break;
}
//
// Shouldn't get here
//
RELEASE_MAC_ENTRY_LOCK(pMacEntry);
DBGP((0, "LearnMacToAtm: MacEntry in wrong state!\n"));
break;
}
while (FALSE);
if (NULL_PATMLANE_ATM_ENTRY != pAtmEntry)
{
//
// Remove the temp ref added by SearchFor...
//
ACQUIRE_ATM_ENTRY_LOCK(pAtmEntry);
rc = AtmLaneDereferenceAtmEntry(pAtmEntry, "search");
if (rc != 0)
{
RELEASE_ATM_ENTRY_LOCK(pAtmEntry);
}
}
TRACEOUT(ArpResponseHandler);
return;
}
VOID
AtmLaneFlushResponseHandler(
IN PATMLANE_ELAN pElan,
IN PLANE_CONTROL_FRAME pCf
)
/*++
Routine Description:
Handles incoming Flush Response packets from peers.
Arguments:
pCf - Pointer to LANE Control Frame
Return Value:
None
--*/
{
PATMLANE_ATM_ENTRY pAtmEntry;
PATMLANE_MAC_ENTRY pMacEntry;
PNDIS_PACKET pNdisPacket;
PNDIS_PACKET pNextPacket;
PATMLANE_VC pVc;
BOOLEAN WasRunning;
ULONG rc;
TRACEIN(FlushResponseHandler);
pAtmEntry = NULL_PATMLANE_ATM_ENTRY;
do
{
//
// Check that we originated the request
//
if (!ATM_ADDR_EQUAL(pCf->SourceAtmAddr, &pElan->AtmAddress.Address))
{
DBGP((0, "FlushResponseHandler: Response not addressed to us!\n"));
break;
}
//
// Find the Atm Entry for the target address
//
pAtmEntry = AtmLaneSearchForAtmAddress(
pElan,
pCf->TargetAtmAddr,
ATM_ENTRY_TYPE_PEER,
FALSE); // don't create a new one
if (pAtmEntry == NULL_PATMLANE_ATM_ENTRY)
{
DBGP((0, "FlushResponseHandler: No matching ATM entry\n"));
break;
}
//
// Grab and Reference the VC for this ATM Entry
//
ACQUIRE_ATM_ENTRY_LOCK(pAtmEntry);
pVc = pAtmEntry->pVcList;
if (pVc == NULL_PATMLANE_VC)
{
DBGP((0, "FlushResponseHandler: No VC on ATM Entry\n"));
RELEASE_ATM_ENTRY_LOCK(pAtmEntry);
break;
}
ACQUIRE_VC_LOCK_DPC(pVc);
AtmLaneReferenceVc(pVc, "temp");
RELEASE_VC_LOCK_DPC(pVc);
//
// Find the Mac Entry on this Atm Entry that matches the Tid
//
pMacEntry = pAtmEntry->pMacEntryList;
while(pMacEntry != NULL_PATMLANE_MAC_ENTRY)
{
if (pMacEntry->FlushTid == pCf->Tid)
break;
pMacEntry = pMacEntry->pNextToAtm;
}
if (pMacEntry == NULL_PATMLANE_MAC_ENTRY)
{
//
// No MAC Entry still exists that originated this flush
//
DBGP((0, "FlushResponseHandler: No MAC entry with matching TID\n"));
ACQUIRE_VC_LOCK(pVc);
rc = AtmLaneDereferenceVc(pVc, "temp");
if (rc > 0)
{
RELEASE_VC_LOCK(pVc);
}
RELEASE_ATM_ENTRY_LOCK(pAtmEntry);
break;
}
else
{
//
// Found it
//
RELEASE_ATM_ENTRY_LOCK(pAtmEntry);
}
//
// Mark MAC Entry ACTIVE
//
ACQUIRE_MAC_ENTRY_LOCK(pMacEntry);
AtmLaneReferenceMacEntry(pMacEntry, "temp");
SET_FLAG(
pMacEntry->Flags,
MAC_ENTRY_STATE_MASK,
MAC_ENTRY_ACTIVE);
//
// Cancel the flush timer
//
WasRunning = AtmLaneStopTimer(&pMacEntry->FlushTimer, pElan);
if (WasRunning)
{
rc = AtmLaneDereferenceMacEntry(pMacEntry, "flush timer");
ASSERT(rc > 0);
}
//
// Send any queued packets
//
while ((pNdisPacket = AtmLaneDequeuePacketFromHead(pMacEntry)) !=
(PNDIS_PACKET)NULL)
{
//
// Send it
//
RELEASE_MAC_ENTRY_LOCK(pMacEntry);
ACQUIRE_VC_LOCK(pVc);
AtmLaneSendPacketOnVc(pVc, pNdisPacket, TRUE);
ACQUIRE_MAC_ENTRY_LOCK(pMacEntry);
}
//
// Dereference the MAC Entry
//
rc = AtmLaneDereferenceMacEntry(pMacEntry, "temp");
if (rc > 0)
{
RELEASE_MAC_ENTRY_LOCK(pMacEntry);
}
//
// Dereference the VC
//
ACQUIRE_VC_LOCK(pVc);
rc = AtmLaneDereferenceVc(pVc, "temp");
if (rc > 0)
{
RELEASE_VC_LOCK(pVc);
}
break;
}
while (FALSE);
if (NULL_PATMLANE_ATM_ENTRY != pAtmEntry)
{
//
// Remove the temp ref added by SearchFor...
//
ACQUIRE_ATM_ENTRY_LOCK(pAtmEntry);
rc = AtmLaneDereferenceAtmEntry(pAtmEntry, "search");
if (rc != 0)
{
RELEASE_ATM_ENTRY_LOCK(pAtmEntry);
}
}
TRACEOUT(FlushResponseHandler);
return;
}
VOID
AtmLaneReadyIndicationHandler(
IN PATMLANE_ELAN pElan,
IN PATMLANE_VC pVc,
IN PNDIS_PACKET pIndNdisPacket
)
/*++
Routine Description:
Handles incoming READY_INDICATION packets from peers.
Arguments:
pElan - Pointer to ATMLANE Elan structure
pVc - Pointer to ATMLANE VC for this packet
pIndNdisPacket - Pointer to the Ndis Packet
Return Value:
None
--*/
{
BOOLEAN WasRunning;
ULONG rc;
TRACEIN(ReadyIndicationHandler);
ACQUIRE_VC_LOCK(pVc);
//
// Cancel the ready timer on VC
//
WasRunning = AtmLaneStopTimer(&pVc->ReadyTimer, pElan);
if (WasRunning)
{
rc = AtmLaneDereferenceVc(pVc, "ready timer");
}
else
{
rc = pVc->RefCount;
}
//
// If VC still around update state
//
if (rc > 0)
{
DBGP((2, "ReadyIndicationHandler: pVc %x State to INDICATED\n", pVc));
SET_FLAG(
pVc->Flags,
VC_READY_STATE_MASK,
VC_READY_INDICATED
);
RELEASE_VC_LOCK(pVc);
}
//
// else VC is gone
//
TRACEOUT(ReadyIndicationHandler);
return;
}
VOID
AtmLaneTopologyRequestHandler(
IN PATMLANE_ELAN pElan,
IN PLANE_CONTROL_FRAME pCf
)
/*++
Routine Description:
Handles incoming Topology Request packets from the LES.
Arguments:
pRequestCf - Pointer to ARP Request Frame
Return Value:
None
--*/
{
ULONG i;
PATMLANE_MAC_ENTRY pMacEntry;
TRACEIN(TopologyRequestHandler);
if ((pCf->Flags & LANE_CONTROL_FLAGS_TOPOLOGY_CHANGE) == 0)
{
//
// Topology change state OFF
//
DBGP((1, "%d TOPOLOGY CHANGE OFF\n", pElan->ElanNumber));
pElan->TopologyChange = 0;
}
else
{
//
// Topology change state ON
//
DBGP((1, "%d TOPOLOGY CHANGE ON\n", pElan->ElanNumber));
pElan->TopologyChange = 1;
//
// Abort all MAC table entries.
//
for (i = 0; i < ATMLANE_MAC_TABLE_SIZE; i++)
{
ACQUIRE_ELAN_MAC_TABLE_LOCK(pElan);
while (pElan->pMacTable[i] != NULL_PATMLANE_MAC_ENTRY)
{
pMacEntry = pElan->pMacTable[i];
RELEASE_ELAN_MAC_TABLE_LOCK(pElan);
ACQUIRE_MAC_ENTRY_LOCK(pMacEntry);
AtmLaneAbortMacEntry(pMacEntry);
//
// MAC Entry Lock is released within the above.
//
ACQUIRE_ELAN_MAC_TABLE_LOCK(pElan);
}
RELEASE_ELAN_MAC_TABLE_LOCK(pElan);
}
}
TRACEOUT(TopologyRequestHandler);
return;
}
BOOLEAN
AtmLaneDataPacketHandler(
IN PATMLANE_ELAN pElan,
IN PATMLANE_VC pVc,
IN PNDIS_PACKET pNdisPacket
)
/*++
Routine Description:
Handles incoming packets from the data VCs from peers and
unknown and multicast packets from the BUS.
Arguments:
pElan - Pointer to ATMLANE Elan structure
pVc - Pointer to ATMLANE Vc structure
pNdisPacket - Pointer to the Ndis Packet
Return Value:
TRUE - if packet will be retained (i.e. sent
up to protocols)
FALSE - if packet was a flush request packet and
can be reliquished back to adapter
immediately.
--*/
{
ULONG TotalLength;
ULONG TempLength;
PUCHAR pBuffer;
BOOLEAN RetainIt;
PLANE_CONTROL_FRAME pCf;
PNDIS_PACKET pNewNdisPacket;
PNDIS_BUFFER pFirstNdisBuffer;
PNDIS_BUFFER pTempNdisBuffer;
PNDIS_BUFFER pNewNdisBuffer;
PUCHAR pTempBuffer;
NDIS_STATUS Status;
ULONG MacHdrSize;
ULONG DestAddrType;
MAC_ADDRESS DestAddr;
BOOLEAN DestIsMulticast;
NDIS_HANDLE MiniportAdapterHandle;
TRACEIN(DataPacketHandler);
// Initialize
RetainIt = FALSE; // default is not to keep packet
pNewNdisPacket = NULL;
do
{
//
// Get initial buffer and total length of packet
//
NdisGetFirstBufferFromPacket(
pNdisPacket,
&pFirstNdisBuffer,
&pBuffer,
&TempLength,
&TotalLength);
DBGP((3, "DataPacketHandler: Pkt %x Length %d\n",
pNdisPacket, TotalLength));
//DbgPrintNdisPacket(pNdisPacket);
//
// Filter out flush request and ready query frames
//
if (TempLength < 6)
{
DBGP((0, "DataPacketHandler: pVc %x First fragment"
" < 6, discarding\n", pVc));
break;
}
pCf = (PLANE_CONTROL_FRAME)pBuffer;
if (pCf->Marker == LANE_CONTROL_MARKER &&
pCf->Protocol == LANE_PROTOCOL &&
pCf->Version == LANE_VERSION)
{
switch (pCf->OpCode)
{
case LANE_FLUSH_REQUEST:
DBGP((2, "DataPacketHandler: pVc %x FLUSH REQUEST\n", pVc));
AtmLaneFlushRequestHandler(pElan, pNdisPacket);
break;
case LANE_READY_QUERY:
DBGP((2, "DataPacketHandler: pVc %x READY QUERY\n", pVc));
AtmLaneReadyQueryHandler(pElan, pVc, pNdisPacket);
break;
case LANE_READY_IND:
DBGP((2, "DataPacketHandler: pVc %x READY INDICATION\n", pVc));
AtmLaneReadyIndicationHandler(pElan, pVc, pNdisPacket);
break;
default:
DBGP((2,
"DataPacketHandler: pVc %x Unexpected control"
" packet, opcode %x\n",
pVc, pCf->OpCode));
break;
}
break;
}
//
// If miniport is not operational - discard
//
if ((pElan->Flags & ELAN_MINIPORT_OPERATIONAL) == 0)
{
DBGP((2, "%d Dropping pkt %x, cuz Elan %x Flags are %x\n",
pElan->ElanNumber, pNdisPacket, pElan, pElan->Flags));
break;
}
//
// If no filters are set, discard.
//
if (pElan->CurPacketFilter == 0)
{
DBGP((2, "%d Dropping pkt %x, cuz Elan %x Filter is zero\n",
pElan->ElanNumber, pNdisPacket, pElan));
break;
}
MiniportAdapterHandle = pElan->MiniportAdapterHandle;
if (NULL == MiniportAdapterHandle)
{
DBGP((0, "%d Dropping pkt %x cuz ELAN %x has Null handle!\n",
pElan->ElanNumber, pNdisPacket, pElan));
break;
}
//
// Mark VC with fact that it has had data packet receive activity
//
// To avoid slowing down the receive path, MP issues with
// setting this flag are ignored. This flag is a VC aging
// optimization and not critical.
//
pVc->ReceiveActivity = 1;
//
// Repackage it and learn some stuff about it.
//
pNewNdisPacket = AtmLaneWrapRecvPacket(
pElan,
pNdisPacket,
&MacHdrSize,
&DestAddrType,
&DestAddr,
&DestIsMulticast);
//
// If wrap failed just discard packet
//
if (pNewNdisPacket == (PNDIS_PACKET)NULL)
{
DBGP((2, "%d Dropping pkt %x, len %d, VC %x, wrap failed\n",
pElan->ElanNumber, pNdisPacket, TotalLength, pVc));
break;
}
//
// Branch on Ethernet v.s. Token Ring
//
if (pElan->LanType == LANE_LANTYPE_ETH)
{
//
// Filter out BUS reflections that we originated.
//
if (pCf->Marker == pElan->LecId)
{
DBGP((2, "%d Dropping pkt %x, len %d, VC %x, BUS reflection\n",
pElan->ElanNumber, pNdisPacket, TotalLength, pVc));
break;
}
//
// Filter out Unicasts not addressed to us
//
if ((!DestIsMulticast) &&
(!MAC_ADDR_EQUAL(&DestAddr, &pElan->MacAddressEth)))
{
DBGP((2, "%d Dropping pkt %x, len %d, VC %x, unicast not for us\n",
pElan->ElanNumber, pNdisPacket, TotalLength, pVc));
break;
}
}
else
{
ASSERT(pElan->LanType == LANE_LANTYPE_TR);
//
// Filter out Non-Multicast BUS reflections that we originated
//
if ((pCf->Marker == pElan->LecId) && (!DestIsMulticast))
{
DBGP((2, "%d Dropping pkt %x, len %d, VC %x, TR Bus refln\n",
pElan->ElanNumber, pNdisPacket, TotalLength, pVc));
break;
}
//
// Filter out Unicasts not addressed to us
//
if ((!DestIsMulticast) &&
(!MAC_ADDR_EQUAL(&DestAddr, &pElan->MacAddressTr)))
{
DBGP((2, "%d Dropping pkt %x, len %d, VC %x, TR unicast not for us\n",
pElan->ElanNumber, pNdisPacket, TotalLength, pVc));
break;
}
}
//
// Filter out multicast/broadcast if we don't have these enabled.
//
if (DestIsMulticast)
{
if ((pElan->CurPacketFilter &
(NDIS_PACKET_TYPE_MULTICAST|
NDIS_PACKET_TYPE_BROADCAST|
NDIS_PACKET_TYPE_ALL_MULTICAST)) == 0)
{
DBGP((2, "%d Dropping multicast pkt %x, cuz CurPacketFilter is %x\n",
pElan->ElanNumber, pNdisPacket, pElan->CurPacketFilter));
break;
}
if (((pElan->CurPacketFilter & NDIS_PACKET_TYPE_BROADCAST) == 0) &&
MAC_ADDR_EQUAL(&DestAddr, &gMacBroadcastAddress))
{
DBGP((2, "%d Dropping broadcast pkt %x, cuz CurPacketFilter is %x\n",
pElan->ElanNumber, pNdisPacket, pElan->CurPacketFilter));
break;
}
}
//
// Count it
//
NdisInterlockedIncrement(&pElan->FramesRecvGood);
//
// Indicate it up to protocols and other interested parties
//
NDIS_SET_PACKET_HEADER_SIZE(pNewNdisPacket, MacHdrSize);
TRACELOGWRITE((&TraceLog,
TL_MINDPACKET,
pNewNdisPacket));
//
// Set the packet status according to what we received from the miniport.
//
Status = NDIS_GET_PACKET_STATUS(pNdisPacket);
NDIS_SET_PACKET_STATUS(pNewNdisPacket, Status);
NdisMIndicateReceivePacket(
MiniportAdapterHandle,
&pNewNdisPacket,
1
);
if (Status != NDIS_STATUS_RESOURCES)
{
RetainIt = TRUE;
DBGP((2, "DataPacketHandler: Packet Retained!\n"));
}
//
// else our ReturnPackets handler is guaranteed to be called.
//
}
while (FALSE);
//
// Unwrap the packet if it was wrapped and we don't have to keep it.
//
if (pNewNdisPacket && !RetainIt)
{
(VOID)AtmLaneUnwrapRecvPacket(pElan, pNewNdisPacket);
}
TRACEOUT(DataPacketHandler);
return (RetainIt);
}
VOID
AtmLaneSendPacketOnVc(
IN PATMLANE_VC pVc LOCKIN NOLOCKOUT,
IN PNDIS_PACKET pNdisPacket,
IN BOOLEAN Refresh
)
/*++
Routine Description:
Send a packet on the specified VC.
Assumes caller has lock on VC structure.
Assumes caller has checked VC state for validity.
If requested, refresh the aging timer.
Sends the packet.
Returns the send status
Arguments:
pVc - Pointer to ATMLANE VC
pNdisPacket - Pointer to packet to be sent.
Refresh - If TRUE refresh the Aging Timer.
Return Value:
NDIS_STATUS value set on the packet by the miniport.
--*/
{
NDIS_HANDLE NdisVcHandle;
PATMLANE_ELAN pElan;
TRACEIN(SendPacketOnVc);
pElan = pVc->pElan;
STRUCT_ASSERT(pElan, atmlane_elan);
//
// If requested, refresh the aging timer
//
if (Refresh)
{
AtmLaneRefreshTimer(&pVc->AgingTimer);
}
#if SENDLIST
//
// Check list for duplicate send
//
NdisAcquireSpinLock(&pElan->SendListLock);
{
PNDIS_PACKET pDbgPkt;
pDbgPkt = pElan->pSendList;
while (pDbgPkt != (PNDIS_PACKET)NULL)
{
if (pNdisPacket == pDbgPkt)
{
DBGP((0, "SendPacketOnVc: Duplicate Send!\n"));
// DbgBreakPoint();
}
pDbgPkt = PSEND_RSVD(pDbgPkt)->pNextInSendList;
}
}
//
// Queue packet on list of outstanding sends
//
PSEND_RSVD(pNdisPacket)->pNextInSendList = pElan->pSendList;
pElan->pSendList = pNdisPacket;
NdisReleaseSpinLock(&pElan->SendListLock);
#endif // SENDLIST
//
// Reference the VC with the outstanding send
//
AtmLaneReferenceVc(pVc, "sendpkt");
//
// Note this outstanding send.
//
pVc->OutstandingSends++;
//
// Get the Ndis handle
//
NdisVcHandle = pVc->NdisVcHandle;
//
// Send it
//
DBGP((3, "SendPacketOnVc: pVc %x, Pkt %x, VcHandle %x\n",
pVc, pNdisPacket, NdisVcHandle));
TRACELOGWRITE((&TraceLog, TL_COSENDPACKET, pNdisPacket));
TRACELOGWRITEPKT((&TraceLog, pNdisPacket));
RELEASE_VC_LOCK(pVc);
NdisCoSendPackets(NdisVcHandle, &pNdisPacket, 1);
#if PROTECT_PACKETS
//
// Lock the packet
//
ACQUIRE_SENDPACKET_LOCK(pNdisPacket);
//
// Mark it with NdisCoSendPackets having returned
//
ASSERT((PSEND_RSVD(pNdisPacket)->Flags & PACKET_RESERVED_COSENDRETURNED) == 0);
PSEND_RSVD(pNdisPacket)->Flags |= PACKET_RESERVED_COSENDRETURNED;
//
// Complete the packet only if it is marked as having been completed
// by miniport.
//
if ((PSEND_RSVD(pNdisPacket)->Flags & PACKET_RESERVED_COMPLETED) != 0)
{
AtmLaneCompleteSendPacket(pElan, pNdisPacket,
PSEND_RSVD(pNdisPacket)->CompletionStatus);
//
// packet lock released in above
//
}
else
{
RELEASE_SENDPACKET_LOCK(pNdisPacket);
}
#endif // PROTECT_PACKETS
TRACEOUT(SendPacketOnVc);
return;
}
VOID
AtmLaneQueuePacketOnHead(
IN PATMLANE_MAC_ENTRY pMacEntry,
IN PNDIS_PACKET pNdisPacket
)
/*++
Routine Description:
Queue a packet at the head of the MAC Entry
packet queue for later transmit.
Assumes caller has lock on MAC Entry.
Arguments:
pMacEntry - Pointer to ATMLANE MAC Entry.
pNdisPacket - The packet to be queued.
Return Value:
None
--*/
{
PNDIS_PACKET pPrevPacket;
TRACEIN(QueuePacketOnHead);
SET_NEXT_PACKET(pNdisPacket, pMacEntry->PacketList);
pMacEntry->PacketList = pNdisPacket;
pMacEntry->PacketListCount++;
DBGP((2, "%d QueueHead Count %d on %s\n",
pMacEntry->pElan->ElanNumber,
pMacEntry->PacketListCount,
MacAddrToString(&pMacEntry->MacAddress)));
TRACEOUT(QueuePacketOnHead);
return;
}
VOID
AtmLaneQueuePacketOnTail(
IN PATMLANE_MAC_ENTRY pMacEntry,
IN PNDIS_PACKET pNdisPacket
)
/*++
Routine Description:
Queue a packet at the tail of the MAC Entry
packet queue for later transmit.
Assumes caller has lock on MAC Entry.
Arguments:
pMacEntry - Pointer to ATMLANE MAC Entry.
pNdisPacket - The packet to be queued.
Return Value:
None
--*/
{
PNDIS_PACKET pPrevPacket;
TRACEIN(QueuePacketOnTail);
if (pMacEntry->PacketList == (PNDIS_PACKET)NULL)
{
//
// Currently empty.
//
pMacEntry->PacketList = pNdisPacket;
}
else
{
//
// Go to the end of the packet list.
//
pPrevPacket = pMacEntry->PacketList;
while (GET_NEXT_PACKET(pPrevPacket) != (PNDIS_PACKET)NULL)
{
pPrevPacket = GET_NEXT_PACKET(pPrevPacket);
}
//
// Found the last packet in the list. Chain this packet
// to it.
//
SET_NEXT_PACKET(pPrevPacket, pNdisPacket);
}
//
// Set tail's next pointer to NULL.
//
SET_NEXT_PACKET(pNdisPacket, NULL);
pMacEntry->PacketListCount++;
DBGP((2, "%d QueueTail Count %d on %s\n",
pMacEntry->pElan->ElanNumber,
pMacEntry->PacketListCount,
MacAddrToString(&pMacEntry->MacAddress)));
TRACEOUT(QueuePacketOnTail);
return;
}
PNDIS_PACKET
AtmLaneDequeuePacketFromHead(
IN PATMLANE_MAC_ENTRY pMacEntry
)
/*++
Routine Description:
Dequeue a packet from the head of the MAC Entry packet queue.
Assumes caller has lock on MAC Entry.
Arguments:
pMacEntry - Pointer to ATMLANE MAC Entry.
Return Value:
First packet on the MAC Entry queue or NULL if queue is empty.
--*/
{
PNDIS_PACKET pNdisPacket;
TRACEIN(DequeuePacketFromHead);
do
{
//
// If queue is empty, setup to return NULL
//
if (pMacEntry->PacketList == (PNDIS_PACKET)NULL)
{
ASSERT(pMacEntry->PacketListCount == 0);
pNdisPacket = (PNDIS_PACKET)NULL;
break;
}
//
// Queue is not empty - remove head
//
ASSERT(pMacEntry->PacketListCount > 0);
pNdisPacket = pMacEntry->PacketList;
pMacEntry->PacketList = GET_NEXT_PACKET(pNdisPacket);
SET_NEXT_PACKET(pNdisPacket, NULL);
pMacEntry->PacketListCount--;
DBGP((2, "%d DequeueHead Count %d on %s\n",
pMacEntry->pElan->ElanNumber,
pMacEntry->PacketListCount,
MacAddrToString(&pMacEntry->MacAddress)));
break;
}
while (FALSE);
TRACEOUT(DequeuePacketFromHead);
return pNdisPacket;
}
NDIS_STATUS
AtmLaneSendUnicastPacket(
IN PATMLANE_ELAN pElan,
IN ULONG DestAddrType,
IN PMAC_ADDRESS pDestAddress,
IN PNDIS_PACKET pNdisPacket
)
/*++
Routine Description:
Send a unicast packet.
Arguments:
pElan - Pointer to ATMLANE elan structure
DestAddrType - Either LANE_MACADDRTYPE_MACADDR or
LANE_MACADDRTYPE_ROUTEDESCR.
pDestAddress - Pointer to Destination MAC Address
pNdisPacket - Pointer to packet to be sent.
Return Value:
NDIS_STATUS_PENDING - if packet queued or sent
NDIS_STATUS_FAILURE - if some error
--*/
{
PATMLANE_MAC_ENTRY pMacEntry;
PATMLANE_ATM_ENTRY pAtmEntry;
PATMLANE_VC pVc;
NDIS_STATUS Status;
ULONG rc;
TRACEIN(SendUnicastPacket);
//
// Initialize
//
pMacEntry = NULL_PATMLANE_MAC_ENTRY;
Status = NDIS_STATUS_PENDING;
do
{
//
// Find a MAC entry for this destination address
//
ACQUIRE_ELAN_MAC_TABLE_LOCK(pElan);
pMacEntry = AtmLaneSearchForMacAddress(
pElan,
DestAddrType,
pDestAddress,
TRUE // Create new entry if not found
);
if (pMacEntry == NULL_PATMLANE_MAC_ENTRY)
{
Status = NDIS_STATUS_RESOURCES;
RELEASE_ELAN_MAC_TABLE_LOCK(pElan);
break;
}
//
// Add a temp ref so that this won't go away when we release
// the MAC table lock (#303602).
//
ACQUIRE_MAC_ENTRY_LOCK_DPC(pMacEntry);
AtmLaneReferenceMacEntry(pMacEntry, "tempunicast");
RELEASE_MAC_ENTRY_LOCK_DPC(pMacEntry);
RELEASE_ELAN_MAC_TABLE_LOCK(pElan);
//
// Lock the MAC Entry
//
ACQUIRE_MAC_ENTRY_LOCK(pMacEntry);
//
// Check if it has been deref'ed away.
//
rc = AtmLaneDereferenceMacEntry(pMacEntry, "tempunicast");
if (rc == 0)
{
//
// The MAC entry is gone! Fail this send.
//
Status = NDIS_STATUS_FAILURE;
break;
}
//
// MAC Entry State - NEW
//
if (IS_FLAG_SET(
pMacEntry->Flags,
MAC_ENTRY_STATE_MASK,
MAC_ENTRY_NEW))
{
DBGP((2, "SendUnicastPacket: NEW Mac Entry %x for %s\n",
pMacEntry, MacAddrToString(pDestAddress)));
//
// Queue packet on MAC Entry
//
AtmLaneQueuePacketOnHead(pMacEntry, pNdisPacket);
//
// Transition to ARPING State
//
SET_FLAG(
pMacEntry->Flags,
MAC_ENTRY_STATE_MASK,
MAC_ENTRY_ARPING);
ASSERT(pMacEntry->pAtmEntry == NULL_PATMLANE_ATM_ENTRY);
//
// Start the BUS sends.
//
AtmLaneStartBusSends(pMacEntry);
//
// Lock released in above
//
//
// Reacquire the lock
//
ACQUIRE_MAC_ENTRY_LOCK(pMacEntry);
//
// Start the ARP protocol
//
pMacEntry->RetriesLeft = pElan->MaxRetryCount;
AtmLaneReferenceMacEntry(pMacEntry, "timer");
AtmLaneStartTimer(
pElan,
&pMacEntry->Timer,
AtmLaneArpTimeout,
pElan->ArpResponseTime,
(PVOID)pMacEntry
);
AtmLaneSendArpRequest(pElan, pMacEntry);
//
// MAC Entry lock released in above
//
break;
}
//
// MAC Entry State - ARPING
//
if (IS_FLAG_SET(
pMacEntry->Flags,
MAC_ENTRY_STATE_MASK,
MAC_ENTRY_ARPING))
{
DBGP((2, "SendUnicastPacket: ARPING Mac Entry %x for %s\n",
pMacEntry, MacAddrToString(pDestAddress)));
//
// Queue packet on MAC Entry
//
AtmLaneQueuePacketOnHead(pMacEntry, pNdisPacket);
//
// Start the BUS sends
//
AtmLaneStartBusSends(pMacEntry);
//
// Lock released in above
//
break;
}
//
// MAC Entry State - RESOLVED
//
if (IS_FLAG_SET(
pMacEntry->Flags,
MAC_ENTRY_STATE_MASK,
MAC_ENTRY_RESOLVED))
{
DBGP((2, "SendUnicastPacket: RESOLVED Mac Entry %x for %s\n",
pMacEntry, MacAddrToString(pDestAddress)));
//
// Queue packet on MAC Entry
//
AtmLaneQueuePacketOnHead(pMacEntry, pNdisPacket);
//
// Start the BUS sends
//
AtmLaneStartBusSends(pMacEntry);
//
// Lock released in above
//
break;
}
//
// MAC Entry State - FLUSHING
//
if (IS_FLAG_SET(
pMacEntry->Flags,
MAC_ENTRY_STATE_MASK,
MAC_ENTRY_FLUSHING))
{
DBGP((2, "SendUnicastPacket: FLUSHING Mac Entry %x for %s\n",
pMacEntry, MacAddrToString(pDestAddress)));
//
// Queue packet on MAC Entry
//
AtmLaneQueuePacketOnHead(pMacEntry, pNdisPacket);
RELEASE_MAC_ENTRY_LOCK(pMacEntry);
break;
}
//
// MAC Entry State - ACTIVE
//
//
if (IS_FLAG_SET(
pMacEntry->Flags,
MAC_ENTRY_STATE_MASK,
MAC_ENTRY_ACTIVE))
{
DBGP((2, "SendUnicastPacket: ACTIVE Mac Entry %x for %s\n",
pMacEntry, MacAddrToString(pDestAddress)));
//
// Mark MAC Entry as having been used to send a packet.
// Will cause revalidation at aging time instead of deletion.
//
pMacEntry->Flags |= MAC_ENTRY_USED_FOR_SEND;
ASSERT(pMacEntry->pAtmEntry != NULL_PATMLANE_ATM_ENTRY);
pVc = pMacEntry->pAtmEntry->pVcList;
if (pVc == NULL_PATMLANE_VC)
{
RELEASE_MAC_ENTRY_LOCK(pMacEntry);
Status = NDIS_STATUS_FAILURE;
break;
}
ACQUIRE_VC_LOCK(pVc);
AtmLaneReferenceVc(pVc, "unicast");
RELEASE_VC_LOCK(pVc);
RELEASE_MAC_ENTRY_LOCK(pMacEntry);
ACQUIRE_VC_LOCK(pVc);
rc = AtmLaneDereferenceVc(pVc, "unicast");
if (rc == 0)
{
Status = NDIS_STATUS_FAILURE;
break;
}
AtmLaneSendPacketOnVc(pVc, pNdisPacket, TRUE);
//
// Vc lock released in above
//
NdisInterlockedIncrement(&pElan->FramesXmitGood); // count packet
break;
}
//
// MAC Entry State - AGED
//
//
if (IS_FLAG_SET(
pMacEntry->Flags,
MAC_ENTRY_STATE_MASK,
MAC_ENTRY_AGED))
{
DBGP((2, "SendUnicastPacket: AGED Mac Entry %x for %s\n",
pMacEntry, MacAddrToString(pDestAddress)));
ASSERT(pMacEntry->pAtmEntry != NULL_PATMLANE_ATM_ENTRY);
ASSERT(pMacEntry->pAtmEntry->pVcList != NULL_PATMLANE_VC);
pVc = pMacEntry->pAtmEntry->pVcList;
ACQUIRE_VC_LOCK(pVc);
AtmLaneReferenceVc(pVc, "unicast");
RELEASE_VC_LOCK(pVc);
RELEASE_MAC_ENTRY_LOCK(pMacEntry);
ACQUIRE_VC_LOCK(pVc);
rc = AtmLaneDereferenceVc(pVc, "unicast");
if (rc == 0)
{
Status = NDIS_STATUS_FAILURE;
break;
}
AtmLaneSendPacketOnVc(pVc, pNdisPacket, TRUE);
//
// Vc lock released in above
//
NdisInterlockedIncrement(&pElan->FramesXmitGood); // count packet
break;
}
//
// MAC Entry State - ABORTING
//
//
if (IS_FLAG_SET(
pMacEntry->Flags,
MAC_ENTRY_STATE_MASK,
MAC_ENTRY_ABORTING))
{
DBGP((2, "SendUnicastPacket: ABORTING Mac Entry %x for %s\n",
pMacEntry, MacAddrToString(pDestAddress)));
Status = NDIS_STATUS_FAILURE;
RELEASE_MAC_ENTRY_LOCK(pMacEntry);
break;
}
}
while (FALSE);
TRACEOUT(SendUnicastPacket);
return Status;
}
VOID
AtmLaneStartBusSends(
IN PATMLANE_MAC_ENTRY pMacEntry LOCKIN NOLOCKOUT
)
/*++
Routine Description:
Starts up the bus send process.
Arguments:
pMacEntry - A pointer to an ATMLANE MAC Entry structure
Return Value:
None
--*/
{
TRACEIN(StartBusSends);
do
{
//
// If timer set, just wait for it to go off
//
if (pMacEntry->Flags & MAC_ENTRY_BUS_TIMER)
{
RELEASE_MAC_ENTRY_LOCK(pMacEntry);
break;
}
//
// Otherwise do the sends
//
AtmLaneDoBusSends(pMacEntry);
//
// lock released in above
//
}
while (FALSE);
TRACEOUT(StartBusSends);
return;
}
VOID
AtmLaneDoBusSends(
IN PATMLANE_MAC_ENTRY pMacEntry LOCKIN NOLOCKOUT
)
/*++
Routine Description:
Attempt to send the packets on the MAC Entry's queue.
Schedule a timer to send later if we exceed the BUS send limits.
The caller is assumed to have acquired the MAC entry lock,
which will be released here.
Arguments:
pMacEntry - A pointer to an ATMLANE MAC Entry structure
Return Value:
None
--*/
{
PATMLANE_ATM_ENTRY pAtmEntry;
PATMLANE_VC pVc;
PATMLANE_ELAN pElan;
PNDIS_PACKET pNdisPacket;
ULONG rc;
TRACEIN(DoBusSends);
pElan = pMacEntry->pElan;
//
// Initialize
//
pVc = NULL_PATMLANE_VC;
//
// Place a temp ref on this MAC entry so that it won't go away.
//
AtmLaneReferenceMacEntry(pMacEntry, "DoBusSends");
do
{
//
// If Elan state not operational then done
//
if (ELAN_STATE_OPERATIONAL != pElan->AdminState ||
ELAN_STATE_OPERATIONAL != pElan->State)
{
break;
}
ACQUIRE_ELAN_ATM_LIST_LOCK(pElan);
pAtmEntry = pElan->pBusAtmEntry;
if (pAtmEntry == NULL_PATMLANE_ATM_ENTRY)
{
RELEASE_ELAN_ATM_LIST_LOCK(pElan);
break;
}
ACQUIRE_ATM_ENTRY_LOCK_DPC(pAtmEntry);
pVc = pAtmEntry->pVcList;
if (pVc == NULL_PATMLANE_VC)
{
RELEASE_ATM_ENTRY_LOCK_DPC(pAtmEntry);
RELEASE_ELAN_ATM_LIST_LOCK(pElan);
break;
}
//
// Reference the VC to keep it around
//
ACQUIRE_VC_LOCK_DPC(pVc);
AtmLaneReferenceVc(pVc, "temp");
RELEASE_VC_LOCK_DPC(pVc);
RELEASE_ATM_ENTRY_LOCK_DPC(pAtmEntry);
RELEASE_ELAN_ATM_LIST_LOCK(pElan);
//
// loop until no more packets or send limit reached
//
do
{
//
// If no more packets to send then done
//
if (pMacEntry->PacketList == (PNDIS_PACKET)NULL)
{
break;
}
//
// Check if ok to send a packet now
//
if (!AtmLaneOKToBusSend(pMacEntry))
{
//
// Not OK to send now, try later
//
// Reference the MAC Entry
//
AtmLaneReferenceMacEntry(pMacEntry, "bus timer");
//
// Reschedule the timer routine
//
pMacEntry->Flags |= MAC_ENTRY_BUS_TIMER;
NdisSetTimer(&pMacEntry->BusTimer, pMacEntry->IncrTime);
break;
}
//
// Dequeue a packet
//
pNdisPacket = AtmLaneDequeuePacketFromHead(pMacEntry);
RELEASE_MAC_ENTRY_LOCK(pMacEntry);
ASSERT(pNdisPacket != (PNDIS_PACKET)NULL);
//
// Reacquire VC lock and if VC still connected send packet
//
ACQUIRE_VC_LOCK(pVc);
if (IS_FLAG_SET(
pVc->Flags,
VC_CALL_STATE_MASK,
VC_CALL_STATE_ACTIVE))
{
DBGP((2, "DoBusSends: pVc %x Pkt %x Sending to BUS\n",
pVc, pNdisPacket));
AtmLaneSendPacketOnVc(pVc, pNdisPacket, FALSE);
//
// VC lock released in above
//
NdisInterlockedIncrement(&pElan->FramesXmitGood); // count it
ACQUIRE_MAC_ENTRY_LOCK(pMacEntry);
}
else
{
//
// Not sent, release lock, requeue packet, abort
//
DBGP((2, "DoBusSend: pVc %x, Flags %x not good, pkt %x\n",
pVc, pVc->Flags, pNdisPacket));
RELEASE_VC_LOCK(pVc);
ACQUIRE_MAC_ENTRY_LOCK(pMacEntry);
AtmLaneQueuePacketOnHead(pMacEntry, pNdisPacket);
break;
}
}
while (FALSE);
//
// Remove temp VC reference
//
if (pVc == NULL_PATMLANE_VC)
{
ACQUIRE_VC_LOCK(pVc);
rc = AtmLaneDereferenceVc(pVc, "temp");
if (rc > 0)
{
RELEASE_VC_LOCK(pVc);
}
//
// else VC is gone
//
}
}
while (FALSE);
//
// Remove the temp ref we had added to the MAC entry on entering
// this function.
//
rc = AtmLaneDereferenceMacEntry(pMacEntry, "DoBusSends");
if (rc != 0)
{
RELEASE_MAC_ENTRY_LOCK(pMacEntry);
}
//
// else the MAC entry is gone.
//
TRACEOUT(DoBusSends);
return;
}
VOID
AtmLaneBusSendTimer(
IN PVOID SystemSpecific1,
IN PVOID pContext,
IN PVOID SystemSpecific2,
IN PVOID SystemSpecific3
)
{
PATMLANE_MAC_ENTRY pMacEntry;
ULONG rc;
TRACEIN(BusSendTimer);
pMacEntry = (PATMLANE_MAC_ENTRY)pContext;
STRUCT_ASSERT(pMacEntry, atmlane_mac);
do
{
//
// Grab the Mac Entry's lock
//
ACQUIRE_MAC_ENTRY_LOCK(pMacEntry);
//
// Clear the bus timer flag
//
pMacEntry->Flags &= ~ MAC_ENTRY_BUS_TIMER;
//
// Dereference the Mac Entry
//
rc = AtmLaneDereferenceMacEntry(pMacEntry, "bus timer");
if (rc == 0)
{
break;
}
//
// Mac Entry still here, try to send more
//
AtmLaneDoBusSends(pMacEntry);
//
// lock released in above
//
break;
}
while (FALSE);
TRACEOUT(BusSendTimer);
return;
}
BOOLEAN
AtmLaneOKToBusSend(
IN PATMLANE_MAC_ENTRY pMacEntry
)
/*++
Routine Description:
Determines if, at the current time, it is OK to send
a packet to the BUS. Additionally, if it is OK to send
a packet, it updates the state variables in the MAC Entry
in preparation for another attempt to send a packet to
the Bus.
The LANE spec requires a LANE client to restrict the
sending of packets over the BUS to a specific LAN
destination address by using two parameters:
Maximum Unknown Packet Count
Maximum Unknown Packet Time
A LANE client can only send "Maximum Unknown Packet Count"
packets within the period of time "Maximum Unknown Packet
Time".
This function expects the MAC Entry to contain three
variables:
BusyTime
LimitTime
IncrTime
Arguments:
pMacEntry - Pointer to an ATMLANE MAC Entry.
Return Value:
TRUE - if ok to send packet on BUS
FALSE - if exceeded traffic to the BUS
--*/
{
ULONG Now;
ULONG BusyTime;
LONG TimeUntilIdle;
Now = AtmLaneSystemTimeMs();
BusyTime = pMacEntry->BusyTime;
TimeUntilIdle = BusyTime - Now;
//
// bring busy until time up to current; also handles
// wrapping. Under normal circumstances, TimeUntilIdle
// is either < 0 or no more than limitTime + incrtime.
// The value of limitTime * 8 is a little more conservative and
// cheaper to compute.
//
if (TimeUntilIdle < 0 ||
TimeUntilIdle > (LONG)(pMacEntry->LimitTime << 3))
{
BusyTime = Now;
}
else
{
if (TimeUntilIdle > (LONG)pMacEntry->LimitTime)
{
//
// channel is already estimated to be busy until past
// the burst time, so we can't overload it by sending
// more now.
//
return FALSE;
}
}
//
// mark channel as busy for another inter-packet arrival
// time, and return OK to send the new packet.
//
pMacEntry->BusyTime = BusyTime + pMacEntry->IncrTime;
return TRUE;
}
VOID
AtmLaneFreePacketQueue(
IN PATMLANE_MAC_ENTRY pMacEntry,
IN NDIS_STATUS Status
)
/*++
Routine Description:
Frees the list of packets queued on a MAC Entry.
Assumes caller holds lock on MAC Entry.
Arguments:
pMacEntry - Pointer to MAC Entry.
Status - The status to use if the packet is
protocol packet.
Return Value:
None
--*/
{
PNDIS_PACKET pNdisPacket;
TRACEIN(FreePacketQueue);
while ((pNdisPacket = AtmLaneDequeuePacketFromHead(pMacEntry)) != (PNDIS_PACKET)NULL)
{
RELEASE_MAC_ENTRY_LOCK(pMacEntry);
#if PROTECT_PACKETS
ACQUIRE_SENDPACKET_LOCK(pNdisPacket);
PSEND_RSVD(pNdisPacket)->Flags |= PACKET_RESERVED_COSENDRETURNED;
PSEND_RSVD(pNdisPacket)->Flags |= PACKET_RESERVED_COMPLETED;
#endif // PROTECT_PACKETS
AtmLaneCompleteSendPacket(pMacEntry->pElan, pNdisPacket, Status);
//
// packet lock released in above
//
ACQUIRE_MAC_ENTRY_LOCK(pMacEntry);
}
TRACEOUT(FreePacketQueue);
return;
}
VOID
AtmLaneCompleteSendPacket(
IN PATMLANE_ELAN pElan,
IN PNDIS_PACKET pNdisPacket LOCKIN NOLOCKOUT,
IN NDIS_STATUS Status
)
/*++
Routine Description:
Complete a send packet. The packet is one of the following types:
(a) Belonging to a protocol (b) Belonging to the ATMLANE module.
In the case of a protocol packet we unwrap it and complete it.
In the case of an ATMLANE packet we just free it.
Arguments:
pElan - Pointer to ATMLANE Elan.
pNdisPacket - Pointer to the packet
Status - The status to use if the packet is
protocol packet.
Return Value:
None
--*/
{
PNDIS_BUFFER pNdisBuffer;
PNDIS_PACKET pProtNdisPacket;
TRACEIN(CompleteSendPacket);
#if PROTECT_PACKETS
//
// Assert that we can release and/or complete all resources for this packet
//
ASSERT((PSEND_RSVD(pNdisPacket)->Flags &
(PACKET_RESERVED_COMPLETED | PACKET_RESERVED_COSENDRETURNED))
== (PACKET_RESERVED_COMPLETED | PACKET_RESERVED_COSENDRETURNED));
#endif // PROTECT_PACKETS
//
// Determine originator of packet
//
if (IS_FLAG_SET(
PSEND_RSVD(pNdisPacket)->Flags,
PACKET_RESERVED_OWNER_MASK,
PACKET_RESERVED_OWNER_ATMLANE
))
{
//
// Packet originated by ATMLANE. Free the buffer.
//
NdisUnchainBufferAtFront(pNdisPacket, &pNdisBuffer);
ASSERT(NULL != pNdisBuffer);
AtmLaneFreeProtoBuffer(pElan, pNdisBuffer);
//
// Free the packet header.
//
DBGP((3, "CompleteSendPkt: Freeing AtmLane owned pkt %x\n", pNdisPacket));
#if PROTECT_PACKETS
RELEASE_SENDPACKET_LOCK(pNdisPacket);
FREE_SENDPACKET_LOCK(pNdisPacket);
#endif // PROTECT_PACKETS
NdisFreePacket(pNdisPacket);
#if PKT_HDR_COUNTS
InterlockedIncrement(&pElan->ProtPktCount);
if ((pElan->ProtPktCount % 20) == 0 &&
pElan->ProtPktCount != pElan->MaxProtocolBufs)
{
DBGP((1, "ProtPktCount %d\n", pElan->ProtPktCount));
}
#endif
}
else
{
//
// Packet orignated by a protocol.
// Unwrap it.
// Complete it to the protocol.
//
pProtNdisPacket = AtmLaneUnwrapSendPacket(pElan, pNdisPacket);
//
// packet lock released in above
//
TRACELOGWRITE((&TraceLog, TL_MSENDCOMPL, pProtNdisPacket, Status));
TRACELOGWRITEPKT((&TraceLog, pProtNdisPacket));
// DBGP((0, "NdisMSendComplete: Pkt %x Stat %x\n", pProtNdisPacket, Status));
NdisMSendComplete(
pElan->MiniportAdapterHandle,
pProtNdisPacket,
Status);
}
TRACEOUT(CompleteSendPacket);
return;
}
PWSTR
AtmLaneMacAddrToString(
IN VOID * pIn
)
{
static PWSTR WHexChars = L"0123456789abcdef";
PWSTR StrBuf;
ULONG Index;
PWSTR pWStr;
PUCHAR pMacAddr;
PWSTR punicodeMacAddrBuffer = ((PWSTR)0);
UNICODE_STRING unicodeString;
ANSI_STRING ansiString;
TRACEIN(MacAddrToString);
// alloc space for output unicode string
ALLOC_MEM(&punicodeMacAddrBuffer, (((sizeof(MAC_ADDRESS) * 2) + 1) * sizeof(WCHAR)));
if (((PWSTR)0) != punicodeMacAddrBuffer)
{
for (Index = 0, pWStr = punicodeMacAddrBuffer, pMacAddr = pIn;
Index < sizeof(MAC_ADDRESS);
Index++, pMacAddr++)
{
*pWStr++ = WHexChars[(*pMacAddr)>>4];
*pWStr++ = WHexChars[(*pMacAddr)&0xf];
}
*pWStr = L'\0';
}
TRACEOUT(MacAddrToString);
return punicodeMacAddrBuffer;
}
PWSTR
AtmLaneAtmAddrToString(
IN PATM_ADDRESS pIn
)
{
static PWSTR WHexChars = L"0123456789abcdef";
PWSTR StrBuf;
ULONG Index;
PWSTR pWStr;
PUCHAR pAtmAddr;
PWSTR punicodeAtmAddrBuffer = ((PWSTR)0);
UNICODE_STRING unicodeString;
ANSI_STRING ansiString;
TRACEIN(AtmAddrToString);
// alloc space for output unicode string
ALLOC_MEM(&punicodeAtmAddrBuffer, (((ATM_ADDRESS_LENGTH * 2) + 1) * sizeof(WCHAR)));
if (((PWSTR)0) != punicodeAtmAddrBuffer)
{
// format ATM addr into Unicode string buffer
for (Index = 0, pWStr = punicodeAtmAddrBuffer, pAtmAddr = pIn->Address;
Index < pIn->NumberOfDigits;
Index++, pAtmAddr++)
{
*pWStr++ = WHexChars[(*pAtmAddr)>>4];
*pWStr++ = WHexChars[(*pAtmAddr)&0xf];
}
*pWStr = L'\0';
}
TRACEOUT(AtmAddrToString);
return punicodeAtmAddrBuffer;
}