0
mirror of https://github.com/Indemsys/Frequency_Inverter.git synced 2026-05-11 14:24:43 +00:00
Files
2022-01-04 12:22:53 +02:00

1761 lines
56 KiB
C

/**HEADER********************************************************************
*
* Copyright (c) 2008 Freescale Semiconductor;
* All Rights Reserved
*
* Copyright (c) 2004-2008 Embedded Access Inc.;
* All Rights Reserved
*
* Copyright (c) 1989-2008 ARC International;
* All Rights Reserved
*
***************************************************************************
*
* THIS SOFTWARE IS PROVIDED BY FREESCALE "AS IS" AND ANY EXPRESSED OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL FREESCALE OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*
**************************************************************************
*
* $FileName: dhcpclnt.c$
* $Version : 3.8.12.0$
* $Date : Aug-6-2012$
*
* Comments:
*
* This file contains the implementation of the DHCP client
* for the TCP/IP protocol suite.
* For more information, refer to:
* RFC 2131 (DHCP)
* RPC 2132 (DHCP Options).
* Limitations: Although DHCP can be used over any medium, this
* implementation will work only over an Ethernet
* link layer.
* Implementation Note:
* The DHCP Client packet is set up in such a way that it may be re-used
* for any message the DCHP Client needs to send. Only DHCP_MAGIC is
* required for a DHCPDISCOVER message, the other options may or may not
* be present if the application did not specify them upon initialization.
* If the option is passed to the DHCP Client, it will be placed in the
* packet in the following order. The Server and Client IP pads will be
* used even if no other options are specified.
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | DHCP_MAGIC (4) |
* +---------------------------------------------------------------+
* | |
* // ClIENT ID (variable, 6 - 255) //
* | |
* +-----------------------------------------------+---------------+
* | OVERLOAD (3) |
* +-----------------------------------------------+--------------------------+
* | SERVER IP PAD (6) (zero, unless used) |
* +--------------------------------------------------------------------------+
* | CLIENT IP PAD (6) (zero, unless used) |
* +-------------------+------------------------------------------------------+
* | BUFFER END PAD (1)|
* +-------------------+-------------------------------------------+
* | |
* // PARAMETER LIST (variable, 3 - 255) //
* | |
* +---------------------------------------------------------------+
* | REQUESTED LEASE TIME (4) |
* +---------------------------------------------------------------+
* | |
* // CLASS ID (variable, 6 -255) //
* | |
* +---------------------------------------------------------------+
* | MAX MESSAGE SIZE (4) |
* +---------------------------------------------------------------+
* | |
* // SITE SPECIFIC OPTIONS (variable) //
* | |
* +--------------------+------------------------------------------+
* | BUFFER END PAD (1) |
* +--------------------------------------------------------------------------+
* | REQUESTED CLIENT IP PAD (6) |
* +--------------------+-----------------------------------------------------+
* | BUFFER END PAD (1) |
* +--------------------+
* Pointers are kept to modify the packet, depending on the current state.
* Please refer to RFC 2131, pg 38, to see what options are allowed in
* each situation. As an example, if sending a DHCPDECLINE message, only the
* Server IP is allowed. Therefore, the Server IP pad section is filled using
* the DHCPCLNT_modify_options() function and the first buffer end pad is
* filled with 0xFF. Only this section of the buffer will be sent to the
* Server. When a state change occurs, these pads will be zeroed out and
* the packet will be set up for the correct message type.
* There are three timed events which may or may not be active depending on
* the current state. If we are initializing for the first time, only the
* RESEND event will be active. Once we have a lease and are in a bound state,
* the RESEND event is cancelled and the RENEW and TERMINATE events are set.
* If we are in a RESENDING state, all three events will be set until we are
* re-bound. If we are in a REBINDING state, only the RESEND and TERMINATE
* events will be active. If we received a DHCPNAK message when renewing or
* rebinding, we will try to get a new lease starting from the INITIALIZE
* state. If the DHCP server does not wish to renew the current lease,
* then only the TERMINATE event will be set for the remainder of the lease. SMR
*
*END************************************************************************/
#include <string.h>
#include <rtcs.h>
#include "rtcs_prv.h"
#include "tcpip.h"
#include "ip_prv.h"
#include "dhcp_prv.h"
#include "dhcpuprv.h"
#include "arp.h"
extern UCB_STRUCT_PTR BOOT_port;
uint_32 DHCPCLNT_probe_address
(
_ip_address ipaddress,
pointer interface
);
/*FUNCTION*-------------------------------------------------------------
*
* Function Name : DHCPCLNT_init
* Returned Values : void
* Comments :
* Initialize the DHCP client. This function should only be called by the
* user's application
*
*END*-----------------------------------------------------------------*/
void DHCPCLNT_init
(
TCPIP_PARM_IF_DHCP _PTR_ parms
/* [IN/OUT] This is the DHCP Client structure from the application */
)
{ /* Body */
#if RTCSCFG_ENABLE_IP4
DHCP_CLNT_STRUCT _PTR_ dhcp_ptr;
uint_32 buff_len;
uint_32 error;
buff_len = parms->OPT_BUFF_SIZE + sizeof(DHCP_HEADER) + 23;
dhcp_ptr = RTCS_mem_alloc_zero(sizeof(DHCP_CLNT_STRUCT) + buff_len);
#if RTCSCFG_CHECK_MEMORY_ALLOCATION_ERRORS
if ( dhcp_ptr == NULL ) {
RTCSCMD_complete(parms, RTCSERR_OUT_OF_MEMORY);
return;
} /* Endif */
#endif
_mem_set_type(dhcp_ptr, MEM_TYPE_DHCP_CLNT_STRUCT);
RTCS_rand_seed(RTCS_time_get()); /* Just add more randomize to Transition ID.*/
error = DHCPCLNT_start(parms, dhcp_ptr);
#if RTCSCFG_CHECK_ERRORS
if ( error ) {
/* Self Destruct, can't do anything if the port isn't open */
_mem_free( dhcp_ptr );
RTCSCMD_complete(parms, error);
return;
} /* Endif */
#endif
DHCPCLNT_open(dhcp_ptr);
RTCSCMD_complete(parms, error);
#else
RTCSCMD_complete(parms, RTCSERR_IP_IS_DISABLED);
return;
#endif /* RTCSCFG_ENABLE_IP4 */
} /* Endbody */
/*FUNCTION*-------------------------------------------------------------
*
* Function Name : DHCPCLNT_reinit
* Returned Values : void
* Comments :
* Initialize the DHCP client without the initial DHCP negotiation.
*
*END*-----------------------------------------------------------------*/
void DHCPCLNT_reinit
(
TCPIP_PARM_IF_DHCP _PTR_ parms
/* [IN/OUT] This is the DHCP Client structure from the application */
)
{ /* Body */
#if RTCSCFG_ENABLE_IP4
DHCP_CLNT_STRUCT _PTR_ dhcp_ptr;
uint_32 buff_len;
uint_32 error;
buff_len = parms->OPT_BUFF_SIZE + sizeof(DHCP_HEADER) + 23;
dhcp_ptr = RTCS_mem_alloc_zero(sizeof(DHCP_CLNT_STRUCT) + buff_len);
#if RTCSCFG_CHECK_MEMORY_ALLOCATION_ERRORS
if ( dhcp_ptr == NULL ) {
RTCSCMD_complete(parms, RTCSERR_OUT_OF_MEMORY);
return;
} /* Endif */
#endif
_mem_set_type(dhcp_ptr, MEM_TYPE_DHCP_CLNT_STRUCT);
error = DHCPCLNT_start(parms, dhcp_ptr);
#if RTCSCFG_CHECK_ERRORS
if ( error ) {
/* Self Destruct, can't do anything if the port isn't open */
_mem_free( dhcp_ptr );
RTCSCMD_complete(parms, error);
return;
} /* Endif */
#endif
dhcp_ptr->DATA.ServerIp = parms->SERVER_IP_ADDR;
dhcp_ptr->DATA.ClientIPaddress = parms->CLNT_IP_ADDR;
dhcp_ptr->DATA.LEASE = parms->LEASE;
dhcp_ptr->DATA.Netmask = parms->CLNT_IP_MASK;
dhcp_ptr->PARMS_BIND.address = parms->CLNT_IP_ADDR;
dhcp_ptr->PARMS_BIND.locmask = INADDR_BROADCAST;
dhcp_ptr->PARMS_BIND.netmask = parms->CLNT_IP_MASK;
dhcp_ptr->PARMS_BIND.probe = FALSE;
RTCSCMD_internal(dhcp_ptr->PARMS_BIND, IPIF_bind);
dhcp_ptr->BOUND = TRUE;
dhcp_ptr->STATE = DHCP_BOUND;
dhcp_ptr->NEW_RENEW_TIME = 0;
dhcp_ptr->NEW_REBIND_TIME = 0;
DHCPCLNT_set_timed_events(dhcp_ptr);
TCPIP_Event_add(&dhcp_ptr->RENEW);
TCPIP_Event_add(&dhcp_ptr->TERMINATE);
RTCSCMD_complete(parms, RTCS_OK);
#else
RTCSCMD_complete(parms, RTCSERR_IP_IS_DISABLED);
return;
#endif /* RTCSCFG_ENABLE_IP4 */
} /* Endbody */
/*FUNCTION*-------------------------------------------------------------
*
* Function Name : DHCPCLNT_start
* Returned Values : error code
* Comments :
* Initialize the DHCP client state structure.
*
*END*-----------------------------------------------------------------*/
#if RTCSCFG_ENABLE_IP4
uint_32 DHCPCLNT_start
(
TCPIP_PARM_IF_DHCP _PTR_ parms,
/* [IN/OUT] This is the DHCP Client structure from the application */
DHCP_CLNT_STRUCT _PTR_ dhcp_ptr
/* [IN/OUT] This is the DHCP Client control structure */
)
{ /* Body */
uint_32 buff_len;
/*
** 23: 4 = Magic Cookie, 3 = Msg Type, 6 = ServerID, 6 = Requested IP,
** 4 = Various Ends
*/
buff_len = parms->OPT_BUFF_SIZE + sizeof(DHCP_HEADER) + 23;
if ( parms->FLAGS & DHCP_SEND_INFORM_MESSAGE ) {
dhcp_ptr->STATE = DHCP_INFORMED;
dhcp_ptr->DATA.ClientIPaddress = parms->CLNT_IP_ADDR;
if ( parms->SERVER_IP_ADDR == INADDR_ANY ) {
dhcp_ptr->DATA.ServerIp = INADDR_BROADCAST;
} else {
dhcp_ptr->DATA.ServerIp = parms->SERVER_IP_ADDR;
} /* Endif */
dhcp_ptr->BOUND = TRUE;
} else {
dhcp_ptr->STATE = DHCP_INITIALIZE;
}/* Endif */
dhcp_ptr->HANDLE = (IP_IF _PTR_)parms->HANDLE;
dhcp_ptr->PARMS_BIND.ihandle = parms->HANDLE;
dhcp_ptr->HANDLE->BOOTFN = NULL;
dhcp_ptr->HANDLE->BOOT = dhcp_ptr;
dhcp_ptr->CHOICE_FUNC = parms->OPTIONS->CHOICE_FUNC;
dhcp_ptr->BIND_FUNC = parms->OPTIONS->BIND_FUNC;
dhcp_ptr->UNBIND_FUNC = parms->OPTIONS->UNBIND_FUNC;
dhcp_ptr->FAILURE_FUNC = parms->OPTIONS->FAILURE_FUNC;
dhcp_ptr->NAK_FUNC = parms->OPTIONS->NAK_FUNC;
dhcp_ptr->FLAGS = parms->FLAGS;
dhcp_ptr->PACKET = (uchar _PTR_)(dhcp_ptr + 1);
dhcp_ptr->TOTAL_PACKET_SIZE = buff_len;
dhcp_ptr->RESEND.EVENT = DHCPCLNT_send;
dhcp_ptr->RESEND.PRIVATE = dhcp_ptr;
dhcp_ptr->RENEW.EVENT = DHCPCLNT_renew_lease;
dhcp_ptr->RENEW.PRIVATE = dhcp_ptr;
dhcp_ptr->TERMINATE.EVENT = DHCPCLNT_terminate_lease;
dhcp_ptr->TERMINATE.PRIVATE = dhcp_ptr;
dhcp_ptr->INIT_TIMEOUT = parms->TIMEOUT * 1000;
DHCPCLNT_fill_header( dhcp_ptr );
DHCPCLNT_fill_options( dhcp_ptr, parms );
return BOOT_open(&DHCPCLNT_service);
} /* Endbody */
#endif /* RTCSCFG_ENABLE_IP4 */
/*FUNCTION*-------------------------------------------------------------
*
* Function Name : DHCPCLNT_fill_header
* Returned Values : void
* Comments :
* Sets up the DHCP Client header structure.
*
*END*-----------------------------------------------------------------*/
#if RTCSCFG_ENABLE_IP4
static void DHCPCLNT_fill_header
(
DHCP_CLNT_STRUCT _PTR_ dhcp_ptr
/* [IN/OUT] This is the DHCP Client control structure */
)
{ /* Body */
DHCP_HEADER _PTR_ header_ptr;
uint_32 xid;
header_ptr = (DHCP_HEADER _PTR_)dhcp_ptr->PACKET;
/* Build the DHCP HEADER */
htonc(header_ptr->OP, DHCPOP_BOOTREQUEST);
htonc(header_ptr->HTYPE, dhcp_ptr->HANDLE->DEV_TYPE);
htonc(header_ptr->HLEN, dhcp_ptr->HANDLE->DEV_ADDRLEN);
htonc(header_ptr->HOPS, 0);
/* Pick a random transaction ID */
xid = RTCS_rand();
htonl(header_ptr->XID, xid);
/* htons(header_ptr->FLAGS, DHCPFLAG_BROADCAST); */
htons(header_ptr->FLAGS, _DHCP_broadcast ? DHCPFLAG_BROADCAST : 0);
if ( dhcp_ptr->STATE == DHCP_INFORMED ) {
htonl(header_ptr->CIADDR, dhcp_ptr->DATA.ClientIPaddress);
} else {
htonl(header_ptr->CIADDR, INADDR_ANY);
} /* Endif */
htonl(header_ptr->YIADDR, INADDR_ANY);
htonl(header_ptr->SIADDR, INADDR_ANY);
htonl(header_ptr->GIADDR, INADDR_ANY);
_mem_zero(header_ptr->CHADDR, sizeof(header_ptr->CHADDR));
_mem_copy(dhcp_ptr->HANDLE->DEV_ADDR, header_ptr->CHADDR, dhcp_ptr->HANDLE->DEV_ADDRLEN);
} /* Endbody */
#endif /* RTCSCFG_ENABLE_IP4 */
/*FUNCTION*-------------------------------------------------------------
*
* Function Name : DHCPCLNT_fill_options
* Returned Values : void
* Comments :
* Checks and fills in the DHCP Client options in the buffer. This
* function should only be called once upon initialization. The DHCP_FILL
* macro is defined in DHCP_PRV.H.
*
*END*-----------------------------------------------------------------*/
#if RTCSCFG_ENABLE_IP4
static void DHCPCLNT_fill_options
(
DHCP_CLNT_STRUCT _PTR_ dhcp_ptr,
/* [IN/OUT] This is the DHCP Client control structure */
TCPIP_PARM_IF_DHCP _PTR_ parms
/* [IN/OUT] This is the DHCP Client structure from the application */
)
{ /* Body */
uchar _PTR_ outp;
uchar _PTR_ temp_ptr;
uchar _PTR_ opt_ptr;
uint_32 len;
uint_32 i;
uint_32 new_total_length;
uchar addr_buffer[6];
uchar _PTR_ buffer_end = parms->OPT_BUFF
+ parms->OPT_BUFF_SIZE - 1;
outp = dhcp_ptr->PACKET + sizeof(DHCP_HEADER);
htonl(outp, DHCP_MAGIC); outp += 4;
htonc(outp, DHCPOPT_MSGTYPE); outp++;
htonc(outp, 1); outp++;
dhcp_ptr->MSGTYPE_PTR = outp;
if ( dhcp_ptr->STATE == DHCP_INFORMED ) {
htonc(outp, DHCPTYPE_DHCPINFORM);
} else {
htonc(outp, DHCPTYPE_DHCPDISCOVER);
} /* Endif */
outp++;
/*
** Only the following options are allowed for a DHCP Client message.
** Client ID, Use 'file'/'sname' fields, Parameter request list,
** IP address lease time, Class Id, Max message size, Requested IP addr.
** DO NOT change the order of insertion into the buffer, as other
** functions will depend on the order given here.
** See pg. 33 of RFC 1541 for more details.
*/
/* Minimum size allowed is 2 (added 2 for option and length fields) */
DHCP_FILL(CLIENTID, (len >= 4))
/*
** Allows 'file'/'sname' fields to be used in replies from DHCP server
** Since we also use these fields for BOOTP, we do not allow this
** functionality at this time. However, if we are to offer it in the future,
** other functions depend on us filling in the overload option here.
** Leave the commented code here for potential future use. SMR
*/
/* Minimum size allowed is 1 (added 2 for option and length fields) */
/* DHCP_FILL(OVERLOAD, (len == 3)) */
dhcp_ptr->SERVERID_PTR = outp;
/* This is to pad for insertion of ServerID and Requested IP later */
outp += 13;
/* Minimum size allowed is 1 (added 2 for option and length fields) */
DHCP_FILL(PARAMLIST, (len >= 3))
if ( dhcp_ptr->STATE != DHCP_INFORMED ) {
/* Size must be 4 (added 2 for option and length fields) */
DHCP_FILL(LEASE, (len == 6))
}/* Endif */
/* Minimum size allowed is 1 (added 2 for option and length fields) */
DHCP_FILL(CLASSID, (len >= 3))
opt_ptr = DHCP_find_option(parms->OPT_BUFF,
parms->OPT_BUFF_SIZE,
DHCPOPT_MSGSIZE);
if (opt_ptr) {
/* 576 octets is an imposed minimum, RFC 2131 */
if ( ntohs(opt_ptr + 2) < DHCP_MIN_MESSAGE_SIZE ) {
htonc(outp, DHCPOPT_MSGSIZE); outp++;
htonc(outp, 2); outp++;
htons(outp, DHCP_MIN_MESSAGE_SIZE); outp += 2;
} else {
_mem_copy(opt_ptr, outp, 4);
outp += 4;
} /* Endif */
for (i = 0; i < 4; i++) {
htonc(opt_ptr, 0);
opt_ptr++;
} /* Endfor */
} /* Endif */
/*
** Have to parse out the ADDRESS option, as it goes after the site specific
** options in the packet.
*/
opt_ptr = DHCP_find_option(parms->OPT_BUFF,
parms->OPT_BUFF_SIZE,
DHCPOPT_ADDRESS);
if ( opt_ptr ) {
for (i = 0; i < 6; i++) {
addr_buffer[i] = ntohc(opt_ptr);
htonc(opt_ptr, 0);
opt_ptr++;
} /* Endfor */
}/* Endif */
/*
** Remove all the remaining options and place in the site specific section.
** Break out of the while loop once all the options are parsed.
*/
temp_ptr = parms->OPT_BUFF;
while ( temp_ptr ) {
temp_ptr = parms->OPT_BUFF;
while ((ntohc(temp_ptr) == 0) && (temp_ptr < buffer_end)) {
temp_ptr++;
} /* Endwhile */
if ( ntohc(temp_ptr) != 0 ) {
new_total_length = buffer_end - temp_ptr + 1;
len = ntohc(temp_ptr + 1) + 2;
if ( len <= new_total_length ) {
_mem_copy(temp_ptr, outp, len);
outp += len;
} else {
len = new_total_length;
}/* Endif */
for ( i = 0; i < len; i++) {
htonc(temp_ptr, 0);
temp_ptr++;
} /* Endfor */
} else {
temp_ptr = NULL;
}/* Endif */
} /* Endwhile */
dhcp_ptr->REQUEST_OPT_PTR = outp;
/* This pad is for DHCP REQUEST messages so we won't overwrite the addr */
outp++;
if (opt_ptr && (dhcp_ptr->STATE != DHCP_INFORMED)) {
for ( i = 0; i < 6; i++ ) {
htonc(outp, addr_buffer[i]);
outp++;
} /* Endfor */
} /* Endif */
/* Add the DHCPEND flag last */
htonc(outp, DHCPOPT_END);
outp++;
dhcp_ptr->CURRENT_PACKET_SIZE = outp - dhcp_ptr->PACKET;
} /* Endbody */
#endif /* RTCSCFG_ENABLE_IP4 */
/*FUNCTION*-------------------------------------------------------------
*
* Function Name : DHCPCLNT_open
* Returned Values : void
* Comments : This function is used to open the DHCP Client Port
* and set up the RESEND event.
*
*END*-----------------------------------------------------------------*/
#if RTCSCFG_ENABLE_IP4
static void DHCPCLNT_open
(
DHCP_CLNT_STRUCT _PTR_ dhcp_ptr
/* [IN/OUT] This is the DHCP Client control structure */
)
{ /* Body */
DHCP_HEADER _PTR_ header_ptr = (DHCP_HEADER _PTR_)dhcp_ptr->PACKET;
htons(header_ptr->SECS, 0);
/* Set initial timeout */
dhcp_ptr->RETRY_TIMEOUT = DHCP_TIMEOUT_MIN;
dhcp_ptr->SECS = 0;
/* Start the retransmission timer to start sending immediately */
dhcp_ptr->RESEND.TIME = 0;
TCPIP_Event_add( &dhcp_ptr->RESEND );
if (dhcp_ptr->INIT_TIMEOUT) {
/* Set a cancellation event in case of failure to bind. */
dhcp_ptr->TERMINATE.EVENT = DHCPCLNT_bind_attempt_timeout;
dhcp_ptr->TERMINATE.TIME = dhcp_ptr->INIT_TIMEOUT;
TCPIP_Event_add(&dhcp_ptr->TERMINATE);
} /* Endif */
} /* Endbody */
#endif /* RTCSCFG_ENABLE_IP4 */
/*FUNCTION*-------------------------------------------------------------
*
* Function Name : DHCPCLNT_modify_options
* Returned Values : void
* Comments :
* Modifies the DHCP Client buffer for packet send, depending on the
* current context. Allowed options change depending on the packet type.
* NOTE: State MUST be checked BEFORE calling, this function is not used
* in an initial or terminated state
*
*END*-----------------------------------------------------------------*/
#if RTCSCFG_ENABLE_IP4
static void DHCPCLNT_modify_options
(
DHCP_CLNT_STRUCT _PTR_ dhcp_ptr
/* [IN/OUT] This is the DHCP Client control structure */
)
{ /* Body */
DHCP_HEADER _PTR_ header_ptr;
uchar _PTR_ outp;
uint_32 i;
header_ptr = (DHCP_HEADER _PTR_)dhcp_ptr->PACKET;
outp = dhcp_ptr->SERVERID_PTR;
for ( i = 0 ; i < 13 ; i++ ) {
htonc(outp, 0); outp++;
} /* Endfor */
outp -= 13;
htonc(dhcp_ptr->REQUEST_OPT_PTR, 0);
if ( dhcp_ptr->BOUND && dhcp_ptr->STATE != DHCP_REQUESTING ) {
htonl(header_ptr->CIADDR, dhcp_ptr->DATA.ClientIPaddress);
} else {
htonl(header_ptr->CIADDR, INADDR_ANY);
}/* Endif */
if ( dhcp_ptr->STATE == DHCP_INITIALIZE ) {
htonc(dhcp_ptr->MSGTYPE_PTR, DHCPTYPE_DHCPDISCOVER);
dhcp_ptr->CURRENT_PACKET_SIZE = dhcp_ptr->TOTAL_PACKET_SIZE;
} else {
htonc(dhcp_ptr->MSGTYPE_PTR, DHCPTYPE_DHCPREQUEST);
if ( dhcp_ptr->STATE == DHCP_REQUESTING ||
dhcp_ptr->STATE == DHCP_DECLINING ||
dhcp_ptr->STATE == DHCP_RELEASING ) {
htonc(outp, DHCPOPT_SERVERID); outp++;
htonc(outp, 4); outp++;
if ( dhcp_ptr->STATE == DHCP_RELEASING ) {
htonc(dhcp_ptr->MSGTYPE_PTR, DHCPTYPE_DHCPRELEASE);
htonl(outp, dhcp_ptr->DATA.ServerIp); outp += 4;
} else {
htonl(outp, dhcp_ptr->NEW_DATA.ServerIp); outp += 4;
htonc(outp, DHCPOPT_ADDRESS); outp++;
htonc(outp, 4); outp++;
htonl(outp, dhcp_ptr->NEW_DATA.ClientIPaddress); outp += 4;
if (dhcp_ptr->STATE == DHCP_DECLINING ) {
htonl(header_ptr->CIADDR, INADDR_ANY);
htonc(dhcp_ptr->MSGTYPE_PTR, DHCPTYPE_DHCPDECLINE);
} else {
outp = dhcp_ptr->REQUEST_OPT_PTR;
}/* Endif */
} /* Endif */
} else {
/* We're Renewing or Rebinding */
outp = dhcp_ptr->REQUEST_OPT_PTR;
}/* Endif */
htonc(outp, DHCPOPT_END); outp++;
dhcp_ptr->CURRENT_PACKET_SIZE = outp - dhcp_ptr->PACKET;
}/* Endif */
} /* Endbody */
#endif /* RTCSCFG_ENABLE_IP4 */
/*FUNCTION*-------------------------------------------------------------
*
* Function Name : DHCPCLNT_send
* Returned Value : boolean
* Comments :
* Called by the Timer. Send a DHCP packet.
*
*END*-----------------------------------------------------------------*/
#if RTCSCFG_ENABLE_IP4
boolean DHCPCLNT_send
(
TCPIP_EVENT_PTR event
/* [IN/OUT] the resend event */
)
{ /* Body */
DHCP_CLNT_STRUCT _PTR_ dhcp_ptr = event->PRIVATE;
DHCP_HEADER _PTR_ header_ptr;
RTCSPCB_PTR pcb_ptr;
_ip_address destination_address;
uint_32 retry_time;
if ( dhcp_ptr->S_EVENT_TIME_LEFT ) {
DHCPCLNT_TIME_OVERFLOW_CHECK(retry_time, dhcp_ptr->S_EVENT_TIME_LEFT)
dhcp_ptr->RESEND.TIME = retry_time;
return( TRUE );
}/* Endif */
switch ( dhcp_ptr->STATE ) {
case DHCP_REQUESTING:
case DHCP_INFORMED:
/* Must retry 4 times before starting over, total is under 60 secs */
if ( dhcp_ptr->RETRY_TIMEOUT != DHCP_TIMEOUT_MAX ) {
/*Set the event to trigger for the next retransmission (+/- 1 sec)*/
retry_time = dhcp_ptr->RETRY_TIMEOUT +
(RTCS_rand() & 0x7FF) - 0x400;
if ( dhcp_ptr->RENEW_TIME &&
dhcp_ptr->RENEW_TIME < dhcp_ptr->REBIND_TIME )
{
dhcp_ptr->RENEW_TIME += (retry_time / 1000);
} else {
/* We were rebinding, increment rebind time */
dhcp_ptr->REBIND_TIME += (retry_time / 1000);
}/* Endif */
dhcp_ptr->RESEND.TIME = retry_time;
/* Double the timeout */
dhcp_ptr->RETRY_TIMEOUT <<= 1;
if (dhcp_ptr->RETRY_TIMEOUT > DHCP_TIMEOUT_MAX) {
dhcp_ptr->RETRY_TIMEOUT = DHCP_TIMEOUT_MAX;
} /* Endif */
dhcp_ptr->STATS.ST_TX_REQUEST++;
break;
} else {
if ( dhcp_ptr->STATE == DHCP_INFORMED ) {
/*
** There was no response to our request for parameters, inform
** the application to use defaults and self destruct
*/
if ( dhcp_ptr->BIND_FUNC != NULL ) {
dhcp_ptr->BIND_FUNC(NULL, 0,
(_rtcs_if_handle)dhcp_ptr->HANDLE);
} /* Endif */
BOOT_close();
dhcp_ptr->HANDLE->BOOT = NULL;
/* Free the DHCP Structure */
_mem_free(dhcp_ptr);
return( FALSE );
} else {
/* We were initializing from an unbound state before */
dhcp_ptr->STATE = DHCP_INITIALIZE;
dhcp_ptr->RETRY_TIMEOUT = DHCP_TIMEOUT_MIN;
DHCPCLNT_modify_options( dhcp_ptr );
} /* Endif */
}/* Endif */
case DHCP_INITIALIZE:
/* Set the event to trigger for the next retransmission (+/- 1 sec) */
retry_time = dhcp_ptr->RETRY_TIMEOUT + (RTCS_rand() & 0x7FF) - 0x400;
dhcp_ptr->RESEND.TIME = retry_time;
/* Double the timeout */
dhcp_ptr->RETRY_TIMEOUT <<= 1;
if (dhcp_ptr->RETRY_TIMEOUT > DHCP_TIMEOUT_MAX) {
dhcp_ptr->RETRY_TIMEOUT = DHCP_TIMEOUT_MAX;
} /* Endif */
dhcp_ptr->STATS.ST_TX_DISCOVER++;
break;
case DHCP_RENEWING:
retry_time = (dhcp_ptr->REBIND_TIME - dhcp_ptr->RENEW_TIME)/2;
if ( retry_time < 60 ) {
/* A 60 second minimum is imposed */
retry_time = 60;
}/* Endif */
dhcp_ptr->RENEW_TIME += retry_time;
dhcp_ptr->S_EVENT_TIME_LEFT = retry_time;
DHCPCLNT_TIME_OVERFLOW_CHECK(retry_time, dhcp_ptr->S_EVENT_TIME_LEFT)
dhcp_ptr->RESEND.TIME = retry_time;
dhcp_ptr->STATS.ST_TX_REQUEST++;
break;
case DHCP_REBINDING:
retry_time = (dhcp_ptr->DATA.LEASE - dhcp_ptr->REBIND_TIME)/2;
if ( retry_time < 60 ) {
/* A 60 second minimum is imposed */
retry_time = 60;
}/* Endif */
if ((dhcp_ptr->REBIND_TIME + retry_time) < dhcp_ptr->DATA.LEASE) {
dhcp_ptr->REBIND_TIME += retry_time;
}/* Endif */
dhcp_ptr->S_EVENT_TIME_LEFT = retry_time;
DHCPCLNT_TIME_OVERFLOW_CHECK(retry_time, dhcp_ptr->S_EVENT_TIME_LEFT)
dhcp_ptr->RESEND.TIME = retry_time;
dhcp_ptr->STATS.ST_TX_REQUEST++;
} /* Endswitch */
/* Allocate a PCB */
pcb_ptr = RTCSPCB_alloc_send();
if (pcb_ptr == NULL) {
return TRUE;
} /* Endif */
//RTCSLOG_PCB_ALLOC(pcb_ptr);
/* The only field that changes in DHCP packets is 'secs' */
header_ptr = (DHCP_HEADER _PTR_)dhcp_ptr->PACKET;
htons(header_ptr->SECS, dhcp_ptr->SECS);
dhcp_ptr->SECS += (retry_time / 1000);
/* Put the DHCP packet in the PCB */
RTCSLOG_PCB_WRITE(pcb_ptr, RTCS_LOGCTRL_PORT(IPPORT_BOOTPC), 0);
RTCSPCB_append_fragment(pcb_ptr, dhcp_ptr->CURRENT_PACKET_SIZE, dhcp_ptr->PACKET);
if ( dhcp_ptr->BOUND ) {
/* We already have an IP address available, we're renewing or rebinding */
if ( dhcp_ptr->STATE == DHCP_RENEWING ||
dhcp_ptr->STATE == DHCP_INFORMED )
{
/* Unicast the message to the server */
destination_address = dhcp_ptr->DATA.ServerIp;
} else {
/* Broadcast the request */
destination_address = INADDR_BROADCAST;
} /* Endif */
UDP_send_internal(BOOT_port,
dhcp_ptr->DATA.ClientIPaddress,
destination_address,
DHCP_SERVER_PORT,
pcb_ptr,
0);
} else {
/* Send the datagram */
BOOT_send(pcb_ptr, dhcp_ptr->HANDLE);
} /* Endif */
return TRUE;
} /* Endbody */
#endif /* RTCSCFG_ENABLE_IP4 */
/*FUNCTION*-------------------------------------------------------------
*
* Function Name : DHCPCLNT_send_one_shot
* Returned Values : void
* Comments : Sends a single DHCP packet without resend.
*
*END*-----------------------------------------------------------------*/
#if RTCSCFG_ENABLE_IP4
static void DHCPCLNT_send_one_shot
(
DHCP_CLNT_STRUCT _PTR_ dhcp_ptr
/* [IN/OUT] This is the DHCP Client control structure */
)
{ /* Body */
RTCSPCB_PTR pcb_ptr;
/* Allocate a PCB */
pcb_ptr = RTCSPCB_alloc_send();
if (pcb_ptr == NULL) {
return;
} /* Endif */
//RTCSLOG_PCB_ALLOC(pcb_ptr);
/* Put the DHCP packet in the PCB */
RTCSLOG_PCB_WRITE(pcb_ptr, RTCS_LOGCTRL_PORT(IPPORT_BOOTPC), 0);
RTCSPCB_append_fragment(pcb_ptr, dhcp_ptr->CURRENT_PACKET_SIZE, dhcp_ptr->PACKET);
if ( dhcp_ptr->BOUND ) {
/* We already have an IP address available */
UDP_send_internal(BOOT_port,
dhcp_ptr->NEW_DATA.ClientIPaddress,
dhcp_ptr->NEW_DATA.ServerIp,
DHCP_SERVER_PORT,
pcb_ptr,
0);
} else {
/* Send the datagram */
BOOT_send(pcb_ptr, dhcp_ptr->HANDLE);
} /* Endif */
} /* Endbody */
#endif /* RTCSCFG_ENABLE_IP4 */
/*FUNCTION*-------------------------------------------------------------
*
* Function Name : DHCPCLNT_rebind_lease
* Returned Values : boolean
* Comments :
* Attempts to renew the current lease unicasting to the server.
*
*END*-----------------------------------------------------------------*/
#if RTCSCFG_ENABLE_IP4
static boolean DHCPCLNT_rebind_lease
(
TCPIP_EVENT_PTR event
/* [IN/OUT] the renew event */
)
{ /* Body */
DHCP_CLNT_STRUCT _PTR_ dhcp_ptr = event->PRIVATE;
uint_32 rebind_time;
boolean reset_event = FALSE;
if ( dhcp_ptr->R_EVENTS_TIME_LEFT ) {
DHCPCLNT_TIME_OVERFLOW_CHECK(rebind_time, dhcp_ptr->R_EVENTS_TIME_LEFT)
dhcp_ptr->RENEW.TIME = rebind_time;
reset_event = TRUE;
} else {
TCPIP_Event_cancel(&dhcp_ptr->RESEND);
/*
** Need to make sure that the renew time is now greater than the rebind
** for use by DHCPCLNT_send to know the previous state if requests fail.
*/
dhcp_ptr->RENEW_TIME = dhcp_ptr->DATA.LEASE;
dhcp_ptr->STATE = DHCP_REBINDING;
DHCPCLNT_modify_options( dhcp_ptr );
DHCPCLNT_open( dhcp_ptr );
} /* Endif */
return( reset_event );
} /* Endbody */
#endif /* RTCSCFG_ENABLE_IP4 */
/*FUNCTION*-------------------------------------------------------------
*
* Function Name : DHCPCLNT_renew_lease
* Returned Values : boolean
* Comments :
* Attempts to renew the current lease unicasting to the server.
*
*END*-----------------------------------------------------------------*/
#if RTCSCFG_ENABLE_IP4
static boolean DHCPCLNT_renew_lease
(
TCPIP_EVENT_PTR event
/* [IN/OUT] the renew event */
)
{ /* Body */
DHCP_CLNT_STRUCT _PTR_ dhcp_ptr = event->PRIVATE;
uint_32 renew_time;
if (!dhcp_ptr->R_EVENTS_TIME_LEFT ) {
dhcp_ptr->STATE = DHCP_RENEWING;
DHCPCLNT_modify_options( dhcp_ptr );
dhcp_ptr->INIT_TIMEOUT = 0;
DHCPCLNT_open( dhcp_ptr );
/* Set up for DHCP Rebinding */
dhcp_ptr->R_EVENTS_TIME_LEFT = dhcp_ptr->REBIND_TIME;
dhcp_ptr->RENEW.EVENT = DHCPCLNT_rebind_lease;
} /* Endif */
DHCPCLNT_TIME_OVERFLOW_CHECK(renew_time, dhcp_ptr->R_EVENTS_TIME_LEFT);
dhcp_ptr->RENEW_TIME = 0;
dhcp_ptr->RENEW.TIME = renew_time;
return( TRUE );
} /* Endbody */
#endif /* RTCSCFG_ENABLE_IP4 */
/*FUNCTION*-------------------------------------------------------------
*
* Function Name : DHCPCLNT_terminate_lease
* Returned Values : boolean
* Comments :
* If a lease expires, or a DHCPNAK message is received, this function
* will broadcast another DHCPDISCOVER message.
*
*END*-----------------------------------------------------------------*/
#if RTCSCFG_ENABLE_IP4
static boolean DHCPCLNT_terminate_lease
(
TCPIP_EVENT_PTR event
/* [IN/OUT] the termination event */
)
{ /* Body */
DHCP_CLNT_STRUCT _PTR_ dhcp_ptr = event->PRIVATE;
uint_32 terminate_time;
boolean retry = FALSE;
boolean reset_event = FALSE;
if ( dhcp_ptr->TERMINATE_TIME ) {
DHCPCLNT_TIME_OVERFLOW_CHECK(terminate_time, dhcp_ptr->TERMINATE_TIME)
dhcp_ptr->TERMINATE.TIME = terminate_time;
reset_event = TRUE;
} else {
if (dhcp_ptr->BOUND) {
RTCSCMD_internal( dhcp_ptr->PARMS_BIND, IPIF_unbind );
if ( dhcp_ptr->UNBIND_FUNC != NULL ) {
retry = dhcp_ptr->UNBIND_FUNC((_rtcs_if_handle)dhcp_ptr->HANDLE);
} /* Endif */
} else {
if ( dhcp_ptr->FAILURE_FUNC != NULL ) {
dhcp_ptr->FAILURE_FUNC((_rtcs_if_handle)dhcp_ptr->HANDLE);
} /* Endif */
} /* Endif */
TCPIP_Event_cancel(&dhcp_ptr->RENEW);
TCPIP_Event_cancel(&dhcp_ptr->RESEND);
if ( retry ) {
dhcp_ptr->REBIND_TIME = 0;
dhcp_ptr->BOUND = FALSE;
dhcp_ptr->STATE = DHCP_INITIALIZE;
DHCPCLNT_modify_options( dhcp_ptr );
DHCPCLNT_open( dhcp_ptr );
} else {
BOOT_close();
dhcp_ptr->HANDLE->BOOT = NULL;
/* Free the DHCP Structure */
_mem_free(dhcp_ptr);
}/* Endif */
} /* Endif */
return( reset_event );
} /* Endbody */
#endif /* RTCSCFG_ENABLE_IP4 */
/*FUNCTION*-------------------------------------------------------------
*
* Function Name : DHCPCLNT_bind_attempt_timeout
* Returned Values : boolean
* Comments :
* This function will timeout a lease attempt if the binding is not
* successful.
*
*END*-----------------------------------------------------------------*/
#if RTCSCFG_ENABLE_IP4
static boolean DHCPCLNT_bind_attempt_timeout
(
TCPIP_EVENT_PTR event
/* [IN/OUT] the termination event */
)
{ /* Body */
DHCP_CLNT_STRUCT _PTR_ dhcp_ptr = event->PRIVATE;
boolean retry = FALSE;
if ( dhcp_ptr->FAILURE_FUNC != NULL ) {
retry = dhcp_ptr->FAILURE_FUNC((_rtcs_if_handle)dhcp_ptr->HANDLE);
} /* Endif */
TCPIP_Event_cancel(&dhcp_ptr->RESEND);
if ( retry ) {
dhcp_ptr->REBIND_TIME = 0;
dhcp_ptr->BOUND = FALSE;
dhcp_ptr->STATE = DHCP_INITIALIZE;
DHCPCLNT_modify_options( dhcp_ptr );
DHCPCLNT_open( dhcp_ptr );
} else {
BOOT_close();
dhcp_ptr->HANDLE->BOOT = NULL;
/* Free the DHCP Structure */
_mem_free(dhcp_ptr);
}/* Endif */
return FALSE;
} /* Endbody */
#endif /* RTCSCFG_ENABLE_IP4 */
/*FUNCTION*-------------------------------------------------------------
*
* Function Name : DHCPCLNT_decline
* Returned Values : void
* Comments :
* Declines a lease, sends a message to the DCHP Server.
* Add error code message later.
*
*END*-----------------------------------------------------------------*/
#if RTCSCFG_ENABLE_IP4
static void DHCPCLNT_decline
(
DHCP_CLNT_STRUCT _PTR_ dhcp_ptr,
/* [IN/OUT] This is the DHCP Client control structure */
uint_32 error
/* [IN] The reason for rejection */
)
{ /* Body */
uint_32 old_state = dhcp_ptr->STATE;
dhcp_ptr->STATE = DHCP_DECLINING;
DHCPCLNT_modify_options( dhcp_ptr );
DHCPCLNT_send_one_shot( dhcp_ptr );
dhcp_ptr->STATS.ST_TX_DECLINE++;
dhcp_ptr->STATE = old_state;
DHCPCLNT_modify_options( dhcp_ptr );
} /* Endbody */
#endif /* RTCSCFG_ENABLE_IP4 */
/*FUNCTION*-------------------------------------------------------------
*
* Function Name : DHCPCLNT_release_internal
* Returned Values : void
* Comments :
*
*END*-----------------------------------------------------------------*/
#if RTCSCFG_ENABLE_IP4
void DHCPCLNT_release_internal
(
TCPIP_PARM_IF_DHCP_RELEASE _PTR_ parms
/* [IN/OUT] This is the DHCP Client structure from the application */
)
{ /* Body */
IP_IF_PTR if_ptr = (IP_IF_PTR)parms->HANDLE;
DHCP_CLNT_STRUCT _PTR_ dhcp_ptr;
if ( if_ptr->BOOT != NULL ) {
dhcp_ptr = (DHCP_CLNT_STRUCT _PTR_)if_ptr->BOOT;
TCPIP_Event_cancel(&dhcp_ptr->RENEW);
TCPIP_Event_cancel(&dhcp_ptr->RESEND);
TCPIP_Event_cancel(&dhcp_ptr->TERMINATE);
dhcp_ptr->STATE = DHCP_RELEASING;
DHCPCLNT_modify_options( dhcp_ptr );
DHCPCLNT_send_one_shot( dhcp_ptr );
if ( dhcp_ptr->BOUND ) {
RTCSCMD_internal( dhcp_ptr->PARMS_BIND, IPIF_unbind );
}/* Endif */
BOOT_close();
/* Free the DHCP Structure */
_mem_free(dhcp_ptr);
if_ptr->BOOT = NULL;
}/* Endif */
RTCSCMD_complete(parms, RTCS_OK);
} /* Endbody */
#endif /* RTCSCFG_ENABLE_IP4 */
/*FUNCTION*-------------------------------------------------------------
*
* Function Name : DHCPCLNT_parse_offer
* Returned Values : void
* Comments : We only look for the options that affect us directly.
* It is assumed that the application will parse any
* site specific options.
*
*END*-----------------------------------------------------------------*/
#if RTCSCFG_ENABLE_IP4
static void DHCPCLNT_parse_offer
(
DHCP_CLNT_STRUCT _PTR_ dhcp_ptr,
/* [IN/OUT] This is the DHCP Client control structure */
RTCSPCB_PTR pcb_ptr
/*[IN] The offer we're accepting */
)
{ /* Body */
DHCP_HEADER _PTR_ header_ptr;
uchar _PTR_ opt;
uint_32 len;
uint_32 optlen;
uchar optval;
dhcp_ptr->NEW_RENEW_TIME = 0;
dhcp_ptr->NEW_REBIND_TIME = 0;
/* Make sure we have a server ID */
header_ptr = (DHCP_HEADER _PTR_)RTCSPCB_DATA(pcb_ptr);
/* Get our IP address, and pick the default netmask */
dhcp_ptr->NEW_PARMS_BIND.address = ntohl(header_ptr->YIADDR);
dhcp_ptr->NEW_DATA.ClientIPaddress = dhcp_ptr->NEW_PARMS_BIND.address;
dhcp_ptr->NEW_PARMS_BIND.locmask = 0xFFFFFFFFL;
dhcp_ptr->NEW_PARMS_BIND.netmask =
IN_DEFAULT_NET(dhcp_ptr->NEW_PARMS_BIND.address);
/* Parse the options field */
opt = (uchar _PTR_)header_ptr + sizeof(DHCP_HEADER) + 4;
len = RTCSPCB_SIZE(pcb_ptr) - (sizeof(DHCP_HEADER) + 4);
#define DHCP_NEXTOPT opt += optlen; \
break
while (len) {
/* Get the next option code */
optval = ntohc(opt);
opt++;
len--;
/* Interpret the pad and end options */
if (optval == DHCPOPT_END) break;
if (optval == DHCPOPT_PAD) continue;
/* All other codes have a length byte */
if (len == 0) break;
optlen = ntohc(opt);
opt++;
len--;
if (len < optlen) break;
len -= optlen;
switch (optval) {
case DHCPOPT_LEASE:
if (optlen != 4) {DHCP_NEXTOPT;}
dhcp_ptr->NEW_DATA.LEASE = ntohl(opt);
opt += 4;
break;
case DHCPOPT_MASK:
if (optlen != 4) {DHCP_NEXTOPT;}
dhcp_ptr->NEW_PARMS_BIND.netmask = ntohl(opt);
dhcp_ptr->NEW_DATA.Netmask = dhcp_ptr->NEW_PARMS_BIND.netmask;
opt += 4;
break;
case DHCPOPT_SERVERNAME:
_mem_copy(opt, dhcp_ptr->NEW_DATA.SNAME, optlen);
opt+=optlen;
break;
case DHCPOPT_FILENAME:
_mem_copy(opt, dhcp_ptr->NEW_DATA.BOOTFILE, optlen);
opt+=optlen;
break;
case DHCPOPT_RENEWALL:
if ( optlen != DHCPSIZE_LEASE ) {
DHCP_NEXTOPT;
} /* Endif */
dhcp_ptr->NEW_RENEW_TIME = ntohl(opt);
opt += DHCPSIZE_LEASE;
break;
case DHCPOPT_REBINDING:
if ( optlen != DHCPSIZE_LEASE ) {
DHCP_NEXTOPT;
} /* Endif */
dhcp_ptr->NEW_REBIND_TIME = ntohl(opt);
opt += DHCPSIZE_LEASE;
break;
default:
DHCP_NEXTOPT;
} /* Endswitch */
} /* Endwhile */
} /* Endbody */
#endif /* RTCSCFG_ENABLE_IP4 */
/*FUNCTION*-------------------------------------------------------------
*
* Function Name : DHCPCLNT_copy_binding
* Returned Values : void
* Comments :
*
*END*-----------------------------------------------------------------*/
#if RTCSCFG_ENABLE_IP4
static void DHCPCLNT_copy_binding
(
DHCP_CLNT_STRUCT _PTR_ dhcp_ptr
/* [IN/OUT] This is the DHCP Client control structure */
)
{ /* Body */
dhcp_ptr->PARMS_BIND.address = dhcp_ptr->NEW_PARMS_BIND.address;
dhcp_ptr->PARMS_BIND.locmask = dhcp_ptr->NEW_PARMS_BIND.locmask;
dhcp_ptr->PARMS_BIND.netmask = dhcp_ptr->NEW_PARMS_BIND.netmask;
dhcp_ptr->DATA.ServerIp = dhcp_ptr->NEW_DATA.ServerIp;
dhcp_ptr->DATA.ClientIPaddress = dhcp_ptr->NEW_DATA.ClientIPaddress;
dhcp_ptr->DATA.LEASE = dhcp_ptr->NEW_DATA.LEASE;
dhcp_ptr->DATA.Netmask = dhcp_ptr->NEW_DATA.Netmask;
dhcp_ptr->DATA.SADDR = dhcp_ptr->NEW_DATA.SADDR;
} /* Endbody */
#endif /* RTCSCFG_ENABLE_IP4 */
/*FUNCTION*-------------------------------------------------------------
*
* Function Name : DHCPCLNT_verify_packet
* Returned Values : uchar
* Comments :
* Verifies the validity of an incoming DHCP packet.
*
*END*-----------------------------------------------------------------*/
#if RTCSCFG_ENABLE_IP4
static uchar DHCPCLNT_verify_packet
(
DHCP_CLNT_STRUCT _PTR_ dhcp_ptr,
RTCSPCB_PTR pcb_ptr,
uchar _PTR_ bootreply,
uint_32 _PTR_ packet_size,
_ip_address _PTR_ temp_addr,
_ip_address _PTR_ current_ip,
uint_32 _PTR_ error
)
{ /* Body */
DHCP_HEADER _PTR_ send_header_ptr;
DHCP_HEADER _PTR_ header_ptr;
uchar _PTR_ opt;
uint_32 len;
uchar _PTR_ packet_option;
/* Make sure the datagram is large enough for the magic cookie */
if (RTCSPCB_SIZE(pcb_ptr) < sizeof(DHCP_HEADER) + 4) {
*error = RTCSERR_DHCPCLNT_PACKET_SIZE_ERROR;
return 0;
} /* Endif */
send_header_ptr = (DHCP_HEADER _PTR_)dhcp_ptr->PACKET;
header_ptr = (DHCP_HEADER _PTR_)bootreply;
/* Make sure the XID matches */
if (ntohl(header_ptr->XID) != ntohl(send_header_ptr->XID)) {
*error = RTCSERR_DHCPCLNT_XID_MISMATCH;
return 0;
} /* Endif */
/* Parse the options field to find the message type */
opt = bootreply + sizeof(DHCP_HEADER);
*packet_size = RTCSPCB_SIZE(pcb_ptr);
len = *packet_size - sizeof(DHCP_HEADER);
if (ntohl(opt) != DHCP_MAGIC) {
*error = RTCSERR_DHCP_PACKET_ERROR;
return 0;
} /* Endif */
opt += 4;
len -= 4;
/* These are to avoid problems in DHCPCLNT_modify_options if we decline */
*temp_addr = dhcp_ptr->NEW_DATA.ServerIp;
dhcp_ptr->NEW_DATA.ServerIp = IP_source(pcb_ptr);
dhcp_ptr->NEW_DATA.ClientIPaddress = ntohl(header_ptr->YIADDR);
packet_option = DHCP_find_option(opt, len, DHCPOPT_SERVERID);
if ( !packet_option || ntohc(packet_option + 1) != 4 ) {
/* Server id option is required in all DHCP responses */
DHCPCLNT_decline( dhcp_ptr, RTCSERR_DHCP_SERVER_OPTION_MISSING );
dhcp_ptr->NEW_DATA.ServerIp = *temp_addr;
*error = RTCSERR_DHCPCLNT_ERROR_DECLINED;
return 0;
} else {
packet_option += 2;
*current_ip = ntohl(packet_option);
} /* Endif */
packet_option = DHCP_find_option(opt, len, DHCPOPT_MSGTYPE);
if ( !packet_option || ntohc(packet_option + 1) != 1 ) {
/* Message type option is required in all DHCP packets */
DHCPCLNT_decline( dhcp_ptr, RTCSERR_DHCP_MESSAGE_OPTION_MISSING);
dhcp_ptr->NEW_DATA.ServerIp = *temp_addr;
*error = RTCSERR_DHCPCLNT_ERROR_DECLINED;
return 0;
} /* Endif */
packet_option += 2;
*error = RTCS_OK;
return(ntohc(packet_option));
} /* Endbody */
#endif /* RTCSCFG_ENABLE_IP4 */
/*FUNCTION*-------------------------------------------------------------
*
* Function Name : DHCPCLNT_service_offer
* Returned Values : void
* Comments :
* Services an incoming DHCP offer packet.
*
*END*-----------------------------------------------------------------*/
#if RTCSCFG_ENABLE_IP4
static void DHCPCLNT_service_offer
(
DHCP_CLNT_STRUCT _PTR_ dhcp_ptr,
RTCSPCB_PTR pcb_ptr,
uchar _PTR_ bootreply,
uint_32 packet_size,
_ip_address temp_addr,
_ip_address current_ip
)
{ /* Body */
dhcp_ptr->STATS.ST_RX_OFFER++;
if ( dhcp_ptr->STATE == DHCP_INITIALIZE ) {
if ( dhcp_ptr->CHOICE_FUNC != NULL ) {
if (dhcp_ptr->CHOICE_FUNC(bootreply, packet_size) < 0) {
/* It's been rejected */
dhcp_ptr->NEW_DATA.ServerIp = temp_addr;
return;
}/* Endif */
}/* Endif */
/* start the probe - this needs to complete before we service the dhACK */
if (dhcp_ptr->FLAGS & DHCP_SEND_PROBE) {
DHCPCLNT_probe_address( dhcp_ptr->NEW_DATA.ClientIPaddress, dhcp_ptr->HANDLE);
}
/* We're accepting this offer */
TCPIP_Event_cancel(&dhcp_ptr->RESEND);
dhcp_ptr->NEW_DATA.ServerIp = current_ip;
DHCPCLNT_parse_offer( dhcp_ptr, pcb_ptr );
dhcp_ptr->STATE = DHCP_REQUESTING;
DHCPCLNT_modify_options( dhcp_ptr );
dhcp_ptr->RETRY_TIMEOUT = DHCP_TIMEOUT_MIN;
/*
** put a bit of delay in before we send the REQEST. This is to give the
** probe (started above) a chance to compete.
*/
dhcp_ptr->RESEND.TIME = 50; /* 50 miliseconds */
TCPIP_Event_add( &dhcp_ptr->RESEND );
}/* Endif */
} /* Endbody */
#endif /* RTCSCFG_ENABLE_IP4 */
/*FUNCTION*-------------------------------------------------------------
*
* Function Name : DHCPCLNT_set_timed_events
* Returned Values : void
* Comments :
* Sets the renewall, rebinding, and termination times.
*
*END*-----------------------------------------------------------------*/
#if RTCSCFG_ENABLE_IP4
static void DHCPCLNT_set_timed_events
(
DHCP_CLNT_STRUCT _PTR_ dhcp_ptr
)
{ /* Body */
uint_32 random;
uint_32 renewall_range;
uint_32 renewall_time;
uint_32 terminate_time;
/* Set or reset the renewall event */
if ( dhcp_ptr->NEW_RENEW_TIME ) {
dhcp_ptr->RENEW_TIME = dhcp_ptr->NEW_RENEW_TIME;
} else {
/*
** The renewall time wasn't specified by the DHCP server,
** we need to set it ourselves.
*/
DHCP_SET_RENEWALL_RANGE(dhcp_ptr->DATA.LEASE, renewall_range);
random = RTCS_rand() % renewall_range;
dhcp_ptr->RENEW_TIME =
DHCP_RENEWALL_BIAS( dhcp_ptr->DATA.LEASE ) + random;
} /* Endif */
/* Set or reset rebinding event */
if ( dhcp_ptr->NEW_REBIND_TIME ) {
dhcp_ptr->REBIND_TIME = dhcp_ptr->NEW_REBIND_TIME
- dhcp_ptr->RENEW_TIME;
} else {
/*
** The rebinding time wasn't specified by the DHCP server,
** we need to set it ourselves.
*/
DHCP_SET_RENEWALL_RANGE(dhcp_ptr->DATA.LEASE, renewall_range);
random = RTCS_rand() % renewall_range;
dhcp_ptr->REBIND_TIME =
(DHCP_REBINDING_BIAS(dhcp_ptr->DATA.LEASE) + random)
- dhcp_ptr->RENEW_TIME;
}/* Endif */
dhcp_ptr->R_EVENTS_TIME_LEFT = dhcp_ptr->RENEW_TIME;
DHCPCLNT_TIME_OVERFLOW_CHECK(renewall_time, dhcp_ptr->R_EVENTS_TIME_LEFT)
dhcp_ptr->RENEW.TIME = renewall_time;
dhcp_ptr->RENEW.EVENT = DHCPCLNT_renew_lease;
dhcp_ptr->TERMINATE_TIME = dhcp_ptr->DATA.LEASE;
DHCPCLNT_TIME_OVERFLOW_CHECK(terminate_time, dhcp_ptr->TERMINATE_TIME)
dhcp_ptr->TERMINATE.TIME = terminate_time;
} /* Endbody */
#endif /* RTCSCFG_ENABLE_IP4 */
/*FUNCTION*-------------------------------------------------------------
*
* Function Name : DHCPCLNT_service_ack
* Returned Values : void
* Comments :
* Services an incoming DHCP ack packet.
*
*END*-----------------------------------------------------------------*/
#if RTCSCFG_ENABLE_IP4
static void DHCPCLNT_service_ack
(
DHCP_CLNT_STRUCT _PTR_ dhcp_ptr,
RTCSPCB_PTR pcb_ptr,
uchar _PTR_ bootreply,
uint_32 packet_size,
IP_IF_PTR if_ptr
)
{ /* Body */
DHCP_HEADER _PTR_ header_ptr;
boolean renew_again = TRUE;
dhcp_ptr->STATS.ST_RX_ACK++;
if ( dhcp_ptr->STATE == DHCP_INFORMED ) {
/* Give the application the info and self destruct */
TCPIP_Event_cancel(&dhcp_ptr->RESEND);
if ( dhcp_ptr->BIND_FUNC != NULL ) {
dhcp_ptr->BIND_FUNC(bootreply, packet_size, (_rtcs_if_handle)if_ptr);
} /* Endif */
BOOT_close();
dhcp_ptr->HANDLE->BOOT = NULL;
/* Free the DHCP Structure */
_mem_free(dhcp_ptr);
return;
} /* Endif */
header_ptr = (DHCP_HEADER _PTR_)bootreply;
/* OK, we've got a valid lease */
dhcp_ptr->DATA.SADDR = ntohl(header_ptr->SIADDR);
dhcp_ptr->NEW_DATA.ClientIPaddress = ntohl(header_ptr->YIADDR);
TCPIP_Event_cancel(&dhcp_ptr->TERMINATE);
DHCPCLNT_parse_offer( dhcp_ptr, pcb_ptr );
if ( dhcp_ptr->BOUND ) {
if (dhcp_ptr->NEW_DATA.LEASE < dhcp_ptr->DATA.LEASE) {
/* Our request was refused, wait for termination to bind again */
renew_again = FALSE;
}/* Endif */
dhcp_ptr->DATA.LEASE = dhcp_ptr->NEW_DATA.LEASE;
/* Cancel renewall and lease expiry events */
TCPIP_Event_cancel(&dhcp_ptr->RENEW);
} else {
/* Bind the received IP address to this interface */
DHCPCLNT_copy_binding( dhcp_ptr );
RTCSCMD_internal( dhcp_ptr->PARMS_BIND, IPIF_bind );
dhcp_ptr->TERMINATE.EVENT = DHCPCLNT_terminate_lease;
} /* Endif */
if ( dhcp_ptr->DATA.LEASE != DHCP_LEASE_INFINITE ) {
DHCPCLNT_set_timed_events(dhcp_ptr);
} /* Endif */
TCPIP_Event_cancel(&dhcp_ptr->RESEND);
dhcp_ptr->BOUND = TRUE;
if ( DHCPCLNT_verify_address( dhcp_ptr )) {
/* Address is in use by another host, decline and restart */
DHCPCLNT_decline( dhcp_ptr, RTCSERR_DHCP_ADDR_IN_USE);
RTCSCMD_internal( dhcp_ptr->PARMS_BIND, IPIF_unbind );
dhcp_ptr->BOUND = FALSE;
dhcp_ptr->RENEW_TIME = 0;
dhcp_ptr->STATE = DHCP_INITIALIZE;
DHCPCLNT_modify_options( dhcp_ptr );
DHCPCLNT_open( dhcp_ptr );
} else {
dhcp_ptr->STATE = DHCP_BOUND;
if ( dhcp_ptr->BIND_FUNC != NULL ) {
dhcp_ptr->BIND_FUNC(bootreply, packet_size,
(_rtcs_if_handle)if_ptr);
}/* Endif */
if (dhcp_ptr->DATA.LEASE == DHCP_LEASE_INFINITE) {
if(!(dhcp_ptr->FLAGS & DHCP_MAINTAIN_STATE_ON_INFINITE_LEASE)) {
BOOT_close();
dhcp_ptr->HANDLE->BOOT = NULL;
/* Free the DHCP Structure */
_mem_free(dhcp_ptr);
} /* Endif */
} else {
if (renew_again) {
TCPIP_Event_add(&dhcp_ptr->RENEW);
}/* Endif */
TCPIP_Event_add(&dhcp_ptr->TERMINATE);
} /* Endif */
} /* Endif */
} /* Endbody */
#endif /* RTCSCFG_ENABLE_IP4 */
/*FUNCTION*-------------------------------------------------------------
*
* Function Name : DHCPCLNT_service_nak
* Returned Values : void
* Comments :
* Services an incoming DHCP NAK packet.
*
*END*-----------------------------------------------------------------*/
#if RTCSCFG_ENABLE_IP4
static void DHCPCLNT_service_nak
(
DHCP_CLNT_STRUCT _PTR_ dhcp_ptr,
uchar _PTR_ bootreply,
uint_32 packet_size
)
{ /* Body */
boolean retry = FALSE;
/* Our request was refused. Start request over */
dhcp_ptr->STATS.ST_RX_NAK++;
if ( dhcp_ptr->NAK_FUNC != NULL )
{
retry = dhcp_ptr->NAK_FUNC(bootreply, packet_size, (_rtcs_if_handle)dhcp_ptr->HANDLE);
} /* Endif */
if ( retry ) {
dhcp_ptr->STATE = DHCP_REQUESTING;
DHCPCLNT_modify_options( dhcp_ptr );
} else {
dhcp_ptr->RENEW_TIME = 0;
dhcp_ptr->TERMINATE_TIME = 0;
TCPIP_Event_cancel(&dhcp_ptr->TERMINATE);
DHCPCLNT_terminate_lease(&dhcp_ptr->TERMINATE);
} /* Endif */
} /* Endbody */
#endif /* RTCSCFG_ENABLE_IP4 */
/*FUNCTION*-------------------------------------------------------------
*
* Function Name : DHCPCLNT_service
* Returned Values : void
* Comments :
* Services an incoming DHCP packet.
*
*END*-----------------------------------------------------------------*/
#if RTCSCFG_ENABLE_IP4
void DHCPCLNT_service
(
RTCSPCB_PTR pcb_ptr, /* [IN] DHCP packet */
UCB_STRUCT_PTR ucb_ptr /* [IN] target UCB */
)
{ /* Body */
IP_IF_PTR if_ptr = (IP_IF_PTR)pcb_ptr->IFSRC;
DHCP_CLNT_STRUCT _PTR_ dhcp_ptr = (DHCP_CLNT_STRUCT _PTR_)if_ptr->BOOT;
uchar _PTR_ bootreply;
uchar msgtype;
uint_32 packet_size;
uint_32 error;
_ip_address current_ip;
_ip_address temp_addr;
RTCSLOG_PCB_READ(pcb_ptr, RTCS_LOGCTRL_PORT(IPPORT_BOOTPC), 0);
if ((dhcp_ptr != NULL) && (dhcp_ptr->STATE != DHCP_BOUND)) {
bootreply = RTCSPCB_DATA(pcb_ptr);
msgtype = DHCPCLNT_verify_packet(dhcp_ptr, pcb_ptr, bootreply,
&packet_size, &temp_addr, &current_ip, &error);
if (error) {
RTCSLOG_PCB_FREE(pcb_ptr, error);
RTCSPCB_free(pcb_ptr);
return;
} /* Endif */
if ( msgtype == DHCPTYPE_DHCPOFFER ) {
DHCPCLNT_service_offer(dhcp_ptr, pcb_ptr, bootreply, packet_size,
temp_addr, current_ip);
} else {
/* It's an ACK or a NAK message */
if ( dhcp_ptr->STATE != DHCP_INITIALIZE ) {
if ( msgtype == DHCPTYPE_DHCPACK ) {
DHCPCLNT_service_ack(dhcp_ptr, pcb_ptr, bootreply, packet_size,
if_ptr);
} else if (msgtype == DHCPTYPE_DHCPNAK ) {
DHCPCLNT_service_nak(dhcp_ptr, bootreply, packet_size);
} /* Endif */
} /* Endif */
} /* Endif */
} /* Endif */
RTCSLOG_PCB_FREE(pcb_ptr, RTCS_OK);
RTCSPCB_free(pcb_ptr);
} /* Endbody */
#endif /* RTCSCFG_ENABLE_IP4 */
/*FUNCTION*-------------------------------------------------------------
*
* Function Name : DHCPCLNT_verify_address
* Returned Values : boolean, TRUE if the address is in use by another host,
* FALSE otherwise
* Comments :
*
*END*-----------------------------------------------------------------*/
#if RTCSCFG_ENABLE_IP4
static boolean DHCPCLNT_verify_address
(
DHCP_CLNT_STRUCT _PTR_ dhcp_ptr
/* [IN] This is the DHCP Client control structure */
)
{ /* Body */
_ip_address new_ip = dhcp_ptr->DATA.ClientIPaddress;
IP_IF_PTR if_ptr = dhcp_ptr->HANDLE;
if (! dhcp_ptr->FLAGS & DHCP_SEND_PROBE) {
/* we are configured to not probe, so don't try to verify */
return FALSE;
}
/* note: an arp probe was sent out during DHCPCLNT_service_offer.
we expect that if an arp response was comming, it arrived by
now.
*/
return ARP_is_complete (if_ptr, new_ip);
} /* Endbody */
#endif /* RTCSCFG_ENABLE_IP4 */
/*FUNCTION*-------------------------------------------------------------
*
* Function Name : DHCPCLNT_probe_address
* Returned Values : RTCS_OK meanse that probe was sent out the interface.
* Parameters :
*
* _ip_address probe_addr [IN] IP address to probe the network for
* pointer : src_interface [IN] interface we will send the probe from
*
* Comments :
* Send out an arp reuest to ipaddress from interface. An arp reply will
* be noted by the arp system on this interface and may be referenced later.
*
*END*-----------------------------------------------------------------*/
#if RTCSCFG_ENABLE_IP4
uint_32 DHCPCLNT_probe_address
(
_ip_address probe_addr,
pointer src_interface
)
{ /* Body */
return( ARP_request(src_interface, probe_addr, probe_addr ));
} /* Endbody */
#endif /* RTCSCFG_ENABLE_IP4 */
/* EOF */