/*++ Copyright (c) 1992 Microsoft Corporation Module Name: zip.c Abstract: This module contains 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 ZIP #ifdef ALLOC_PRAGMA #pragma alloc_text(PAGE, AtalkZipInit) #pragma alloc_text(PAGEINIT, AtalkInitZipStartProcessingOnPort) #pragma alloc_text(PAGEINIT, atalkZipGetZoneListForPort) #pragma alloc_text(PAGE_RTR, AtalkZipPacketInRouter) #pragma alloc_text(PAGE_RTR, atalkZipHandleNetInfo) #pragma alloc_text(PAGE_RTR, atalkZipHandleReply) #pragma alloc_text(PAGE_RTR, atalkZipHandleQuery) #pragma alloc_text(PAGE_RTR, atalkZipHandleAtpRequest) #pragma alloc_text(PAGE_RTR, atalkZipQueryTimer) #pragma alloc_text(PAGE_NZ, AtalkZipGetMyZone) #pragma alloc_text(PAGE_NZ, atalkZipGetMyZoneReply) #pragma alloc_text(PAGE_NZ, AtalkZipGetZoneList) #pragma alloc_text(PAGE_NZ, atalkZipGetZoneListReply) #pragma alloc_text(PAGE_NZ, atalkZipZoneInfoTimer) #pragma alloc_text(PAGE_NZ, atalkZipSendPacket) #endif /*** AtalkZipInit * */ ATALK_ERROR AtalkZipInit( IN BOOLEAN Init ) { if (Init) { // Allocate space for zones AtalkZonesTable = (PZONE *)AtalkAllocZeroedMemory(sizeof(PZONE) * NUM_ZONES_HASH_BUCKETS); if (AtalkZonesTable == NULL) { return ATALK_RESR_MEM; } INITIALIZE_SPIN_LOCK(&AtalkZoneLock); } else { // At this point, we are unloading and there are no race conditions // or lock contentions. Do not bother locking down the zones table if (AtalkDesiredZone != NULL) AtalkZoneDereference(AtalkDesiredZone); if (AtalkZonesTable != NULL) { AtalkFreeMemory(AtalkZonesTable); AtalkZonesTable = NULL; } } return ATALK_NO_ERROR; } /*** AtalkZipStartProcessingOnPort * */ BOOLEAN AtalkInitZipStartProcessingOnPort( IN PPORT_DESCRIPTOR pPortDesc, IN PATALK_NODEADDR pRouterNode ) { ATALK_ADDR closeAddr; ATALK_ERROR Status; KIRQL OldIrql; BOOLEAN RetCode = FALSE; PDDP_ADDROBJ pZpDdpAddr=NULL; // Switch the incoming zip handler to the router version closeAddr.ata_Network = pRouterNode->atn_Network; closeAddr.ata_Node = pRouterNode->atn_Node; closeAddr.ata_Socket = ZONESINFORMATION_SOCKET; do { ACQUIRE_SPIN_LOCK(&pPortDesc->pd_Lock, &OldIrql); pPortDesc->pd_Flags |= PD_ROUTER_STARTING; RELEASE_SPIN_LOCK(&pPortDesc->pd_Lock, OldIrql); // Close the non-router version of the handler and start the router version AtalkDdpInitCloseAddress(pPortDesc, &closeAddr); if (!ATALK_SUCCESS(Status = AtalkDdpOpenAddress(pPortDesc, ZONESINFORMATION_SOCKET, pRouterNode, AtalkZipPacketInRouter, NULL, DDPPROTO_ANY, NULL, &pZpDdpAddr))) { DBGPRINT(DBG_COMP_RTMP, DBG_LEVEL_ERR, ("AtalkZipStartProcessingOnPort: AtalkDdpOpenAddress failed %ld\n", Status)); break; } // mark the fact that this is an "internal" socket pZpDdpAddr->ddpao_Flags |= DDPAO_SOCK_INTERNAL; // Try to get or set the zone information if (!atalkZipGetZoneListForPort(pPortDesc)) { DBGPRINT(DBG_COMP_ZIP, DBG_LEVEL_ERR, ("AtalkZipStartProcessingOnPort: Failed to get zone list for port\n")); break; } if (!atalkZipQryTmrRunning) { AtalkTimerInitialize(&atalkZipQTimer, atalkZipQueryTimer, ZIP_QUERY_TIMER); AtalkTimerScheduleEvent(&atalkZipQTimer); atalkZipQryTmrRunning = TRUE; } ACQUIRE_SPIN_LOCK(&pPortDesc->pd_Lock, &OldIrql); pPortDesc->pd_Flags &= ~PD_ROUTER_STARTING; RELEASE_SPIN_LOCK(&pPortDesc->pd_Lock, OldIrql); RetCode = TRUE; } while (FALSE); return RetCode; } /*** AtalkZipPacketIn * */ VOID AtalkZipPacketIn( 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 Status, IN BYTE DdpType, IN PVOID pHandlerCtx, IN BOOLEAN OptimizedPath, IN PVOID OptimizeCtx ) { BYTE CmdType, Flags; BYTE ZoneLen, DefZoneLen, MulticastAddrLen; PBYTE pZone, pDefZone, pMulticastAddr; TIME TimeS, TimeE, TimeD; ULONG Index; ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL); TimeS = KeQueryPerformanceCounter(NULL); do { if ((Status == ATALK_SOCKET_CLOSED) || (DdpType != DDPPROTO_ZIP)) break; else if (Status != ATALK_NO_ERROR) { break; } if (!EXT_NET(pPortDesc)) { AtalkLogBadPacket(pPortDesc, pSrcAddr, pDstAddr, pPkt, PktLen); break; } if (PktLen < ZIP_CMD_OFF+1) { break; } CmdType = pPkt[ZIP_CMD_OFF]; // We only care about Zip Notifies and NetInfo replies if (((CmdType != ZIP_NOTIFY) && (CmdType != ZIP_NETINFO_REPLY)) || (PktLen < (ZIP_ZONELEN_OFF + 1))) { break; } // If it is a NetInfoReply, then we should be looking for either the // default or the desired zone if ((CmdType != ZIP_NETINFO_REPLY) && (pPortDesc->pd_Flags & (PD_FINDING_DEFAULT_ZONE | PD_FINDING_DESIRED_ZONE))) break; if ((CmdType == ZIP_NETINFO_REPLY) && !(pPortDesc->pd_Flags & (PD_FINDING_DEFAULT_ZONE | PD_FINDING_DESIRED_ZONE))) break; // If it is a Notify then the desired zone must be valid if ((CmdType == ZIP_NOTIFY) && !(pPortDesc->pd_Flags & PD_VALID_DESIRED_ZONE)) break; // We have a NetInfoReply or a Notify. Handle it Flags = pPkt[ZIP_FLAGS_OFF]; Index = ZIP_ZONELEN_OFF; ZoneLen = pPkt[ZIP_ZONELEN_OFF]; Index ++; if ((ZoneLen > MAX_ZONE_LENGTH) || (PktLen < (Index + ZoneLen))) { AtalkLogBadPacket(pPortDesc, pSrcAddr, pDstAddr, pPkt, PktLen); break; } pZone = pPkt+Index; Index += ZoneLen; // If we are looking for a desired zone and we get a late default zone // response then toss this packet if ((CmdType == ZIP_NETINFO_REPLY) && (ZoneLen == 0) && (pPortDesc->pd_Flags & (PD_FINDING_DESIRED_ZONE)) && (pPortDesc->pd_InitialDesiredZone != NULL)) { DBGPRINT(DBG_COMP_RTMP, DBG_LEVEL_ERR, ("AtalkZipPacketIn: dropping a NetInfoReply packet\n")); break; } // If we're requesting the zone name, make sure the response matches // our request. ZoneLen will be zero when we're looking for the def // zone, so we won't do this test if ((CmdType == ZIP_NETINFO_REPLY) && (ZoneLen != 0) && (pPortDesc->pd_InitialDesiredZone != NULL)) { BOOLEAN NoMatch = FALSE; ACQUIRE_SPIN_LOCK_DPC(&pPortDesc->pd_Lock); ASSERT(!(pPortDesc->pd_Flags & PD_ROUTER_RUNNING) || (pPortDesc->pd_Flags & PD_FINDING_DESIRED_ZONE)); if (!AtalkFixedCompareCaseInsensitive(pZone, ZoneLen, pPortDesc->pd_InitialDesiredZone->zn_Zone, pPortDesc->pd_InitialDesiredZone->zn_ZoneLen)) { NoMatch = TRUE; } RELEASE_SPIN_LOCK_DPC(&pPortDesc->pd_Lock); if (NoMatch) break; } // If its a Notify, make sure we're in the zone that is being changed if (CmdType == ZIP_NOTIFY) { BOOLEAN NoMatch = FALSE; ACQUIRE_SPIN_LOCK_DPC(&pPortDesc->pd_Lock); if (!AtalkFixedCompareCaseInsensitive(pZone, ZoneLen, pPortDesc->pd_DesiredZone->zn_Zone, pPortDesc->pd_DesiredZone->zn_ZoneLen)) { NoMatch = TRUE; } RELEASE_SPIN_LOCK_DPC(&pPortDesc->pd_Lock); if (NoMatch) break; } if (PktLen < (Index + 1)) { AtalkLogBadPacket(pPortDesc, pSrcAddr, pDstAddr, pPkt, PktLen); break; } MulticastAddrLen = pPkt[Index++]; if (MulticastAddrLen != pPortDesc->pd_BroadcastAddrLen) { AtalkLogBadPacket(pPortDesc, pSrcAddr, pDstAddr, pPkt, PktLen); break; } if (PktLen < (Index + MulticastAddrLen)) { AtalkLogBadPacket(pPortDesc, pSrcAddr, pDstAddr, pPkt, PktLen); break; } pMulticastAddr = pPkt + Index; Index += MulticastAddrLen; #if 0 if (Flags & ZIP_USE_BROADCAST_FLAG) pMulticastAddr = pPortDesc->pd_BroadcastAddr; #endif // Grab second name, if needed or present DefZoneLen = 0; if ((CmdType == ZIP_NOTIFY) || (PktLen > Index)) { if (PktLen < (Index+1)) { AtalkLogBadPacket(pPortDesc, pSrcAddr, pDstAddr, pPkt, PktLen); break; } DefZoneLen = pPkt[Index++]; if ((DefZoneLen == 0) || (DefZoneLen > MAX_ZONE_LENGTH) || (PktLen < (Index+DefZoneLen))) { AtalkLogBadPacket(pPortDesc, pSrcAddr, pDstAddr, pPkt, PktLen); break; } pDefZone = pPkt+Index; Index += DefZoneLen; } // Make default zone be the new one. We may not have a default/new // zone in netinfo reply case and we requested for the correct zone if (DefZoneLen == 0) { pDefZone = pZone; DefZoneLen = ZoneLen; } // Make sure the port lock is released before calling any depend/ddp // etc. routines. ACQUIRE_SPIN_LOCK_DPC(&pPortDesc->pd_Lock); // If we're just looking for the default zone, set here and note // our mission completed if ((pPortDesc->pd_Flags & PD_FINDING_DEFAULT_ZONE) && (ZoneLen == 0)) { if (pPortDesc->pd_DefaultZone != NULL) AtalkZoneDereference(pPortDesc->pd_DefaultZone); pPortDesc->pd_DefaultZone = AtalkZoneReferenceByName(pDefZone, DefZoneLen); if (pPortDesc->pd_DefaultZone == NULL) { RELEASE_SPIN_LOCK_DPC(&pPortDesc->pd_Lock); RES_LOG_ERROR(); break; } pPortDesc->pd_Flags |= PD_VALID_DEFAULT_ZONE; pPortDesc->pd_Flags &= ~PD_FINDING_DEFAULT_ZONE; } // Now we want to accept all of the information about 'thiszone' // for the nodes on the current port // If the new multicast address is different, remove the old and // set the new. Don't allow changes to the 'broadcast' multicast // address. if (pPortDesc->pd_Flags & PD_FINDING_DESIRED_ZONE) { if (!AtalkFixedCompareCaseSensitive(pMulticastAddr, MulticastAddrLen, pPortDesc->pd_ZoneMulticastAddr, MulticastAddrLen)) { RELEASE_SPIN_LOCK_DPC(&pPortDesc->pd_Lock); (*pPortDesc->pd_RemoveMulticastAddr)(pPortDesc, pMulticastAddr, FALSE, NULL, NULL); ACQUIRE_SPIN_LOCK_DPC(&pPortDesc->pd_Lock); } if (!AtalkFixedCompareCaseSensitive(pMulticastAddr, MulticastAddrLen, pPortDesc->pd_BroadcastAddr, MulticastAddrLen)) { RELEASE_SPIN_LOCK_DPC(&pPortDesc->pd_Lock); (*pPortDesc->pd_AddMulticastAddr)(pPortDesc, pMulticastAddr, FALSE, NULL, NULL); ACQUIRE_SPIN_LOCK_DPC(&pPortDesc->pd_Lock); } RtlCopyMemory(pPortDesc->pd_ZoneMulticastAddr, pMulticastAddr, MulticastAddrLen); } // Finally set this cable range if this is a net info reply if (CmdType == ZIP_NETINFO_REPLY) { GETSHORT2SHORT(&pPortDesc->pd_NetworkRange.anr_FirstNetwork, pPkt+ZIP_CABLE_RANGE_START_OFF); GETSHORT2SHORT(&pPortDesc->pd_NetworkRange.anr_LastNetwork, pPkt+ZIP_CABLE_RANGE_END_OFF); if (!(pPortDesc->pd_Flags & PD_ROUTER_STARTING)) { pPortDesc->pd_ARouter.atn_Network = pSrcAddr->ata_Network; pPortDesc->pd_ARouter.atn_Node = pSrcAddr->ata_Node; } pPortDesc->pd_Flags |= PD_SEEN_ROUTER_RECENTLY; KeSetEvent(&pPortDesc->pd_SeenRouterEvent, IO_NETWORK_INCREMENT, FALSE); } // Now that we know the zone if (pPortDesc->pd_Flags & PD_FINDING_DESIRED_ZONE) { pPortDesc->pd_Flags &= ~PD_FINDING_DESIRED_ZONE; pPortDesc->pd_Flags |= PD_VALID_DESIRED_ZONE; if (pPortDesc->pd_DesiredZone != NULL) AtalkZoneDereference(pPortDesc->pd_DesiredZone); pPortDesc->pd_DesiredZone = AtalkZoneReferenceByName(pDefZone, DefZoneLen); if (pPortDesc->pd_DesiredZone == NULL) { pPortDesc->pd_Flags &= ~PD_VALID_DESIRED_ZONE; RES_LOG_ERROR(); } } RELEASE_SPIN_LOCK_DPC(&pPortDesc->pd_Lock); TimeE = KeQueryPerformanceCounter(NULL); TimeD.QuadPart = TimeE.QuadPart - TimeS.QuadPart; INTERLOCKED_ADD_LARGE_INTGR_DPC( &pPortDesc->pd_PortStats.prtst_ZipPacketInProcessTime, TimeD, &AtalkStatsLock.SpinLock); INTERLOCKED_INCREMENT_LONG_DPC( &pPortDesc->pd_PortStats.prtst_NumZipPacketsIn, &AtalkStatsLock.SpinLock); } while (FALSE); } /*** AtalkZipPacketInRouter * */ VOID AtalkZipPacketInRouter( 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 Status, IN BYTE DdpType, IN PVOID pHandlerCtx, IN BOOLEAN OptimizedPath, IN PVOID OptimizeCtx ) { BYTE CmdType; TIME TimeS, TimeE, TimeD; ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL); TimeS = KeQueryPerformanceCounter(NULL); do { if (Status == ATALK_SOCKET_CLOSED) break; else if (Status != ATALK_NO_ERROR) { break; } if (DdpType == DDPPROTO_ZIP) { if (PktLen < ZIP_FIRST_NET_OFF) { break; } CmdType = pPkt[ZIP_CMD_OFF]; switch (CmdType) { case ZIP_NETINFO_REPLY: case ZIP_NOTIFY: DBGPRINT(DBG_COMP_ZIP, DBG_LEVEL_INFO, ("AtalkZipPacketInRouter: Ignoring %s\n", (CmdType == ZIP_NOTIFY) ? "Notify" : "NetInfoReply")); break; case ZIP_GET_NETINFO: // We do not want to do a thing if we're starting up if (pPortDesc->pd_Flags & PD_ROUTER_STARTING) break; if (!EXT_NET(pPortDesc)) { AtalkLogBadPacket(pPortDesc, pSrcAddr, pDstAddr, pPkt, PktLen); break; } if (pPortDesc->pd_ZoneList == NULL) break; // Not fully up yet ! if (PktLen < ZIP_REQ_ZONENAME_OFF) { AtalkLogBadPacket(pPortDesc, pSrcAddr, pDstAddr, pPkt, PktLen); break; } DBGPRINT(DBG_COMP_ZIP, DBG_LEVEL_INFO, ("AtalkZipPacketInRouter: GetNetInfo Port %Z\n", &pPortDesc->pd_AdapterKey)); atalkZipHandleNetInfo(pPortDesc, pDdpAddr, pSrcAddr, pDstAddr, pPkt, PktLen); break; case ZIP_EXT_REPLY: case ZIP_REPLY: DBGPRINT(DBG_COMP_ZIP, DBG_LEVEL_INFO, ("AtalkZipPacketInRouter: %sReply Port %Z\n", (CmdType == ZIP_REPLY) ? "" : "Extended", &pPortDesc->pd_AdapterKey)); atalkZipHandleReply(pDdpAddr, pSrcAddr, pPkt, PktLen); break; case ZIP_QUERY: DBGPRINT(DBG_COMP_ZIP, DBG_LEVEL_INFO, ("AtalkZipPacketInRouter: Query Port %Z\n", &pPortDesc->pd_AdapterKey)); // We do not want to do a thing if we're starting up if (pPortDesc->pd_Flags & PD_ROUTER_STARTING) break; atalkZipHandleQuery(pPortDesc, pDdpAddr, pSrcAddr, pPkt, PktLen); break; default: AtalkLogBadPacket(pPortDesc, pSrcAddr, pDstAddr, pPkt, PktLen); break; } } else if (DdpType == DDPPROTO_ATP) { USHORT TrId, StartIndex; if (PktLen < ATP_ZIP_START_INDEX_OFF+1) { ASSERT(0); break; } // We do not want to do a thing if we're starting up if (pPortDesc->pd_Flags & PD_ROUTER_STARTING) break; // This had better be a GetZoneList, a GetMyZone ATP request if ((pPkt[ATP_CMD_CONTROL_OFF] & ATP_FUNC_MASK) != ATP_REQUEST) break; if (pPkt[ATP_BITMAP_OFF] != 1) { AtalkLogBadPacket(pPortDesc, pSrcAddr, pDstAddr, pPkt, PktLen); break; } GETSHORT2SHORT(&TrId, pPkt + ATP_TRANS_ID_OFF); CmdType = pPkt[ATP_ZIP_CMD_OFF]; if ((CmdType != ZIP_GET_ZONE_LIST) && (CmdType != ZIP_GET_MY_ZONE) && (CmdType != ZIP_GET_LOCAL_ZONES)) { AtalkLogBadPacket(pPortDesc, pSrcAddr, pDstAddr, pPkt, PktLen); break; } DBGPRINT(DBG_COMP_ZIP, DBG_LEVEL_INFO, ("ZIP: Received atp type command %d\n", CmdType)); // Get start index. Not meaningful for GetMyZone GETSHORT2SHORT(&StartIndex, pPkt+ATP_ZIP_START_INDEX_OFF); DBGPRINT(DBG_COMP_ZIP, DBG_LEVEL_INFO, ("AtalkZipPacketInRouter: AtpRequest %d, Port %Z\n", CmdType, &pPortDesc->pd_AdapterKey)); atalkZipHandleAtpRequest(pPortDesc, pDdpAddr, pSrcAddr, CmdType, TrId, StartIndex); } } while (FALSE); TimeE = KeQueryPerformanceCounter(NULL); TimeD.QuadPart = TimeE.QuadPart - TimeS.QuadPart; INTERLOCKED_ADD_LARGE_INTGR_DPC( &pPortDesc->pd_PortStats.prtst_ZipPacketInProcessTime, TimeD, &AtalkStatsLock.SpinLock); INTERLOCKED_INCREMENT_LONG_DPC( &pPortDesc->pd_PortStats.prtst_NumZipPacketsIn, &AtalkStatsLock.SpinLock); } /*** atalkZipHandleNetInfo * */ VOID atalkZipHandleNetInfo( IN PPORT_DESCRIPTOR pPortDesc, IN PDDP_ADDROBJ pDdpAddr, IN PATALK_ADDR pSrcAddr, IN PATALK_ADDR pDstAddr, IN PBYTE pPkt, IN USHORT PktLen ) { PBUFFER_DESC pBuffDesc; BYTE ZoneLen; PBYTE Datagram, pZoneName; ATALK_ADDR SrcAddr = *pSrcAddr; ATALK_ERROR error; BOOLEAN UseDefZone = FALSE; USHORT index; SEND_COMPL_INFO SendInfo; ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL); do { // Get the zone name out of the request ZoneLen = pPkt[ZIP_REQ_ZONELEN_OFF]; if ((ZoneLen > MAX_ZONE_LENGTH) || (PktLen < (USHORT)(ZoneLen + ZIP_REQ_ZONENAME_OFF))) { AtalkLogBadPacket(pPortDesc, pSrcAddr, pDstAddr, pPkt, PktLen); break; } pZoneName = pPkt+ZIP_REQ_ZONENAME_OFF; if ((pBuffDesc = AtalkAllocBuffDesc(NULL, MAX_DGRAM_SIZE, BD_CHAR_BUFFER | BD_FREE_BUFFER)) == NULL) { break; } Datagram = pBuffDesc->bd_CharBuffer; // Format a GetNetInfo reply command Datagram[ZIP_CMD_OFF] = ZIP_NETINFO_REPLY; Datagram[ZIP_FLAGS_OFF] = 0; ACQUIRE_SPIN_LOCK_DPC(&pPortDesc->pd_Lock); if ((ZoneLen == 0) || !AtalkZoneNameOnList(pZoneName, ZoneLen, pPortDesc->pd_ZoneList)) { Datagram[ZIP_FLAGS_OFF] |= ZIP_ZONE_INVALID_FLAG; UseDefZone = TRUE; } if (AtalkZoneNumOnList(pPortDesc->pd_ZoneList) == 1) Datagram[ZIP_FLAGS_OFF] |= ZIP_ONLYONE_ZONE_FLAG; // Add our cable range PUTSHORT2SHORT(&Datagram[ZIP_FIRST_NET_OFF], pPortDesc->pd_NetworkRange.anr_FirstNetwork); PUTSHORT2SHORT(Datagram +ZIP_LAST_NET_OFF, pPortDesc->pd_NetworkRange.anr_LastNetwork); // Echo back the requested zone name Datagram[ZIP_REQ_ZONELEN_OFF] = ZoneLen; RtlCopyMemory(Datagram+ZIP_REQ_ZONENAME_OFF, pZoneName, ZoneLen); index = ZIP_REQ_ZONENAME_OFF + ZoneLen; // Place in the correct zone multicast address Datagram[index++] = (BYTE)(pPortDesc->pd_BroadcastAddrLen); if (UseDefZone) { pZoneName = pPortDesc->pd_DefaultZone->zn_Zone; ZoneLen = pPortDesc->pd_DefaultZone->zn_ZoneLen; } AtalkZipMulticastAddrForZone(pPortDesc, pZoneName, ZoneLen, Datagram + index); index += pPortDesc->pd_BroadcastAddrLen; // If we need it, add in the default zone if (UseDefZone) { Datagram[index++] = ZoneLen = pPortDesc->pd_DefaultZone->zn_ZoneLen; RtlCopyMemory(Datagram + index, pPortDesc->pd_DefaultZone->zn_Zone, ZoneLen); index += ZoneLen; } // If the request came as a cable-wide broadcast and its // source network is not valid for this port, then we want // to respond to cable-wide broadcast rather than the source if ((pDstAddr->ata_Network == CABLEWIDE_BROADCAST_NETWORK) && (pDstAddr->ata_Node == ATALK_BROADCAST_NODE) && !WITHIN_NETWORK_RANGE(pSrcAddr->ata_Network, &pPortDesc->pd_NetworkRange) && !WITHIN_NETWORK_RANGE(pSrcAddr->ata_Network, &AtalkStartupNetworkRange)) { SrcAddr.ata_Network = CABLEWIDE_BROADCAST_NETWORK; SrcAddr.ata_Node = ATALK_BROADCAST_NODE; } RELEASE_SPIN_LOCK_DPC(&pPortDesc->pd_Lock); // Set the length in the buffer descriptor. AtalkSetSizeOfBuffDescData(pBuffDesc, index); // Finally, send this out DBGPRINT(DBG_COMP_ZIP, DBG_LEVEL_INFO, ("atalkZipHandleNetInfo: Sending Reply to %d.%d.%d\n", SrcAddr.ata_Network, SrcAddr.ata_Node, SrcAddr.ata_Socket)); SendInfo.sc_TransmitCompletion = atalkZipSendComplete; SendInfo.sc_Ctx1 = pBuffDesc; // SendInfo.sc_Ctx2 = NULL; // SendInfo.sc_Ctx3 = NULL; error = AtalkDdpSend(pDdpAddr, &SrcAddr, DDPPROTO_ZIP, FALSE, pBuffDesc, NULL, 0, NULL, &SendInfo); if (!ATALK_SUCCESS(error)) { AtalkFreeBuffDesc(pBuffDesc); DBGPRINT(DBG_COMP_ZIP, DBG_LEVEL_ERR, ("atalkZipHandleNetInfo: AtalkDdpSend %ld\n", error)); } } while (FALSE); } /*** atalkZipHandleReply * */ VOID atalkZipHandleReply( IN PDDP_ADDROBJ pDdpAddr, IN PATALK_ADDR pSrcAddr, IN PBYTE pPkt, IN USHORT PktLen ) { ULONG index, TotalNetCnt; PRTE pRte = NULL; PBYTE ZoneName; USHORT NetNum; BYTE CmdType, NwCnt, NumZonesOnNet, ZoneLen; BOOLEAN RteLocked = FALSE; BOOLEAN ExtReply = FALSE; ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL); DBGPRINT(DBG_COMP_ZIP, DBG_LEVEL_INFO, ("atalkZipHandleReply: Enetered\n")); // For a zip extended reply, the network count is really not // the # of networks contained in the packet. It is the total # // of zones on the single network that is described by the reply NwCnt = NumZonesOnNet = pPkt[ZIP_NW_CNT_OFF]; CmdType = pPkt[ZIP_CMD_OFF]; do { // Walk through the reply packet (assuming we asked for the // contained information). We're still using NwCnt when // processing an extended reply, but that's okay 'cause it // will certainly be at least the # of zones contained in // this packet. The '+3' guarantees that we really have // network # and node for (index = ZIP_FIRST_NET_OFF, TotalNetCnt = 0; (TotalNetCnt < NwCnt) && ((index + 3 ) <= PktLen); TotalNetCnt ++) { if (pRte != NULL) { if (RteLocked) { RELEASE_SPIN_LOCK_DPC(&pRte->rte_Lock); RteLocked = FALSE; } AtalkRtmpDereferenceRte(pRte, FALSE); pRte = NULL; } // Get the next netwotk #, if it's not in our routing // table (or not the start of a range), then we certainly // don't care about its zone name GETSHORT2SHORT(&NetNum, pPkt+index); index += sizeof(USHORT); ZoneLen = pPkt[index++]; if (((pRte = AtalkRtmpReferenceRte(NetNum)) == NULL) || (pRte->rte_NwRange.anr_FirstNetwork != NetNum)) { DBGPRINT(DBG_COMP_ZIP, DBG_LEVEL_ERR, ("atalkZipHandleReply: Don't know about this range %d\n", NetNum)); index += ZoneLen; continue; } // Validate the zone name if ((ZoneLen == 0) || (ZoneLen > MAX_ZONE_LENGTH) || ((index + ZoneLen) > PktLen)) { AtalkLogBadPacket(pDdpAddr->ddpao_Node->an_Port, pSrcAddr, NULL, pPkt, PktLen); break; } // Conditionally move the zone name into the routing table ZoneName = pPkt+index; index += ZoneLen; ACQUIRE_SPIN_LOCK_DPC(&pRte->rte_Lock); RteLocked = TRUE; if (AtalkZoneNameOnList(ZoneName, ZoneLen, pRte->rte_ZoneList)) { DBGPRINT(DBG_COMP_ZIP, DBG_LEVEL_INFO, ("atalkZipHandleReply: Already have this zone\n")); continue; } // Check for somebody out there trying to add another zone to // our directly connected non-extended network and we already // know its zone. if ((pRte->rte_NumHops == 0) && !EXT_NET(pRte->rte_PortDesc) && (AtalkZoneNumOnList(pRte->rte_ZoneList) == 1)) { AtalkLogBadPacket(pDdpAddr->ddpao_Node->an_Port, pSrcAddr, NULL, pPkt, PktLen); continue; } // Add to the list now pRte->rte_ZoneList = AtalkZoneAddToList(pRte->rte_ZoneList, ZoneName, ZoneLen); if (pRte->rte_ZoneList == NULL) { DBGPRINT(DBG_COMP_ZIP, DBG_LEVEL_ERR, ("atalkZipHandleReply: Failed to add zone to list\n")); pRte->rte_Flags &= ~RTE_ZONELIST_VALID; continue; } DBGPRINT(DBG_COMP_ZIP, DBG_LEVEL_INFO, ("atalkZipHandleReply: # of zones known so far %d\n", AtalkZoneNumOnList(pRte->rte_ZoneList))); // If not an extended reply, we know that we have all // of the information about a given network contained // in this packet, so we can go ahead and mark the zone // list valid now if (!ExtReply) pRte->rte_Flags |= RTE_ZONELIST_VALID; } // If we just handled an extended reply, do we now know all // that we should know about the specified network ? if (pRte != NULL) { if (ExtReply) { if (!RteLocked) { ACQUIRE_SPIN_LOCK_DPC(&pRte->rte_Lock); RteLocked = TRUE; } if (AtalkZoneNumOnList(pRte->rte_ZoneList) >= NumZonesOnNet) pRte->rte_Flags |= RTE_ZONELIST_VALID; } if (RteLocked) { RELEASE_SPIN_LOCK_DPC(&pRte->rte_Lock); // RteLocked = FALSE; } AtalkRtmpDereferenceRte(pRte, FALSE); // pRte = NULL; } } while (FALSE); } /*** atalkZipHandleQuery * */ VOID atalkZipHandleQuery( IN PPORT_DESCRIPTOR pPortDesc, IN PDDP_ADDROBJ pDdpAddr, IN PATALK_ADDR pSrcAddr, IN PBYTE pPkt, IN USHORT PktLen ) { PRTE pRte = NULL; PBUFFER_DESC pBuffDesc, pBuffDescStart = NULL, *ppBuffDesc = &pBuffDescStart; PZONE_LIST pZoneList; PBYTE Datagram; ATALK_ERROR error; ULONG i, CurrNumZones, PrevNumZones, TotalNetCnt; ULONG NwCnt, NetCntInPkt; USHORT NetNum, Size; BOOLEAN AllocNewBuffDesc = TRUE, NewPkt = TRUE; BOOLEAN PortLocked = FALSE, RteLocked = FALSE; BYTE CurrReply, NextReply; SEND_COMPL_INFO SendInfo; ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL); CurrNumZones = 0; do { // Walk through the query packet building reply packets that // have as much information as we know. // When sending replies, we will always send a reply about a // network that has more than one zone as an extended reply. // As were walking the query list, and we encounter a couple of // networks that have only one zone, we'll pack as many of // these as we can into a non-extended reply NwCnt = pPkt[ZIP_NW_CNT_OFF]; for (NetCntInPkt = 0, TotalNetCnt = 0, i = ZIP_FIRST_NET_OFF; (TotalNetCnt < NwCnt) && ((i + sizeof(SHORT)) <= PktLen); i += sizeof(USHORT), TotalNetCnt++) { // Dereference any previous Rtes if (pRte != NULL) { if (RteLocked) { RELEASE_SPIN_LOCK_DPC(&pRte->rte_Lock); RteLocked = FALSE; } AtalkRtmpDereferenceRte(pRte, FALSE); pRte = NULL; } if (PortLocked) { RELEASE_SPIN_LOCK_DPC(&pPortDesc->pd_Lock); PortLocked = FALSE; } // Grab the next network number from the query packet, // if we don't know about the network, or we don't know // the zone name, continue with the next network number GETSHORT2SHORT(&NetNum, pPkt+i); ACQUIRE_SPIN_LOCK_DPC(&pPortDesc->pd_Lock); if ((WITHIN_NETWORK_RANGE(NetNum,&pPortDesc->pd_NetworkRange)) && (pPortDesc->pd_ZoneList != NULL)) { pZoneList = pPortDesc->pd_ZoneList; PortLocked = TRUE; } else { RELEASE_SPIN_LOCK_DPC(&pPortDesc->pd_Lock); if (((pRte = AtalkRtmpReferenceRte(NetNum)) == NULL) || (!WITHIN_NETWORK_RANGE(NetNum, &pRte->rte_NwRange)) || !(pRte->rte_Flags & RTE_ZONELIST_VALID)) { continue; } else { ACQUIRE_SPIN_LOCK_DPC(&pRte->rte_Lock); pZoneList = pRte->rte_ZoneList; RteLocked = TRUE; } } next_reply: if (AllocNewBuffDesc) { if ((pBuffDesc = AtalkAllocBuffDesc(NULL, MAX_DGRAM_SIZE, BD_CHAR_BUFFER | BD_FREE_BUFFER)) == NULL) { DBGPRINT(DBG_COMP_RTMP, DBG_LEVEL_ERR, ("\natalkZipHandleQuery: AtalkAllocBuffDesc @1 failed\n")); break; } Size = 0; Datagram = pBuffDesc->bd_CharBuffer; *ppBuffDesc = pBuffDesc; pBuffDesc->bd_Next = NULL; ppBuffDesc = &pBuffDesc->bd_Next; AllocNewBuffDesc = FALSE; } // What type of response does this network want ? // Copy the previous network's zone count. In case of the first // pass, make it same. PrevNumZones = CurrNumZones; CurrNumZones = AtalkZoneNumOnList(pZoneList); if (i == ZIP_FIRST_NET_OFF) PrevNumZones = CurrNumZones; ASSERT (CurrNumZones != 0); NextReply = ZIP_REPLY; if (CurrNumZones > 1) { // We start a new packet for each extended network NewPkt = TRUE; NextReply = ZIP_EXT_REPLY; if (NetCntInPkt > 0) { Datagram[ZIP_CMD_OFF] = CurrReply; if (CurrReply == ZIP_REPLY) Datagram[ZIP_NW_CNT_OFF] = (BYTE)NetCntInPkt; else Datagram[ZIP_NW_CNT_OFF] = (BYTE)PrevNumZones; AllocNewBuffDesc = TRUE; pBuffDesc->bd_Length = Size; NetCntInPkt = 0; goto next_reply; } } // Walk the zone list for (; pZoneList != NULL; pZoneList = pZoneList->zl_Next) { PZONE pZone = pZoneList->zl_pZone; // If we're starting to build a new reply packet due to // either: // // 1. first time through // 2. packet full // 3. switching reply types // // set the index to the first tuple position. if (NewPkt || (CurrReply != NextReply)) { if (NetCntInPkt > 0) { // Close the current buffdesc and open a new one // Careful here with the CurrNumZones vs. PrevNumZones // If we are going from ExtReply to a Reply, we need // to get PrevNumZones. If we are continuing the // same ExtReply then we need CurrNumZones. Datagram[ZIP_CMD_OFF] = CurrReply; if (CurrReply == ZIP_REPLY) Datagram[ZIP_NW_CNT_OFF] = (BYTE)NetCntInPkt; else { Datagram[ZIP_NW_CNT_OFF] = (BYTE)CurrNumZones; if (CurrReply != NextReply) Datagram[ZIP_NW_CNT_OFF] = (BYTE)PrevNumZones; } pBuffDesc->bd_Length = Size; if ((pBuffDesc = AtalkAllocBuffDesc(NULL,MAX_DGRAM_SIZE, BD_CHAR_BUFFER | BD_FREE_BUFFER)) == NULL) { DBGPRINT(DBG_COMP_RTMP, DBG_LEVEL_ERR, ("\natalkZipHandleQuery: AtalkAllocBuffDesc @2 failed\n")); break; } Size = 0; Datagram = pBuffDesc->bd_CharBuffer; *ppBuffDesc = pBuffDesc; pBuffDesc->bd_Next = NULL; ppBuffDesc = &pBuffDesc->bd_Next; NetCntInPkt = 0; } Size = ZIP_FIRST_NET_OFF; CurrReply = NextReply; NewPkt = FALSE; } // We know the answer to the question. Pack a new // network/zone tuple into the reply packet. PUTSHORT2SHORT(Datagram+Size, NetNum); Size += sizeof(USHORT); Datagram[Size++] = pZone->zn_ZoneLen; RtlCopyMemory(Datagram + Size, pZone->zn_Zone, pZone->zn_ZoneLen); Size += pZone->zn_ZoneLen; NetCntInPkt ++; // If we can't hold another big tuple, signal that we // should send on the next pass. if ((Size + sizeof(USHORT) + sizeof(char) + MAX_ZONE_LENGTH) >= MAX_DGRAM_SIZE) { NewPkt = TRUE; } } if (pBuffDesc == NULL) { break; } } // Dereference an rte if we broke out the loop above if (pRte != NULL) { ASSERT(!PortLocked); if (RteLocked) { RELEASE_SPIN_LOCK_DPC(&pRte->rte_Lock); // RteLocked = FALSE; } AtalkRtmpDereferenceRte(pRte, FALSE); // pRte = NULL; } if (PortLocked) { ASSERT(!RteLocked); RELEASE_SPIN_LOCK_DPC(&pPortDesc->pd_Lock); PortLocked = FALSE; } // Close the current buffdesc if ((!AllocNewBuffDesc) && (pBuffDesc != NULL)) { pBuffDesc->bd_Length = Size; if (NetCntInPkt > 0) { Datagram[ZIP_CMD_OFF] = CurrReply; if (CurrReply == ZIP_REPLY) Datagram[ZIP_NW_CNT_OFF] = (BYTE)NetCntInPkt; else Datagram[ZIP_NW_CNT_OFF] = (BYTE)CurrNumZones; } } // We have a bunch of datagrams ready to be fired off. // Make it so. Do not send any with zero lengths, however. SendInfo.sc_TransmitCompletion = atalkZipSendComplete; // SendInfo.sc_Ctx2 = NULL; // SendInfo.sc_Ctx3 = NULL; for (pBuffDesc = pBuffDescStart; pBuffDesc != NULL; pBuffDesc = pBuffDescStart) { pBuffDescStart = pBuffDesc->bd_Next; if (pBuffDesc->bd_Length == 0) { ASSERT(pBuffDescStart == NULL); AtalkFreeBuffDesc(pBuffDesc); break; } // Set the next ptr to be null. Length already set correctly. pBuffDesc->bd_Next = NULL; DBGPRINT(DBG_COMP_ZIP, DBG_LEVEL_INFO, ("atalkZipHandleQuery: Sending Reply to %d.%d.%d\n", pSrcAddr->ata_Network, pSrcAddr->ata_Node, pSrcAddr->ata_Socket)); SendInfo.sc_Ctx1 = pBuffDesc; error = AtalkDdpSend(pDdpAddr, pSrcAddr, DDPPROTO_ZIP, FALSE, pBuffDesc, NULL, 0, NULL, &SendInfo); if (!ATALK_SUCCESS(error)) { AtalkFreeBuffDesc(pBuffDesc); DBGPRINT(DBG_COMP_ZIP, DBG_LEVEL_ERR, ("atalkZipHandleQuery: AtalkDdpSend %ld\n", error)); } } } while (FALSE); if (PortLocked) { ASSERT(!RteLocked); RELEASE_SPIN_LOCK_DPC(&pPortDesc->pd_Lock); } } /*** atalkZipHandleAtpRequest * */ VOID atalkZipHandleAtpRequest( IN PPORT_DESCRIPTOR pPortDesc, IN PDDP_ADDROBJ pDdpAddr, IN PATALK_ADDR pSrcAddr, IN BYTE CmdType, IN USHORT TrId, IN USHORT StartIndex ) { PBUFFER_DESC pBuffDesc; PBYTE Datagram, ZoneName; PZONE pZone; ATALK_ERROR error; int i, ZoneLen, ZoneCnt, CurrZoneIndex, index; BYTE LastFlag = 0; SEND_COMPL_INFO SendInfo; ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL); do { // Allocate a buffer descriptor and initialize the header if ((pBuffDesc = AtalkAllocBuffDesc(NULL, MAX_DGRAM_SIZE, BD_CHAR_BUFFER | BD_FREE_BUFFER)) == NULL) { break; } Datagram = pBuffDesc->bd_CharBuffer; Datagram[ATP_CMD_CONTROL_OFF] = ATP_RESPONSE + ATP_EOM_MASK; Datagram[ATP_SEQ_NUM_OFF] = 0; PUTSHORT2SHORT(Datagram + ATP_TRANS_ID_OFF, TrId); SendInfo.sc_TransmitCompletion = atalkZipSendComplete; SendInfo.sc_Ctx1 = pBuffDesc; // SendInfo.sc_Ctx2 = NULL; // SendInfo.sc_Ctx3 = NULL; if (CmdType == ZIP_GET_MY_ZONE) { // We really shouldn't be getting this request on an // extended network, but go ahead and reply with the // "default zone" in this case, of course, reply with // "desired zone" for non-extended nets. We are a router, // so "desired zone" will always be valid -- as will the // default zone for extended net. PUTSHORT2SHORT(Datagram+ATP_ZIP_LAST_FLAG_OFF, 0); PUTSHORT2SHORT(Datagram+ATP_ZIP_START_INDEX_OFF, 1); ACQUIRE_SPIN_LOCK_DPC(&pPortDesc->pd_Lock); if (EXT_NET(pPortDesc)) { ZoneName = pPortDesc->pd_DefaultZone->zn_Zone; ZoneLen = pPortDesc->pd_DefaultZone->zn_ZoneLen; } else { ZoneName = pPortDesc->pd_DesiredZone->zn_Zone; ZoneLen = pPortDesc->pd_DesiredZone->zn_ZoneLen; } RtlCopyMemory(Datagram+ATP_DATA_OFF+1, ZoneName, ZoneLen); Datagram[ATP_DATA_OFF] = (BYTE)ZoneLen; RELEASE_SPIN_LOCK_DPC(&pPortDesc->pd_Lock); // Set the length in the buffer descriptor. AtalkSetSizeOfBuffDescData(pBuffDesc, (USHORT)(ATP_DATA_OFF + 1 + ZoneLen)); DBGPRINT(DBG_COMP_ZIP, DBG_LEVEL_INFO, ("atalkZipHandleAtpReq: Sending GetMyZone Reply to %d.%d.%d\n", pSrcAddr->ata_Network, pSrcAddr->ata_Node, pSrcAddr->ata_Socket)); error = AtalkDdpSend(pDdpAddr, pSrcAddr, DDPPROTO_ATP, FALSE, pBuffDesc, NULL, 0, NULL, &SendInfo); if (!ATALK_SUCCESS(error)) { DBGPRINT(DBG_COMP_ZIP, DBG_LEVEL_ERR, ("atalkZipHandleAtpRequest: AtalkDdpSend %ld\n", error)); } break; } // Either a GetLocalZones or a GetZoneList. Fill the reply packet // with as many zones as it'll hold starting at the requested // start index index = ATP_DATA_OFF; if (CmdType == ZIP_GET_LOCAL_ZONES) { PZONE_LIST pZoneList; // For GetLocalZones, we only want to count zones // that are on the network that is directly connected // to the port on which the request originated. Use the // zone list on the port. ACQUIRE_SPIN_LOCK_DPC(&pPortDesc->pd_Lock); for (pZoneList = pPortDesc->pd_ZoneList, ZoneCnt = 0, CurrZoneIndex = 0; pZoneList != NULL; pZoneList = pZoneList->zl_Next) { // If we have not seen StartIndex zones yet, keep going if (++CurrZoneIndex < StartIndex) continue; pZone = pZoneList->zl_pZone; // If this packet cannot hold more, we're done (for now) // Fill in the zone count and the last flag if ((index + pZone->zn_ZoneLen + 1) >= MAX_DGRAM_SIZE) { break; } // Place zone name in the packet ASSERT(pZone != NULL); Datagram[index] = pZone->zn_ZoneLen; RtlCopyMemory(Datagram+index+1, pZone->zn_Zone, pZone->zn_ZoneLen); index += (pZone->zn_ZoneLen + 1); ZoneCnt ++; } RELEASE_SPIN_LOCK_DPC(&pPortDesc->pd_Lock); // We've build a packet, set the last flag, if applicable LastFlag = (pZoneList == NULL) ? 1 : 0; } else // This is a ZIP_GET_ZONE_LIST { BOOLEAN PktFull = FALSE; ASSERT (CmdType == ZIP_GET_ZONE_LIST); // For GetZoneList, we want all the zones that we know // of, so use the AtalkZoneTable. ACQUIRE_SPIN_LOCK_DPC(&AtalkZoneLock); for (i = 0, ZoneCnt = 0, CurrZoneIndex = 0; (i < NUM_ZONES_HASH_BUCKETS) && !PktFull; i++) { for (pZone = AtalkZonesTable[i]; pZone != NULL; pZone = pZone->zn_Next) { // If we have not seen StartIndex zones yet, keep going if (++CurrZoneIndex < StartIndex) continue; // If this packet cannot hold more, we're done (for now) // Fill in the zone count and the last flag if ((index + pZone->zn_ZoneLen + 1) >= MAX_DGRAM_SIZE) { PktFull = TRUE; break; } // Place zone name in the packet Datagram[index] = pZone->zn_ZoneLen; RtlCopyMemory(Datagram+index+1, pZone->zn_Zone, pZone->zn_ZoneLen); index += (pZone->zn_ZoneLen + 1); ZoneCnt ++; } } RELEASE_SPIN_LOCK_DPC(&AtalkZoneLock); // We've build a packet, set the last flag, if applicable LastFlag = ((i == NUM_ZONES_HASH_BUCKETS) && (pZone == NULL)) ? 1 : 0; } // We've build a packet, set the last flag and # of zones in packet Datagram[ATP_ZIP_LAST_FLAG_OFF] = LastFlag; Datagram[ATP_ZIP_LAST_FLAG_OFF + 1] = 0; PUTSHORT2SHORT(Datagram + ATP_ZIP_ZONE_CNT_OFF, ZoneCnt); // Set the length in the buffer descriptor. AtalkSetSizeOfBuffDescData(pBuffDesc, (USHORT)index); // Finally, send this out DBGPRINT(DBG_COMP_ZIP, DBG_LEVEL_INFO, ("atalkZipHandleAtpReq: Sending LocalZones Reply to %d.%d.%d\n", pSrcAddr->ata_Network, pSrcAddr->ata_Node, pSrcAddr->ata_Socket)); error = AtalkDdpSend(pDdpAddr, pSrcAddr, DDPPROTO_ATP, FALSE, pBuffDesc, NULL, 0, NULL, &SendInfo); if (!ATALK_SUCCESS(error)) { AtalkFreeBuffDesc(pBuffDesc); DBGPRINT(DBG_COMP_ZIP, DBG_LEVEL_ERR, ("atalkZipHandleAtpRequest: AtalkDdpSend %ld\n", error)); } } while (FALSE); } /*** AtalkZipMulticastAddrForZone * */ VOID AtalkZipMulticastAddrForZone( IN PPORT_DESCRIPTOR pPortDesc, IN PBYTE pZone, IN BYTE ZoneLen, IN PBYTE MulticastAddr ) { USHORT CheckSum; BYTE UpCasedZone[MAX_ZONE_LENGTH]; AtalkUpCase(pZone, ZoneLen, UpCasedZone); // Caculate the checksum for the zone CheckSum = AtalkDdpCheckSumBuffer(UpCasedZone, ZoneLen, 0); switch (pPortDesc->pd_PortType) { case ELAP_PORT: case FDDI_PORT: RtlCopyMemory(MulticastAddr, AtalkEthernetZoneMulticastAddrsHdr, ELAP_MCAST_HDR_LEN); MulticastAddr[ELAP_MCAST_HDR_LEN] = AtalkEthernetZoneMulticastAddrs[CheckSum % ELAP_ZONE_MULTICAST_ADDRS]; break; case TLAP_PORT: RtlCopyMemory(MulticastAddr, AtalkTokenRingZoneMulticastAddrsHdr, TLAP_MCAST_HDR_LEN); RtlCopyMemory(&MulticastAddr[TLAP_MCAST_HDR_LEN], AtalkTokenRingZoneMulticastAddrs[CheckSum % TLAP_ZONE_MULTICAST_ADDRS], TLAP_ADDR_LEN - TLAP_MCAST_HDR_LEN); break; default: DBGBRK(DBG_LEVEL_FATAL); KeBugCheck(0); } } /*** AtalkZipGetNetworkInfoForNode * */ BOOLEAN AtalkZipGetNetworkInfoForNode( IN PPORT_DESCRIPTOR pPortDesc, IN PATALK_NODEADDR pNode, IN BOOLEAN FindDefZone ) { PBUFFER_DESC pBuffDesc = NULL; ATALK_ADDR SrcAddr, DstAddr; ATALK_ERROR error; USHORT NumReqs, DgLen; BYTE DgCopy[ZIP_ZONENAME_OFF + MAX_ZONE_LENGTH]; KIRQL OldIrql; BOOLEAN RetCode, Done; SEND_COMPL_INFO SendInfo; ASSERT(EXT_NET(pPortDesc)); ACQUIRE_SPIN_LOCK(&pPortDesc->pd_Lock, &OldIrql); if (FindDefZone) { pPortDesc->pd_Flags &= ~PD_VALID_DEFAULT_ZONE; pPortDesc->pd_Flags |= PD_FINDING_DEFAULT_ZONE; } else { pPortDesc->pd_Flags &= ~PD_VALID_DESIRED_ZONE; pPortDesc->pd_Flags |= PD_FINDING_DESIRED_ZONE; } // Get source and destination addresses SrcAddr.ata_Network = pNode->atn_Network; SrcAddr.ata_Node = pNode->atn_Node; SrcAddr.ata_Socket = ZONESINFORMATION_SOCKET; DstAddr.ata_Network = CABLEWIDE_BROADCAST_NETWORK; DstAddr.ata_Node = ATALK_BROADCAST_NODE; DstAddr.ata_Socket = ZONESINFORMATION_SOCKET; // Build a ZipNetGetInfo datagram DgCopy[ZIP_CMD_OFF] = ZIP_GET_NETINFO; DgCopy[ZIP_FLAGS_OFF] = 0; PUTSHORT2SHORT(DgCopy + ZIP_CABLE_RANGE_START_OFF, 0); PUTSHORT2SHORT(DgCopy + ZIP_CABLE_RANGE_END_OFF, 0); DgLen = ZIP_ZONENAME_OFF; DgCopy[ZIP_ZONELEN_OFF] = 0; if (!FindDefZone && (pPortDesc->pd_InitialDesiredZone != NULL)) { DgCopy[ZIP_ZONELEN_OFF] = pPortDesc->pd_InitialDesiredZone->zn_ZoneLen; RtlCopyMemory(DgCopy + ZIP_ZONENAME_OFF, pPortDesc->pd_InitialDesiredZone->zn_Zone, pPortDesc->pd_InitialDesiredZone->zn_ZoneLen); DgLen += DgCopy[ZIP_ZONELEN_OFF]; } RELEASE_SPIN_LOCK(&pPortDesc->pd_Lock, OldIrql); for (NumReqs = 0; NumReqs < ZIP_NUM_GETNET_INFOS; NumReqs++) { Done = FindDefZone ? ((pPortDesc->pd_Flags & PD_VALID_DEFAULT_ZONE) != 0) : ((pPortDesc->pd_Flags & PD_VALID_DESIRED_ZONE) != 0); if (Done) { break; } if ((pBuffDesc = AtalkAllocBuffDesc(NULL, DgLen, BD_CHAR_BUFFER | BD_FREE_BUFFER)) == NULL) { break; } RtlCopyMemory(pBuffDesc->bd_CharBuffer, DgCopy, DgLen); // Set the length in the buffer descriptor. AtalkSetSizeOfBuffDescData(pBuffDesc, DgLen); SendInfo.sc_TransmitCompletion = atalkZipSendComplete; SendInfo.sc_Ctx1 = pBuffDesc; // SendInfo.sc_Ctx2 = NULL; // SendInfo.sc_Ctx3 = NULL; error = AtalkDdpTransmit(pPortDesc, &SrcAddr, &DstAddr, DDPPROTO_ZIP, pBuffDesc, NULL, 0, 0, NULL, NULL, &SendInfo); if (!ATALK_SUCCESS(error)) { DBGPRINT(DBG_COMP_ZIP, DBG_LEVEL_ERR, ("AtalkZipGetNetworkInfoForNode: AtalkDdpTransmit %ld\n", error)); break; } pBuffDesc = NULL; AtalkSleep(ZIP_GET_NETINFO_WAIT); } if (pBuffDesc != NULL) AtalkFreeBuffDesc(pBuffDesc); ACQUIRE_SPIN_LOCK(&pPortDesc->pd_Lock, &OldIrql); if (FindDefZone) { pPortDesc->pd_Flags &= ~PD_FINDING_DEFAULT_ZONE; } else { pPortDesc->pd_Flags &= ~PD_FINDING_DESIRED_ZONE; } RetCode = FindDefZone ? ((pPortDesc->pd_Flags & PD_VALID_DEFAULT_ZONE) == PD_VALID_DEFAULT_ZONE) : ((pPortDesc->pd_Flags & PD_VALID_DESIRED_ZONE) == PD_VALID_DESIRED_ZONE); RELEASE_SPIN_LOCK(&pPortDesc->pd_Lock, OldIrql); return RetCode; } /*** AtalkZipGetMyZone * */ ATALK_ERROR AtalkZipGetMyZone( IN PPORT_DESCRIPTOR pPortDesc, IN BOOLEAN fDesired, IN OUT PAMDL pAMdl, IN INT Size, IN PACTREQ pActReq ) { PZIPCOMPLETIONINFO pZci = NULL; ATALK_ERROR Status = ATALK_NO_ERROR; ULONG BytesCopied; PZONE pZone; KIRQL OldIrql; BOOLEAN Done = FALSE; ASSERT (VALID_ACTREQ(pActReq)); if (Size < (MAX_ZONE_LENGTH + 1)) return ATALK_BUFFER_TOO_SMALL; do { ACQUIRE_SPIN_LOCK(&pPortDesc->pd_Lock, &OldIrql); // For extended network, we either know or cannot find out if (EXT_NET(pPortDesc)) { BOOLEAN Yes = FALSE; if (fDesired && (pPortDesc->pd_Flags & PD_VALID_DESIRED_ZONE)) { pZone = pPortDesc->pd_DesiredZone; Yes = TRUE; } else if (!fDesired && (pPortDesc->pd_Flags & PD_VALID_DEFAULT_ZONE)) { pZone = pPortDesc->pd_DefaultZone; Yes = TRUE; } if (Yes) { TdiCopyBufferToMdl( pZone->zn_Zone, 0, pZone->zn_ZoneLen, pAMdl, 0, &BytesCopied); ASSERT (BytesCopied == pZone->zn_ZoneLen); TdiCopyBufferToMdl( "", 0, 1, pAMdl, pZone->zn_ZoneLen, &BytesCopied); ASSERT (BytesCopied == 1); Done = TRUE; } } // For non-extended networks, we need to ask a router. If we don't // know about a router, return. if (!Done && (EXT_NET(pPortDesc) || !(pPortDesc->pd_Flags & PD_SEEN_ROUTER_RECENTLY))) { TdiCopyBufferToMdl( "*", 0, sizeof("*"), pAMdl, 0, &BytesCopied); ASSERT (BytesCopied == sizeof("*")); Done = TRUE; } RELEASE_SPIN_LOCK(&pPortDesc->pd_Lock, OldIrql); if (Done) { (*pActReq->ar_Completion)(ATALK_NO_ERROR, pActReq); break; } ASSERT (!EXT_NET(pPortDesc)); // Allocate a Completion info structure if ((pZci = AtalkAllocMemory(sizeof(ZIPCOMPLETIONINFO))) == NULL) { Status = ATALK_RESR_MEM; break; } // Initialize completion info #if DBG pZci->zci_Signature = ZCI_SIGNATURE; #endif INITIALIZE_SPIN_LOCK(&pZci->zci_Lock); pZci->zci_RefCount = 1; pZci->zci_pPortDesc = pPortDesc; pZci->zci_pDdpAddr = NULL; pZci->zci_pAMdl = pAMdl; pZci->zci_BufLen = Size; pZci->zci_pActReq = pActReq; pZci->zci_Router.ata_Network = pPortDesc->pd_ARouter.atn_Network; pZci->zci_Router.ata_Node = pPortDesc->pd_ARouter.atn_Node; pZci->zci_Router.ata_Socket = ZONESINFORMATION_SOCKET; pZci->zci_ExpirationCount = ZIP_GET_ZONEINFO_RETRIES; pZci->zci_NextZoneOff = 0; pZci->zci_ZoneCount = -1; pZci->zci_AtpRequestType = ZIP_GET_MY_ZONE; pZci->zci_Handler = atalkZipGetMyZoneReply; AtalkTimerInitialize(&pZci->zci_Timer, atalkZipZoneInfoTimer, ZIP_GET_ZONEINFO_TIMER); Status = atalkZipSendPacket(pZci, TRUE); if (!ATALK_SUCCESS(Status)) { DBGPRINT(DBG_COMP_ZIP, DBG_LEVEL_INFO, ("AtalkZipGetMyZone: atalkZipSendPacket %ld\n", Status)); pZci->zci_FinalStatus = Status; atalkZipDereferenceZci(pZci); Status = ATALK_PENDING; // atalkZipDereferenceZci completes the req } } while (FALSE); return(Status); } /*** atalkZipGetMyZoneReply * */ VOID atalkZipGetMyZoneReply( 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 Status, IN BYTE DdpType, IN PZIPCOMPLETIONINFO pZci, IN BOOLEAN OptimizePath, IN PVOID OptimizeCtx ) { ULONG BytesCopied; KIRQL OldIrql; USHORT ZoneCnt; BYTE ZoneLen; do { if (Status == ATALK_SOCKET_CLOSED) { pZci->zci_pDdpAddr = NULL; if (AtalkTimerCancelEvent(&pZci->zci_Timer, NULL)) atalkZipDereferenceZci(pZci); pZci->zci_FinalStatus = Status; atalkZipDereferenceZci(pZci); break; } if ((Status != ATALK_NO_ERROR) || (DdpType != DDPPROTO_ATP) || (PktLen <= ATP_ZIP_FIRST_ZONE_OFF)) { AtalkLogBadPacket(pPortDesc, pSrcAddr, pDstAddr, pPkt, PktLen); break; } // We should have one zone GETSHORT2SHORT(&ZoneCnt, pPkt + ATP_ZIP_ZONE_CNT_OFF); ZoneLen = pPkt[ATP_ZIP_FIRST_ZONE_OFF]; if ((ZoneCnt != 1) || (ZoneLen == 0) || (ZoneLen > MAX_ZONE_LENGTH)) { DBGPRINT(DBG_COMP_ZIP, DBG_LEVEL_ERR, ("atalkZipGetMyZoneReply: Bad reply\n")); break; } if (AtalkTimerCancelEvent(&pZci->zci_Timer, NULL)) { atalkZipDereferenceZci(pZci); } ACQUIRE_SPIN_LOCK(&pZci->zci_Lock, &OldIrql); TdiCopyBufferToMdl( pPkt + ATP_ZIP_FIRST_ZONE_OFF + 1, 0, ZoneLen, pZci->zci_pAMdl, 0, &BytesCopied); ASSERT (BytesCopied == ZoneLen); TdiCopyBufferToMdl( "", 0, 1, pZci->zci_pAMdl, ZoneLen, &BytesCopied); ASSERT (BytesCopied == 1); pZci->zci_FinalStatus = ATALK_NO_ERROR; RELEASE_SPIN_LOCK(&pZci->zci_Lock, OldIrql); atalkZipDereferenceZci(pZci); } while (FALSE); } /*** AtalkZipGetZoneList * */ ATALK_ERROR AtalkZipGetZoneList( IN PPORT_DESCRIPTOR pPortDesc, IN BOOLEAN fLocalZones, IN OUT PAMDL pAMdl, IN INT Size, IN PACTREQ pActReq ) { PZIPCOMPLETIONINFO pZci = NULL; ATALK_ERROR Status = ATALK_NO_ERROR; ULONG BytesCopied, index, NumZones; KIRQL OldIrql; BOOLEAN Done = FALSE, PortLocked = TRUE; ASSERT (VALID_ACTREQ(pActReq)); if (Size < (MAX_ZONE_LENGTH + 1)) return ATALK_BUFFER_TOO_SMALL; ACQUIRE_SPIN_LOCK(&pPortDesc->pd_Lock, &OldIrql); do { // If we don't know about a router, return. if (!(pPortDesc->pd_Flags & PD_SEEN_ROUTER_RECENTLY)) { DBGPRINT(DBG_COMP_ZIP, DBG_LEVEL_WARN, ("AtalkZipGetZoneList: Don't know a router !!!\n")); TdiCopyBufferToMdl( "*", 0, sizeof("*"), pAMdl, 0, &BytesCopied); ASSERT (BytesCopied == sizeof("*")); Done = TRUE; } RELEASE_SPIN_LOCK(&pPortDesc->pd_Lock, OldIrql); PortLocked = FALSE; if (Done) { ((PZIP_GETZONELIST_PARAMS)(pActReq->ar_pParms))->ZonesAvailable = 1; (*pActReq->ar_Completion)(ATALK_NO_ERROR, pActReq); break; } // If we are a router, then simply copy the zones. Else send a // a request to the router. DO NOT SEND A REQUEST IF WE ARE A // ROUTER SINCE THAT WILL RESULT IN A HORRIBLE RECURSION RESULTING // IN A DOUBLE FAULT (OUT OF STACK SPACE). if (pPortDesc->pd_Flags & PD_ROUTER_RUNNING) { PZONE pZone; NumZones = 0; if (fLocalZones) { PZONE_LIST pZoneList; // For GetLocalZones, we only want to count zones // that are on the network that is directly connected // to the port on which the request originated ACQUIRE_SPIN_LOCK(&pPortDesc->pd_Lock, &OldIrql); for (index = 0, pZoneList = pPortDesc->pd_ZoneList; pZoneList != NULL; pZoneList = pZoneList->zl_Next) { pZone = pZoneList->zl_pZone; ASSERT (pZone != NULL); // If this packet cannot hold more, we're done if ((INT)(index + pZone->zn_ZoneLen + 1) >= Size) { break; } // Place zone name in the packet TdiCopyBufferToMdl( pZone->zn_Zone, 0, pZone->zn_ZoneLen + 1, pAMdl, index, &BytesCopied); ASSERT (BytesCopied == (ULONG)(pZone->zn_ZoneLen + 1)); NumZones ++; index += (pZone->zn_ZoneLen + 1); } RELEASE_SPIN_LOCK(&pPortDesc->pd_Lock, OldIrql); Status = (pZoneList != NULL) ? ATALK_BUFFER_TOO_SMALL : ATALK_NO_ERROR; } else { BOOLEAN PktFull = FALSE; INT i; ACQUIRE_SPIN_LOCK(&AtalkZoneLock, &OldIrql); for (i = 0, index = 0, PktFull = FALSE; (i < NUM_ZONES_HASH_BUCKETS) && !PktFull; i++) { for (pZone = AtalkZonesTable[i]; pZone != NULL; pZone = pZone->zn_Next) { // If this packet cannot hold more, we're done if ((INT)(index + pZone->zn_ZoneLen + 1) >= Size) { PktFull = TRUE; break; } // Place zone name in the packet TdiCopyBufferToMdl( pZone->zn_Zone, 0, pZone->zn_ZoneLen + 1, pAMdl, index, &BytesCopied); ASSERT (BytesCopied == (ULONG)(pZone->zn_ZoneLen + 1)); NumZones ++; index += (pZone->zn_ZoneLen + 1); } } RELEASE_SPIN_LOCK(&AtalkZoneLock, OldIrql); Status = ((pZone != NULL) || ( i < NUM_ZONES_HASH_BUCKETS)) ? ATALK_BUFFER_TOO_SMALL : ATALK_NO_ERROR; } ((PZIP_GETZONELIST_PARAMS) (pActReq->ar_pParms))->ZonesAvailable = NumZones; if (ATALK_SUCCESS(Status)) { (*pActReq->ar_Completion)(Status, pActReq); } break; } ASSERT ((pPortDesc->pd_Flags & PD_ROUTER_RUNNING) == 0); // Allocate a Completion info structure if ((pZci = AtalkAllocMemory(sizeof(ZIPCOMPLETIONINFO))) == NULL) { Status = ATALK_RESR_MEM; break; } // Initialize completion info #if DBG pZci->zci_Signature = ZCI_SIGNATURE; #endif INITIALIZE_SPIN_LOCK(&pZci->zci_Lock); pZci->zci_RefCount = 1; pZci->zci_pPortDesc = pPortDesc; pZci->zci_pDdpAddr = NULL; pZci->zci_pAMdl = pAMdl; pZci->zci_BufLen = Size; pZci->zci_pActReq = pActReq; pZci->zci_Router.ata_Network = pPortDesc->pd_ARouter.atn_Network; pZci->zci_Router.ata_Node = pPortDesc->pd_ARouter.atn_Node; pZci->zci_Router.ata_Socket = ZONESINFORMATION_SOCKET; pZci->zci_ExpirationCount = ZIP_GET_ZONEINFO_RETRIES; pZci->zci_NextZoneOff = 0; pZci->zci_ZoneCount = 0; pZci->zci_AtpRequestType = ZIP_GET_ZONE_LIST; AtalkTimerInitialize(&pZci->zci_Timer, atalkZipZoneInfoTimer, ZIP_GET_ZONEINFO_TIMER); if (fLocalZones) pZci->zci_AtpRequestType = ZIP_GET_LOCAL_ZONES; pZci->zci_Handler = atalkZipGetZoneListReply; Status = atalkZipSendPacket(pZci, TRUE); if (!ATALK_SUCCESS(Status)) { DBGPRINT(DBG_COMP_ZIP, DBG_LEVEL_ERR, ("AtalkZipGetZoneList: atalkZipSendPacket %ld\n", Status)); pZci->zci_FinalStatus = Status; atalkZipDereferenceZci(pZci); Status = ATALK_PENDING; // atalkZipDereferenceZci completes the req } } while (FALSE); if (PortLocked) RELEASE_SPIN_LOCK(&pPortDesc->pd_Lock, OldIrql); return(Status); } /*** atalkZipGetZoneListReply * */ VOID atalkZipGetZoneListReply( 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 Status, IN BYTE DdpType, IN PZIPCOMPLETIONINFO pZci, IN BOOLEAN OptimizePath, IN PVOID OptimizeCtx ) { PBYTE pZone; ULONG dindex; ULONG BytesCopied; USHORT ZoneCnt; BYTE ZoneLen; BOOLEAN LastFlag, Overflow = FALSE; ASSERT(VALID_ZCI(pZci)); do { if (Status == ATALK_SOCKET_CLOSED) { pZci->zci_pDdpAddr = NULL; if (AtalkTimerCancelEvent(&pZci->zci_Timer, NULL)) { atalkZipDereferenceZci(pZci); } pZci->zci_FinalStatus = Status; atalkZipDereferenceZci(pZci); break; } if ((Status != ATALK_NO_ERROR) || (DdpType != DDPPROTO_ATP) || (PktLen <= ATP_ZIP_FIRST_ZONE_OFF)) { AtalkLogBadPacket(pPortDesc, pSrcAddr, pDstAddr, pPkt, PktLen); break; } // We should have a zone list. // Cancel the timer. Start it again if we have not got all the zones if (AtalkTimerCancelEvent(&pZci->zci_Timer, NULL)) { atalkZipDereferenceZci(pZci); } DBGPRINT(DBG_COMP_ZIP, DBG_LEVEL_INFO, ("atalkZipGetZoneListReply: More zones. Index %d, SizeLeft %d\n", pZci->zci_ZoneCount, pZci->zci_BufLen - pZci->zci_NextZoneOff)); ACQUIRE_SPIN_LOCK_DPC(&pZci->zci_Lock); GETSHORT2SHORT(&ZoneCnt, pPkt + ATP_ZIP_ZONE_CNT_OFF); LastFlag = FALSE; if ((pPkt[ATP_ZIP_LAST_FLAG_OFF] != 0) || (ZoneCnt == 0)) LastFlag = TRUE; dindex = ATP_ZIP_FIRST_ZONE_OFF; while (ZoneCnt != 0) { // Pull out the next zone ZoneLen = pPkt[dindex++]; if ((ZoneLen == 0) || (ZoneLen > MAX_ZONE_LENGTH) || (PktLen < (dindex + ZoneLen))) { DBGPRINT(DBG_COMP_ZIP, DBG_LEVEL_ERR, ("atalkZipGetZoneListReply: Bad Zip reply\n")); break; } pZone = pPkt + dindex; dindex += ZoneLen; if ((pZci->zci_NextZoneOff + ZoneLen + 1) > pZci->zci_BufLen) { DBGPRINT(DBG_COMP_ZIP, DBG_LEVEL_INFO, ("AtalkZipGetZoneList: Overflow\n")); Overflow = TRUE; break; } DBGPRINT(DBG_COMP_ZIP, DBG_LEVEL_INFO, ("AtalkZipGetZoneList: Copying a zone (%d, %d)\n", pZci->zci_ZoneCount, pZci->zci_BufLen - pZci->zci_NextZoneOff)); TdiCopyBufferToMdl( pZone, 0, ZoneLen, pZci->zci_pAMdl, pZci->zci_NextZoneOff, &BytesCopied); ASSERT (BytesCopied == ZoneLen); TdiCopyBufferToMdl( "", 0, 1, pZci->zci_pAMdl, pZci->zci_NextZoneOff + ZoneLen, &BytesCopied); pZci->zci_NextZoneOff += (ZoneLen + 1); pZci->zci_ZoneCount ++; ZoneCnt --; } RELEASE_SPIN_LOCK_DPC(&pZci->zci_Lock); if (Overflow || LastFlag) { DBGPRINT(DBG_COMP_ZIP, DBG_LEVEL_INFO, ("atalkZipGetZoneListReply: All that we wanted\n")); pZci->zci_FinalStatus = ATALK_NO_ERROR; if (Overflow) pZci->zci_FinalStatus = ATALK_BUFFER_TOO_SMALL; ((PZIP_GETZONELIST_PARAMS) (pZci->zci_pActReq->ar_pParms))->ZonesAvailable = pZci->zci_ZoneCount; atalkZipDereferenceZci(pZci); } else { DBGPRINT(DBG_COMP_ZIP, DBG_LEVEL_INFO, ("atalkZipGetZoneListReply: Sending another packet\n")); Status = atalkZipSendPacket(pZci, TRUE); if (!ATALK_SUCCESS(Status)) { DBGPRINT(DBG_COMP_ZIP, DBG_LEVEL_ERR, ("AtalkZipGetZoneListReply: atalkZipSendPacket %ld\n", Status)); pZci->zci_FinalStatus = Status; atalkZipDereferenceZci(pZci); } } } while (FALSE); } /*** atalkZipZoneInfoTimer * */ LOCAL LONG FASTCALL atalkZipZoneInfoTimer( IN PTIMERLIST pTimer, IN BOOLEAN TimerShuttingDown ) { PZIPCOMPLETIONINFO pZci; ATALK_ERROR Status; ULONG BytesCopied; BOOLEAN Done = FALSE, RestartTimer = FALSE; pZci = (PZIPCOMPLETIONINFO)CONTAINING_RECORD(pTimer, ZIPCOMPLETIONINFO, zci_Timer); DBGPRINT(DBG_COMP_ZIP, DBG_LEVEL_INFO, ("atalkZipZoneInfoTimer: Entered for pZci = %lx\n", pZci)); ASSERT(VALID_ZCI(pZci)); do { ACQUIRE_SPIN_LOCK_DPC(&pZci->zci_Lock); if (--(pZci->zci_ExpirationCount) != 0) { RestartTimer = TRUE; DBGPRINT(DBG_COMP_ZIP, DBG_LEVEL_INFO, ("atalkZipZoneInfoTimer: Sending another packet\n", pZci)); RELEASE_SPIN_LOCK_DPC(&pZci->zci_Lock); Status = atalkZipSendPacket(pZci, FALSE); if (!ATALK_SUCCESS(Status)) { RestartTimer = FALSE; DBGPRINT(DBG_COMP_ZIP, DBG_LEVEL_INFO, ("atalkZipZoneInfoTimer: atalkZipSendPacket %ld\n", Status)); pZci->zci_FinalStatus = Status; atalkZipDereferenceZci(pZci); } break; } if (pZci->zci_AtpRequestType == ZIP_GET_MY_ZONE) { DBGPRINT(DBG_COMP_ZIP, DBG_LEVEL_INFO, ("atalkZipZoneInfoTimer: Completing GetMyZone\n")); TdiCopyBufferToMdl("*", 0, sizeof("*"), pZci->zci_pAMdl, 0, &BytesCopied); } else // GET_ZONE_LIST { DBGPRINT(DBG_COMP_ZIP, DBG_LEVEL_INFO, ("atalkZipZoneInfoTimer: Completing GetZoneList\n")); if ((pZci->zci_ZoneCount == 0) && ((SHORT)(pZci->zci_NextZoneOff + sizeof("*")) < pZci->zci_BufLen)) { pZci->zci_ZoneCount++; TdiCopyBufferToMdl("*", 0, sizeof("*"), pZci->zci_pAMdl, pZci->zci_NextZoneOff, &BytesCopied); ASSERT (BytesCopied == sizeof("*")); } ((PZIP_GETZONELIST_PARAMS) (pZci->zci_pActReq->ar_pParms))->ZonesAvailable = pZci->zci_ZoneCount; } RELEASE_SPIN_LOCK_DPC(&pZci->zci_Lock); atalkZipDereferenceZci(pZci); // Timer reference pZci->zci_FinalStatus = ATALK_NO_ERROR; atalkZipDereferenceZci(pZci); ASSERT(!RestartTimer); } while (FALSE); return (RestartTimer ? ATALK_TIMER_REQUEUE : ATALK_TIMER_NO_REQUEUE); } /*** atalkZipSendPacket * */ ATALK_ERROR atalkZipSendPacket( IN PZIPCOMPLETIONINFO pZci, IN BOOLEAN EnqueueTimer ) { PBUFFER_DESC pBuffDesc; ATALK_ERROR Status; ATALK_ADDR DestAddr; PBYTE Datagram; SEND_COMPL_INFO SendInfo; ASSERT (VALID_ZCI(pZci)); if (pZci->zci_pDdpAddr == NULL) { DBGPRINT(DBG_COMP_ZIP, DBG_LEVEL_INFO, ("atalkZipSendPacket: Opening Ddp Socket\n")); // Open a socket for handling replies Status = AtalkDdpOpenAddress(pZci->zci_pPortDesc, UNKNOWN_SOCKET, NULL, pZci->zci_Handler, pZci, 0, NULL, &pZci->zci_pDdpAddr); if (!ATALK_SUCCESS(Status)) { DBGPRINT(DBG_COMP_ZIP, DBG_LEVEL_ERR, ("atalkZipSendPacket: AtalkDdpOpenAddress %ld\n", Status)); return Status; } // mark the fact that this is an "internal" socket pZci->zci_pDdpAddr->ddpao_Flags |= DDPAO_SOCK_INTERNAL; } ASSERT (VALID_DDP_ADDROBJ(pZci->zci_pDdpAddr)); // Alloc a buffer desciptor for the atp request if ((pBuffDesc = AtalkAllocBuffDesc(pZci->zci_Datagram, ZIP_GETZONELIST_DDPSIZE, BD_CHAR_BUFFER)) == NULL) { DBGPRINT(DBG_COMP_ZIP, DBG_LEVEL_ERR, ("atalkZipSendPacket: Couldn't allocate a buffdesc\n")); AtalkDdpCloseAddress(pZci->zci_pDdpAddr, NULL, NULL); return ATALK_RESR_MEM; } // Start the zone info timer if (EnqueueTimer) { KIRQL OldIrql; ACQUIRE_SPIN_LOCK(&pZci->zci_Lock, &OldIrql); pZci->zci_RefCount ++; // For the timer AtalkTimerScheduleEvent(&pZci->zci_Timer); RELEASE_SPIN_LOCK(&pZci->zci_Lock, OldIrql); } // Build the Atp request and send it along Datagram = pBuffDesc->bd_CharBuffer; Datagram[ATP_CMD_CONTROL_OFF] = ATP_REQUEST; Datagram[ATP_BITMAP_OFF] = 1; Datagram[ATP_TRANS_ID_OFF] = 0; Datagram[ATP_TRANS_ID_OFF+1] = 0; Datagram[ATP_ZIP_CMD_OFF] = (BYTE)pZci->zci_AtpRequestType; Datagram[ATP_ZIP_CMD_OFF+1] = 0; PUTSHORT2SHORT(Datagram + ATP_ZIP_START_INDEX_OFF, pZci->zci_ZoneCount+1); // Set the length in the buffer descriptor. AtalkSetSizeOfBuffDescData(pBuffDesc, ZIP_GETZONELIST_DDPSIZE); DBGPRINT(DBG_COMP_ZIP, DBG_LEVEL_INFO, ("atalkZipSendPacket: Sending the packet along\n")); DestAddr = pZci->zci_Router; SendInfo.sc_TransmitCompletion = atalkZipSendComplete; SendInfo.sc_Ctx1 = pBuffDesc; // SendInfo.sc_Ctx2 = NULL; // SendInfo.sc_Ctx3 = NULL; if (!ATALK_SUCCESS(Status = AtalkDdpSend(pZci->zci_pDdpAddr, &DestAddr, DDPPROTO_ATP, FALSE, pBuffDesc, NULL, 0, NULL, &SendInfo))) { DBGPRINT(DBG_COMP_ZIP, DBG_LEVEL_ERR, ("atalkZipSendPacket: AtalkDdpSend %ld\n", Status)); AtalkFreeBuffDesc(pBuffDesc); if (AtalkTimerCancelEvent(&pZci->zci_Timer, NULL)) { atalkZipDereferenceZci(pZci); } } else Status = ATALK_PENDING; return Status; } /*** atalkZipDereferenceZci * */ LOCAL VOID atalkZipDereferenceZci( IN PZIPCOMPLETIONINFO pZci ) { BOOLEAN Done; KIRQL OldIrql; ASSERT(VALID_ZCI(pZci)); ACQUIRE_SPIN_LOCK(&pZci->zci_Lock, &OldIrql); Done = (--(pZci->zci_RefCount) == 0); RELEASE_SPIN_LOCK(&pZci->zci_Lock, OldIrql); if (Done) { if (pZci->zci_pDdpAddr != NULL) AtalkDdpCloseAddress(pZci->zci_pDdpAddr, NULL, NULL); (*pZci->zci_pActReq->ar_Completion)(pZci->zci_FinalStatus, pZci->zci_pActReq); // Unlock the Zip stuff back again, if there are no more pending zip operations AtalkUnlockZipIfNecessary(); AtalkFreeMemory(pZci); } } // We do not want to send too many queries per invocation of the timer. This is to avoid // spending too much time within the timer Dpc and also using up all of the Ndis packets // and buffers during this. #define MAX_QUERIES_PER_INVOCATION 75 // Structure used by the atalkZipQueryTimer routine typedef struct _QueryTimerData { struct _QueryTimerData * qtd_Next; BOOLEAN qtd_SkipThis; PBUFFER_DESC qtd_pBuffDesc; ATALK_ADDR qtd_DstAddr; PDDP_ADDROBJ qtd_pDdpAddr; } QTD, *PQTD; /*** atalkZipQueryTimer * * When we are a router and if any of our RTEs do not have a valid zone list, we send * out queries to other routers who do. */ LOCAL LONG FASTCALL atalkZipQueryTimer( IN PTIMERLIST pContext, IN BOOLEAN TimerShuttingDown ) { PPORT_DESCRIPTOR pPortDesc; ATALK_ADDR SrcAddr; PRTE pRte; PBYTE Datagram; PQTD pQtd, pQtdStart = NULL, *ppQtd = &pQtdStart; ATALK_ERROR Status; int i, j; SEND_COMPL_INFO SendInfo; if (TimerShuttingDown) return ATALK_TIMER_NO_REQUEUE; // Go through the routing tables and send out a query to any network // that we do not know the zone name of ACQUIRE_SPIN_LOCK_DPC(&AtalkRteLock) for (i = 0, j = 0; (i < NUM_RTMP_HASH_BUCKETS) && (j <= MAX_QUERIES_PER_INVOCATION); i++) { for (pRte = AtalkRoutingTable[i]; pRte != NULL; pRte = pRte->rte_Next) { if (pRte->rte_Flags & RTE_ZONELIST_VALID) { continue; } // If login is to restrict access to zones over dial up connection // put restrictions here if (pRte->rte_PortDesc == RasPortDesc) { continue; } // Up the count of # of datagrams used. Do need exceed max. if (++j >= MAX_QUERIES_PER_INVOCATION) break; if (((pQtd = AtalkAllocMemory(sizeof(QTD))) == NULL) || ((pQtd->qtd_pBuffDesc = AtalkAllocBuffDesc(NULL, ZIP_ONEZONEQUERY_DDPSIZE, BD_CHAR_BUFFER | BD_FREE_BUFFER)) == NULL)) { if (pQtd != NULL) AtalkFreeMemory(pQtd); break; } *ppQtd = pQtd; pQtd->qtd_Next = NULL; ppQtd = &pQtd->qtd_Next; pQtd->qtd_SkipThis = FALSE; Datagram = pQtd->qtd_pBuffDesc->bd_CharBuffer; // Build the datagram and send it on its way Datagram[ZIP_CMD_OFF] = ZIP_QUERY; Datagram[ZIP_NW_CNT_OFF] = 1; PUTSHORT2SHORT(Datagram+ZIP_FIRST_NET_OFF, pRte->rte_NwRange.anr_FirstNetwork); // Compute the source and destination SrcAddr.ata_Network = pRte->rte_PortDesc->pd_ARouter.atn_Network; SrcAddr.ata_Node = pRte->rte_PortDesc->pd_ARouter.atn_Node; SrcAddr.ata_Socket = ZONESINFORMATION_SOCKET; pQtd->qtd_DstAddr.ata_Socket = ZONESINFORMATION_SOCKET; if (pRte->rte_NumHops == 0) { pQtd->qtd_DstAddr = SrcAddr; } else { pQtd->qtd_DstAddr.ata_Network = pRte->rte_NextRouter.atn_Network; pQtd->qtd_DstAddr.ata_Node = pRte->rte_NextRouter.atn_Node; } // Map source address to the ddp address object (open socket) AtalkDdpReferenceByAddr(pRte->rte_PortDesc, &SrcAddr, &pQtd->qtd_pDdpAddr, &Status); if (!ATALK_SUCCESS(Status)) { DBGPRINT(DBG_COMP_ZIP, DBG_LEVEL_ERR, ("atalkZipQueryTimer: DdpRefByAddr failed for %d.%d\n", SrcAddr.ata_Network, SrcAddr.ata_Node)); pQtd->qtd_pDdpAddr = NULL; pQtd->qtd_SkipThis = TRUE; } } } RELEASE_SPIN_LOCK_DPC(&AtalkRteLock); // We have a bunch of datagrams ready to be fired off. // Make it so. SendInfo.sc_TransmitCompletion = atalkZipSendComplete; // SendInfo.sc_Ctx2 = NULL; // SendInfo.sc_Ctx3 = NULL; for (pQtd = pQtdStart; pQtd != NULL; pQtd = pQtdStart) { pQtdStart = pQtd->qtd_Next; // Set the length in the buffer descriptor. AtalkSetSizeOfBuffDescData(pQtd->qtd_pBuffDesc, ZIP_ONEZONEQUERY_DDPSIZE); SendInfo.sc_Ctx1 = pQtd->qtd_pBuffDesc; if (pQtd->qtd_SkipThis || !ATALK_SUCCESS(AtalkDdpSend(pQtd->qtd_pDdpAddr, &pQtd->qtd_DstAddr, DDPPROTO_ZIP, FALSE, pQtd->qtd_pBuffDesc, NULL, 0, NULL, &SendInfo))) { AtalkFreeBuffDesc(pQtd->qtd_pBuffDesc); } if (pQtd->qtd_pDdpAddr != NULL) AtalkDdpDereferenceDpc(pQtd->qtd_pDdpAddr); AtalkFreeMemory(pQtd); } return ATALK_TIMER_REQUEUE; } /*** atalkZipGetZoneListForPort * */ LOCAL BOOLEAN atalkZipGetZoneListForPort( IN PPORT_DESCRIPTOR pPortDesc ) { PRTE pRte; PBUFFER_DESC pBuffDesc = NULL; ATALK_ADDR SrcAddr, DstAddr; ATALK_ERROR Status; KIRQL OldIrql; int NumReqs = 0; BOOLEAN RetCode = FALSE; BYTE MulticastAddr[ELAP_ADDR_LEN]; SEND_COMPL_INFO SendInfo; ASSERT (KeGetCurrentIrql() == LOW_LEVEL); // Similar to RTMP finding out the network number attached to port, our // task is to find out the zone list of the network attached to a // particular port. We too don't want to mess up a working AppleTalk // internet. So, spend a little while doing zone queries to see if the // network already has a zone list -- if we find one, use it; else, we // had better be a seed router. // Set source and destination address SrcAddr.ata_Node = pPortDesc->pd_ARouter.atn_Node; SrcAddr.ata_Network = pPortDesc->pd_ARouter.atn_Network; SrcAddr.ata_Socket = ZONESINFORMATION_SOCKET; DstAddr.ata_Network = CABLEWIDE_BROADCAST_NETWORK; DstAddr.ata_Node = ATALK_BROADCAST_NODE; DstAddr.ata_Socket = ZONESINFORMATION_SOCKET; if ((pRte = AtalkRtmpReferenceRte(pPortDesc->pd_NetworkRange.anr_FirstNetwork)) == NULL) { DBGPRINT(DBG_COMP_ZIP, DBG_LEVEL_ERR, ("atalkZipGetZoneListForPort: Could not reference Rte for nwrange on port\n")); return FALSE; } // Blast a few queries and see if anybody knows our zone-name ACQUIRE_SPIN_LOCK(&pPortDesc->pd_Lock, &OldIrql); pPortDesc->pd_Flags |= PD_FINDING_DEFAULT_ZONE; RELEASE_SPIN_LOCK(&pPortDesc->pd_Lock, OldIrql); SendInfo.sc_TransmitCompletion = atalkZipSendComplete; // SendInfo.sc_Ctx2 = NULL; // SendInfo.sc_Ctx3 = NULL; while ((NumReqs < (ZIP_NUM_QUERIES * ZIP_NUM_RETRIES)) && !(pRte->rte_Flags & RTE_ZONELIST_VALID)) { if ((NumReqs % ZIP_NUM_RETRIES) == 0) { if ((pBuffDesc = AtalkAllocBuffDesc(NULL, ZIP_ONEZONEQUERY_DDPSIZE, BD_CHAR_BUFFER | BD_FREE_BUFFER)) == NULL) { break; } pBuffDesc->bd_CharBuffer[ZIP_CMD_OFF] = ZIP_QUERY; pBuffDesc->bd_CharBuffer[ZIP_NW_CNT_OFF] = 1; PUTSHORT2SHORT(pBuffDesc->bd_CharBuffer + ZIP_FIRST_NET_OFF, pPortDesc->pd_NetworkRange.anr_FirstNetwork); // Set the length in the buffer descriptor. AtalkSetSizeOfBuffDescData(pBuffDesc, ZIP_ONEZONEQUERY_DDPSIZE); SendInfo.sc_Ctx1 = pBuffDesc; Status = AtalkDdpTransmit(pPortDesc, &SrcAddr, &DstAddr, DDPPROTO_ZIP, pBuffDesc, NULL, 0, 0, NULL, NULL, &SendInfo); if (!ATALK_SUCCESS(Status)) { DBGPRINT(DBG_COMP_ZIP, DBG_LEVEL_ERR, ("atalkZipGetZoneListForPort: AtalkDdpTransmit %ld\n", Status)); break; } pBuffDesc = NULL; } NumReqs++; AtalkSleep(ZIP_QUERY_WAIT); } // We either got an answer or we did not. In the latter case we should // be seeding. do { if (pRte->rte_Flags & RTE_ZONELIST_VALID) { // We got an answer. The valid zone list is in the routing table // Move it to the port descriptor ACQUIRE_SPIN_LOCK(&pPortDesc->pd_Lock, &OldIrql); ACQUIRE_SPIN_LOCK_DPC(&pRte->rte_Lock); DBGPRINT(DBG_COMP_ZIP, DBG_LEVEL_INFO, ("atalkZipGetZoneListForPort: Moving ZoneList from Rte to Port %Z\n", &pPortDesc->pd_AdapterKey)); pPortDesc->pd_ZoneList = AtalkZoneCopyList(pRte->rte_ZoneList); RELEASE_SPIN_LOCK_DPC(&pRte->rte_Lock); RELEASE_SPIN_LOCK(&pPortDesc->pd_Lock, OldIrql); if (pPortDesc->pd_ZoneList == NULL) { DBGPRINT(DBG_COMP_ZIP, DBG_LEVEL_INFO, ("atalkZipGetZoneListForPort: Failed to Move ZoneList from Rte to Port\n")); break; } // If this is an extended network, we should already have "ThisZone" // set (due to GetNetInfo's when we allocated this node), if not // find out the true default zone if (EXT_NET(pPortDesc)) { PDDP_ADDROBJ pDdpAddr = NULL; ATALK_ADDR Addr; ATALK_ERROR Status; // The router's Zip packet handler doesn't want to be told // about zones (it thinks it knows), so it ignores // NetInfoReplies. Switch back to the non-router Zip handler // while we do a GetNetworkInfoForNode Addr.ata_Node = pPortDesc->pd_ARouter.atn_Node; Addr.ata_Network = pPortDesc->pd_ARouter.atn_Network; Addr.ata_Socket = ZONESINFORMATION_SOCKET; AtalkDdpReferenceByAddr(pPortDesc, &Addr, &pDdpAddr, &Status); if (!ATALK_SUCCESS(Status)) { DBGPRINT(DBG_COMP_RTMP, DBG_LEVEL_ERR, ("atalkZipGetZoneListForPort: AtalkDdpRefByAddr %ld for %d.%d\n", Status, Addr.ata_Network, Addr.ata_Node)); break; } AtalkDdpNewHandlerForSocket(pDdpAddr, AtalkZipPacketIn, pPortDesc); if ((!(pPortDesc->pd_Flags & PD_VALID_DESIRED_ZONE) && !AtalkZipGetNetworkInfoForNode(pPortDesc, &pPortDesc->pd_ARouter, FALSE)) || !AtalkZipGetNetworkInfoForNode(pPortDesc, &pPortDesc->pd_ARouter, TRUE)) { AtalkDdpDereference(pDdpAddr); break; } // Switch back the handler to the router's version AtalkDdpNewHandlerForSocket(pDdpAddr, AtalkZipPacketInRouter, pPortDesc); AtalkDdpDereference(pDdpAddr); // The default zone had better be on the list we just // received ACQUIRE_SPIN_LOCK(&pPortDesc->pd_Lock, &OldIrql); if (!AtalkZoneOnList(pPortDesc->pd_DefaultZone, pPortDesc->pd_ZoneList) || !AtalkZoneOnList(pPortDesc->pd_DesiredZone, pPortDesc->pd_ZoneList)) { DBGPRINT(DBG_COMP_ZIP, DBG_LEVEL_ERR, ("atalkZipGetZoneListForPort: Ext port, Default/Desired zone not on list\n")); } else RetCode = TRUE; RELEASE_SPIN_LOCK(&pPortDesc->pd_Lock, OldIrql); } else { // On non-extended network, the one entry on the zone list // should also be "ThisZone" ACQUIRE_SPIN_LOCK(&pPortDesc->pd_Lock, &OldIrql); if (pPortDesc->pd_DesiredZone != NULL) AtalkZoneDereference(pPortDesc->pd_DesiredZone); AtalkZoneReferenceByPtr(pPortDesc->pd_DesiredZone = pPortDesc->pd_ZoneList->zl_pZone); RELEASE_SPIN_LOCK(&pPortDesc->pd_Lock, OldIrql); RetCode = TRUE; } break; } // We did not get an answer. We had better be able to seed. There is // a chance that we got "ThisZone" set when allocating our node and // whatever router told us that went down before we could ask for the // zone list - so de-allocate the multicast address, if any first if ((pPortDesc->pd_Flags & (PD_EXT_NET | PD_VALID_DESIRED_ZONE)) == (PD_EXT_NET | PD_VALID_DESIRED_ZONE)) { if (!AtalkFixedCompareCaseSensitive(pPortDesc->pd_ZoneMulticastAddr, pPortDesc->pd_BroadcastAddrLen, pPortDesc->pd_BroadcastAddr, pPortDesc->pd_BroadcastAddrLen)) (*pPortDesc->pd_RemoveMulticastAddr)(pPortDesc, pPortDesc->pd_ZoneMulticastAddr, FALSE, NULL, NULL); } // Now we better know enough to seed if (pPortDesc->pd_InitialZoneList == NULL) { DBGPRINT(DBG_COMP_ZIP, DBG_LEVEL_ERR, ("atalkZipGetZoneListForPort: %sExt port, NULL InitialZoneList\n", EXT_NET(pPortDesc) ? "" : "Non")); break; } ACQUIRE_SPIN_LOCK(&pPortDesc->pd_Lock, &OldIrql); DBGPRINT(DBG_COMP_ZIP, DBG_LEVEL_INFO, ("atalkZipGetZoneListForPort: Moving Initial ZoneList to Current on port %Z\n", &pPortDesc->pd_AdapterKey)); pPortDesc->pd_ZoneList = AtalkZoneCopyList(pPortDesc->pd_InitialZoneList); if (EXT_NET(pPortDesc)) { // We need to seed the default zone too AtalkZoneReferenceByPtr(pPortDesc->pd_DefaultZone = pPortDesc->pd_InitialDefaultZone); pPortDesc->pd_Flags |= PD_VALID_DEFAULT_ZONE; if (pPortDesc->pd_InitialDesiredZone != NULL) { AtalkZoneReferenceByPtr(pPortDesc->pd_DesiredZone = pPortDesc->pd_InitialDesiredZone); } else { AtalkZoneReferenceByPtr(pPortDesc->pd_DesiredZone = pPortDesc->pd_InitialDefaultZone); } // Finally set the zone multicast address AtalkZipMulticastAddrForZone(pPortDesc, pPortDesc->pd_DesiredZone->zn_Zone, pPortDesc->pd_DesiredZone->zn_ZoneLen, MulticastAddr); if (!AtalkFixedCompareCaseSensitive(MulticastAddr, pPortDesc->pd_BroadcastAddrLen, pPortDesc->pd_BroadcastAddr, pPortDesc->pd_BroadcastAddrLen)) { RELEASE_SPIN_LOCK(&pPortDesc->pd_Lock, OldIrql); (*pPortDesc->pd_AddMulticastAddr)(pPortDesc, MulticastAddr, FALSE, NULL, NULL); ACQUIRE_SPIN_LOCK(&pPortDesc->pd_Lock, &OldIrql); } RtlCopyMemory(pPortDesc->pd_ZoneMulticastAddr, MulticastAddr, pPortDesc->pd_BroadcastAddrLen); } else { // On non-extended networks, this (desired/default)should be the // only one on zone-list AtalkZoneReferenceByPtr(pPortDesc->pd_DesiredZone = pPortDesc->pd_ZoneList->zl_pZone); } pPortDesc->pd_Flags |= PD_VALID_DESIRED_ZONE; RELEASE_SPIN_LOCK(&pPortDesc->pd_Lock, OldIrql); RetCode = TRUE; } while (FALSE); AtalkRtmpDereferenceRte(pRte, FALSE); if (pBuffDesc != NULL) { AtalkFreeBuffDesc(pBuffDesc); } return(RetCode); } /*** AtalkZipZoneReferenceByName * */ PZONE AtalkZoneReferenceByName( IN PBYTE ZoneName, IN BYTE ZoneLen ) { PZONE pZone; BYTE Len; KIRQL OldIrql; ULONG i, Hash; for (i = 0, Hash = 0, Len = ZoneLen; Len > 0; Len --, i++) { Hash <<= 1; Hash += AtalkUpCaseTable[ZoneName[i]]; } Hash %= NUM_ZONES_HASH_BUCKETS; ACQUIRE_SPIN_LOCK(&AtalkZoneLock, &OldIrql); for (pZone = AtalkZonesTable[Hash]; pZone != NULL; pZone = pZone->zn_Next) { if (AtalkFixedCompareCaseInsensitive(ZoneName, ZoneLen, pZone->zn_Zone, pZone->zn_ZoneLen)) { pZone->zn_RefCount ++; break; } } if (pZone == NULL) { if ((pZone = (PZONE)AtalkAllocMemory(sizeof(ZONE) + ZoneLen)) != NULL) { pZone->zn_RefCount = 1; pZone->zn_ZoneLen = ZoneLen; RtlCopyMemory(pZone->zn_Zone, ZoneName, ZoneLen); pZone->zn_Zone[ZoneLen] = 0; AtalkLinkDoubleAtHead(AtalkZonesTable[Hash], pZone, zn_Next, zn_Prev); } } RELEASE_SPIN_LOCK(&AtalkZoneLock, OldIrql); return(pZone); } /*** AtalkZipZoneReferenceByPtr * */ VOID AtalkZoneReferenceByPtr( IN PZONE pZone ) { KIRQL OldIrql; ACQUIRE_SPIN_LOCK(&AtalkZoneLock, &OldIrql); pZone->zn_RefCount++; RELEASE_SPIN_LOCK(&AtalkZoneLock, OldIrql); } /*** AtalkZoneDereference * */ VOID AtalkZoneDereference( IN PZONE pZone ) { KIRQL OldIrql; ACQUIRE_SPIN_LOCK(&AtalkZoneLock, &OldIrql); if (--pZone->zn_RefCount == 0) { AtalkUnlinkDouble(pZone, zn_Next, zn_Prev); AtalkFreeMemory(pZone); } RELEASE_SPIN_LOCK(&AtalkZoneLock, OldIrql); } /*** AtalkZipZoneFreeList * */ VOID AtalkZoneFreeList( IN PZONE_LIST pZoneList ) { PZONE_LIST pNextZone; for (; pZoneList != NULL; pZoneList = pNextZone) { pNextZone = pZoneList->zl_Next; AtalkZoneDereference(pZoneList->zl_pZone); AtalkFreeMemory(pZoneList); } } /*** AtalkZoneNameOnList * */ BOOLEAN AtalkZoneNameOnList( IN PBYTE ZoneName, IN BYTE ZoneLen, IN PZONE_LIST pZoneList ) { for ( ; pZoneList != NULL; pZoneList = pZoneList->zl_Next) if (AtalkFixedCompareCaseInsensitive(pZoneList->zl_pZone->zn_Zone, pZoneList->zl_pZone->zn_ZoneLen, ZoneName, ZoneLen)) return(TRUE); return(FALSE); } /*** AtalkZipZoneOnList * */ BOOLEAN AtalkZoneOnList( IN PZONE pZone, IN PZONE_LIST pZoneList ) { for ( ; pZoneList != NULL; pZoneList = pZoneList->zl_Next) if (pZoneList->zl_pZone == pZone) return(TRUE); return(FALSE); } /*** AtalkZipZone * */ ULONG AtalkZoneNumOnList( IN PZONE_LIST pZoneList ) { ULONG Cnt; for (Cnt = 0; pZoneList != NULL; pZoneList = pZoneList->zl_Next) Cnt++; return Cnt; } /*** AtalkZipZoneAddToList * */ PZONE_LIST AtalkZoneAddToList( IN PZONE_LIST pZoneList, IN PBYTE ZoneName, IN BYTE ZoneLen ) { PZONE_LIST pNewZoneList; PZONE pZone; // Get memory for a new ZoneList node. pNewZoneList = (PZONE_LIST)AtalkAllocMemory(sizeof(ZONE_LIST)); if (pNewZoneList != NULL) { if ((pZone = AtalkZoneReferenceByName(ZoneName, ZoneLen)) != NULL) { pNewZoneList->zl_Next = pZoneList; pNewZoneList->zl_pZone = pZone; } else { AtalkZoneFreeList(pNewZoneList); pNewZoneList = NULL; } } else { AtalkZoneFreeList(pZoneList); } return(pNewZoneList); } /*** AtalkZipZoneCopyList * */ PZONE_LIST AtalkZoneCopyList( IN PZONE_LIST pZoneList ) { PZONE_LIST pNewZoneList, pZoneListStart = NULL, *ppZoneList = &pZoneListStart; for (; pZoneList != NULL; pZoneList = pZoneList = pZoneList->zl_Next) { pNewZoneList = AtalkAllocMemory(sizeof(ZONE_LIST)); if (pNewZoneList == NULL) { break; } pNewZoneList->zl_Next = NULL; pNewZoneList->zl_pZone = pZoneList->zl_pZone; *ppZoneList = pNewZoneList; ppZoneList = &pNewZoneList->zl_Next; AtalkZoneReferenceByPtr(pNewZoneList->zl_pZone); } if (pNewZoneList == NULL) { AtalkZoneFreeList(pZoneListStart); } return(pZoneListStart); } /*** atalkZipSendComplete * */ VOID FASTCALL atalkZipSendComplete( IN NDIS_STATUS Status, IN PSEND_COMPL_INFO pSendInfo ) { PBUFFER_DESC pBuffDesc = (PBUFFER_DESC)(pSendInfo->sc_Ctx1); DBGPRINT(DBG_COMP_ZIP, DBG_LEVEL_INFO, ("atalkZipSendComplete: Freeing BuffDesc %lx\n", pBuffDesc)); if (!ATALK_SUCCESS(Status)) DBGPRINT(DBG_COMP_ZIP, DBG_LEVEL_ERR, ("atalkZipSendComplete: Failed %lx, pBuffDesc %lx\n", Status, pBuffDesc)); AtalkFreeBuffDesc(pBuffDesc); } #if DBG VOID AtalkZoneDumpTable( VOID ) { int i; PZONE pZone; ACQUIRE_SPIN_LOCK_DPC(&AtalkZoneLock); DBGPRINT(DBG_COMP_DUMP, DBG_LEVEL_FATAL, ("ZONETABLE: \n")); for (i = 0; i < NUM_ZONES_HASH_BUCKETS; i ++) { for (pZone = AtalkZonesTable[i]; pZone != NULL; pZone = pZone->zn_Next) { DBGPRINT(DBG_COMP_DUMP, DBG_LEVEL_FATAL, ("\t\t%s\n", pZone->zn_Zone)); } } RELEASE_SPIN_LOCK_DPC(&AtalkZoneLock); } #endif