/*++ 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 #include #include #include 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; iOptionValue + 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; iOptionType = 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); }