windows-nt/Source/XPSP1/NT/net/dhcp/lib/dhcpcom.c
2020-09-26 16:20:57 +08:00

557 lines
13 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
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);
}