📄 dhcp.c
字号:
/*********************************************************************
*
* DHCP Module for Microchip TCP/IP Stack
*
*********************************************************************
* FileName: DHCP.c
* Dependencies: StackTsk.h
* UDP.h
* Processor: PIC18, PIC24F, PIC24H, dsPIC30F, dsPIC33F
* Complier: Microchip C18 v3.02 or higher
* Microchip C30 v2.01 or higher
* Company: Microchip Technology, Inc.
*
* Software License Agreement
*
* This software is owned by Microchip Technology Inc. ("Microchip")
* and is supplied to you for use exclusively as described in the
* associated software agreement. This software is protected by
* software and other intellectual property laws. Any use in
* violation of the software license may subject the user to criminal
* sanctions as well as civil liability. Copyright 2006 Microchip
* Technology Inc. All rights reserved.
*
* This software is provided "AS IS." MICROCHIP DISCLAIMS ALL
* WARRANTIES, EXPRESS, IMPLIED, STATUTORY OR OTHERWISE, NOT LIMITED
* TO MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND
* INFRINGEMENT. Microchip shall in no event be liable for special,
* incidental, or consequential damages.
*
*
* Author Date Comment
*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Nilesh Rajbharti 3/21/01 Original (Rev 1.0)
* Nilesh Rajbharti 7/10/02 Explicitly initialized tempIPAddress
* (Rev 2.11)
* Nilesh Rajbharti 5/16/03 Increased DHCP_TIMEOUT to 2 seconds.
* Nilesh Rajbharti 5/16/03 Fixed SM_DHCP_BROADCAST logic
* where UDPPut was called before setting
* active socket.
* Robert Sloan 5/29/03 Improved DHCP State machine to handle
* NAK and renew existing IP address.
* Nilesh Rajbharti 8/15/03 Modified _DHCPRecieve() to check for
* chaddr field before accpting the packet.
* Fixed DHCPTask() where it would not
* reply to first OFFER.
* Nilesh Rajbharti 3/1/04 Used tickDiff in DHCPTask() "bind"
* state to adjust for irregular TICK_SECOND
* Without this logic, actual lease time count
* down may be incorrect.
* Howard Schlunder 5/11/06 Fixed tickDiff usage, reducing
* accumulated timing error. Fixed DHCP
* state machine requesting IP 0.0.0.0
* after lease expiration.
* Howard Schlunder 6/01/06 Added DHCPState.bits.bOfferReceived flag to
* allow operation on networks with multiple
* DHCP servers offering multiple addresses
* Howard Schlunder 8/01/06 Added DNS server option to DHCP request,
* untested Host Name option to DHCP request
********************************************************************/
#define THIS_IS_DHCP
#include "..\Include\StackTsk.h"
#if defined(STACK_USE_DHCP)
#include "..\Include\DHCP.h"
#include "..\Include\UDP.h"
#include "..\Include\Tick.h"
#if defined(STACK_USE_SLIP)
#error DHCP module is not available when SLIP is used.
#endif
#define DHCP_TIMEOUT (TICK)(2L * TICK_SECOND)
#define DHCP_CLIENT_PORT (68u)
#define DHCP_SERVER_PORT (67u)
#define BOOT_REQUEST (1u)
#define BOOT_REPLY (2u)
#define HW_TYPE (1u)
#define LEN_OF_HW_TYPE (6u)
#define DHCP_MESSAGE_TYPE (53u)
#define DHCP_MESSAGE_TYPE_LEN (1u)
#define DHCP_UNKNOWN_MESSAGE (0u)
#define DHCP_DISCOVER_MESSAGE (1u)
#define DHCP_OFFER_MESSAGE (2u)
#define DHCP_REQUEST_MESSAGE (3u)
#define DHCP_DECLINE_MESSAGE (4u)
#define DHCP_ACK_MESSAGE (5u)
#define DHCP_NAK_MESSAGE (6u)
#define DHCP_RELEASE_MESSAGE (7u)
#define DHCP_SERVER_IDENTIFIER (54u)
#define DHCP_SERVER_IDENTIFIER_LEN (4u)
#define DHCP_PARAM_REQUEST_LIST (55u)
#define DHCP_PARAM_REQUEST_LIST_LEN (4u)
#define DHCP_PARAM_REQUEST_IP_ADDRESS (50u)
#define DHCP_PARAM_REQUEST_IP_ADDRESS_LEN (4u)
#define DHCP_SUBNET_MASK (1u)
#define DHCP_ROUTER (3u)
#define DHCP_DNS (6u)
#define DHCP_HOST_NAME (12u)
#define DHCP_IP_LEASE_TIME (51u)
#define DHCP_END_OPTION (255u)
#define HALF_HOUR (WORD)((WORD)60 * (WORD)30)
SM_DHCP smDHCPState = SM_DHCP_INIT_FIRST_TIME;
static UDP_SOCKET DHCPSocket = INVALID_UDP_SOCKET;
DHCP_STATE DHCPState = { 0x00 };
static DWORD_VAL DHCPServerID;
static DWORD_VAL DHCPLeaseTime;
static IP_ADDR tempIPAddress;
static IP_ADDR tempGateway;
static IP_ADDR tempMask;
#if defined(STACK_USE_DNS)
static IP_ADDR tempDNS;
#endif
//static BYTE tempHostName[16];
static union
{
struct
{
char IPAddress:1;
char Gateway:1;
char Mask:1;
char DNS:1;
char HostName:1;
} bits;
BYTE Val;
} ValidValues;
static BYTE _DHCPReceive(void);
static void _DHCPSend(BYTE messageType);
BYTE DHCPBindCount = 0;
// Uncomment following line if DHCP transactions are to be displayed on
// RS-232 - for debug purpose only.
//#define DHCP_DEBUG_MODE
#if defined(DHCP_DEBUG_MODE)
static USARTPut(BYTE c)
{
while( !TXSTA_TRMT);
TXREG = c;
}
#else
#define USARTPut(a)
#endif
void DHCPReset(void)
{
// Do not reset DHCP if it was previously disabled.
if ( smDHCPState == SM_DHCP_DISABLED )
return;
if ( DHCPSocket != INVALID_UDP_SOCKET )
UDPClose(DHCPSocket);
DHCPSocket = INVALID_UDP_SOCKET;
smDHCPState = SM_DHCP_INIT_FIRST_TIME;
DHCPBindCount = 0;
DHCPState.bits.bIsBound = FALSE;
}
/*********************************************************************
* Function: void DHCPTask(void)
*
* PreCondition: DHCPInit() is already called AND
* IPGetHeader() is called with
* IPFrameType == IP_PROT_UDP
*
* Input: None
*
* Output: None
*
* Side Effects: None
*
* Overview: Fetches pending UDP packet from MAC receive buffer
* and dispatches it appropriate UDP socket.
* If not UDP socket is matched, UDP packet is
* silently discarded.
*
* Note: Caller must make sure that MAC receive buffer
* access pointer is set to begining of UDP packet.
* Required steps before calling this function is:
*
* If ( MACIsRxReady() )
* {
* MACGetHeader()
* If MACFrameType == IP
* IPGetHeader()
* if ( IPFrameType == IP_PROT_UDP )
* Call DHCPTask()
* ...
********************************************************************/
void DHCPTask(void)
{
NODE_INFO DHCPServerNode;
static TICK lastTryTick;
BYTE DHCPRecvReturnValue;
TICK tickDiff;
switch(smDHCPState)
{
case SM_DHCP_INIT_FIRST_TIME:
tempIPAddress.Val = 0x0;
// smDHCPState = SM_DHCP_INIT; // State automatically changes
/* No break */
case SM_DHCP_INIT:
DHCPServerNode.MACAddr.v[0] = 0xff;
DHCPServerNode.MACAddr.v[1] = 0xff;
DHCPServerNode.MACAddr.v[2] = 0xff;
DHCPServerNode.MACAddr.v[3] = 0xff;
DHCPServerNode.MACAddr.v[4] = 0xff;
DHCPServerNode.MACAddr.v[5] = 0xff;
DHCPServerNode.IPAddr.Val = 0xffffffff;
DHCPSocket = UDPOpen(DHCP_CLIENT_PORT,
&DHCPServerNode,
DHCP_SERVER_PORT);
lastTryTick = TickGet();
smDHCPState = SM_DHCP_RESET_WAIT;
/* No break */
case SM_DHCP_RESET_WAIT:
if ( TickGetDiff(TickGet(), lastTryTick) >= (TICK_SECOND/(TICK)5) )
smDHCPState = SM_DHCP_BROADCAST;
break;
case SM_DHCP_BROADCAST:
// Assume default IP Lease time of 60 seconds.
// This should be minimum possible to make sure that if
// server did not specify lease time, we try again after this minimum time.
DHCPLeaseTime.Val = 60;
// If we have already obtained some IP address, renew it.
if(DHCPState.bits.bIsBound)
{
smDHCPState = SM_DHCP_REQUEST;
}
else if ( UDPIsPutReady(DHCPSocket) )
{
// To minimize code requirement, user must make sure that
// above call will be successful by making at least one
// UDP socket available.
// Usually this will be the case, given that DHCP will be
// the first one to use UDP socket.
// Also, we will not check for transmitter readiness,
// we assume it to be ready.
_DHCPSend(DHCP_DISCOVER_MESSAGE);
ValidValues.Val = 0x00;
// DEBUG
USARTPut('\n');
USARTPut('\r');
USARTPut('D');
lastTryTick = TickGet();
smDHCPState = SM_DHCP_DISCOVER;
}
break;
case SM_DHCP_DISCOVER:
if ( TickGetDiff(TickGet(), lastTryTick) >= DHCP_TIMEOUT )
{
smDHCPState = SM_DHCP_BROADCAST;
//return;
}
if ( UDPIsGetReady(DHCPSocket) )
{
// DEBUG
USARTPut('R');
if ( _DHCPReceive() == DHCP_OFFER_MESSAGE )
{
// DEBUG
USARTPut('O');
smDHCPState = SM_DHCP_REQUEST;
}
else
break;
}
else
break;
case SM_DHCP_REQUEST:
if ( UDPIsPutReady(DHCPSocket) )
{
_DHCPSend(DHCP_REQUEST_MESSAGE);
lastTryTick = TickGet();
smDHCPState = SM_DHCP_BIND;
}
break;
case SM_DHCP_BIND:
if ( UDPIsGetReady(DHCPSocket) )
{
DHCPRecvReturnValue = _DHCPReceive();
if ( DHCPRecvReturnValue == DHCP_NAK_MESSAGE )
{
// (RSS) NAK recieved. DHCP server didn't like our DHCP Request (format wrong/IP address allocated to someone else/outside IP pool)
USARTPut('n');
DHCPReset(); // Start all over again
return;
}
else if ( DHCPRecvReturnValue == DHCP_ACK_MESSAGE )
{
// DEBUG
USARTPut('B');
// Once DCHP is successful, release the UDP socket
// This will ensure that UDP layer discards any further DHCP related packets.
UDPClose(DHCPSocket);
DHCPSocket = INVALID_UDP_SOCKET;
lastTryTick = TickGet();
smDHCPState = SM_DHCP_BOUND;
if(ValidValues.bits.IPAddress)
AppConfig.MyIPAddr = tempIPAddress;
if(ValidValues.bits.Mask)
AppConfig.MyMask = tempMask;
if(ValidValues.bits.Gateway)
AppConfig.MyGateway = tempGateway;
#if defined(STACK_USE_DNS)
if(ValidValues.bits.DNS)
AppConfig.PrimaryDNSServer = tempDNS;
#endif
// if(ValidValues.bits.HostName)
// memcpy(AppConfig.NetBIOSName, (void*)tempHostName, sizeof(AppConfig.NetBIOSName));
DHCPState.bits.bIsBound = TRUE;
DHCPBindCount++;
return;
}
}
else if ( TickGetDiff(TickGet(), lastTryTick) >= DHCP_TIMEOUT )
{
USARTPut('t');
smDHCPState = SM_DHCP_BROADCAST;
}
break;
case SM_DHCP_BOUND:
// Keep track of how long we use this IP configuration.
// When lease period expires, renew the configuration.
tickDiff = TickGetDiff(TickGet(), lastTryTick);
if(tickDiff >= TICK_SECOND)
{
do
{
DHCPLeaseTime.Val--;
tickDiff -= TICK_SECOND;
if(DHCPLeaseTime.Val == 0u)
smDHCPState = SM_DHCP_INIT;
} while(tickDiff >= TICK_SECOND);
lastTryTick = TickGet() - tickDiff;
}
}
}
/*********************************************************************
DHCP PACKET FORMAT AS PER RFC 1541
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| op (1) | htype (1) | hlen (1) | hops (1) |
+---------------+---------------+---------------+---------------+
| xid (4) |
+-------------------------------+-------------------------------+
| secs (2) | flags (2) |
+-------------------------------+-------------------------------+
| ciaddr (4) |
+---------------------------------------------------------------+
| yiaddr (4) |
+---------------------------------------------------------------+
| siaddr (4) |
+---------------------------------------------------------------+
| giaddr (4) |
+---------------------------------------------------------------+
| |
| chaddr (16) |
| |
| |
+---------------------------------------------------------------+
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -