mirror of https://github.com/lianthony/NT4.0
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.
1399 lines
32 KiB
1399 lines
32 KiB
/*++
|
|
|
|
Copyright (c) 1991 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
zipstub.c
|
|
|
|
Abstract:
|
|
|
|
ZIP handling for non-routing nodes.
|
|
|
|
Author:
|
|
|
|
Garth Conboy initial coding
|
|
Nikhil Kamkolkar recoding/mpsafe
|
|
|
|
Revision History:
|
|
|
|
GC - (06/29/92): Added capability to find the default zone for a cable;
|
|
needed because we now have "defaultOrDesiredZone" as two
|
|
separate concepts.
|
|
GC - (11/16/92): Corrected above feature!
|
|
|
|
--*/
|
|
|
|
#define ZIPGLBL
|
|
#include "atalk.h"
|
|
|
|
#if (Iam an AppleTalkRouter) and (IamNot an AppleTalkStack)
|
|
#include "atpconst.h"
|
|
#endif
|
|
|
|
LOCAL
|
|
INCOMING_DDPHANDLER GetMyZoneReply, GetZoneListReply;
|
|
|
|
LOCAL
|
|
TimerHandler GetZoneInfoTimerExpired;
|
|
|
|
LOCAL
|
|
VOID SendZipPacketTo(ZipCompletionInfo completionInfo);
|
|
|
|
|
|
|
|
|
|
LONG
|
|
ZipPacketIn(
|
|
APPLETALK_ERROR ErrorCode,
|
|
ULONG UserData,
|
|
int Port,
|
|
APPLETALK_ADDRESS Source,
|
|
long DestinationSocket,
|
|
int ProtocolType,
|
|
PUCHAR Datagram,
|
|
int DatagramLength,
|
|
APPLETALK_ADDRESS ActualDestination)
|
|
{
|
|
int commandType;
|
|
int index;
|
|
int flags;
|
|
USHORT netRangeStart, netRangeEnd;
|
|
BOOLEAN foundZone;
|
|
int zoneLength, defaultZoneLength, multicastAddressLength;
|
|
CHAR zone[MAXIMUM_ZONELENGTH + 1], defaultZone[MAXIMUM_ZONELENGTH + 1];
|
|
CHAR multicastAddress[MAXIMUM_HARDWAREADDRESSLENGTH];
|
|
PPORT_HANDLERS portHandlers;
|
|
|
|
PUCHAR startOfPacket = Datagram;
|
|
int bytesAccepted = DatagramLength;
|
|
int logEventPlace = 0;
|
|
|
|
// "Use" unneeded actual parameters.
|
|
UNREFERENCED_PARAMETER(DestinationSocket);
|
|
UNREFERENCED_PARAMETER(UserData);
|
|
UNREFERENCED_PARAMETER(ActualDestination);
|
|
|
|
// Only play if we've been asked nicely!
|
|
if (ErrorCode == ATsocketClosed)
|
|
return(0);
|
|
else if (ErrorCode != ATnoError) {
|
|
INTERNAL_ERROR(__LINE__ | __ZIPSTUB__, ErrorCode, NULL, 0);
|
|
return(0);
|
|
}
|
|
|
|
//
|
|
// We are the handler for the non-router ZIP socket. We only have
|
|
// to care about ZIP Notifies (when a router changes our zone on us)
|
|
// and NetInfoReplies (when we are trying to find out info about the
|
|
// net)
|
|
//
|
|
// Our sole purpose of existence is so we can find out if the zone we
|
|
// have as our defaultZone is valid for this network, and if not, to
|
|
// get the default zone from the router.
|
|
//
|
|
// On a non-extended network ofcourse, there is only one zone on the net
|
|
// and that is '*'. So for a non-extended port, this routine has no
|
|
// reason to exist. It is in AarpForNodeOnPort (hence only extended networks)
|
|
// that this routine is set as a handler for the ZIP socket.
|
|
//
|
|
|
|
if (!AtalkVerifyPortDescriptorInterlocked(
|
|
GET_PORTDESCRIPTOR(Port),
|
|
__LINE__ | __ZIPSTUB__)) {
|
|
|
|
return(0);
|
|
}
|
|
|
|
|
|
do {
|
|
|
|
if (!GET_PORTDESCRIPTOR(Port)->ExtendedNetwork) {
|
|
INTERNAL_ERROR(
|
|
__LINE__ | __ZIPSTUB__,
|
|
GET_PORTDESCRIPTOR(Port)->ExtendedNetwork,
|
|
NULL,
|
|
0);
|
|
|
|
break;
|
|
}
|
|
|
|
// Verify the datagram satisfies the length constraints
|
|
// Use the fact that both packets have the same format
|
|
|
|
index = ZIP_ZONELENGTHOFFSET;
|
|
if (DatagramLength < index + 1) {
|
|
logEventPlace = __ZIPSTUB__ | __LINE__;
|
|
break;
|
|
}
|
|
|
|
GETUCHAR2INT(Datagram + index, &zoneLength);
|
|
index += (1 + zoneLength);
|
|
|
|
// Check if length will allow multicast address length to fit
|
|
if (DatagramLength < index + 1) {
|
|
logEventPlace = __ZIPSTUB__ | __LINE__;
|
|
break;
|
|
}
|
|
|
|
GETUCHAR2INT(Datagram + index, &multicastAddressLength);
|
|
index += (1 + multicastAddressLength);
|
|
|
|
// Check if length will allow final zone name length to fit
|
|
if (DatagramLength < index + 1) {
|
|
logEventPlace = __ZIPSTUB__ | __LINE__;
|
|
break;
|
|
}
|
|
|
|
GETUCHAR2INT(Datagram + index, &defaultZoneLength);
|
|
index += (1 + defaultZoneLength);
|
|
|
|
// Check if the datagram can fit in the expected zone name
|
|
if (DatagramLength < index) {
|
|
logEventPlace = __ZIPSTUB__ | __LINE__;
|
|
break;
|
|
}
|
|
|
|
Datagram += ZIP_COMMANDOFFSET; // Start from command offset
|
|
|
|
GETUCHAR2INT(Datagram, &commandType);
|
|
Datagram += 1;
|
|
|
|
if (((ProtocolType != DDPPROTOCOL_ZIP) ||
|
|
((commandType != ZIP_NOTIFYCOMMAND) &&
|
|
(commandType != ZIP_NETINFOREPLYCOMMAND)))
|
|
|
|
||
|
|
|
|
// Dont care if this is not a reply packet, and we are
|
|
// in the process of trying to find out our default zone
|
|
((GET_PORTDESCRIPTOR(Port)->LookingForDefaultZone) &&
|
|
(commandType != ZIP_NETINFOREPLYCOMMAND))
|
|
|
|
||
|
|
|
|
// If we already know our default zone, or if the zone we
|
|
// have set for this node is valid, then we do not care
|
|
// about reply packets
|
|
((!GET_PORTDESCRIPTOR(Port)->LookingForDefaultZone) &&
|
|
(commandType == ZIP_NETINFOREPLYCOMMAND) &&
|
|
(GET_PORTDESCRIPTOR(Port)->ThisZoneValid))) {
|
|
|
|
bytesAccepted = 0;
|
|
break;
|
|
}
|
|
|
|
portHandlers = &portSpecificInfo[GET_PORTDESCRIPTOR(Port)->PortType];
|
|
|
|
//
|
|
// Handle our two cases. Decode both of them as if we have a net info
|
|
// reply. 'if' above will prevent anything other than ZIP_NOTIFYCOMMAND
|
|
// and ZIP_NETINFOREPLYCOMMAND from getting here. Both these packets have
|
|
// the same format.
|
|
//
|
|
|
|
GETUCHAR2INT(Datagram, &flags);
|
|
Datagram += 1;
|
|
|
|
//
|
|
// Get the network number range start/end values, only meaningful for
|
|
// GetNetInfo replies. Since Notifies will be really rare, we will do this
|
|
// useless piece of work for those also.
|
|
//
|
|
|
|
GETUSHORT2USHORT(Datagram, &netRangeStart);
|
|
Datagram += 2;
|
|
|
|
GETUSHORT2USHORT(Datagram, &netRangeEnd);
|
|
Datagram += 2;
|
|
|
|
//
|
|
// We already have the zone/multicast address lengths, and the packet is
|
|
// guaranteed to be holding all of them.
|
|
//
|
|
|
|
// Skip the zone length, verify it is an ok value
|
|
Datagram += 1;
|
|
if (zoneLength > MAXIMUM_ZONELENGTH) {
|
|
logEventPlace = __ZIPSTUB__ | __LINE__;
|
|
break;
|
|
}
|
|
|
|
MoveMem(
|
|
zone,
|
|
Datagram,
|
|
zoneLength);
|
|
|
|
zone[zoneLength] = 0;
|
|
|
|
// Done with zone, skip it to get to the multicast address length
|
|
Datagram += zoneLength;
|
|
|
|
//
|
|
// If we're requesting the zone name, make sure the response matches our
|
|
// request. ZoneLength will be zero when we're looking for the default
|
|
// zone, so we won't do this test.
|
|
//
|
|
|
|
EnterCriticalSection(GLOBAL_ROUTING);
|
|
if ((commandType == ZIP_NETINFOREPLYCOMMAND) && (zoneLength != 0)) {
|
|
if (!CompareCaseInsensitive(
|
|
zone,
|
|
GET_PORTDESCRIPTOR(Port)->InitialDesiredZone)) {
|
|
|
|
// BUGBUG: Do we care to log this?
|
|
LeaveCriticalSection(GLOBAL_ROUTING);
|
|
break;
|
|
}
|
|
}
|
|
|
|
// If we're a notify make sure we're in the zone that is being changed.
|
|
if (commandType == ZIP_NOTIFYCOMMAND) {
|
|
if ((GET_PORTDESCRIPTOR(Port)->ThisZoneValid) &&
|
|
(!CompareCaseInsensitive(
|
|
zone,
|
|
GET_PORTDESCRIPTOR(Port)->ThisZone)) {
|
|
|
|
LeaveCriticalSection(GLOBAL_ROUTING);
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Skip multicast length
|
|
Datagram += 1;
|
|
|
|
if (multicastAddressLength != portHandlers->HardwareAddressLength) {
|
|
logEventPlace = __ZIPSTUB__ | __LINE__;
|
|
LeaveCriticalSection(GLOBAL_ROUTING);
|
|
break;
|
|
}
|
|
|
|
MoveMem(
|
|
multicastAddress,
|
|
Datagram,
|
|
multicastAddressLength);
|
|
|
|
Datagram += multicastAddressLength;
|
|
if (flags & ZIP_USEBROADCASTFLAG)
|
|
MoveMem(
|
|
multicastAddress,
|
|
portHandlers->BroadcastAddress,
|
|
multicastAddressLength);
|
|
|
|
|
|
// Grab second zone name, if needed or present.
|
|
if (commandType == ZIP_NOTIFYCOMMAND || defaultZoneLength > 0) {
|
|
if ((defaultZoneLength == 0) ||
|
|
(defaultZoneLength > MAXIMUM_ZONELENGTH)) {
|
|
|
|
logEventPlace = __ZIPSTUB__ | __LINE__;
|
|
LeaveCriticalSection(GLOBAL_ROUTING);
|
|
break;
|
|
}
|
|
|
|
MoveMem(
|
|
defaultZone,
|
|
Datagram,
|
|
defaultZoneLength);
|
|
|
|
defaultZone[defaultZoneLength] = 0;
|
|
Datagram += defaultZoneLength;
|
|
}
|
|
|
|
//
|
|
// Make "defaultZone" be the "new" one. We may not have a default/new
|
|
// zone in NetInfoReplyCase and we requested with a correct zone.
|
|
//
|
|
|
|
if (defaultZoneLength == 0) {
|
|
strcpy(defaultZone, zone);
|
|
defaultZoneLength = zoneLength;
|
|
}
|
|
|
|
//
|
|
// If we're just looking for the default zone, set here and note our
|
|
// mission completed.
|
|
//
|
|
|
|
if (GET_PORTDESCRIPTOR(Port)->LookingForDefaultZone) {
|
|
strcpy(GET_PORTDESCRIPTOR(Port)->ThisDefaultZone, defaultZone);
|
|
GET_PORTDESCRIPTOR(Port)->ThisDefaultZoneValid = TRUE;
|
|
}
|
|
|
|
//
|
|
// Okay, now we want to "accept" all of the information about "this zone"
|
|
// for the nodes on the current port.
|
|
//
|
|
// If the new multicast address is different, remove the old and set
|
|
// the new. Don't allow mucking with the "broadcast" multicast address.
|
|
//
|
|
|
|
if (!FixedCompareCaseSensitive(
|
|
multicastAddress,
|
|
multicastAddressLength,
|
|
GET_PORTDESCRIPTOR(Port)->ZoneMulticastAddress,
|
|
multicastAddressLength)) {
|
|
|
|
if ((GET_PORTDESCRIPTOR(Port)->ThisZoneValid &&
|
|
(!FixedCompareCaseSensitive(
|
|
GET_PORTDESCRIPTOR(Port)->ZoneMulticastAddress,
|
|
multicastAddressLength,
|
|
portHandlers->BroadcastAddress,
|
|
multicastAddressLength)))) {
|
|
|
|
(*portHandlers->RemoveMulticastAddress)(
|
|
Port,
|
|
1,
|
|
GET_PORTDESCRIPTOR(Port)->ZoneMulticastAddress);
|
|
}
|
|
|
|
if (!FixedCompareCaseSensitive(
|
|
multicastAddress,
|
|
multicastAddressLength,
|
|
portHandlers->BroadcastAddress,
|
|
multicastAddressLength)) {
|
|
|
|
(*portHandlers->AddMulticastAddress)(
|
|
Port,
|
|
1,
|
|
multicastAddress);
|
|
}
|
|
|
|
MoveMem(
|
|
GET_PORTDESCRIPTOR(Port)->ZoneMulticastAddress,
|
|
multicastAddress,
|
|
multicastAddressLength);
|
|
}
|
|
|
|
// Set this cable range if we're a net info reply.
|
|
if (commandType == ZIP_NETINFOREPLYCOMMAND) {
|
|
GET_PORTDESCRIPTOR(Port)->ThisCableRange.FirstNetworkNumber =
|
|
netRangeStart;
|
|
GET_PORTDESCRIPTOR(Port)->ThisCableRange.LastNetworkNumber =
|
|
netRangeEnd;
|
|
|
|
GET_PORTDESCRIPTOR(Port)->ARouter.NetworkNumber = Source.NetworkNumber;
|
|
GET_PORTDESCRIPTOR(Port)->ARouter.NodeNumber = Source.NodeNumber;
|
|
GET_PORTDESCRIPTOR(Port)->SeenRouterRecently = TRUE;
|
|
}
|
|
|
|
// Okay, now we know the zone!
|
|
strcpy(GET_PORTDESCRIPTOR(Port)->ThisZone, defaultZone);
|
|
GET_PORTDESCRIPTOR(Port)->ThisZoneValid = TRUE;
|
|
LeaveCriticalSection(GLOBAL_ROUTING);
|
|
|
|
} while (FALSE);
|
|
|
|
|
|
if (logEventPlace) {
|
|
LOG_ERRORONPORT(
|
|
Port,
|
|
EVENT_ATALK_INVALIDAARPPACKET,
|
|
logEventPlace,
|
|
STATUS_INSUFFICIENT_RESOURCES,
|
|
startOfPacket,
|
|
Length,
|
|
0,
|
|
NULL);
|
|
}
|
|
|
|
AtalkDereferencePortDescriptor(GET_PORTDESCRIPTOR(Port),__LINE__ | __ZIPSTUB__);
|
|
return(DatagramLength);
|
|
|
|
} // ZipPacketIn
|
|
|
|
|
|
|
|
|
|
BOOLEAN
|
|
GetNetworkInfoForNode(
|
|
int Port,
|
|
EXTENDED_NODENUMBER ExtendedNode,
|
|
BOOLEAN FindDefaultZone,
|
|
BOOLEAN WaitForAllowed
|
|
)
|
|
{
|
|
int numberOfRequests;
|
|
int datagramLength;
|
|
BOOLEAN done;
|
|
PBUFFER_DESC datagram, copy;
|
|
APPLETALK_ADDRESS source, destination;
|
|
|
|
//
|
|
// Our node is just coming up; send out some ZipGetNetInfo packets,
|
|
// and see what we can find out!
|
|
//
|
|
|
|
if (!AtalkVerifyPortDescriptorInterlocked(
|
|
GET_PORTDESCRIPTOR(Port),
|
|
__LINE__ | __ZIPSTUB__)) {
|
|
|
|
return(FALSE);
|
|
}
|
|
|
|
// Setup.
|
|
if (!GET_PORTDESCRIPTOR(Port)->ExtendedNetwork) {
|
|
INTERNAL_ERROR(__LINE__ | __ZIPSTUB__, ErrorCode, NULL, 0);
|
|
return(FALSE);
|
|
}
|
|
|
|
if (FindDefaultZone) {
|
|
GET_PORTDESCRIPTOR(Port)->ThisDefaultZoneValid = FALSE;
|
|
GET_PORTDESCRIPTOR(Port)->LookingForDefaultZone = TRUE;
|
|
} else {
|
|
GET_PORTDESCRIPTOR(Port)->ThisZoneValid = FALSE;
|
|
}
|
|
|
|
source.NetworkNumber = ExtendedNode.NetworkNumber;
|
|
source.NodeNumber = ExtendedNode.NodeNumber;
|
|
source.SocketNumber = ZONESINFORMATION_SOCKET;
|
|
destination.NetworkNumber = CABLEWIDE_BROADCASTNETWORKNUMBER;
|
|
destination.NodeNumber = APPLETALK_BROADCASTNODENUMBER;
|
|
destination.SocketNumber = ZONESINFORMATION_SOCKET;
|
|
|
|
done = FALSE;
|
|
do {
|
|
|
|
// Allocate a buffer descriptor.
|
|
if ((datagram = NewBufferDescriptor(
|
|
ZIP_ZONENAMEOFFSET + MAXIMUM_ZONELENGTH)) == NULL) {
|
|
|
|
LOG_ERROR(
|
|
EVENT_ATALK_MEMORY_RESOURCES,
|
|
(__ZIPSTUB__ | __LINE__),
|
|
0,
|
|
NULL,
|
|
0,
|
|
0,
|
|
NULL);
|
|
|
|
break;
|
|
}
|
|
|
|
// Build a ZipGetNetInfo datagram...
|
|
datagram->data[ZIP_COMMANDOFFSET] = ZIP_GETNETINFOCOMMAND;
|
|
datagram->data[ZIP_FLAGSOFFSET] = 0;
|
|
datagram->data[ZIP_CABLERANGESTARTOFFSET] = 0;
|
|
datagram->data[ZIP_CABLERANGESTARTOFFSET + 1] = 0;
|
|
datagram->data[ZIP_CABLERANGEENDOFFSET] = 0;
|
|
datagram->data[ZIP_CABLERANGEENDOFFSET + 1] = 0;
|
|
if (FindDefaultZone) {
|
|
datagram->data[ZIP_ZONELENGTHOFFSET] = 0;
|
|
datagramLength = ZIP_ZONENAMEOFFSET;
|
|
|
|
} else {
|
|
|
|
datagram->data[ZIP_ZONELENGTHOFFSET] =
|
|
(UCHAR)strlen(GET_PORTDESCRIPTOR(Port)->InitialDesiredZone);
|
|
if (datagram->data[ZIP_ZONELENGTHOFFSET] != 0) {
|
|
strcpy(
|
|
datagram->data + ZIP_ZONENAMEOFFSET,
|
|
GET_PORTDESCRIPTOR(Port)->InitialDesiredZone);
|
|
|
|
datagramLength =
|
|
ZIP_ZONENAMEOFFSET + datagram->data[ZIP_ZONELENGTHOFFSET];
|
|
} else {
|
|
datagramLength = ZIP_ZONENAMEOFFSET;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Okay, blast a few of these guys out to see if any router on the
|
|
// network knows what's up.
|
|
//
|
|
|
|
for (numberOfRequests = 0;
|
|
numberOfRequests < NUMBEROF_GETNETINFOS;
|
|
numberOfRequest++) {
|
|
|
|
// Are we done?
|
|
EnterCriticalSection(GLOBAL_ROUTING);
|
|
done =
|
|
((FindDefaultZone && GET_PORTDESCRIPTOR(Port)->ThisDefaultZoneValid) ||
|
|
(!FindDefaultZone && GET_PORTDESCRIPTOR(Port)->ThisZoneValid));
|
|
LeaveCriticalSection(GLOBAL_ROUTING);
|
|
|
|
if (done) {
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Copy our datagram due to multiple sends and possible asynchronous
|
|
// transmit completion.
|
|
//
|
|
|
|
if ((copy = CopyBufferChain(datagram)) == NULL) {
|
|
break;
|
|
}
|
|
|
|
if (!TransmitDdp(
|
|
Port,
|
|
source,
|
|
destination,
|
|
DDPPROTOCOL_ZIP,
|
|
copy,
|
|
datagramLength,
|
|
0,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
0)) {
|
|
|
|
LOG_ERRORONPORT(
|
|
Port,
|
|
EVENT_ATALK_ZIPSENDPACKET,
|
|
(__ZIPSTUB__ | __LINE__),
|
|
0,
|
|
NULL,
|
|
0,
|
|
0,
|
|
NULL);
|
|
|
|
break;
|
|
}
|
|
|
|
if (!WaitForAllowed) {
|
|
break;
|
|
}
|
|
|
|
if (FindDefaultZone) {
|
|
WaitFor(
|
|
ZIP_GETNETINFOHUNDRETHS,
|
|
&GET_PORTDESCRIPTOR(Port)->ThisDefaultZoneValid);
|
|
|
|
continue;
|
|
}
|
|
|
|
WaitFor(
|
|
ZIP_GETNETINFOHUNDRETHS,
|
|
&GET_PORTDESCRIPTOR(Port)->ThisZoneValid);
|
|
}
|
|
|
|
// Well... did we get anything?
|
|
FreeBufferChain(datagram);
|
|
|
|
EnterCriticalSection(GLOBAL_ROUTING);
|
|
if (FindDefaultZone) {
|
|
GET_PORTDESCRIPTOR(Port)->LookingForDefaultZone = FALSE;
|
|
done = GET_PORTDESCRIPTOR(Port)->ThisDefaultZoneValid;
|
|
} else {
|
|
done = GET_PORTDESCRIPTOR(Port)->ThisZoneValid;
|
|
}
|
|
LeaveCriticalSection(GLOBAL_ROUTING);
|
|
break;
|
|
|
|
} while (FALSE);
|
|
|
|
AtalkDereferencePortDescriptor(GET_PORTDESCRIPTOR(Port),__LINE__ | __ZIPSTUB__);
|
|
return(done);
|
|
|
|
} // GetNetworkInfoOnPort
|
|
|
|
|
|
|
|
|
|
APPLETALK_ERROR
|
|
GetMyZone(
|
|
int Port, // On what port?
|
|
PVOID OpaqueBuffer, // "Buffer" for the zone name
|
|
GetMyZoneComplete *CompletionRoutine, // Routine to call when we're finished.
|
|
ULONG UserData // Passed along to above.
|
|
)
|
|
{
|
|
long socket;
|
|
PZIP_COMPLETIONINFO completionInfo;
|
|
APPLETALK_ERROR errorCode = ATnoError;
|
|
|
|
//
|
|
// Call the supplied completion routine with the following arguments when
|
|
// we've come up with the answer:
|
|
//
|
|
// errorCode - APPLETALK_ERROR; completion status.
|
|
// UserData - ULONG; as passed to us.
|
|
// OpaqueBuffer - PVOID ; ad passed to us (filled in now).
|
|
//
|
|
//
|
|
|
|
// If the "default port" is requested, demystify it.
|
|
if (Port == DEFAULT_PORT)
|
|
if ((Port = FindDefaultPort()) < 0)
|
|
return(ATappleTalkShutDown);
|
|
|
|
if (!AtalkVerifyStackInterlocked(__LINE__ | __ZIPSTUB__)) {
|
|
return(ATappleTalkShutDown);
|
|
}
|
|
|
|
if (!AtalkVerifyPortDescriptorInterlocked(
|
|
GET_PORTDESCRIPTOR(Port),
|
|
__LINE__ | __ZIPSTUB__)) {
|
|
|
|
return(ATappleTalkShutDown);
|
|
}
|
|
|
|
do {
|
|
|
|
EnterCriticalSection(GLOBAL_ROUTING);
|
|
|
|
// For extended networks, we either know or can't find out!
|
|
if (GET_PORTDESCRIPTOR(Port)->ExtendedNetwork) {
|
|
if (GET_PORTDESCRIPTOR(Port)->ThisZoneValid) {
|
|
MoveToOpaque(
|
|
OpaqueBuffer,
|
|
0,
|
|
GET_PORTDESCRIPTOR(Port)->ThisZone,
|
|
strlen(GET_PORTDESCRIPTOR(Port)->ThisZone) + 1);
|
|
|
|
} else {
|
|
|
|
MoveToOpaque(
|
|
OpaqueBuffer,
|
|
0,
|
|
WILDCARD_ZONE,
|
|
WILDCARD_ZONESIZE);
|
|
}
|
|
LeaveCriticalSection(GLOBAL_ROUTING);
|
|
|
|
(*CompletionRoutine)(ATnoError, UserData, OpaqueBuffer);
|
|
break;
|
|
}
|
|
|
|
//
|
|
// For non-extended networks we need to ask a router. If we don't know
|
|
// about a router, don't play.
|
|
//
|
|
|
|
if (!GET_PORTDESCRIPTOR(Port)->SeenRouterRecently) {
|
|
MoveToOpaque(
|
|
OpaqueBuffer,
|
|
0,
|
|
WILDCARD_ZONE,
|
|
WILDCARD_ZONESIZE);
|
|
|
|
LeaveCriticalSection(GLOBAL_ROUTING);
|
|
|
|
(*CompletionRoutine)(ATnoError, UserData, OpaqueBuffer);
|
|
break;
|
|
}
|
|
|
|
LeaveCriticalSection(GLOBAL_ROUTING);
|
|
|
|
// Build a completion node.
|
|
if ((completionInfo = AllocateZipCompletionInfo()) == NULL) {
|
|
errorCode = ATnoMemory;
|
|
break;
|
|
}
|
|
|
|
// Open a socket for handling the replies.
|
|
if ((errorCode = OpenSocketOnNode(
|
|
&socket,
|
|
Port,
|
|
NULL,
|
|
UNKNOWN_SOCKET,
|
|
GetMyZoneReply,
|
|
(ULONG)completionInfo,
|
|
FALSE,
|
|
NULL,
|
|
0,
|
|
NULL)) != ATnoError) {
|
|
|
|
Free(completionInfo);
|
|
break;
|
|
}
|
|
|
|
completionInfo->AtpRequestType = ZIP_GETMYZONECOMMAND;
|
|
completionInfo->Socket = socket;
|
|
completionInfo->Router.NetworkNumber =
|
|
GET_PORTDESCRIPTOR(Port)->ARouter.NetworkNumber;
|
|
completionInfo->Router.NodeNumber =
|
|
GET_PORTDESCRIPTOR(Port)->ARouter.NodeNumber;
|
|
completionInfo->Router.SocketNumber = ZONESINFORMATION_SOCKET;
|
|
completionInfo->OpaqueBuffer = OpaqueBuffer;
|
|
completionInfo->MyZoneCompletionRoutine = CompletionRoutine;
|
|
completionInfo->UserData = UserData;
|
|
|
|
EnterCriticalSection(GLOBAL_ROUTING);
|
|
|
|
// Timer (removed in timer expiration, or if timer successfully cancelled
|
|
AtalkReferenceZipCompletion(
|
|
completionInfo,
|
|
__ZIPSTUB__ | __LINE__);
|
|
|
|
// Request (removed upon request completion)
|
|
AtalkReferenceZipCompletion(
|
|
completionInfo,
|
|
__ZIPSTUB__ | __LINE__);
|
|
|
|
// Insert into the list, before starting the timer etc
|
|
InsertTailList (
|
|
&ZipCompletionInfoList,
|
|
&completionInfo->Linkage);
|
|
|
|
LeaveCriticalSection(GLOBAL_ROUTING);
|
|
|
|
|
|
// Start the retry timer, then send the first query.
|
|
completionInfo->timerId = StartTimer(
|
|
GetZoneInfoTimerExpired,
|
|
GETZONEINFO_TIMERSECONDS,
|
|
sizeof(PZIP_COMPLETIONINFO),
|
|
(PCHAR)completionInfo);
|
|
|
|
SendZipPacketTo(completionInfo);
|
|
|
|
} while (FALSE);
|
|
|
|
AtalkDereferencePortDescriptor(GET_PORTDESCRIPTOR(Port),__LINE__ | __ZIPSTUB__);
|
|
AtalkDereferenceStack(__LINE__ | __ZIPSTUB__);
|
|
|
|
return(errorCode);
|
|
|
|
} // GetMyZone
|
|
|
|
|
|
|
|
|
|
APPLETALK_ERROR
|
|
GetZoneList(
|
|
int Port, // Port to get zone list from.
|
|
BOOLEAN GetLocalZones, // Does the caller want only the local zones?
|
|
PVOID OpaqueBuffer, // "Buffer" to fill with zone list.
|
|
int BufferSize, // Buffer size (bytes).
|
|
GetZoneListComplete *CompletionRoutine,
|
|
// Routine to call when we're finished.
|
|
ULONG UserData // Passed along to above.
|
|
)
|
|
{
|
|
long socket;
|
|
ZipCompletionInfo completionInfo;
|
|
APPLETALK_ERROR errorCode;
|
|
|
|
//
|
|
// Call the supplied completion routine with the following arguments when
|
|
// we've come up with the answer:
|
|
//
|
|
// errorCode - APPLETALK_ERROR; completion status.
|
|
// UserData - ULONG; as passed to us.
|
|
// OpaqueBuffer
|
|
// - PVOID ; addr passed to us (filled in now).
|
|
// zoneCount - int; how many zones did we pack in buffer.
|
|
//
|
|
//
|
|
|
|
// If the "default port" is requested, demystify it.
|
|
if (Port == DEFAULT_PORT)
|
|
if ((Port = FindDefaultPort()) < 0)
|
|
return(ATappleTalkShutDown);
|
|
|
|
if (!AtalkVerifyStackInterlocked(__LINE__ | __ZIPSTUB__)) {
|
|
return(ATappleTalkShutDown);
|
|
}
|
|
|
|
if (!AtalkVerifyPortDescriptorInterlocked(
|
|
GET_PORTDESCRIPTOR(Port),
|
|
__LINE__ | __ZIPSTUB__)) {
|
|
|
|
return(ATappleTalkShutDown);
|
|
}
|
|
|
|
do {
|
|
|
|
EnterCriticalSection(GLOBAL_ROUTING);
|
|
|
|
// If we don't know about a router, don't play.
|
|
if (!GET_PORTDESCRIPTOR(Port)->SeenRouterRecently) {
|
|
MoveToOpaque(
|
|
OpaqueBuffer,
|
|
0,
|
|
WILDCARD_ZONE,
|
|
WILDCARD_ZONESIZE);
|
|
|
|
LeaveCriticalSection(GLOBAL_ROUTING);
|
|
|
|
(*CompletionRoutine)(ATnoError, UserData, OpaqueBuffer, 1);
|
|
break;
|
|
}
|
|
|
|
LeaveCriticalSection(GLOBAL_ROUTING);
|
|
|
|
// Build a completion node.
|
|
if ((completionInfo = AllocateZipCompletionInfo()) == NULL) {
|
|
errorCode = ATnoMemory;
|
|
break;
|
|
}
|
|
|
|
// Open a socket for handling the replies.
|
|
if ((errorCode = OpenSocketOnNode(
|
|
&socket,
|
|
Port,
|
|
NULL,
|
|
UNKNOWN_SOCKET,
|
|
GetZoneListReply,
|
|
(ULONG)completionInfo,
|
|
FALSE,
|
|
NULL,
|
|
0,
|
|
NULL)) != ATnoError) {
|
|
|
|
Free(completionInfo);
|
|
break;
|
|
}
|
|
|
|
if (GetLocalZones)
|
|
completionInfo->AtpRequestType = ZIP_GETLOCALZONESCOMMAND;
|
|
else
|
|
completionInfo->AtpRequestType = ZIP_GETZONELISTCOMMAND;
|
|
|
|
completionInfo->Router.NetworkNumber =
|
|
GET_PORTDESCRIPTOR(Port)->ARouter.NetworkNumber;
|
|
completionInfo->Router.NodeNumber =
|
|
GET_PORTDESCRIPTOR(Port)->ARouter.NodeNumber;
|
|
completionInfo->Router.SocketNumber = ZONESINFORMATION_SOCKET;
|
|
|
|
completionInfo->Socket = socket;
|
|
completionInfo->OpaqueBuffer = OpaqueBuffer;
|
|
completionInfo->BufferSize = BufferSize;
|
|
completionInfo->ZoneListCompletionRoutine = CompletionRoutine;
|
|
completionInfo->UserData = UserData;
|
|
completionInfo->ZoneListIndex = 1;
|
|
|
|
EnterCriticalSection(GLOBAL_ROUTING);
|
|
|
|
// Timer (removed in timer expiration, or if timer successfully cancelled
|
|
AtalkReferenceZipCompletion(
|
|
completionInfo,
|
|
__ZIPSTUB__ | __LINE__);
|
|
|
|
// Request (removed upon request completion)
|
|
AtalkReferenceZipCompletion(
|
|
completionInfo,
|
|
__ZIPSTUB__ | __LINE__);
|
|
|
|
// Insert into the list, before starting the timer etc
|
|
InsertTailList (
|
|
&ZipCompletionInfoList,
|
|
&completionInfo->Linkage);
|
|
|
|
LeaveCriticalSection(GLOBAL_ROUTING);
|
|
|
|
|
|
// Start the retry timer, then send the first query.
|
|
completionInfo->TimerId = StartTimer(
|
|
GetZoneInfoTimerExpired,
|
|
GETZONEINFO_TIMERSECONDS,
|
|
sizeof(PZIP_COMPLETIONINFO),
|
|
(PCHAR)completionInfo);
|
|
|
|
SendZipPacketTo(completionInfo);
|
|
|
|
} while (FALSE);
|
|
|
|
AtalkDereferencePortDescriptor(GET_PORTDESCRIPTOR(Port),__LINE__ | __ZIPSTUB__);
|
|
AtalkDereferenceStack(__LINE__ | __ZIPSTUB__);
|
|
|
|
return(errorCode);
|
|
|
|
} // GetZoneList
|
|
|
|
|
|
|
|
|
|
VOID
|
|
SendZipPacketTo(
|
|
PZIP_COMPLETIONINFO completionInfo
|
|
)
|
|
{
|
|
PBUFFER_DESC datagram;
|
|
|
|
// Allocate a buffer descriptor.
|
|
if ((datagram = NewBufferDescriptor(ZIP_GETZONELISTDDPSIZE)) == NULL) {
|
|
|
|
LOG_ERROR(
|
|
EVENT_ATALK_MEMORY_RESOURCES,
|
|
(__ZIPSTUB__ | __LINE__),
|
|
0,
|
|
NULL,
|
|
0,
|
|
0,
|
|
NULL);
|
|
|
|
return;
|
|
}
|
|
|
|
// Build our toy ATP packet.
|
|
PUTUCHAR2UCHAR(
|
|
ATP_REQUESTFUNCTIONCODE,
|
|
datagram->data + ATP_COMMANDCONTROLOFFSET);
|
|
|
|
PUTUCHAR2UCHAR(
|
|
1,
|
|
datagram->data + ATP_BITMAPOFFSET);
|
|
|
|
PUTUSHORT2USHORT(
|
|
0,
|
|
datagram->data + ATP_TRANSACTIONIDOFFSET);
|
|
|
|
PUTUCHAR2UCHAR(
|
|
completionInfo->AtpRequestType,
|
|
datagram->data + ATPZIP_COMMANDOFFSET);
|
|
|
|
// 0 byte padding
|
|
PUTUCHAR2UCHAR(
|
|
0,
|
|
datagram->data + ATPZIP_COMMANDOFFSET + 1);
|
|
|
|
PUTUSHORT2USHORT(
|
|
completionInfo->ZoneListIndex,
|
|
datagram->data + ATPZIP_STARTINDEXOFFSET);
|
|
|
|
// Send the datagram to the specified destination.
|
|
if (DeliverDdp(
|
|
completionInfo->Socket,
|
|
completionInfo->Router,
|
|
DDPPROTOCOL_ATP,
|
|
datagram,
|
|
ZIP_GETZONELISTDDPSIZE,
|
|
NULL,
|
|
NULL,
|
|
0) != ATnoError) {
|
|
|
|
LOG_ERRORONPORT(
|
|
Port,
|
|
EVENT_ATALK_ZIPSENDPACKET,
|
|
(__ZIPSTUB__ | __LINE__),
|
|
0,
|
|
NULL,
|
|
0,
|
|
0,
|
|
NULL);
|
|
}
|
|
|
|
return;
|
|
|
|
} // SendZipPacketTo
|
|
|
|
|
|
|
|
|
|
LONG
|
|
GetMyZoneReply(
|
|
APPLETALK_ERROR errorCode,
|
|
ULONG UserData,
|
|
int Port,
|
|
APPLETALK_ADDRESS source,
|
|
long DestinationSocket,
|
|
int ProtocolType,
|
|
PCHAR Datagram,
|
|
int DatagramLength,
|
|
APPLETALK_ADDRESS ActualDestination
|
|
)
|
|
{
|
|
PZIP_COMPLETIONINFO completionInfo;
|
|
USHORT zoneCount;
|
|
USHORT zoneLength;
|
|
PVOID opaqueBuffer;
|
|
BOOLEAN success;
|
|
GetMyZoneComplete *completionRoutine;
|
|
|
|
// "Use" unused formals.
|
|
UNREFERENCED_PARAMETERS(Port);
|
|
UNREFERENCED_PARAMETERS(source);
|
|
UNREFERENCED_PARAMETERS(ActualDestination);
|
|
|
|
completionInfo = (PZIP_COMPLETIONINFO)UserData;
|
|
|
|
//
|
|
// On most error cases flee -- however, remove our completion info on
|
|
// socket closed.
|
|
//
|
|
|
|
if (errorCode == ATsocketClosed) {
|
|
AtalkDereferenceZipCompletion(completionInfo);
|
|
}
|
|
|
|
if ((errorCode != ATnoError) ||
|
|
(ProtocolType != DDPPROTOCOL_ATP) ||
|
|
(DatagramLength <= ATPZIP_FIRSTZONEOFFSET)) {
|
|
|
|
return(0);
|
|
}
|
|
|
|
// We should have one quality zone!
|
|
GETUSHORT2USHORT(
|
|
Datagram + ATPZIP_ZONECOUNTOFFSET,
|
|
&zoneCount);
|
|
|
|
GETUCHAR2USHORT(
|
|
Datagram + ATPZIP_FIRSTZONEOFFSET,
|
|
&zoneLength);
|
|
|
|
if ((zoneCount != 1) ||
|
|
(zoneLength == 0) ||
|
|
(zoneLength > MAXIMUM_ZONELENGTH)) {
|
|
|
|
return(0);
|
|
}
|
|
|
|
// Okay, move the zone name into the user's buffer.
|
|
MoveToOpaque(
|
|
completionInfo->OpaqueBuffer,
|
|
0,
|
|
Datagram + ATPZIP_FIRSTZONEOFFSET + 1,
|
|
zoneLength);
|
|
|
|
// Move a null after the zone name
|
|
MoveToOpaque(
|
|
completionInfo->OpaqueBuffer,
|
|
zoneLength,
|
|
"",
|
|
1);
|
|
|
|
//
|
|
// We're all set: cancel the retry timer, close our socket [this will cause
|
|
// a recursive call which will remove the completion info], call the
|
|
// completion routine, flee.
|
|
//
|
|
|
|
success = TRUE;
|
|
EnterCriticalSection(GLOBAL_ROUTING);
|
|
if (completionInfo->Flags & ZIPCOMPLETION_DONE) {
|
|
|
|
// Hmm, looks like the timer timed out, and has already
|
|
// called the completion routine. It must be trying to
|
|
// close the socket right now. We just get out, without
|
|
// doing anything, the Timer routines, socketClose should
|
|
// lead to the dereference for the request.
|
|
|
|
success = FALSE;
|
|
|
|
} else {
|
|
completionInfo->Flags |= ZIPCOMPLETION_DONE;
|
|
}
|
|
LeaveCriticalSection(GLOBAL_ROUTING);
|
|
|
|
if (success) {
|
|
success = CancelTimer(completionInfo->TimerId);
|
|
if (success) {
|
|
|
|
// Dereference for the timer reference
|
|
AtalkDereferenceZipCompletion(completionInfo);
|
|
}
|
|
|
|
opaqueBuffer = completionInfo->OpaqueBuffer;
|
|
completionRoutine = completionInfo->MyZoneCompletionRoutine;
|
|
UserData = completionInfo->UserData;
|
|
if (CloseSocketOnNode(
|
|
completionInfo->Socket,
|
|
NULL,
|
|
(ULONG)0) != ATnoError) {
|
|
|
|
LOG_ERRORONPORT(
|
|
Port,
|
|
EVENT_ATALK_ZIPSOCKETCLOSE,
|
|
(__ZIPSTUB__ | __LINE__),
|
|
0,
|
|
NULL,
|
|
0,
|
|
0,
|
|
NULL);
|
|
}
|
|
|
|
(*completionRoutine)(ATnoError, UserData, opaqueBuffer);
|
|
}
|
|
|
|
return(DatagramLength);
|
|
|
|
} // GetMyZoneReply
|
|
|
|
|
|
|
|
|
|
VOID
|
|
GetZoneInfoTimerExpired(
|
|
ULONG TimerId,
|
|
int AdditionalDataSize,
|
|
PCHAR AdditionalData
|
|
)
|
|
{
|
|
PZIP_COMPLETIONINFO completionInfo;
|
|
BOOLEAN getMyZone;
|
|
|
|
// "Use" unused formal.
|
|
UNREFERENCED_PARAMETERS(TimerId);
|
|
|
|
// Verify args.
|
|
if (AdditionalDataSize != sizeof(PZIP_COMPLETIONINFO )) {
|
|
INTERNAL_ERROR(__LINE__ | __ZIPSTUB__, additionalDataSize, NULL, 0);
|
|
return;
|
|
}
|
|
|
|
completionInfo = *(PZIP_COMPLETIONINFO *)AdditionalData;
|
|
|
|
// Bump our expiration count, if there's still time try it again.
|
|
completionInfo->ExpirationCount += 1;
|
|
if (completionInfo->ExpirationCount < GETZONEINFO_RETRIES) {
|
|
|
|
// BUGBUG: TimerId assignment in a critical section...?
|
|
completionInfo->TimerId = StartTimer(
|
|
GetZoneInfoTimerExpired,
|
|
GETZONEINFO_TIMERSECONDS,
|
|
sizeof(PZIP_COMPLETIONINFO),
|
|
(PCHAR)completionInfo);
|
|
|
|
SendZipPacketTo(completionInfo);
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Else, we're out of time, just plead ignorance, close the temporary
|
|
// socket (in turn freeing the completion info), and call the completion
|
|
// routine.
|
|
//
|
|
|
|
getMyZone = (completionInfo->AtpRequestType == ZIP_GETMYZONECOMMAND);
|
|
MoveToOpaque(
|
|
completionInfo->OpaqueBuffer,
|
|
0,
|
|
WILDCARD_ZONE,
|
|
WILDCARD_ZONESIZE);
|
|
|
|
if (!getMyZone) {
|
|
completionInfo->ZoneCount = 1;
|
|
}
|
|
|
|
if (CloseSocketOnNode(completionInfo->Socket) != ATnoError)
|
|
LOG_ERRORONPORT(
|
|
Port,
|
|
EVENT_ATALK_ZIPSOCKETCLOSE,
|
|
(__ZIPSTUB__ | __LINE__),
|
|
completionInfo->Socket,
|
|
NULL,
|
|
0,
|
|
0,
|
|
NULL);
|
|
|
|
if (getMyZone) {
|
|
(*completionInfo->MyZoneCompletionRoutine)(
|
|
ATnoError,
|
|
completionInfo->UserData,
|
|
completionInfo->OpaqueBuffer);
|
|
|
|
} else {
|
|
(*completionInfo->ZoneListCompletionRoutine)(
|
|
ATnoError,
|
|
completionInfo->UserData,
|
|
completionInfo->OpaqueBuffer,
|
|
completionInfo->ZoneCount);
|
|
}
|
|
|
|
AtalkDereferenceZipCompletion(completionInfo, __ZIPSTUB__ | __LINE__);
|
|
return;
|
|
|
|
} // GetZoneInfoTimerExpired
|
|
|
|
|
|
|
|
|
|
LONG
|
|
GetZoneListReply(
|
|
APPLETALK_ERROR ErrorCode,
|
|
ULONG UserData,
|
|
int Port,
|
|
APPLETALK_ADDRESS Source,
|
|
long DestinationSocket,
|
|
int ProtocolType,
|
|
PCHAR Datagram,
|
|
int DatagramLength,
|
|
APPLETALK_ADDRESS ActualDestination
|
|
)
|
|
{
|
|
PZIP_COMPLETIONINFO completionInfo;
|
|
int zoneCount;
|
|
int zoneLength;
|
|
PVOID opaqueBuffer;
|
|
GetZoneListComplete *completionRoutine;
|
|
BOOLEAN lastFlag, formatError = FALSE, overflow = FALSE;
|
|
int datagramIndex;
|
|
PCHAR currentZone;
|
|
int validZones = 0;
|
|
|
|
// "Use" unused formals.
|
|
UNREFERENCED_PARAMETERS(Source);
|
|
UNREFERENCED_PARAMETERS(Port);
|
|
UNREFERENCED_PARAMETERS(ActualDestination);
|
|
|
|
// Get our completionInfo
|
|
completionInfo = (PZIP_COMPLETIONINFO)UserData;
|
|
|
|
|
|
//
|
|
// On most error cases flee -- however, remove our completion info on
|
|
// socket closed.
|
|
//
|
|
|
|
if (ErrorCode == ATsocketClosed) {
|
|
if (previousCompletionInfo == NULL)
|
|
zipCompletionInfoList = completionInfo->Next;
|
|
else
|
|
previousCompletionInfo->Next = completionInfo->Next;
|
|
Free(completionInfo);
|
|
}
|
|
if (ErrorCode != ATnoError or
|
|
ProtocolType != DDPPROTOCOL_ATP or
|
|
DatagramLength < ATPZIP_FIRSTZONEOFFSET) {
|
|
HandleIncomingPackets();
|
|
HandleDeferredTimerChecks();
|
|
return((long)TRUE);
|
|
}
|
|
|
|
// We should have a zone list now.
|
|
|
|
lastFlag = (Datagram[ATPZIP_LASTFLAGOFFSET] != 0);
|
|
zoneCount = (Datagram[ATPZIP_ZONECOUNTOFFSET] << 8);
|
|
zoneCount += (unsigned char)(Datagram[ATPZIP_ZONECOUNTOFFSET + 1]);
|
|
if (zoneCount == 0)
|
|
lastFlag = TRUE;
|
|
datagramIndex = ATPZIP_FIRSTZONEOFFSET;
|
|
while (zoneCount > 0) {
|
|
// Pull out the next zoneLength/zone pair.
|
|
|
|
if (DatagramIndex + 1 > DatagramLength) {
|
|
formatError = TRUE;
|
|
break;
|
|
}
|
|
zoneLength = (unsigned char)Datagram[datagramIndex];
|
|
if (zoneLength == 0 or
|
|
zoneLength > MAXIMUM_ZONELENGTH) {
|
|
formatError = TRUE;
|
|
break;
|
|
}
|
|
datagramIndex += 1;
|
|
if (datagramIndex + zoneLength > DatagramLength) {
|
|
formatError = TRUE;
|
|
break;
|
|
}
|
|
currentZone = Datagram + datagramIndex;
|
|
datagramIndex += zoneLength;
|
|
|
|
// Place the new zone into the user's buffer.
|
|
|
|
if (completionInfo->NextZoneOffset + zoneLength + 1 >
|
|
completionInfo->BufferSize) {
|
|
overflow = TRUE;
|
|
break;
|
|
}
|
|
MoveToOpaque(completionInfo->OpaqueBuffer, completionInfo->NextZoneOffset,
|
|
currentZone, zoneLength);
|
|
MoveToOpaque(completionInfo->OpaqueBuffer,
|
|
completionInfo->NextZoneOffset + zoneLength, "", 1);
|
|
completionInfo->NextZoneOffset += (zoneLength + 1);
|
|
completionInfo->ZoneCount += 1;
|
|
validZones += 1;
|
|
zoneCount -= 1;
|
|
}
|
|
|
|
//
|
|
// The next one we'll want will be past the ones we've just read. If
|
|
// we've had a format error or we don't have them all yet, retry the
|
|
// request.
|
|
//
|
|
|
|
completionInfo->ZoneListIndex += validZones;
|
|
if (formatError or (not overflow and not lastFlag)) {
|
|
SendZipPacketTo(completionInfo);
|
|
HandleIncomingPackets();
|
|
HandleDeferredTimerChecks();
|
|
return((long)TRUE);
|
|
}
|
|
|
|
//
|
|
// Otherwise, we're set, either due to overflow or we have them all:
|
|
// cancel the retry timer, close our socket [this will cause
|
|
// a recursive call which will remove the completion info], call the
|
|
// completion routine, flee.
|
|
//
|
|
|
|
CancelTimer(completionInfo->TimerId);
|
|
opaqueBuffer = completionInfo->OpaqueBuffer;
|
|
completionRoutine = completionInfo->ZoneListCompletionRoutine;
|
|
UserData = completionInfo->UserData;
|
|
zoneCount = completionInfo->ZoneCount;
|
|
if (CloseSocketOnNode(completionInfo->Socket) != ATnoError)
|
|
LOG_ERRORONPORT(
|
|
Port,
|
|
EVENT_ATALK_ZIPSOCKETCLOSE,
|
|
(__ZIPSTUB__ | __LINE__),
|
|
0,
|
|
NULL,
|
|
0,
|
|
0,
|
|
NULL);
|
|
|
|
ErrorLog("GetZoneListReply", ISevError, __LINE__, Port,
|
|
IErrZipStubBadSocketClose, IMsgZipStubBadSocketClose,
|
|
Insert0());
|
|
|
|
HandleIncomingPackets();
|
|
HandleDeferredTimerChecks();
|
|
if (overflow)
|
|
ErrorCode = ATzipBufferTooSmall;
|
|
else
|
|
ErrorCode = ATnoError;
|
|
(*completionRoutine)(ErrorCode, UserData, opaqueBuffer, zoneCount);
|
|
|
|
return((long)TRUE);
|
|
|
|
} // GetZoneListReply
|
|
|
|
|
|
|
|
PZIP_COMPLETIONINFO
|
|
AllocateZipCompletionInfo(
|
|
VOID
|
|
)
|
|
{
|
|
PZIP_COMPLETIONINFO info;
|
|
|
|
if ((info = (PZIP_COMPLETIONINFO)Calloc(ZIP_COMPLETIONSIZE, 1)) != NULL) {
|
|
|
|
info->Type = ZIP_COMPLETIONTYPE;
|
|
info->Size = ZIP_COMPLETIONSIZE;
|
|
|
|
InitializeListHead(&info->Linkage);
|
|
}
|
|
|
|
return(info);
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
AtalkRefZipCompletion(
|
|
PZIP_COMPLETIONINFO ZipCompletion
|
|
)
|
|
{
|
|
ASSERT(ZipCompletion->ReferenceCount >= 0);
|
|
ZipCompletion->ReferenceCount++;
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
|
|
VOID
|
|
AtalkDerefZipCompletion(
|
|
PZIP_COMPLETIONINFO ZipCompletion
|
|
)
|
|
{
|
|
ASSERT(ZipCompletion->ReferenceCount > 0);
|
|
if (--ZipCompletion->ReferenceCount > 0) {
|
|
return;
|
|
}
|
|
|
|
// Reference count is now zero, remove from list and free it up
|
|
RemoveEntryList (&ZipCompletion->Linkage);
|
|
InitializeListHead (&ZipCompletion->Linkage);
|
|
|
|
Free(ZipCompletion);
|
|
return;
|
|
}
|
|
|