/*++ 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 --*/ #define ATKINIT_LOCALS #define FILENUM ATKINIT #include #pragma hdrstop #ifdef ALLOC_PRAGMA #pragma alloc_text(INIT, AtalkInitializeTransport) #pragma alloc_text(PAGEINIT, atalkInitGetHandleToKey) #pragma alloc_text(INIT, 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; } // 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; 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; } // Initialize the global port descriptors AtalkPortList = NULL; AtalkDefaultPort = NULL; AtalkNumberOfPorts = 0; AtalkRouter = FALSE; // 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) { AtalkRouter = TRUE; AtalkRtmpInit(TRUE); AtalkLockRouterIfNecessary(); } } else { DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_ERR, ("atalkInitGlobal: EnableRouter value not found, assuming false\nq")); } // 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); break; } portName = (PWCHAR)((PBYTE)Info + Info->DataOffset); AtalkDefaultPortName.Buffer = NULL; if (*portName != 0) { RtlInitUnicodeString(&unicodePortName, portName); 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); ZwClose(ParametersHandle); status = STATUS_UNSUCCESSFUL; 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; } // 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); // 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\ 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\ 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\ 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; // Ensure that the zone exists in the zone list, We are seed-routing ASSERT(pPortDesc->pd_Flags & PD_SEED_ROUTER); for (pZone = pPortDesc->pd_InitialZoneList->zl_pZone; pZone != NULL; pZone = pZone->zn_Next) { 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; 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; } error = AtalkInitNdisQueryAddrInfo(pPortDesc); if (!ATALK_SUCCESS(error)) { break; } // Set lookahead to be the max of the complete aarp packet including link error = AtalkInitNdisSetLookaheadSize(pPortDesc, (pPortDesc->pd_NdisPortType == NdisMedium802_5) ? AARPLINK_MAX_PKT_SIZE + TLAP_MAX_LINKHDR_LEN : AARPLINK_MAX_PKT_SIZE); if (!ATALK_SUCCESS(error)) { break; } if (*pPortDesc->pd_AddMulticastAddr) { error = (*pPortDesc->pd_AddMulticastAddr)(pPortDesc, pPortDesc->pd_BroadcastAddr, TRUE, NULL, NULL); if (!ATALK_SUCCESS(error)) { break; } } error = AtalkInitNdisStartPacketReception(pPortDesc); if (!ATALK_SUCCESS(error)) { LOG_ERRORONPORT(pPortDesc, EVENT_ATALK_RECEPTION, 0, NULL, 0); break; } // 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); // 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 = 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); 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 = 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); 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); } // Set up the name in the statistics structure. length = MIN(pPortDesc->pd_AdapterKey.Length, MAX_PORTNAME_LEN - sizeof(WCHAR)); RtlCopyMemory(pPortDesc->pd_PortStats.prtst_PortName, pPortDesc->pd_AdapterKey.Buffer, length); *(pPortDesc->pd_PortStats.prtst_PortName + length) = '\0'; AtalkStatistics.stat_NumActivePorts++; AtalkNumberOfActivePorts ++; status = STATUS_SUCCESS; } while (FALSE); if (!NT_SUCCESS(status)) { DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_ERR, ("atalkInitStartPort: Start port failed %lx\n", status)); } 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 ) /*++ Routine Description: Arguments: Return Value: --*/ { PPORT_DESCRIPTOR pPortDesc; KIRQL OldIrql; PWCHAR devicePrefix = L"\\Device\\"; #define prefixLength (sizeof(L"\\Device\\") - sizeof(WCHAR)) NTSTATUS Status; UNICODE_STRING Us; UNICODE_STRING AspDeviceName; HANDLE RegHandle; 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)) { break; } // 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. This is a kludge to force LONGLONG alignment. pPortDesc = (PPORT_DESCRIPTOR)AtalkAllocZeroedMemory(sizeof(PORT_DESCRIPTOR) + AdapterName->Length + sizeof(WCHAR) + sizeof(DWORD)); if (pPortDesc == NULL) { Status = STATUS_INSUFFICIENT_RESOURCES; break; } // Past the extra DWORD that we allocated above (PDWORD)pPortDesc += 1; // 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; // Now initialize any other fields that need to be. INITIALIZE_SPIN_LOCK(&pPortDesc->pd_Lock); InitializeListHead(&pPortDesc->pd_ReceiveQueue); // 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); if (RtlEqualUnicodeString(&pPortDesc->pd_AdapterName, &AtalkDefaultPortName, 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); // Get per port parameters Status = atalkInitPort(pPortDesc, RegHandle); if (NT_SUCCESS(Status)) { // Now bind to the adapter Status = AtalkNdisInitBind(pPortDesc); if (Status == NDIS_STATUS_SUCCESS) { // And start the port Status = atalkInitStartPort(pPortDesc); if (NT_SUCCESS(Status) && (pPortDesc->pd_Flags & PD_DEF_PORT)) { // 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); Status = TdiRegisterDeviceObject( &AspDeviceName, &TdiRegistrationHandle); if (!NT_SUCCESS(Status)) { DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_ERR, ( "TdiRegisterDeviceObject failed with %lx\n", Status)); TdiRegistrationHandle = NULL; } } } if (pPortDesc->pd_AdapterInfoHandle != NULL) { ZwClose(pPortDesc->pd_AdapterInfoHandle); pPortDesc->pd_AdapterInfoHandle = NULL; } } else { DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_ERR, ( "AtalkInitBinding failed %lx\n", Status)); } } while (FALSE); // Close the Adapters Key if (RegHandle != NULL) ZwClose (RegHandle); 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. };