|
|
/*++
Copyright (c) 1994 Microsoft Corporation
Module Name:
dhcpcom.c
Abstract:
This module contains OS independent routines
Author:
John Ludeman (johnl) 13-Nov-1993 Broke out independent routines from existing files
Revision History:
--*/
#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#include <dhcpl.h>
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(( 0, "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(( 0, "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(( 0, "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; }
WIDE_OPTION UNALIGNED * AppendWideOption( WIDE_OPTION UNALIGNED *Option, WORD OptionType, PVOID OptionValue, WORD 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;
//
// add this option only iff we have enough space in the buffer.
//
if(((LPBYTE)&Option->OptionValue + OptionLength) >= (OptionEnd - FIELD_OFFSET(WIDE_OPTION, OptionValue)) ) { DhcpPrint(( 0, "AppendWideOption failed to append Option " "%ld, Buffer too small.\n", OptionType )); return Option; }
Option->OptionType = ntohs(OptionType); Option->OptionLength = ntohs(OptionLength); memcpy(Option->OptionValue, OptionValue, OptionLength); Option = (WIDE_OPTION UNALIGNED *)((PBYTE)&Option->OptionValue + OptionLength ); DhcpAssert((LPBYTE)Option < OptionEnd);
return Option; }
WIDE_OPTION UNALIGNED * AppendMadcapAddressList( WIDE_OPTION UNALIGNED * Option, DWORD UNALIGNED *AddrList, WORD AddrCount, LPBYTE OptionEnd ) /*++
Routine Description:
This function appends madcap address list option.
Arguments:
Option - A pointer to a message buffer.
AddrList - The list of the addresses to be attached.
AddrCount - Count of addresses in above list.
OptionEnd - End of Option Buffer.
Return Value:
A pointer to the end of the appended option.
--*/ { DWORD StartAddr; WORD i; WORD BlockCount,BlockSize; PBYTE Buff; WORD OptionLength;
if (AddrCount < 1) { return Option; } // First find out how many blocks do we need
for (BlockCount = i = 1; i<AddrCount; i++ ) { if (ntohl(AddrList[i]) != ntohl(AddrList[i-1]) + 1 ) { BlockCount++; } }
OptionLength = BlockCount*6; if(((LPBYTE)&Option->OptionValue + OptionLength) >= (OptionEnd - FIELD_OFFSET(WIDE_OPTION, OptionValue)) ) { DhcpPrint(( 0, "AppendMadcapAddressList failed to append Option " "Buffer too small\n" )); return Option; }
StartAddr = AddrList[0]; BlockSize = 1; Buff = Option->OptionValue; for (i = 1; i<AddrCount; i++ ) { if (ntohl(AddrList[i]) != ntohl(AddrList[i-1]) + 1 ) { BlockCount--; *(DWORD UNALIGNED *)Buff = StartAddr; Buff += 4; *(WORD UNALIGNED *)Buff = htons(BlockSize); Buff += 2; BlockSize = 1; StartAddr = AddrList[i]; } else { BlockSize++; } } BlockCount--; DhcpAssert(0==BlockCount); *(DWORD UNALIGNED *)Buff = StartAddr; Buff += 4; *(WORD UNALIGNED *)Buff = htons(BlockSize); Buff += 2;
Option->OptionType = ntohs(MADCAP_OPTION_ADDR_LIST); Option->OptionLength = htons(OptionLength); Option = (WIDE_OPTION UNALIGNED *)Buff; DhcpAssert((LPBYTE)Option < OptionEnd);
return Option;
}
DWORD ExpandMadcapAddressList( PBYTE AddrRangeList, WORD AddrRangeListSize, DWORD UNALIGNED *ExpandList, WORD *ExpandListSize )
/*++
Routine Description:
This function expands AddrRangeList from the wire format to array of addresses.
Arguments:
AddrRangeList - pointer to the AddrRangeList option Buffer.
AddrRangeListSize - size of the above buffer.
ExpandList - the pointer to the array where addresses are to be expanded. pass NULL if you want to determine the size of the expanded list.
ExpandListSize - No. of elements in above array.
Return Value:
Win32 ErrorCode --*/ { WORD TotalCount, BlockSize; PBYTE ListEnd, Buff; DWORD StartAddr;
// first count how many addresses we have in the list
ListEnd = AddrRangeList + AddrRangeListSize; Buff = AddrRangeList; TotalCount = 0; while ((Buff + 6 ) <= ListEnd) { StartAddr = *(DWORD UNALIGNED *) Buff; Buff += 4; BlockSize = ntohs(*(WORD UNALIGNED *)Buff); Buff += 2; if (!CLASSD_NET_ADDR(StartAddr) || !CLASSD_NET_ADDR(htonl(ntohl(StartAddr)+BlockSize-1)) ) { return ERROR_BAD_FORMAT; } TotalCount += BlockSize; } if (NULL == ExpandList) { *ExpandListSize = TotalCount; return ERROR_BUFFER_OVERFLOW; } if (Buff != ListEnd || TotalCount > *ExpandListSize || 0 == TotalCount) { return ERROR_BAD_FORMAT; } // now expand the actual list.
ListEnd = AddrRangeList + AddrRangeListSize; Buff = AddrRangeList;
while ((Buff + 6 ) <= ListEnd) { StartAddr = *(DWORD UNALIGNED *) Buff; Buff += 4; BlockSize = ntohs(*(WORD UNALIGNED *)Buff); Buff += 2; StartAddr = ntohl(StartAddr); while (BlockSize--) { *ExpandList = htonl(StartAddr); StartAddr++; ExpandList++; } } DhcpAssert(Buff == ListEnd); *ExpandListSize = TotalCount; return ERROR_SUCCESS; }
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 | -----------------------------------------------------------------
--*/ { struct _CLIENT_ID { BYTE bHardwareAddressType; BYTE pbHardwareAddress[0]; } *pClientID;
LPOPTION lpNewOption;
pClientID = 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; }
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 DhcpAppendEnterpriseName( LPOPTION Option, PCHAR DSEnterpriseName, LPBYTE OptionEnd ) /*++
Routine Description:
This routine appends the name of the enterprise as a MSFT-option to the DHCP message.
Arguments:
Option - A pointer to the place to append the magic cookie. DSEnterpriseName - null-terminated string containing name of enterprise OptionEnd - End of Option buffer.
Return Value:
A pointer to the end of the appended cookie. --*/ {
CHAR Buffer[260]; // enough room? should we malloc?
DWORD DSEnpriNameLen; LPOPTION RetOpt;
Buffer[0] = OPTION_MSFT_DSDOMAINNAME_RESP;
if (DSEnterpriseName) { // how big is the enterprise name? (include the null terminator)
DSEnpriNameLen = strlen(DSEnterpriseName) + 1;
Buffer[1] = (BYTE)DSEnpriNameLen;
strcpy(&Buffer[2],DSEnterpriseName); }
//
// if we are not part of any enterprise then DSEnterpriseName will be NULL
// In that case, just return a null-string, so the receiver can positively
// say we are a standalone server (as opposed to ignoring the option)
//
else { DSEnpriNameLen = 1; Buffer[1] = 1; Buffer[2] = '\0'; }
RetOpt = DhcpAppendOption( Option, OPTION_VENDOR_SPEC_INFO, Buffer, (BYTE)(DSEnpriNameLen + 2), // include Buffer[0] and Buffer[1]
OptionEnd );
return(RetOpt); }
|