1904 lines
49 KiB
C
1904 lines
49 KiB
C
|
/*++
|
|||
|
|
|||
|
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);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|