📄 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 ethernet debug system.
Functions:
Notes:
--*/
#include <windows.h>
#include <Kitl.h>
#include <halether.h>
#include "Kitlethp.h"
#include "dhcp.h"
#define DHCP_ACK_TIMEOUT 120 // 2 minutes
#define ARP_WAIT_TIMEOUT 120 // 2 minutes
// This is used to broadcast things to the DHCP servers
static EDBG_ADDR BroadCastAddr = { 0xFFFFFFFFUL, { 0xFFFF, 0xFFFF, 0xFFFF }, DHCP_SERVER_PORT };
static DWORD DHCPLeaseTime;
static DWORD dwXID;
static DWORD DHCPState = DHCP_BOUND;
static void RenewDHCP (LPVOID lpParam);
static void EdbgDHCPError (void);
static BOOL EdbgSendDHCPRenew (EDBG_ADDR *pMyAddr, DWORD *dwXID);
static BOOL SendGratuitousARP (EDBG_ADDR *pMyAddr);
// setup a timer callback to renew DHCP half way through our DHCP lease period
BOOL EdbgInitDHCP (EDBG_ADDR *pMyAddr, DWORD dwDHCPLeaseTime)
{
static EDBG_ADDR MyAddr;
// make a local copy, update port number
memcpy (&MyAddr, pMyAddr, sizeof (EDBG_ADDR));
MyAddr.wPort = DHCP_CLIENT_PORT;
if (!(DHCPLeaseTime = dwDHCPLeaseTime)) {
// use static IP, don't bother DHCP server, just ARP it every now and then
DHCPLeaseTime = DEFAULT_DHCP_LEASE;
DHCPState = DHCP_ARPED;
}
// set timer to renew DHCP half way through the renew period
KitlSetTimerCallback (DHCPLeaseTime >> 1, RenewDHCP, &MyAddr);
return TRUE;
}
// function to handle ARP packets received
void HandleARPPacket (EDBG_ADDR *pMyAddr, LPBYTE pbFrame)
{
EthernetFrameHeader *pFrameHeader;
ARPPacketFormat *pARP;
pARP = (ARPPacketFormat *) (pbFrame + sizeof(EthernetFrameHeader));
// Check to see that they were requesting the ARP response from us
if (pARP->dwDestIP != pMyAddr->dwIP)
return; // not for us
// Make sure this is an ARP request
switch (htons(pARP->wOperation)) {
case 1: // ARP request
break;
case 2:
// ARP response -- we shared an IP address as others, FATAL
// spin forever
EdbgDHCPError ();
return;
case 3: // RARP request
case 4: // RARP response
default:
// just ignore it
return;
}
// Fill in destination and source MAC addresses and the ARP frame type
pFrameHeader = (EthernetFrameHeader *) pbFrame;
pFrameHeader->wDestMAC[0] = pARP->wSrcMAC[0];
pFrameHeader->wDestMAC[1] = pARP->wSrcMAC[1];
pFrameHeader->wDestMAC[2] = pARP->wSrcMAC[2];
pFrameHeader->wSrcMAC[0] = pMyAddr->wMAC[0];
pFrameHeader->wSrcMAC[1] = pMyAddr->wMAC[1];
pFrameHeader->wSrcMAC[2] = pMyAddr->wMAC[2];
pFrameHeader->wFrameType = htons(ARP_FRAME);
// The field information comes from page 57 of TCP/IP Illustrated by W. Richard Stevens
pARP->wHardwareType = htons(1); // Specifies Ethernet
pARP->wProtocolType = htons(IP_FRAME); // Specifies that IP addresses are being mapped
pARP->bHardwareAddrSize = 6; // Ethernet MAC addresses are 6 bytes long
pARP->bProtocolAddrSize = 4; // IP addresses are 4 bytes long
pARP->wOperation = htons(2); // Specify an ARP reply
// Fill in the destination information
pARP->wDestMAC[0] = pARP->wSrcMAC[0];
pARP->wDestMAC[1] = pARP->wSrcMAC[1];
pARP->wDestMAC[2] = pARP->wSrcMAC[2];
pARP->dwDestIP = pARP->dwSrcIP;
// Fill in the source side information
pARP->wSrcMAC[0] = pMyAddr->wMAC[0];
pARP->wSrcMAC[1] = pMyAddr->wMAC[1];
pARP->wSrcMAC[2] = pMyAddr->wMAC[2];
pARP->dwSrcIP = pMyAddr->dwIP;
KitlSendRawData (pbFrame, sizeof(EthernetFrameHeader) + sizeof(ARPPacketFormat));
}
BOOL HandleDHCPPacket (EDBG_ADDR *pMyAddr, UDPHeaderFormat *pUdpHdr)
{
DHCPMsgFormat *pDHCPMsg = (DHCPMsgFormat *) ((LPBYTE) pUdpHdr + sizeof (UDPHeaderFormat));
// check if this is a DHCP message
if ((pUdpHdr->wDestPort != DHCP_CLIENT_PORT)
|| (pUdpHdr->wSrcPort != DHCP_SERVER_PORT))
return FALSE;
// ignore all DHCP messages if we're not renewing
if (DHCPState != DHCP_RENEWING) {
return TRUE;
}
// ignore messages not for our renewing request
if (pDHCPMsg->dwXID != dwXID) {
return TRUE;
}
// If the server says to discard the offer, we're toast
if (pDHCPMsg->bOptions[6] == DHCP_NAK) {
EdbgDHCPError(); // doesn't return
return TRUE;
}
// signal we've got an valid IP address if we got an ACK
if (pDHCPMsg->bOptions[6] == DHCP_ACK) {
LPBYTE pbParse = EdbgDHCPFindOption (DHCP_LEASE_TIME, pDHCPMsg);
if (pbParse == NULL) {
KITLOutputDebugString ("ProcessDHCP()::DHCP_REQUESTING::DHCPFindOption() Got DHCP_ACK without DHCP_LEASE_TIME\r\n");
return TRUE;
}
DHCPState = DHCP_ACKED;
DHCPLeaseTime = ((DWORD)(pbParse[5])) | (((DWORD)(pbParse[4])) << 8)
| (((DWORD)(pbParse[3])) << 16) | (((DWORD)(pbParse[2])) << 24);
KITLOutputDebugString ("\r\nProcessDHCP()::DHCP IP Address Resolved as %s\r\n",
inet_ntoa(pMyAddr->dwIP));
KITLOutputDebugString("Lease time: %d seconds\r\n",DHCPLeaseTime);
}
return TRUE;
}
//
// callback from timer to renew DHCP
//
static void RenewDHCP (LPVOID lpParam)
{
EDBG_ADDR *pMyAddr = (EDBG_ADDR *) lpParam;
switch (DHCPState) {
// states for using DHCP
case DHCP_BOUND: // lease just expired, renew
DHCPState = DHCP_RENEWING;
// fall through
case DHCP_RENEWING: // in the process of renewing
EdbgSendDHCPRenew (pMyAddr, &dwXID);
KitlSetTimerCallback (DHCP_ACK_TIMEOUT, RenewDHCP, pMyAddr);
break;
case DHCP_ACKED: // got ack'd for our renewal
DHCPState = DHCP_BOUND;
// next renewal will be half way through our lease time
KitlSetTimerCallback (DHCPLeaseTime >> 1, RenewDHCP, pMyAddr);
break;
// states for using static IP
case DHCP_ARPED:
DHCPState = DHCP_ARPING;
// send Gratuitous ARP, hoping no one respond
SendGratuitousARP (pMyAddr);
KitlSetTimerCallback (ARP_WAIT_TIMEOUT, RenewDHCP, pMyAddr);
break;
case DHCP_ARPING: // didn't received ARP response for gratituous ARP
DHCPState = DHCP_ARPED;
// next renewal will be half way through our lease time
KitlSetTimerCallback (DHCPLeaseTime >> 1, RenewDHCP, pMyAddr);
break;
}
}
// This routine will look for a DHCP option in the field that starts at the
// location that pbParse points too. Note that all DHCP fields MUST end in
// a DHCP_END option, so that this search won't run away.
static LPBYTE EdbgDHCPParseField (DHCPOptions DHCPOption, BYTE *pbParse)
{
while (*pbParse != DHCP_END) {
if (*pbParse == DHCPOption)
return pbParse;
pbParse += *(pbParse + 1) + 2;
} // for every option code in this field
return NULL;
} // EdbgDHCPParseField
// This routine will parse through the DHCP message looking for the specified option.
// Note that the options can extend beyond the Options field into the file and sname
// fields. The order is not arranged very well, so that the Options field doesn't
// simply spill over into the others. Further, there is a defined parsing order that
// doesn't make much sense. This is why this routine is so confusing.
static LPBYTE EdbgDHCPFindOption (DHCPOptions DHCPOption, DHCPMsgFormat *pDHCPMsg)
{
BYTE *pbParse;
BYTE fUseSname = 0;
BYTE fUseFile = 0;
// First determine if the file or sname fields have been used to include addtional options.
// If they have, a DHCP_OPTION_OVERLOAD will appear in the normal Options field
// Don't forget to skip over Magic Cookie in Options field
pbParse = EdbgDHCPParseField (DHCP_OPTION_OVERLOAD, pDHCPMsg->bOptions + 4);
if (pbParse != NULL) {
fUseFile = (*(pbParse + 2)) & 1;
fUseSname = (*(pbParse + 2)) & 2;
}
// Now look for the option that we were called for, in the order specified by RFC1541
// Don't forget to skip over Magic Cookie in Options field
pbParse = EdbgDHCPParseField (DHCPOption, pDHCPMsg->bOptions + 4);
if (pbParse != NULL)
return pbParse;
if (fUseFile) {
pbParse = EdbgDHCPParseField (DHCPOption, pDHCPMsg->szFILE);
if (pbParse != NULL)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -