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.
2221 lines
57 KiB
2221 lines
57 KiB
/*++
|
|
|
|
Copyright (c) 1992 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
aarp.c
|
|
|
|
Abstract:
|
|
|
|
This module contains the Appletalk Address Resolution Protocol code.
|
|
|
|
Author:
|
|
|
|
Jameel Hyder ([email protected])
|
|
Nikhil Kamkolkar ([email protected])
|
|
|
|
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
|
|
|
|
|