2396 lines
60 KiB
C
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.
|
|
};
|
|
|