/*++ 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 #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 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); }