📄 dhcp.c
字号:
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft end-user
// license agreement (EULA) under which you licensed this SOFTWARE PRODUCT.
// If you did not accept the terms of the EULA, you are not authorized to use
// this source code. For a copy of the EULA, please see the LICENSE.RTF on your
// install media.
//
/*++
THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
PARTICULAR PURPOSE.
Module Name: dhcp.c
Abstract:
This contains the DHCP protocol IP address resolution
routines for the bootloader. It also contains a routine at
the bottom to allow IP address input via the serial port.
Functions:
Notes:
--*/
#include <windows.h>
#include <nkintr.h>
#include "udp.h"
#include "dhcp.h"
#include "eboot.h"
#include "tftp.h"
// This is used to broadcast things to the DHCP servers
static EDBG_ADDR BroadCastAddr = { 0xFFFFFFFFUL, { 0xFFFF, 0xFFFF, 0xFFFF }, DHCP_SERVER_PORT };
// For detecting loops in DHCP
static DWORD dwTimeLastDiscover = 0;
static DWORD dwPrevAddr = 0;
static EDBG_ADDR ServerAddr;
static DWORD dwXID;
// This will start the DHCP process by sending the first DISCOVER packet
UINT16
EbootInitDHCP( EDBG_ADDR *pMyAddr ) {
// Calling ProcessDHCP() with the initialization parameters will generate the first DISCOVER packet
EdbgOutputDebugString( "InitDHCP():: Calling ProcessDHCP()\r\n" );
if (EbootProcessDHCP( pMyAddr, NULL, NULL, 0, NULL, NULL)) {
EdbgOutputDebugString( "InitDHCP() Error - First DHCP Option isn't the message type\r\n" );
return 1;
}
return 0;
}
// This is the main routine called when a DHCP packet is received. It maintains the DHCP
// state machine and sends appropriate responses to the DHCP hosts when they send packets.
// When an IP address has been obtained, the flag pointed to by pfwDHCPComplete will be
// set to true. The routine can also be called with the pfwDHCPComplete set to NULL to
// indicate that it should re-initialize and begin the DHCP IP address acquisition process
// over again.
UINT16 EbootProcessDHCP(
EDBG_ADDR *pMyAddr,
DWORD *pSubnetMask,
BYTE *pbData,
WORD cwLength,
DWORD *pLeaseDuration,
BOOL *pfwDHCPComplete )
{
static DHCPStates DHCPState;
DHCPMsgFormat *pDHCPMsg = (DHCPMsgFormat *)pbData;
BYTE *pbParse;
DWORD DHCPLease;
BYTE DHCPMsgType;
EDBG_DEBUGMSG(ZONE_DHCP,("+EbootProcessDHCP: State: %u, pMyAddr: %X, Length: %u\n",DHCPState,(ULONG)pMyAddr,cwLength));
if (pLeaseDuration) {
*pLeaseDuration = 0;
}
// If pfwDHCPComplete == NULL, then we are re-initializing the DHCP process.
if (pfwDHCPComplete == NULL)
DHCPState = DHCP_INIT;
// Otherwise, there's a packet to process
else {
*pfwDHCPComplete = FALSE;
// Make sure that this is a Server to Client BOOTRESPONSE
if (pDHCPMsg->bOperation != 2)
return 0;
// Check for the "Magic Cookie" / sentinel
if (pDHCPMsg->bOptions[0] != 99 || pDHCPMsg->bOptions[1] != 130 ||
pDHCPMsg->bOptions[2] != 83 || pDHCPMsg->bOptions[3] != 99) {
return 0;
}
// Check message formating
else {
pbParse = DHCPFindOption( DHCP_MSGTYPE, pDHCPMsg );
if (NULL == pbParse) {
EdbgOutputDebugString( "ProcessDHCP() Error - No DHCP Message Type Option\r\n" );
return 1;
}
DHCPMsgType = pbParse[2];
}
}
switch( DHCPState ) {
case DHCP_INIT:
EdbgOutputDebugString( "ProcessDHCP()::DHCP_INIT\r\n" );
// Always try for a new address.
// (Before, we would request a previously leased IP address on platforms that stored the IP address
// on the netcard (i.e. ODO). This caused problems when the DHCP servers were switched.)
pMyAddr->dwIP = 0;
pMyAddr->wPort = DHCP_CLIENT_PORT;
if (SendDHCP( 0, DHCP_DISCOVER, &ServerAddr, pMyAddr, &dwXID )) {
EdbgOutputDebugString( "ProcessDHCP()::DHCP_INIT::SendDHCP(DHCP_DISCOVER) Error\r\n" );
return 1;
}
DHCPState = DHCP_SELECTING;
// This will indicate to CheckUDP() that it should accept any destination IP address.
SetPromiscuousIP();
break;
case DHCP_SELECTING:
if (pDHCPMsg->dwXID != dwXID)
break;
// We should only accept OFFER messages at this point, and we'll take the first one we get
if (DHCPMsgType == DHCP_OFFER) {
pMyAddr->dwIP = pDHCPMsg->dwYIADDR;
pbParse = DHCPFindOption( DHCP_SERVER_ID, pDHCPMsg );
if (pbParse == NULL) {
EdbgOutputDebugString( "ProcessDHCP()::DHCP_SELECTING::DHCPFindOption() Got DHCP_OFFER without DHCP_SERVER_ID\r\n" );
return 1;
}
// Pull out the server IP address, remembering to skip over option code and length
// I can't just retrieve a DWORD pointer from the buffer address because it might not be 4
// byte aligned.
ServerAddr.dwIP = ((DWORD)(pbParse[2])) | (((DWORD)(pbParse[3])) << 8) |
(((DWORD)(pbParse[4])) << 16) | (((DWORD)(pbParse[5])) << 24);
// Get our subnet mask
pbParse = DHCPFindOption( DHCP_SUBNET_MASK, pDHCPMsg );
if (pbParse == NULL) {
EdbgOutputDebugString( "ProcessDHCP()::DHCP_SELECTING::DHCPFindOption() Got DHCP_OFFER without DHCP_SUBNET_MASK\r\n" );
// We didn't get a subnet mask from the DHCP server - choose a good default.
//
*pSubnetMask = ntohl(0xffff0000);
return 1;
}
*pSubnetMask = ((DWORD)(pbParse[2])) | (((DWORD)(pbParse[3])) << 8) |
(((DWORD)(pbParse[4])) << 16) | (((DWORD)(pbParse[5])) << 24);
if (SendDHCP( 0, DHCP_REQUEST, &ServerAddr, pMyAddr, &dwXID )) {
EdbgOutputDebugString( "ProcessDHCP()::DHCP_SELECTING::SendDHCP() Error\r\n" );
return 1;
}
DHCPState = DHCP_REQUESTING;
}
// If the server says to discard the offer, start over
else if (DHCPMsgType == DHCP_NAK) {
DHCPState = DHCP_INIT;
pMyAddr->dwIP = 0;
dwTimeLastDiscover = 0; // Reset loop detection
return EbootInitDHCP( pMyAddr );
}
break;
case DHCP_REQUESTING:
if (pDHCPMsg->dwXID != dwXID)
break;
if (DHCPMsgType == DHCP_ACK) {
// This will tell CheckUDP() to only accept datagrams for our IP address
ClearPromiscuousIP();
// Signal that we've got a valid IP address
*pfwDHCPComplete = TRUE;
DHCPState = DHCP_BOUND;
pbParse = DHCPFindOption(DHCP_LEASE_TIME, pDHCPMsg);
if (pbParse == NULL) {
EdbgOutputDebugString( "ProcessDHCP()::DHCP_REQUESTING::DHCPFindOption() Got DHCP_ACK without DHCP_LEASE_TIME\r\n" );
return 1;
}
DHCPLease = ((DWORD)(pbParse[5])) | (((DWORD)(pbParse[4])) << 8) |
(((DWORD)(pbParse[3])) << 16) | (((DWORD)(pbParse[2])) << 24);
if (pLeaseDuration) {
*pLeaseDuration = DHCPLease;
}
EdbgOutputDebugString( "\r\nProcessDHCP()::DHCP IP Address Resolved as %s, ",
inet_ntoa(pMyAddr->dwIP));
EdbgOutputDebugString("netmask: %s\r\n",inet_ntoa(*pSubnetMask));
EdbgOutputDebugString("Lease time: %d seconds\r\n",DHCPLease);
}
// If the server says to discard the offer, start over
else if (DHCPMsgType == DHCP_NAK) {
DHCPState = DHCP_INIT;
pMyAddr->dwIP = 0;
dwTimeLastDiscover = 0; // Reset loop detection
return EbootInitDHCP( pMyAddr );
}
break;
case DHCP_BOUND:
break;
} // switch( DHCPState )
return 0;
} // ProcessDHCP
// This routine will form the DHCP messages that we have to send and send them out. There are three different
// messages that need to be sent: DHCP_DISCOVER and two types of DHCP_REQUEST. If the fRequestLastIP flag is
// set, then we are doing a request for a IP address that we've already got. If fRequestLastIP is not true,
// then we are requesting an IP address that we've just been OFFERed.
UINT16 SendDHCP( BYTE fRequestLastIP, DHCPMsgTypes MsgType, EDBG_ADDR *pServerAddr, EDBG_ADDR *pMyAddr, DWORD *dwXID ) {
UCHAR FrameBuf[UDP_DATA_FRAME_OFFSET + sizeof(DHCPMsgFormat)];
DHCPMsgFormat *pDHCPMsg = (DHCPMsgFormat *)(FrameBuf + UDP_DATA_FRAME_OFFSET);
EDBG_ADDR ClientAddr;
WORD wOpOff;
EDBG_DEBUGMSG(ZONE_DHCP,("+SendDHCP, MsgType: %u", MsgType));
ClientAddr = *pMyAddr;
// Start out by zeroing out the whole thing because most of it is supposed to be zero anyway
memset(pDHCPMsg, 0, sizeof(DHCPMsgFormat));
pDHCPMsg->bOperation = 1; // Client to Server messages are BOOTREQUEST
pDHCPMsg->bHardwareAddrType = 1; // Hardware type is 10Mbps Ethernet
pDHCPMsg->bHardwareAddrLen = 6; // Hardware address length
// Fill in our MAC address
pDHCPMsg->wCHADDR[0] = pMyAddr->wMAC[0];
pDHCPMsg->wCHADDR[1] = pMyAddr->wMAC[1];
pDHCPMsg->wCHADDR[2] = pMyAddr->wMAC[2];
pDHCPMsg->wSecs = (WORD)OEMEthGetSecs(); // Number of seconds elapsed since last reset
// The flags field is zero. Note that since the broadcast bit isn't set
// here, we must accept packets using our new IP address before we
// do the final confirmation.
// Now fill in the option fields
wOpOff = 0;
// Fill in the "Magic Cookie"
pDHCPMsg->bOptions[wOpOff++] = 99; pDHCPMsg->bOptions[wOpOff++] = 130;
pDHCPMsg->bOptions[wOpOff++] = 83; pDHCPMsg->bOptions[wOpOff++] = 99;
// Put in the message type field
pDHCPMsg->bOptions[wOpOff++] = DHCP_MSGTYPE; // This is the DHCP message type field
pDHCPMsg->bOptions[wOpOff++] = 1; // Length of 1 byte
pDHCPMsg->bOptions[wOpOff++] = MsgType; // Set the message type
switch( MsgType ) {
case DHCP_DISCOVER:
dwTimeLastDiscover = OEMEthGetSecs();
// This is supposed to be a random number used to identify the link.
// This number should be more or less unique.
*dwXID = pDHCPMsg->dwXID = (((DWORD)pDHCPMsg->wCHADDR[2]) << 16) | GenerateSrcPort();
// Specify our host name
DHCPBuildOps( DHCP_HOSTNAME, pDHCPMsg, &wOpOff, (DWORD)pMyAddr->wMAC);
if (ClientAddr.dwIP)
DHCPBuildOps( DHCP_IP_ADDR_REQ, pDHCPMsg, &wOpOff, ClientAddr.dwIP );
DHCPBuildOps( DHCP_CLIENT_ID, pDHCPMsg, &wOpOff, (DWORD)pMyAddr->wMAC);
// Indicate end of options
DHCPBuildOps( DHCP_END, pDHCPMsg, &wOpOff, 0 );
// The source IP for the DISCOVER is supposed to be 0;
ClientAddr.dwIP = 0;
break;
case DHCP_REQUEST:
// Specify our host name
DHCPBuildOps( DHCP_HOSTNAME, pDHCPMsg, &wOpOff, (DWORD)pMyAddr->wMAC);
// Request the new or old IP address
DHCPBuildOps( DHCP_IP_ADDR_REQ, pDHCPMsg, &wOpOff, ClientAddr.dwIP );
if (fRequestLastIP) {
// This number should be more or less unique.
*dwXID = pDHCPMsg->dwXID = (((DWORD)pDHCPMsg->wCHADDR[2]) << 16) | GenerateSrcPort();
pDHCPMsg->dwCIADDR = pMyAddr->dwIP;
}
else {
pDHCPMsg->dwXID = *dwXID;
DHCPBuildOps( DHCP_SERVER_ID, pDHCPMsg, &wOpOff, pServerAddr->dwIP );
}
DHCPBuildOps( DHCP_CLIENT_ID, pDHCPMsg, &wOpOff, (DWORD)pMyAddr->wMAC);
// Indicate end of options
DHCPBuildOps( DHCP_END, pDHCPMsg, &wOpOff, 0 );
ClientAddr.dwIP = 0;
break;
case DHCP_DECLINE:
DHCPBuildOps( DHCP_IP_ADDR_REQ, pDHCPMsg, &wOpOff, pMyAddr->dwIP);
// fallthrough to DHCP_RELEASE case
case DHCP_RELEASE:
*dwXID = pDHCPMsg->dwXID = (((DWORD)pDHCPMsg->wCHADDR[2]) << 16) | GenerateSrcPort();
pDHCPMsg->dwCIADDR = pMyAddr->dwIP;
DHCPBuildOps( DHCP_CLIENT_ID, pDHCPMsg, &wOpOff, (DWORD)pMyAddr->wMAC);
DHCPBuildOps( DHCP_SERVER_ID, pDHCPMsg, &wOpOff, pServerAddr->dwIP );
DHCPBuildOps( DHCP_END, pDHCPMsg, &wOpOff, 0 );
break;
} // switch( MsgType )
if (MsgType == DHCP_DECLINE) {
if (!EbootSendUDP(FrameBuf, &BroadCastAddr, pMyAddr, (BYTE *)pDHCPMsg, sizeof(DHCPMsgFormat))) {
EdbgOutputDebugString( "SendDHCP()::Error On SendUDP() Call\r\n" );
return 1;
}
return 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -