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.
435 lines
10 KiB
435 lines
10 KiB
/*++
|
|
|
|
Copyright (c) 1991 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
atalk.c
|
|
|
|
Abstract:
|
|
|
|
This module is the main file for the portable code. It contains the globals
|
|
for the portable stack and the ref/deref code for it
|
|
|
|
Notes:
|
|
|
|
LOCKS:
|
|
The portable stack uses the following locks for all its critical section
|
|
requirements. There are no locks within any structures. Only these locks
|
|
will be used even for per-structure critical sections.
|
|
|
|
GLOBAL_STACK
|
|
This lock provides critical sections over the whole stack. Used for
|
|
referencing/dereferencing stack usage.
|
|
|
|
GLOBAL_DDP
|
|
This lock provides critical sections for the ddp structures and module.
|
|
It protects the following structures-
|
|
OPEN_SOCKET
|
|
ACTIVE_NODE
|
|
PORT_DESCRIPTOR
|
|
|
|
GLOBAL_ROUTING
|
|
This lock provides safety for all structures/operations associated
|
|
with routing, and hence is used in rtmp/zip/nbp modules.
|
|
|
|
GLOBAL_ATP
|
|
GLOBAL_RTMP
|
|
GLOBAL_AEP
|
|
GLOBAL_NBP
|
|
GLOBAL_AURP
|
|
GLOBAL_ARAP
|
|
GLOBAL_ADSP
|
|
GLOBAL_ASP
|
|
GLOBAL_PAP
|
|
|
|
The reference/dereference routines have the following semantics due to this
|
|
paradigm.
|
|
AtalkRefXXX must always be called from within a critical section. It is
|
|
upto the caller to ensure this happens.
|
|
|
|
AtalkDerefX must always be called from *outside* a critical section. It
|
|
is upto the caller to ensure this happens. Note that the
|
|
dereference functionality will most probably lead to a lot
|
|
of activity some of which may try to acquire the same locks
|
|
as Deref does. Also, deref does a lot more work than ref.
|
|
Hence, it must be outside a critical section.
|
|
|
|
|
|
Author:
|
|
|
|
Nikhil Kamkolkar Initial Coding
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
|
|
|
|
#define GLOBALS
|
|
#include "atalk.h"
|
|
|
|
|
|
|
|
VOID
|
|
UnloadAppleTalk(
|
|
UNLOAD_COMPLETION *CompletionRoutine,
|
|
PVOID Context
|
|
)
|
|
{
|
|
int index;
|
|
|
|
//
|
|
// Stop all new AppleTalk activity (geting nodes, opening sockets, starting
|
|
// timers, etc.)
|
|
//
|
|
|
|
if (!AtalkReferenceStack(__LINE__ | __INITIAL__) {
|
|
|
|
// We must already be unloading
|
|
return;
|
|
}
|
|
|
|
EnterCriticalSection(GLOBAL_STACK);
|
|
if (AppletalkRunning) {
|
|
AppletalkRunning = FALSE;
|
|
UnloadCompletion = CompletionRoutine;
|
|
UnloadContext = Context;
|
|
}
|
|
LeaveCriticalSection(GLOBAL_STACK);
|
|
|
|
// Stop timer handling.
|
|
StopTimerHandling();
|
|
|
|
// Force the shutdown of all ports.
|
|
for (index = 0; index < NumberOfPortsAllocated; index += 1)
|
|
if (GET_PORTDESCRIPTOR(index)->Flags & PD_ACTIVE)
|
|
ShutdownPort(index, True);
|
|
|
|
//
|
|
// Let the various protocol levels know that they need to restart timers
|
|
// when we get started again.
|
|
//
|
|
|
|
ShutdownErrorLogging();
|
|
ShutdownAarp();
|
|
ShutdownRtmpStub();
|
|
#if Iam an AppleTalkRouter
|
|
ShutdownFullRtmp();
|
|
ShutdownFullZip();
|
|
#endif
|
|
|
|
#if Iam an AppleTalkStack
|
|
ShutdownAsp();
|
|
#endif
|
|
|
|
// Free the routing tables and the best-routes cache.
|
|
#if Iam an AppleTalkRouter
|
|
ReleaseRoutingTable();
|
|
#endif
|
|
|
|
#if ArapIncluded
|
|
ShutdownArap();
|
|
desdone();
|
|
#endif
|
|
|
|
//
|
|
// All set... the next call to Initialize() will bring everything back up
|
|
// again.
|
|
//
|
|
|
|
AtalkDereferenceStack(__INITIAL__ | __LINE__ ); // Temporary reference
|
|
AtalkDereferenceStack(__INITIAL__ | __LINE__ ); // Creation reference
|
|
return;
|
|
|
|
} // UnloadAppleTalk
|
|
|
|
|
|
|
|
|
|
VOID
|
|
AtalkRefStack(
|
|
VOID
|
|
)
|
|
{
|
|
ASSERT(AtalkReferenceCount >= 0);
|
|
AtalkReferenceCount++;
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
|
|
VOID
|
|
AtalkDerefStack(
|
|
VOID
|
|
)
|
|
{
|
|
EnterCriticalSection(GLOBAL_STACK);
|
|
ASSERT(AtalkReferenceCount > 0);
|
|
do {
|
|
if (--AtalkReferenceCount) {
|
|
LeaveCriticalSection(GLOBAL_STACK);
|
|
break;
|
|
}
|
|
|
|
LeaveCriticalSection(GLOBAL_STACK);
|
|
|
|
// No more references to the stack, call unload completion
|
|
if (AtalkUnloadComplete) {
|
|
(*AtalkUnloadComplete)(UnloadCompleteContext);
|
|
}
|
|
break;
|
|
|
|
} while (FALSE);
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
|
|
BOOLEAN
|
|
AtalkVerifyStack(
|
|
ULONG Location
|
|
)
|
|
{
|
|
ASSERT(AtalkReferenceCount >= 0);
|
|
|
|
if (AppletalkRunning) {
|
|
OpenSocket->ReferenceCount++;
|
|
}
|
|
|
|
return(AppletalkRunning);
|
|
}
|
|
|
|
|
|
|
|
|
|
BOOLEAN
|
|
AtalkVerifyStackInterlocked(
|
|
ULONG Location
|
|
)
|
|
{
|
|
BOOLEAN result;
|
|
|
|
EnterCriticalSection(GLOBAL_STACK);
|
|
result = AtalkVerifyStack(Location);
|
|
LeaveCriticalSection(GLOBAL_STACK);
|
|
|
|
return(result);
|
|
}
|
|
|
|
|
|
|
|
|
|
BOOLEAN
|
|
ShutdownPort(
|
|
int Port,
|
|
BOOLEAN Force
|
|
)
|
|
{
|
|
AddressMappingNode addressMappingNode, nextAddressMappingNode;
|
|
int index;
|
|
|
|
//
|
|
// If we're a stack, not just a router, we can't allow the default port
|
|
// to be stopped. Also, we can't shutdown if we're the default port and
|
|
// there are any currently active remote access ports... we're where the
|
|
// proxy nodes live.
|
|
//
|
|
|
|
#if Iam an AppleTalkStack
|
|
if (not force && GET_PORTDESCRIPTOR(Port)->DefaultPort) {
|
|
ErrorLog("ShutdownPort", ISevError, __LINE__, port,
|
|
IErrInitialShutdownDefault, IMsgInitialShutdownDefault,
|
|
Insert0());
|
|
return(False);
|
|
}
|
|
#endif
|
|
if (not force && GET_PORTDESCRIPTOR(Port)->DefaultPort)
|
|
for (index = 0; index < NumberOfPortsAllocated; index += 1)
|
|
if (GET_PORTDESCRIPTOR(index)->PortType is AppleTalkRemoteAccess and
|
|
GET_PORTDESCRIPTOR(index)->Flags & PD_ACTIVE) {
|
|
ErrorLog("ShutdownPort", ISevError, __LINE__, port,
|
|
IErrInitialShutdownDefault, IMsgInitialShutdownDefault,
|
|
Insert0());
|
|
return(False);
|
|
}
|
|
|
|
//
|
|
// Do all that we need to stop the operation of a specified port (a slot
|
|
// in the portDescriptors table). Free all memory that we can, and mark
|
|
// the slot as inactive.
|
|
//
|
|
|
|
if (not GET_PORTDESCRIPTOR(Port)->Flags & PD_ACTIVE)
|
|
return(False); // Already not operating.
|
|
|
|
// Stop routing, if needed.
|
|
|
|
#if Iam an AppleTalkRouter
|
|
if (GET_PORTDESCRIPTOR(Port)->RoutingPort and
|
|
GET_PORTDESCRIPTOR(Port)->SeenRouterRecently)
|
|
RemoveFromRoutingTable(GET_PORTDESCRIPTOR(Port)->ThisCableRange);
|
|
if (GET_PORTDESCRIPTOR(Port)->RoutingPort and
|
|
GET_PORTDESCRIPTOR(Port)->RouterRunning)
|
|
if (not StopRouterOnPort(port))
|
|
return(False);
|
|
#endif
|
|
|
|
//
|
|
// Free all of our remaining nodes. This loop will stop when we've freed
|
|
// 'em all (they will get removed from the head of the list). This will
|
|
// inturn close of the open sockets and signal this actual up the stack,
|
|
// as needed. If we're a remote access port, just free the single proxy
|
|
// node! If we're the default port and shutting down proxy nodes for remote
|
|
// access ports, shutdown the remote access port (that will inturn cause
|
|
// the proxy node to be freed.
|
|
//
|
|
|
|
if (GET_PORTDESCRIPTOR(Port)->PortType is AppleTalkRemoteAccess) {
|
|
#if ArapIncluded
|
|
TeardownConnection(port);
|
|
#endif
|
|
ReleaseNodeOnPort(GET_PORTDESCRIPTOR(Port)->RemoteAccessInfo->proxyPort,
|
|
GET_PORTDESCRIPTOR(Port)->RemoteAccessInfo->proxyNode->
|
|
extendedNode);
|
|
Free(GET_PORTDESCRIPTOR(Port)->RemoteAccessInfo);
|
|
}
|
|
else
|
|
while (GET_PORTDESCRIPTOR(Port)->ActiveNodes != Empty)
|
|
if (GET_PORTDESCRIPTOR(Port)->ActiveNodes->proxyNode)
|
|
ShutdownPort(GET_PORTDESCRIPTOR(Port)->ActiveNodes->proxyPort, force);
|
|
else
|
|
ReleaseNodeOnPort(port,
|
|
GET_PORTDESCRIPTOR(Port)->ActiveNodes->extendedNode);
|
|
|
|
// Don't be bothered while we're playing with in-memory structures.
|
|
|
|
DeferTimerChecking();
|
|
DeferIncomingPackets();
|
|
|
|
// Okay, free all the memory used by this port's structures.
|
|
|
|
FreeZoneList(GET_PORTDESCRIPTOR(Port)->InitialZoneList);
|
|
#if Iam an AppleTalkRouter
|
|
FreeZoneList(GET_PORTDESCRIPTOR(Port)->ThisZoneList);
|
|
#endif
|
|
#if (IamNot a DOS) && (IamNot an OS2)
|
|
if (GET_PORTDESCRIPTOR(Port)->ControllerInfo != Empty)
|
|
Free(GET_PORTDESCRIPTOR(Port)->ControllerInfo);
|
|
#endif
|
|
|
|
// Okay, now free all address mapping table chains.
|
|
|
|
for (index = 0; index < NumberOfAddressMapHashBuckets; index += 1)
|
|
for (addressMappingNode = GET_PORTDESCRIPTOR(Port)->AddressMappingTable[index];
|
|
addressMappingNode != Empty;
|
|
addressMappingNode = nextAddressMappingNode) {
|
|
nextAddressMappingNode = addressMappingNode->next;
|
|
Free(addressMappingNode);
|
|
}
|
|
|
|
// All set
|
|
GET_PORTDESCRIPTOR(Port)->Flags & PD_ACTIVE = False;
|
|
|
|
HandleIncomingPackets();
|
|
HandleDeferredTimerChecks();
|
|
return(True);
|
|
|
|
} // ShutdownPort
|
|
|
|
|
|
|
|
|
|
VOID
|
|
AtalkRefPortDescriptor(
|
|
PPORT_DESCRIPTOR PortDescriptor
|
|
)
|
|
{
|
|
ASSERT(PortDescriptor->ReferenceCount >= 0);
|
|
PortDescriptor->ReferenceCount++;
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
|
|
PPORT_DESCRIPTOR
|
|
AtalkVerifyPortDescriptor(
|
|
PPORT_DESCRIPTOR PortDescriptor,
|
|
ULONG Location
|
|
)
|
|
{
|
|
PPORT_DESCRIPTOR portDesc = PortDescriptor;
|
|
|
|
ASSERT(PortDescriptor->ReferenceCount >= 0);
|
|
if ((PortDescriptor->Flags & PD_CLOSING) == 0) {
|
|
AtalkReferencePortDescriptor(PortDescriptor, Location);
|
|
} else {
|
|
portDesc = NULL;
|
|
}
|
|
|
|
return(portDesc);
|
|
}
|
|
|
|
|
|
|
|
|
|
PPORT_DESCRIPTOR
|
|
AtalkVerifyPortDescriptorInterlocked(
|
|
PPORT_DESCRIPTOR PortDescriptor,
|
|
ULONG Location
|
|
)
|
|
{
|
|
PPORT_DESCRIPTOR portDesc = PortDescriptor;
|
|
|
|
EnterCriticalSection(GLOBAL_DDP);
|
|
ASSERT(PortDescriptor->ReferenceCount >= 0);
|
|
if ((PortDescriptor->Flags & PD_CLOSING) == 0) {
|
|
AtalkReferencePortDescriptor(PortDescriptor, Location);
|
|
} else {
|
|
portDesc = NULL;
|
|
}
|
|
LeaveCriticalSection(GLOBAL_DDP);
|
|
|
|
return(portDesc);
|
|
}
|
|
|
|
|
|
|
|
|
|
VOID
|
|
AtalkDerefPortDescriptor(
|
|
PPORT_DESCRIPTOR PortDescriptor
|
|
)
|
|
{
|
|
EnterCriticalSection(GLOBAL_DDP);
|
|
ASSERT(PortDescriptor->ReferenceCount > 0);
|
|
if (--PortDescriptor->ReferenceCount > 0) {
|
|
LeaveCriticalSection(GLOBAL_DDP);
|
|
return;
|
|
}
|
|
|
|
|
|
// No more references on this port, shutdown port is complete
|
|
ASSERT(PortDescriptor->Flags & PD_CLOSING);
|
|
if ((PortDescriptor->Flags & PD_CLOSING) == 0) {
|
|
LeaveCriticalSection(GLOBAL_DDP);
|
|
INTERNAL_ERROR(__LINE__ | __INITIAL__, PortDescriptor->Flags, NULL, 0);
|
|
return;
|
|
}
|
|
PortDescriptor->Flags = 0;
|
|
LeaveCriticalSection(GLOBAL_DDP);
|
|
|
|
FreeZoneList(PortDescriptor->ZoneList);
|
|
|
|
// Dereference the stack for this port
|
|
AtalkDereferenceStack(__INITIAL__ | __LINE__);
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
|