📄 dhcp.c
字号:
}
// We need to broadcast these messages to all the DHCP servers.
if (EbootDHCPRetransmit( pMyAddr, &ClientAddr, FrameBuf)) {
EdbgOutputDebugString( "SendDHCP()::Error On DHCPRetransmit() Call\r\n" );
return 1;
}
return 0;
} // SendDHCP()
static BYTE HexToChar(BYTE hex)
{
switch (hex) {
case 0:
case 1:
case 2:
case 3:
case 4:
case 5:
case 6:
case 7:
case 8:
case 9:
return '0' + hex;
case 10:
case 11:
case 12:
case 13:
case 14:
case 15:
return 'A' + hex - 10;
}
return 'X';
}
// Generate a string which is the concatenation of "CED" and the ethernet address
// ("CED" denotes the debug ethernet component of a CE device.)
static void FormatDHCPName(BYTE * pName, BYTE * pEthAddr)
{
DWORD j;
BYTE * pN;
BYTE * pA;
BYTE A;
pName[0] = 'C';
pName[1] = 'E';
pName[2] = 'D';
pN = pName + 3;
pA = pEthAddr;
for (j = 0; j < 6; j++, pA++, pN += 2) {
A = *pA;
pN[0] = HexToChar((BYTE)(A >> 4));
pN[1] = HexToChar((BYTE)(A & 0x0f));
}
*pN = 0;
} // FormatDHCPName
// This routine will add options to the DHCP Options field. The option type is filled in
// and the Option Offset (pwOpOff) is incremented to include the new option. Some of the
// options can be taken from the DHCP header itself, data for others is passed in through
// the generic dwData.
void DHCPBuildOps( DHCPOptions DHCPOption, DHCPMsgFormat *pDHCPMsg, WORD *pwOpOff, DWORD dwData )
{
BYTE * pName;
switch( DHCPOption ) {
case DHCP_SERVER_ID:
case DHCP_IP_ADDR_REQ:
case DHCP_HOSTNAME:
case DHCP_CLIENT_ID:
case DHCP_END:
pDHCPMsg->bOptions[(*pwOpOff)++] = DHCPOption;
break;
} // switch
switch( DHCPOption ) {
case DHCP_SERVER_ID:
case DHCP_IP_ADDR_REQ:
// There are 4 data bytes
pDHCPMsg->bOptions[(*pwOpOff)++] = 4;
// IP address that we'd like to have
pDHCPMsg->bOptions[(*pwOpOff)++] = (BYTE)dwData;
pDHCPMsg->bOptions[(*pwOpOff)++] = (BYTE)(dwData >> 8);
pDHCPMsg->bOptions[(*pwOpOff)++] = (BYTE)(dwData >> 16);
pDHCPMsg->bOptions[(*pwOpOff)++] = (BYTE)(dwData >> 24);
break;
case DHCP_HOSTNAME:
// The ethernet address is passed in dwData
pName = &(pDHCPMsg->bOptions[*pwOpOff+1]);
FormatDHCPName(pName, (BYTE *)dwData);
// Fill out the host name length
(*pwOpOff) += pDHCPMsg->bOptions[*pwOpOff] = strlen(pName) + 1;
(*pwOpOff)++;
break;
case DHCP_CLIENT_ID:
pDHCPMsg->bOptions[(*pwOpOff)++] = 7; // 1 byte of hw addr type and 6 bytes of ethernet addr
pDHCPMsg->bOptions[(*pwOpOff)++] = 1; // ethernet hw addr type
memcpy(&(pDHCPMsg->bOptions[*pwOpOff]), (BYTE *) dwData, 6); // ethernet addr
*pwOpOff += 6;
break;
} // switch
} // DHCPBuildOps()
// 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. They are done in a somewhat non-obvious order 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.
BYTE *DHCPFindOption( 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 = DHCPParseField( 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 = DHCPParseField( DHCPOption, pDHCPMsg->bOptions + 4);
if (pbParse != NULL)
return pbParse;
if (fUseFile) {
pbParse = DHCPParseField( DHCPOption, pDHCPMsg->szFILE );
if (pbParse != NULL)
return pbParse;
}
if (fUseSname)
pbParse = DHCPParseField( DHCPOption, pDHCPMsg->szSNAME );
return pbParse;
} // DHCPFindOption()
// 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.
BYTE *DHCPParseField( 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;
} // DHCPParseField
// This routine is called in two instances. When the SendDHCP() routine forms a packet, this
// routine is called with the source address and the message to be sent. That initilizes the
// retry timers and causes the routine to save the message. Then the routine is called
// by the main Ethernet() loop so that the DHCP message can be retransmit as necessary.
// If there are too many retry attempts without a reply, the routine will call ProcessDHCP()
// with the initialize flag set, which will cause the DHCP process to begin again.
// Note that the pMyAddr pointer must be valid on every call.
UINT16 EbootDHCPRetransmit( EDBG_ADDR *pMyAddr, EDBG_ADDR *pSrcAddr, BYTE *pFrame) {
DHCPMsgFormat *pDHCPMsg;
// These globals are used to store all the transmission information for the last DHCP packet
// that was sent. The DHCPRetransmit() routine uses this info to do retries.
static EDBG_ADDR SrcAddr;
static UCHAR LastDHCPFrame[UDP_DATA_FRAME_OFFSET+sizeof(DHCPMsgFormat)];
static WORD cRetries;
static DWORD dwTimeOfLastRetry;
// If this is the first call, then initialize everything and send the packet.
if (pSrcAddr != NULL) {
cRetries = 0;
dwTimeOfLastRetry = OEMEthGetSecs();
EDBG_DEBUGMSG(ZONE_DHCP,("+DHCPRetransmit: 1st transmission, time: %u\n",dwTimeOfLastRetry));
pDHCPMsg = (DHCPMsgFormat *)(pFrame+UDP_DATA_FRAME_OFFSET);
// Save last DHCP message sent, and source address
memcpy(LastDHCPFrame+UDP_DATA_FRAME_OFFSET, (BYTE *)pDHCPMsg, sizeof(DHCPMsgFormat));
SrcAddr = *pSrcAddr;
}
// If this is a retransmit call and we haven't exceeded the retry count, send it again
// It's supposed to be a doubling backoff from 4 seconds to 64
else if (OEMEthGetSecs() - dwTimeOfLastRetry > (4UL << cRetries)) {
dwTimeOfLastRetry = OEMEthGetSecs();
cRetries++;
EDBG_DEBUGMSG(ZONE_DHCP,("+DHCPRetransmit: Retry %u, time: %u\n",cRetries,dwTimeOfLastRetry));
// If we've reached the maximum retry count (64 seconds), re-initialize the DHCP handler
if (cRetries >= 5) {
EDBG_DEBUGMSG(ZONE_DHCP,("DHCPRetransmit, retry count exceeded, reinitializing...\n"));
pMyAddr->dwIP = 0;
return EbootInitDHCP( pMyAddr );
}
// Retransmit saved frame
pFrame = LastDHCPFrame;
pDHCPMsg = (DHCPMsgFormat *)(pFrame+UDP_DATA_FRAME_OFFSET);
}
else
return 0;
if (!EbootSendUDP( pFrame, &BroadCastAddr, &SrcAddr, (BYTE *)pDHCPMsg, sizeof(DHCPMsgFormat))) {
EdbgOutputDebugString( "EbootDHCPRetransmit()::Error On SendUDP() Call\r\n" );
return 1;
}
return 0;
} // EbootDHCPRetransmit
//
// Send a DHCP DECLINE message and wait 10 seconds
//
BOOL
EbootDHCPDecline( EDBG_ADDR *pMyAddr) {
BOOL bRet;
DWORD dwSentTime;
if (dwPrevAddr) {
if (dwPrevAddr == pMyAddr->dwIP) {
//
// Server keeps sending us the same IP addr!
// The bootloader code will continue the same retry algorithm as for ARP collisions
//
}
} else {
dwPrevAddr = pMyAddr->dwIP;
}
dwSentTime = OEMEthGetSecs();
bRet = SendDHCP(0, DHCP_DECLINE, &ServerAddr, pMyAddr, &dwXID ) ? FALSE : TRUE;
if (bRet) {
while (OEMEthGetSecs() - dwSentTime < 10) {
}
}
return bRet;
} // EbootDHCPDecline
// This routine is called repeatedly during the DHCP IP acquisition process to scan for serial
// input from the user. It first sends a message out the serial port asking for an IP
// address. If the user enters anything, the DHCP process will be interrupted and the user
// will be allowed to enter an IP address by hand. The user's IP address will be returned
// in pMyAddr and the routine will return non-zero if this happens.
BOOL
EbootReadSerialIP( EDBG_ADDR *pMyAddr, DWORD *pSubnetMask) {
static char szDottedD[16]; // The string used to collect the dotted decimal IP address
static WORD cwNumChars = 0;
static BOOL fIPEntered = FALSE;
UINT16 InChar;
InChar = OEMReadDebugByte();
if (InChar != OEM_DEBUG_COM_ERROR && InChar != OEM_DEBUG_READ_NODATA) {
// If it's a number or a period, add it to the string
if (InChar == '.' || (InChar >= '0' && InChar <= '9')) {
if (cwNumChars < 16) {
szDottedD[cwNumChars++] = (char)InChar;
OEMWriteDebugByte((BYTE)InChar);
}
}
// If it's a backspace, back up
else if (InChar == 8) {
if (cwNumChars > 0) {
cwNumChars--;
OEMWriteDebugByte((BYTE)InChar);
}
}
// If it's a carriage return or line feed, send it back
else if ((InChar == 0x0d) || (InChar == 0x0a)) {
if (fIPEntered) {
if (cwNumChars) {
szDottedD[cwNumChars] = '\0';
*pSubnetMask = inet_addr( szDottedD );
}
EdbgOutputDebugString( "\r\nReadSerialIP()::Using IP Address %s, ",
inet_ntoa(pMyAddr->dwIP));
EdbgOutputDebugString("netmask: %s\r\n", inet_ntoa(*pSubnetMask));
// Now we've got our address, allow timeouts again
return TRUE;
}
else {
// If it's a carriage return with an empty string, use the default pMyAddr
if (cwNumChars) {
szDottedD[cwNumChars] = '\0';
pMyAddr->dwIP = inet_addr( szDottedD );
}
fIPEntered = TRUE;
EdbgOutputDebugString("\r\nEnter new subnet mask or CR to use existing mask: ");
cwNumChars = 0;
// This will tell CheckUDP() to only accept datagrams for our IP address
ClearPromiscuousIP();
}
}
}
return FALSE;
} // ReadSerialIP()
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -