|
|
/*++
Copyright (c) 1992-1996 Microsoft Corporation
Module Name:
registry.c
Abstract:
This file contains the code to read the registry.
Author:
Jameel Hyder (jameelh@microsoft.com) July 1996
Environment:
Kernel mode
Revision History:
--*/
#include <precomp.h>
#define _FILENUM_ FILENUM_REGISTRY
NTSTATUS ArpSReadGlobalConfiguration( IN PUNICODE_STRING RegistryPath ) /*++
Routine Description:
Read the global registry.
Arguments:
RegistryPath - Pointer to the service section in the registry.
Return Value:
Error code from registry apis.
--*/ { NDIS_STATUS Status; NDIS_HANDLE ConfigHandle;
//
// Open the per-adapter registry config
//
NdisOpenProtocolConfiguration(&Status, &ConfigHandle, RegistryPath);
if (Status == NDIS_STATUS_SUCCESS) { NDIS_STRING ArpsBufString = NDIS_STRING_CONST("ArpBuffers"); NDIS_STRING FlushString = NDIS_STRING_CONST("FlushTime"); PNDIS_CONFIGURATION_PARAMETER Param;
//
// Read number of configured buffers
//
NdisReadConfiguration(&Status, &Param, ConfigHandle, &ArpsBufString, NdisParameterInteger); if ((Status == NDIS_STATUS_SUCCESS) && (Param->ParameterType == NdisParameterInteger)) { ArpSBuffers = Param->ParameterData.IntegerData; }
//
// Should we save cache in a file ?
//
NdisReadConfiguration(&Status, &Param, ConfigHandle, &FlushString, NdisParameterInteger); if ((Status == NDIS_STATUS_SUCCESS) && (Param->ParameterType == NdisParameterInteger)) { ArpSFlushTime = (USHORT)(Param->ParameterData.IntegerData * MULTIPLIER); }
NdisCloseConfiguration(ConfigHandle); }
return NDIS_STATUS_SUCCESS; }
NDIS_STATUS ArpSReadAdapterConfigFromRegistry( IN PINTF pIntF, OUT PATMARPS_CONFIG pConfig ) /*++
Routine Description:
Read configuration for the specified interface.
Arguments:
pIntF - Interface pConfig - Place to return information read in.
Return Value:
Error code from registry apis.
--*/ { NDIS_STATUS Status; NDIS_HANDLE ConfigHandle;
//
// Open the per-adapter registry config
//
NdisOpenProtocolConfiguration(&Status, &ConfigHandle, &pIntF->ConfigString);
if (Status == NDIS_STATUS_SUCCESS) { NDIS_STRING RegdAddrsString = NDIS_STRING_CONST("RegisteredAddresses"); NDIS_STRING SelString = NDIS_STRING_CONST("Selector"); NDIS_STRING McsString = NDIS_STRING_CONST("MulticastAddresses"); PNDIS_CONFIGURATION_PARAMETER Param; PWSTR p; UINT i, Length;
//
// Read the value, if present for the selector byte to be used for the registered sap
// for the std. address (as opposed to added addresses).
//
pConfig->SelByte = 0; NdisReadConfiguration(&Status, &Param, ConfigHandle, &SelString, NdisParameterInteger); if ((Status == NDIS_STATUS_SUCCESS) && (Param->ParameterType == NdisParameterInteger) && (Param->ParameterData.IntegerData <= 0xFF)) { pConfig->SelByte = (UCHAR)(Param->ParameterData.IntegerData); DBGPRINT(DBG_LEVEL_INFO, ("Selector byte for interface %Z is %d\n", &pIntF->InterfaceName, pConfig->SelByte)); }
//
// Read registered addresses here. On an interface there can be a set of
// atm addresses registered. These need to be added and SAPs registered on
// them.
//
pConfig->NumAllocedRegdAddresses = 0; pConfig->RegAddresses = NULL; NdisReadConfiguration(&Status, &Param, ConfigHandle, &RegdAddrsString, NdisParameterMultiString); if ((Status == NDIS_STATUS_SUCCESS) && (Param->ParameterType == NdisParameterMultiString)) { NDIS_STRING String;
//
// Param now contains a list of atm addresses. Convert them into the right format and store
// it in the intf structure. First determine the number of addresses.
//
for (p = Param->ParameterData.StringData.Buffer, i = 0; *p != L'\0'; i++) { RtlInitUnicodeString(&String, p); DBGPRINT(DBG_LEVEL_INFO, ("Configured address for interface %Z - %Z\n", &pIntF->InterfaceName, &String));
p = (PWSTR)((PUCHAR)p + String.Length + sizeof(WCHAR)); }
if (i) { //
// Allocate space for the addresses
//
pConfig->RegAddresses = (PATM_ADDRESS)ALLOC_NP_MEM(sizeof(ATM_ADDRESS) * i, POOL_TAG_ADDR); if (pConfig->RegAddresses == NULL) { LOG_ERROR(NDIS_STATUS_RESOURCES); } else { DBGPRINT(DBG_LEVEL_INFO, ("%d addresses registered for %Z\n", i, &pIntF->InterfaceName)); ZERO_MEM(pConfig->RegAddresses, sizeof(ATM_ADDRESS) * i); for (i = 0, p = Param->ParameterData.StringData.Buffer; *p != L'\0'; NOTHING) { RtlInitUnicodeString(&String, p); NdisConvertStringToAtmAddress(&Status, &String, &pConfig->RegAddresses[i]); if (Status == NDIS_STATUS_SUCCESS) { i++; pConfig->NumAllocedRegdAddresses ++; } else { DBGPRINT(DBG_LEVEL_ERROR, ("ArpSReadAdapterConfiguration: Failed to convert address %Z\n", &String)); } p = (PWSTR)((PUCHAR)p + String.Length + sizeof(WCHAR)); } } } }
pConfig->pMcsList = NULL; NdisReadConfiguration(&Status, &Param, ConfigHandle, &McsString, NdisParameterMultiString); if ((Status == NDIS_STATUS_SUCCESS) && (Param->ParameterType == NdisParameterMultiString)) { NDIS_STRING String;
//
// Param now contains a list of Multicast IP Address ranges.
// Each string is of the form "M.M.M.M-N.N.N.N"
// Read them in.
//
for (p = Param->ParameterData.StringData.Buffer, i = 0; *p != L'\0'; i++) { RtlInitUnicodeString(&String, p); DBGPRINT(DBG_LEVEL_INFO, ("Configured Multicast range for interface %Z - %Z\n", &pIntF->InterfaceName, &String));
p = (PWSTR)((PUCHAR)p + String.Length + sizeof(WCHAR)); }
//
// Allocate space for the addresses
//
pConfig->pMcsList = (PMCS_ENTRY)ALLOC_NP_MEM(sizeof(MCS_ENTRY) * i, POOL_TAG_MARS); if (pConfig->pMcsList == (PMCS_ENTRY)NULL) { LOG_ERROR(NDIS_STATUS_RESOURCES); } else { DBGPRINT(DBG_LEVEL_INFO, ("%d Multicast ranges configured on %Z\n", i, &pIntF->InterfaceName));
ZERO_MEM(pConfig->pMcsList, sizeof(MCS_ENTRY) * i); for (i = 0, p = Param->ParameterData.StringData.Buffer; *p != L'\0'; NOTHING) { RtlInitUnicodeString(&String, p); ArpSConvertStringToIpPair(&Status, &String, &pConfig->pMcsList[i]); if (Status == NDIS_STATUS_SUCCESS) { if (i > 0) { pConfig->pMcsList[i-1].Next = &(pConfig->pMcsList[i]); } i++; } else { DBGPRINT(DBG_LEVEL_ERROR, ("ArpSReadAdapterConfiguration: Failed to convert IP Range %Z\n", &String)); } p = (PWSTR)((PUCHAR)p + String.Length + sizeof(WCHAR)); } } }
//
// Close the configuration handle
//
NdisCloseConfiguration(ConfigHandle);
Status = NDIS_STATUS_SUCCESS; }
return Status; }
NDIS_STATUS ArpSReadAdapterConfiguration( IN PINTF pIntF ) /*++
Routine Description:
Read the registry for parameters for the specified Interface. This could be in response to a reconfiguration event, in which case handle existing values/structures.
Arguments:
pIntF - Interface to be read in.
Return Value:
Error code from registry apis.
--*/ { NDIS_STATUS Status; ATMARPS_CONFIG AtmArpSConfig; KIRQL OldIrql; ULONG PrevNumAllocedRegdAddresses; PATM_ADDRESS PrevRegAddresses; PMCS_ENTRY PrevMcsList;
Status = ArpSReadAdapterConfigFromRegistry(pIntF, &AtmArpSConfig);
if (Status == NDIS_STATUS_SUCCESS) { //
// Copy them into the interface structure. We could be handling a
// parameter reconfig, so any space used to store old information.
//
ACQUIRE_SPIN_LOCK(&pIntF->Lock, &OldIrql);
//
// Selector Byte:
//
pIntF->SelByte = AtmArpSConfig.SelByte;
//
// List of addresses to be registered with the switch.
// Take out the old list first. We'll have to delete those
// addresses (deregister them from the switch).
//
PrevNumAllocedRegdAddresses = pIntF->NumAllocedRegdAddresses; PrevRegAddresses = pIntF->RegAddresses;
//
// Get the new list in:
//
pIntF->NumAllocedRegdAddresses = AtmArpSConfig.NumAllocedRegdAddresses; pIntF->RegAddresses = AtmArpSConfig.RegAddresses; pIntF->NumAddressesRegd = 0; // reset count of addresses regd with switch
//
// Take out the old MCS list and insert the new one.
//
PrevMcsList = pIntF->pMcsList; pIntF->pMcsList = AtmArpSConfig.pMcsList;
RELEASE_SPIN_LOCK(&pIntF->Lock, OldIrql);
//
// Deregister all previously registered addresses with the switch.
//
if (PrevNumAllocedRegdAddresses) { ArpSDeleteIntFAddresses(pIntF, PrevNumAllocedRegdAddresses, PrevRegAddresses);
//
// Register the new list of addresses with the switch.
//
ArpSQueryAndSetAddresses(pIntF); }
//
// Free unused memory.
//
if (PrevMcsList) { FREE_MEM(PrevMcsList); }
if (PrevRegAddresses) { FREE_MEM(PrevRegAddresses); }
}
return Status; }
VOID ArpSConvertStringToIpPair( OUT PNDIS_STATUS pStatus, IN PNDIS_STRING pString, IN PMCS_ENTRY pMcsEntry ) /*++
Routine Description:
Extract a pair of IP addresses that identify a range of multicast addresses that this MCS serves, from the given string.
Arguments:
pStatus - Place to return status pString - Points to string containing "<IP1>-<IP2>" pMcsEntry - Entry to read into.
Return Value:
None. *pStatus is set to indicate the status of this call.
--*/ { PWSTR pMin, pMax; IPADDR Min, Max; ULONG Length; ULONG i;
ARPS_PAGED_CODE();
Length = pString->Length;
*pStatus = NDIS_STATUS_FAILURE;
do { //
// Locate the '-' and replace it with a NULL char.
//
pMin = pString->Buffer; pMax = pString->Buffer;
for (i = 0; i < Length; i++, pMax++) { if (*pMax == L'-') { *pMax++ = L'\0'; break; } }
if (i == Length) { break; // Didn't find '-'
}
if (IPConvertStringToAddress(pMin, &Min) && IPConvertStringToAddress(pMax, &Max)) { DBGPRINT(DBG_LEVEL_INFO, ("MCS pair: ")); ArpSDumpIpAddr(Min, " to "); ArpSDumpIpAddr(Max, "\n");
pMcsEntry->GrpAddrPair.MinAddr = Min; pMcsEntry->GrpAddrPair.MaxAddr = Max; *pStatus = NDIS_STATUS_SUCCESS; }
break; } while (FALSE);
}
#define IP_ADDRESS_STRING_LENGTH (16+2) // +2 for double NULL on MULTI_SZ
BOOLEAN IPConvertStringToAddress( IN PWCHAR AddressString, OUT PULONG IpAddress )
/*++
Routine Description
This function converts an Internet standard 4-octet dotted decimal IP address string into a numeric IP address. Unlike inet_addr(), this routine does not support address strings of less than 4 octets nor does it support octal and hexadecimal octets.
Copied from tcpip\ip\ntip.c
Arguments
AddressString - IP address in dotted decimal notation IpAddress - Pointer to a variable to hold the resulting address
Return Value:
TRUE if the address string was converted. FALSE otherwise.
--*/
{ UNICODE_STRING unicodeString; STRING aString; UCHAR dataBuffer[IP_ADDRESS_STRING_LENGTH]; NTSTATUS status; PUCHAR addressPtr, cp, startPointer, endPointer; ULONG digit, multiplier; int i;
ARPS_PAGED_CODE();
aString.Length = 0; aString.MaximumLength = IP_ADDRESS_STRING_LENGTH; aString.Buffer = dataBuffer;
RtlInitUnicodeString(&unicodeString, AddressString);
status = RtlUnicodeStringToAnsiString( &aString, &unicodeString, FALSE );
if (!NT_SUCCESS(status)) { return(FALSE); }
*IpAddress = 0; addressPtr = (PUCHAR) IpAddress; startPointer = dataBuffer; endPointer = dataBuffer; i = 3;
while (i >= 0) { //
// Collect the characters up to a '.' or the end of the string.
//
while ((*endPointer != '.') && (*endPointer != '\0')) { endPointer++; }
if (startPointer == endPointer) { return(FALSE); }
//
// Convert the number.
//
for ( cp = (endPointer - 1), multiplier = 1, digit = 0; cp >= startPointer; cp--, multiplier *= 10 ) {
if ((*cp < '0') || (*cp > '9') || (multiplier > 100)) { return(FALSE); }
digit += (multiplier * ((ULONG) (*cp - '0'))); }
if (digit > 255) { return(FALSE); }
addressPtr[i] = (UCHAR) digit;
//
// We are finished if we have found and converted 4 octets and have
// no other characters left in the string.
//
if ( (i-- == 0) && ((*endPointer == '\0') || (*endPointer == ' ')) ) { return(TRUE); }
if (*endPointer == '\0') { return(FALSE); }
startPointer = ++endPointer; }
return(FALSE); }
VOID ArpSReadArpCache( IN PINTF pIntF ) /*++
Routine Description:
Read the per-adapter Arp Cache. TBD.
Arguments:
pIntF - Per adapter arp cache.
Return Value:
None
--*/ { HANDLE FileHandle; OBJECT_ATTRIBUTES ObjectAttributes; IO_STATUS_BLOCK IoStatus; NTSTATUS Status; LARGE_INTEGER Offset; ULONG Space, NumEntries; PDISK_HEADER DskHdr; PUCHAR Buffer; PDISK_ENTRY pDskEntry; PARP_ENTRY ArpEntry;
Buffer = ALLOC_PG_MEM(DISK_BUFFER_SIZE); if (Buffer == NULL) { LOG_ERROR(NDIS_STATUS_RESOURCES); return; }
InitializeObjectAttributes(&ObjectAttributes, &pIntF->FileName, OBJ_CASE_INSENSITIVE, NULL, NULL);
Status = ZwCreateFile(&FileHandle, SYNCHRONIZE | FILE_READ_DATA, &ObjectAttributes, &IoStatus, NULL, 0, 0, FILE_OPEN, FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE | FILE_SEQUENTIAL_ONLY, NULL, 0);
if (Status == STATUS_SUCCESS) { do { //
// First read the disk header and validate it
//
Offset.QuadPart = 0; Status = ZwReadFile(FileHandle, NULL, NULL, NULL, &IoStatus, Buffer, DISK_BUFFER_SIZE, &Offset, NULL); if (Status != STATUS_SUCCESS) { LOG_ERROR(Status); break; }
DskHdr = (PDISK_HEADER)Buffer; if ((IoStatus.Information < sizeof(DISK_HEADER)) || (DskHdr->Signature != DISK_HDR_SIGNATURE) || (DskHdr->Version != DISK_HDR_VERSION)) { LOG_ERROR(STATUS_INVALID_LEVEL); break; } NumEntries = DskHdr->NumberOfArpEntries; Space = (ULONG) IoStatus.Information - sizeof(DISK_HEADER); pDskEntry = (PDISK_ENTRY)(Buffer + sizeof(DISK_HEADER)); Offset.QuadPart = sizeof(DISK_HEADER); while (NumEntries > 0) { UINT Consumed;
if ((Space < sizeof(DISK_ENTRY)) || (Space < (sizeof(DISK_ENTRY) + pDskEntry->AtmAddr.SubAddrLen))) { Status = ZwReadFile(FileHandle, NULL, NULL, NULL, &IoStatus, Buffer, DISK_BUFFER_SIZE, &Offset, NULL); if (Status != STATUS_SUCCESS) { LOG_ERROR(Status); break; }
pDskEntry = (PDISK_ENTRY)Buffer; if ((IoStatus.Information < sizeof(DISK_ENTRY)) || (IoStatus.Information < (sizeof(DISK_ENTRY) + pDskEntry->AtmAddr.SubAddrLen))) { LOG_ERROR(STATUS_INVALID_LEVEL); break; } Space = (ULONG) IoStatus.Information - sizeof(DISK_HEADER); }
ArpEntry = ArpSAddArpEntryFromDisk(pIntF, pDskEntry); ASSERT (ArpEntry != NULL);
Consumed = (sizeof(DISK_ENTRY) + SIZE_4N(pDskEntry->AtmAddr.SubAddrLen)); (PUCHAR)pDskEntry += Consumed; Offset.QuadPart += Consumed; Space -= Consumed; NumEntries --; } } while (FALSE);
ZwClose(FileHandle); }
FREE_MEM(Buffer); }
BOOLEAN ArpSWriteArpCache( IN PINTF pIntF, IN PTIMER Timer, IN BOOLEAN TimerShuttingDown ) /*++
Routine Description:
Write the per-adapter Arp Cache. TBD.
Arguments:
pIntF - Per adapter arp cache. Timer - FlushTimer TimerShuttingDown - Do not requeue when set.
Return Value:
TRUE to requeue unless TimerShuttingDown is set
--*/ { HANDLE FileHandle; OBJECT_ATTRIBUTES ObjectAttributes; IO_STATUS_BLOCK IoStatus; NTSTATUS Status; LARGE_INTEGER Offset; ULONG Space, i; PDISK_HEADER DskHdr; PUCHAR Buffer; PDISK_ENTRY pDskEntry; PARP_ENTRY ArpEntry; TIME SystemTime, LocalTime; ULONG CurrentTime;
Buffer = ALLOC_PG_MEM(DISK_BUFFER_SIZE); if (Buffer == NULL) { LOG_ERROR(NDIS_STATUS_RESOURCES); return (!TimerShuttingDown); }
KeQuerySystemTime(&SystemTime);
ExSystemTimeToLocalTime(&SystemTime, &LocalTime);
// Convert this to number of seconds since 1980
if (!RtlTimeToSecondsSince1980(&LocalTime, &CurrentTime)) { // Could not convert! Bail out.
LOG_ERROR(NDIS_STATUS_BUFFER_OVERFLOW); FREE_MEM(Buffer); return (!TimerShuttingDown); }
InitializeObjectAttributes(&ObjectAttributes, &pIntF->FileName, OBJ_CASE_INSENSITIVE, NULL, NULL);
Status = ZwCreateFile(&FileHandle, SYNCHRONIZE | FILE_WRITE_DATA, &ObjectAttributes, &IoStatus, NULL, 0, 0, FILE_OVERWRITE_IF, FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE | FILE_SEQUENTIAL_ONLY, NULL, 0); if (Status == STATUS_SUCCESS) { do { Offset.QuadPart = 0; Space = DISK_BUFFER_SIZE - sizeof(DISK_HEADER); DskHdr = (PDISK_HEADER)Buffer; pDskEntry = (PDISK_ENTRY)(Buffer + sizeof(DISK_HEADER)); DskHdr->Signature = DISK_HDR_SIGNATURE; DskHdr->Version = DISK_HDR_VERSION; DskHdr->NumberOfArpEntries = pIntF->NumCacheEntries; DskHdr->TimeStamp = CurrentTime;
for (i =0; i < ARP_TABLE_SIZE; i++) { for (ArpEntry = pIntF->ArpCache[i]; ArpEntry != NULL; ArpEntry = ArpEntry->Next) { UINT Size;
Size = sizeof(DISK_ENTRY) + ((ArpEntry->HwAddr.SubAddress != NULL) ? SIZE_4N(ArpEntry->HwAddr.SubAddress->NumberOfDigits) : 0); if (Space < Size) { Status = ZwWriteFile(FileHandle, NULL, NULL, NULL, &IoStatus, Buffer, DISK_BUFFER_SIZE - Space, &Offset, NULL); if (Status != STATUS_SUCCESS) { LOG_ERROR(Status); break; }
Space = DISK_BUFFER_SIZE; pDskEntry = (PDISK_ENTRY)Buffer; Offset.QuadPart += (DISK_BUFFER_SIZE - Space); }
pDskEntry->IpAddr = ArpEntry->IpAddr; pDskEntry->AtmAddr.AddrType = (UCHAR)ArpEntry->HwAddr.Address.AddressType; pDskEntry->AtmAddr.AddrLen = (UCHAR)ArpEntry->HwAddr.Address.NumberOfDigits; COPY_MEM(pDskEntry->AtmAddr.Address, ArpEntry->HwAddr.Address.Address, pDskEntry->AtmAddr.AddrLen);
pDskEntry->AtmAddr.SubAddrLen = 0; if (ArpEntry->HwAddr.SubAddress != NULL) { pDskEntry->AtmAddr.SubAddrLen = (UCHAR)ArpEntry->HwAddr.SubAddress->NumberOfDigits; pDskEntry->AtmAddr.SubAddrType = (UCHAR)ArpEntry->HwAddr.SubAddress->AddressType; COPY_MEM((PUCHAR)pDskEntry + sizeof(DISK_ENTRY), ArpEntry->HwAddr.SubAddress->Address, pDskEntry->AtmAddr.SubAddrLen); }
Space -= Size; (PUCHAR)pDskEntry += Size; }
if (Status != STATUS_SUCCESS) { break; } } } while (FALSE);
if ((Status == STATUS_SUCCESS) && (Space < DISK_BUFFER_SIZE)) { Status = ZwWriteFile(FileHandle, NULL, NULL, NULL, &IoStatus, Buffer, DISK_BUFFER_SIZE - Space, &Offset, NULL); }
ZwClose(FileHandle); }
FREE_MEM(Buffer);
return (!TimerShuttingDown); }
|