669 lines
24 KiB
C
669 lines
24 KiB
C
|
/*++
|
||
|
|
||
|
Copyright (C) 1998 Microsoft Corporation
|
||
|
|
||
|
Module Name:
|
||
|
change.c
|
||
|
|
||
|
Abstract:
|
||
|
handles some change notifications for dhcp.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
#include "precomp.h"
|
||
|
#include <dhcpcapi.h>
|
||
|
#include <apiappl.h>
|
||
|
#include <dhcploc.h>
|
||
|
#include <dhcppro.h>
|
||
|
|
||
|
DWORD
|
||
|
ConvertNetworkString(
|
||
|
IN OUT LPBYTE Buf,
|
||
|
IN ULONG Size
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
This routine converts a wide character string where each
|
||
|
character is in network-order, to host-order so that the
|
||
|
string can be used (for ex, for displaying).
|
||
|
|
||
|
Arguments:
|
||
|
Buf -- wide character string buffer, replace in-place.
|
||
|
Size -- size of above buffer in BYTES.
|
||
|
|
||
|
Return Value:
|
||
|
ERROR_INTERNAL_ERROR or ERROR_SUCCESS
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
if( 0 == Size ) return ERROR_INTERNAL_ERROR;
|
||
|
if( Size % sizeof(WCHAR)) return ERROR_INTERNAL_ERROR;
|
||
|
|
||
|
while( Size ) {
|
||
|
*(LPWSTR) Buf = ntohs(*(LPWSTR)Buf);
|
||
|
Buf += sizeof(WCHAR);
|
||
|
Size -= sizeof(WCHAR);
|
||
|
}
|
||
|
|
||
|
return ERROR_SUCCESS;
|
||
|
}
|
||
|
|
||
|
DWORD
|
||
|
ConvertFromBufferToClassInfo(
|
||
|
IN LPBYTE Data,
|
||
|
IN ULONG nData,
|
||
|
IN OUT LPDHCP_CLASS_INFO ClassesArray,
|
||
|
IN OUT LPDWORD Size
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
This routine converts a buffer which has wire-data to the
|
||
|
DHCP_CLASS_INFO array structure. The wire-data format is as
|
||
|
follows: it is a set of triples, where each triple contains the
|
||
|
actual user-class-id used on wire (binary), its name (LPWSTR), and
|
||
|
its description (LPWSTR). Each of these three items have their
|
||
|
length specified first using two bytes -- the hi-byte followed by
|
||
|
the lo-byte.
|
||
|
|
||
|
N.B. If the first of the triple (user-class-id) has length X,
|
||
|
then the actual number of bytes of data on-wire would be X rounded
|
||
|
off to 4 to preserve alignment. This is taken care of in this
|
||
|
routine.
|
||
|
|
||
|
N.B #2. The pointers within the ClassesArray all point to the
|
||
|
buffer (Data) provided.
|
||
|
|
||
|
Arguments:
|
||
|
Data -- the wire-data buffer
|
||
|
nData -- number of bytes of above
|
||
|
ClassesArray -- input buffer that will be formatted with info.
|
||
|
Size -- on input, this must be size of above buffer in bytes.
|
||
|
on output, if the routine failed with ERROR_MORE_DATA, then
|
||
|
this will contain the required number of bytes. If the
|
||
|
routine succeeded, then this will contain the number of
|
||
|
elements in above array that got filled.
|
||
|
|
||
|
Return Values:
|
||
|
ERROR_SUCCESS -- success
|
||
|
ERROR_MORE_DATA -- data buffer provided in ClassesArray must be at
|
||
|
least as many bytes as "Size."
|
||
|
Win32 errors
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
ULONG ReqdSize, ThisSize, nBytes, nClasses;
|
||
|
LPBYTE Buf;
|
||
|
|
||
|
Buf = Data; nBytes = 0;
|
||
|
ReqdSize = 0; nClasses = 0;
|
||
|
do {
|
||
|
//
|
||
|
// Require length (hi-byte, lo-byte)
|
||
|
//
|
||
|
if( nBytes + 2 > nData ) return ERROR_INTERNAL_ERROR;
|
||
|
|
||
|
//
|
||
|
// user-classid binary blob of specified size.
|
||
|
// N.B. length must be rounded off to nearest
|
||
|
// multiple of 4.
|
||
|
//
|
||
|
ThisSize = ((Buf[0])<<8)+Buf[1];
|
||
|
if( 0 == ThisSize ) return ERROR_INTERNAL_ERROR;
|
||
|
ThisSize = (ThisSize + 3) & ~3;
|
||
|
|
||
|
//
|
||
|
// Go over class id.
|
||
|
//
|
||
|
Buf += 2 + ThisSize;
|
||
|
nBytes += 2 + ThisSize;
|
||
|
ReqdSize += ThisSize;
|
||
|
|
||
|
if( nBytes + 2 > nData ) return ERROR_INTERNAL_ERROR;
|
||
|
|
||
|
//
|
||
|
// user class name.. size must be multiple of sizeof(WCHAR)
|
||
|
//
|
||
|
ThisSize = ((Buf[0])<<8)+Buf[1];
|
||
|
Buf += 2 + ThisSize;
|
||
|
nBytes += 2 + ThisSize;
|
||
|
|
||
|
if( (ThisSize % 2 ) ) return ERROR_INTERNAL_ERROR;
|
||
|
ReqdSize += ThisSize + sizeof(L'\0');
|
||
|
|
||
|
if( nBytes + 2 > nData ) return ERROR_INTERNAL_ERROR;
|
||
|
|
||
|
//
|
||
|
// user class description..
|
||
|
//
|
||
|
ThisSize = ((Buf[0])<<8)+Buf[1];
|
||
|
Buf += 2 + ThisSize;
|
||
|
nBytes += 2 + ThisSize;
|
||
|
|
||
|
if( (ThisSize % 2 ) ) return ERROR_INTERNAL_ERROR;
|
||
|
ReqdSize += ThisSize + sizeof(L'\0');
|
||
|
|
||
|
nClasses ++;
|
||
|
} while( nBytes < nData );
|
||
|
|
||
|
//
|
||
|
// Check if we have the required size.
|
||
|
//
|
||
|
ReqdSize += sizeof(DHCP_CLASS_INFO)*nClasses;
|
||
|
|
||
|
if( (*Size) < ReqdSize ) {
|
||
|
*Size = ReqdSize;
|
||
|
return ERROR_MORE_DATA;
|
||
|
} else {
|
||
|
*Size = nClasses;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Assemble the array.
|
||
|
//
|
||
|
|
||
|
Buf = nClasses*sizeof(DHCP_CLASS_INFO) + ((LPBYTE)ClassesArray);
|
||
|
nClasses = 0;
|
||
|
do {
|
||
|
|
||
|
ClassesArray[nClasses].Version = DHCP_CLASS_INFO_VERSION_0;
|
||
|
|
||
|
//
|
||
|
// user class id binary info
|
||
|
//
|
||
|
ThisSize = ((Data[0])<<8)+Data[1];
|
||
|
Data += 2;
|
||
|
ClassesArray[nClasses].ClassData = Buf;
|
||
|
ClassesArray[nClasses].ClassDataLen = ThisSize;
|
||
|
memcpy(Buf, Data, ThisSize);
|
||
|
ThisSize = (ThisSize + 3)&~3;
|
||
|
Buf += ThisSize; Data += ThisSize;
|
||
|
|
||
|
//
|
||
|
// class name
|
||
|
//
|
||
|
ThisSize = ((Data[0])<<8)+Data[1];
|
||
|
Data += 2;
|
||
|
ClassesArray[nClasses].ClassName = (LPWSTR)Buf;
|
||
|
memcpy(Buf, Data, ThisSize);
|
||
|
if( ERROR_SUCCESS != ConvertNetworkString(Buf, ThisSize) ){
|
||
|
return ERROR_INTERNAL_ERROR;
|
||
|
}
|
||
|
|
||
|
Buf += ThisSize; Data += ThisSize;
|
||
|
*(LPWSTR)Buf = L'\0'; Buf += sizeof(WCHAR);
|
||
|
|
||
|
//
|
||
|
// Class description
|
||
|
//
|
||
|
ThisSize = ((Data[0])<<8)+Data[1];
|
||
|
Data += 2;
|
||
|
if( 0 == ThisSize ) {
|
||
|
ClassesArray[nClasses].ClassDescr = NULL;
|
||
|
} else {
|
||
|
ClassesArray[nClasses].ClassDescr = (LPWSTR)Buf;
|
||
|
memcpy(Buf, Data, ThisSize);
|
||
|
if( ERROR_SUCCESS != ConvertNetworkString(Buf, ThisSize) ) {
|
||
|
return ERROR_INTERNAL_ERROR;
|
||
|
}
|
||
|
}
|
||
|
Buf += ThisSize; Data += ThisSize;
|
||
|
*(LPWSTR)Buf = L'\0'; Buf += sizeof(WCHAR);
|
||
|
|
||
|
nClasses ++;
|
||
|
} while( nClasses < *Size );
|
||
|
|
||
|
return ERROR_SUCCESS;
|
||
|
}
|
||
|
|
||
|
//DOC DhcpEnumClasses enumerates the list of classes available on the system for configuration.
|
||
|
//DOC This is predominantly going to be used by the NetUI. (in which case the ClassData part of the
|
||
|
//DOC DHCP_CLASS_INFO structure is essentially useless).
|
||
|
//DOC Note that Flags is used for future use.
|
||
|
//DOC The AdapterName can currently be only GUIDs but may soon be EXTENDED to be IpAddress strings or
|
||
|
//DOC h-w addresses or any other user friendly means of denoting the Adapter. Note that if the Adapter
|
||
|
//DOC Name is NULL (not the empty string L""), then it refers to either ALL adapters.
|
||
|
//DOC The Size parameter is an input/output parameter. The input value is the # of bytes of allocated
|
||
|
//DOC space in the ClassesArray buffer. On return, the meaning of this value depends on the return value.
|
||
|
//DOC If the function returns ERROR_SUCCESS, then, this parameter would return the # of elements in the
|
||
|
//DOC array ClassesArray. If the function returns ERROR_MORE_DATA, then, this parameter refers to the
|
||
|
//DOC # of bytes space that is actually REQUIRED to hold the information.
|
||
|
//DOC In all other cases, the values in Size and ClassesArray dont mean anything.
|
||
|
//DOC
|
||
|
//DOC Return Values:
|
||
|
//DOC ERROR_DEVICE_DOES_NOT_EXIST The AdapterName is illegal in the given context
|
||
|
//DOC ERROR_INVALID_PARAMETER
|
||
|
//DOC ERROR_MORE_DATA ClassesArray is not a large enough buff..
|
||
|
//DOC ERROR_FILE_NOT_FOUND The DHCP Client is not running and could not be started up.
|
||
|
//DOC ERROR_NOT_ENOUGH_MEMORY This is NOT the same as ERROR_MORE_DATA
|
||
|
//DOC Win32 errors
|
||
|
//DOC
|
||
|
//DOC Remarks:
|
||
|
//DOC To notify DHCP that some class has changed, please use the DhcpHandlePnPEvent API.
|
||
|
DWORD
|
||
|
DhcpEnumClasses( // enumerate the list of classes available
|
||
|
IN DWORD Flags, // currently must be zero
|
||
|
IN LPWSTR AdapterName, // currently must be AdapterGUID (cannot be NULL yet)
|
||
|
IN OUT DWORD *Size, // input # of bytes available in BUFFER, output # of elements in array
|
||
|
IN OUT DHCP_CLASS_INFO *ClassesArray // pre-allocated buffer
|
||
|
)
|
||
|
{
|
||
|
DHCPAPI_PARAMS SendParams; // we need to get something from teh dhcp server..
|
||
|
PDHCPAPI_PARAMS RecdParams;
|
||
|
DWORD Result;
|
||
|
DWORD nBytesToAllocate;
|
||
|
DWORD nRecdParams;
|
||
|
BYTE Opt;
|
||
|
|
||
|
if( 0 != Flags || NULL == AdapterName || NULL == Size ) {
|
||
|
return ERROR_INVALID_PARAMETER; // sanity check
|
||
|
}
|
||
|
|
||
|
if( NULL == ClassesArray && 0 != *Size ) {
|
||
|
return ERROR_INVALID_DATA; // if *Size is non-Zero, then the ClassesArray buffer should exist
|
||
|
}
|
||
|
|
||
|
Opt = OPTION_USER_CLASS; // intiialize request packet for this option..
|
||
|
SendParams.OptionId = (BYTE)OPTION_PARAMETER_REQUEST_LIST;
|
||
|
SendParams.IsVendor = FALSE;
|
||
|
SendParams.Data = &Opt;
|
||
|
SendParams.nBytesData = sizeof(Opt);
|
||
|
|
||
|
nBytesToAllocate = 0;
|
||
|
Result = DhcpRequestParameters // try to get this either directly from client or via INFORM
|
||
|
(
|
||
|
/* LPWSTR AdapterName */ AdapterName,
|
||
|
/* LPBYTE ClassId */ NULL,
|
||
|
/* DWORD ClassIdLen */ 0,
|
||
|
/* PDHCPAPI_PARAMS SendParams */ &SendParams,
|
||
|
/* DWORD nSendParams */ 1,
|
||
|
/* DWORD Flags */ 0,
|
||
|
/* PDHCPAPI_PARAMS RecdParams */ NULL,
|
||
|
/* LPDWORD pnRecdParamsBytes*/ &nBytesToAllocate
|
||
|
);
|
||
|
if( ERROR_MORE_DATA != Result ) { // either an error or dont have anything to return?
|
||
|
return Result;
|
||
|
}
|
||
|
|
||
|
DhcpAssert(nBytesToAllocate); // if it were 0, Result would have been ERROR_SUCCESS
|
||
|
RecdParams = DhcpAllocateMemory(nBytesToAllocate);
|
||
|
if( NULL == RecdParams ) { // um? dont have memory? cant really happen?
|
||
|
return ERROR_NOT_ENOUGH_MEMORY;
|
||
|
}
|
||
|
|
||
|
nRecdParams = nBytesToAllocate;
|
||
|
Result = DhcpRequestParameters // try to get this either directly from client or via INFORM
|
||
|
(
|
||
|
/* LPWSTR AdapterName */ AdapterName,
|
||
|
/* LPBYTE ClassId */ NULL,
|
||
|
/* DWORD ClassIdLen */ 0,
|
||
|
/* PDHCPAPI_PARAMS SendParams */ &SendParams,
|
||
|
/* DWORD nSendParams */ 1,
|
||
|
/* DWORD Flags */ 0,
|
||
|
/* PDHCPAPI_PARAMS RecdParams */ RecdParams,
|
||
|
/* LPDWORD pnRecdParamsBytes*/ &nRecdParams
|
||
|
);
|
||
|
|
||
|
if( ERROR_SUCCESS == Result && 1 != nRecdParams ) {
|
||
|
DhcpAssert(FALSE);
|
||
|
Result = ERROR_INTERNAL_ERROR; // dont expect this to happen..
|
||
|
}
|
||
|
|
||
|
if( ERROR_SUCCESS != Result ) { // aw, comeone, cant happen now...
|
||
|
// it is possible for instance to have a PnP event in the middle that would cause
|
||
|
// the adapter to go away. In this case ERROR_FILE_NOT_FOUND (2) is returned.
|
||
|
// no point for the assert - otherwise returning the error up to the caller is
|
||
|
// just fine.
|
||
|
//DhcpAssert(FALSE);
|
||
|
DhcpPrint((DEBUG_ERRORS, "DhcpRequestParams: 0x%lx (%ld)\n", Result, Result));
|
||
|
DhcpFreeMemory(RecdParams);
|
||
|
return Result;
|
||
|
}
|
||
|
|
||
|
DhcpAssert(NULL != RecdParams);
|
||
|
Result = ConvertFromBufferToClassInfo( // convert from straight bytes to classinfo struct
|
||
|
RecdParams->Data,
|
||
|
RecdParams->nBytesData,
|
||
|
ClassesArray,
|
||
|
Size
|
||
|
);
|
||
|
|
||
|
DhcpFreeMemory(RecdParams);
|
||
|
return Result;
|
||
|
}
|
||
|
|
||
|
ULONG _inline // status
|
||
|
GetRegistryClassIdName( // get registr string class id name written by ui
|
||
|
IN LPWSTR AdapterName, // for this adapter
|
||
|
OUT LPWSTR *ClassIdName
|
||
|
)
|
||
|
{
|
||
|
ULONG Error;
|
||
|
LPBYTE Value;
|
||
|
ULONG ValueType, ValueSize;
|
||
|
|
||
|
*ClassIdName = NULL;
|
||
|
ValueSize = 0; Value = NULL;
|
||
|
Error = DhcpRegReadFromLocation(
|
||
|
DEFAULT_USER_CLASS_UI_LOC_FULL,
|
||
|
AdapterName,
|
||
|
&Value,
|
||
|
&ValueType,
|
||
|
&ValueSize
|
||
|
);
|
||
|
if( ERROR_SUCCESS != Error ) return Error; // failed?
|
||
|
if( REG_SZ != ValueType ) {
|
||
|
if( Value ) DhcpFreeMemory(Value);
|
||
|
DhcpPrint((DEBUG_ERRORS, "DhcpClassId Type is incorrect: %ld\n", ValueType));
|
||
|
DhcpAssert(FALSE);
|
||
|
return ERROR_INVALID_DATA; // uh ? should not have happened!
|
||
|
}
|
||
|
|
||
|
*ClassIdName = (LPWSTR)Value;
|
||
|
return ERROR_SUCCESS;
|
||
|
}
|
||
|
|
||
|
ULONG _inline // status
|
||
|
ConvertClassIdNameToBin( // get corresponding value, return itself in ASCII o/w
|
||
|
IN LPWSTR AdapterName, // for this adapter
|
||
|
IN LPWSTR ClassIdName, // ClassIdName for which we are searching
|
||
|
IN BOOL SkipClassEnum, // to skip dhcp class enumeration during initialization
|
||
|
OUT LPBYTE *ClassIdBin, // fill this ptr up
|
||
|
OUT ULONG *ClassIdBinSize // fill this with size of memory allocated
|
||
|
)
|
||
|
{
|
||
|
ULONG Error, Size, i;
|
||
|
PDHCP_CLASS_INFO pDhcpClassInfo;// array
|
||
|
LPBYTE BinData;
|
||
|
ULONG BinDataLen;
|
||
|
|
||
|
pDhcpClassInfo = NULL;
|
||
|
BinData = NULL; BinDataLen = 0;
|
||
|
*ClassIdBin = NULL; *ClassIdBinSize = 0;
|
||
|
|
||
|
// do not perform class enumeration before Dhcp is initialized.
|
||
|
if (!SkipClassEnum) {
|
||
|
do { // not a loop, just to avoid GOTOs
|
||
|
Size = 0; // buffer yet be allocated..
|
||
|
Error = DhcpEnumClasses(
|
||
|
/* Flags */ 0,
|
||
|
/* AdapterName */ AdapterName,
|
||
|
/* Size */ &Size,
|
||
|
/* ClassesArray */ NULL
|
||
|
);
|
||
|
if( ERROR_MORE_DATA != Error ) { // failed?
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
DhcpAssert(0 != Size);
|
||
|
pDhcpClassInfo = DhcpAllocateMemory(Size);
|
||
|
if( NULL == pDhcpClassInfo ) return ERROR_NOT_ENOUGH_MEMORY;
|
||
|
|
||
|
Error = DhcpEnumClasses(
|
||
|
/* Flags */ 0,
|
||
|
/* AdapterName */ AdapterName,
|
||
|
/* Size */ &Size,
|
||
|
/* ClassesArray */ pDhcpClassInfo
|
||
|
);
|
||
|
if( ERROR_SUCCESS != Error ) { // This call should not fail!
|
||
|
DhcpPrint((DEBUG_ERRORS, "DhcpEnumClasses failed %ld\n", Error));
|
||
|
DhcpAssert(FALSE);
|
||
|
DhcpFreeMemory(pDhcpClassInfo);
|
||
|
return Error;
|
||
|
}
|
||
|
|
||
|
DhcpAssert(0 != Size);
|
||
|
for( i = 0; i != Size ; i ++ ) {
|
||
|
if( 0 == wcscmp(pDhcpClassInfo[i].ClassName, ClassIdName) )
|
||
|
break;
|
||
|
}
|
||
|
if( i != Size ) { // found a match
|
||
|
BinData = pDhcpClassInfo[i].ClassData;
|
||
|
BinDataLen = pDhcpClassInfo[i].ClassDataLen;
|
||
|
} else {
|
||
|
DhcpFreeMemory(pDhcpClassInfo);
|
||
|
}
|
||
|
} while(0); // not a loop just to avoid GOTOs
|
||
|
}
|
||
|
|
||
|
// BinData and BinDataLen holds the info we know..
|
||
|
|
||
|
if( NULL == BinData ) { // couldn't find the class..
|
||
|
DhcpPrint((DEBUG_ERRORS, "Could not find the class <%ws>\n", ClassIdName));
|
||
|
|
||
|
BinDataLen = wcslen(ClassIdName);
|
||
|
BinData = DhcpAllocateMemory(BinDataLen);
|
||
|
if( NULL == BinData ) { // could not allocate this mem?
|
||
|
return ERROR_NOT_ENOUGH_MEMORY;
|
||
|
}
|
||
|
|
||
|
Error = wcstombs(BinData, ClassIdName, BinDataLen);
|
||
|
if( -1 == Error ) { // failed conversion?
|
||
|
Error = GetLastError();
|
||
|
DhcpPrint((DEBUG_ERRORS, "Failed ot convert %ws\n", ClassIdName));
|
||
|
DhcpAssert(FALSE);
|
||
|
DhcpFreeMemory(BinData);
|
||
|
return Error;
|
||
|
}
|
||
|
|
||
|
*ClassIdBin = BinData; *ClassIdBinSize = BinDataLen;
|
||
|
return ERROR_SUCCESS;
|
||
|
}
|
||
|
|
||
|
// successfully got the bindata etc..
|
||
|
DhcpAssert(pDhcpClassInfo); // this is where the string is..
|
||
|
|
||
|
*ClassIdBin = DhcpAllocateMemory(BinDataLen); // try allocating memory
|
||
|
if( NULL == *ClassIdBin ) { // failed
|
||
|
return ERROR_NOT_ENOUGH_MEMORY;
|
||
|
}
|
||
|
|
||
|
memcpy(*ClassIdBin, BinData, BinDataLen);
|
||
|
*ClassIdBinSize = BinDataLen;
|
||
|
|
||
|
if (pDhcpClassInfo != NULL)
|
||
|
DhcpFreeMemory(pDhcpClassInfo); // free allocated ptr
|
||
|
|
||
|
return ERROR_SUCCESS;
|
||
|
}
|
||
|
|
||
|
LPWSTR _inline // String (allocated)
|
||
|
GetRegClassIdBinLocation( // find where to store bin
|
||
|
IN LPWSTR AdapterName // for this adapter
|
||
|
)
|
||
|
{
|
||
|
ULONG Error;
|
||
|
LPWSTR Value, RetVal;
|
||
|
ULONG ValueSize, ValueType;
|
||
|
|
||
|
ValueSize = 0; Value = NULL;
|
||
|
Error = DhcpRegReadFromLocation(
|
||
|
DHCP_CLIENT_PARAMETER_KEY REGISTRY_CONNECT_STRING DHCP_CLASS_LOCATION_VALUE,
|
||
|
AdapterName,
|
||
|
&(LPBYTE)Value,
|
||
|
&ValueType,
|
||
|
&ValueSize
|
||
|
);
|
||
|
if( ERROR_SUCCESS != Error ) { // couldn't find it? choose default!
|
||
|
ValueSize = 0; // didn't allocate nothing..
|
||
|
} else if( ValueType != DHCP_CLASS_LOCATION_TYPE ) {
|
||
|
DhcpPrint((DEBUG_ERRORS, "DhcpLocationType is %ld\n", ValueType));
|
||
|
DhcpAssert(FALSE);
|
||
|
ValueSize = 0;
|
||
|
}
|
||
|
if( 0 == ValueSize ) { // choose default..
|
||
|
Value = DEFAULT_USER_CLASS_LOC_FULL;
|
||
|
}
|
||
|
|
||
|
Error = DhcpRegExpandString( // replace '?' with AdapterName
|
||
|
Value,
|
||
|
AdapterName,
|
||
|
&RetVal,
|
||
|
NULL
|
||
|
);
|
||
|
|
||
|
if( 0 != ValueSize ) DhcpFreeMemory(Value); // free only if we didn't allocate
|
||
|
if( ERROR_SUCCESS != Error ) return NULL; // can't return error codes?
|
||
|
|
||
|
return RetVal;
|
||
|
}
|
||
|
|
||
|
|
||
|
ULONG _inline // status
|
||
|
SetRegistryClassIdBin( // write the binary classid value
|
||
|
IN LPWSTR AdapterName, // for this adapter
|
||
|
IN LPBYTE ClassIdBin, // Binary value to write
|
||
|
IN ULONG ClassIdBinSize // size of entry..
|
||
|
)
|
||
|
{
|
||
|
ULONG Error;
|
||
|
LPWSTR RegLocation; // registry location..
|
||
|
LPWSTR RegValue;
|
||
|
HKEY RegKey;
|
||
|
|
||
|
RegLocation = GetRegClassIdBinLocation(AdapterName);
|
||
|
if( NULL == RegLocation ) return ERROR_NOT_ENOUGH_MEMORY;
|
||
|
|
||
|
RegValue = wcsrchr(RegLocation, REGISTRY_CONNECT);
|
||
|
if( NULL == RegValue ) { // invalid string?
|
||
|
return ERROR_INVALID_DATA;
|
||
|
}
|
||
|
|
||
|
*RegValue ++ = L'\0'; // separate key and value..
|
||
|
|
||
|
Error = RegOpenKeyEx( // open the key..
|
||
|
HKEY_LOCAL_MACHINE,
|
||
|
RegLocation,
|
||
|
0 /* Reserved */,
|
||
|
DHCP_CLIENT_KEY_ACCESS,
|
||
|
&RegKey
|
||
|
);
|
||
|
if( ERROR_SUCCESS != Error ) {
|
||
|
DhcpPrint((DEBUG_ERRORS, "Could not open key: %ws : %ld\n", RegLocation, Error));
|
||
|
DhcpFreeMemory(RegLocation);
|
||
|
return Error;
|
||
|
}
|
||
|
|
||
|
Error = RegSetValueEx(
|
||
|
RegKey,
|
||
|
RegValue,
|
||
|
0 /* Reserved */,
|
||
|
REG_BINARY,
|
||
|
ClassIdBin,
|
||
|
ClassIdBinSize
|
||
|
);
|
||
|
RegCloseKey(RegKey);
|
||
|
if( ERROR_SUCCESS != Error ) {
|
||
|
DhcpPrint((DEBUG_ERRORS, "Could not save value:"
|
||
|
"%ws / %ws: %ld\n", RegLocation, RegValue, Error));
|
||
|
}
|
||
|
DhcpFreeMemory(RegLocation);
|
||
|
return Error;
|
||
|
}
|
||
|
|
||
|
ULONG // status
|
||
|
FixupDhcpClassId( // fix ClassIdBin value in registry based on ClassId
|
||
|
IN LPWSTR AdapterName,
|
||
|
IN BOOL SkipClassEnum
|
||
|
)
|
||
|
{
|
||
|
LPWSTR ClassIdName; // as written by UI
|
||
|
LPBYTE ClassIdBin; // as needs to be written in registry
|
||
|
ULONG ClassIdBinSize;// the # of bytes of above..
|
||
|
ULONG Error; // status
|
||
|
|
||
|
ClassIdName = NULL;
|
||
|
Error = GetRegistryClassIdName(AdapterName, &ClassIdName);
|
||
|
if( ERROR_SUCCESS != Error || NULL == ClassIdName
|
||
|
|| L'\0' == *ClassIdName ) {
|
||
|
DhcpPrint((DEBUG_ERRORS, "Could not read ClassId: %ld\n", Error));
|
||
|
ClassIdName = NULL;
|
||
|
}
|
||
|
|
||
|
ClassIdBinSize = 0; ClassIdBin = NULL;
|
||
|
|
||
|
if( ClassIdName ) {
|
||
|
Error = ConvertClassIdNameToBin(
|
||
|
AdapterName, ClassIdName, SkipClassEnum, &ClassIdBin, &ClassIdBinSize
|
||
|
);
|
||
|
|
||
|
DhcpFreeMemory(ClassIdName);// Dont need this memory anymore
|
||
|
} else {
|
||
|
Error = ERROR_SUCCESS;
|
||
|
}
|
||
|
|
||
|
if( ERROR_SUCCESS != Error || NULL == ClassIdBin ) {
|
||
|
DhcpPrint((DEBUG_ERRORS, "Could not convert classid.. making it NULL\n"));
|
||
|
ClassIdBin = NULL;
|
||
|
ClassIdBinSize = 0;
|
||
|
}
|
||
|
|
||
|
Error = SetRegistryClassIdBin(AdapterName, ClassIdBin, ClassIdBinSize);
|
||
|
if( ClassIdBin ) DhcpFreeMemory(ClassIdBin);
|
||
|
|
||
|
return Error;
|
||
|
}
|
||
|
|
||
|
//DOC DhcpHandlePnpEvent can be called as an API by any process (excepting that executing within the
|
||
|
//DOC DHCP process itself) when any of the registry based configuration has changed and DHCP client has to
|
||
|
//DOC re-read the registry. The Flags parameter is for future expansion.
|
||
|
//DOC The AdapterName can currently be only GUIDs but may soon be EXTENDED to be IpAddress strings or
|
||
|
//DOC h-w addresses or any other user friendly means of denoting the Adapter. Note that if the Adapter
|
||
|
//DOC Name is NULL (not the empty string L""), then it refers to either GLOBAL parameters or ALL adapters
|
||
|
//DOC depending on which BOOL has been set. (this may not get done for BETA2).
|
||
|
//DOC The Changes structure gives the information on what changed.
|
||
|
//DOC Currently, only a few of the defined BOOLs would be supported (for BETA2 NT5).
|
||
|
//DOC
|
||
|
//DOC Return Values:
|
||
|
//DOC ERROR_DEVICE_DOES_NOT_EXIST The AdapterName is illegal in the given context
|
||
|
//DOC ERROR_INVALID_PARAMETER
|
||
|
//DOC ERROR_CALL_NOT_SUPPORTED The particular parameter that has changed is not completely pnp yet.
|
||
|
//DOC Win32 errors
|
||
|
DWORD
|
||
|
WINAPI
|
||
|
DhcpHandlePnPEvent(
|
||
|
IN DWORD Flags, // MUST BE ZERO
|
||
|
IN DWORD Caller, // currently must be DHCP_CALLER_TCPUI
|
||
|
IN LPWSTR AdapterName, // currently must be the adapter GUID or NULL if global
|
||
|
IN LPDHCP_PNP_CHANGE Changes, // specify what changed
|
||
|
IN LPVOID Reserved // reserved for future use..
|
||
|
)
|
||
|
{
|
||
|
ULONG Error;
|
||
|
|
||
|
if( 0 != Flags || DHCP_CALLER_TCPUI != Caller ||
|
||
|
NULL != Reserved || NULL == Changes ) {
|
||
|
return ERROR_INVALID_PARAMETER; // sanity check
|
||
|
}
|
||
|
|
||
|
if( Changes->Version > DHCP_PNP_CHANGE_VERSION_0 ) {
|
||
|
return ERROR_NOT_SUPPORTED; // this version is not supported
|
||
|
}
|
||
|
|
||
|
if( Changes->ClassIdChanged ) { // the classid got changed..
|
||
|
// The UI writes any changes to the "DhcpClassId" registry value... but
|
||
|
// this is just the name of the class and not the actual ClassId binary value
|
||
|
// So we read this compare and write the correct value..
|
||
|
(void) FixupDhcpClassId(AdapterName, FALSE); // figure the binary classid value
|
||
|
}
|
||
|
|
||
|
Error = DhcpStaticRefreshParams(AdapterName); // refresh all static params..
|
||
|
|
||
|
if( ERROR_SUCCESS != Error ) return Error;
|
||
|
if( Changes->ClassIdChanged ) {
|
||
|
//
|
||
|
// If ClassID changes, we have to refresh lease..
|
||
|
//
|
||
|
(void) DhcpAcquireParameters(AdapterName);
|
||
|
}
|
||
|
|
||
|
return ERROR_SUCCESS;
|
||
|
}
|
||
|
|
||
|
//================================================================================
|
||
|
// end of file
|
||
|
//================================================================================
|
||
|
|
||
|
|