2221 lines
55 KiB
C
2221 lines
55 KiB
C
/*++
|
||
|
||
Copyright (c) 1992 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
aarp.c
|
||
|
||
Abstract:
|
||
|
||
This module contains the Appletalk Address Resolution Protocol code.
|
||
|
||
Author:
|
||
|
||
Jameel Hyder (jameelh@microsoft.com)
|
||
Nikhil Kamkolkar (nikhilk@microsoft.com)
|
||
|
||
Revision History:
|
||
19 Jun 1992 Initial Version
|
||
|
||
Notes: Tab stop: 4
|
||
--*/
|
||
|
||
#include <atalk.h>
|
||
#pragma hdrstop
|
||
|
||
// Define the file number for this module for errorlogging.
|
||
#define FILENUM AARP
|
||
|
||
#ifdef ALLOC_PRAGMA
|
||
#pragma alloc_text(PAGEINIT, AtalkInitAarpForNodeOnPort)
|
||
#pragma alloc_text(PAGEINIT, AtalkInitAarpForNodeInRange)
|
||
#pragma alloc_text(PAGEINIT, atalkInitAarpForNode)
|
||
#endif
|
||
|
||
VOID
|
||
AtalkAarpPacketIn(
|
||
IN OUT PPORT_DESCRIPTOR pPortDesc,
|
||
IN PBYTE pLinkHdr,
|
||
IN PBYTE pPkt, // Only aarp data
|
||
IN USHORT Length
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
|
||
Arguments:
|
||
|
||
|
||
Return Value:
|
||
|
||
|
||
--*/
|
||
{
|
||
PBYTE srcAddr;
|
||
PBYTE startOfPkt;
|
||
ATALK_NODEADDR srcNode, dstNode;
|
||
|
||
PBYTE pRouteInfo = NULL;
|
||
USHORT routeInfoLen = 0;
|
||
ULONG logEventPlace = 0;
|
||
|
||
USHORT hardwareLen, protocolLength, aarpCommand;
|
||
PBUFFER_DESC pBuffDesc;
|
||
ATALK_ERROR error;
|
||
PVOID pRasConn;
|
||
PATCPCONN pAtcpConn=NULL;
|
||
PARAPCONN pArapConn=NULL;
|
||
DWORD dwFlags;
|
||
BOOLEAN fDialInNode=TRUE;
|
||
BOOLEAN fThisIsPPP;
|
||
|
||
TIME TimeS, TimeE, TimeD;
|
||
|
||
ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
|
||
|
||
TimeS = KeQueryPerformanceCounter(NULL);
|
||
|
||
if (PORT_CLOSING(pPortDesc))
|
||
{
|
||
// If we are not active, return!
|
||
return;
|
||
}
|
||
|
||
if (pPortDesc->pd_NdisPortType == NdisMedium802_5)
|
||
{
|
||
if (pLinkHdr[TLAP_SRC_OFFSET] & TLAP_SRC_ROUTING_MASK)
|
||
{
|
||
routeInfoLen = (pLinkHdr[TLAP_ROUTE_INFO_OFFSET] & TLAP_ROUTE_INFO_SIZE_MASK);
|
||
|
||
// First, glean any AARP information that we can, then handle the DDP
|
||
// packet. This guy also makes sure we have a good 802.2 header...
|
||
//
|
||
// Need to make a localcopy of the source address and then turn
|
||
// the source routing bit off before calling AarpGleanInfo
|
||
//
|
||
// (HdrBuf)[TLAP_SRC_OFFSET] = ((HdrBuf)[TLAP_SRC_OFFSET] & ~TLAP_SRC_ROUTING_MASK);
|
||
|
||
pLinkHdr[TLAP_SRC_OFFSET] &= ~TLAP_SRC_ROUTING_MASK;
|
||
pRouteInfo = pLinkHdr + TLAP_ROUTE_INFO_OFFSET;
|
||
}
|
||
}
|
||
|
||
startOfPkt = pPkt;
|
||
|
||
ASSERT(routeInfoLen <= TLAP_MAX_ROUTING_BYTES);
|
||
|
||
// Pull out the information we'll be playing with. All three valid AARP
|
||
// commands use the same packet format. But have some variable length
|
||
// fields.
|
||
|
||
// The packet will not include the 802.2 header!
|
||
// pPkt += IEEE8022_HDR_LEN;
|
||
// Length -= IEEE8022_HDR_LEN;
|
||
|
||
pPkt += AARP_HW_LEN_OFFSET; // Skip the hardware type
|
||
|
||
do
|
||
{
|
||
GETBYTE2SHORT (&hardwareLen, pPkt);
|
||
pPkt++ ;
|
||
|
||
if ((hardwareLen < AARP_MIN_HW_ADDR_LEN ) ||
|
||
(hardwareLen > AARP_MAX_HW_ADDR_LEN))
|
||
{
|
||
logEventPlace = (FILENUM | __LINE__);
|
||
break;
|
||
}
|
||
|
||
GETBYTE2SHORT(&protocolLength, pPkt);
|
||
pPkt ++;
|
||
|
||
if (protocolLength != AARP_PROTO_ADDR_LEN)
|
||
{
|
||
logEventPlace = (FILENUM | __LINE__);
|
||
break;
|
||
}
|
||
|
||
GETSHORT2SHORT(&aarpCommand, pPkt);
|
||
pPkt += 2;
|
||
|
||
// Remember where the source address is in the packet for
|
||
// entering it into the mapping table
|
||
srcAddr = pPkt;
|
||
|
||
// Skip over the source hardware length
|
||
// Skip over to leading null pad on logical address.
|
||
pPkt += (hardwareLen + 1);
|
||
|
||
GETSHORT2SHORT(&srcNode.atn_Network, pPkt);
|
||
pPkt += 2;
|
||
|
||
srcNode.atn_Node = *pPkt++;
|
||
|
||
// Skip the destination hardware address
|
||
// Skip over to leading null pad on logical destination address.
|
||
pPkt += (hardwareLen + 1);
|
||
|
||
GETSHORT2SHORT(&dstNode.atn_Network, pPkt);
|
||
pPkt += 2;
|
||
|
||
dstNode.atn_Node = *pPkt++;
|
||
|
||
// We should have eaten the whole packet...
|
||
if ((ULONG)(pPkt - startOfPkt) != Length)
|
||
{
|
||
logEventPlace = (FILENUM | __LINE__);
|
||
break;
|
||
}
|
||
|
||
// Ignore any AARPs from us.
|
||
|
||
ASSERT(hardwareLen == TLAP_ADDR_LEN);
|
||
if (AtalkFixedCompareCaseSensitive(srcAddr,
|
||
hardwareLen,
|
||
pPortDesc->pd_PortAddr,
|
||
hardwareLen))
|
||
{
|
||
break;
|
||
}
|
||
|
||
// Handle the Aarp command packets
|
||
switch(aarpCommand)
|
||
{
|
||
case AARP_REQUEST:
|
||
|
||
// We can get valid mapping info from a request, use it!
|
||
// We are guaranteed routing info is positive and is not odd
|
||
// (atleast 2 bytes).
|
||
|
||
ASSERT((routeInfoLen >= 0) && (routeInfoLen != 1));
|
||
if (routeInfoLen > 0)
|
||
atalkAarpTuneRouteInfo(pPortDesc, pRouteInfo);
|
||
|
||
atalkAarpEnterIntoAmt(pPortDesc,
|
||
&srcNode,
|
||
srcAddr,
|
||
hardwareLen,
|
||
pRouteInfo,
|
||
routeInfoLen);
|
||
|
||
// After that, we can ignore any request not destined for us.
|
||
if (!AtalkNodeExistsOnPort(pPortDesc, &dstNode))
|
||
{
|
||
// our dial-in clients can only be in the network range of the
|
||
// default port. If another adapter is plugged into the same net
|
||
// as the default adapter, we don't want dial-in clients to
|
||
// mess things up: ignore anything not coming on default adapter
|
||
// (as far as dial-in clients go)
|
||
if (pPortDesc != AtalkDefaultPort)
|
||
{
|
||
break;
|
||
}
|
||
|
||
//
|
||
// is this one of our dial-in "nodes"? If so, we must send out
|
||
// a proxy response from our DefaultPort.
|
||
//
|
||
if ((pRasConn = FindAndRefRasConnByAddr(dstNode,
|
||
&dwFlags,
|
||
&fThisIsPPP)) != NULL)
|
||
{
|
||
if (fThisIsPPP)
|
||
{
|
||
ASSERT(((PATCPCONN)pRasConn)->Signature == ATCPCONN_SIGNATURE);
|
||
DerefPPPConn((PATCPCONN)pRasConn);
|
||
}
|
||
else
|
||
{
|
||
ASSERT(((PARAPCONN)pRasConn)->Signature == ARAPCONN_SIGNATURE);
|
||
DerefArapConn((PARAPCONN)pRasConn);
|
||
}
|
||
}
|
||
|
||
//
|
||
// nope, a dial-in client with such a node addr doesn't exist either..
|
||
//
|
||
else
|
||
{
|
||
break;
|
||
}
|
||
}
|
||
|
||
// The're asking about us, speak the truth.
|
||
pBuffDesc = BUILD_AARPRESPONSE(pPortDesc,
|
||
hardwareLen,
|
||
srcAddr,
|
||
pRouteInfo,
|
||
routeInfoLen,
|
||
dstNode,
|
||
srcNode);
|
||
|
||
if (pBuffDesc == NULL)
|
||
{
|
||
DBGPRINT(DBG_COMP_AARP, DBG_LEVEL_ERR,
|
||
("AtalkAarpPacketIn: Mem alloc failed %d\n", __LINE__));
|
||
|
||
break;
|
||
}
|
||
|
||
if (!ATALK_SUCCESS(AtalkNdisSendPacket(pPortDesc,
|
||
pBuffDesc,
|
||
AtalkAarpSendComplete,
|
||
NULL)))
|
||
{
|
||
DBGPRINT(DBG_COMP_AARP, DBG_LEVEL_ERR,
|
||
("AtalkAarpPacketIn: SendPkt %lx failed %d\n",
|
||
pBuffDesc->bd_CharBuffer, __LINE__));
|
||
|
||
LOG_ERRORONPORT(pPortDesc,
|
||
EVENT_ATALK_AARP_SEND_FAIL,
|
||
STATUS_INSUFFICIENT_RESOURCES,
|
||
pBuffDesc->bd_CharBuffer,
|
||
Length);
|
||
|
||
// We allocated the packet.
|
||
AtalkAarpSendComplete(NDIS_STATUS_FAILURE,
|
||
pBuffDesc,
|
||
NULL);
|
||
|
||
}
|
||
break;
|
||
|
||
case AARP_RESPONSE:
|
||
|
||
ACQUIRE_SPIN_LOCK_DPC(&pPortDesc->pd_Lock);
|
||
if (pPortDesc->pd_Flags & PD_FINDING_NODE)
|
||
{
|
||
// No doubt, this is a response to our probe, check to make sure
|
||
// the address matches, if so set the "used" flag.
|
||
if (ATALK_NODES_EQUAL(&dstNode, &pPortDesc->pd_TentativeNodeAddr))
|
||
{
|
||
pPortDesc->pd_Flags |= PD_NODE_IN_USE;
|
||
|
||
// Wakeup the blocking thread...
|
||
KeSetEvent(&pPortDesc->pd_NodeAcquireEvent, IO_NETWORK_INCREMENT, FALSE);
|
||
}
|
||
}
|
||
RELEASE_SPIN_LOCK_DPC(&pPortDesc->pd_Lock);
|
||
|
||
// is this one of our dial-in "nodes"? If so, check if we are probing
|
||
if ((pRasConn = FindAndRefRasConnByAddr(dstNode,
|
||
&dwFlags,
|
||
&fThisIsPPP)) != NULL)
|
||
{
|
||
//
|
||
// our dial-in clients can only be in the network range of the
|
||
// default port
|
||
//
|
||
ASSERT(pPortDesc == AtalkDefaultPort);
|
||
|
||
pAtcpConn = NULL;
|
||
pArapConn = NULL;
|
||
|
||
if (fThisIsPPP)
|
||
{
|
||
pAtcpConn = (PATCPCONN)pRasConn;
|
||
ASSERT(pAtcpConn->Signature == ATCPCONN_SIGNATURE);
|
||
}
|
||
else
|
||
{
|
||
pArapConn = (PARAPCONN)pRasConn;
|
||
ASSERT(pArapConn->Signature == ARAPCONN_SIGNATURE);
|
||
}
|
||
|
||
// PPP client?
|
||
if (pAtcpConn)
|
||
{
|
||
if (dwFlags & ATCP_FINDING_NODE)
|
||
{
|
||
ACQUIRE_SPIN_LOCK_DPC(&pAtcpConn->SpinLock);
|
||
|
||
DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_WARN,
|
||
("AtalkAarpPacketIn: PPP: someone owns %lx %x, retrying\n",
|
||
dstNode.atn_Network,dstNode.atn_Node));
|
||
|
||
pAtcpConn->Flags |= ATCP_NODE_IN_USE;
|
||
|
||
// Wakeup the blocking thread...
|
||
KeSetEvent(&pAtcpConn->NodeAcquireEvent,
|
||
IO_NETWORK_INCREMENT,
|
||
FALSE);
|
||
|
||
RELEASE_SPIN_LOCK_DPC(&pAtcpConn->SpinLock);
|
||
}
|
||
|
||
// remove refcount put by FindAndRefRasConnByAddr
|
||
DerefPPPConn(pAtcpConn);
|
||
}
|
||
// nope, ARAP client
|
||
else
|
||
{
|
||
if (dwFlags & ARAP_FINDING_NODE)
|
||
{
|
||
ACQUIRE_SPIN_LOCK_DPC(&pArapConn->SpinLock);
|
||
|
||
DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_WARN,
|
||
("AtalkAarpPacketIn: ARAP: someone owns %lx %x, retrying\n",
|
||
dstNode.atn_Network,dstNode.atn_Node));
|
||
|
||
pArapConn->Flags |= ARAP_NODE_IN_USE;
|
||
|
||
// Wakeup the blocking thread...
|
||
KeSetEvent(&pArapConn->NodeAcquireEvent,
|
||
IO_NETWORK_INCREMENT,
|
||
FALSE);
|
||
|
||
RELEASE_SPIN_LOCK_DPC(&pArapConn->SpinLock);
|
||
}
|
||
|
||
// remove refcount put by FindAndRefRasConnByAddr
|
||
DerefArapConn(pArapConn);
|
||
}
|
||
}
|
||
|
||
// This must have been a response to a probe or request... update our
|
||
// mapping table.
|
||
if (routeInfoLen != 0)
|
||
{
|
||
atalkAarpTuneRouteInfo(pPortDesc, pRouteInfo);
|
||
}
|
||
|
||
atalkAarpEnterIntoAmt(pPortDesc,
|
||
&srcNode,
|
||
srcAddr,
|
||
hardwareLen,
|
||
pRouteInfo,
|
||
routeInfoLen);
|
||
break;
|
||
|
||
case AARP_PROBE:
|
||
|
||
ACQUIRE_SPIN_LOCK_DPC(&pPortDesc->pd_Lock);
|
||
if (pPortDesc->pd_Flags & PD_FINDING_NODE)
|
||
{
|
||
// If we get a probe for our current tentative address, set the
|
||
// "used" flag.
|
||
if (ATALK_NODES_EQUAL(&dstNode, &pPortDesc->pd_TentativeNodeAddr))
|
||
{
|
||
pPortDesc->pd_Flags |= PD_NODE_IN_USE;
|
||
|
||
KeSetEvent(&pPortDesc->pd_NodeAcquireEvent,
|
||
IO_NETWORK_INCREMENT,
|
||
FALSE);
|
||
}
|
||
}
|
||
RELEASE_SPIN_LOCK_DPC(&pPortDesc->pd_Lock);
|
||
|
||
if (pPortDesc != AtalkDefaultPort)
|
||
{
|
||
break;
|
||
}
|
||
|
||
fDialInNode = FALSE;
|
||
|
||
// is the probe asking about one of our dial-in nodes? if so, we
|
||
// must defend that address (or, if we are trying to acquire this
|
||
// node addr, stop that since someone else is doing the same)
|
||
//
|
||
// our dial-in clients can only be in the network range of the
|
||
// default port. If another adapter is plugged into the same net
|
||
// as the default adapter, we don't want dial-in clients to
|
||
// mess things up: ignore anything not coming on default adapter
|
||
// (as far as dial-in clients go)
|
||
if ((pPortDesc == AtalkDefaultPort) &&
|
||
((pRasConn = FindAndRefRasConnByAddr(dstNode,
|
||
&dwFlags,
|
||
&fThisIsPPP)) != NULL))
|
||
{
|
||
|
||
pAtcpConn = NULL;
|
||
pArapConn = NULL;
|
||
|
||
if (fThisIsPPP)
|
||
{
|
||
pAtcpConn = (PATCPCONN)pRasConn;
|
||
ASSERT(pAtcpConn->Signature == ATCPCONN_SIGNATURE);
|
||
}
|
||
else
|
||
{
|
||
pArapConn = (PARAPCONN)pRasConn;
|
||
ASSERT(pArapConn->Signature == ARAPCONN_SIGNATURE);
|
||
}
|
||
|
||
// PPP client?
|
||
if (pAtcpConn)
|
||
{
|
||
if (dwFlags & ATCP_FINDING_NODE)
|
||
{
|
||
ACQUIRE_SPIN_LOCK_DPC(&pAtcpConn->SpinLock);
|
||
|
||
DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_WARN,
|
||
("AtalkAarpPacketIn: PPP: someone trying to acquire %lx %x, retrying\n",
|
||
dstNode.atn_Network,dstNode.atn_Node));
|
||
|
||
pAtcpConn->Flags |= ATCP_NODE_IN_USE;
|
||
|
||
// Wakeup the blocking thread...
|
||
KeSetEvent(&pAtcpConn->NodeAcquireEvent,
|
||
IO_NETWORK_INCREMENT,
|
||
FALSE);
|
||
|
||
RELEASE_SPIN_LOCK_DPC(&pAtcpConn->SpinLock);
|
||
}
|
||
else
|
||
{
|
||
fDialInNode = TRUE;
|
||
}
|
||
|
||
// remove refcount put by FindAndRefRasConnByAddr
|
||
DerefPPPConn(pAtcpConn);
|
||
|
||
}
|
||
// nope, ARAP client
|
||
else
|
||
{
|
||
if (dwFlags & ARAP_FINDING_NODE)
|
||
{
|
||
ACQUIRE_SPIN_LOCK_DPC(&pArapConn->SpinLock);
|
||
|
||
DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_WARN,
|
||
("AtalkAarpPacketIn: ARAP: someone trying to acquire %lx %x, retrying\n",
|
||
dstNode.atn_Network,dstNode.atn_Node));
|
||
|
||
pArapConn->Flags |= ARAP_NODE_IN_USE;
|
||
|
||
// Wakeup the blocking thread...
|
||
KeSetEvent(&pArapConn->NodeAcquireEvent,
|
||
IO_NETWORK_INCREMENT,
|
||
FALSE);
|
||
|
||
RELEASE_SPIN_LOCK_DPC(&pArapConn->SpinLock);
|
||
}
|
||
else
|
||
{
|
||
fDialInNode = TRUE;
|
||
}
|
||
|
||
// remove refcount put by FindAndRefRasConnByAddr
|
||
DerefArapConn(pArapConn);
|
||
}
|
||
}
|
||
|
||
// If the probe isn't asking about one of our AppleTalk addresses,
|
||
// and it's not one of our dial-in nodes either, drop it on the floor.
|
||
if (!fDialInNode && !AtalkNodeExistsOnPort(pPortDesc, &dstNode))
|
||
{
|
||
break;
|
||
}
|
||
|
||
// The're talking to us! Build and send the response.
|
||
if (routeInfoLen != 0)
|
||
{
|
||
atalkAarpTuneRouteInfo(pPortDesc, pRouteInfo);
|
||
}
|
||
|
||
if (fDialInNode)
|
||
{
|
||
DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
|
||
("AtalkAarpPacketIn: defending dial-in client's addr %x %x\n",
|
||
dstNode.atn_Network,dstNode.atn_Node));
|
||
}
|
||
|
||
pBuffDesc = BUILD_AARPRESPONSE(pPortDesc,
|
||
hardwareLen,
|
||
srcAddr,
|
||
pRouteInfo,
|
||
routeInfoLen,
|
||
dstNode,
|
||
srcNode);
|
||
|
||
if (pBuffDesc == NULL)
|
||
{
|
||
DBGPRINT(DBG_COMP_AARP, DBG_LEVEL_ERR,
|
||
("AtalkAarpPacketIn: Mem alloc failed %d\n", __LINE__));
|
||
|
||
break;
|
||
}
|
||
|
||
if (!ATALK_SUCCESS(AtalkNdisSendPacket(pPortDesc,
|
||
pBuffDesc,
|
||
AtalkAarpSendComplete,
|
||
NULL)))
|
||
{
|
||
DBGPRINT(DBG_COMP_AARP, DBG_LEVEL_ERR,
|
||
("AtalkAarpPacketIn: SendPkt %lx failed %d\n",
|
||
pBuffDesc->bd_CharBuffer, __LINE__));
|
||
|
||
LOG_ERRORONPORT(pPortDesc,
|
||
EVENT_ATALK_AARP_SEND_FAIL,
|
||
STATUS_INSUFFICIENT_RESOURCES,
|
||
pBuffDesc->bd_CharBuffer,
|
||
Length);
|
||
|
||
// We allocated the packet. This will free it up.
|
||
AtalkAarpSendComplete(NDIS_STATUS_FAILURE,
|
||
pBuffDesc,
|
||
NULL);
|
||
|
||
}
|
||
break;
|
||
|
||
default:
|
||
logEventPlace = (FILENUM | __LINE__);
|
||
break;
|
||
}
|
||
} while (FALSE);
|
||
|
||
if (logEventPlace)
|
||
{
|
||
LOG_ERRORONPORT(pPortDesc,
|
||
EVENT_ATALK_INVALIDAARPPACKET,
|
||
logEventPlace,
|
||
startOfPkt,
|
||
Length);
|
||
}
|
||
|
||
TimeE = KeQueryPerformanceCounter(NULL);
|
||
|
||
TimeD.QuadPart = TimeE.QuadPart - TimeS.QuadPart;
|
||
|
||
INTERLOCKED_ADD_LARGE_INTGR_DPC(
|
||
&pPortDesc->pd_PortStats.prtst_AarpPacketInProcessTime,
|
||
TimeD,
|
||
&AtalkStatsLock.SpinLock);
|
||
|
||
INTERLOCKED_INCREMENT_LONG_DPC(
|
||
&pPortDesc->pd_PortStats.prtst_NumAarpPacketsIn,
|
||
&AtalkStatsLock.SpinLock);
|
||
}
|
||
|
||
|
||
|
||
|
||
VOID
|
||
AtalkAarpSendComplete(
|
||
NDIS_STATUS Status,
|
||
PBUFFER_DESC pBuffDesc,
|
||
PSEND_COMPL_INFO pSendInfo
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
|
||
Arguments:
|
||
|
||
|
||
Return Value:
|
||
|
||
|
||
--*/
|
||
{
|
||
ASSERT(pBuffDesc->bd_Next == NULL);
|
||
ASSERT(pBuffDesc->bd_Flags & BD_CHAR_BUFFER);
|
||
|
||
AtalkNdisFreeBuf(pBuffDesc);
|
||
}
|
||
|
||
|
||
|
||
|
||
#define AtalkAarpUpdateBre(_pPortDesc, \
|
||
_Network, \
|
||
_SrcAddr, \
|
||
_AddrLen, \
|
||
_RouteInfo, \
|
||
_RouteInfoLen) \
|
||
{ \
|
||
PBRE pBre, *ppBre; \
|
||
int index; \
|
||
BLKID BlkId; \
|
||
\
|
||
DBGPRINT(DBG_COMP_AARP, DBG_LEVEL_INFO, \
|
||
("AtalkAarpUpdateBre: Entering %x in brc\n", _Network)); \
|
||
\
|
||
index = (int)((_Network) & (PORT_BRC_HASH_SIZE - 1)); \
|
||
\
|
||
ACQUIRE_SPIN_LOCK_DPC(&(_pPortDesc)->pd_Lock); \
|
||
\
|
||
for (ppBre = &(_pPortDesc)->pd_Brc[index]; \
|
||
(pBre = *ppBre) != NULL; \
|
||
ppBre = &pBre->bre_Next) \
|
||
{ \
|
||
if (pBre->bre_Network == (_Network)) \
|
||
{ \
|
||
/* \
|
||
* Unlink it from the list since it could potentially \
|
||
* be freed if the routeinfolen grew and also we want \
|
||
* to link it again at the head of the list \
|
||
*/ \
|
||
*ppBre = pBre->bre_Next; \
|
||
break; \
|
||
} \
|
||
} \
|
||
\
|
||
if ((pBre != NULL) && \
|
||
(pBre->bre_RouteInfoLen < (BYTE)(_RouteInfoLen))) \
|
||
{ \
|
||
AtalkBPFreeBlock(pBre); \
|
||
pBre = NULL; \
|
||
} \
|
||
\
|
||
if (pBre == NULL) \
|
||
{ \
|
||
BlkId = BLKID_BRE; \
|
||
if ((_RouteInfoLen) != 0) \
|
||
BlkId = BLKID_BRE_ROUTE; \
|
||
pBre = (PBRE)AtalkBPAllocBlock(BlkId); \
|
||
} \
|
||
\
|
||
if (pBre != NULL) \
|
||
{ \
|
||
pBre->bre_Age = 0; \
|
||
pBre->bre_Network = (_Network); \
|
||
\
|
||
COPY_NETWORK_ADDR(pBre->bre_RouterAddr, \
|
||
_SrcAddr); \
|
||
\
|
||
pBre->bre_RouteInfoLen =(BYTE)(_RouteInfoLen); \
|
||
\
|
||
if ((_RouteInfoLen) > 0) \
|
||
RtlCopyMemory((PBYTE)pBre + sizeof(BRE), \
|
||
_RouteInfo, \
|
||
_RouteInfoLen); \
|
||
\
|
||
pBre->bre_Next = *ppBre; \
|
||
*ppBre = pBre; \
|
||
} \
|
||
\
|
||
RELEASE_SPIN_LOCK_DPC(&(_pPortDesc)->pd_Lock); \
|
||
}
|
||
|
||
BOOLEAN
|
||
AtalkAarpGleanInfo(
|
||
IN OUT PPORT_DESCRIPTOR pPortDesc,
|
||
IN PBYTE SrcAddr,
|
||
IN SHORT AddrLen,
|
||
IN OUT PBYTE RouteInfo,
|
||
IN USHORT RouteInfoLen,
|
||
IN PBYTE pPkt,
|
||
IN USHORT Length
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
|
||
Arguments:
|
||
|
||
|
||
Return Value:
|
||
|
||
|
||
--*/
|
||
{
|
||
ATALK_NODEADDR srcNode, dstNode;
|
||
PBYTE startOfPkt;
|
||
ULONG logEventPlace = 0;
|
||
BYTE offCableInfo;
|
||
BOOLEAN result = TRUE;
|
||
|
||
if (PORT_CLOSING(pPortDesc))
|
||
{
|
||
// If we are not active, return!
|
||
return FALSE;
|
||
}
|
||
|
||
// Packet will not include the 802.2 header!
|
||
// pPkt += IEEE8022_HDR_LEN;
|
||
// Length -= IEEE8022_HDR_LEN;
|
||
|
||
// Remember the start of the packet
|
||
startOfPkt = pPkt;
|
||
|
||
// Get the off cable information
|
||
offCableInfo = *pPkt;
|
||
|
||
// Skip the datagram length and checksum fields
|
||
pPkt += (2 + 2);
|
||
|
||
// Get the destination network number
|
||
GETSHORT2SHORT(&dstNode.atn_Network, pPkt);
|
||
pPkt += sizeof(USHORT);
|
||
|
||
// Get the source network number
|
||
GETSHORT2SHORT(&srcNode.atn_Network, pPkt);
|
||
pPkt += sizeof(USHORT);
|
||
|
||
// Get the destination node id
|
||
dstNode.atn_Node = *pPkt++;
|
||
|
||
// Get the source node id
|
||
srcNode.atn_Node = *pPkt++;
|
||
|
||
do
|
||
{
|
||
// Do a little verification.
|
||
if ((srcNode.atn_Node < MIN_USABLE_ATALKNODE) ||
|
||
(srcNode.atn_Node > MAX_USABLE_ATALKNODE) ||
|
||
(srcNode.atn_Network < FIRST_VALID_NETWORK) ||
|
||
(srcNode.atn_Network > LAST_VALID_NETWORK))
|
||
{
|
||
// Only bother logging this if we are in some routing capacity,
|
||
// otherwise, let A-ROUTER worry about it
|
||
if (AtalkRouter)
|
||
{
|
||
DBGPRINT(DBG_COMP_AARP, DBG_LEVEL_ERR,
|
||
("AtalkAarpGleanInfo: dstNode invalid %x.%x\n",
|
||
srcNode.atn_Network, srcNode.atn_Node));
|
||
logEventPlace = FILENUM | __LINE__;
|
||
}
|
||
break;
|
||
}
|
||
|
||
if (dstNode.atn_Network > LAST_VALID_NETWORK)
|
||
{
|
||
DBGPRINT(DBG_COMP_AARP, DBG_LEVEL_ERR,
|
||
("AtalkAarpGleanInfo: srcNode invalid %x.%x\n",
|
||
dstNode.atn_Network, dstNode.atn_Node));
|
||
logEventPlace = FILENUM | __LINE__;
|
||
break;
|
||
}
|
||
|
||
// Did the packet come from off this cable? Look at the hop count. If so,
|
||
// enter it into our best-router cache.
|
||
//
|
||
// **NOTE** We assume that the RouteInfo buffer can be written to!
|
||
|
||
if (RouteInfoLen > 0)
|
||
atalkAarpTuneRouteInfo(pPortDesc, RouteInfo);
|
||
|
||
if ((offCableInfo >> 2) & AARP_OFFCABLE_MASK)
|
||
{
|
||
AtalkAarpUpdateBre(pPortDesc,
|
||
srcNode.atn_Network,
|
||
SrcAddr,
|
||
AddrLen,
|
||
RouteInfo,
|
||
RouteInfoLen);
|
||
}
|
||
else
|
||
{
|
||
DBGPRINT(DBG_COMP_AARP, DBG_LEVEL_INFO,
|
||
("AtalkAarpGleanInfo: Entering %x.%x info in Amt tables\n",
|
||
srcNode.atn_Network, srcNode.atn_Node));
|
||
|
||
// "Glean" AARP information from on-cable packets.
|
||
atalkAarpEnterIntoAmt(pPortDesc,
|
||
&srcNode,
|
||
SrcAddr,
|
||
AddrLen,
|
||
RouteInfo,
|
||
RouteInfoLen);
|
||
}
|
||
} while (FALSE);
|
||
|
||
if (logEventPlace)
|
||
{
|
||
LOG_ERRORONPORT(pPortDesc,
|
||
EVENT_ATALK_INVALIDAARPPACKET,
|
||
logEventPlace,
|
||
startOfPkt,
|
||
Length);
|
||
}
|
||
|
||
return (logEventPlace == 0);
|
||
}
|
||
|
||
|
||
VOID
|
||
AtalkAarpOptGleanInfo(
|
||
IN OUT PPORT_DESCRIPTOR pPortDesc,
|
||
IN PBYTE pLinkHdr,
|
||
IN PATALK_ADDR pSrcAddr,
|
||
IN PATALK_ADDR pDestAddr,
|
||
IN BOOLEAN OffCablePkt
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
|
||
Arguments:
|
||
|
||
|
||
Return Value:
|
||
|
||
|
||
--*/
|
||
{
|
||
ATALK_NODEADDR srcNode, dstNode;
|
||
int index;
|
||
PBYTE pRouteInfo;
|
||
USHORT routeLen = 0, srcOffset;
|
||
|
||
if (PORT_CLOSING(pPortDesc))
|
||
{
|
||
// If we are not active, return!
|
||
return;
|
||
}
|
||
|
||
switch (pPortDesc->pd_NdisPortType)
|
||
{
|
||
case NdisMedium802_5:
|
||
|
||
if (pLinkHdr[TLAP_SRC_OFFSET] & TLAP_SRC_ROUTING_MASK)
|
||
{
|
||
routeLen = (pLinkHdr[TLAP_ROUTE_INFO_OFFSET] & TLAP_ROUTE_INFO_SIZE_MASK);
|
||
|
||
//
|
||
// First, glean any AARP information that we can, then handle the DDP
|
||
// packet. This guy also makes sure we have a good 802.2 header...
|
||
//
|
||
// Need to make a localcopy of the source address and then turn
|
||
// the source routing bit off before calling AarpGleanInfo
|
||
//
|
||
// (HdrBuf)[TLAP_SRC_OFFSET] = ((HdrBuf)[TLAP_SRC_OFFSET] & ~TLAP_SRC_ROUTING_MASK);
|
||
//
|
||
|
||
pLinkHdr[TLAP_SRC_OFFSET] &= ~TLAP_SRC_ROUTING_MASK;
|
||
pRouteInfo = pLinkHdr + TLAP_ROUTE_INFO_OFFSET;
|
||
}
|
||
srcOffset = TLAP_SRC_OFFSET;
|
||
break;
|
||
|
||
case NdisMedium802_3:
|
||
srcOffset = ELAP_SRC_OFFSET;
|
||
break;
|
||
|
||
case NdisMediumFddi:
|
||
srcOffset = FDDI_SRC_OFFSET;
|
||
break;
|
||
|
||
default:
|
||
KeBugCheck(0);
|
||
break;
|
||
}
|
||
|
||
// Get the destination network number
|
||
dstNode.atn_Network = pDestAddr->ata_Network;
|
||
dstNode.atn_Node = pDestAddr->ata_Node;
|
||
srcNode.atn_Network = pSrcAddr->ata_Network;
|
||
srcNode.atn_Node = pSrcAddr->ata_Node;
|
||
|
||
do
|
||
{
|
||
// Do a little verification.
|
||
if ((srcNode.atn_Node < MIN_USABLE_ATALKNODE) ||
|
||
(srcNode.atn_Node > MAX_USABLE_ATALKNODE) ||
|
||
(srcNode.atn_Network < FIRST_VALID_NETWORK) ||
|
||
(srcNode.atn_Network > LAST_VALID_NETWORK))
|
||
{
|
||
break;
|
||
}
|
||
|
||
if (dstNode.atn_Network > LAST_VALID_NETWORK)
|
||
{
|
||
break;
|
||
}
|
||
|
||
// Did the packet come from off this cable? Look at the hop count. If so,
|
||
// enter it into our best-router cache.
|
||
//
|
||
// **NOTE** We assume that the pRouteInfo buffer can be written to!
|
||
|
||
if (routeLen > 0)
|
||
atalkAarpTuneRouteInfo(pPortDesc, pRouteInfo);
|
||
|
||
if (OffCablePkt)
|
||
{
|
||
AtalkAarpUpdateBre(pPortDesc,
|
||
srcNode.atn_Network,
|
||
pLinkHdr + srcOffset,
|
||
ELAP_ADDR_LEN,
|
||
pRouteInfo,
|
||
routeLen);
|
||
}
|
||
else
|
||
{
|
||
DBGPRINT(DBG_COMP_AARP, DBG_LEVEL_INFO,
|
||
("AtalkAarpGleanInfo: Entering %x.%x info in Amt tables\n",
|
||
srcNode.atn_Network, srcNode.atn_Node));
|
||
|
||
// "Glean" AARP information from on-cable packets.
|
||
atalkAarpEnterIntoAmt(pPortDesc,
|
||
&srcNode,
|
||
pLinkHdr + srcOffset,
|
||
ELAP_ADDR_LEN,
|
||
pRouteInfo,
|
||
routeLen);
|
||
}
|
||
|
||
} while (FALSE);
|
||
}
|
||
|
||
|
||
ATALK_ERROR
|
||
AtalkInitAarpForNodeOnPort(
|
||
IN PPORT_DESCRIPTOR pPortDesc,
|
||
IN BOOLEAN AllowStartupRange,
|
||
IN ATALK_NODEADDR DesiredNode,
|
||
IN OUT PATALK_NODE * ppAtalkNode
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
|
||
Arguments:
|
||
|
||
|
||
Return Value:
|
||
|
||
|
||
--*/
|
||
{
|
||
ATALK_ERROR error;
|
||
PDDP_ADDROBJ pDdpAddr;
|
||
ATALK_NODEADDR newNode;
|
||
PATALK_NODE pAtalkNode;
|
||
KIRQL OldIrql;
|
||
BOOLEAN foundNode = FALSE;
|
||
BOOLEAN inStartupRange = FALSE, result = TRUE;
|
||
|
||
if (!ATALK_SUCCESS(AtalkInitNodeAllocate(pPortDesc, &pAtalkNode)))
|
||
{
|
||
return ATALK_RESR_MEM;
|
||
}
|
||
|
||
// Try to find a new extended Node on the given port; first try for the
|
||
// requested address (if specified), else try in this port's cable range
|
||
// (if it's known) or in the default cable range (if any), then try the
|
||
// start-up range (if allowed).
|
||
|
||
do
|
||
{
|
||
if (DesiredNode.atn_Network != UNKNOWN_NETWORK)
|
||
{
|
||
if (((pPortDesc->pd_Flags & PD_SEEN_ROUTER_RECENTLY) == 0) ||
|
||
(WITHIN_NETWORK_RANGE(DesiredNode.atn_Network, &pPortDesc->pd_NetworkRange)))
|
||
{
|
||
foundNode = atalkInitAarpForNode(pPortDesc,
|
||
NULL, // not a dial-in client
|
||
FALSE, // don't care
|
||
DesiredNode.atn_Network,
|
||
DesiredNode.atn_Node);
|
||
|
||
}
|
||
// leave if we found a node.
|
||
if (foundNode)
|
||
{
|
||
newNode = DesiredNode;
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (pPortDesc->pd_Flags & PD_SEEN_ROUTER_RECENTLY)
|
||
{
|
||
foundNode = AtalkInitAarpForNodeInRange(pPortDesc,
|
||
NULL, // not a dial-in client
|
||
FALSE, // don't care
|
||
pPortDesc->pd_NetworkRange,
|
||
&newNode);
|
||
|
||
// leave if we found a node.
|
||
if (foundNode)
|
||
{
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (pPortDesc->pd_InitialNetworkRange.anr_FirstNetwork != UNKNOWN_NETWORK)
|
||
{
|
||
foundNode = AtalkInitAarpForNodeInRange(pPortDesc,
|
||
NULL, // not a dial-in client
|
||
FALSE, // don't care
|
||
pPortDesc->pd_InitialNetworkRange,
|
||
&newNode);
|
||
|
||
// leave if we found a node.
|
||
if (foundNode)
|
||
{
|
||
break;
|
||
}
|
||
}
|
||
|
||
// If no place else to try, try the start-up range. Do this even if
|
||
// we don't want to end up there.
|
||
//
|
||
// The idea is that this happens only when we are starting the router
|
||
// on one of our ports. So we do not want the router started in the
|
||
// startup range. If we do start in the startup range, and we see later
|
||
// that we did not see a router in the process,
|
||
// we will release the node. Of course, if we are a seed router, we will
|
||
// never be here, as the if statement above will be true.
|
||
//
|
||
|
||
inStartupRange = TRUE;
|
||
foundNode = AtalkInitAarpForNodeInRange(pPortDesc,
|
||
NULL, // not a dial-in client
|
||
FALSE, // don't care
|
||
AtalkStartupNetworkRange,
|
||
&newNode);
|
||
break;
|
||
|
||
} while (FALSE);
|
||
|
||
// If we have a tentative Node, go on.
|
||
if (foundNode)
|
||
{
|
||
do
|
||
{
|
||
// Use the allocated structure to set the info.
|
||
// Thread this into the port structure.
|
||
pAtalkNode->an_NodeAddr = newNode;
|
||
|
||
ACQUIRE_SPIN_LOCK(&pPortDesc->pd_Lock, &OldIrql);
|
||
|
||
// Reference the port for this node.
|
||
AtalkPortRefByPtrNonInterlock(pPortDesc, &error);
|
||
if (!ATALK_SUCCESS(error))
|
||
{
|
||
result = FALSE;
|
||
RELEASE_SPIN_LOCK(&pPortDesc->pd_Lock, OldIrql);
|
||
AtalkFreeMemory(pAtalkNode);
|
||
break;
|
||
}
|
||
|
||
// Now put it in the port descriptor
|
||
pAtalkNode->an_Next = pPortDesc->pd_Nodes;
|
||
pPortDesc->pd_Nodes = pAtalkNode;
|
||
RELEASE_SPIN_LOCK(&pPortDesc->pd_Lock, OldIrql);
|
||
|
||
// See who's out there. We need to open the ZIP socket in order to be
|
||
// able to hear replies.
|
||
if (!ATALK_SUCCESS(AtalkDdpOpenAddress(pPortDesc,
|
||
ZONESINFORMATION_SOCKET,
|
||
&newNode,
|
||
AtalkZipPacketIn,
|
||
NULL,
|
||
DDPPROTO_ANY,
|
||
NULL,
|
||
&pDdpAddr)))
|
||
{
|
||
LOG_ERRORONPORT(pPortDesc,
|
||
EVENT_ATALK_OPENZIPSOCKET,
|
||
0,
|
||
NULL,
|
||
0);
|
||
|
||
AtalkNodeReleaseOnPort(pPortDesc, pAtalkNode);
|
||
|
||
result = FALSE;
|
||
break;
|
||
}
|
||
|
||
// mark the fact that this is an "internal" socket
|
||
pDdpAddr->ddpao_Flags |= DDPAO_SOCK_INTERNAL;
|
||
|
||
|
||
if (!(pPortDesc->pd_Flags & PD_SEEN_ROUTER_RECENTLY))
|
||
{
|
||
// Get the default zone
|
||
AtalkZipGetNetworkInfoForNode(pPortDesc, &pAtalkNode->an_NodeAddr, TRUE);
|
||
|
||
// Validate the desired zone
|
||
AtalkZipGetNetworkInfoForNode(pPortDesc, &pAtalkNode->an_NodeAddr, FALSE);
|
||
}
|
||
|
||
// If nobody was out there and our tentative Node was in the
|
||
// startup range and our caller doesn't want to be there, return
|
||
// an error now.
|
||
//
|
||
// Note: this means that we were trying to start the router on
|
||
// a non-seeding port, and since there is not router on the net,
|
||
// it means the net is not seeded and so, we exit.
|
||
|
||
if (inStartupRange &&
|
||
!(pPortDesc->pd_Flags & PD_SEEN_ROUTER_RECENTLY) &&
|
||
!AllowStartupRange)
|
||
{
|
||
LOG_ERRORONPORT(pPortDesc,
|
||
EVENT_ATALK_STARTUPRANGENODE,
|
||
0,
|
||
NULL,
|
||
0);
|
||
|
||
AtalkNodeReleaseOnPort(pPortDesc, pAtalkNode);
|
||
|
||
result = FALSE;
|
||
break;
|
||
}
|
||
|
||
// If we have seen SeenRouterRecently is not true, that means we have
|
||
// used the InitialNetworkRange to AARP. If now SeenRouterRecently is
|
||
// true that means we have gotten the address in the InitialNetworkRange,
|
||
// but now there is a seeded range on the net that we must use. So redo
|
||
// the GetNode work.
|
||
|
||
if ((pPortDesc->pd_Flags & PD_SEEN_ROUTER_RECENTLY) &&
|
||
!WITHIN_NETWORK_RANGE(newNode.atn_Network,
|
||
&pPortDesc->pd_NetworkRange))
|
||
{
|
||
LOG_ERRORONPORT(pPortDesc,
|
||
EVENT_ATALK_INITIALRANGENODE,
|
||
0,
|
||
NULL,
|
||
0);
|
||
|
||
// Release the node we obtained.
|
||
AtalkNodeReleaseOnPort(pPortDesc, pAtalkNode);
|
||
|
||
// Get another node and retry in the correct range.
|
||
ASSERTMSG("NetworkRange still set to startup!\n",
|
||
pPortDesc->pd_NetworkRange.anr_FirstNetwork != UNKNOWN_NETWORK);
|
||
|
||
foundNode = AtalkInitAarpForNodeInRange(pPortDesc,
|
||
NULL, // not a dial-in client
|
||
FALSE, // don't care
|
||
pPortDesc->pd_NetworkRange,
|
||
&newNode);
|
||
|
||
if (foundNode)
|
||
{
|
||
ASSERTMSG("New node is not within NetworkRange!\n",
|
||
WITHIN_NETWORK_RANGE(newNode.atn_Network,
|
||
&pPortDesc->pd_NetworkRange));
|
||
|
||
if (!ATALK_SUCCESS(AtalkInitNodeAllocate(pPortDesc, &pAtalkNode)))
|
||
{
|
||
result = FALSE;
|
||
break;
|
||
}
|
||
|
||
// Use the allocated structure to set the info.
|
||
// Thread this into the port structure.
|
||
pAtalkNode->an_NodeAddr = newNode;
|
||
|
||
// Reference the port for this node.
|
||
AtalkPortReferenceByPtr(pPortDesc, &error);
|
||
if (!ATALK_SUCCESS(error))
|
||
{
|
||
result = FALSE;
|
||
AtalkFreeMemory(pAtalkNode);
|
||
break;
|
||
}
|
||
|
||
// Now put it in the port descriptor
|
||
ACQUIRE_SPIN_LOCK(&pPortDesc->pd_Lock, &OldIrql);
|
||
pAtalkNode->an_Next = pPortDesc->pd_Nodes;
|
||
pPortDesc->pd_Nodes = pAtalkNode;
|
||
RELEASE_SPIN_LOCK(&pPortDesc->pd_Lock, OldIrql);
|
||
|
||
// Open the zip socket to be consistent
|
||
if (!ATALK_SUCCESS(AtalkDdpOpenAddress(pPortDesc,
|
||
ZONESINFORMATION_SOCKET,
|
||
&newNode,
|
||
AtalkZipPacketIn,
|
||
NULL,
|
||
DDPPROTO_ANY,
|
||
NULL,
|
||
&pDdpAddr)))
|
||
{
|
||
LOG_ERRORONPORT(pPortDesc,
|
||
EVENT_ATALK_OPENZIPSOCKET,
|
||
0,
|
||
NULL,
|
||
0);
|
||
|
||
AtalkNodeReleaseOnPort(pPortDesc, pAtalkNode);
|
||
|
||
result = FALSE;
|
||
break;
|
||
}
|
||
|
||
// mark the fact that this is an "internal" socket
|
||
pDdpAddr->ddpao_Flags |= DDPAO_SOCK_INTERNAL;
|
||
}
|
||
}
|
||
|
||
} while (FALSE);
|
||
}
|
||
else
|
||
{
|
||
// Free the allocated node structure. This has not yet been
|
||
// inserted into the port descriptor, so we can just free it.
|
||
AtalkFreeMemory(pAtalkNode);
|
||
}
|
||
|
||
if (foundNode && result)
|
||
{
|
||
// All set!
|
||
ASSERT(ppAtalkNode != NULL);
|
||
*ppAtalkNode = pAtalkNode;
|
||
|
||
// atalkAarpEnterIntoAmt() expects to be called at DISPATCH_LEVEL. Make it so.
|
||
KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
|
||
|
||
atalkAarpEnterIntoAmt(pPortDesc,
|
||
&newNode,
|
||
pPortDesc->pd_PortAddr,
|
||
MAX_HW_ADDR_LEN,
|
||
NULL,
|
||
0);
|
||
KeLowerIrql(OldIrql);
|
||
|
||
|
||
}
|
||
|
||
return ((foundNode && result) ? ATALK_NO_ERROR : ATALK_FAILURE);
|
||
}
|
||
|
||
|
||
|
||
BOOLEAN
|
||
AtalkInitAarpForNodeInRange(
|
||
IN PPORT_DESCRIPTOR pPortDesc,
|
||
IN PVOID pRasConn,
|
||
IN BOOLEAN fThisIsPPP,
|
||
IN ATALK_NETWORKRANGE NetworkRange,
|
||
OUT PATALK_NODEADDR Node
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
|
||
Arguments:
|
||
|
||
|
||
Return Value:
|
||
|
||
|
||
--*/
|
||
{
|
||
BYTE currentNode;
|
||
USHORT currentNetwork;
|
||
int firstNode, lastNode;
|
||
long netTry;
|
||
int nodeTry;
|
||
USHORT nodeWidth, nodeChange, nodeIndex;
|
||
USHORT netWidth, netChange, netIndex;
|
||
BOOLEAN found = FALSE;
|
||
|
||
// Pick the node number range we'll try for (we do not pay attention to the
|
||
// "ServerNode" concept for LocalTalk). Our node is obtained by the
|
||
// localtalk driver anyways.
|
||
firstNode = MIN_USABLE_ATALKNODE;
|
||
lastNode = MAX_EXT_ATALKNODE;
|
||
|
||
// Okay, now some fun starts. Plow through our options trying to find an
|
||
// unused extended node number.
|
||
|
||
// Compute the width of our network range, and pick a random start point.
|
||
netWidth = (USHORT)((NetworkRange.anr_LastNetwork + 1) - NetworkRange.anr_FirstNetwork);
|
||
netTry = GET_RANDOM(NetworkRange.anr_FirstNetwork, NetworkRange.anr_LastNetwork);
|
||
|
||
// Come up with a random decrement, making sure it's odd (to avoid repeats)
|
||
// and large enough to appear pretty random.
|
||
netChange = (USHORT)(GET_RANDOM(1, netWidth) | 1);
|
||
while ((netWidth % netChange == 0) ||
|
||
(!AtalkIsPrime((long)netChange)))
|
||
{
|
||
netChange += 2;
|
||
}
|
||
|
||
// Now walk trough the range decrementing the starting network by the
|
||
// choosen change (with wrap, of course) until we find an address or
|
||
// we've processed every available network in the range.
|
||
for (netIndex = 0; netIndex < netWidth; netIndex ++)
|
||
{
|
||
currentNetwork = (USHORT) netTry;
|
||
|
||
// Compute the width of our node range, and pick a random start point.
|
||
nodeWidth = (USHORT)((lastNode + 1) - firstNode);
|
||
nodeTry = (int)GET_RANDOM(firstNode, lastNode);
|
||
|
||
// Come up with a random decrement, making sure it's odd (to avoid repeats)
|
||
// and large enough to appear pretty random.
|
||
nodeChange = (USHORT)(GET_RANDOM(1, nodeWidth) | 1);
|
||
while ((nodeWidth % nodeChange == 0) || !(AtalkIsPrime((long)nodeChange)))
|
||
nodeChange += 2;
|
||
|
||
// Now walk trough the range decrementing the starting network by the
|
||
// choosen change (with wrap, of course) until we find an address or
|
||
// we've processed every available node in the range.
|
||
for (nodeIndex = 0; nodeIndex < nodeWidth; nodeIndex ++)
|
||
{
|
||
currentNode = (BYTE )nodeTry;
|
||
|
||
// Let AARP have a crack at it.
|
||
if ((found = atalkInitAarpForNode(pPortDesc,
|
||
pRasConn,
|
||
fThisIsPPP,
|
||
currentNetwork,
|
||
currentNode)))
|
||
{
|
||
break;
|
||
}
|
||
|
||
// Okay, try again, bump down with wrap.
|
||
nodeTry -= nodeChange;
|
||
while (nodeTry < firstNode)
|
||
nodeTry += nodeWidth;
|
||
|
||
} // Node number loop
|
||
|
||
// If we found a node, break on thru to the other side.
|
||
if (found)
|
||
break;
|
||
|
||
// Okay, try again, bump down with wrap.
|
||
netTry -= netChange;
|
||
while (netTry < (long)NetworkRange.anr_FirstNetwork)
|
||
netTry += netWidth;
|
||
|
||
} // Network number loop
|
||
|
||
// Okay if we found one return all's well, otherwise no luck.
|
||
if (found)
|
||
{
|
||
if (Node != NULL)
|
||
{
|
||
Node->atn_Network = currentNetwork;
|
||
Node->atn_Node = currentNode;
|
||
}
|
||
}
|
||
return found;
|
||
|
||
} // AarpForNodeInRange
|
||
|
||
|
||
|
||
LOCAL BOOLEAN
|
||
atalkInitAarpForNode(
|
||
IN PPORT_DESCRIPTOR pPortDesc,
|
||
IN PVOID pRasConn,
|
||
IN BOOLEAN fThisIsPPP,
|
||
IN USHORT Network,
|
||
IN BYTE Node
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
|
||
Arguments:
|
||
|
||
|
||
Return Value:
|
||
|
||
|
||
--*/
|
||
{
|
||
SHORT probeAttempt;
|
||
PBUFFER_DESC pBuffDesc;
|
||
PVOID pTmpConn;
|
||
PATCPCONN pAtcpConn;
|
||
PARAPCONN pArapConn;
|
||
ATALK_NODEADDR tryNode;
|
||
KIRQL OldIrql;
|
||
PKEVENT pWaitEvent;
|
||
DWORD dwFlags;
|
||
BOOLEAN nodeInUse;
|
||
BOOLEAN fNoOneHasResponded=TRUE;
|
||
BOOLEAN fPPPConn;
|
||
|
||
|
||
DBGPRINT(DBG_COMP_AARP, DBG_LEVEL_INFO,
|
||
("atalkAarpForNode: AARPing for %x.%x on port %Z\n",
|
||
Network, Node, &pPortDesc->pd_AdapterKey));
|
||
|
||
// First make sure we don't own this node.
|
||
tryNode.atn_Network = Network;
|
||
tryNode.atn_Node = Node;
|
||
|
||
KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
|
||
|
||
nodeInUse = AtalkNodeExistsOnPort(pPortDesc, &tryNode);
|
||
|
||
KeLowerIrql(OldIrql);
|
||
|
||
if (nodeInUse)
|
||
{
|
||
return(FALSE);
|
||
}
|
||
|
||
// is this node used by one of the dial in clients?
|
||
if ((pTmpConn = FindAndRefRasConnByAddr(tryNode, &dwFlags, &fPPPConn)) != NULL)
|
||
{
|
||
DBGPRINT(DBG_COMP_AARP, DBG_LEVEL_INFO,
|
||
("atalkAarpForNode: %x.%x already a dial in client (%lx)\n",
|
||
Network, Node, pTmpConn));
|
||
|
||
// our dial-in clients can only be in the network range of the
|
||
// default port
|
||
ASSERT(pPortDesc == AtalkDefaultPort);
|
||
|
||
if (fPPPConn)
|
||
{
|
||
ASSERT(((PATCPCONN)pTmpConn)->Signature == ATCPCONN_SIGNATURE);
|
||
DerefPPPConn((PATCPCONN)pTmpConn);
|
||
}
|
||
else
|
||
{
|
||
ASSERT(((PARAPCONN)pTmpConn)->Signature == ARAPCONN_SIGNATURE);
|
||
DerefArapConn((PARAPCONN)pTmpConn);
|
||
}
|
||
return(FALSE);
|
||
}
|
||
|
||
pAtcpConn = NULL;
|
||
pArapConn = NULL;
|
||
|
||
//
|
||
// if we are acquiring a node addr for a dial-in client...
|
||
//
|
||
|
||
if (pRasConn != NULL)
|
||
{
|
||
if (fThisIsPPP)
|
||
{
|
||
pAtcpConn = (PATCPCONN)pRasConn;
|
||
}
|
||
else
|
||
{
|
||
pArapConn = (PARAPCONN)pRasConn;
|
||
}
|
||
}
|
||
|
||
// PPP client?
|
||
if (pAtcpConn)
|
||
{
|
||
ACQUIRE_SPIN_LOCK(&pAtcpConn->SpinLock, &OldIrql);
|
||
pAtcpConn->NetAddr.atn_Network = Network;
|
||
pAtcpConn->NetAddr.atn_Node = Node;
|
||
pAtcpConn->Flags &= ~ATCP_NODE_IN_USE;
|
||
pWaitEvent = &pAtcpConn->NodeAcquireEvent;
|
||
RELEASE_SPIN_LOCK(&pAtcpConn->SpinLock, OldIrql);
|
||
}
|
||
|
||
// nope, ARAP client?
|
||
else if (pArapConn)
|
||
{
|
||
ACQUIRE_SPIN_LOCK(&pArapConn->SpinLock, &OldIrql);
|
||
pArapConn->NetAddr.atn_Network = Network;
|
||
pArapConn->NetAddr.atn_Node = Node;
|
||
pArapConn->Flags &= ~ARAP_NODE_IN_USE;
|
||
pWaitEvent = &pArapConn->NodeAcquireEvent;
|
||
RELEASE_SPIN_LOCK(&pArapConn->SpinLock, OldIrql);
|
||
}
|
||
// no, this is node acquisition for one of the server nodes
|
||
else
|
||
{
|
||
// Use AARP to probe for a particular network/node address.
|
||
ACQUIRE_SPIN_LOCK(&pPortDesc->pd_Lock, &OldIrql);
|
||
pPortDesc->pd_Flags &= ~PD_NODE_IN_USE;
|
||
pPortDesc->pd_TentativeNodeAddr.atn_Network = Network;
|
||
pPortDesc->pd_TentativeNodeAddr.atn_Node = Node;
|
||
pWaitEvent = &pPortDesc->pd_NodeAcquireEvent;
|
||
RELEASE_SPIN_LOCK(&pPortDesc->pd_Lock, OldIrql);
|
||
}
|
||
|
||
fNoOneHasResponded = TRUE;
|
||
|
||
// Build the packet and blast it out the specified number of times.
|
||
for (probeAttempt = 0;
|
||
((probeAttempt < pPortDesc->pd_AarpProbes) && (fNoOneHasResponded));
|
||
probeAttempt ++)
|
||
{
|
||
pBuffDesc = BUILD_AARPPROBE(pPortDesc, MAX_HW_ADDR_LEN, tryNode);
|
||
|
||
if (pBuffDesc == NULL)
|
||
{
|
||
RES_LOG_ERROR();
|
||
break;
|
||
}
|
||
|
||
if (!ATALK_SUCCESS(AtalkNdisSendPacket(pPortDesc,
|
||
pBuffDesc,
|
||
AtalkAarpSendComplete,
|
||
NULL)))
|
||
{
|
||
DBGPRINT(DBG_COMP_AARP, DBG_LEVEL_ERR,
|
||
("atalkAarpForNode: AtalkNdisSendPacket failed while AARPing for %x.%x\n",
|
||
Network, Node));
|
||
|
||
// We allocated the packet.
|
||
AtalkAarpSendComplete(NDIS_STATUS_FAILURE, pBuffDesc, NULL);
|
||
break;
|
||
}
|
||
|
||
AtalkWaitTE(pWaitEvent, AARP_PROBE_TIMER_MS);
|
||
|
||
// node addr for a PPP client?
|
||
if (pAtcpConn)
|
||
{
|
||
ACQUIRE_SPIN_LOCK(&pAtcpConn->SpinLock, &OldIrql);
|
||
if (pAtcpConn->Flags & ATCP_NODE_IN_USE)
|
||
{
|
||
fNoOneHasResponded = FALSE;
|
||
}
|
||
RELEASE_SPIN_LOCK(&pAtcpConn->SpinLock, OldIrql);
|
||
}
|
||
// node addr for a ARAP client?
|
||
else if (pArapConn)
|
||
{
|
||
ACQUIRE_SPIN_LOCK(&pArapConn->SpinLock, &OldIrql);
|
||
if (pArapConn->Flags & ARAP_NODE_IN_USE)
|
||
{
|
||
fNoOneHasResponded = FALSE;
|
||
}
|
||
RELEASE_SPIN_LOCK(&pArapConn->SpinLock, OldIrql);
|
||
}
|
||
// nope, node addr for one of the server nodes
|
||
else
|
||
{
|
||
ACQUIRE_SPIN_LOCK(&pPortDesc->pd_Lock, &OldIrql);
|
||
if (pPortDesc->pd_Flags & PD_NODE_IN_USE)
|
||
{
|
||
fNoOneHasResponded = FALSE;
|
||
}
|
||
RELEASE_SPIN_LOCK(&pPortDesc->pd_Lock, OldIrql);
|
||
}
|
||
|
||
} // Probe attempts loop
|
||
|
||
|
||
// We win if the current tentenative node has not been used
|
||
// (i.e. no one responds to our probes)
|
||
|
||
return (fNoOneHasResponded);
|
||
|
||
} // atalkAarpForNode
|
||
|
||
|
||
|
||
LOCAL VOID
|
||
atalkAarpEnterIntoAmt(
|
||
IN PPORT_DESCRIPTOR pPortDesc,
|
||
IN PATALK_NODEADDR pSrcNode,
|
||
IN PBYTE SrcAddr,
|
||
IN SHORT AddrLen,
|
||
IN PBYTE RouteInfo,
|
||
IN SHORT RouteInfoLen
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
|
||
Arguments:
|
||
|
||
|
||
Return Value:
|
||
|
||
|
||
--*/
|
||
{
|
||
int index;
|
||
PAMT pAmt, *ppAmt;
|
||
|
||
if ((pSrcNode->atn_Node < MIN_USABLE_ATALKNODE) ||
|
||
(pSrcNode->atn_Node > MAX_USABLE_ATALKNODE) ||
|
||
(pSrcNode->atn_Network < FIRST_VALID_NETWORK) ||
|
||
(pSrcNode->atn_Network > LAST_VALID_NETWORK))
|
||
{
|
||
UCHAR AtalkAndMacAddress[sizeof(ATALK_NODEADDR) + MAX_HW_ADDR_LEN];
|
||
DBGPRINT(DBG_COMP_AARP, DBG_LEVEL_ERR,
|
||
("atalkAarpEnterIntoAmt: Bad Node %x, %x\n",
|
||
pSrcNode->atn_Node, pSrcNode->atn_Network));
|
||
|
||
RtlCopyMemory(AtalkAndMacAddress, pSrcNode, sizeof(ATALK_NODEADDR));
|
||
RtlCopyMemory(AtalkAndMacAddress + sizeof(ATALK_NODEADDR), SrcAddr, MAX_HW_ADDR_LEN);
|
||
LOG_ERRORONPORT(pPortDesc,
|
||
EVENT_ATALK_AMT_INVALIDSOURCE,
|
||
0,
|
||
AtalkAndMacAddress,
|
||
sizeof(AtalkAndMacAddress));
|
||
return;
|
||
}
|
||
|
||
DBGPRINT(DBG_COMP_AARP, DBG_LEVEL_INFO,
|
||
("AtalkAarpEnterIntoAmt: Entering %x.%x in amt\n",
|
||
pSrcNode->atn_Network, pSrcNode->atn_Node));
|
||
|
||
// Do we already know about this mapping?
|
||
index = HASH_ATALK_NODE(pSrcNode) & (PORT_AMT_HASH_SIZE - 1);
|
||
|
||
ACQUIRE_SPIN_LOCK_DPC(&pPortDesc->pd_Lock);
|
||
|
||
for (ppAmt = &pPortDesc->pd_Amt[index];
|
||
(pAmt = *ppAmt) != NULL;
|
||
ppAmt = &pAmt->amt_Next)
|
||
{
|
||
ASSERT(VALID_AMT(pAmt));
|
||
if (ATALK_NODES_EQUAL(pSrcNode, &pAmt->amt_Target))
|
||
{
|
||
DBGPRINT(DBG_COMP_AARP, DBG_LEVEL_INFO,
|
||
("atalkAarpEnterIntoAmt: Address %x.%x exists in tables\n",
|
||
pSrcNode->atn_Network, pSrcNode->atn_Node));
|
||
|
||
if ((pAmt->amt_RouteInfoLen == 0) ^ (RouteInfoLen == 0))
|
||
{
|
||
DBGPRINT(DBG_COMP_AARP, DBG_LEVEL_WARN,
|
||
("atalkAarpEnterIntoAmt: %x.%x has wrong routing info\n",
|
||
pSrcNode->atn_Network, pSrcNode->atn_Node));
|
||
|
||
*ppAmt = pAmt->amt_Next;
|
||
AtalkBPFreeBlock(pAmt);
|
||
pAmt = NULL;
|
||
}
|
||
break;
|
||
}
|
||
}
|
||
|
||
// If not, allocate a new mapping Node.
|
||
if (pAmt == NULL)
|
||
{
|
||
BLKID BlkId;
|
||
|
||
DBGPRINT(DBG_COMP_AARP, DBG_LEVEL_WARN,
|
||
("atalkAarpEnterIntoAmt: Address %x.%x DOES NOT exist in tables\n",
|
||
pSrcNode->atn_Network, pSrcNode->atn_Node));
|
||
|
||
ASSERT(RouteInfoLen <= TLAP_MAX_ROUTING_BYTES);
|
||
|
||
BlkId = BLKID_AMT;
|
||
if (RouteInfoLen != 0)
|
||
BlkId = BLKID_AMT_ROUTE;
|
||
if ((pAmt = (PAMT)AtalkBPAllocBlock(BlkId)) != NULL)
|
||
{
|
||
#if DBG
|
||
pAmt->amt_Signature = AMT_SIGNATURE;
|
||
#endif
|
||
// Link it in. Fill in below
|
||
pAmt->amt_Target.atn_Network = pSrcNode->atn_Network;
|
||
pAmt->amt_Target.atn_Node = pSrcNode->atn_Node;
|
||
pAmt->amt_Next = pPortDesc->pd_Amt[index];
|
||
pPortDesc->pd_Amt[index] = pAmt;
|
||
}
|
||
}
|
||
|
||
if (pAmt != NULL)
|
||
{
|
||
// Update mapping table! Do this if we knew about the mapping OR
|
||
// if we allocated a new node
|
||
|
||
ASSERTMSG("HWAddrLen is not right!\n", (AddrLen == MAX_HW_ADDR_LEN));
|
||
|
||
RtlCopyMemory(pAmt->amt_HardwareAddr, SrcAddr, AddrLen);
|
||
|
||
ASSERTMSG("RouteLen is not right!\n", (RouteInfoLen <= MAX_ROUTING_BYTES));
|
||
|
||
if (RouteInfoLen > 0)
|
||
RtlCopyMemory((PBYTE)pAmt + sizeof(AMT), RouteInfo, RouteInfoLen);
|
||
|
||
pAmt->amt_RouteInfoLen = (BYTE)RouteInfoLen;
|
||
pAmt->amt_Age = 0;
|
||
}
|
||
|
||
RELEASE_SPIN_LOCK_DPC(&pPortDesc->pd_Lock);
|
||
}
|
||
|
||
|
||
|
||
|
||
VOID
|
||
AtalkAarpReleaseAmt(
|
||
IN OUT PPORT_DESCRIPTOR pPortDesc
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
|
||
Arguments:
|
||
|
||
|
||
Return Value:
|
||
|
||
|
||
--*/
|
||
{
|
||
int index;
|
||
PAMT pAmt, *ppAmt;
|
||
|
||
// Free up all the AMT entries. No need to acquire spinlock at this
|
||
// point. We are unloading and all binding etc are gone.
|
||
for (index = 0; index < PORT_AMT_HASH_SIZE; index ++)
|
||
{
|
||
for (ppAmt = &pPortDesc->pd_Amt[index];
|
||
(pAmt = *ppAmt) != NULL;
|
||
NOTHING)
|
||
{
|
||
ASSERT(VALID_AMT(pAmt));
|
||
*ppAmt = pAmt->amt_Next;
|
||
AtalkBPFreeBlock(pAmt);
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
|
||
|
||
VOID
|
||
AtalkAarpReleaseBrc(
|
||
IN OUT PPORT_DESCRIPTOR pPortDesc
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
|
||
Arguments:
|
||
|
||
|
||
Return Value:
|
||
|
||
|
||
--*/
|
||
{
|
||
int index;
|
||
PBRE pBre, *ppBre;
|
||
|
||
// Free up all the BRC entries. No need to acquire spinlock at this
|
||
// point. We are unloading and all binding etc are gone.
|
||
for (index = 0; index < PORT_BRC_HASH_SIZE; index ++)
|
||
{
|
||
for (ppBre = &pPortDesc->pd_Brc[index];
|
||
(pBre = *ppBre) != NULL;
|
||
NOTHING)
|
||
{
|
||
*ppBre = pBre->bre_Next;
|
||
AtalkBPFreeBlock(pBre);
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
|
||
|
||
LONG FASTCALL
|
||
AtalkAarpAmtTimer(
|
||
IN PTIMERLIST pTimer,
|
||
IN BOOLEAN TimerShuttingDown
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
|
||
Arguments:
|
||
|
||
|
||
Return Value:
|
||
|
||
|
||
--*/
|
||
{
|
||
PAMT pAmt, *ppAmt;
|
||
PPORT_DESCRIPTOR pPortDesc;
|
||
int index;
|
||
|
||
pPortDesc = (PPORT_DESCRIPTOR)CONTAINING_RECORD(pTimer, PORT_DESCRIPTOR, pd_AmtTimer);
|
||
ASSERT(VALID_PORT(pPortDesc));
|
||
|
||
ASSERT(EXT_NET(pPortDesc));
|
||
|
||
// Walk though all address mapping entries on this port aging the entries.
|
||
// We need to protect the mapping tables with critical sections, but don't
|
||
// stay in a critical section too long.
|
||
|
||
ACQUIRE_SPIN_LOCK_DPC(&pPortDesc->pd_Lock);
|
||
|
||
if (TimerShuttingDown ||
|
||
((pPortDesc->pd_Flags & PD_CLOSING) != 0))
|
||
{
|
||
RELEASE_SPIN_LOCK_DPC(&pPortDesc->pd_Lock);
|
||
|
||
// Remove the reference we added to this port at the time of
|
||
// starting the timer. Return;
|
||
AtalkPortDereferenceDpc(pPortDesc);
|
||
return ATALK_TIMER_NO_REQUEUE;
|
||
}
|
||
|
||
for (index = 0; index < PORT_AMT_HASH_SIZE; index ++)
|
||
{
|
||
for (ppAmt = &pPortDesc->pd_Amt[index];
|
||
(pAmt = *ppAmt) != NULL;
|
||
NOTHING)
|
||
{
|
||
ASSERT(VALID_AMT(pAmt));
|
||
if (pAmt->amt_Age < AMT_MAX_AGE)
|
||
{
|
||
DBGPRINT(DBG_COMP_AARP, DBG_LEVEL_INFO,
|
||
("atalkAarpAmtTimer: Entry for %x.%x %lx OK\n",
|
||
pAmt->amt_Target.atn_Network, pAmt->amt_Target.atn_Node,
|
||
pAmt));
|
||
pAmt->amt_Age ++;
|
||
ppAmt = &pAmt->amt_Next;
|
||
}
|
||
else
|
||
{
|
||
DBGPRINT(DBG_COMP_AARP, DBG_LEVEL_WARN,
|
||
("atalkAarpAmtTimer: Freeing node %x.%x from list\n",
|
||
pAmt->amt_Target.atn_Network,
|
||
pAmt->amt_Target.atn_Node));
|
||
*ppAmt = pAmt->amt_Next;
|
||
AtalkBPFreeBlock(pAmt);
|
||
}
|
||
}
|
||
}
|
||
|
||
RELEASE_SPIN_LOCK_DPC(&pPortDesc->pd_Lock);
|
||
|
||
return ATALK_TIMER_REQUEUE;
|
||
}
|
||
|
||
|
||
|
||
|
||
LONG FASTCALL
|
||
AtalkAarpBrcTimer(
|
||
IN PTIMERLIST pTimer,
|
||
IN BOOLEAN TimerShuttingDown
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
|
||
Arguments:
|
||
|
||
|
||
Return Value:
|
||
|
||
|
||
--*/
|
||
{
|
||
int index;
|
||
PPORT_DESCRIPTOR pPortDesc;
|
||
BOOLEAN DerefPort = FALSE;
|
||
|
||
pPortDesc = (PPORT_DESCRIPTOR)CONTAINING_RECORD(pTimer, PORT_DESCRIPTOR, pd_BrcTimer);
|
||
|
||
ASSERT(VALID_PORT(pPortDesc));
|
||
ASSERT(EXT_NET(pPortDesc));
|
||
|
||
// Walk though all best router entries on this port aging the entries.
|
||
// We need to protect the brc tables with critical sections, but don't
|
||
// stay in a critical section too long.
|
||
|
||
ACQUIRE_SPIN_LOCK_DPC(&pPortDesc->pd_Lock);
|
||
|
||
if (TimerShuttingDown ||
|
||
((pPortDesc->pd_Flags & PD_CLOSING) != 0))
|
||
{
|
||
RELEASE_SPIN_LOCK_DPC(&pPortDesc->pd_Lock);
|
||
|
||
// Remove the reference we added to this port at the time of
|
||
// starting the timer. Return;
|
||
AtalkPortDereferenceDpc(pPortDesc);
|
||
return ATALK_TIMER_NO_REQUEUE;
|
||
}
|
||
|
||
for (index = 0; index < PORT_BRC_HASH_SIZE; index ++)
|
||
{
|
||
PBRE pBre, *ppBre;
|
||
|
||
for (ppBre = &pPortDesc->pd_Brc[index];
|
||
(pBre = *ppBre) != NULL;
|
||
NOTHING)
|
||
{
|
||
if (pBre->bre_Age < BRC_MAX_AGE)
|
||
{
|
||
pBre->bre_Age ++;
|
||
ppBre = &pBre->bre_Next;
|
||
}
|
||
else
|
||
{
|
||
*ppBre = pBre->bre_Next;
|
||
AtalkBPFreeBlock(pBre);
|
||
}
|
||
}
|
||
}
|
||
|
||
RELEASE_SPIN_LOCK_DPC(&pPortDesc->pd_Lock);
|
||
|
||
return ATALK_TIMER_REQUEUE;
|
||
}
|
||
|
||
|
||
|
||
|
||
PBUFFER_DESC
|
||
AtalkAarpBuildPacket(
|
||
IN PPORT_DESCRIPTOR pPortDesc,
|
||
IN USHORT Type,
|
||
IN USHORT HardwareLen,
|
||
IN PBYTE SrcHardwareAddr,
|
||
IN ATALK_NODEADDR SrcLogicalAddr,
|
||
IN PBYTE DestHardwareAddr,
|
||
IN ATALK_NODEADDR DestLogicalAddr,
|
||
IN PBYTE TrueDest,
|
||
IN PBYTE RouteInfo,
|
||
IN USHORT RouteInfoLen
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
|
||
Arguments:
|
||
|
||
|
||
Return Value:
|
||
|
||
|
||
--*/
|
||
{
|
||
PBYTE aarpData;
|
||
USHORT linkLen;
|
||
|
||
PBUFFER_DESC pBuffDesc = NULL;
|
||
BYTE protocolLength = AARP_PROTO_ADDR_LEN;
|
||
PVOID pRasConn;
|
||
DWORD dwFlags;
|
||
BOOLEAN fThisIsPPP;
|
||
|
||
|
||
// Read only.
|
||
static BYTE zeroAddr[MAX_HW_ADDR_LEN] =
|
||
{
|
||
0, 0, 0, 0, 0, 0
|
||
};
|
||
|
||
#if DBG
|
||
// make sure we aren't sending AARP request/probe for our own dial-in client
|
||
if ((Type == AARP_REQUEST) || (Type == AARP_PROBE))
|
||
{
|
||
pRasConn = FindAndRefRasConnByAddr(DestLogicalAddr, &dwFlags, &fThisIsPPP);
|
||
if (pRasConn)
|
||
{
|
||
if (fThisIsPPP)
|
||
{
|
||
ASSERT(((PATCPCONN)pRasConn)->Signature == ATCPCONN_SIGNATURE);
|
||
|
||
if (dwFlags & ATCP_NODE_IN_USE)
|
||
{
|
||
DBGPRINT(DBG_COMP_AARP, DBG_LEVEL_ERR,
|
||
("AtalkAarpBuildPacket: PPP client (%lx) owns %x.%x (Type=%x)\n",
|
||
pRasConn,DestLogicalAddr.atn_Network, DestLogicalAddr.atn_Node,Type));
|
||
}
|
||
|
||
DerefPPPConn((PATCPCONN)pRasConn);
|
||
}
|
||
else
|
||
{
|
||
ASSERT(((PARAPCONN)pRasConn)->Signature == ARAPCONN_SIGNATURE);
|
||
|
||
if (dwFlags & ARAP_NODE_IN_USE)
|
||
{
|
||
DBGPRINT(DBG_COMP_AARP, DBG_LEVEL_ERR,
|
||
("AtalkAarpBuildPacket: ARA client (%lx) owns %x.%x (Type=%x)\n",
|
||
pRasConn,DestLogicalAddr.atn_Network, DestLogicalAddr.atn_Node,Type));
|
||
}
|
||
|
||
DerefArapConn((PARAPCONN)pRasConn);
|
||
}
|
||
}
|
||
}
|
||
#endif
|
||
|
||
// If no destination hardware address is specified, set it
|
||
// to all zeros.
|
||
if (DestHardwareAddr == NULL)
|
||
{
|
||
DestHardwareAddr = zeroAddr;
|
||
}
|
||
|
||
// Get a header buffer allocated from link routines. Tell it we want
|
||
// maximum aarp data size as the required size.
|
||
AtalkNdisAllocBuf(&pBuffDesc);
|
||
if (pBuffDesc == NULL)
|
||
{
|
||
return(pBuffDesc);
|
||
}
|
||
|
||
// Build the LAP header.
|
||
AtalkNdisBuildHdr(pPortDesc,
|
||
pBuffDesc->bd_CharBuffer,
|
||
linkLen,
|
||
AARP_MIN_DATA_SIZE,
|
||
TrueDest,
|
||
RouteInfo,
|
||
RouteInfoLen,
|
||
AARP_PROTOCOL);
|
||
|
||
aarpData = pBuffDesc->bd_CharBuffer + linkLen;
|
||
|
||
// Build the specified type of AARP packet with the specified information;
|
||
PUTSHORT2SHORT((PUSHORT)aarpData,
|
||
pPortDesc->pd_AarpHardwareType);
|
||
|
||
aarpData += sizeof(USHORT);
|
||
|
||
PUTSHORT2SHORT((PUSHORT)aarpData,
|
||
pPortDesc->pd_AarpProtocolType);
|
||
|
||
aarpData += sizeof(USHORT);
|
||
|
||
*aarpData++ = (BYTE)HardwareLen;
|
||
*aarpData++ = (BYTE)AARP_PROTO_ADDR_LEN;
|
||
|
||
PUTSHORT2SHORT((PUSHORT)aarpData, Type);
|
||
|
||
aarpData += sizeof(USHORT);
|
||
|
||
// Source hardware address.
|
||
RtlCopyMemory(aarpData, SrcHardwareAddr, HardwareLen);
|
||
|
||
aarpData += HardwareLen;
|
||
|
||
// Source logical address pad
|
||
*aarpData++ = 0;
|
||
|
||
// Network number
|
||
PUTSHORT2SHORT(aarpData, SrcLogicalAddr.atn_Network);
|
||
|
||
aarpData += sizeof(USHORT);
|
||
|
||
// Node number
|
||
*aarpData++ = SrcLogicalAddr.atn_Node;
|
||
|
||
// Destination hardware address.
|
||
RtlCopyMemory(aarpData, DestHardwareAddr, HardwareLen);
|
||
|
||
aarpData += HardwareLen;
|
||
|
||
// Destination logical address, null pad
|
||
*aarpData++ = 0;
|
||
|
||
// Network number
|
||
PUTSHORT2SHORT(aarpData, DestLogicalAddr.atn_Network);
|
||
|
||
aarpData += sizeof(USHORT);
|
||
|
||
// Node number
|
||
*aarpData++ = DestLogicalAddr.atn_Node;
|
||
|
||
// Set length in the buffer descriptor. Pad it to max data size. Some devices seem
|
||
// to drop the aarp responses if they see less, Macs dictate their behavior.
|
||
// Also zero out the extra space.
|
||
AtalkSetSizeOfBuffDescData(pBuffDesc,
|
||
(SHORT)(aarpData - pBuffDesc->bd_CharBuffer + AARP_MAX_DATA_SIZE - AARP_MIN_DATA_SIZE));
|
||
RtlZeroMemory(aarpData, AARP_MAX_DATA_SIZE - AARP_MIN_DATA_SIZE);
|
||
|
||
return pBuffDesc;
|
||
}
|
||
|
||
|
||
|
||
|
||
LOCAL VOID FASTCALL
|
||
atalkAarpTuneRouteInfo(
|
||
IN PPORT_DESCRIPTOR pPortDesc,
|
||
IN OUT PBYTE RouteInfo
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
|
||
Arguments:
|
||
|
||
|
||
Return Value:
|
||
|
||
|
||
--*/
|
||
{
|
||
// Given an incoming TokenRing routing info, tune it to make it valid
|
||
// for outing routing info. Do this in place!
|
||
ASSERT(pPortDesc->pd_PortType == TLAP_PORT);
|
||
|
||
// Set to "non-broadcast" and invert "direction".
|
||
RouteInfo[0] &= TLAP_NON_BROADCAST_MASK;
|
||
RouteInfo[1] ^= TLAP_DIRECTION_MASK;
|
||
}
|
||
|
||
|
||
#if DBG
|
||
|
||
VOID
|
||
AtalkAmtDumpTable(
|
||
VOID
|
||
)
|
||
{
|
||
int j, k;
|
||
KIRQL OldIrql;
|
||
PPORT_DESCRIPTOR pPortDesc;
|
||
PAMT pAmt;
|
||
|
||
ACQUIRE_SPIN_LOCK(&AtalkPortLock, &OldIrql);
|
||
|
||
for (pPortDesc = AtalkPortList;
|
||
pPortDesc != NULL;
|
||
pPortDesc = pPortDesc = pPortDesc->pd_Next)
|
||
{
|
||
DBGPRINT(DBG_COMP_DUMP, DBG_LEVEL_FATAL,
|
||
("AMT Table for port %Z\n", &pPortDesc->pd_AdapterKey));
|
||
|
||
ACQUIRE_SPIN_LOCK_DPC(&pPortDesc->pd_Lock);
|
||
|
||
for (j = 0; j < PORT_AMT_HASH_SIZE; j++)
|
||
{
|
||
for (pAmt = pPortDesc->pd_Amt[j];
|
||
pAmt != NULL;
|
||
pAmt = pAmt->amt_Next)
|
||
{
|
||
DBGPRINTSKIPHDR(DBG_COMP_DUMP, DBG_LEVEL_FATAL,
|
||
("\t%d: %lx.%lx", j,
|
||
pAmt->amt_Target.atn_Network, pAmt->amt_Target.atn_Node));
|
||
|
||
for (k = 0; k < MAX_HW_ADDR_LEN; k++)
|
||
{
|
||
DBGPRINTSKIPHDR(DBG_COMP_DUMP, DBG_LEVEL_FATAL,
|
||
("%02x", pAmt->amt_HardwareAddr[k]));
|
||
}
|
||
|
||
if (pAmt->amt_RouteInfoLen != 0)
|
||
{
|
||
PBYTE pRouteInfo;
|
||
|
||
pRouteInfo = (PBYTE)pAmt + sizeof(AMT);
|
||
|
||
DBGPRINTSKIPHDR(DBG_COMP_DUMP, DBG_LEVEL_FATAL,
|
||
(" ("));
|
||
for (k = 0; k < pAmt->amt_RouteInfoLen; k++)
|
||
{
|
||
DBGPRINTSKIPHDR(DBG_COMP_DUMP, DBG_LEVEL_FATAL,
|
||
(" %02x", pRouteInfo[k]));
|
||
}
|
||
DBGPRINTSKIPHDR(DBG_COMP_DUMP, DBG_LEVEL_FATAL, (" )"));
|
||
}
|
||
DBGPRINTSKIPHDR(DBG_COMP_DUMP, DBG_LEVEL_FATAL, ("\n"));
|
||
}
|
||
}
|
||
RELEASE_SPIN_LOCK_DPC(&pPortDesc->pd_Lock);
|
||
DBGPRINTSKIPHDR(DBG_COMP_DUMP, DBG_LEVEL_FATAL, ("\n"));
|
||
}
|
||
|
||
RELEASE_SPIN_LOCK(&AtalkPortLock, OldIrql);
|
||
}
|
||
|
||
#endif
|
||
|
||
|