|
|
//--------------------------------------------------------------------------------
// Copyright (C) Micorosoft Confidential 1997
// Author: RameshV
// Description: Option related registry handling -- common between NT and VxD
//--------------------------------------------------------------------------------
#include <wininetp.h>
#include "aproxp.h"
#ifndef OPTREG_H
#define OPTREG_H
//--------------------------------------------------------------------------------
// function definitions
//--------------------------------------------------------------------------------
POPTION // option from which more appends can occur
DhcpAppendSendOptions( // append all configured options
IN OUT PDHCP_CONTEXT DhcpContext, // this is the context to append for
IN PLIST_ENTRY SendOptionsList, IN LPBYTE ClassName, // current class
IN DWORD ClassLen, // len of above in bytes
IN LPBYTE BufStart, // start of buffer
IN LPBYTE BufEnd, // how far can we go in this buffer
IN OUT LPBYTE SentOptions, // BoolArray[OPTION_END+1] to avoid repeating options
IN OUT LPBYTE VSentOptions, // to avoid repeating vendor specific options
IN OUT LPBYTE VendorOpt, // Buffer[OPTION_END+1] Holding Vendor specific options
OUT LPDWORD VendorOptLen // the # of bytes filled into that
);
DWORD // status
DhcpDestroyOptionsList( // destroy a list of options, freeing up memory
IN OUT PLIST_ENTRY OptionsList, // this is the list of options to destroy
IN PLIST_ENTRY ClassesList // this is where to remove classes off
);
DWORD // win32 status
DhcpClearAllOptions( // remove all turds from off registry
IN OUT PDHCP_CONTEXT DhcpContext // the context to clear for
);
#endif OPTREG_H
// internal private function that takes the lock on OPTIONS_LIST
DWORD // status
DhcpRegClearOptDefs( // clear all standard options
IN LPTSTR AdapterName // clear for this adapter
);
//
// options related lists
//
LIST_ENTRY DhcpGlobalRecvFromList; LPSTR DhcpGlobalClientClassInfo = NULL;
LPBYTE // ptr to buf loc where more appends can occur
DhcpAppendParamRequestList( // append the param request list option
IN PDHCP_CONTEXT DhcpContext, // the context to append for
IN PLIST_ENTRY SendOptionsList,// look thru this list
IN LPBYTE ClassName, // which class does this belong to?
IN DWORD ClassLen, // size of above in bytes
IN LPBYTE BufStart, // where to start adding this option
IN LPBYTE BufEnd // limit for this option
) { BYTE Buffer[OPTION_END+1]; LPBYTE Tmp; DWORD FirstSize; DWORD Size; PLIST_ENTRY ThisEntry; PDHCP_OPTION ThisOpt; DWORD i, j;
Size = FirstSize = 0; Buffer[Size++] = OPTION_SUBNET_MASK; // standard requested options
Buffer[Size++] = OPTION_DOMAIN_NAME; Buffer[Size++] = OPTION_ROUTER_ADDRESS; Buffer[Size++] = OPTION_DOMAIN_NAME_SERVERS; Buffer[Size++] = OPTION_NETBIOS_NAME_SERVER; Buffer[Size++] = OPTION_NETBIOS_NODE_TYPE; Buffer[Size++] = OPTION_NETBIOS_SCOPE_OPTION; Buffer[Size++] = OPTION_VENDOR_SPEC_INFO; Buffer[Size++] = OPTION_USER_CLASS; Buffer[Size++] = OPTION_WPAD_URL;
ThisEntry = SendOptionsList->Flink; while( ThisEntry != SendOptionsList ) { ThisOpt = CONTAINING_RECORD(ThisEntry, DHCP_OPTION, OptionList); ThisEntry = ThisEntry->Flink;
if( ThisOpt->IsVendor) continue;
if( ThisOpt->ClassLen ) { if( ThisOpt->ClassLen != ClassLen ) continue; if( ThisOpt->ClassName != ClassName ) continue; // this option is not used for this client
}
if( OPTION_PARAMETER_REQUEST_LIST != ThisOpt->OptionId ) { //
// only if the option is param_request_list do we request..
//
continue; }
for( i = 0; i < ThisOpt->DataLen ; i ++ ) { for( j = 0; j < Size; j ++ ) if( ThisOpt->Data[i] == Buffer[j] ) break; if( j < Size ) continue; // option already plugged in
Buffer[Size++] = ThisOpt->Data[i]; // add this option
}
if( 0 == FirstSize ) FirstSize = Size; }
if( 0 == FirstSize ) FirstSize = Size;
Tmp = BufStart; BufStart = (LPBYTE)DhcpAppendOption( // now add the param request list
(POPTION)BufStart, (BYTE)OPTION_PARAMETER_REQUEST_LIST, Buffer, (BYTE)Size, BufEnd );
if( Tmp == BufStart ) { // did not really add the option
BufStart = (LPBYTE)DhcpAppendOption( // now try adding the first request we saw instead of everything
(POPTION)BufStart, (BYTE)OPTION_PARAMETER_REQUEST_LIST, Buffer, (BYTE)FirstSize, BufEnd ); }
return BufStart; }
POPTION // option from which more appends can occur
DhcpAppendSendOptions( // append all configured options
IN OUT PDHCP_CONTEXT DhcpContext, // this is the context to append for
IN PLIST_ENTRY SendOptionsList, IN LPBYTE ClassName, // current class
IN DWORD ClassLen, // len of above in bytes
IN LPBYTE BufStart, // start of buffer
IN LPBYTE BufEnd, // how far can we go in this buffer
IN OUT LPBYTE SentOptions, // BoolArray[OPTION_END+1] to avoid repeating options
IN OUT LPBYTE VSentOptions, // to avoid repeating vendor specific options
IN OUT LPBYTE VendorOpt, // Buffer[OPTION_END+1] Holding Vendor specific options
OUT LPDWORD VendorOptLen // the # of bytes filled into that
) { PLIST_ENTRY ThisEntry; PDHCP_OPTION ThisOpt;
DhcpAssert(FALSE == SentOptions[OPTION_PARAMETER_REQUEST_LIST]); BufStart = DhcpAppendParamRequestList( DhcpContext, SendOptionsList, ClassName, ClassLen, BufStart, BufEnd ); SentOptions[OPTION_PARAMETER_REQUEST_LIST] = TRUE;
ThisEntry = SendOptionsList->Flink; while( ThisEntry != SendOptionsList ) { ThisOpt = CONTAINING_RECORD(ThisEntry, DHCP_OPTION, OptionList); ThisEntry = ThisEntry->Flink;
if( ThisOpt->IsVendor ? VSentOptions[ThisOpt->OptionId] : SentOptions[ThisOpt->OptionId] ) continue;
// if( ThisOpt->IsVendor) continue; // No vendor specific information this round through
if( ThisOpt->ClassLen ) { if( ThisOpt->ClassLen != ClassLen ) continue; if( ThisOpt->ClassName != ClassName ) continue; // this option is not used for this client
}
if( !ThisOpt->IsVendor ) { // easy to add non-vendor spec options
SentOptions[ThisOpt->OptionId] = TRUE; BufStart = (LPBYTE)DhcpAppendOption( (POPTION)BufStart, ThisOpt->OptionId, ThisOpt->Data, (BYTE)ThisOpt->DataLen, BufEnd ); } else { // ENCAPSULATE vendor specific options
if( SentOptions[OPTION_VENDOR_SPEC_INFO] ) continue; // Vendor spec info already added
VSentOptions[ThisOpt->OptionId] = TRUE;
if( ThisOpt->DataLen + 2 + *VendorOptLen > OPTION_END ) continue; // this option overflows the buffer
VendorOpt[(*VendorOptLen)++] = ThisOpt->OptionId; VendorOpt[(*VendorOptLen)++] = (BYTE)ThisOpt->DataLen; memcpy(&VendorOpt[*VendorOptLen], ThisOpt->Data, ThisOpt->DataLen); (*VendorOptLen) += ThisOpt->DataLen; } } return (POPTION)BufStart; }
DWORD // status
DhcpDestroyOptionsList( // destroy a list of options, freeing up memory
IN OUT PLIST_ENTRY OptionsList, // this is the list of options to destroy
IN PLIST_ENTRY ClassesList // this is where to remove classes off
) { PLIST_ENTRY ThisEntry; PDHCP_OPTION ThisOption; DWORD Error; DWORD LastError;
LastError = ERROR_SUCCESS; while(!IsListEmpty(OptionsList) ) { // for each element of this list
ThisEntry = RemoveHeadList(OptionsList); ThisOption = CONTAINING_RECORD(ThisEntry, DHCP_OPTION, OptionList);
if( NULL != ThisOption->ClassName ) { // if there is a class, deref it
Error = DhcpDelClass( ClassesList, ThisOption->ClassName, ThisOption->ClassLen ); if( ERROR_SUCCESS != Error ) { DhcpAssert( ERROR_SUCCESS == Error); LastError = Error; } }
DhcpFreeMemory(ThisOption); // now really free this
} return LastError; }
DWORD // win32 status
DhcpClearAllOptions( // clear all the options information
IN OUT PDHCP_CONTEXT DhcpContext // the context to clear for
) { PLIST_ENTRY ThisEntry; PDHCP_OPTION ThisOption; DWORD LocalError;
//(void) DhcpRegClearOptDefs(DhcpContext->AdapterName));
ThisEntry = DhcpContext->RecdOptionsList.Flink; while(ThisEntry != &DhcpContext->RecdOptionsList) { ThisOption = CONTAINING_RECORD(ThisEntry, DHCP_OPTION, OptionList); ThisEntry = ThisEntry->Flink;
// bug bug, need to return space?
ThisOption->Data = NULL; ThisOption->DataLen = 0;
//LocalError = DhcpMarkParamChangeRequests(
// DhcpContext->AdapterName,
// ThisOption->OptionId,
// ThisOption->IsVendor,
// ThisOption->ClassName
//);
DhcpAssert(ERROR_SUCCESS == LocalError); } return ERROR_SUCCESS; }
POPTION // buffer after filling option
DhcpAppendClassIdOption( // fill class id if exists
IN OUT PDHCP_CONTEXT DhcpContext, // the context to fillfor
OUT LPBYTE BufStart, // start of message buffer
IN LPBYTE BufEnd // end of message buffer
) { DWORD Size;
Size = (DWORD)(BufEnd - BufStart);
if( DhcpContext->ClassId ) { DhcpAssert(DhcpContext->ClassIdLength); BufStart = (LPBYTE)DhcpAppendOption( (POPTION)BufStart, OPTION_USER_CLASS, DhcpContext->ClassId, (BYTE)DhcpContext->ClassIdLength, BufEnd ); }
return (POPTION) BufStart; }
LPOPTION DhcpAppendOption( LPOPTION Option, BYTE OptionType, PVOID OptionValue, ULONG OptionLength, LPBYTE OptionEnd ) /*++
Routine Description:
This function writes a DHCP option to message buffer.
Arguments:
Option - A pointer to a message buffer.
OptionType - The option number to append.
OptionValue - A pointer to the option data.
OptionLength - The lenght, in bytes, of the option data.
OptionEnd - End of Option Buffer.
Return Value:
A pointer to the end of the appended option.
--*/ { DWORD i;
if ( OptionType == OPTION_END ) {
//
// we should alway have atleast one BYTE space in the buffer
// to append this option.
//
DhcpAssert( (LPBYTE)Option < OptionEnd );
Option->OptionType = OPTION_END; return( (LPOPTION) ((LPBYTE)(Option) + 1) );
}
if ( OptionType == OPTION_PAD ) {
//
// add this option only iff we have enough space in the buffer.
//
if(((LPBYTE)Option + 1) < (OptionEnd - 1) ) { Option->OptionType = OPTION_PAD; return( (LPOPTION) ((LPBYTE)(Option) + 1) ); }
DhcpPrint(("DhcpAppendOption failed to append Option " "%ld, Buffer too small.\n", OptionType )); return Option; }
//
// add this option only iff we have enough space in the buffer.
//
if(((LPBYTE)Option + 2 + OptionLength) >= (OptionEnd - 1) ) { DhcpPrint(("DhcpAppendOption failed to append Option " "%ld, Buffer too small.\n", OptionType )); return Option; }
if( OptionLength <= 0xFF ) { // simple option.. no need to use OPTION_MSFT_CONTINUED
Option->OptionType = OptionType; Option->OptionLength = (BYTE)OptionLength; memcpy( Option->OptionValue, OptionValue, OptionLength ); return( (LPOPTION) ((LPBYTE)(Option) + Option->OptionLength + 2) ); }
// option size is > 0xFF --> need to continue it using multiple ones..
// there are OptionLenght / 0xFF occurances using 0xFF+2 bytes + one
// using 2 + (OptionLength % 0xFF ) space..
// check to see if we have the space first..
if( 2 + (OptionLength%0xFF) + 0x101*(OptionLength/0xFF) + (LPBYTE)Option >= (OptionEnd - 1) ) { DhcpPrint(("DhcpAppendOption failed to append Option " "%ld, Buffer too small.\n", OptionType )); return Option; }
// first finish off all chunks of 0xFF size that we can do..
i = OptionLength/0xFF; while(i) { Option->OptionType = OptionType; Option->OptionLength = 0xFF; memcpy(Option->OptionValue, OptionValue, 0xFF); OptionValue = 0xFF+(LPBYTE)OptionValue; Option = (LPOPTION)(0x101 + (LPBYTE)Option); OptionType = OPTION_MSFT_CONTINUED; // all but the first use this ...
OptionLength -= 0xFF; }
// now finish off the remaining stuff..
DhcpAssert(OptionLength <= 0xFF); Option->OptionType = OPTION_MSFT_CONTINUED; Option->OptionLength = (BYTE)OptionLength; memcpy(Option->OptionValue, OptionValue, OptionLength); Option = (LPOPTION)(2 + OptionLength + (LPBYTE)Option); DhcpAssert((LPBYTE)Option < OptionEnd);
return Option; }
LPBYTE DhcpAppendMagicCookie( LPBYTE Option, LPBYTE OptionEnd ) /*++
Routine Description:
This routine appends magic cookie to a DHCP message.
Arguments:
Option - A pointer to the place to append the magic cookie.
OptionEnd - End of Option buffer.
Return Value:
A pointer to the end of the appended cookie.
Note : The magic cookie is :
-------------------- | 99 | 130 | 83 | 99 | --------------------
--*/ { DhcpAssert( (Option + 4) < (OptionEnd - 1) ); if( (Option + 4) < (OptionEnd - 1) ) { *Option++ = (BYTE)DHCP_MAGIC_COOKIE_BYTE1; *Option++ = (BYTE)DHCP_MAGIC_COOKIE_BYTE2; *Option++ = (BYTE)DHCP_MAGIC_COOKIE_BYTE3; *Option++ = (BYTE)DHCP_MAGIC_COOKIE_BYTE4; }
return( Option ); }
LPOPTION DhcpAppendClientIDOption( LPOPTION Option, BYTE ClientHWType, LPBYTE ClientHWAddr, BYTE ClientHWAddrLength, LPBYTE OptionEnd
) /*++
Routine Description:
This routine appends client ID option to a DHCP message.
History: 8/26/96 Frankbee Removed 16 byte limitation on the hardware address
Arguments:
Option - A pointer to the place to append the option request.
ClientHWType - Client hardware type.
ClientHWAddr - Client hardware address
ClientHWAddrLength - Client hardware address length.
OptionEnd - End of Option buffer.
Return Value:
A pointer to the end of the newly appended option.
Note : The client ID option will look like as below in the message:
----------------------------------------------------------------- | OpNum | Len | HWType | HWA1 | HWA2 | ..... | HWAn | -----------------------------------------------------------------
--*/ { #pragma warning(disable : 4200) // disable 0-sized array warning
struct _CLIENT_ID { BYTE bHardwareAddressType; BYTE pbHardwareAddress[0]; } *pClientID;
LPOPTION lpNewOption;
pClientID = (_CLIENT_ID *) DhcpAllocateMemory( sizeof( struct _CLIENT_ID ) + ClientHWAddrLength );
//
// currently there is no way to indicate failure. simply return unmodified option
// list
//
if ( !pClientID ) return Option;
pClientID->bHardwareAddressType = ClientHWType; memcpy( pClientID->pbHardwareAddress, ClientHWAddr, ClientHWAddrLength );
lpNewOption = DhcpAppendOption( Option, OPTION_CLIENT_ID, (LPBYTE)pClientID, (BYTE)(ClientHWAddrLength + sizeof(BYTE)), OptionEnd );
DhcpFreeMemory( pClientID );
return lpNewOption; }
// data locks on ClassesList must be taken before calling this function
PDHCP_CLASSES PRIVATE // the required classes struct
DhcpFindClass( // find a specified class
IN OUT PLIST_ENTRY ClassesList, // list of classes to srch in
IN LPBYTE Data, // non-NULL data bytes
IN DWORD Len // # of bytes of above, > 0
) { PLIST_ENTRY ThisEntry; PDHCP_CLASSES ThisClass;
ThisEntry = ClassesList->Flink; // first element in list
while( ThisEntry != ClassesList ) { // search the full list
ThisClass = CONTAINING_RECORD( ThisEntry, DHCP_CLASSES, ClassList ); ThisEntry = ThisEntry->Flink;
if( ThisClass->ClassLen == Len ) { // lengths must match
if( ThisClass->ClassName == Data ) // data ptrs can match OR data can match
return ThisClass; if( 0 == memcmp(ThisClass->ClassName, Data, Len) ) return ThisClass; } } return NULL; }
// locks on ClassesList should be taken when using this function
LPBYTE // data bytes, or NULL
DhcpAddClass( // add a new class
IN OUT PLIST_ENTRY ClassesList, // list to add to
IN LPBYTE Data, // input class name
IN DWORD Len // # of bytes of above
) { PDHCP_CLASSES Class; DWORD MemSize; // amt of memory reqd
if( NULL == ClassesList ) { // invalid parameter
DhcpAssert( NULL != ClassesList ); return NULL; }
if( 0 == Len || NULL == Data ) { // invalid parameters
DhcpAssert(0 != Len && NULL != Data ); return NULL; }
Class = DhcpFindClass(ClassesList,Data,Len); // already there in list?
if(NULL != Class) { // yes, found
Class->RefCount++; // increase ref-count
return Class->ClassName; }
MemSize = sizeof(*Class)+Len; // amt of memory reqd
Class = (PDHCP_CLASSES) DhcpAllocateMemory(MemSize); if( NULL == Class ) { // not enough memory
DhcpAssert( NULL != Class); return NULL; }
Class->ClassLen = Len; Class->RefCount = 1; Class->ClassName = ((LPBYTE)Class) + sizeof(*Class); memcpy(Class->ClassName, Data, Len);
InsertHeadList(ClassesList, &Class->ClassList);
return Class->ClassName; }
// locks on ClassesList must be taken before calling this function
DWORD // status
DhcpDelClass( // de-refernce a class
IN OUT PLIST_ENTRY ClassesList, // the list to delete off
IN LPBYTE Data, // the data ptr
IN DWORD Len // the # of bytes of above
) { PDHCP_CLASSES Class;
if( NULL == ClassesList ) { DhcpAssert( NULL != ClassesList ); return ERROR_INVALID_PARAMETER; }
if( 0 == Len || NULL == Data ) { // invalid parameter
DhcpAssert( 0 != Len && NULL != Data ); return ERROR_INVALID_PARAMETER; }
Class = DhcpFindClass(ClassesList,Data,Len); if( NULL == Class ) { // did not find this class?
DhcpAssert( NULL != Class ); return ERROR_FILE_NOT_FOUND; }
Class->RefCount --; if( 0 == Class->RefCount ) { // all references removed
RemoveEntryList( &Class->ClassList ); // remove this from the list
DhcpFreeMemory(Class); // free it
}
return ERROR_SUCCESS; }
// locks on ClassesList must be taken before calling this function
VOID // always succeed
DhcpFreeAllClasses( // free each elt of the list
IN OUT PLIST_ENTRY ClassesList // input list of classes
) { PDHCP_CLASSES ThisClass; PLIST_ENTRY ThisEntry;
if( NULL == ClassesList ) { DhcpAssert( NULL != ClassesList && "DhcpFreeAllClasses" ); return ; }
while( !IsListEmpty(ClassesList) ) { ThisEntry = RemoveHeadList(ClassesList); ThisClass = CONTAINING_RECORD(ThisEntry, DHCP_CLASSES, ClassList);
if( ThisClass->RefCount ) { DhcpPrint(("Freeing with refcount = %ld\n", ThisClass->RefCount)); }
DhcpFreeMemory(ThisClass); }
InitializeListHead(ClassesList); }
//--------------------------------------------------------------------------------
// exported functions, options
//--------------------------------------------------------------------------------
// data locks need to be taken on OptionsList before calling this function
PDHCP_OPTION // the reqd structure or NULL
DhcpFindOption( // find a specific option
IN OUT PLIST_ENTRY OptionsList, // the list of options to search
IN BYTE OptionId, // the option id to search for
IN BOOL IsVendor, // is it vendor specific?
IN LPBYTE ClassName, // is there a class associated?
IN DWORD ClassLen // # of bytes of above parameter
) { PLIST_ENTRY ThisEntry; PDHCP_OPTION ThisOption;
if( NULL == OptionsList ) { DhcpAssert( NULL != OptionsList ); return NULL; }
ThisEntry = OptionsList->Flink; while( ThisEntry != OptionsList ) { // search the set of options
ThisOption = CONTAINING_RECORD( ThisEntry, DHCP_OPTION, OptionList ); ThisEntry = ThisEntry->Flink;
if( ThisOption->OptionId != OptionId ) continue; if( ThisOption->IsVendor != IsVendor ) continue; if( ThisOption->ClassLen != ClassLen ) continue; if( ClassLen && ThisOption->ClassName != ClassName ) continue; // mismatched so far
return ThisOption; // found the option
}
return NULL; // did not find any match
}
// locks on OptionsList need to be taken before calling this function
DWORD // status
DhcpDelOption( // remove a particular option
IN PDHCP_OPTION ThisOption // option to delete
) { if( NULL == ThisOption) // nope, did not find this option
return ERROR_FILE_NOT_FOUND;
RemoveEntryList( &ThisOption->OptionList); // found it. remove and free
DhcpFreeMemory(ThisOption);
return ERROR_SUCCESS; }
// locks on OptionsList need to be taken before calling this function
DWORD // status
DhcpAddOption( // add a new option
IN OUT PLIST_ENTRY OptionsList, // list to add to
IN BYTE OptionId, // option id to add
IN BOOL IsVendor, // is it vendor specific?
IN LPBYTE ClassName, // what is the class?
IN DWORD ClassLen, // size of above in bytes
IN LPBYTE Data, // data for this option
IN DWORD DataLen, // # of bytes of above
IN time_t ExpiryTime // when the option expires
) { PDHCP_OPTION ThisOption; DWORD MemSize;
if( NULL == OptionsList ) { DhcpAssert( NULL != OptionsList && "DhcpAddOption" ); return ERROR_INVALID_PARAMETER; }
if( 0 != ClassLen && NULL == ClassName ) { DhcpAssert( 0 == ClassLen || NULL != ClassName && "DhcpAddOption" ); return ERROR_INVALID_PARAMETER; }
if( 0 != DataLen && NULL == Data ) { DhcpAssert( 0 == DataLen || NULL != Data && "DhcpAddOption" ); return ERROR_INVALID_PARAMETER; }
MemSize = sizeof(DHCP_OPTION) + DataLen ; ThisOption = (PDHCP_OPTION) DhcpAllocateMemory(MemSize); if( NULL == ThisOption ) // could not allocate memory
return ERROR_NOT_ENOUGH_MEMORY;
ThisOption->OptionId = OptionId; ThisOption->IsVendor = IsVendor; ThisOption->ClassName = ClassName; ThisOption->ClassLen = ClassLen; ThisOption->ExpiryTime = ExpiryTime; ThisOption->DataLen = DataLen; ThisOption->Data = ((LPBYTE)ThisOption) + sizeof(DHCP_OPTION); memcpy(ThisOption->Data, Data, DataLen);
InsertHeadList( OptionsList, &ThisOption->OptionList );
return ERROR_SUCCESS; }
//================================================================================
// end of file
//================================================================================
|