|
|
/*++
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
|