/*++ Copyright (c) 1989-1993 Microsoft Corporation Module Name: config.c Abstract: This contains all routines necessary for the support of the dynamic configuration of the ISN IPX module. Revision History: Sanjay Anand (SanjayAn) 19-Sept-1995 Changes to support Plug and Play --*/ #include "precomp.h" #pragma hdrstop // // Local functions used to access the registry. // NTSTATUS IpxGetConfigValue( IN PWSTR ValueName, IN ULONG ValueType, IN PVOID ValueData, IN ULONG ValueLength, IN PVOID Context, IN PVOID EntryContext ); NTSTATUS IpxGetBindingValue( IN PWSTR ValueName, IN ULONG ValueType, IN PVOID ValueData, IN ULONG ValueLength, IN PVOID Context, IN PVOID EntryContext ); NTSTATUS IpxGetFrameType( IN PWSTR ValueName, IN ULONG ValueType, IN PVOID ValueData, IN ULONG ValueLength, IN PVOID Context, IN PVOID EntryContext ); NTSTATUS IpxAddBind( IN PWSTR ValueName, IN ULONG ValueType, IN PVOID ValueData, IN ULONG ValueLength, IN PVOID Context, IN PVOID EntryContext ); NTSTATUS IpxAddExport( IN PWSTR ValueName, IN ULONG ValueType, IN PVOID ValueData, IN ULONG ValueLength, IN PVOID Context, IN PVOID EntryContext ); NTSTATUS IpxReadLinkageInformation( IN PCONFIG Config ); #ifdef ALLOC_PRAGMA #pragma alloc_text(INIT,IpxGetConfiguration) #pragma alloc_text(INIT,IpxFreeConfiguration) #pragma alloc_text(INIT,IpxAddBind) #pragma alloc_text(INIT,IpxAddExport) #pragma alloc_text(INIT,IpxReadLinkageInformation) #endif #define MAX_PATH 260 NTSTATUS IpxGetConfiguration ( IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath, OUT PCONFIG * ConfigPtr ) /*++ Routine Description: This routine is called by IPX to get information from the configuration management routines. We read the registry, starting at RegistryPath, to get the parameters. If they don't exist, we use the defaults set in ipxcnfg.h file. A list of adapters to bind to is chained on to the config information. Arguments: DriverObject - Used for logging errors. RegistryPath - The name of IPX's node in the registry. ConfigPtr - Returns the configuration information. Return Value: Status - STATUS_SUCCESS if everything OK, STATUS_INSUFFICIENT_RESOURCES otherwise. --*/ { PWSTR RegistryPathBuffer; PCONFIG Config; RTL_QUERY_REGISTRY_TABLE QueryTable[CONFIG_PARAMETERS+2]; NTSTATUS Status; ULONG Zero = 0; ULONG One = 1; ULONG Five = 5; ULONG Eight = 8; ULONG Ten = 10; ULONG Fifteen = 15; ULONG Fifty = 50; ULONG DefaultSocketStart = 0x4000; ULONG DefaultSocketEnd = 0x8000; ULONG RipSegments = RIP_SEGMENTS; PWSTR Parameters = L"Parameters"; struct { PWSTR KeyName; PULONG DefaultValue; } ParameterValues[CONFIG_PARAMETERS] = { { L"DedicatedRouter", &Zero } , { L"InitDatagrams", &Ten } , { L"MaxDatagrams", &Fifty } , { L"RipAgeTime", &Five } , // minutes { L"RipCount", &Five } , { L"RipTimeout", &One } , // half-second { L"RipUsageTime", &Fifteen } , // minutes { L"SourceRouteUsageTime", &Ten } , // minutes { L"SocketUniqueness", &Eight } , { L"SocketStart", &DefaultSocketStart } , { L"SocketEnd", &DefaultSocketEnd } , { L"VirtualNetworkNumber", &Zero } , { L"MaxMemoryUsage", &Zero } , { L"RipTableSize", &RipSegments } , { L"VirtualNetworkOptional", &One } , { L"EthernetPadToEven", &One } , { L"EthernetExtraPadding", &Zero } , { L"SingleNetworkActive", &Zero } , { L"DisableDialoutSap", &Zero } , { L"DisableDialinNetbios", &One } , { L"VerifySourceAddress", &One } }; UINT i; // // Allocate memory for the main config structure. // Config = IpxAllocateMemory (sizeof(CONFIG), MEMORY_CONFIG, "Config"); if (Config == NULL) { IpxWriteResourceErrorLog( (PVOID)DriverObject, EVENT_TRANSPORT_RESOURCE_POOL, sizeof(CONFIG), MEMORY_CONFIG); return STATUS_INSUFFICIENT_RESOURCES; } Config->DeviceName.Buffer = NULL; InitializeListHead (&Config->BindingList); Config->DriverObject = DriverObject; // // Read in the NDIS binding information. // // IpxReadLinkageInformation expects a null-terminated path, // so we have to create one from the UNICODE_STRING. // RegistryPathBuffer = (PWSTR)IpxAllocateMemory(RegistryPath->Length + sizeof(WCHAR), MEMORY_CONFIG, "RegistryPathBuffer"); if (RegistryPathBuffer == NULL) { IpxFreeConfiguration(Config); IpxWriteResourceErrorLog( (PVOID)DriverObject, EVENT_TRANSPORT_RESOURCE_POOL, RegistryPath->Length + sizeof(WCHAR), MEMORY_CONFIG); return STATUS_INSUFFICIENT_RESOURCES; } RtlCopyMemory (RegistryPathBuffer, RegistryPath->Buffer, RegistryPath->Length); *(PWCHAR)(((PUCHAR)RegistryPathBuffer)+RegistryPath->Length) = (WCHAR)'\0'; Config->RegistryPathBuffer = RegistryPathBuffer; // // Determine what name to export and who to bind to. // Status = IpxReadLinkageInformation (Config); if (Status != STATUS_SUCCESS) { // // It logged an error if it failed. // IpxFreeMemory (Config->RegistryPathBuffer, RegistryPath->Length + sizeof(WCHAR), MEMORY_CONFIG, "RegistryPathBuffer"); IpxFreeConfiguration(Config); return Status; } // // Read the per-transport (as opposed to per-binding) // parameters. // // // Set up QueryTable to do the following: // // // 1) Switch to the Parameters key below IPX // QueryTable[0].QueryRoutine = NULL; QueryTable[0].Flags = RTL_QUERY_REGISTRY_SUBKEY; QueryTable[0].Name = Parameters; // // 2-14) Call IpxGetConfigValue for each of the keys we // care about. // for (i = 0; i < CONFIG_PARAMETERS; i++) { QueryTable[i+1].QueryRoutine = IpxGetConfigValue; QueryTable[i+1].Flags = 0; QueryTable[i+1].Name = ParameterValues[i].KeyName; QueryTable[i+1].EntryContext = UlongToPtr(i); QueryTable[i+1].DefaultType = REG_DWORD; QueryTable[i+1].DefaultData = (PVOID)(ParameterValues[i].DefaultValue); QueryTable[i+1].DefaultLength = sizeof(ULONG); } // // 15) Stop // QueryTable[CONFIG_PARAMETERS+1].QueryRoutine = NULL; QueryTable[CONFIG_PARAMETERS+1].Flags = 0; QueryTable[CONFIG_PARAMETERS+1].Name = NULL; Status = RtlQueryRegistryValues( RTL_REGISTRY_ABSOLUTE, Config->RegistryPathBuffer, QueryTable, (PVOID)Config, NULL); if (Status != STATUS_SUCCESS) { IpxFreeMemory (Config->RegistryPathBuffer, RegistryPath->Length + sizeof(WCHAR), MEMORY_CONFIG, "RegistryPathBuffer"); IpxFreeConfiguration(Config); IpxWriteGeneralErrorLog( (PVOID)DriverObject, EVENT_IPX_ILLEGAL_CONFIG, 905, Status, Parameters, 0, NULL); return STATUS_DEVICE_CONFIGURATION_ERROR; } // // For PnP, we need to keep this path around // *ConfigPtr = Config; return STATUS_SUCCESS; } /* IpxGetConfiguration */ VOID IpxFreeConfiguration ( IN PCONFIG Config ) /*++ Routine Description: This routine is called by IPX to get free any storage that was allocated by IpxGetConfiguration in producing the specified CONFIG structure. Arguments: Config - A pointer to the configuration information structure. Return Value: None. --*/ { PLIST_ENTRY p; PBINDING_CONFIG Binding; while (!IsListEmpty (&Config->BindingList)) { p = RemoveHeadList (&Config->BindingList); Binding = CONTAINING_RECORD (p, BINDING_CONFIG, Linkage); IpxFreeMemory (Binding->AdapterName.Buffer, Binding->AdapterName.MaximumLength, MEMORY_CONFIG, "NameBuffer"); IpxFreeMemory (Binding, sizeof(BINDING_CONFIG), MEMORY_CONFIG, "Binding"); } if (Config->DeviceName.Buffer) { IpxFreeMemory (Config->DeviceName.Buffer, Config->DeviceName.MaximumLength, MEMORY_CONFIG, "DeviceName"); } IpxFreeMemory (Config, sizeof(CONFIG), MEMORY_CONFIG, "Config"); } /* IpxFreeConfiguration */ NTSTATUS IpxGetConfigValue( IN PWSTR ValueName, IN ULONG ValueType, IN PVOID ValueData, IN ULONG ValueLength, IN PVOID Context, IN PVOID EntryContext ) /*++ Routine Description: This routine is a callback routine for RtlQueryRegistryValues It is called for each entry in the Parameters node to set the config values. The table is set up so that this function will be called with correct default values for keys that are not present. Arguments: ValueName - The name of the value (ignored). ValueType - The type of the value (REG_DWORD -- ignored). ValueData - The data for the value. ValueLength - The length of ValueData (ignored). Context - A pointer to the CONFIG structure. EntryContext - The index in Config->Parameters to save the value. Return Value: STATUS_SUCCESS --*/ { PCONFIG Config = (PCONFIG)Context; UNREFERENCED_PARAMETER(ValueName); UNREFERENCED_PARAMETER(ValueType); UNREFERENCED_PARAMETER(ValueLength); if ((ValueType != REG_DWORD) || (ValueLength != sizeof(ULONG))) { IpxWriteGeneralErrorLog( (PVOID)Config->DriverObject, EVENT_IPX_ILLEGAL_CONFIG, 904, STATUS_INVALID_PARAMETER, ValueName, 0, NULL); return STATUS_INVALID_PARAMETER; } #ifdef SUNDOWN IPX_DEBUG (CONFIG, ("Config parameter %d, value %lx\n", (ULONG_PTR)EntryContext, *(UNALIGNED ULONG *)ValueData)); Config->Parameters[(ULONG_PTR)EntryContext] = *(UNALIGNED ULONG *)ValueData; #else IPX_DEBUG (CONFIG, ("Config parameter %d, value %lx\n", (ULONG)EntryContext, *(UNALIGNED ULONG *)ValueData)); Config->Parameters[(ULONG)EntryContext] = *(UNALIGNED ULONG *)ValueData; #endif return STATUS_SUCCESS; } /* IpxGetConfigValue */ NTSTATUS IpxGetBindingValue( IN PWSTR ValueName, IN ULONG ValueType, IN PVOID ValueData, IN ULONG ValueLength, IN PVOID Context, IN PVOID EntryContext ) /*++ Routine Description: This routine is a callback routine for RtlQueryRegistryValues It is called for each entry in the NetConfig\DriverNN node to set the per-binding values. The table is set up so that this function will be called with correct default values for keys that are not present. Arguments: ValueName - The name of the value (ignored). ValueType - The type of the value (REG_DWORD -- ignored). ValueData - The data for the value. ValueLength - The length of ValueData (ignored). Context - A pointer to the BINDING_CONFIG structure. EntryContext - The index in Binding->Parameters to save the value. Return Value: STATUS_SUCCESS --*/ { PBINDING_CONFIG Binding = (PBINDING_CONFIG)Context; UNREFERENCED_PARAMETER(ValueName); UNREFERENCED_PARAMETER(ValueType); UNREFERENCED_PARAMETER(ValueLength); if ((ValueType != REG_DWORD) || (ValueLength != sizeof(ULONG))) { IpxWriteGeneralErrorLog( (PVOID)Binding->DriverObject, EVENT_IPX_ILLEGAL_CONFIG, 903, STATUS_INVALID_PARAMETER, ValueName, 0, NULL); return STATUS_INVALID_PARAMETER; } #ifdef SUNDOWN IPX_DEBUG (CONFIG, ("Binding parameter %d, value %lx\n", (ULONG_PTR)EntryContext, *(UNALIGNED ULONG *)ValueData)); Binding->Parameters[(ULONG_PTR)EntryContext] = *(UNALIGNED ULONG *)ValueData; #else IPX_DEBUG (CONFIG, ("Binding parameter %d, value %lx\n", (ULONG)EntryContext, *(UNALIGNED ULONG *)ValueData)); Binding->Parameters[(ULONG)EntryContext] = *(UNALIGNED ULONG *)ValueData; #endif return STATUS_SUCCESS; } /* IpxGetBindingValue */ NTSTATUS IpxGetFrameType( IN PWSTR ValueName, IN ULONG ValueType, IN PVOID ValueData, IN ULONG ValueLength, IN PVOID Context, IN PVOID EntryContext ) /*++ Routine Description: This routine is a callback routine for RtlQueryRegistryValues. It is called for each of the entry in the "PktType" and "NetworkNumber" multi-strings for a given binding. Arguments: ValueName - The name of the value ("PktType" or "NetworkNumber" -- ignored). ValueType - The type of the value (REG_MULTI_SZ -- ignored). ValueData - The null-terminated data for the value. ValueLength - The length of ValueData. Context - A pointer to the BINDING_CONFIG structure. EntryContext - A pointer to a count of multi-string entries. Return Value: STATUS_SUCCESS --*/ { PBINDING_CONFIG Binding = (PBINDING_CONFIG)Context; ULONG IntegerValue; PWCHAR Cur; PULONG Count = (PULONG)EntryContext; ASSERT(Binding->DriverObject != NULL); if ((ValueType != REG_SZ) || (*Count >= 4)) { IpxWriteGeneralErrorLog( (PVOID)Binding->DriverObject, EVENT_IPX_ILLEGAL_CONFIG, 903, STATUS_INVALID_PARAMETER, ValueName, 0, NULL); return STATUS_INVALID_PARAMETER; } IntegerValue = 0; for (Cur = (PWCHAR)(ValueData); ; Cur++) { if (*Cur >= L'0' && *Cur <= L'9') { IntegerValue = (IntegerValue * 16) + (*Cur - L'0'); } else if (*Cur >= L'A' && *Cur <= L'F') { IntegerValue = (IntegerValue * 16) + (*Cur - L'A' + 10); } else if (*Cur >= L'a' && *Cur <= L'f') { IntegerValue = (IntegerValue * 16) + (*Cur - L'a' + 10); } else { break; } } if (((PWCHAR)ValueName)[0] == L'P') { // // PktType. We map arcnet to 802_3 so the code around // here can assume there are only four packets type -- // the frame type is ignored later for arcnet. // if ((IntegerValue > ISN_FRAME_TYPE_ARCNET) && (IntegerValue != ISN_FRAME_TYPE_AUTO)) { IpxWriteGeneralErrorLog( (PVOID)Binding->DriverObject, EVENT_IPX_ILLEGAL_CONFIG, 903, STATUS_INVALID_PARAMETER, ValueName, 0, NULL); return STATUS_INVALID_PARAMETER; } IPX_DEBUG (CONFIG, ("PktType(%d) is %lx\n", *Count, IntegerValue)); if (IntegerValue == ISN_FRAME_TYPE_ARCNET) { Binding->FrameType[*Count] = ISN_FRAME_TYPE_802_3; } else { Binding->FrameType[*Count] = IntegerValue; } } else { // // NetworkNumber // IPX_DEBUG (CONFIG, ("NetworkNumber(%d) is %d\n", *Count, IntegerValue)); Binding->NetworkNumber[*Count] = IntegerValue; } ++(*Count); return STATUS_SUCCESS; } /* IpxGetFrameType */ NTSTATUS IpxAddBind( IN PWSTR ValueName, IN ULONG ValueType, IN PVOID ValueData, IN ULONG ValueLength, IN PVOID Context, IN PVOID EntryContext ) /*++ Routine Description: This routine is a callback routine for RtlQueryRegistryValues It is called for each piece of the "Bind" multi-string and saves the information in a Config structure. It also queries the per-binding information and stores it. Arguments: ValueName - The name of the value ("Bind" -- ignored). ValueType - The type of the value (REG_SZ -- ignored). ValueData - The null-terminated data for the value. ValueLength - The length of ValueData. Context - A pointer to the Config structure. EntryContext - A pointer to a count of binds that is incremented. Return Value: STATUS_SUCCESS --*/ { PCONFIG Config = (PCONFIG)Context; PBINDING_CONFIG Binding; PULONG CurBindNum = ((PULONG)EntryContext); RTL_QUERY_REGISTRY_TABLE QueryTable[BINDING_PARAMETERS+4]; ULONG FrameTypeCount, NetworkNumberCount; ULONG StringLoc; BOOLEAN AutoDetect; ULONG AutoDetectLoc; ULONG SlideCount; PWCHAR NameBuffer; NTSTATUS Status; BOOLEAN FrameTypeUsed[ISN_FRAME_TYPE_MAX]; ULONG Zero = 0; ULONG One = 1; ULONG DefaultBindSap = 0x8137; ULONG DefaultAutoDetectType = ISN_FRAME_TYPE_802_2; WCHAR Subkey[MAX_PATH];// = L"Parameters\\Adapters\\12345678901234567890"; PWSTR ValueDataWstr = (PWSTR)ValueData; struct { PWSTR KeyName; PULONG DefaultValue; } ParameterValues[BINDING_PARAMETERS] = { { L"MaxPktSize", &Zero } , { L"BindSap", &DefaultBindSap } , { L"DefaultAutoDetectType", &DefaultAutoDetectType } , { L"SourceRouting", &One } , { L"SourceRouteDef", &Zero } , { L"SourceRouteBcast", &Zero } , { L"SourceRouteMcast", &Zero } , { L"EnableFuncaddr", &One } , { L"EnableWanRouter", &One } }; ULONG BindingPreference[ISN_FRAME_TYPE_MAX] = { ISN_FRAME_TYPE_802_2, ISN_FRAME_TYPE_802_3, ISN_FRAME_TYPE_ETHERNET_II, ISN_FRAME_TYPE_SNAP }; UINT i, j, k; UNREFERENCED_PARAMETER(ValueName); UNREFERENCED_PARAMETER(ValueType); Binding = (PBINDING_CONFIG)IpxAllocateMemory (sizeof(BINDING_CONFIG), MEMORY_CONFIG, "Binding"); if (Binding == NULL) { IpxWriteResourceErrorLog( (PVOID)Config->DriverObject, EVENT_TRANSPORT_RESOURCE_POOL, sizeof(BINDING_CONFIG), MEMORY_CONFIG); return STATUS_INSUFFICIENT_RESOURCES; } NameBuffer = (PWCHAR)IpxAllocateMemory (ValueLength, MEMORY_CONFIG, "NameBuffer"); if (NameBuffer == NULL) { IpxFreeMemory (Binding, sizeof(BINDING_CONFIG), MEMORY_CONFIG, "Binding"); IpxWriteResourceErrorLog( (PVOID)Config->DriverObject, EVENT_TRANSPORT_RESOURCE_POOL, ValueLength, MEMORY_CONFIG); return STATUS_INSUFFICIENT_RESOURCES; } RtlCopyMemory (NameBuffer, ValueData, ValueLength); Binding->AdapterName.Buffer = NameBuffer; Binding->AdapterName.Length = (USHORT)(ValueLength - sizeof(WCHAR)); Binding->AdapterName.MaximumLength = (USHORT)ValueLength; Binding->DriverObject = Config->DriverObject; FrameTypeCount = 0; NetworkNumberCount = 0; // // The structure is allocated OK, insert it into the list. // InsertTailList (&Config->BindingList, &Binding->Linkage); ++(*CurBindNum); // // Set up QueryTable to do the following: // // // 1) Switch to the NetConfig\XXXX key below IPX // (we construct the right name in Subkey, // first scan back to find the \, then copy // the rest over, including the final '\0'). // StringLoc = (ValueLength / sizeof(WCHAR)) - 2; while (ValueDataWstr[StringLoc] != L'\\') { --StringLoc; } RtlCopyMemory(&Subkey, L"Parameters\\Adapters\\12345678901234567890", 40); RtlCopyMemory(&Subkey[20], &ValueDataWstr[StringLoc+1], ValueLength - ((StringLoc+1) * sizeof(WCHAR))); KdPrint(("Subkey:%ws\n", Subkey)); QueryTable[0].QueryRoutine = NULL; QueryTable[0].Flags = RTL_QUERY_REGISTRY_SUBKEY; QueryTable[0].Name = Subkey; // // 2) Call IpxGetFrameType for each part of the // "PktType" multi-string. // QueryTable[1].QueryRoutine = IpxGetFrameType; QueryTable[1].Flags = RTL_QUERY_REGISTRY_REQUIRED; QueryTable[1].Name = L"PktType"; QueryTable[1].EntryContext = &FrameTypeCount; QueryTable[1].DefaultType = REG_NONE; // // 3) Call IpxGetFrameType for each part of the // "NetworkNumber" multi-string. // QueryTable[2].QueryRoutine = IpxGetFrameType; QueryTable[2].Flags = RTL_QUERY_REGISTRY_REQUIRED; QueryTable[2].Name = L"NetworkNumber"; QueryTable[2].EntryContext = &NetworkNumberCount; QueryTable[2].DefaultType = REG_NONE; // // 4-11) Call IpxGetBindingValue for each of the keys we // care about. // for (i = 0; i < BINDING_PARAMETERS; i++) { QueryTable[i+3].QueryRoutine = IpxGetBindingValue; QueryTable[i+3].Flags = 0; QueryTable[i+3].Name = ParameterValues[i].KeyName; QueryTable[i+3].EntryContext = UlongToPtr(i); QueryTable[i+3].DefaultType = REG_DWORD; QueryTable[i+3].DefaultData = (PVOID)(ParameterValues[i].DefaultValue); QueryTable[i+3].DefaultLength = sizeof(ULONG); } // // 12) Stop // QueryTable[BINDING_PARAMETERS+3].QueryRoutine = NULL; QueryTable[BINDING_PARAMETERS+3].Flags = 0; QueryTable[BINDING_PARAMETERS+3].Name = NULL; IPX_DEBUG (CONFIG, ("Read bind key for %ws (%ws)\n", ValueData, Subkey)); Status = RtlQueryRegistryValues( RTL_REGISTRY_ABSOLUTE, Config->RegistryPathBuffer, QueryTable, (PVOID)Binding, NULL); if (Status != STATUS_SUCCESS) { // // The binding will get freed during cleanup. // IpxWriteGeneralErrorLog( (PVOID)Config->DriverObject, EVENT_IPX_ILLEGAL_CONFIG, 906, Status, Subkey, 0, NULL); return STATUS_DEVICE_CONFIGURATION_ERROR; } if (FrameTypeCount == 0) { IpxWriteGeneralErrorLog( (PVOID)Config->DriverObject, EVENT_IPX_NO_FRAME_TYPES, 907, Status, Subkey + 10, 0, NULL); } if (FrameTypeCount > NetworkNumberCount) { for (i = NetworkNumberCount; i NetworkNumber[i] = 0; } } Binding->FrameTypeCount = FrameTypeCount; // // Go through and eliminate duplicates from the frame // type array. // for (i = 0; i < Binding->FrameTypeCount; i++) { for (j = i+1; j < Binding->FrameTypeCount; j++) { if (Binding->FrameType[j] == Binding->FrameType[i]) { IPX_DEBUG (CONFIG, ("Frame types %d and %d identical\n", i, j)); // // A duplicate, slide everything else down. // for (k = j+1; k < Binding->FrameTypeCount; k++) { Binding->FrameType[k-1] = Binding->FrameType[k]; Binding->NetworkNumber[k-1] = Binding->NetworkNumber[k]; } --Binding->FrameTypeCount; --j; // so we check whoever just moved into this spot. } } } // // Mark all the explicitly configured frame types, and // see if we have to auto-detect. // for (i = 0; i < 4; i++) { FrameTypeUsed[i] = FALSE; } AutoDetect = FALSE; for (i = 0; i < Binding->FrameTypeCount; i++) { if (Binding->FrameType[i] == ISN_FRAME_TYPE_AUTO) { AutoDetectLoc = i; AutoDetect = TRUE; } else { Binding->AutoDetect[i] = FALSE; Binding->DefaultAutoDetect[i] = FALSE; FrameTypeUsed[Binding->FrameType[i]] = TRUE; } } if (!AutoDetect) { IPX_DEBUG (AUTO_DETECT, ("No bindings auto-detected\n")); return STATUS_SUCCESS; } // // Slide everything that is past the auto-detect point up // to the end. // SlideCount = Binding->FrameTypeCount - AutoDetectLoc - 1; for (j = 3; j > 3 - SlideCount; j--) { Binding->FrameType[j] = Binding->FrameType[j-(3-Binding->FrameTypeCount)]; Binding->NetworkNumber[j] = Binding->NetworkNumber[j-(3-Binding->FrameTypeCount)]; Binding->AutoDetect[j] = Binding->AutoDetect[j-(3-Binding->FrameTypeCount)]; Binding->DefaultAutoDetect[j] = Binding->DefaultAutoDetect[j-(3-Binding->FrameTypeCount)]; } // // Now fill in any frame types that are not hard-coded, // this will start at AutoDetectLoc and exactly fill up // the gap created when we slid things up above. We // first put the default auto-detect at the first spot. // if (!FrameTypeUsed[Binding->Parameters[BINDING_DEFAULT_AUTO_DETECT]]) { Binding->FrameType[AutoDetectLoc] = Binding->Parameters[BINDING_DEFAULT_AUTO_DETECT]; Binding->NetworkNumber[AutoDetectLoc] = 0; Binding->AutoDetect[AutoDetectLoc] = TRUE; Binding->DefaultAutoDetect[AutoDetectLoc] = TRUE; ++AutoDetectLoc; FrameTypeUsed[Binding->Parameters[BINDING_DEFAULT_AUTO_DETECT]] = TRUE; } // // Now fill in the array, using the preference order in // the BindingPreference array (this comes into effect // because the first frame type in our list that we // find is used). // for (i = 0; i < ISN_FRAME_TYPE_MAX; i++) { if (!FrameTypeUsed[BindingPreference[i]]) { Binding->FrameType[AutoDetectLoc] = BindingPreference[i]; Binding->NetworkNumber[AutoDetectLoc] = 0; Binding->AutoDetect[AutoDetectLoc] = TRUE; Binding->DefaultAutoDetect[AutoDetectLoc] = FALSE; ++AutoDetectLoc; } } Binding->FrameTypeCount = ISN_FRAME_TYPE_MAX; #if DBG for (i = 0; i < ISN_FRAME_TYPE_MAX; i++) { IPX_DEBUG (AUTO_DETECT, ("%d: type %d, net %d, auto %d, defaultautodetect %d\n", i, Binding->FrameType[i], Binding->NetworkNumber[i], Binding->AutoDetect[i], Binding->DefaultAutoDetect[i])); } #endif return STATUS_SUCCESS; } /* IpxAddBind */ NTSTATUS IpxAddExport( IN PWSTR ValueName, IN ULONG ValueType, IN PVOID ValueData, IN ULONG ValueLength, IN PVOID Context, IN PVOID EntryContext ) /*++ Routine Description: This routine is a callback routine for RtlQueryRegistryValues It is called for each piece of the "Export" multi-string. It saves the first callback string in the Config structure. Arguments: ValueName - The name of the value ("Export" -- ignored). ValueType - The type of the value (REG_SZ -- ignored). ValueData - The null-terminated data for the value. ValueLength - The length of ValueData. Context - A pointer to the Config structure. EntryContext - A pointer to a ULONG that goes to 1 after the first call to this routine (so we know to ignore other ones). Return Value: STATUS_SUCCESS --*/ { PCONFIG Config = (PCONFIG)Context; PULONG ValueReadOk = ((PULONG)EntryContext); PWCHAR NameBuffer; UNREFERENCED_PARAMETER(ValueName); UNREFERENCED_PARAMETER(ValueType); if (*ValueReadOk == 0) { IPX_DEBUG (CONFIG, ("Read export value %ws\n", ValueData)); NameBuffer = (PWCHAR)IpxAllocateMemory (ValueLength, MEMORY_CONFIG, "DeviceName"); if (NameBuffer == NULL) { IpxWriteResourceErrorLog( (PVOID)Config->DriverObject, EVENT_TRANSPORT_RESOURCE_POOL, ValueLength, MEMORY_CONFIG); return STATUS_INSUFFICIENT_RESOURCES; } RtlCopyMemory (NameBuffer, ValueData, ValueLength); Config->DeviceName.Buffer = NameBuffer; Config->DeviceName.Length = (USHORT)(ValueLength - sizeof(WCHAR)); Config->DeviceName.MaximumLength = (USHORT)ValueLength; // // Set this to ignore any other callbacks and let the // caller know we read something. // *ValueReadOk = 1; } return STATUS_SUCCESS; } /* IpxAddExport */ NTSTATUS IpxReadLinkageInformation( IN PCONFIG Config ) /*++ Routine Description: This routine is called by IPX to read its linkage information from the registry. Arguments: Config - The config structure which will have per-binding information linked on to it. Return Value: The status of the operation. --*/ { NTSTATUS Status; RTL_QUERY_REGISTRY_TABLE QueryTable[3]; PWSTR Subkey = L"Linkage"; PWSTR Bind = L"Bind"; PWSTR Export = L"Export"; ULONG ValueReadOk; // // Set up QueryTable to do the following: // // // 1) Switch to the Linkage key below IPX // QueryTable[0].QueryRoutine = NULL; QueryTable[0].Flags = RTL_QUERY_REGISTRY_SUBKEY; QueryTable[0].Name = Subkey; // // 1) Call IpxAddExport for each string in "Export" // QueryTable[1].QueryRoutine = IpxAddExport; QueryTable[1].Flags = RTL_QUERY_REGISTRY_REQUIRED; QueryTable[1].Name = Export; QueryTable[1].EntryContext = (PVOID)&ValueReadOk; QueryTable[1].DefaultType = REG_NONE; // // 2) Stop // QueryTable[2].QueryRoutine = NULL; QueryTable[2].Flags = 0; QueryTable[2].Name = NULL; ValueReadOk = 0; Status = RtlQueryRegistryValues( RTL_REGISTRY_ABSOLUTE, Config->RegistryPathBuffer, QueryTable, (PVOID)Config, NULL); if ((Status != STATUS_SUCCESS) || (ValueReadOk == 0)) { IpxWriteGeneralErrorLog( (PVOID)Config->DriverObject, EVENT_IPX_ILLEGAL_CONFIG, 901, Status, Export, 0, NULL); return STATUS_DEVICE_CONFIGURATION_ERROR; } return STATUS_SUCCESS; } /* IpxReadLinkageInformation */ VOID IpxWriteDefaultAutoDetectType( IN PUNICODE_STRING RegistryPath, IN struct _ADAPTER * Adapter, IN ULONG FrameType ) /*++ Routine Description: This routine is called when we were unable to detect the default auto-detect type and instead found a different one. We update the "DefaultAutoDetectType" in the registry. Arguments: RegistryPath - The name of IPX's node in the registry. Adapter - The adapter which we auto-detected on. FrameType - The new auto-detected value. Return Value: None. --*/ { PWSTR FullRegistryPath; PUCHAR CurRegistryPath; ULONG FullRegistryPathLength; ULONG AdapterNameLength; WCHAR Adapters[] = L"\\Parameter\\Adapters\\"; static PWCHAR FrameTypeNames[4] = { L"Ethernet II", L"802.3", L"802.2", L"SNAP" }; PWCHAR CurAdapterName; NTSTATUS Status; // // We need to allocate a buffer which contains the registry path, // followed by "\Parameters\Adapters\", followed by the adapter name, and // then NULL-terminated. // CurAdapterName = &Adapter->AdapterName[(Adapter->AdapterNameLength/sizeof(WCHAR))-2]; while (*CurAdapterName != L'\\') { --CurAdapterName; } // AdapterNameLength is unlikely to exceed 32-bit, RtlCopyMemory takes 32-bit only, so we cast it to ULONG AdapterNameLength = (ULONG) (Adapter->AdapterNameLength - ((CurAdapterName - Adapter->AdapterName) * sizeof(WCHAR)) - sizeof(WCHAR)); FullRegistryPathLength = RegistryPath->Length + sizeof(Adapters) + AdapterNameLength; FullRegistryPath = (PWSTR)IpxAllocateMemory (FullRegistryPathLength, MEMORY_CONFIG, "FullRegistryPath"); if (FullRegistryPath == NULL) { IpxWriteResourceErrorLog( IpxDevice->DeviceObject, EVENT_TRANSPORT_RESOURCE_POOL, FullRegistryPathLength, MEMORY_CONFIG); return; } CurRegistryPath = (PUCHAR)FullRegistryPath; RtlCopyMemory (CurRegistryPath, RegistryPath->Buffer, RegistryPath->Length); CurRegistryPath += RegistryPath->Length; RtlCopyMemory (CurRegistryPath, Adapters, sizeof(Adapters) - sizeof(WCHAR)); CurRegistryPath += (sizeof(Adapters) - sizeof(WCHAR)); RtlCopyMemory (CurRegistryPath, CurAdapterName, AdapterNameLength); CurRegistryPath += AdapterNameLength; *(PWCHAR)CurRegistryPath = L'\0'; Status = RtlWriteRegistryValue( RTL_REGISTRY_ABSOLUTE, FullRegistryPath, L"DefaultAutoDetectType", REG_DWORD, &FrameType, sizeof(ULONG)); IpxFreeMemory (FullRegistryPath, FullRegistryPathLength, MEMORY_CONFIG, "FullRegistryPath"); IpxWriteGeneralErrorLog( IpxDevice->DeviceObject, EVENT_IPX_NEW_DEFAULT_TYPE, 888, STATUS_SUCCESS, FrameTypeNames[FrameType], 0, NULL); } /* IpxWriteDefaultAutoDetectType */ // // Vnet# and VnetOptional // #define VIRTUAL_NETWORK_PARAMETERS 2 NTSTATUS IpxPnPGetVirtualNetworkNumber ( IN PCONFIG Config ) /*++ Routine Description: This routine is called by IPX to read the virtual network number from the registry. This is called on appearance/disappearance of an adapter from the system. We read the registry, starting at RegistryPath, to get the value of the VirtualNetworkNumber parameter. If it doesn't exist, we use the default set in ipxcnfg.h file. Adapted from IpxGetConfiguration(). Arguments: Config - Contians the configuration information. Return Value: Status - STATUS_SUCCESS if everything OK, STATUS_DEVICE_CONFIGURATION_ERROR otherwise. --*/ { RTL_QUERY_REGISTRY_TABLE QueryTable[VIRTUAL_NETWORK_PARAMETERS+2]; NTSTATUS Status; ULONG Zero = 0; ULONG One = 1; PWSTR Parameters = L"Parameters"; struct { PWSTR KeyName; PULONG DefaultValue; } ParameterValues[VIRTUAL_NETWORK_PARAMETERS] = { { L"VirtualNetworkNumber", &Zero } , { L"VirtualNetworkOptional", &One } }; UINT i; // // Read the virtual net number from the parameters. // // // Set up QueryTable to do the following: // // // 1) Switch to the Parameters key below IPX // QueryTable[0].QueryRoutine = NULL; QueryTable[0].Flags = RTL_QUERY_REGISTRY_SUBKEY; QueryTable[0].Name = Parameters; // // 2) Call IpxGetConfigValue for the virtual net number key // QueryTable[1].QueryRoutine = IpxGetConfigValue; QueryTable[1].Flags = 0; QueryTable[1].Name = ParameterValues[0].KeyName; QueryTable[1].EntryContext = (PVOID)CONFIG_VIRTUAL_NETWORK; QueryTable[1].DefaultType = REG_DWORD; QueryTable[1].DefaultData = (PVOID)(ParameterValues[0].DefaultValue); QueryTable[1].DefaultLength = sizeof(ULONG); // // 2) Call IpxGetConfigValue for the virtual net optional key // QueryTable[2].QueryRoutine = IpxGetConfigValue; QueryTable[2].Flags = 0; QueryTable[2].Name = ParameterValues[1].KeyName; QueryTable[2].EntryContext = (PVOID)CONFIG_VIRTUAL_OPTIONAL; QueryTable[2].DefaultType = REG_DWORD; QueryTable[2].DefaultData = (PVOID)(ParameterValues[1].DefaultValue); QueryTable[2].DefaultLength = sizeof(ULONG); // // 15) Stop // QueryTable[3].QueryRoutine = NULL; QueryTable[3].Flags = 0; QueryTable[3].Name = NULL; Status = RtlQueryRegistryValues( RTL_REGISTRY_ABSOLUTE, Config->RegistryPathBuffer, QueryTable, (PVOID)Config, NULL); if (Status != STATUS_SUCCESS) { IpxWriteGeneralErrorLog( (PVOID)Config->DriverObject, EVENT_IPX_ILLEGAL_CONFIG, 905, Status, Parameters, 0, NULL); return STATUS_DEVICE_CONFIGURATION_ERROR; } return STATUS_SUCCESS; } /* IpxPnPGetNetworkNumber */ #define IPX_REG_KEY_CONFIG_NAME L"Parameters\\Adapters\\12345678901234567890" #define IPX_REG_KEY_CONFIG_DUMMY_LENGTH 40 #define IPX_REG_KEY_CONFIG_LENGTH 20 NTSTATUS IpxPnPGetAdapterParameters( IN PCONFIG Config, IN PNDIS_STRING DeviceName, IN OUT PBINDING_CONFIG Binding ) /*++ Routine Description: This routine is called by IPX to read the adapter-specific parameters from the registry on PnP appearance of an adapter in the system. We read the registry, starting at RegistryPath\NetConfig\DeviceName. Adapted from IpxAddBind(). Arguments: Config - Config structure - supplies the DeviceObject and RegistryPathBuffer. DeviceName - name of the adapter that was added. Binding - Returns the configuration information per adapter. Return Value: Status - STATUS_SUCCESS if everything OK, STATUS_DEVICE_CONFIGURATION_ERROR otherwise. --*/ { RTL_QUERY_REGISTRY_TABLE QueryTable[BINDING_PARAMETERS+4]; ULONG FrameTypeCount, NetworkNumberCount; ULONG StringLoc; BOOLEAN AutoDetect; ULONG AutoDetectLoc; ULONG SlideCount; PWCHAR NameBuffer; NTSTATUS Status; BOOLEAN FrameTypeUsed[ISN_FRAME_TYPE_MAX]; ULONG Zero = 0; ULONG One = 1; ULONG DefaultBindSap = 0x8137; ULONG DefaultAutoDetectType = ISN_FRAME_TYPE_802_2; WCHAR Subkey[MAX_PATH];// = L"NetConfig\\12345678901234567890"; struct { PWSTR KeyName; PULONG DefaultValue; } ParameterValues[BINDING_PARAMETERS] = { { L"MaxPktSize", &Zero } , { L"BindSap", &DefaultBindSap } , { L"DefaultAutoDetectType", &DefaultAutoDetectType } , { L"SourceRouting", &One } , { L"SourceRouteDef", &Zero } , { L"SourceRouteBcast", &Zero } , { L"SourceRouteMcast", &Zero } , { L"EnableFuncaddr", &One } , { L"EnableWanRouter", &One } }; ULONG BindingPreference[ISN_FRAME_TYPE_MAX] = { ISN_FRAME_TYPE_802_2, ISN_FRAME_TYPE_802_3, ISN_FRAME_TYPE_ETHERNET_II, ISN_FRAME_TYPE_SNAP }; UINT i, j, k; ASSERT(Binding->DriverObject != NULL); FrameTypeCount = 0; NetworkNumberCount = 0; // // The structure is allocated OK, insert it into the list. // // InsertTailList (&Config->BindingList, &Binding->Linkage); // ++(*CurBindNum); // // Set up QueryTable to do the following: // // // 1) Switch to the NetConfig\XXXX key below IPX // (we construct the right name in Subkey, // first scan back to find the \, then copy // the rest over, including the final '\0'). // StringLoc = (DeviceName->Length / sizeof(WCHAR)) - 2; while (DeviceName->Buffer[StringLoc] != L'\\') { --StringLoc; } RtlCopyMemory(&Subkey, IPX_REG_KEY_CONFIG_NAME, IPX_REG_KEY_CONFIG_DUMMY_LENGTH); RtlCopyMemory(&Subkey[IPX_REG_KEY_CONFIG_LENGTH], &DeviceName->Buffer[StringLoc+1], DeviceName->Length - ((StringLoc+1) * sizeof(WCHAR))); Subkey[IPX_REG_KEY_CONFIG_LENGTH + (DeviceName->Length / sizeof (WCHAR)) - (StringLoc+1) ] = L'\0'; IPX_DEBUG(CONFIG, ("Subkey:%ws\n", Subkey)); //RtlCopyMemory(&Subkey[10], &DeviceName->Buffer[StringLoc+1], DeviceName->MaximumLength - ((StringLoc+1) * sizeof(WCHAR))); QueryTable[0].QueryRoutine = NULL; QueryTable[0].Flags = RTL_QUERY_REGISTRY_SUBKEY; QueryTable[0].Name = Subkey; // // 2) Call IpxGetFrameType for each part of the // "PktType" multi-string. // QueryTable[1].QueryRoutine = IpxGetFrameType; QueryTable[1].Flags = RTL_QUERY_REGISTRY_REQUIRED; QueryTable[1].Name = L"PktType"; QueryTable[1].EntryContext = &FrameTypeCount; QueryTable[1].DefaultType = REG_NONE; // // 3) Call IpxGetFrameType for each part of the // "NetworkNumber" multi-string. // QueryTable[2].QueryRoutine = IpxGetFrameType; QueryTable[2].Flags = RTL_QUERY_REGISTRY_REQUIRED; QueryTable[2].Name = L"NetworkNumber"; QueryTable[2].EntryContext = &NetworkNumberCount; QueryTable[2].DefaultType = REG_NONE; // // 4-11) Call IpxGetBindingValue for each of the keys we // care about. // for (i = 0; i < BINDING_PARAMETERS; i++) { QueryTable[i+3].QueryRoutine = IpxGetBindingValue; QueryTable[i+3].Flags = 0; QueryTable[i+3].Name = ParameterValues[i].KeyName; QueryTable[i+3].EntryContext = UlongToPtr(i); QueryTable[i+3].DefaultType = REG_DWORD; QueryTable[i+3].DefaultData = (PVOID)(ParameterValues[i].DefaultValue); QueryTable[i+3].DefaultLength = sizeof(ULONG); } // // 12) Stop // QueryTable[BINDING_PARAMETERS+3].QueryRoutine = NULL; QueryTable[BINDING_PARAMETERS+3].Flags = 0; QueryTable[BINDING_PARAMETERS+3].Name = NULL; IPX_DEBUG (CONFIG, ("Read bind key for %ws (%ws)\n", DeviceName->Buffer, Subkey)); Status = RtlQueryRegistryValues( RTL_REGISTRY_ABSOLUTE, Config->RegistryPathBuffer, QueryTable, (PVOID)Binding, NULL); if (Status != STATUS_SUCCESS) { // // The binding will get freed during cleanup. // IpxWriteGeneralErrorLog( (PVOID)Config->DriverObject, EVENT_IPX_ILLEGAL_CONFIG, 906, Status, Subkey, 0, NULL); return STATUS_DEVICE_CONFIGURATION_ERROR; } if (FrameTypeCount == 0) { IpxWriteGeneralErrorLog( (PVOID)Config->DriverObject, EVENT_IPX_NO_FRAME_TYPES, 907, Status, Subkey + 10, 0, NULL); } if (FrameTypeCount > NetworkNumberCount) { for (i = NetworkNumberCount; i NetworkNumber[i] = 0; } } Binding->FrameTypeCount = FrameTypeCount; // // Go through and eliminate duplicates from the frame // type array. // for (i = 0; i < Binding->FrameTypeCount; i++) { for (j = i+1; j < Binding->FrameTypeCount; j++) { if (Binding->FrameType[j] == Binding->FrameType[i]) { IPX_DEBUG (CONFIG, ("Frame types %d and %d identical\n", i, j)); // // A duplicate, slide everything else down. // for (k = j+1; k < Binding->FrameTypeCount; k++) { Binding->FrameType[k-1] = Binding->FrameType[k]; Binding->NetworkNumber[k-1] = Binding->NetworkNumber[k]; } --Binding->FrameTypeCount; --j; // so we check whoever just moved into this spot. } } } // // Mark all the explicitly configured frame types, and // see if we have to auto-detect. // for (i = 0; i < 4; i++) { FrameTypeUsed[i] = FALSE; } AutoDetect = FALSE; for (i = 0; i < Binding->FrameTypeCount; i++) { if ((Binding->FrameType[i] == ISN_FRAME_TYPE_AUTO)) { AutoDetectLoc = i; AutoDetect = TRUE; } else { Binding->AutoDetect[i] = FALSE; Binding->DefaultAutoDetect[i] = FALSE; FrameTypeUsed[Binding->FrameType[i]] = TRUE; } } if (!AutoDetect) { IPX_DEBUG (AUTO_DETECT, ("No bindings auto-detected\n")); #if DBG for (i = 0; i < ISN_FRAME_TYPE_MAX; i++) { IPX_DEBUG (AUTO_DETECT, ("%d: type %d, net %d, auto %d, default auto detect %d\n", i, Binding->FrameType[i], Binding->NetworkNumber[i], Binding->AutoDetect[i], Binding->DefaultAutoDetect[i])); } #endif return STATUS_SUCCESS; } // // Slide everything that is past the auto-detect point up // to the end. // // // Fixed this loop which can spill over if the FrameTypeCount is 4 and the SlideCount > 0. // Here, the FrameTypeCount is 1-based, whereas the indices are 0-based, we need to make // the index 1-based for this to work. So, instead of (3-Binding->FrameTypeCount), we use // (4-Binding->FrameTypeCount). This loop copies all the non-auto-detect frametypes down to // the bottom of the array to make space after the last auto-detect frame-type for filling // in the frametypes in the preference order. // #if 0 SlideCount = Binding->FrameTypeCount - AutoDetectLoc - 1; for (j = 3; j > 3 - SlideCount; j--) { Binding->FrameType[j] = Binding->FrameType[j-(3-Binding->FrameTypeCount)]; Binding->NetworkNumber[j] = Binding->NetworkNumber[j-(3-Binding->FrameTypeCount)]; Binding->AutoDetect[j] = Binding->AutoDetect[j-(3-Binding->FrameTypeCount)]; Binding->DefaultAutoDetect[j] = Binding->DefaultAutoDetect[j-(3-Binding->FrameTypeCount)]; } #else SlideCount = Binding->FrameTypeCount - AutoDetectLoc - 1; for (j = 3; j > 3 - SlideCount; j--) { Binding->FrameType[j] = Binding->FrameType[j-(4-Binding->FrameTypeCount)]; Binding->NetworkNumber[j] = Binding->NetworkNumber[j-(4-Binding->FrameTypeCount)]; Binding->AutoDetect[j] = Binding->AutoDetect[j-(4-Binding->FrameTypeCount)]; Binding->DefaultAutoDetect[j] = Binding->DefaultAutoDetect[j-(4-Binding->FrameTypeCount)]; } #endif // // Now fill in any frame types that are not hard-coded, // this will start at AutoDetectLoc and exactly fill up // the gap created when we slid things up above. We // first put the default auto-detect at the first spot. // if (!FrameTypeUsed[Binding->Parameters[BINDING_DEFAULT_AUTO_DETECT]]) { Binding->FrameType[AutoDetectLoc] = Binding->Parameters[BINDING_DEFAULT_AUTO_DETECT]; Binding->NetworkNumber[AutoDetectLoc] = 0; Binding->AutoDetect[AutoDetectLoc] = TRUE; Binding->DefaultAutoDetect[AutoDetectLoc] = TRUE; ++AutoDetectLoc; FrameTypeUsed[Binding->Parameters[BINDING_DEFAULT_AUTO_DETECT]] = TRUE; } // // Now fill in the array, using the preference order in // the BindingPreference array (this comes into effect // because the first frame type in our list that we // find is used). // for (i = 0; i < ISN_FRAME_TYPE_MAX; i++) { if (!FrameTypeUsed[BindingPreference[i]]) { Binding->FrameType[AutoDetectLoc] = BindingPreference[i]; Binding->NetworkNumber[AutoDetectLoc] = 0; Binding->AutoDetect[AutoDetectLoc] = TRUE; Binding->DefaultAutoDetect[AutoDetectLoc] = FALSE; ++AutoDetectLoc; } } Binding->FrameTypeCount = ISN_FRAME_TYPE_MAX; #if DBG for (i = 0; i < ISN_FRAME_TYPE_MAX; i++) { IPX_DEBUG (AUTO_DETECT, ("%d: type %d, net %d, auto %d, default auto detect %d\n", i, Binding->FrameType[i], Binding->NetworkNumber[i], Binding->AutoDetect[i], Binding->DefaultAutoDetect[i])); } #endif return STATUS_SUCCESS; } /* IpxPnPGetAdapterParameters */