windows-nt/Source/XPSP1/NT/net/sfm/atalk/sys/atkinit.c
2020-09-26 16:20:57 +08:00

2396 lines
60 KiB
C

/*++
Copyright (c) 1992 Microsoft Corporation
Module Name:
atkinit.c
Abstract:
This module contains the initialization code for the Appletalk stack.
Author:
Jameel Hyder (jameelh@microsoft.com)
Nikhil Kamkolkar (nikhilk@microsoft.com)
Revision History:
19 Jun 1992 Initial Version
Notes: Tab stop: 4
--*/
#include <atalk.h>
#pragma hdrstop
#define FILENUM ATKINIT
#ifdef ALLOC_PRAGMA
#pragma alloc_text(INIT, AtalkInitializeTransport)
#pragma alloc_text(PAGEINIT, atalkInitGetHandleToKey)
#pragma alloc_text(PAGEINIT, atalkInitGlobal)
#pragma alloc_text(PAGEINIT, atalkInitPort)
#pragma alloc_text(PAGEINIT, atalkInitNetRangeCheck)
#pragma alloc_text(PAGEINIT, atalkInitNetRange)
#pragma alloc_text(PAGEINIT, atalkInitZoneList)
#pragma alloc_text(PAGEINIT, atalkInitDefZone)
#pragma alloc_text(PAGEINIT, atalkInitSeeding)
#pragma alloc_text(PAGEINIT, atalkInitPortParameters)
#pragma alloc_text(PAGEINIT, atalkInitStartPort)
#pragma alloc_text(PAGEINIT, AtalkInitAdapter)
#pragma alloc_text(PAGEINIT, AtalkDeinitAdapter)
#pragma alloc_text(PAGEINIT, atalkInitStartPort)
#endif
NTSTATUS
AtalkInitializeTransport(
IN PDRIVER_OBJECT pDrvObj,
IN PUNICODE_STRING pRegPath
)
/*++
Routine Description:
This routine is called during initialization time to
initialize the transport.
Arguments:
Return Value:
Status - STATUS_SUCCESS if initialized,
Appropriate NT error code otherwise
--*/
{
PPORT_DESCRIPTOR pPortDesc;
NTSTATUS status;
do
{
// Initialize the default-port event
KeInitializeEvent(&AtalkDefaultPortEvent, NotificationEvent, FALSE);
// Save our registry path
if ((AtalkRegPath.Buffer = AtalkAllocMemory(pRegPath->Length)) == NULL)
{
status = STATUS_INSUFFICIENT_RESOURCES;
RES_LOG_ERROR();
break;
}
AtalkRegPath.MaximumLength =
AtalkRegPath.Length = pRegPath->Length;
RtlCopyMemory(AtalkRegPath.Buffer,
pRegPath->Buffer,
pRegPath->Length);
AtalkInitMemorySystem();
// Get the frequency of the performance counters
KeQueryPerformanceCounter(&AtalkStatistics.stat_PerfFreq);
// Initialize the timer subsystem
if (!NT_SUCCESS(status = AtalkTimerInit()) ||
!NT_SUCCESS(status = AtalkZipInit(TRUE)))
{
RES_LOG_ERROR();
break;
}
// Initialize the global port descriptors
AtalkPortList = NULL;
AtalkDefaultPort = NULL;
AtalkNumberOfPorts = 0;
AtalkRouter = FALSE;
// Get the global parameters
status = atalkInitGlobal();
if (!NT_SUCCESS(status))
{
DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_ERR,
("AtalkInitializeTransport: AtalkInitGlobal failed %ul\n", status));
break;
}
if (!NT_SUCCESS(status = AtalkNdisInitRegisterProtocol()))
{
break;
}
} while (FALSE);
if (NT_SUCCESS(status))
{
#if DBG
AtalkTimerInitialize(&AtalkDumpTimerList,
AtalkDumpComponents,
DBG_DUMP_DEF_INTERVAL);
AtalkTimerScheduleEvent(&AtalkDumpTimerList);
#endif
// Initialize the other subsystems now
AtalkInitAspInitialize();
AtalkInitPapInitialize();
AtalkInitAdspInitialize();
}
else
{
DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_ERR,
("Initialization failed!\n"));
// We are not loading. Stop everything and return.
// Stop all ports, release port resources
// Stop the timer subsystem if it was started
AtalkCleanup();
}
return status;
}
NTSTATUS
atalkInitGetHandleToKey(
IN PUNICODE_STRING KeyName,
OUT PHANDLE KeyHandle
)
/*++
Routine Description:
Returns the handle for the key specified using SectionHandle as the
root.
Arguments:
SectionHandle - Key to registry tree root
KeyNameString - name of key to be opened
KeyHandle - Returns the handle for KeyNameString
Return Value:
The status of the request.
--*/
{
HANDLE ConfigHandle;
NTSTATUS status;
OBJECT_ATTRIBUTES ObjectAttributes;
*KeyHandle = NULL;
InitializeObjectAttributes(&ObjectAttributes,
&AtalkRegPath, // name
OBJ_CASE_INSENSITIVE, // attributes
NULL, // root
NULL); // security descriptor
status = ZwOpenKey(&ConfigHandle,
KEY_READ,
&ObjectAttributes);
if (NT_SUCCESS(status))
{
InitializeObjectAttributes(&ObjectAttributes,
KeyName, // name
OBJ_CASE_INSENSITIVE, // attributes
ConfigHandle, // root
NULL); // security descriptor
status = ZwOpenKey(KeyHandle,
KEY_READ,
&ObjectAttributes);
ZwClose(ConfigHandle);
}
return status;
}
NTSTATUS
atalkInitGlobal(
VOID
)
/*++
Routine Description:
Reads the Parameters key to get the global parameters. These are:
- DefaultPort
- DesiredZOne
- EnableRouter
- FilterOurNames
Arguments:
Return Value:
Status - STATUS_SUCCESS
Or other NT status codes
--*/
{
UNICODE_STRING valueName, unicodePortName, unicodeZone;
UNICODE_STRING rasName;
HANDLE ParametersHandle;
ANSI_STRING ansiZone;
BYTE ansiBuf[MAX_ENTITY_LENGTH+1];
NTSTATUS status;
ULONG bytesWritten;
PWCHAR portName;
PWCHAR desiredZoneValue;
PCHAR asciiDesiredZone = NULL;
BYTE Storage[2*2*MAX_ENTITY_LENGTH+sizeof(KEY_VALUE_FULL_INFORMATION)];
PKEY_VALUE_FULL_INFORMATION Info = (PKEY_VALUE_FULL_INFORMATION)Storage;
PULONG Value;
do
{
// Open the parameters key.
RtlInitUnicodeString(&valueName, PARAMETERS_STRING);
status = atalkInitGetHandleToKey(&valueName,
&ParametersHandle);
if (!NT_SUCCESS(status))
{
break;
}
// Read the "EnableRouter" value name
RtlInitUnicodeString (&valueName, VALUENAME_ENABLEROUTER);
status = ZwQueryValueKey(ParametersHandle,
&valueName,
KeyValueFullInformation,
Info,
sizeof(Storage),
&bytesWritten);
if (status == STATUS_SUCCESS)
{
Value = (PULONG)((PBYTE)Info + Info->DataOffset);
if (*Value != 0)
{
// if router wasn't running before, change that! (PnP case)
if (!AtalkRouter)
{
AtalkRouter = TRUE;
AtalkRtmpInit(TRUE);
AtalkLockRouterIfNecessary();
}
}
else
{
AtalkRouter = FALSE;
}
}
else
{
DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_ERR,
("atalkInitGlobal: EnableRouter value not found, assuming false\n"));
}
// Read the "FilterOurNames" value name
RtlInitUnicodeString (&valueName, VALUENAME_FILTEROURNAMES);
status = ZwQueryValueKey(ParametersHandle,
&valueName,
KeyValueFullInformation,
Info,
sizeof(Storage),
&bytesWritten);
if (status == STATUS_SUCCESS)
{
Value = (PULONG)((PBYTE)Info + Info->DataOffset);
if (*Value == 0)
{
AtalkFilterOurNames = FALSE;
}
}
else
{
DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_WARN,
("atalkInitGlobal: FilterOurNames value not found, assuming true\nq"));
}
// Get the default port value
RtlInitUnicodeString (&valueName, VALUENAME_DEFAULTPORT);
status = ZwQueryValueKey(ParametersHandle,
&valueName,
KeyValueFullInformation,
Info,
sizeof(Storage),
&bytesWritten);
if (status != STATUS_SUCCESS)
{
// No default port keyword specified! ABORT
LOG_ERROR(EVENT_ATALK_NO_DEFAULTPORT, status, NULL, 0);
ZwClose(ParametersHandle);
// let appletalk run: it's just that it won't have default adapter
status = STATUS_SUCCESS;
break;
}
portName = (PWCHAR)((PBYTE)Info + Info->DataOffset);
AtalkDefaultPortName.Buffer = NULL;
if (*portName != 0)
{
RtlInitUnicodeString(&unicodePortName, portName);
RtlInitUnicodeString(&rasName,RAS_ADAPTER_NAME);
// make sure this isn't RAS adapter (setup bug)
if (RtlEqualUnicodeString(&unicodePortName,&rasName,TRUE))
{
DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_ERR,
("atalkInitGlobal: can't have RAS adapter as default adapter!\n"));
// No default port keyword specified! ABORT
LOG_ERROR(EVENT_ATALK_NO_DEFAULTPORT, status, NULL, 0);
ZwClose(ParametersHandle);
status = STATUS_INVALID_PARAMETER;
break;
}
AtalkDefaultPortName.Buffer = AtalkAllocMemory(unicodePortName.Length);
if (AtalkDefaultPortName.Buffer != NULL)
{
AtalkDefaultPortName.Length =
AtalkDefaultPortName.MaximumLength = unicodePortName.Length;
RtlCopyMemory(AtalkDefaultPortName.Buffer,
unicodePortName.Buffer,
unicodePortName.Length);
}
}
if (AtalkDefaultPortName.Buffer == NULL)
{
LOG_ERROR(EVENT_ATALK_NO_DEFAULTPORT, status, NULL, 0);
DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_ERR,
("WARNING!!! Appletalk driver running, but no default port configured\n"));
ZwClose(ParametersHandle);
// let appletalk run: it's just that it won't have default adapter
status = STATUS_SUCCESS;
break;
}
// Get the desired zone value in the form of an asciiz string
RtlInitUnicodeString (&valueName, VALUENAME_DESIREDZONE);
status = ZwQueryValueKey(ParametersHandle,
&valueName,
KeyValueFullInformation,
Info,
sizeof(Storage),
&bytesWritten);
// Close this handle now - we do not need it anymore
ZwClose(ParametersHandle);
ParametersHandle = NULL;
if (status != STATUS_SUCCESS)
{
LOG_ERROR(EVENT_ATALK_INVALID_DESIREDZONE, status, NULL, 0);
status = STATUS_SUCCESS;
break;
}
desiredZoneValue = (PWCHAR)((PBYTE)Info + Info->DataOffset);
if (*desiredZoneValue != 0)
{
RtlInitUnicodeString(&unicodeZone, desiredZoneValue);
ansiZone.Length = (USHORT)RtlUnicodeStringToAnsiSize(&unicodeZone)-1;
if (ansiZone.Length > MAX_ENTITY_LENGTH)
{
status = STATUS_UNSUCCESSFUL;
// Incorrect zone name!
LOG_ERROR(EVENT_ATALK_INVALID_DESIREDZONE, status, NULL, 0);
break;
}
ansiZone.Buffer = ansiBuf;
ansiZone.MaximumLength = sizeof(ansiBuf);
status = RtlUnicodeStringToAnsiString(&ansiZone,
&unicodeZone,
(BOOLEAN)FALSE);
if (status == STATUS_SUCCESS)
{
AtalkDesiredZone = AtalkZoneReferenceByName(ansiBuf, (BYTE)(ansiZone.Length));
}
if ((status != STATUS_SUCCESS) ||
(AtalkDesiredZone == NULL))
{
LOG_ERROR(EVENT_ATALK_RESOURCES, status, NULL, 0);
}
}
} while (FALSE);
return status;
}
NTSTATUS
atalkInitPort(
IN PPORT_DESCRIPTOR pPortDesc,
IN HANDLE AdaptersHandle
)
/*++
Routine Description:
This routine is called during initialization time to get the per port
parameters from the registry. It will store the per port parameters
in the port information structures readying them to be passed to the main
initialize() routine
Arguments:
AdaptersHandle- Handle to the ...\Parameters\Adapters key in registry
Return Value:
Status - STATUS_SUCCESS
STATUS_INSUFFICIENT_RESOURCES
--*/
{
OBJECT_ATTRIBUTES ObjectAttributes;
NTSTATUS status;
BOOLEAN seeding;
// Get the key to the adapter for this port
InitializeObjectAttributes(&ObjectAttributes,
&pPortDesc->pd_AdapterKey, // name
OBJ_CASE_INSENSITIVE, // attributes
AdaptersHandle, // root
NULL); // security descriptor
status = ZwOpenKey(&pPortDesc->pd_AdapterInfoHandle,
KEY_READ,
&ObjectAttributes);
if (!NT_SUCCESS(status))
{
if (!AtalkRouter)
status = STATUS_SUCCESS;
return status;
}
//
// if this is the first time the adapter is being initialized (usually the case),
// read the PramNodes from the registry. If we are initializing this adapter on
// a PnP event, then there is a good chance our network config has changed, so
// ignore the registry values and get fresh ones)
//
if (!(pPortDesc->pd_Flags & PD_CONFIGURED_ONCE))
{
pPortDesc->pd_Flags |= PD_CONFIGURED_ONCE;
// Get PRAM Information
AtalkInitNodeGetPramAddr(pPortDesc,
ROUTER_NODE_VALUE,
&pPortDesc->pd_RoutersPramNode);
AtalkInitNodeGetPramAddr(pPortDesc,
USER_NODE1_VALUE,
&pPortDesc->pd_UsersPramNode1);
AtalkInitNodeGetPramAddr(pPortDesc,
USER_NODE2_VALUE,
&pPortDesc->pd_UsersPramNode2);
}
else
{
ASSERT(pPortDesc->pd_RoutersPramNode.atn_Network == 0);
ASSERT(pPortDesc->pd_RoutersPramNode.atn_Node == 0);
ASSERT(pPortDesc->pd_UsersPramNode1.atn_Network == 0);
ASSERT(pPortDesc->pd_UsersPramNode1.atn_Node == 0);
ASSERT(pPortDesc->pd_UsersPramNode2.atn_Network == 0);
ASSERT(pPortDesc->pd_UsersPramNode2.atn_Node == 0);
}
// If we are a router, get the following information
if (AtalkRouter)
{
if (!DEF_PORT(pPortDesc))
{
AtalkZapPramValue(pPortDesc, USER_NODE1_VALUE);
AtalkZapPramValue(pPortDesc, USER_NODE2_VALUE);
}
atalkInitSeeding(pPortDesc, &seeding);
// Check following values only if the seeding flag is set.
if (seeding) do
{
// Get the Network range information. Value names are
// NetworkRangeLowerEnd & NetworkRangeUpperEnd
status = atalkInitNetRange(pPortDesc);
if (!NT_SUCCESS(status))
{
LOG_ERRORONPORT(pPortDesc,
EVENT_ATALK_SEEDROUTER_NONETRANGE,
0,
NULL,
0);
DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_ERR,
("atalkInitPort: Could not get network range\n"));
break;
}
status = atalkInitNetRangeCheck(pPortDesc);
if (!NT_SUCCESS(status))
{
break;
}
// Get the Zone list information. Value name is ZoneList
status = atalkInitZoneList(pPortDesc);
if (!NT_SUCCESS(status))
{
LOG_ERRORONPORT(pPortDesc,
EVENT_ATALK_SEEDROUTER_NOZONELIST,
0,
NULL,
0);
DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_ERR,
("atalkInitPort: Could not get zone list\n"));
break;
}
// Get the default zone specification. Value name is DefaultZone
status = atalkInitDefZone(pPortDesc);
if (!NT_SUCCESS(status))
{
DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_ERR,
("atalkInitPort: Could not get default zone\n"));
break;
}
// Check for default zone being in the zone list for the port
// Also make sure that a localtalk port is not specified
// as the default port. And that a default zone was not
// specified for a localtalk port. We can only do this after
// bind as we do not know until then the media type.
if (pPortDesc->pd_Flags & PD_SEED_ROUTER)
{
if (pPortDesc->pd_InitialDefaultZone == NULL)
{
LOG_ERRORONPORT(pPortDesc,
EVENT_ATALK_NO_DEFZONE,
0,
NULL,
0);
status = STATUS_UNSUCCESSFUL;
break;
}
if (pPortDesc->pd_InitialZoneList == NULL)
{
LOG_ERRORONPORT(pPortDesc,
EVENT_ATALK_SEEDROUTER_NOZONELIST,
0,
NULL,
0);
status = STATUS_UNSUCCESSFUL;
break;
}
if (!AtalkZoneOnList(pPortDesc->pd_InitialDefaultZone,
pPortDesc->pd_InitialZoneList))
{
LOG_ERRORONPORT(pPortDesc,
EVENT_ATALK_ZONE_NOTINLIST,
0,
NULL,
0);
status = STATUS_UNSUCCESSFUL;
break;
}
}
} while (FALSE);
}
else
{
AtalkZapPramValue(pPortDesc, ROUTER_NODE_VALUE);
}
if (NT_SUCCESS(status)) do
{
// Get the per-Port parameters
status = atalkInitPortParameters(pPortDesc);
if (!NT_SUCCESS(status))
{
DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_ERR,
("atalkInitPort: Could not get port parameters\n"));
}
// None of the above affect us loading.
status = STATUS_SUCCESS;
break;
} while (FALSE);
return status;
}
NTSTATUS
atalkInitNetRangeCheck(
IN PPORT_DESCRIPTOR pPortDesc
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
PPORT_DESCRIPTOR pTmp;
NTSTATUS status = STATUS_SUCCESS;
do
{
// Check for network range overlap among all the ports
for (pTmp = AtalkPortList;
pTmp != NULL;
pTmp = pTmp->pd_Next)
{
if (pTmp != pPortDesc)
{
if ((pPortDesc->pd_InitialNetworkRange.anr_FirstNetwork != UNKNOWN_NETWORK) &&
(pTmp->pd_InitialNetworkRange.anr_FirstNetwork != UNKNOWN_NETWORK))
{
if (AtalkRangesOverlap(&pPortDesc->pd_InitialNetworkRange,
&pTmp->pd_InitialNetworkRange))
{
LOG_ERRORONPORT(pPortDesc,
EVENT_ATALK_INITIAL_RANGEOVERLAP,
status,
NULL,
0);
status = STATUS_UNSUCCESSFUL;
break;
}
}
}
}
if (!NT_SUCCESS(status))
{
break;
}
// Make sure any PRAM values we might have are in this range
if ((pPortDesc->pd_RoutersPramNode.atn_Network != UNKNOWN_NETWORK) &&
(pPortDesc->pd_InitialNetworkRange.anr_FirstNetwork != UNKNOWN_NETWORK) &&
!(WITHIN_NETWORK_RANGE(pPortDesc->pd_RoutersPramNode.atn_Network,
&pPortDesc->pd_InitialNetworkRange)))
{
LOG_ERRORONPORT(pPortDesc,
EVENT_ATALK_PRAM_OUTOFSYNC,
status,
NULL,
0);
pPortDesc->pd_RoutersPramNode.atn_Network = UNKNOWN_NETWORK;
pPortDesc->pd_RoutersPramNode.atn_Node = UNKNOWN_NODE;
}
if ((pPortDesc->pd_UsersPramNode1.atn_Network != UNKNOWN_NETWORK) &&
(pPortDesc->pd_InitialNetworkRange.anr_FirstNetwork != UNKNOWN_NETWORK) &&
!(WITHIN_NETWORK_RANGE(pPortDesc->pd_UsersPramNode1.atn_Network,
&pPortDesc->pd_InitialNetworkRange)))
{
LOG_ERRORONPORT(pPortDesc,
EVENT_ATALK_PRAM_OUTOFSYNC,
status,
NULL,
0);
pPortDesc->pd_UsersPramNode1.atn_Network = UNKNOWN_NETWORK;
pPortDesc->pd_UsersPramNode1.atn_Node = UNKNOWN_NODE;
}
if ((pPortDesc->pd_UsersPramNode2.atn_Network != UNKNOWN_NETWORK) &&
(pPortDesc->pd_InitialNetworkRange.anr_FirstNetwork != UNKNOWN_NETWORK) &&
!(WITHIN_NETWORK_RANGE(pPortDesc->pd_UsersPramNode2.atn_Network,
&pPortDesc->pd_InitialNetworkRange)))
{
LOG_ERRORONPORT(pPortDesc,
EVENT_ATALK_PRAM_OUTOFSYNC,
status,
NULL,
0);
pPortDesc->pd_UsersPramNode2.atn_Network = UNKNOWN_NETWORK;
pPortDesc->pd_UsersPramNode2.atn_Node = UNKNOWN_NODE;
}
} while (FALSE);
return status;
}
NTSTATUS
atalkInitNetRange(
OUT PPORT_DESCRIPTOR pPortDesc
)
/*++
Routine Description:
Gets the network range for the port defined by AdapterInfoHandle
Arguments:
AdapterInfoHandle- Handle to ...Atalk\Adapters\<adapterName>
pPortDesc- Pointer to port information structure for the port
Return Value:
Status - STATUS_SUCCESS or system call returned status codes
--*/
{
UNICODE_STRING valueName;
NTSTATUS registryStatus;
ULONG bytesWritten;
PULONG netNumber;
BYTE netNumberStorage[sizeof(KEY_VALUE_FULL_INFORMATION) + 80];
PKEY_VALUE_FULL_INFORMATION netValue = (PKEY_VALUE_FULL_INFORMATION)netNumberStorage;
do
{
// Read the "NetworkRangeLowerEnd" value name
RtlInitUnicodeString (&valueName, VALUENAME_NETLOWEREND);
registryStatus = ZwQueryValueKey(pPortDesc->pd_AdapterInfoHandle,
&valueName,
KeyValueFullInformation,
netValue,
sizeof(netNumberStorage),
&bytesWritten);
// This should change with the routing flags.
if (registryStatus != STATUS_SUCCESS)
{
// Set defaults
pPortDesc->pd_InitialNetworkRange.anr_FirstNetwork = UNKNOWN_NETWORK;
pPortDesc->pd_InitialNetworkRange.anr_LastNetwork = UNKNOWN_NETWORK;
registryStatus = STATUS_SUCCESS;
break;
}
netNumber = (PULONG)((PBYTE)netValue + netValue->DataOffset);
pPortDesc->pd_InitialNetworkRange.anr_FirstNetwork = (USHORT)(*netNumber);
// Get the upper number only if lower was specified
RtlInitUnicodeString (&valueName, VALUENAME_NETUPPEREND);
registryStatus = ZwQueryValueKey(pPortDesc->pd_AdapterInfoHandle,
&valueName,
KeyValueFullInformation,
netValue,
sizeof(netNumberStorage),
&bytesWritten);
if (registryStatus != STATUS_SUCCESS)
{
// Do not load if lower end specified but upper end was not
break;
}
// Set the upper end of the network range
netNumber = (PULONG)((PBYTE)netValue + netValue->DataOffset);
pPortDesc->pd_InitialNetworkRange.anr_LastNetwork =(USHORT)(*netNumber);
if (!AtalkCheckNetworkRange(&pPortDesc->pd_InitialNetworkRange))
{
registryStatus = STATUS_UNSUCCESSFUL;
break;
}
} while (FALSE);
if (registryStatus != STATUS_SUCCESS)
{
LOG_ERRORONPORT(pPortDesc,
EVENT_ATALK_INVALID_NETRANGE,
registryStatus,
NULL,
0);
}
return registryStatus;
}
NTSTATUS
atalkInitZoneList(
OUT PPORT_DESCRIPTOR pPortDesc
)
/*++
Routine Description:
Gets the zone list for the port defined by AdapterInfoHandle
Arguments:
AdapterInfoHandle- Handle to ...Atalk\Adapters\<adapterName>
pPortDesc- Pointer to port information structure for the port
Return Value:
Status - STATUS_SUCCESS or system call returned status codes
--*/
{
UNICODE_STRING valueName;
NTSTATUS status;
ULONG bytesWritten;
PWCHAR curZoneValue;
// Anticipate about 10 zones and get space for those, if more then do a
// dynamic alloc. Note that the below *does not* guarantee 10 zones...
BYTE zoneStorage[10*2*(MAX_ENTITY_LENGTH)+sizeof(KEY_VALUE_FULL_INFORMATION)];
PKEY_VALUE_FULL_INFORMATION zoneValue = (PKEY_VALUE_FULL_INFORMATION)zoneStorage;
RtlInitUnicodeString (&valueName, VALUENAME_ZONELIST);
status = ZwQueryValueKey(pPortDesc->pd_AdapterInfoHandle,
&valueName,
KeyValueFullInformation,
zoneValue,
sizeof(zoneStorage),
&bytesWritten);
if (status == STATUS_BUFFER_OVERFLOW)
{
// If error was a buffer overrun, then allocate space and try again
zoneValue = (PKEY_VALUE_FULL_INFORMATION)AtalkAllocMemory(bytesWritten);
if (zoneValue == NULL)
{
return STATUS_INSUFFICIENT_RESOURCES;
}
status = ZwQueryValueKey(pPortDesc->pd_AdapterInfoHandle,
&valueName,
KeyValueFullInformation,
zoneValue,
bytesWritten,
&bytesWritten);
}
do
{
if (status != STATUS_SUCCESS)
{
break;
}
// Proceed to get zone list
pPortDesc->pd_InitialZoneList = NULL;
curZoneValue = (PWCHAR)((PBYTE)zoneValue + zoneValue->DataOffset);
while (*curZoneValue != 0)
{
UNICODE_STRING Us;
ANSI_STRING As;
BYTE ansiBuf[MAX_ENTITY_LENGTH + 1];
RtlInitUnicodeString(&Us, curZoneValue);
As.Buffer = ansiBuf;
As.Length = (USHORT)RtlUnicodeStringToAnsiSize(&Us) - 1;
As.MaximumLength = sizeof(ansiBuf);
if (As.Length > MAX_ENTITY_LENGTH)
{
// Incorrect zone name!
LOG_ERROR(EVENT_ATALK_INVALID_ZONEINLIST, status, NULL, 0);
}
status = RtlUnicodeStringToAnsiString(&As, &Us, FALSE);
if (!NT_SUCCESS(status))
{
DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_ERR,
("atalkInitZoneList: RtlUnicodeStringToAnsiSize %lx\n", status));
break;
}
// Insert the zone in the list in Port
pPortDesc->pd_InitialZoneList = AtalkZoneAddToList(pPortDesc->pd_InitialZoneList,
ansiBuf,
(BYTE)(As.Length));
if (pPortDesc->pd_InitialZoneList == NULL)
{
DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_ERR,
("atalkInitZoneList: AtalkZoneAddToList failed\n"));
break;
}
// Now advance the curZoneValue value to next zone
curZoneValue = (PWCHAR)((PBYTE)curZoneValue + Us.Length + sizeof(WCHAR));
}
} while (FALSE);
if ((PVOID)zoneValue != (PVOID)zoneStorage)
{
AtalkFreeMemory(zoneValue);
}
return status;
}
NTSTATUS
atalkInitDefZone(
OUT PPORT_DESCRIPTOR pPortDesc
)
/*++
Routine Description:
Gets the default zone for the port defined by AdapterInfoHandle
Arguments:
AdapterInfoHandle- Handle to ...Atalk\Adapters\<adapterName>
pPort- Pointer to port information structure for the port
Return Value:
Status - STATUS_SUCCESS or system call returned status codes
--*/
{
UNICODE_STRING valueName;
NTSTATUS status;
ULONG bytesWritten;
PWCHAR defZoneValue;
BYTE zoneStorage[2*MAX_ENTITY_LENGTH+sizeof(KEY_VALUE_FULL_INFORMATION)];
PKEY_VALUE_FULL_INFORMATION zoneValue = (PKEY_VALUE_FULL_INFORMATION)zoneStorage;
RtlInitUnicodeString (&valueName, VALUENAME_DEFAULTZONE);
status = ZwQueryValueKey(pPortDesc->pd_AdapterInfoHandle,
&valueName,
KeyValueFullInformation,
zoneValue,
sizeof(zoneStorage),
&bytesWritten);
if (status == STATUS_BUFFER_OVERFLOW)
{
// If error was a buffer overrun, then allocate space and try again
zoneValue = (PKEY_VALUE_FULL_INFORMATION)AtalkAllocMemory(bytesWritten);
if (zoneValue == NULL)
{
return STATUS_INSUFFICIENT_RESOURCES;
}
status = ZwQueryValueKey(pPortDesc->pd_AdapterInfoHandle,
&valueName,
KeyValueFullInformation,
zoneValue,
bytesWritten,
&bytesWritten);
}
do
{
if (status != STATUS_SUCCESS)
{
LOG_ERRORONPORT(pPortDesc,
EVENT_ATALK_NO_DEFZONE,
status,
NULL,
0);
status = STATUS_SUCCESS;
break;
}
else
{
ANSI_STRING ansiZone;
UNICODE_STRING unicodeZone;
BYTE ansiBuf[MAX_ENTITY_LENGTH+1];
NTSTATUS status;
defZoneValue = (PWCHAR)((PBYTE)zoneValue + zoneValue->DataOffset);
if (*defZoneValue != 0)
{
RtlInitUnicodeString(&unicodeZone, defZoneValue);
ansiZone.Length = (USHORT)RtlUnicodeStringToAnsiSize(&unicodeZone) - 1;
if (ansiZone.Length > MAX_ENTITY_LENGTH+1)
{
status = STATUS_UNSUCCESSFUL;
// Incorrect zone name!
LOG_ERRORONPORT(pPortDesc,
EVENT_ATALK_INVALID_DEFZONE,
status,
NULL,
0);
break;
}
ansiZone.Buffer = ansiBuf;
ansiZone.MaximumLength = sizeof(ansiBuf);
status = RtlUnicodeStringToAnsiString(&ansiZone, &unicodeZone, (BOOLEAN)FALSE);
if (status == STATUS_SUCCESS)
{
PZONE pZone;
PZONE_LIST pZoneList;
// Ensure that the zone exists in the zone list, We are seed-routing
ASSERT(pPortDesc->pd_Flags & PD_SEED_ROUTER);
for (pZoneList = pPortDesc->pd_InitialZoneList;
pZoneList != NULL;
pZoneList = pZoneList->zl_Next)
{
pZone = pZoneList->zl_pZone;
if (AtalkFixedCompareCaseInsensitive(pZone->zn_Zone,
pZone->zn_ZoneLen,
ansiBuf,
ansiZone.Length))
{
break;
}
}
if (pZone == NULL)
{
// Incorrect zone name - not in the list
LOG_ERRORONPORT(pPortDesc,
EVENT_ATALK_INVALID_DEFZONE,
status,
NULL,
0);
}
pPortDesc->pd_InitialDefaultZone = AtalkZoneReferenceByName(ansiBuf,
(BYTE)(ansiZone.Length));
}
if ((status != STATUS_SUCCESS) ||
(pPortDesc->pd_InitialDefaultZone == NULL))
{
LOG_ERROR(EVENT_ATALK_RESOURCES, status, NULL, 0);
}
}
}
} while (FALSE);
if ((PVOID)zoneValue != (PVOID)zoneStorage)
{
AtalkFreeMemory(zoneValue);
}
return status;
}
NTSTATUS
atalkInitSeeding(
IN OUT PPORT_DESCRIPTOR pPortDesc,
OUT PBOOLEAN Seeding
)
/*++
Routine Description:
Gets the value of the enable router flag from the registry. Sets the
startRouter value in PortInfo based on this flag.
Arguments:
AdapterHandle- Handle to the Adapter in registry
Return Value:
Value of the flag: TRUE/FALSE
--*/
{
UNICODE_STRING valueName;
NTSTATUS registryStatus;
ULONG bytesWritten;
PULONG seedingPortFlag;
BYTE flagStorage[sizeof(KEY_VALUE_FULL_INFORMATION)+32];
PKEY_VALUE_FULL_INFORMATION flagValue = (PKEY_VALUE_FULL_INFORMATION)flagStorage;
*Seeding = FALSE;
// Read the "seedingPort" value name
RtlInitUnicodeString (&valueName, VALUENAME_SEEDROUTER);
registryStatus = ZwQueryValueKey(pPortDesc->pd_AdapterInfoHandle,
&valueName,
KeyValueFullInformation,
flagValue,
sizeof(flagStorage),
&bytesWritten);
if (registryStatus == STATUS_SUCCESS)
{
seedingPortFlag = (PULONG)((PBYTE)flagValue + flagValue->DataOffset);
if (*seedingPortFlag != 0)
{
*Seeding = TRUE;
pPortDesc->pd_Flags |= PD_SEED_ROUTER;
}
}
return registryStatus;
}
NTSTATUS
atalkInitPortParameters(
OUT PPORT_DESCRIPTOR pPortDesc
)
/*++
Routine Description:
Gets the per-port parameters for the port
Arguments:
pPortDesc- Pointer to port information structure for the port
Return Value:
Status - STATUS_SUCCESS or system call returned status codes
--*/
{
UNICODE_STRING valueName;
NTSTATUS status;
ULONG bytesWritten;
BYTE Storage[sizeof(KEY_VALUE_FULL_INFORMATION)+4*MAX_ENTITY_LENGTH];
PKEY_VALUE_FULL_INFORMATION pInfo = (PKEY_VALUE_FULL_INFORMATION)Storage;
// Read the "DdpChecksums" value name
RtlInitUnicodeString (&valueName, VALUENAME_DDPCHECKSUMS);
status = ZwQueryValueKey(pPortDesc->pd_AdapterInfoHandle,
&valueName,
KeyValueFullInformation,
pInfo,
sizeof(Storage),
&bytesWritten);
if (status == STATUS_SUCCESS)
{
PULONG ddpChecksumFlag;
ddpChecksumFlag = (PULONG)((PBYTE)pInfo + pInfo->DataOffset);
if ((*ddpChecksumFlag) != 0)
{
pPortDesc->pd_Flags |= PD_SEND_CHECKSUMS;
}
}
// Read the "AarpRetries" value name
RtlInitUnicodeString (&valueName, VALUENAME_AARPRETRIES);
status = ZwQueryValueKey(pPortDesc->pd_AdapterInfoHandle,
&valueName,
KeyValueFullInformation,
pInfo,
sizeof(Storage),
&bytesWritten);
if (status == STATUS_SUCCESS)
{
PULONG aarpRetries;
aarpRetries = (PULONG)((PBYTE)pInfo + pInfo->DataOffset);
pPortDesc->pd_AarpProbes = (USHORT)*aarpRetries;
}
RtlInitUnicodeString (&valueName, VALUENAME_PORTNAME);
status = ZwQueryValueKey(pPortDesc->pd_AdapterInfoHandle,
&valueName,
KeyValueFullInformation,
pInfo,
sizeof(Storage),
&bytesWritten);
do
{
if (status == STATUS_SUCCESS)
{
PWCHAR portName;
ANSI_STRING ansiPort;
UNICODE_STRING unicodePort;
ULONG ansiSize;
NTSTATUS status;
portName = (PWCHAR)((PBYTE)pInfo + pInfo->DataOffset);
if (*portName != 0)
{
RtlInitUnicodeString(&unicodePort, portName);
ansiSize = RtlUnicodeStringToAnsiSize(&unicodePort);
if (ansiSize > MAX_ENTITY_LENGTH+1)
{
status = STATUS_UNSUCCESSFUL;
// Incorrect port name!
LOG_ERRORONPORT(pPortDesc,
EVENT_ATALK_INVALID_PORTNAME,
status,
NULL,
0);
break;
}
ansiPort.Buffer = pPortDesc->pd_PortName;
ansiPort.MaximumLength = (USHORT)ansiSize+1;
ansiPort.Length = 0;
status = RtlUnicodeStringToAnsiString(&ansiPort,
&unicodePort,
(BOOLEAN)FALSE);
if (status != STATUS_SUCCESS)
{
LOG_ERROR(EVENT_ATALK_RESOURCES,status, NULL, 0);
}
}
else
{
// NULL Port Name! Set status to unsuccessful so we copy
// default name at the end.
status = STATUS_UNSUCCESSFUL;
}
}
} while (FALSE);
// Do we need to copy the default port name?
if (!NT_SUCCESS(status))
{
RtlCopyMemory(pPortDesc->pd_PortName, ATALK_PORT_NAME, ATALK_PORT_NAME_SIZE);
}
return status;
}
NTSTATUS
atalkInitStartPort(
IN OUT PPORT_DESCRIPTOR pPortDesc
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
ATALK_NODEADDR Node;
ATALK_ADDR AtalkAddr;
PDDP_ADDROBJ pDdpAddr;
KIRQL OldIrql;
ATALK_ERROR error;
ULONG length;
NTSTATUS status = STATUS_UNSUCCESSFUL;
INT LookaheadSize;
BOOLEAN fPnpReconfigure;
fPnpReconfigure = (pPortDesc->pd_Flags & PD_PNP_RECONFIGURE)? TRUE : FALSE;
do
{
// Initialize NetworkRange. We can do this here, only *after*
// we bind, as we dont know our port type until then.
if (EXT_NET(pPortDesc))
{
pPortDesc->pd_NetworkRange.anr_FirstNetwork = FIRST_VALID_NETWORK;
pPortDesc->pd_NetworkRange.anr_LastNetwork = LAST_STARTUP_NETWORK;
}
else
{
pPortDesc->pd_NetworkRange.anr_FirstNetwork =
pPortDesc->pd_NetworkRange.anr_LastNetwork = UNKNOWN_NETWORK;
pPortDesc->pd_LtNetwork = UNKNOWN_NETWORK;
}
//
// only when the adapter is initialized for the first time, we need
// to all the initialization stuff (like set lookahead size etc.).
// If we are here because of a PnPReconfigure event, don't do it
//
if (!fPnpReconfigure)
{
error = AtalkInitNdisQueryAddrInfo(pPortDesc);
if (!ATALK_SUCCESS(error))
{
DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_ERR,
("atalkInitStartPort: Error in AtalkInitNdisQueryAddrInfo %lx\n", error));
break;
}
LookaheadSize = AARPLINK_MAX_PKT_SIZE;
if (pPortDesc->pd_NdisPortType == NdisMedium802_5)
{
LookaheadSize = AARPLINK_MAX_PKT_SIZE + TLAP_MAX_LINKHDR_LEN;
}
else if (pPortDesc->pd_NdisPortType == NdisMediumWan)
{
LookaheadSize = AARPLINK_MAX_PKT_SIZE + TLAP_MAX_LINKHDR_LEN;
}
// Set lookahead to be the max of the complete aarp packet including link
error = AtalkInitNdisSetLookaheadSize(pPortDesc, LookaheadSize);
if (!ATALK_SUCCESS(error))
{
DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_ERR,
("atalkInitStartPort: Error in AtalkInitNdisSetLookaheadSize %lx\n", error));
break;
}
//
// if this is an ARAP port, we need to do a little more work (e.g. set the
// protocol type, etc.
//
if (pPortDesc->pd_Flags & PD_RAS_PORT)
{
error = ArapAdapterInit( pPortDesc );
if (!ATALK_SUCCESS(error))
{
DBGPRINT(DBG_COMP_RAS, DBG_LEVEL_ERR,
("ArapAdapterInit: failed (%d)\n",error));
break;
}
}
if (pPortDesc->pd_AddMulticastAddr)
{
error = (*pPortDesc->pd_AddMulticastAddr)(pPortDesc,
pPortDesc->pd_BroadcastAddr,
TRUE,
NULL,
NULL);
if (!ATALK_SUCCESS(error))
{
DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_ERR,
("atalkInitStartPort: Error in pd_AddMulticastAddr %lx\n", error));
break;
}
}
error = AtalkInitNdisStartPacketReception(pPortDesc);
if (!ATALK_SUCCESS(error))
{
DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_ERR,
("atalkInitStartPort: Error in AtalkInitNdisStartPacketReception %lx\n", error));
LOG_ERRORONPORT(pPortDesc,
EVENT_ATALK_RECEPTION,
0,
NULL,
0);
break;
}
} // if (!fPnpReconfigure)
// Set flag to active here. Until then all packets will be dropped
ACQUIRE_SPIN_LOCK(&pPortDesc->pd_Lock, &OldIrql);
pPortDesc->pd_Flags |= PD_ACTIVE;
RELEASE_SPIN_LOCK(&pPortDesc->pd_Lock, OldIrql);
// if this is arap port, we are done at this point
if (pPortDesc->pd_Flags & PD_RAS_PORT)
{
RtlZeroMemory(pPortDesc->pd_PortStats.prtst_PortName,
sizeof(pPortDesc->pd_PortStats.prtst_PortName));
// Set up the name in the statistics structure.
length = MIN(pPortDesc->pd_AdapterKey.Length,
((MAX_INTERNAL_PORTNAME_LEN * sizeof(WCHAR)) - sizeof(WCHAR)));
RtlCopyMemory(pPortDesc->pd_PortStats.prtst_PortName,
pPortDesc->pd_AdapterKey.Buffer,
length);
AtalkStatistics.stat_NumActivePorts++;
AtalkNumberOfActivePorts ++;
status = STATUS_SUCCESS;
break;
}
// is localtalk our default port? if so, we make sure routing is not on.
if (AtalkRouter && !EXT_NET(pPortDesc) && DEF_PORT(pPortDesc))
{
// No can do.
break;
}
// We need to have a node created on every single port. If routing
// is on, then this will be the router node. The Default port will
// also have an additional user node. In the case, where we are non-
// routing, we should only create the user node on the default port.
// The other nodes will be created on the other ports as usual.
//
// !!! AtalkNodeCreateOnPort should set the pointer to the router
// node in the port descriptor. !!!
// Make sure we do not create this node if localtalk default port.
if (!DEF_PORT(pPortDesc) || AtalkRouter)
{
BOOLEAN allowstartuprange = !AtalkRouter;
// If router then startup range is not allowed!
error = AtalkInitNodeCreateOnPort(pPortDesc,
allowstartuprange,
AtalkRouter,
&Node);
if (!ATALK_SUCCESS(error))
{
LOG_ERRORONPORT(pPortDesc,
EVENT_ATALK_INIT_COULDNOTGETNODE,
0,
NULL,
0);
DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_ERR,
("atalkInitStartPort: Failed to open node on port %lx (%Z)\n",
pPortDesc, &pPortDesc->pd_AdapterKey));
break;
}
if (AtalkRouter)
{
// Start RTMP/ZIP Processing on this port.
if (!AtalkInitRtmpStartProcessingOnPort(pPortDesc, &Node) ||
!AtalkInitZipStartProcessingOnPort(pPortDesc, &Node))
{
break;
}
}
// Register the port name on the NIS on this node.
AtalkAddr.ata_Network = Node.atn_Network;
AtalkAddr.ata_Node = Node.atn_Node;
AtalkAddr.ata_Socket = NAMESINFORMATION_SOCKET;
AtalkDdpReferenceByAddr(pPortDesc,
&AtalkAddr,
&pDdpAddr,
&error);
if (ATALK_SUCCESS(error))
{
PACTREQ pActReq;
NBPTUPLE NbpTuple;
NbpTuple.tpl_Zone[0] = '*';
NbpTuple.tpl_ZoneLen = 1;
NbpTuple.tpl_ObjectLen = (BYTE)strlen(pPortDesc->pd_PortName);
RtlCopyMemory(NbpTuple.tpl_Object,
pPortDesc->pd_PortName,
NbpTuple.tpl_ObjectLen);
if (AtalkRouter)
{
RtlCopyMemory(NbpTuple.tpl_Type,
ATALK_ROUTER_NBP_TYPE,
sizeof(ATALK_ROUTER_NBP_TYPE) - 1);
NbpTuple.tpl_TypeLen = sizeof(ATALK_ROUTER_NBP_TYPE) - 1;
}
else
{
RtlCopyMemory(NbpTuple.tpl_Type,
ATALK_NONROUTER_NBP_TYPE,
sizeof(ATALK_NONROUTER_NBP_TYPE) - 1);
NbpTuple.tpl_TypeLen = sizeof(ATALK_NONROUTER_NBP_TYPE) - 1;
}
// Initialize parameters and call AtalkNbpAction
if ((pActReq = AtalkAllocZeroedMemory(sizeof(ACTREQ))) == NULL)
error = ATALK_RESR_MEM;
else
{
#if DBG
pActReq->ar_Signature = ACTREQ_SIGNATURE;
#endif
pActReq->ar_Completion = atalkRegNbpComplete;
pActReq->ar_pParms = pPortDesc;
AtalkLockNbpIfNecessary();
error = AtalkNbpAction(pDdpAddr,
FOR_REGISTER,
&NbpTuple,
NULL,
0,
pActReq);
if (!ATALK_SUCCESS(error))
{
DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_ERR,
("atalkInitStartPort: AtalkNbpAction returned %lx\n",
error));
ASSERT(0);
AtalkFreeMemory(pActReq);
AtalkUnlockNbpIfNecessary();
}
else
{
DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_WARN,
("atalkInitStartPort: AtalkNbpAction(Register) %lx\n",
error));
}
}
// Remove the reference added here.
AtalkDdpDereference(pDdpAddr);
}
else
{
LOG_ERRORONPORT(pPortDesc,
EVENT_ATALK_INIT_NAMEREGISTERFAILED,
AtalkErrorToNtStatus(error),
NULL,
0);
}
}
// If this is the default port, open the user node on it.
if (DEF_PORT(pPortDesc))
{
ASSERT(!AtalkRouter || EXT_NET(pPortDesc));
if (!ATALK_SUCCESS(AtalkInitNodeCreateOnPort(pPortDesc,
TRUE,
FALSE,
&Node)))
{
LOG_ERRORONPORT(pPortDesc,
EVENT_ATALK_INIT_COULDNOTGETNODE,
0,
NULL,
0);
DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_ERR,
("atalkInitStartPort: Failed to open node on port %lx (%Z)\n",
pPortDesc, &pPortDesc->pd_AdapterKey));
break;
}
ACQUIRE_SPIN_LOCK(&pPortDesc->pd_Lock, &OldIrql);
pPortDesc->pd_Flags |= PD_USER_NODE_1;
AtalkUserNode1 = Node;
RELEASE_SPIN_LOCK(&pPortDesc->pd_Lock, OldIrql);
// Register the port name on the NIS on this node.
AtalkAddr.ata_Network = Node.atn_Network;
AtalkAddr.ata_Node = Node.atn_Node;
AtalkAddr.ata_Socket = NAMESINFORMATION_SOCKET;
AtalkDdpReferenceByAddr(pPortDesc,
&AtalkAddr,
&pDdpAddr,
&error);
if (ATALK_SUCCESS(error))
{
PACTREQ pActReq;
NBPTUPLE NbpTuple;
NbpTuple.tpl_Zone[0] = '*';
NbpTuple.tpl_ZoneLen = 1;
RtlCopyMemory(NbpTuple.tpl_Object,
pPortDesc->pd_PortName,
NbpTuple.tpl_ObjectLen = (BYTE)strlen(pPortDesc->pd_PortName));
RtlCopyMemory(NbpTuple.tpl_Type,
ATALK_NONROUTER_NBP_TYPE,
sizeof(ATALK_NONROUTER_NBP_TYPE) - 1);
NbpTuple.tpl_TypeLen = sizeof(ATALK_NONROUTER_NBP_TYPE) - 1;
// Initialize parameters and call AtalkNbpAction
if ((pActReq = AtalkAllocZeroedMemory(sizeof(ACTREQ))) == NULL)
error = ATALK_RESR_MEM;
else
{
#if DBG
pActReq->ar_Signature = ACTREQ_SIGNATURE;
#endif
pActReq->ar_Completion = atalkRegNbpComplete;
pActReq->ar_pParms = pPortDesc;
AtalkLockNbpIfNecessary();
error = AtalkNbpAction(pDdpAddr,
FOR_REGISTER,
&NbpTuple,
NULL,
0,
pActReq);
if (!ATALK_SUCCESS(error))
{
DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_ERR,
("atalkInitStartPort: AtalkNbpAction returned %lx\n",
error));
AtalkFreeMemory(pActReq);
AtalkUnlockNbpIfNecessary();
}
else
{
DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_WARN,
("atalkInitStartPort: AtalkNbpAction(Register) %lx\n",
error));
}
}
// Remove the reference added here.
AtalkDdpDereference(pDdpAddr);
}
else
{
LOG_ERRORONPORT(pPortDesc,
EVENT_ATALK_INIT_NAMEREGISTERFAILED,
STATUS_UNSUCCESSFUL,
NULL,
0);
}
// If we are an extended port, we open a second node on the port.
if (EXT_NET(pPortDesc))
{
if (ATALK_SUCCESS(AtalkInitNodeCreateOnPort(pPortDesc,
TRUE,
FALSE,
&Node)))
{
ACQUIRE_SPIN_LOCK(&pPortDesc->pd_Lock, &OldIrql);
pPortDesc->pd_Flags |= PD_USER_NODE_2;
AtalkUserNode2 = Node;
RELEASE_SPIN_LOCK(&pPortDesc->pd_Lock, OldIrql);
}
else
{
LOG_ERRORONPORT(pPortDesc,
EVENT_ATALK_INIT_COULDNOTGETNODE,
0,
NULL,
0);
DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_ERR,
("atalkInitStartPort: Fail 2nd node port %lx (%Z)\n",
pPortDesc, &pPortDesc->pd_AdapterKey));
}
}
}
// Start the Amt and Brc timers for the port, only for extended ports
if (EXT_NET(pPortDesc))
{
AtalkPortReferenceByPtr(pPortDesc, &error);
if (ATALK_SUCCESS(error))
{
AtalkTimerInitialize(&pPortDesc->pd_BrcTimer,
AtalkAarpBrcTimer,
BRC_AGE_TIME);
AtalkTimerScheduleEvent(&pPortDesc->pd_BrcTimer);
}
AtalkPortReferenceByPtr(pPortDesc, &error);
if (ATALK_SUCCESS(error))
{
AtalkTimerInitialize(&pPortDesc->pd_AmtTimer,
AtalkAarpAmtTimer,
AMT_AGE_TIME);
AtalkTimerScheduleEvent(&pPortDesc->pd_AmtTimer);
}
}
// Start the Rtmp aging timer for non-routing case
if (!AtalkRouter)
{
AtalkPortReferenceByPtr(pPortDesc, &error);
if (!ATALK_SUCCESS(error))
{
break;
}
AtalkTimerInitialize(&pPortDesc->pd_RtmpAgingTimer,
AtalkRtmpAgingTimer,
RTMP_AGING_TIMER);
AtalkTimerScheduleEvent(&pPortDesc->pd_RtmpAgingTimer);
}
RtlZeroMemory(pPortDesc->pd_PortStats.prtst_PortName,
sizeof(pPortDesc->pd_PortStats.prtst_PortName));
// Set up the name in the statistics structure.
length = MIN(pPortDesc->pd_AdapterKey.Length,
((MAX_INTERNAL_PORTNAME_LEN * sizeof(WCHAR)) - sizeof(WCHAR)));
RtlCopyMemory(pPortDesc->pd_PortStats.prtst_PortName,
pPortDesc->pd_AdapterKey.Buffer,
length);
status = STATUS_SUCCESS;
} while (FALSE);
//
// in case of PnP, we want to get the stats right even in case of failure
//
if (fPnpReconfigure || NT_SUCCESS(status))
{
AtalkStatistics.stat_NumActivePorts++;
AtalkNumberOfActivePorts ++;
}
if (!NT_SUCCESS(status))
{
DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_ERR,
("atalkInitStartPort: Start port failed %lx %s\n",
status, (fPnpReconfigure)?"(during PnP)" : " "));
}
return status;
}
VOID
atalkRegNbpComplete(
IN ATALK_ERROR Status,
IN PACTREQ pActReq
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
ASSERT (VALID_ACTREQ(pActReq));
if (ATALK_SUCCESS(Status))
{
DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_INFO,
("atalkInitNbpCompletion: NBP Name registered on port %Z\n",
&((PPORT_DESCRIPTOR)(pActReq->ar_pParms))->pd_AdapterKey));
LOG_ERRORONPORT((PPORT_DESCRIPTOR)(pActReq->ar_pParms),
EVENT_ATALK_INIT_NAMEREGISTERED,
STATUS_SUCCESS,
NULL,
0);
}
else
{
DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_ERR,
("atalkInitNbpCompletion: Failed to register name on port %Z (%ld)\n",
&((PPORT_DESCRIPTOR)(pActReq->ar_pParms))->pd_AdapterKey, Status));
LOG_ERRORONPORT((PPORT_DESCRIPTOR)(pActReq->ar_pParms),
EVENT_ATALK_INIT_NAMEREGISTERFAILED,
STATUS_UNSUCCESSFUL,
NULL,
0);
}
AtalkFreeMemory(pActReq);
}
NTSTATUS
AtalkInitAdapter(
IN PUNICODE_STRING AdapterName,
IN PPORT_DESCRIPTOR pExistingPortDesc
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
PPORT_DESCRIPTOR pPortDesc;
KIRQL OldIrql;
PWCHAR devicePrefix = L"\\Device\\";
#define prefixLength (sizeof(L"\\Device\\") - sizeof(WCHAR))
UCHAR Address[sizeof(TA_ADDRESS) + sizeof(TDI_ADDRESS_APPLETALK)];
PTA_ADDRESS AddressPtr;
NTSTATUS Status;
UNICODE_STRING Us;
UNICODE_STRING AspDeviceName;
HANDLE RegHandle;
BOOLEAN fMustBindToNdis;
BOOLEAN IsDefaultPort = FALSE;
if (AdapterName)
{
DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_INFO,
("AtalkInitAdapter: Initiating bind for adapter %Z\n", AdapterName));
}
do
{
// Open the adapters section key.
RtlInitUnicodeString(&Us, ADAPTERS_STRING);
Status = atalkInitGetHandleToKey(&Us,
&RegHandle);
if (!NT_SUCCESS(Status))
{
DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_ERR,
("AtalkInitAdapter: Failed to open %ws key\n", ADAPTERS_STRING));
break;
}
if (pExistingPortDesc == NULL)
{
// Get the size of the string, and make sure that is it atleast
// greater than the \Device prefix. Fail if not.
if (AdapterName->Length <= prefixLength)
{
break;
}
// Allocate space for the port descriptors. Allocate an extra DWORD
// and set port descriptor past the first DWORD_PTR. This is a kludge to
// force LONGLONG alignment.
pPortDesc =
(PPORT_DESCRIPTOR)AtalkAllocZeroedMemory(sizeof(PORT_DESCRIPTOR) +
AdapterName->Length +
sizeof(WCHAR) +
sizeof(DWORD_PTR));
if (pPortDesc == NULL)
{
Status = STATUS_INSUFFICIENT_RESOURCES;
break;
}
// Reference the port for creation
pPortDesc->pd_RefCount = 1;
#if DBG
pPortDesc->pd_Signature = PD_SIGNATURE;
#endif
// Copy the AdapterName and AdapterKey strings into the portdesc
pPortDesc->pd_AdapterName.Buffer =
(PWCHAR)((PBYTE)pPortDesc + sizeof(PORT_DESCRIPTOR));
pPortDesc->pd_AdapterName.Length = AdapterName->Length;
pPortDesc->pd_AdapterName.MaximumLength =
AdapterName->Length + sizeof(WCHAR);
RtlUpcaseUnicodeString(&pPortDesc->pd_AdapterName,
AdapterName,
FALSE);
pPortDesc->pd_AdapterKey.Buffer =
(PWCHAR)((PBYTE)pPortDesc->pd_AdapterName.Buffer + prefixLength);
pPortDesc->pd_AdapterKey.Length =
pPortDesc->pd_AdapterName.Length - prefixLength;
pPortDesc->pd_AdapterKey.MaximumLength =
pPortDesc->pd_AdapterName.MaximumLength - prefixLength;
// buffer for this will be allocated later
pPortDesc->pd_FriendlyAdapterName.Buffer = NULL;
pPortDesc->pd_FriendlyAdapterName.MaximumLength = 0;
pPortDesc->pd_FriendlyAdapterName.Length = 0;
// Now initialize any other fields that need to be.
INITIALIZE_SPIN_LOCK(&pPortDesc->pd_Lock);
InitializeListHead(&pPortDesc->pd_ReceiveQueue);
// only in case of a Ras port will these lists head be used
InitializeListHead(&pPortDesc->pd_ArapConnHead);
InitializeListHead(&pPortDesc->pd_PPPConnHead);
// Initialize the events in the port descriptor
KeInitializeEvent(&pPortDesc->pd_RequestEvent, NotificationEvent, FALSE);
KeInitializeEvent(&pPortDesc->pd_SeenRouterEvent, NotificationEvent, FALSE);
KeInitializeEvent(&pPortDesc->pd_NodeAcquireEvent, NotificationEvent, FALSE);
fMustBindToNdis = TRUE;
}
else
{
pPortDesc = pExistingPortDesc;
fMustBindToNdis = FALSE;
}
if ((AtalkDefaultPortName.Buffer != NULL) &&
(RtlEqualUnicodeString(&pPortDesc->pd_AdapterName,
&AtalkDefaultPortName,
TRUE)))
{
// Used for tracking Default Port for error message logging
IsDefaultPort = TRUE;
pPortDesc->pd_Flags |= PD_DEF_PORT;
pPortDesc->pd_InitialDesiredZone = AtalkDesiredZone;
if (AtalkDesiredZone != NULL)
AtalkZoneReferenceByPtr(pPortDesc->pd_InitialDesiredZone);
}
// Link it in the global list
ACQUIRE_SPIN_LOCK(&AtalkPortLock, &OldIrql);
pPortDesc->pd_Next = AtalkPortList;
AtalkPortList = pPortDesc;
AtalkNumberOfPorts ++;
RELEASE_SPIN_LOCK(&AtalkPortLock, OldIrql);
if (fMustBindToNdis)
{
// bind to the adapter
Status = AtalkNdisInitBind(pPortDesc);
if (NT_SUCCESS(Status))
{
DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_ERR,
("Bind done for %Z\n", (pPortDesc->pd_FriendlyAdapterName.Buffer) ?
(&pPortDesc->pd_FriendlyAdapterName) :
(&pPortDesc->pd_AdapterName)));
}
else
{
DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_ERR,
("AtalkInitAdapter: AtalkNdisInitBind failed (0x%lx) for adapter %Z\n",
Status,AdapterName));
}
}
else
{
Status = STATUS_SUCCESS;
}
if (Status == NDIS_STATUS_SUCCESS)
{
Status = STATUS_SUCCESS;
DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_INFO,
("AtalkInitAdapter: Going into atalkInitPort (0x%lx) for adapter %Z\n",
Status,AdapterName));
// Get per port parameters (ARAP port doesn't have any parms to get)
if (!(pPortDesc->pd_Flags & PD_RAS_PORT))
{
Status = atalkInitPort(pPortDesc, RegHandle);
}
if (NT_SUCCESS(Status))
{
DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_INFO,
("AtalkInitAdapter: atalkInitPort succeeded (0x%lx) for adapter %Z\n",
Status,AdapterName));
// And start the port
Status = atalkInitStartPort(pPortDesc);
if (NT_SUCCESS(Status) && (pPortDesc->pd_Flags & PD_DEF_PORT))
{
DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_INFO,
("AtalkInitAdapter: atalkInitStartPort succeeded (0x%lx) for adapter %Z\n",
Status,AdapterName));
//
// if we were doing PnP, we are done with the PnP at this point:
// clear the flag, so macfile can do its things...
//
ACQUIRE_SPIN_LOCK(&pPortDesc->pd_Lock, &OldIrql);
pPortDesc->pd_Flags &= ~PD_PNP_RECONFIGURE;
RELEASE_SPIN_LOCK(&pPortDesc->pd_Lock, OldIrql);
// Set the global default port value
AtalkDefaultPort = pPortDesc;
KeSetEvent(&AtalkDefaultPortEvent, IO_NETWORK_INCREMENT, FALSE);
// Now tell TDI that we are up and ready for binding
RtlInitUnicodeString(&AspDeviceName, ATALKASPS_DEVICENAME);
DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_INFO,
("AtalkInitAdapter: Calling TdiRegisterDeviceObject for adapter %Z\n",
AdapterName));
Status = TdiRegisterDeviceObject(
&AspDeviceName,
&TdiRegistrationHandle);
if (!NT_SUCCESS(Status))
{
DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_ERR,
( "TdiRegisterDeviceObject failed with %lx\n", Status));
TdiRegistrationHandle = NULL;
}
else
{
DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_INFO,
( "TdiRegisterDeviceObject succeeded\n"));
AddressPtr = (PTA_ADDRESS)Address;
RtlZeroMemory(Address, sizeof(Address));
AddressPtr->AddressLength = sizeof(TDI_ADDRESS_APPLETALK);
AddressPtr->AddressType = TDI_ADDRESS_TYPE_APPLETALK;
Status = TdiRegisterNetAddress(AddressPtr,
&pPortDesc->pd_AdapterName,
NULL,
&TdiAddressChangeRegHandle);
if (!NT_SUCCESS(Status))
{
DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_ERR,
("AtalkInitAdapter: TdiRegisterNetAddress failed %lx\n",Status));
TdiAddressChangeRegHandle = NULL;
}
else
{
DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_INFO,
("AtalkInitAdapter: TdiRegisterNetAddress on %Z done\n",
&pPortDesc->pd_AdapterName));
ASSERT(TdiAddressChangeRegHandle != NULL);
}
}
}
else if (!NT_SUCCESS(Status))
{
DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_ERR,
( "AtalkInitBinding: atalkInitStartPort failed (%lx) on %Z\n",
Status, &pPortDesc->pd_AdapterName));
}
}
else
{
DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_ERR,
("AtalkInitAdapter: atalkInitPort failed (0x%lx) for adapter %Z\n",
Status,AdapterName));
}
if (pPortDesc->pd_AdapterInfoHandle != NULL)
{
ZwClose(pPortDesc->pd_AdapterInfoHandle);
pPortDesc->pd_AdapterInfoHandle = NULL;
}
}
else
{
ASSERT(AdapterName != NULL);
DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_ERR,
( "AtalkInitBinding failed (%lx) on %Z\n", Status, AdapterName));
if (pPortDesc->pd_FriendlyAdapterName.Buffer)
{
AtalkFreeMemory(pPortDesc->pd_FriendlyAdapterName.Buffer);
}
AtalkFreeMemory(pPortDesc);
}
} while (FALSE);
// Close the Adapters Key
if (RegHandle != NULL)
ZwClose (RegHandle);
//
// if we just successfully initialized default adapter or the RAS adapter,
// let RAS know about it
//
if ( (NT_SUCCESS(Status)) &&
(pPortDesc->pd_Flags & (PD_RAS_PORT | PD_DEF_PORT)) )
{
DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_ERR,
("AtalkInitAdapter: %s adapter initialized (%lx), informing RAS\n",
(pPortDesc->pd_Flags & PD_RAS_PORT)? "RAS" : "Default",pPortDesc));
AtalkPnPInformRas(TRUE);
}
else
{
if (IsDefaultPort)
{
LOG_ERROR(EVENT_ATALK_NO_DEFAULTPORT, Status, NULL, 0);
DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_ERR,
("WARNING!!! Appletalk driver running, but no default port configured\n"));
}
}
return Status;
}
NTSTATUS
AtalkDeinitAdapter(
IN PPORT_DESCRIPTOR pPortDesc
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_INFO,
("AtalkDeinitAdapter: Initiating un-bind for adapter %Z\n",
&pPortDesc->pd_AdapterName));
AtalkPortShutdown(pPortDesc);
return STATUS_SUCCESS;
}
#ifdef ALLOC_DATA_PRAGMA
#pragma data_seg("PAGE")
#endif
ACTION_DISPATCH AtalkActionDispatch[MAX_ALLACTIONCODES+1] =
{
//
// NBP dispatch functions
//
{
sizeof(NBP_LOOKUP_ACTION),
COMMON_ACTION_NBPLOOKUP,
(DFLAG_CNTR | DFLAG_ADDR | DFLAG_MDL),
sizeof(NBP_LOOKUP_ACTION),
ATALK_DEV_ANY,
AtalkNbpTdiAction
},
{
sizeof(NBP_CONFIRM_ACTION),
COMMON_ACTION_NBPCONFIRM,
(DFLAG_CNTR | DFLAG_ADDR),
sizeof(NBP_CONFIRM_ACTION),
ATALK_DEV_ANY,
AtalkNbpTdiAction
},
{
sizeof(NBP_REGDEREG_ACTION),
COMMON_ACTION_NBPREGISTER,
DFLAG_ADDR,
sizeof(NBP_REGDEREG_ACTION),
ATALK_DEV_ANY,
AtalkNbpTdiAction
},
{
sizeof(NBP_REGDEREG_ACTION),
COMMON_ACTION_NBPREMOVE,
DFLAG_ADDR,
sizeof(NBP_REGDEREG_ACTION),
ATALK_DEV_ANY,
AtalkNbpTdiAction
},
//
// ZIP dispatch functions
//
{
sizeof(ZIP_GETMYZONE_ACTION),
COMMON_ACTION_ZIPGETMYZONE,
(DFLAG_CNTR | DFLAG_ADDR | DFLAG_MDL),
sizeof(ZIP_GETMYZONE_ACTION),
ATALK_DEV_ANY,
AtalkZipTdiAction
},
{
sizeof(ZIP_GETZONELIST_ACTION),
COMMON_ACTION_ZIPGETZONELIST,
(DFLAG_CNTR | DFLAG_ADDR | DFLAG_MDL),
sizeof(ZIP_GETZONELIST_ACTION),
ATALK_DEV_ANY,
AtalkZipTdiAction
},
{
sizeof(ZIP_GETZONELIST_ACTION),
COMMON_ACTION_ZIPGETLZONES,
(DFLAG_CNTR | DFLAG_ADDR | DFLAG_MDL),
sizeof(ZIP_GETZONELIST_ACTION),
ATALK_DEV_ANY,
AtalkZipTdiAction
},
{
sizeof(ZIP_GETZONELIST_ACTION),
COMMON_ACTION_ZIPGETLZONESONADAPTER,
(DFLAG_CNTR | DFLAG_ADDR | DFLAG_MDL),
sizeof(ZIP_GETZONELIST_ACTION),
ATALK_DEV_ANY,
AtalkZipTdiAction
},
{
sizeof(ZIP_GETPORTDEF_ACTION),
COMMON_ACTION_ZIPGETADAPTERDEFAULTS,
(DFLAG_CNTR | DFLAG_ADDR | DFLAG_MDL),
sizeof(ZIP_GETPORTDEF_ACTION),
ATALK_DEV_ANY,
AtalkZipTdiAction
},
{
sizeof(ATALK_STATS) +
sizeof(GET_STATISTICS_ACTION),
COMMON_ACTION_GETSTATISTICS,
(DFLAG_CNTR | DFLAG_ADDR | DFLAG_MDL),
sizeof(GET_STATISTICS_ACTION),
ATALK_DEV_ANY,
AtalkStatTdiAction
},
//
// ADSP dispatch functions
//
{
sizeof(ADSP_FORWARDRESET_ACTION),
ACTION_ADSPFORWARDRESET,
(DFLAG_CONN),
sizeof(ADSP_FORWARDRESET_ACTION),
ATALK_DEV_ADSP,
AtalkAdspTdiAction
},
//
// ASPC Dispatch functions
//
{
sizeof(ASPC_GETSTATUS_ACTION),
ACTION_ASPCGETSTATUS,
(DFLAG_ADDR | DFLAG_MDL),
sizeof(ASPC_GETSTATUS_ACTION),
ATALK_DEV_ASPC,
AtalkAspCTdiAction
},
{
sizeof(ASPC_COMMAND_OR_WRITE_ACTION),
ACTION_ASPCCOMMAND,
(DFLAG_CONN | DFLAG_MDL),
sizeof(ASPC_COMMAND_OR_WRITE_ACTION),
ATALK_DEV_ASPC,
AtalkAspCTdiAction
},
{
sizeof(ASPC_COMMAND_OR_WRITE_ACTION),
ACTION_ASPCWRITE,
(DFLAG_CONN | DFLAG_MDL),
sizeof(ASPC_COMMAND_OR_WRITE_ACTION),
ATALK_DEV_ASPC,
AtalkAspCTdiAction
},
//
// NBP dispatch functions used by atalk
// winsock helper dll's SetService Api
//
{
sizeof(NBP_REGDEREG_ACTION),
COMMON_ACTION_NBPREGISTER_BY_ADDR,
DFLAG_ADDR,
sizeof(NBP_REGDEREG_ACTION),
ATALK_DEV_ANY,
AtalkNbpTdiAction
},
{
sizeof(NBP_REGDEREG_ACTION),
COMMON_ACTION_NBPREMOVE_BY_ADDR,
DFLAG_ADDR,
sizeof(NBP_REGDEREG_ACTION),
ATALK_DEV_ANY,
AtalkNbpTdiAction
},
{
sizeof(ASPC_RESERVED_ACTION),
ACTION_ASPCRESERVED3,
(DFLAG_ADDR),
sizeof(ASPC_RESERVED_ACTION),
ATALK_DEV_ASPC,
AtalkAspCTdiAction
},
//
// ASP Dispatch functions
//
{
sizeof(ASP_BIND_ACTION),
ACTION_ASP_BIND,
(DFLAG_ADDR),
sizeof(ASP_BIND_ACTION),
ATALK_DEV_ASP,
AtalkAspTdiAction
},
//
// PAP dispatch routines
//
{
sizeof(PAP_GETSTATUSSRV_ACTION),
ACTION_PAPGETSTATUSSRV,
(DFLAG_ADDR | DFLAG_CNTR | DFLAG_MDL),
sizeof(PAP_GETSTATUSSRV_ACTION),
ATALK_DEV_PAP,
AtalkPapTdiAction
},
{
sizeof(PAP_SETSTATUS_ACTION),
ACTION_PAPSETSTATUS,
(DFLAG_ADDR | DFLAG_MDL),
sizeof(PAP_SETSTATUS_ACTION),
ATALK_DEV_PAP,
AtalkPapTdiAction
},
{
sizeof(PAP_PRIMEREAD_ACTION),
ACTION_PAPPRIMEREAD,
(DFLAG_CONN | DFLAG_MDL),
0, // !!!NOTE!!!
ATALK_DEV_PAP, // We set the offset to be 0. We want the
AtalkPapTdiAction // complete buffer to be used for read data
// overwriting action header to preserve
} // winsock read model.
};