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);
|
||
}
|
||
|
||
|
||
|
||
|
||
|