You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
3272 lines
85 KiB
3272 lines
85 KiB
/*++
|
|
|
|
Copyright (c) 1992 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
zip.c
|
|
|
|
Abstract:
|
|
|
|
This module contains
|
|
|
|
Author:
|
|
|
|
Jameel Hyder ([email protected])
|
|
Nikhil Kamkolkar ([email protected])
|
|
|
|
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(pPortDesc->pd_PortType == ELAP_PORT || pPortDesc->pd_PortType == FDDI_PORT)
|
|
{
|
|
int IsOldAddress, IsBroadcastAddress;
|
|
IsOldAddress = AtalkFixedCompareCaseSensitive(pMulticastAddr,
|
|
MulticastAddrLen,
|
|
pPortDesc->pd_ZoneMulticastAddr,
|
|
MulticastAddrLen);
|
|
IsBroadcastAddress = AtalkFixedCompareCaseSensitive(pMulticastAddr,
|
|
MulticastAddrLen,
|
|
pPortDesc->pd_BroadcastAddr,
|
|
MulticastAddrLen);
|
|
if(!IsOldAddress && !IsBroadcastAddress)
|
|
{
|
|
RELEASE_SPIN_LOCK_DPC(&pPortDesc->pd_Lock);
|
|
AtalkNdisReplaceMulticast(pPortDesc,
|
|
pPortDesc->pd_ZoneMulticastAddr,
|
|
pMulticastAddr);
|
|
ACQUIRE_SPIN_LOCK_DPC(&pPortDesc->pd_Lock);
|
|
}
|
|
else
|
|
{
|
|
if (!IsOldAddress)
|
|
{
|
|
RELEASE_SPIN_LOCK_DPC(&pPortDesc->pd_Lock);
|
|
(*pPortDesc->pd_RemoveMulticastAddr)(pPortDesc,
|
|
pPortDesc->pd_ZoneMulticastAddr,
|
|
FALSE,
|
|
NULL,
|
|
NULL);
|
|
ACQUIRE_SPIN_LOCK_DPC(&pPortDesc->pd_Lock);
|
|
}
|
|
|
|
if (!IsBroadcastAddress)
|
|
{
|
|
RELEASE_SPIN_LOCK_DPC(&pPortDesc->pd_Lock);
|
|
(*pPortDesc->pd_AddMulticastAddr)(pPortDesc,
|
|
pMulticastAddr,
|
|
FALSE,
|
|
NULL,
|
|
NULL);
|
|
ACQUIRE_SPIN_LOCK_DPC(&pPortDesc->pd_Lock);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (!AtalkFixedCompareCaseSensitive(pMulticastAddr,
|
|
MulticastAddrLen,
|
|
pPortDesc->pd_ZoneMulticastAddr,
|
|
MulticastAddrLen))
|
|
{
|
|
RELEASE_SPIN_LOCK_DPC(&pPortDesc->pd_Lock);
|
|
(*pPortDesc->pd_RemoveMulticastAddr)(pPortDesc,
|
|
pPortDesc->pd_ZoneMulticastAddr,
|
|
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
|
|
|
|
|
|
|
|
|