|
|
/*++
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 <atalk.h>
#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
|