windows-nt/Source/XPSP1/NT/net/sfm/atalk/sys/nbp.c
2020-09-26 16:20:57 +08:00

1904 lines
49 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
Copyright (c) 1992 Microsoft Corporation
Module Name:
nbp.c
Abstract:
This module contains nbp 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 FILENUM NBP
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE_NZ, AtalkNbpAction)
#pragma alloc_text(PAGE_NZ, atalkNbpLinkPendingNameInList)
#pragma alloc_text(PAGE_NZ, atalkNbpSendRequest)
#endif
/*** AtalkNbpPacketIn
*
*/
VOID
AtalkNbpPacketIn(
IN PPORT_DESCRIPTOR pPortDesc,
IN PDDP_ADDROBJ pDdpAddr,
IN PBYTE pPkt,
IN USHORT PktLen,
IN PATALK_ADDR pSrcAddr,
IN PATALK_ADDR pDstAddr,
IN ATALK_ERROR ErrorCode,
IN BYTE DdpType,
IN PVOID pHandlerCtx,
IN BOOLEAN OptimizedPath,
IN PVOID OptimizeCtx
)
{
PPEND_NAME pPendName;
PATALK_NODE pNode;
TIME TimeS, TimeE, TimeD;
PNBPHDR pNbpHdr = (PNBPHDR)pPkt;
PRTE pRte;
SHORT i, NbpId, NbpCmd, TupleCnt;
PNBPTUPLE pNbpTuple = NULL, pInBufTuple = NULL;
BOOLEAN DefZone = FALSE, RestartTimer = FALSE;
BOOLEAN fWeCancelledTimer = TRUE;
BOOLEAN Found;
ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
TimeS = KeQueryPerformanceCounter(NULL);
do
{
if ((ErrorCode == ATALK_SOCKET_CLOSED) || (DdpType != DDPPROTO_NBP))
break;
else if ((ErrorCode != ATALK_NO_ERROR) || (PktLen < sizeof(NBPHDR)))
{
break;
}
// Get NBP header information and decide what to do
NbpCmd = (SHORT)((pNbpHdr->_CmdAndTupleCnt >> 4) & 0x0F);
TupleCnt = (SHORT)(pNbpHdr->_CmdAndTupleCnt & 0x0F);
NbpId = (SHORT)pNbpHdr->_NbpId;
if ((pNbpTuple = AtalkAllocMemory(sizeof(NBPTUPLE))) == NULL)
{
TMPLOGERR();
break;
}
switch (NbpCmd)
{
case NBP_LOOKUP:
DBGPRINT(DBG_COMP_NBP, DBG_LEVEL_INFO,
("atalkNbpPacketIn: Cmd Lookup\n"));
if ((TupleCnt == 1) &&
(atalkNbpDecodeTuple(pPkt + sizeof(NBPHDR),
(USHORT)(PktLen - sizeof(NBPHDR)),
pNbpTuple) > 0))
{
atalkNbpLookupNames(pPortDesc, pDdpAddr, pNbpTuple, NbpId);
}
else
{
#if 0
AtalkLogBadPacket(pPortDesc,
pSrcAddr,
pDstAddr,
pPkt,
PktLen);
#endif
break;
}
break;
case NBP_BROADCAST_REQUEST:
case NBP_FORWARD_REQUEST:
DBGPRINT(DBG_COMP_NBP, DBG_LEVEL_INFO,
("atalkNbpPacketIn: Cmd %sRequest\n",
(NbpCmd == NBP_BROADCAST_REQUEST) ? "Broadcast" : "Forward"));
// We don't care if we are not a router
if ((pPortDesc->pd_Flags & PD_ROUTER_RUNNING) == 0)
break;
if (TupleCnt != 1)
{
AtalkLogBadPacket(pPortDesc,
pSrcAddr,
pDstAddr,
pPkt,
PktLen);
break;
}
if (atalkNbpDecodeTuple(pPkt + sizeof(NBPHDR),
(USHORT)(PktLen - sizeof(NBPHDR)),
pNbpTuple) == 0)
{
AtalkLogBadPacket(pPortDesc,
pSrcAddr,
pDstAddr,
pPkt,
PktLen);
break;
}
if ((pNbpTuple->tpl_ZoneLen == 0) ||
((pNbpTuple->tpl_Zone[0] == '*') && (pNbpTuple->tpl_ZoneLen == 1)))
DefZone = TRUE;
if (EXT_NET(pPortDesc))
{
if (DefZone)
{
AtalkLogBadPacket(pPortDesc,
pSrcAddr,
pDstAddr,
pPkt,
PktLen);
break;
}
}
else // Non-extended network
{
if (DefZone)
{
if (pPortDesc->pd_NetworkRange.anr_FirstNetwork != pSrcAddr->ata_Network)
{
DBGPRINT(DBG_COMP_NBP, DBG_LEVEL_ERR,
("AtalkNbpPacketIn: LT Port, '*' zone - SrcAddr %d.%d, Net %d\n",
pSrcAddr->ata_Network, pSrcAddr->ata_Node,
pPortDesc->pd_NetworkRange.anr_FirstNetwork));
AtalkLogBadPacket(pPortDesc,
pSrcAddr,
pDstAddr,
pPkt,
PktLen);
break;
}
if (!(pPortDesc->pd_Flags & PD_VALID_DESIRED_ZONE))
break;
ACQUIRE_SPIN_LOCK_DPC(&pPortDesc->pd_Lock);
pNbpTuple->tpl_ZoneLen = pPortDesc->pd_DesiredZone->zn_ZoneLen;
RtlCopyMemory(pNbpTuple->tpl_Zone,
pPortDesc->pd_DesiredZone->zn_Zone,
pPortDesc->pd_DesiredZone->zn_ZoneLen);
RELEASE_SPIN_LOCK_DPC(&pPortDesc->pd_Lock);
}
}
// For a forward request send a lookup datagram
if (NbpCmd == NBP_FORWARD_REQUEST)
{
DBGPRINT(DBG_COMP_NBP, DBG_LEVEL_INFO,
("AtalkNbpPacketIn: Sending NbpLookup for a NbpForwardRequest\n"));
atalkNbpSendLookupDatagram(pPortDesc, pDdpAddr, NbpId, pNbpTuple);
break;
}
// We have a broadcast request. Walk through the routing tables
// sending either a forward request or a lookup (broadcast) to
// each network that contains the specified zone
ACQUIRE_SPIN_LOCK_DPC(&AtalkRteLock);
for (i = 0;i < NUM_RTMP_HASH_BUCKETS; i++)
{
for (pRte = AtalkRoutingTable[i];
pRte != NULL;
pRte = pRte->rte_Next)
{
ATALK_ERROR Status;
// If the network is directly connected i.e. 0 hops away
// use the zone-list in the PortDesc rather than the
// routing table - the routing table may not be filled
// in with a zone list (due to the normal ZipQuery mechanism)
ACQUIRE_SPIN_LOCK_DPC(&pRte->rte_Lock);
if (!(pRte->rte_Flags & RTE_ZONELIST_VALID))
{
if ((pRte->rte_NumHops != 0) ||
!AtalkZoneNameOnList(pNbpTuple->tpl_Zone,
pNbpTuple->tpl_ZoneLen,
pRte->rte_PortDesc->pd_ZoneList))
{
RELEASE_SPIN_LOCK_DPC(&pRte->rte_Lock);
continue;
}
}
else if (!AtalkZoneNameOnList(pNbpTuple->tpl_Zone,
pNbpTuple->tpl_ZoneLen,
pRte->rte_ZoneList))
{
RELEASE_SPIN_LOCK_DPC(&pRte->rte_Lock);
continue;
}
pRte->rte_RefCount ++;
RELEASE_SPIN_LOCK_DPC(&pRte->rte_Lock);
// If not a local network, send a forward request
if (pRte->rte_NumHops != 0)
{
DBGPRINT(DBG_COMP_NBP, DBG_LEVEL_INFO,
("AtalkNbpPacketIn: Sending NbpForwardRequest for a broadcast\n"));
// Do not hold the Rte lock during a DdpSend
RELEASE_SPIN_LOCK_DPC(&AtalkRteLock);
atalkNbpSendForwardRequest(pDdpAddr,
pRte,
NbpId,
pNbpTuple);
ACQUIRE_SPIN_LOCK_DPC(&AtalkRteLock);
AtalkRtmpDereferenceRte(pRte, TRUE);
}
else
{
DBGPRINT(DBG_COMP_NBP, DBG_LEVEL_INFO,
("AtalkNbpPacketIn: Sending Lookup for a broadcast\n"));
// Send a lookup
RELEASE_SPIN_LOCK_DPC(&AtalkRteLock);
atalkNbpSendLookupDatagram(pRte->rte_PortDesc,
NULL,
NbpId,
pNbpTuple);
ACQUIRE_SPIN_LOCK_DPC(&AtalkRteLock);
AtalkRtmpDereferenceRte(pRte, TRUE);
}
}
}
RELEASE_SPIN_LOCK_DPC(&AtalkRteLock);
break;
case NBP_LOOKUP_REPLY:
DBGPRINT(DBG_COMP_NBP, DBG_LEVEL_INFO,
("atalkNbpPacketIn: Cmd LookupReply\n"));
// This had better be a response to a previous lookup
// Look for a pending name on all open sockets on this node
if (TupleCnt == 0)
break;
// Decode the tuple for Register/Confirm case
if (atalkNbpDecodeTuple(pPkt + sizeof(NBPHDR),
(USHORT)(PktLen - sizeof(NBPHDR)),
pNbpTuple) == 0)
{
break;
}
pNode = pDdpAddr->ddpao_Node;
ACQUIRE_SPIN_LOCK_DPC(&pNode->an_Lock);
Found = FALSE;
for (i = 0; (i < NODE_DDPAO_HASH_SIZE) && !Found; i++)
{
PDDP_ADDROBJ pSkt;
for (pSkt = pNode->an_DdpAoHash[i];
(pSkt != NULL) && !Found;
pSkt = pSkt->ddpao_Next)
{
PPEND_NAME * ppPendName;
ACQUIRE_SPIN_LOCK_DPC(&pSkt->ddpao_Lock);
for (ppPendName = &pSkt->ddpao_PendNames;
(pPendName = *ppPendName) != NULL;
ppPendName = &pPendName->pdn_Next)
{
ASSERT (VALID_PENDNAME(pPendName));
if (pPendName->pdn_Flags & PDN_CLOSING)
{
continue;
}
if (pPendName->pdn_NbpId == NbpId)
{
DBGPRINT(DBG_COMP_NBP, DBG_LEVEL_INFO,
("atalkNbpPacketIn: LookupReply Found name\n"));
Found = TRUE;
ACQUIRE_SPIN_LOCK_DPC(&pPendName->pdn_Lock);
pPendName->pdn_RefCount ++;
RELEASE_SPIN_LOCK_DPC(&pPendName->pdn_Lock);
break;
}
}
RELEASE_SPIN_LOCK_DPC(&pSkt->ddpao_Lock);
}
}
RELEASE_SPIN_LOCK_DPC(&pNode->an_Lock);
// If the timer fired just before we could find and cancel it
if (pPendName == NULL)
break;
do
{
if (AtalkTimerCancelEvent(&pPendName->pdn_Timer, NULL))
{
// if the timer was successfully cancelled, take away
// the reference for it
atalkNbpDerefPendName(pPendName);
RestartTimer = TRUE;
}
else
{
fWeCancelledTimer = FALSE;
}
if ((pPendName->pdn_Reason == FOR_REGISTER) ||
(pPendName->pdn_Reason == FOR_CONFIRM))
{
BOOLEAN NoMatch;
// Does the reply match the one we're trying to register ?
NoMatch = ( (TupleCnt != 1) ||
(pPendName->pdn_pRegdName == NULL) ||
!AtalkFixedCompareCaseInsensitive(
pPendName->pdn_pRegdName->rdn_Tuple.tpl_Object,
pPendName->pdn_pRegdName->rdn_Tuple.tpl_ObjectLen,
pNbpTuple->tpl_Object,
pNbpTuple->tpl_ObjectLen) ||
!AtalkFixedCompareCaseInsensitive(
pPendName->pdn_pRegdName->rdn_Tuple.tpl_Type,
pPendName->pdn_pRegdName->rdn_Tuple.tpl_TypeLen,
pNbpTuple->tpl_Type,
pNbpTuple->tpl_TypeLen));
if (NoMatch)
{
if (TupleCnt != 1)
AtalkLogBadPacket(pPortDesc,
pSrcAddr,
pDstAddr,
pPkt,
PktLen);
break;
}
// If we are registering, we're done as someone already
// has our name
if (pPendName->pdn_Reason == FOR_REGISTER)
{
DBGPRINT(DBG_COMP_NBP, DBG_LEVEL_INFO,
("atalkNbpPacketIn: Register failure\n"));
ACQUIRE_SPIN_LOCK_DPC(&pPendName->pdn_Lock);
pPendName->pdn_Status = ATALK_SHARING_VIOLATION;
pPendName->pdn_Flags |= PDN_CLOSING;
RELEASE_SPIN_LOCK_DPC(&pPendName->pdn_Lock);
if (fWeCancelledTimer)
{
atalkNbpDerefPendName(pPendName); // Take away creation ref
}
RestartTimer = FALSE;
break;
}
// We're confirming, if no match get out
if ((pPendName->pdn_ConfirmAddr.ata_Network != pNbpTuple->tpl_Address.ata_Network) ||
(pPendName->pdn_ConfirmAddr.ata_Node != pNbpTuple->tpl_Address.ata_Node))
{
break;
}
DBGPRINT(DBG_COMP_NBP, DBG_LEVEL_INFO,
("atalkNbpPacketIn: Confirm success\n"));
ACQUIRE_SPIN_LOCK_DPC(&pPendName->pdn_Lock);
pPendName->pdn_Status = ATALK_NO_ERROR;
((PNBP_CONFIRM_PARAMS)(pPendName->pdn_pActReq->ar_pParms))->ConfirmTuple.Address.Address =
pNbpTuple->tpl_Address.ata_Address;
if (pPendName->pdn_ConfirmAddr.ata_Socket != pNbpTuple->tpl_Address.ata_Socket)
{
pPendName->pdn_Status = ATALK_NEW_SOCKET;
}
pPendName->pdn_Flags |= PDN_CLOSING;
RELEASE_SPIN_LOCK_DPC(&pPendName->pdn_Lock);
atalkNbpDerefPendName(pPendName); // Take away creation ref
RestartTimer = FALSE;
}
else // FOR_LOOKUP
{
int i, j, tmp, NextTupleOff = sizeof(NBPHDR);
BOOLEAN Done = FALSE;
ULONG BytesCopied;
DBGPRINT(DBG_COMP_NBP, DBG_LEVEL_INFO,
("atalkNbpPacketIn: Lookup searching...\n"));
// Allocate space for an NBP tuple for copying and comparing
// Failure to allocate can result in duplicates - so be it
if (pInBufTuple == NULL)
pInBufTuple = AtalkAllocMemory(sizeof(NBPTUPLE));
for (i = 0; i < TupleCnt && !Done; i++)
{
BOOLEAN Duplicate = FALSE;
// If we encounter a bad tuple, ignore the rest. Drop tuples which are
// our names and we are set to drop them !!!
if (((tmp = atalkNbpDecodeTuple(pPkt + NextTupleOff,
(USHORT)(PktLen - NextTupleOff),
pNbpTuple)) == 0) ||
(AtalkFilterOurNames &&
(((pNbpTuple->tpl_Address.ata_Network == AtalkUserNode1.atn_Network) &&
(pNbpTuple->tpl_Address.ata_Node == AtalkUserNode1.atn_Node)) ||
((pNbpTuple->tpl_Address.ata_Network == AtalkUserNode2.atn_Network) &&
(pNbpTuple->tpl_Address.ata_Node == AtalkUserNode2.atn_Node)))))
break;
NextTupleOff += tmp;
ACQUIRE_SPIN_LOCK_DPC(&pPendName->pdn_Lock);
// Now walk through the tuples that we already picked
// up and drop duplicates
if (pInBufTuple != NULL)
{
for (j = 0; j < pPendName->pdn_TotalTuples; j++)
{
TdiCopyMdlToBuffer(pPendName->pdn_pAMdl,
j * sizeof(NBPTUPLE),
(PBYTE)pInBufTuple,
0,
sizeof(NBPTUPLE),
&BytesCopied);
ASSERT (BytesCopied == sizeof(NBPTUPLE));
if ((pInBufTuple->tpl_Address.ata_Network ==
pNbpTuple->tpl_Address.ata_Network) &&
(pInBufTuple->tpl_Address.ata_Node ==
pNbpTuple->tpl_Address.ata_Node) &&
(pInBufTuple->tpl_Address.ata_Socket ==
pNbpTuple->tpl_Address.ata_Socket))
{
Duplicate = TRUE;
break;
}
}
if (Duplicate)
{
RELEASE_SPIN_LOCK_DPC(&pPendName->pdn_Lock);
continue;
}
}
// We are guaranteed that there is space available
// for another tuple.
TdiCopyBufferToMdl((PBYTE)pNbpTuple,
0,
sizeof(NBPTUPLE),
pPendName->pdn_pAMdl,
pPendName->pdn_TotalTuples * sizeof(NBPTUPLE),
&BytesCopied);
ASSERT (BytesCopied == sizeof(NBPTUPLE));
DBGPRINT(DBG_COMP_NBP, DBG_LEVEL_INFO,
("atalkNbpPacketIn: Lookup, found a tuple\n"));
pPendName->pdn_TotalTuples ++;
if ((pPendName->pdn_TotalTuples == pPendName->pdn_MaxTuples) ||
(pPendName->pdn_MdlLength -
(pPendName->pdn_TotalTuples * sizeof(NBPTUPLE)) <
sizeof(NBPTUPLE)))
{
Done = TRUE;
((PNBP_LOOKUP_PARAMS)(pPendName->pdn_pActReq->ar_pParms))->NoTuplesRead =
pPendName->pdn_TotalTuples;
pPendName->pdn_Status = ATALK_NO_ERROR;
pPendName->pdn_Flags |= PDN_CLOSING;
RestartTimer = FALSE;
}
RELEASE_SPIN_LOCK_DPC(&pPendName->pdn_Lock);
if (Done)
{
DBGPRINT(DBG_COMP_NBP, DBG_LEVEL_INFO,
("atalkNbpPacketIn: Lookup calling completion\n"));
if (fWeCancelledTimer)
{
atalkNbpDerefPendName(pPendName); // Take away creation ref
}
break;
}
}
}
} while (FALSE);
if (RestartTimer)
{
DBGPRINT(DBG_COMP_NBP, DBG_LEVEL_INFO,
("atalkNbpPacketIn: Restarting timer\n"));
ACQUIRE_SPIN_LOCK_DPC(&pPendName->pdn_Lock);
pPendName->pdn_RefCount ++;
RELEASE_SPIN_LOCK_DPC(&pPendName->pdn_Lock);
AtalkTimerScheduleEvent(&pPendName->pdn_Timer);
}
atalkNbpDerefPendName(pPendName);
break;
default:
AtalkLogBadPacket(pPortDesc,
pSrcAddr,
pDstAddr,
pPkt,
PktLen);
break;
}
} while (FALSE);
if (pNbpTuple != NULL)
AtalkFreeMemory(pNbpTuple);
if (pInBufTuple != NULL)
AtalkFreeMemory(pInBufTuple);
TimeE = KeQueryPerformanceCounter(NULL);
TimeD.QuadPart = TimeE.QuadPart - TimeS.QuadPart;
INTERLOCKED_ADD_LARGE_INTGR(
&pPortDesc->pd_PortStats.prtst_NbpPacketInProcessTime,
TimeD,
&AtalkStatsLock.SpinLock);
INTERLOCKED_INCREMENT_LONG_DPC(
&pPortDesc->pd_PortStats.prtst_NumNbpPacketsIn,
&AtalkStatsLock.SpinLock);
}
/*** atalkNbpTimer
*
*/
LOCAL LONG FASTCALL
atalkNbpTimer(
IN PTIMERLIST pTimer,
IN BOOLEAN TimerShuttingDown
)
{
PPEND_NAME pCurrPendName;
ATALK_ERROR error;
PDDP_ADDROBJ pDdpAddr;
BOOLEAN RestartTimer = TRUE;
BYTE Reason;
pCurrPendName = (PPEND_NAME)CONTAINING_RECORD(pTimer, PEND_NAME, pdn_Timer);
ASSERT (VALID_PENDNAME(pCurrPendName));
Reason = pCurrPendName->pdn_Reason;
ASSERT ((Reason == FOR_REGISTER) ||
(Reason == FOR_LOOKUP) ||
(Reason == FOR_CONFIRM));
pDdpAddr = pCurrPendName->pdn_pDdpAddr;
DBGPRINT(DBG_COMP_NBP, DBG_LEVEL_INFO,
("atalkNbpTimer: For Socket %lx, PendName %lx\n",
pDdpAddr, pCurrPendName));
ACQUIRE_SPIN_LOCK_DPC(&pCurrPendName->pdn_Lock);
if (TimerShuttingDown ||
(pCurrPendName->pdn_Flags & PDN_CLOSING))
pCurrPendName->pdn_RemainingBroadcasts = 1;
if (--(pCurrPendName->pdn_RemainingBroadcasts) == 0)
{
RestartTimer = FALSE;
if (Reason == FOR_REGISTER)
{
DBGPRINT(DBG_COMP_NBP, DBG_LEVEL_INFO,
("atalkNbpTimer: Register success\n"));
ACQUIRE_SPIN_LOCK_DPC(&pDdpAddr->ddpao_Lock);
pCurrPendName->pdn_pRegdName->rdn_Next = pDdpAddr->ddpao_RegNames;
pDdpAddr->ddpao_RegNames = pCurrPendName->pdn_pRegdName;
RELEASE_SPIN_LOCK_DPC(&pDdpAddr->ddpao_Lock);
pCurrPendName->pdn_Flags &= ~PDN_FREE_REGDNAME;
}
pCurrPendName->pdn_Flags |= PDN_CLOSING;
}
DBGPRINT(DBG_COMP_NBP, DBG_LEVEL_INFO,
("atalkNbpTimer: Remaining broadcasts %d\n",
pCurrPendName->pdn_RemainingBroadcasts));
if (RestartTimer)
{
pCurrPendName->pdn_RefCount ++;
RELEASE_SPIN_LOCK_DPC(&pCurrPendName->pdn_Lock);
DBGPRINT(DBG_COMP_NBP, DBG_LEVEL_INFO,
("atalkNbpTimer: Sending another request\n"));
if (!atalkNbpSendRequest(pCurrPendName))
{
DBGPRINT(DBG_COMP_NBP, DBG_LEVEL_ERR,
("atalkNbpTimer: atalkNbpSendRequest failed\n"));
}
}
else
{
RELEASE_SPIN_LOCK_DPC(&pCurrPendName->pdn_Lock);
error = ATALK_NO_ERROR;
if (Reason == FOR_CONFIRM)
{
DBGPRINT(DBG_COMP_NBP, DBG_LEVEL_INFO,
("atalkNbpTimer: Confirm Failure\n"));
error = ATALK_TIMEOUT;
}
else if (Reason == FOR_LOOKUP)
{
((PNBP_LOOKUP_PARAMS)(pCurrPendName->pdn_pActReq->ar_pParms))->NoTuplesRead =
pCurrPendName->pdn_TotalTuples;
}
DBGPRINT(DBG_COMP_NBP, DBG_LEVEL_INFO,
("atalkNbpTimer: Calling completion routine\n"));
pCurrPendName->pdn_Status = error;
atalkNbpDerefPendName(pCurrPendName); // Take away creation reference
}
atalkNbpDerefPendName(pCurrPendName);
return (RestartTimer ? ATALK_TIMER_REQUEUE : ATALK_TIMER_NO_REQUEUE);
}
/*** atalkNbpLookupNames
*
*/
LOCAL VOID
atalkNbpLookupNames(
IN PPORT_DESCRIPTOR pPortDesc,
IN PDDP_ADDROBJ pDdpAddr,
IN PNBPTUPLE pNbpTuple,
IN SHORT NbpId
)
{
int i, index, TupleCnt;
BOOLEAN AllocNewBuffDesc = TRUE;
PBUFFER_DESC pBuffDesc,
pBuffDescStart = NULL,
*ppBuffDesc = &pBuffDescStart;
PATALK_NODE pNode = pDdpAddr->ddpao_Node;
SEND_COMPL_INFO SendInfo;
PBYTE Datagram;
ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
DBGPRINT(DBG_COMP_NBP, DBG_LEVEL_INFO,
("atalkNbpLookupNames: Entered\n"));
// Does the requestor atleast has the right zone ?
if ((pNbpTuple->tpl_Zone[0] != '*') ||
(pNbpTuple->tpl_ZoneLen != 1))
{
// If either we do not know our zone or if it does not match or
// we are an extended network, return - we have nothing to do
if (EXT_NET(pPortDesc))
{
if (!(pPortDesc->pd_Flags & PD_VALID_DESIRED_ZONE) ||
((pPortDesc->pd_DesiredZone == NULL) ?1:
(!AtalkFixedCompareCaseInsensitive(pNbpTuple->tpl_Zone,
pNbpTuple->tpl_ZoneLen,
pPortDesc->pd_DesiredZone->zn_Zone,
pPortDesc->pd_DesiredZone->zn_ZoneLen))))
{
return;
}
}
}
// Walk the registered names list on all sockets open on this node and
// see if we have a matching name. We have to walk the pending names
// list also (should not answer, if we the node trying to register the
// name).
ACQUIRE_SPIN_LOCK_DPC(&pDdpAddr->ddpao_Node->an_Lock);
for (i = 0; i < NODE_DDPAO_HASH_SIZE; i++)
{
PDDP_ADDROBJ pSkt;
for (pSkt = pNode->an_DdpAoHash[i];
pSkt != NULL;
pSkt = pSkt->ddpao_Next)
{
PREGD_NAME pRegdName;
PPEND_NAME pPendName;
ACQUIRE_SPIN_LOCK_DPC(&pSkt->ddpao_Lock);
DBGPRINT(DBG_COMP_NBP, DBG_LEVEL_INFO,
("atalkNbpLookupNames: Checking Socket %lx\n", pSkt));
// First check registered names
for (pRegdName = pSkt->ddpao_RegNames;
pRegdName != NULL;
pRegdName = pRegdName->rdn_Next)
{
ASSERT (VALID_REGDNAME(pRegdName));
DBGPRINT(DBG_COMP_NBP, DBG_LEVEL_INFO,
("atalkNbpLookupNames: Checking RegdName %lx\n", pRegdName));
if (!atalkNbpMatchWild(pNbpTuple->tpl_Object,
pNbpTuple->tpl_ObjectLen,
pRegdName->rdn_Tuple.tpl_Object,
pRegdName->rdn_Tuple.tpl_ObjectLen) ||
!atalkNbpMatchWild(pNbpTuple->tpl_Type,
pNbpTuple->tpl_TypeLen,
pRegdName->rdn_Tuple.tpl_Type,
pRegdName->rdn_Tuple.tpl_TypeLen))
continue;
// Allocate a new buffer descriptor, if we must
if (AllocNewBuffDesc)
{
if ((pBuffDesc = AtalkAllocBuffDesc(NULL,
MAX_DGRAM_SIZE,
BD_CHAR_BUFFER | BD_FREE_BUFFER)) == NULL)
break;
Datagram = pBuffDesc->bd_CharBuffer;
index = sizeof(NBPHDR);
TupleCnt = 0;
*ppBuffDesc = pBuffDesc;
pBuffDesc->bd_Next = NULL;
ppBuffDesc = &pBuffDesc->bd_Next;
AllocNewBuffDesc = FALSE;
}
// We have a match. Build complete Nbp tuple
index += atalkNbpEncodeTuple(&pRegdName->rdn_Tuple,
"*",
1,
0,
Datagram+index);
TupleCnt ++;
if (((index + MAX_NBP_TUPLELENGTH) > MAX_DGRAM_SIZE) ||
(TupleCnt == 0x0F))
{
((PNBPHDR)Datagram)->_NbpId = (BYTE)NbpId;
((PNBPHDR)Datagram)->_CmdAndTupleCnt =
(NBP_LOOKUP_REPLY << 4) + TupleCnt;
AllocNewBuffDesc = TRUE;
pBuffDesc->bd_Length = (SHORT)index;
}
}
// Now check pending names
for (pPendName = pSkt->ddpao_PendNames;
pPendName != NULL;
pPendName = pPendName->pdn_Next)
{
ASSERT (VALID_PENDNAME(pPendName));
DBGPRINT(DBG_COMP_NBP, DBG_LEVEL_INFO,
("atalkNbpLookupNames: Checking PendName %lx\n", pPendName));
// Ignore all but the ones that are being registered
if (pPendName->pdn_Reason != FOR_REGISTER)
continue;
// Also those that we are registering
if ((pSkt->ddpao_Node->an_NodeAddr.atn_Network ==
pNbpTuple->tpl_Address.ata_Network) &&
(pSkt->ddpao_Node->an_NodeAddr.atn_Node ==
pNbpTuple->tpl_Address.ata_Node) &&
(pPendName->pdn_NbpId == (BYTE)NbpId))
continue;
if ((pPendName->pdn_pRegdName == NULL) ||
!atalkNbpMatchWild(
pNbpTuple->tpl_Object,
pNbpTuple->tpl_ObjectLen,
pPendName->pdn_pRegdName->rdn_Tuple.tpl_Object,
pPendName->pdn_pRegdName->rdn_Tuple.tpl_ObjectLen) ||
!atalkNbpMatchWild(
pNbpTuple->tpl_Type,
pNbpTuple->tpl_TypeLen,
pPendName->pdn_pRegdName->rdn_Tuple.tpl_Type,
pPendName->pdn_pRegdName->rdn_Tuple.tpl_TypeLen))
{
continue;
}
// Allocate a new buffer descriptor, if we must
if (AllocNewBuffDesc)
{
if ((pBuffDesc = AtalkAllocBuffDesc(NULL,
MAX_DGRAM_SIZE,
BD_CHAR_BUFFER | BD_FREE_BUFFER)) == NULL)
break;
Datagram = pBuffDesc->bd_CharBuffer;
index = sizeof(NBPHDR);
TupleCnt = 0;
*ppBuffDesc = pBuffDesc;
pBuffDesc->bd_Next = NULL;
ppBuffDesc = &pBuffDesc->bd_Next;
AllocNewBuffDesc = FALSE;
}
// We have a match. Build complete Nbp tuple
index += atalkNbpEncodeTuple(&pPendName->pdn_pRegdName->rdn_Tuple,
"*",
1,
0,
Datagram+index);
TupleCnt ++;
if (((index + MAX_NBP_TUPLELENGTH) > MAX_DGRAM_SIZE) ||
(TupleCnt == 0x0F))
{
((PNBPHDR)Datagram)->_NbpId = (BYTE)NbpId;
((PNBPHDR)Datagram)->_CmdAndTupleCnt =
(NBP_LOOKUP_REPLY << 4) + TupleCnt;
AllocNewBuffDesc = TRUE;
pBuffDesc->bd_Length = (SHORT)index;
}
}
RELEASE_SPIN_LOCK_DPC(&pSkt->ddpao_Lock);
}
}
RELEASE_SPIN_LOCK_DPC(&pDdpAddr->ddpao_Node->an_Lock);
// Close the current buffdesc
if (!AllocNewBuffDesc)
{
((PNBPHDR)Datagram)->_NbpId = (BYTE)NbpId;
((PNBPHDR)Datagram)->_CmdAndTupleCnt = (NBP_LOOKUP_REPLY << 4) + TupleCnt;
pBuffDesc->bd_Length = (SHORT)index;
}
// Now blast off all the datagrams that we have filled up
SendInfo.sc_TransmitCompletion = atalkNbpSendComplete;
// SendInfo.sc_Ctx2 = NULL;
// SendInfo.sc_Ctx3 = NULL;
for (pBuffDesc = pBuffDescStart;
pBuffDesc != NULL;
pBuffDesc = pBuffDescStart)
{
ATALK_ERROR ErrorCode;
DBGPRINT(DBG_COMP_NBP, DBG_LEVEL_INFO,
("atalkNbpLookupNames: Sending lookup response\n"));
pBuffDescStart = pBuffDesc->bd_Next;
pBuffDesc->bd_Next = NULL;
DBGPRINT(DBG_COMP_NBP, DBG_LEVEL_INFO,
("atalkNbpLookupNames: Sending %lx\n", pBuffDesc));
ASSERT(pBuffDesc->bd_Length > 0);
// Length is already properly set in the buffer descriptor.
SendInfo.sc_Ctx1 = pBuffDesc;
ErrorCode = AtalkDdpSend(pDdpAddr,
&pNbpTuple->tpl_Address,
DDPPROTO_NBP,
FALSE,
pBuffDesc,
NULL,
0,
NULL,
&SendInfo);
if (!ATALK_SUCCESS(ErrorCode))
{
DBGPRINT(DBG_COMP_NBP, DBG_LEVEL_WARN,
("atalkNbpLookupNames: DdpSend failed %ld\n", ErrorCode));
AtalkFreeBuffDesc(pBuffDesc);
}
}
}
/*** AtalkNbpAction
*
*/
ATALK_ERROR
AtalkNbpAction(
IN PDDP_ADDROBJ pDdpAddr,
IN BYTE Reason,
IN PNBPTUPLE pNbpTuple,
OUT PAMDL pAMdl OPTIONAL, // FOR_LOOKUP
IN USHORT MaxTuples OPTIONAL, // FOR_LOOKUP
IN PACTREQ pActReq
)
{
PPORT_DESCRIPTOR pPortDesc;
PPEND_NAME pPendName = NULL;
PREGD_NAME pRegdName = NULL;
ATALK_ERROR Status = ATALK_INVALID_PARAMETER;
LONG MdlLen = 0;
BOOLEAN DefZone = FALSE;
ASSERT (Reason == FOR_REGISTER ||
Reason == FOR_CONFIRM ||
Reason == FOR_LOOKUP);
do
{
if ((pNbpTuple->tpl_ObjectLen == 0) ||
(pNbpTuple->tpl_ObjectLen > MAX_ENTITY_LENGTH) ||
(pNbpTuple->tpl_TypeLen == 0) ||
(pNbpTuple->tpl_TypeLen > MAX_ENTITY_LENGTH))
break;
if ((Reason == FOR_LOOKUP) &&
((pAMdl == NULL) ||
((MdlLen = AtalkSizeMdlChain(pAMdl)) < sizeof(NBPTUPLE))))
{
Status = ATALK_BUFFER_TOO_SMALL;
break;
}
pPortDesc = pDdpAddr->ddpao_Node->an_Port;
if (pNbpTuple->tpl_ZoneLen != 0)
{
if (pNbpTuple->tpl_ZoneLen > MAX_ENTITY_LENGTH)
break;
if (((pNbpTuple->tpl_Zone[0] == '*') && (pNbpTuple->tpl_ZoneLen == 1)) ||
((pPortDesc->pd_DesiredZone != NULL) &&
AtalkFixedCompareCaseInsensitive(pNbpTuple->tpl_Zone,
pNbpTuple->tpl_ZoneLen,
pPortDesc->pd_DesiredZone->zn_Zone,
pPortDesc->pd_DesiredZone->zn_ZoneLen)))
{
DefZone = TRUE;
}
}
else
{
pNbpTuple->tpl_Zone[0] = '*';
pNbpTuple->tpl_ZoneLen = 1;
DefZone = TRUE;
}
if (Reason != FOR_LOOKUP) // i.e. REGISTER or CONFIRM
{
if ((pNbpTuple->tpl_Object[0] == '=') ||
(pNbpTuple->tpl_Type[0] == '=') ||
(AtalkSearchBuf(pNbpTuple->tpl_Object,
pNbpTuple->tpl_ObjectLen,
NBP_WILD_CHARACTER) != NULL) ||
(AtalkSearchBuf(pNbpTuple->tpl_Type,
pNbpTuple->tpl_TypeLen,
NBP_WILD_CHARACTER) != NULL))
break;
if ((Reason == FOR_REGISTER) && !DefZone)
break;
}
// For extended networks, set the zone name correctly
if (DefZone &&
(pPortDesc->pd_Flags & (PD_EXT_NET | PD_VALID_DESIRED_ZONE)) ==
(PD_EXT_NET | PD_VALID_DESIRED_ZONE))
{
RtlCopyMemory(pNbpTuple->tpl_Zone,
pPortDesc->pd_DesiredZone->zn_Zone,
pPortDesc->pd_DesiredZone->zn_ZoneLen);
pNbpTuple->tpl_ZoneLen = pPortDesc->pd_DesiredZone->zn_ZoneLen;
}
// Start by building the pending name structure. This needs to be linked
// to the socket holding the spin lock and getting a unique enumerator
// and an nbp id. If either of these fail, then we undo the stuff.
if (((pPendName = (PPEND_NAME)AtalkAllocZeroedMemory(sizeof(PEND_NAME))) == NULL) ||
((pRegdName = (PREGD_NAME)AtalkAllocZeroedMemory(sizeof(REGD_NAME))) == NULL))
{
if (pPendName != NULL)
{
AtalkFreeMemory(pPendName);
pPendName = NULL;
}
Status = ATALK_RESR_MEM;
break;
}
DBGPRINT(DBG_COMP_NBP, DBG_LEVEL_INFO,
("AtalkNbpAction: %s, Socket %lx, PendName %lx, RegdName %lx\n",
(Reason == FOR_REGISTER) ? "Register" :
((Reason == FOR_CONFIRM) ? "Confirm" : "Lookup"),
pDdpAddr, pPendName, pRegdName));
#if DBG
pRegdName->rdn_Signature = RDN_SIGNATURE;
pPendName->pdn_Signature = PDN_SIGNATURE;
#endif
pRegdName->rdn_Tuple.tpl_ObjectLen = pNbpTuple->tpl_ObjectLen;;
RtlCopyMemory(pRegdName->rdn_Tuple.tpl_Object,
pNbpTuple->tpl_Object,
pNbpTuple->tpl_ObjectLen);
pRegdName->rdn_Tuple.tpl_TypeLen = pNbpTuple->tpl_TypeLen;;
RtlCopyMemory(pRegdName->rdn_Tuple.tpl_Type,
pNbpTuple->tpl_Type,
pNbpTuple->tpl_TypeLen);
pRegdName->rdn_Tuple.tpl_ZoneLen = pNbpTuple->tpl_ZoneLen;;
RtlCopyMemory(pRegdName->rdn_Tuple.tpl_Zone,
pNbpTuple->tpl_Zone,
pNbpTuple->tpl_ZoneLen);
pRegdName->rdn_Tuple.tpl_Address.ata_Address = pDdpAddr->ddpao_Addr.ata_Address;
pPendName->pdn_pRegdName = pRegdName;
INITIALIZE_SPIN_LOCK(&pPendName->pdn_Lock);
pPendName->pdn_RefCount = 3; // Reference for creation, timer & for ourselves
pPendName->pdn_pDdpAddr = pDdpAddr;
AtalkDdpReferenceByPtr(pDdpAddr, &Status);
ASSERT(ATALK_SUCCESS(Status));
pPendName->pdn_Flags = PDN_FREE_REGDNAME;
pPendName->pdn_Reason = Reason;
pPendName->pdn_pActReq = pActReq;
pPendName->pdn_RemainingBroadcasts = NBP_NUM_BROADCASTS;
AtalkTimerInitialize(&pPendName->pdn_Timer,
atalkNbpTimer,
NBP_BROADCAST_INTERVAL);
if (Reason == FOR_CONFIRM)
pPendName->pdn_ConfirmAddr = pNbpTuple->tpl_Address;
else if (Reason == FOR_LOOKUP)
{
pPendName->pdn_pAMdl = pAMdl;
pPendName->pdn_MdlLength = (USHORT)MdlLen;
pPendName->pdn_TotalTuples = 0;
pPendName->pdn_MaxTuples = MaxTuples;
// If we are not doing a wild card search, restrict
// the tuples to one so we get out early instead of
// the max. time-out since we are never going to
// fill the buffer
if (!((pNbpTuple->tpl_Object[0] == '=') ||
(pNbpTuple->tpl_Type[0] == '=') ||
(pNbpTuple->tpl_Zone[0] == '=') ||
(AtalkSearchBuf(pNbpTuple->tpl_Object,
pNbpTuple->tpl_ObjectLen,
NBP_WILD_CHARACTER) != NULL) ||
(AtalkSearchBuf(pNbpTuple->tpl_Type,
pNbpTuple->tpl_TypeLen,
NBP_WILD_CHARACTER) != NULL) ||
(AtalkSearchBuf(pNbpTuple->tpl_Zone,
pNbpTuple->tpl_ZoneLen,
NBP_WILD_CHARACTER) != NULL)))
{
pPendName->pdn_MaxTuples = 1;
}
}
// We're going to send a directed lookup for confirms, or either a
// broadcast request or a lookup for registers or lookup depending
// on whether we know about a router or not. We do not have to bother
// checking the registered names list, for register, in our node
// because the broadcast will eventually get to us and we'll handle
// it then ! Request packet, with one tuple
if (Reason == FOR_CONFIRM) // Send to confirming node
((PNBPHDR)(pPendName->pdn_Datagram))->_CmdAndTupleCnt =
(NBP_LOOKUP << 4) + 1;
else if (pPortDesc->pd_Flags & PD_SEEN_ROUTER_RECENTLY)
((PNBPHDR)(pPendName->pdn_Datagram))->_CmdAndTupleCnt =
(NBP_BROADCAST_REQUEST << 4) + 1;
else ((PNBPHDR)(pPendName->pdn_Datagram))->_CmdAndTupleCnt =
(NBP_LOOKUP << 4) + 1;
pPendName->pdn_DatagramLength = sizeof(NBPHDR) +
atalkNbpEncodeTuple(&pPendName->pdn_pRegdName->rdn_Tuple,
NULL,
0,
// NAMESINFORMATION_SOCKET,
LAST_DYNAMIC_SOCKET,
pPendName->pdn_Datagram + sizeof(NBPHDR));
// Alloc an Nbp Id and an enumerator and link it into the list
atalkNbpLinkPendingNameInList(pDdpAddr, pPendName);
((PNBPHDR)(pPendName->pdn_Datagram))->_NbpId = (BYTE)(pPendName->pdn_NbpId);
AtalkTimerScheduleEvent(&pPendName->pdn_Timer);
atalkNbpSendRequest(pPendName);
atalkNbpDerefPendName(pPendName); // We are done now.
Status = ATALK_PENDING;
} while (FALSE);
return Status;
}
/*** AtalkNbpRemove
*
*/
ATALK_ERROR
AtalkNbpRemove(
IN PDDP_ADDROBJ pDdpAddr,
IN PNBPTUPLE pNbpTuple,
IN PACTREQ pActReq
)
{
PREGD_NAME pRegdName, *ppRegdName;
KIRQL OldIrql;
ATALK_ERROR Status = ATALK_INVALID_PARAMETER;
do
{
// Remove a registered NBP name. Zone must either be NULL or "*"
if ((pNbpTuple->tpl_ObjectLen == 0) ||
(pNbpTuple->tpl_ObjectLen > MAX_ENTITY_LENGTH) ||
(pNbpTuple->tpl_TypeLen == 0) ||
(pNbpTuple->tpl_TypeLen > MAX_ENTITY_LENGTH))
break;
if (pNbpTuple->tpl_ZoneLen == 0)
{
pNbpTuple->tpl_ZoneLen = 1;
pNbpTuple->tpl_Zone[0] = '*';
}
else
{
if ((pNbpTuple->tpl_ZoneLen != 1) ||
(pNbpTuple->tpl_Zone[0] != '*'))
break;
}
if ((pNbpTuple->tpl_Object[0] == '=') || (pNbpTuple->tpl_Type[0] == '=') ||
AtalkSearchBuf(pNbpTuple->tpl_Object, pNbpTuple->tpl_ObjectLen, NBP_WILD_CHARACTER) ||
AtalkSearchBuf(pNbpTuple->tpl_Type, pNbpTuple->tpl_TypeLen, NBP_WILD_CHARACTER))
break;
// Search in the registered names list in the open socket
// Lock down the structure first
ACQUIRE_SPIN_LOCK(&pDdpAddr->ddpao_Lock, &OldIrql);
for (ppRegdName = &pDdpAddr->ddpao_RegNames;
(pRegdName = *ppRegdName) != NULL;
ppRegdName = &pRegdName->rdn_Next)
{
ASSERT (VALID_REGDNAME(pRegdName));
if (AtalkFixedCompareCaseInsensitive(pNbpTuple->tpl_Object,
pNbpTuple->tpl_ObjectLen,
pRegdName->rdn_Tuple.tpl_Object,
pRegdName->rdn_Tuple.tpl_ObjectLen) &&
AtalkFixedCompareCaseInsensitive(pNbpTuple->tpl_Type,
pNbpTuple->tpl_TypeLen,
pRegdName->rdn_Tuple.tpl_Type,
pRegdName->rdn_Tuple.tpl_TypeLen))
{
*ppRegdName = pRegdName->rdn_Next;
break;
}
}
RELEASE_SPIN_LOCK(&pDdpAddr->ddpao_Lock, OldIrql);
Status = ATALK_FAILURE;
if (pRegdName != NULL)
{
AtalkFreeMemory(pRegdName);
Status = ATALK_NO_ERROR;
}
} while (FALSE);
AtalkUnlockNbpIfNecessary();
(*pActReq->ar_Completion)(Status, pActReq);
return (ATALK_PENDING);
}
/*** atalkNbpMatchWild
*
*/
LOCAL BOOLEAN
atalkNbpMatchWild(
IN PBYTE WildString,
IN BYTE WildStringLen,
IN PBYTE String,
IN BYTE StringLen
)
/*++
There are two kinds of wild card searches. An '=' by itself matches anything.
Partial matches use the 'curly equals' or 0xC5. So representing that by the
'=' character below.
foo= will match any name which starts with foo.
=foo will match any name which ends in foo.
=foo= will match any name with foo in it.
foo=bar will match any name that starts with foo and ends with bar.
--*/
{
PBYTE pTarget, pTokStr;
int TargetLen, TokStrLen;
PBYTE pWildCard, pCurStr, pCurWild;
int Len;
int i;
BOOLEAN fWildCharPresent = FALSE;
// first see if it's a 'match any' request
if ((WildString[0] == 0) ||
((WildString[0] == '=') && (WildStringLen == 1)))
return TRUE;
// now, check to see if there is any wild char in the requested name
for (i=0; i<WildStringLen; i++)
{
if (WildString[i] == NBP_WILD_CHARACTER)
{
fWildCharPresent = TRUE;
break;
}
}
// if there is no wild character in the requested name, this is
// a straight forward string compare!
if (!fWildCharPresent)
{
if (WildStringLen != StringLen)
return FALSE;
if (SubStringMatch(WildString,String,StringLen,WildStringLen))
return TRUE;
else
return FALSE;
}
// ok, now deal with the wild character mess
pTarget = String;
pTokStr = WildString;
TargetLen = StringLen;
while (WildStringLen > 0 && StringLen > 0)
{
// find length of substring until the next wild-char
TokStrLen = GetTokenLen(pTokStr,WildStringLen,NBP_WILD_CHARACTER);
if (TokStrLen > 0)
{
if (!SubStringMatch(pTarget,pTokStr,StringLen,TokStrLen))
{
return (FALSE);
}
pTokStr += TokStrLen;
WildStringLen -= (BYTE)TokStrLen;
pTarget += TokStrLen;
StringLen -= (BYTE)TokStrLen;
}
// the very first char was wild-char: skip over it
else
{
pTokStr++;
WildStringLen--;
}
}
// if we survived all the checks, this string is a match!
return (TRUE);
}
/*** atalkNbpEncodeTuple
*
*/
LOCAL SHORT
atalkNbpEncodeTuple(
IN PNBPTUPLE pNbpTuple,
IN PBYTE pZone OPTIONAL, // Override zone
IN BYTE ZoneLen OPTIONAL, // Valid only if pZone != NULL
IN BYTE Socket OPTIONAL,
OUT PBYTE pBuffer
)
{
typedef struct
{
BYTE _NetNum[2];
BYTE _Node;
BYTE _Socket;
BYTE _Enumerator;
} HDR, *PHDR;
SHORT Len = sizeof(HDR);
if (pZone == NULL)
{
pZone = pNbpTuple->tpl_Zone;
ZoneLen = pNbpTuple->tpl_ZoneLen;
}
PUTSHORT2SHORT(((PHDR)pBuffer)->_NetNum, pNbpTuple->tpl_Address.ata_Network);
((PHDR)pBuffer)->_Node = pNbpTuple->tpl_Address.ata_Node;
((PHDR)pBuffer)->_Socket = pNbpTuple->tpl_Address.ata_Socket;
if (Socket != 0)
((PHDR)pBuffer)->_Socket = Socket;
PUTSHORT2BYTE(&((PHDR)pBuffer)->_Enumerator, pNbpTuple->tpl_Enumerator);
pBuffer += sizeof(HDR);
*pBuffer++ = pNbpTuple->tpl_ObjectLen;
RtlCopyMemory(pBuffer, pNbpTuple->tpl_Object, pNbpTuple->tpl_ObjectLen);
pBuffer += pNbpTuple->tpl_ObjectLen;
Len += (pNbpTuple->tpl_ObjectLen + 1);
*pBuffer++ = pNbpTuple->tpl_TypeLen;
RtlCopyMemory(pBuffer, pNbpTuple->tpl_Type, pNbpTuple->tpl_TypeLen);
pBuffer += pNbpTuple->tpl_TypeLen;
Len += (pNbpTuple->tpl_TypeLen + 1);
*pBuffer++ = ZoneLen;
RtlCopyMemory(pBuffer, pZone, ZoneLen);
// pBuffer += ZoneLen;
Len += (ZoneLen + 1);
return (Len);
}
/*** atalkNbpDecodeTuple
*
*/
LOCAL SHORT
atalkNbpDecodeTuple(
IN PBYTE pBuffer,
IN USHORT PktLen,
OUT PNBPTUPLE pNbpTuple
)
{
typedef struct
{
BYTE _NetNum[2];
BYTE _Node;
BYTE _Socket;
BYTE _Enumerator;
} HDR, *PHDR;
SHORT Len = 0;
do
{
if (PktLen < MIN_NBP_TUPLELENGTH)
{
break;
}
GETSHORT2SHORT(&pNbpTuple->tpl_Address.ata_Network,
((PHDR)pBuffer)->_NetNum);
pNbpTuple->tpl_Address.ata_Node = ((PHDR)pBuffer)->_Node;
pNbpTuple->tpl_Address.ata_Socket = ((PHDR)pBuffer)->_Socket;
GETBYTE2SHORT(&pNbpTuple->tpl_Enumerator,
&((PHDR)pBuffer)->_Enumerator);
// Get past the header
pBuffer += sizeof(HDR);
PktLen -= sizeof(HDR);
Len = sizeof(HDR);
pNbpTuple->tpl_ObjectLen = *pBuffer++;
PktLen --;
if ((pNbpTuple->tpl_ObjectLen > PktLen) ||
(pNbpTuple->tpl_ObjectLen > MAX_ENTITY_LENGTH))
{
Len = 0;
break;
}
RtlCopyMemory(pNbpTuple->tpl_Object, pBuffer, pNbpTuple->tpl_ObjectLen);
pBuffer += pNbpTuple->tpl_ObjectLen;
PktLen -= pNbpTuple->tpl_ObjectLen;
Len += (pNbpTuple->tpl_ObjectLen + 1);
if (PktLen == 0)
{
Len = 0;
break;
}
pNbpTuple->tpl_TypeLen = *pBuffer++;
PktLen --;
if ((pNbpTuple->tpl_TypeLen > PktLen) ||
(pNbpTuple->tpl_TypeLen > MAX_ENTITY_LENGTH))
{
Len = 0;
break;
}
RtlCopyMemory(pNbpTuple->tpl_Type, pBuffer, pNbpTuple->tpl_TypeLen);
pBuffer += pNbpTuple->tpl_TypeLen;
PktLen -= pNbpTuple->tpl_TypeLen;
Len += (pNbpTuple->tpl_TypeLen + 1);
if (PktLen == 0)
{
Len = 0;
break;
}
pNbpTuple->tpl_ZoneLen = *pBuffer++;
PktLen --;
if ((pNbpTuple->tpl_ZoneLen > PktLen) ||
(pNbpTuple->tpl_ZoneLen > MAX_ENTITY_LENGTH))
{
Len = 0;
break;
}
RtlCopyMemory(pNbpTuple->tpl_Zone, pBuffer, pNbpTuple->tpl_ZoneLen);
Len += (pNbpTuple->tpl_ZoneLen + 1);
} while (FALSE);
return (Len);
}
/*** atalkNbpLinkPendingNameInList
*
*/
LOCAL VOID
atalkNbpLinkPendingNameInList(
IN PDDP_ADDROBJ pDdpAddr,
IN OUT PPEND_NAME pPendName
)
{
PATALK_NODE pNode = pDdpAddr->ddpao_Node;
KIRQL OldIrql;
ASSERT (VALID_PENDNAME(pPendName));
ACQUIRE_SPIN_LOCK(&pNode->an_Lock, &OldIrql);
// Use the next consecutive values. If there are > 256 pending names on a node, we'll
// end up re-using the ids and enums. Still ok unless all of them are of the form
// =:=@=. Well lets just keep it simple.
pPendName->pdn_NbpId = ++(pNode->an_NextNbpId);
pPendName->pdn_pRegdName->rdn_Tuple.tpl_Enumerator = ++(pNode->an_NextNbpEnum);
DBGPRINT(DBG_COMP_NBP, DBG_LEVEL_INFO,
("atalkNbpLinkPendingNameInList: Linking PendingName %lx in socket %lx\n",
pPendName, pDdpAddr));
pPendName->pdn_Next = pDdpAddr->ddpao_PendNames;
pDdpAddr->ddpao_PendNames = pPendName;
RELEASE_SPIN_LOCK(&pNode->an_Lock, OldIrql);
}
/*** AtalkNbpCloseSocket
*
*/
VOID
AtalkNbpCloseSocket(
IN PDDP_ADDROBJ pDdpAddr
)
{
PPEND_NAME pPendName, *ppPendName;
PREGD_NAME pRegdName, *ppRegdName;
KIRQL OldIrql;
ACQUIRE_SPIN_LOCK(&pDdpAddr->ddpao_Lock, &OldIrql);
// Free the pending names from the open socket.
for (ppPendName = &pDdpAddr->ddpao_PendNames;
(pPendName = *ppPendName) != NULL;
NOTHING)
{
ASSERT (VALID_PENDNAME(pPendName));
if (pPendName->pdn_Flags & PDN_CLOSING)
{
ppPendName = &pPendName->pdn_Next;
continue;
}
pPendName->pdn_Flags |= PDN_CLOSING;
pPendName->pdn_Status = ATALK_SOCKET_CLOSED;
// Cancel outstanding timers on the pending names
if (AtalkTimerCancelEvent(&pPendName->pdn_Timer, NULL))
{
atalkNbpDerefPendName(pPendName);
}
RELEASE_SPIN_LOCK(&pDdpAddr->ddpao_Lock, OldIrql);
ASSERT (pPendName->pdn_RefCount > 0);
atalkNbpDerefPendName(pPendName);
ACQUIRE_SPIN_LOCK(&pDdpAddr->ddpao_Lock, &OldIrql);
ppPendName = &pDdpAddr->ddpao_PendNames;
}
// Free the registered names from the open socket.
for (ppRegdName = &pDdpAddr->ddpao_RegNames;
(pRegdName = *ppRegdName) != NULL;
NOTHING)
{
ASSERT (VALID_REGDNAME(pRegdName));
*ppRegdName = pRegdName->rdn_Next;
AtalkFreeMemory(pRegdName);
}
RELEASE_SPIN_LOCK(&pDdpAddr->ddpao_Lock, OldIrql);
}
/*** atalkNbpSendRequest
*
*/
LOCAL BOOLEAN
atalkNbpSendRequest(
IN PPEND_NAME pPendName
)
{
PDDP_ADDROBJ pDdpAddr;
PBUFFER_DESC pBuffDesc;
ATALK_ADDR DestAddr;
ATALK_ADDR SrcAddr;
ATALK_ERROR Status;
PPORT_DESCRIPTOR pPortDesc;
SEND_COMPL_INFO SendInfo;
DBGPRINT(DBG_COMP_NBP, DBG_LEVEL_INFO,
("atalkNbpSendRequest: Sending request for PendName %lx\n", pPendName));
ASSERT(!(pPendName->pdn_Flags & PDN_CLOSING));
pPortDesc = pPendName->pdn_pDdpAddr->ddpao_Node->an_Port;
DestAddr.ata_Socket = NAMESINFORMATION_SOCKET;
if (pPendName->pdn_Reason == FOR_CONFIRM)
{
DestAddr.ata_Network = pPendName->pdn_ConfirmAddr.ata_Network;
DestAddr.ata_Node = pPendName->pdn_ConfirmAddr.ata_Node;
}
else
{
if (pPortDesc->pd_Flags & PD_SEEN_ROUTER_RECENTLY)
{
DestAddr.ata_Network = pPortDesc->pd_ARouter.atn_Network;
DestAddr.ata_Node = pPortDesc->pd_ARouter.atn_Node;
}
else
{
DestAddr.ata_Network = CABLEWIDE_BROADCAST_NETWORK;
DestAddr.ata_Node = ATALK_BROADCAST_NODE;
}
}
SrcAddr.ata_Address = pPendName->pdn_pDdpAddr->ddpao_Addr.ata_Address;
// SrcAddr.ata_Socket = NAMESINFORMATION_SOCKET;
SrcAddr.ata_Socket = LAST_DYNAMIC_SOCKET;
AtalkDdpReferenceByAddr(pPendName->pdn_pDdpAddr->ddpao_Node->an_Port,
&SrcAddr,
&pDdpAddr,
&Status);
if (!ATALK_SUCCESS(Status))
{
return FALSE;
}
if ((pBuffDesc = AtalkAllocBuffDesc(pPendName->pdn_Datagram,
pPendName->pdn_DatagramLength,
BD_CHAR_BUFFER)) == NULL)
{
AtalkDdpDereference(pDdpAddr);
return FALSE;
}
ASSERT(pBuffDesc->bd_Length == pPendName->pdn_DatagramLength);
ASSERT(pBuffDesc->bd_Length > 0);
SendInfo.sc_TransmitCompletion = atalkNbpSendComplete;
SendInfo.sc_Ctx1 = pBuffDesc;
// SendInfo.sc_Ctx2 = NULL;
// SendInfo.sc_Ctx3 = NULL;
Status = AtalkDdpSend(pDdpAddr,
&DestAddr,
DDPPROTO_NBP,
FALSE,
pBuffDesc,
NULL,
0,
NULL,
&SendInfo);
if (!ATALK_SUCCESS(Status))
{
DBGPRINT(DBG_COMP_NBP, DBG_LEVEL_ERR,
("atalkNbpSendRequest: AtalkDdpSend Failed %lx\n", Status));
AtalkFreeBuffDesc(pBuffDesc);
}
AtalkDdpDereference(pDdpAddr);
return (ATALK_SUCCESS(Status));
}
/*** atalkNbpSendLookupDatagram
*
*/
LOCAL VOID
atalkNbpSendLookupDatagram(
IN PPORT_DESCRIPTOR pPortDesc,
IN PDDP_ADDROBJ pDdpAddr OPTIONAL,
IN SHORT NbpId,
IN PNBPTUPLE pNbpTuple
)
{
PBYTE Datagram = NULL;
BYTE MulticastAddr[ELAP_ADDR_LEN];
PBUFFER_DESC pBuffDesc = NULL;
BOOLEAN DerefDdp = FALSE;
ULONG Len;
ATALK_ADDR Dst, Src;
ATALK_ERROR Status;
SEND_COMPL_INFO SendInfo;
if (pDdpAddr == NULL)
{
Src.ata_Network = pPortDesc->pd_ARouter.atn_Network;
Src.ata_Node = pPortDesc->pd_ARouter.atn_Node;
Src.ata_Socket = NAMESINFORMATION_SOCKET;
AtalkDdpReferenceByAddr(pPortDesc, &Src, &pDdpAddr, &Status);
if (!ATALK_SUCCESS(Status))
{
return;
}
DerefDdp = TRUE;
}
do
{
if ((pBuffDesc = AtalkAllocBuffDesc(NULL,
sizeof(NBPHDR) + MAX_NBP_TUPLELENGTH,
BD_CHAR_BUFFER | BD_FREE_BUFFER)) == NULL)
break;
Datagram = pBuffDesc->bd_CharBuffer;
((PNBPHDR)Datagram)->_NbpId = (BYTE)NbpId;
((PNBPHDR)Datagram)->_CmdAndTupleCnt = (NBP_LOOKUP << 4) + 1;
Len = sizeof(NBPHDR) +
atalkNbpEncodeTuple(pNbpTuple,
NULL,
0,
0,
Datagram+sizeof(NBPHDR));
Dst.ata_Node = ATALK_BROADCAST_NODE;
Dst.ata_Socket = NAMESINFORMATION_SOCKET;
if (EXT_NET(pPortDesc))
{
// Send to "0000FF" at correct zone multicast address
Dst.ata_Network = CABLEWIDE_BROADCAST_NETWORK;
AtalkZipMulticastAddrForZone(pPortDesc,
pNbpTuple->tpl_Zone,
pNbpTuple->tpl_ZoneLen,
MulticastAddr);
}
else
{
// Send to "nnnnFF" as broadcast
Dst.ata_Network = pPortDesc->pd_NetworkRange.anr_FirstNetwork;
}
// Set the length in the buffer descriptor.
AtalkSetSizeOfBuffDescData(pBuffDesc, (USHORT)Len);
ASSERT(pBuffDesc->bd_Length > 0);
SendInfo.sc_TransmitCompletion = atalkNbpSendComplete;
SendInfo.sc_Ctx1 = pBuffDesc;
// SendInfo.sc_Ctx2 = NULL;
// SendInfo.sc_Ctx3 = NULL;
if (!ATALK_SUCCESS(Status = AtalkDdpSend(pDdpAddr,
&Dst,
DDPPROTO_NBP,
FALSE,
pBuffDesc,
NULL,
0,
MulticastAddr,
&SendInfo)))
{
DBGPRINT(DBG_COMP_NBP, DBG_LEVEL_ERR,
("atalkNbpSendLookupDatagram: DdpSend failed %ld\n", Status));
break;
}
Datagram = NULL;
pBuffDesc = NULL;
} while (FALSE);
if (DerefDdp)
AtalkDdpDereference(pDdpAddr);
if (pBuffDesc != NULL)
AtalkFreeBuffDesc(pBuffDesc);
}
/*** atalkNbpSendForwardRequest
*
*/
LOCAL VOID
atalkNbpSendForwardRequest(
IN PDDP_ADDROBJ pDdpAddr,
IN PRTE pRte,
IN SHORT NbpId,
IN PNBPTUPLE pNbpTuple
)
{
PBYTE Datagram = NULL;
PBUFFER_DESC pBuffDesc = NULL;
SEND_COMPL_INFO SendInfo;
ATALK_ERROR ErrorCode;
ULONG Len;
ATALK_ADDR Dst;
do
{
if ((pBuffDesc = AtalkAllocBuffDesc(NULL,
sizeof(NBPHDR) + MAX_NBP_TUPLELENGTH,
BD_CHAR_BUFFER | BD_FREE_BUFFER)) == NULL)
break;
Datagram = pBuffDesc->bd_CharBuffer;
((PNBPHDR)Datagram)->_NbpId = (BYTE)NbpId;
((PNBPHDR)Datagram)->_CmdAndTupleCnt = (NBP_FORWARD_REQUEST << 4) + 1;
Len = sizeof(NBPHDR) +
atalkNbpEncodeTuple(pNbpTuple,
NULL,
0,
0,
Datagram+sizeof(NBPHDR));
Dst.ata_Network = pRte->rte_NwRange.anr_FirstNetwork;
Dst.ata_Node = ANY_ROUTER_NODE;
Dst.ata_Socket = NAMESINFORMATION_SOCKET;
// Set the length in the buffer descriptor.
AtalkSetSizeOfBuffDescData(pBuffDesc, (USHORT)Len);
ASSERTMSG("Dest in rte 0\n", Dst.ata_Network != CABLEWIDE_BROADCAST_NETWORK);
ASSERT(pBuffDesc->bd_Length > 0);
SendInfo.sc_TransmitCompletion = atalkNbpSendComplete;
SendInfo.sc_Ctx1 = pBuffDesc;
// SendInfo.sc_Ctx2 = NULL;
// SendInfo.sc_Ctx3 = NULL;
ErrorCode = AtalkDdpSend(pDdpAddr,
&Dst,
DDPPROTO_NBP,
FALSE,
pBuffDesc,
NULL,
0,
NULL,
&SendInfo);
if (!ATALK_SUCCESS(ErrorCode))
{
DBGPRINT(DBG_COMP_NBP, DBG_LEVEL_ERR,
("atalkNbpSendForwardRequest: DdpSend failed %ld\n", ErrorCode));
break;
}
Datagram = NULL;
pBuffDesc = NULL;
} while (FALSE);
if (pBuffDesc != NULL)
AtalkFreeBuffDesc(pBuffDesc);
}
/*** atalkNbpDerefPendName
*
*/
VOID
atalkNbpDerefPendName(
IN PPEND_NAME pPendName
)
{
PPEND_NAME * ppPendName;
PDDP_ADDROBJ pDdpAddr = pPendName->pdn_pDdpAddr;
BOOLEAN Unlink, Found = FALSE;
KIRQL OldIrql;
ACQUIRE_SPIN_LOCK(&pPendName->pdn_Lock, &OldIrql);
Unlink = (--(pPendName->pdn_RefCount) == 0);
DBGPRINT(DBG_COMP_NBP, DBG_LEVEL_INFO,
("atalkNbpDerefPendName: New Count %d\n", pPendName->pdn_RefCount));
RELEASE_SPIN_LOCK(&pPendName->pdn_Lock, OldIrql);
if (!Unlink)
return;
DBGPRINT(DBG_COMP_NBP, DBG_LEVEL_INFO,
("atalkNbpDerefPendName: Unlinking pPendName\n"));
ACQUIRE_SPIN_LOCK(&pDdpAddr->ddpao_Lock, &OldIrql);
for (ppPendName = &pDdpAddr->ddpao_PendNames;
*ppPendName != NULL;
ppPendName = &(*ppPendName)->pdn_Next)
{
if (*ppPendName == pPendName)
{
*ppPendName = pPendName->pdn_Next;
Found = TRUE;
break;
}
}
RELEASE_SPIN_LOCK(&pDdpAddr->ddpao_Lock, OldIrql);
if (Found)
{
AtalkDdpDereference(pDdpAddr);
}
else ASSERTMSG("atalkNbpDerefPendName: Could not find\n", 0);
AtalkUnlockNbpIfNecessary();
(*pPendName->pdn_pActReq->ar_Completion)(pPendName->pdn_Status, pPendName->pdn_pActReq);
if (pPendName->pdn_Flags & PDN_FREE_REGDNAME)
AtalkFreeMemory(pPendName->pdn_pRegdName);
AtalkFreeMemory(pPendName);
}
/*** atalkNbpSendComplete
*
*/
VOID FASTCALL
atalkNbpSendComplete(
IN NDIS_STATUS Status,
IN PSEND_COMPL_INFO pSendInfo
)
{
PBUFFER_DESC pBuffDesc = (PBUFFER_DESC)(pSendInfo->sc_Ctx1);
if (!ATALK_SUCCESS(Status))
DBGPRINT(DBG_COMP_NBP, DBG_LEVEL_ERR,
("atalkNbpSendComplete: Failed %lx, pBuffDesc %lx\n",
Status, pBuffDesc));
AtalkFreeBuffDesc(pBuffDesc);
}