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

1239 lines
34 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: dhcpsrv.c$
* $Version : 3.8.15.0$
* $Date : Jun-14-2012$
*
* Comments:
*
* This file contains the DHCP Server for RTCS.
*
*END************************************************************************/
#include <rtcs.h>
#if RTCSCFG_ENABLE_UDP
#include "dhcpsrv.h"
static DHCPSRV_STATE_STRUCT_PTR DHCPSRV_cfg = NULL;
void DHCPSRV_task (pointer, pointer);
/*FUNCTION*-------------------------------------------------------------
*
* Function Name : DHCPSRV_lease_start
* Returned Value : void
* Comments : This function starts a lease or offer.
*
* Notes : This function must be called with the IPLIST
* semaphore locked.
*
*END*-----------------------------------------------------------------*/
static void DHCPSRV_lease_start
(
DHCPSRV_ADDR_STRUCT_PTR _PTR_ addrhead,
DHCPSRV_ADDR_STRUCT_PTR addr,
uint_32 time
)
{ /* Body */
while ((*addrhead) && (*addrhead)->EXPIRE < time) {
if (time < DHCP_LEASE_INFINITE) {
time -= (*addrhead)->EXPIRE;
} /* Endif */
addrhead = &(*addrhead)->NEXT;
} /* Endwhile */
if (*addrhead && (*addrhead)->EXPIRE < DHCP_LEASE_INFINITE) {
(*addrhead)->EXPIRE -= time;
} /* Endif */
addr->EXPIRE = time;
addr->NEXT = (*addrhead);
*addrhead = addr;
} /* Endbody */
/*FUNCTION*-------------------------------------------------------------
*
* Function Name : DHCPSRV_lease_stop
* Returned Value : dequeued IP address
* Comments : This function terminates a lease or offer.
*
* Notes : This function must be called with the IPLIST
* semaphore locked.
*
*END*-----------------------------------------------------------------*/
static DHCPSRV_ADDR_STRUCT_PTR DHCPSRV_lease_stop
(
DHCPSRV_ADDR_STRUCT_PTR _PTR_ addrhead
)
{ /* Body */
DHCPSRV_ADDR_STRUCT_PTR addr = *addrhead;
if (addr->NEXT && addr->NEXT->EXPIRE < DHCP_LEASE_INFINITE) {
addr->NEXT->EXPIRE += addr->EXPIRE;
} /* Endif */
*addrhead = addr->NEXT;
return addr;
} /* Endbody */
/*FUNCTION*-------------------------------------------------------------
*
* Function Name : DHCPSRV_lease_extend
* Returned Value : void
* Comments : This function extends the EXPIRE time of an
* offer or a lease by delta.
*
* Notes : This function must be called with the IPLIST
* semaphore locked.
*
*END*-----------------------------------------------------------------*/
static void DHCPSRV_lease_extend
(
DHCPSRV_ADDR_STRUCT_PTR _PTR_ addrhead,
uint_32 delta
)
{ /* Body */
DHCPSRV_ADDR_STRUCT_PTR addr = *addrhead;
delta += addr->EXPIRE;
addr = DHCPSRV_lease_stop(addrhead);
DHCPSRV_lease_start(addrhead, addr, delta);
} /* Endbody */
/*FUNCTION*-------------------------------------------------------------
*
* Function Name : DHCPSRV_ippool_add
* Returned Value : error code
* Comments : This function adds a block of IP addresses to
* the IP_AVAIL list.
*
*END*-----------------------------------------------------------------*/
uint_32 DHCPSRV_ippool_add
(
_ip_address ipstart,
uint_32 ipnum,
DHCPSRV_DATA_STRUCT_PTR params,
uchar_ptr optptr,
uint_32 optlen
)
{ /* Body */
DHCPSRV_OPTIONS_STRUCT_PTR options;
DHCPSRV_ADDR_STRUCT_PTR addr;
uchar_ptr moreoptions = NULL;
options = RTCS_mem_alloc_system(sizeof(DHCPSRV_OPTIONS_STRUCT) + optlen);
if (!options) {
return RTCSERR_OUT_OF_MEMORY;
} /* Endif */
_mem_set_type(options, MEM_TYPE_DHCPSRV_OPTIONS_STRUCT);
moreoptions = (uchar_ptr)(options+1);
_mem_copy(optptr, moreoptions, optlen);
options->COUNT = 0;
options->SERVERID = params->SERVERID;
options->LEASE = params->LEASE;
options->MASK = params->MASK;
options->OPTION_PTR = moreoptions;
options->OPTION_LEN = optlen;
options->SADDR = params->SADDR;
_mem_copy(params->SNAME, options->SNAME, sizeof(options->SNAME) - 1);
options->SNAME[sizeof(options->SNAME) - 1] = '\0';
_mem_copy(params->FILE, options->FILE, sizeof(options->FILE) - 1);
options->FILE[sizeof(options->FILE) - 1] = '\0';
RTCS_mutex_lock(&DHCPSRV_cfg->IPLIST_SEM);
for (; ipnum; ipnum--, ipstart++) {
addr = RTCS_mem_alloc_system(sizeof(DHCPSRV_ADDR_STRUCT));
if (!addr) {
if (options->COUNT == 0) {
_mem_free(options);
} /* Endif */
RTCS_mutex_unlock(&DHCPSRV_cfg->IPLIST_SEM);
return RTCSERR_OUT_OF_MEMORY;
} /* Endif */
_mem_set_type(options, MEM_TYPE_DHCPSRV_ADDR_STRUCT);
addr->CLIENTID_LEN = 0;
addr->CLIENTID_PTR = NULL;
addr->IP_ADDR = ipstart;
addr->OPTIONS = options;
options->COUNT++;
DHCPSRV_lease_start(&DHCPSRV_cfg->IP_AVAIL, addr, 0);
} /* Endfor */
RTCS_mutex_unlock(&DHCPSRV_cfg->IPLIST_SEM);
return RTCS_OK;
} /* Endbody */
/*FUNCTION*-------------------------------------------------------------
*
* Function Name : DHCPSRV_expire
* Returned Value : time to next expiry, 0 = forever.
* Comments : This function expires offers and leases.
*
*END*-----------------------------------------------------------------*/
static uint_32 DHCPSRV_expire
(
DHCPSRV_STATE_STRUCT_PTR state
)
{ /* Body */
DHCPSRV_ADDR_STRUCT_PTR addr;
TIME_STRUCT time;
uint_32 elapsed;
RTCS_mutex_lock(&state->IPLIST_SEM);
_time_get(&time);
/* Expire offers */
elapsed = time.SECONDS - state->TIME;
while (state->IP_OFFERED) {
if (state->IP_OFFERED->EXPIRE > elapsed) {
state->IP_OFFERED->EXPIRE -= elapsed;
break;
} /* Endif */
addr = state->IP_OFFERED;
state->IP_OFFERED = addr->NEXT;
elapsed -= addr->EXPIRE;
DHCPSRV_lease_start(&state->IP_AVAIL, addr, 0);
} /* Endwhile */
/* Expire leases */
elapsed = time.SECONDS - state->TIME;
while (state->IP_LEASED && state->IP_LEASED->EXPIRE < DHCP_LEASE_INFINITE) {
if (state->IP_LEASED->EXPIRE > elapsed) {
state->IP_LEASED->EXPIRE -= elapsed;
break;
} /* Endif */
addr = state->IP_LEASED;
state->IP_LEASED = addr->NEXT;
elapsed -= addr->EXPIRE;
DHCPSRV_lease_start(&state->IP_AVAIL, addr, 0);
} /* Endwhile */
/* Start CR 1547 */
/* Expire takens */
elapsed = time.SECONDS - state->TIME;
while (state->IP_TAKEN && state->IP_TAKEN->EXPIRE < DHCP_LEASE_INFINITE) {
if (state->IP_TAKEN->EXPIRE > elapsed) {
state->IP_TAKEN->EXPIRE -= elapsed;
break;
} /* Endif */
addr = state->IP_TAKEN;
state->IP_TAKEN = addr->NEXT;
elapsed -= addr->EXPIRE;
DHCPSRV_lease_start(&state->IP_AVAIL, addr, 0);
} /* Endwhile */
/* End CR 1547 */
/* Calculate time to next expiry */
elapsed = DHCP_LEASE_INFINITE;
if (state->IP_OFFERED && state->IP_OFFERED->EXPIRE < elapsed) {
elapsed = state->IP_OFFERED->EXPIRE;
} /* Endif */
if (state->IP_LEASED && state->IP_LEASED->EXPIRE < elapsed) {
elapsed = state->IP_LEASED->EXPIRE;
} /* Endif */
if (elapsed == DHCP_LEASE_INFINITE) {
elapsed = 0;
} /* Endif */
state->TIME = time.SECONDS;
RTCS_mutex_unlock(&state->IPLIST_SEM);
return elapsed;
} /* Endbody */
/*FUNCTION*-------------------------------------------------------------
*
* Function Name : DHCPSRV_find_option
* Returned Value : uchar_ptr
* Comments : This function searches through the OPTIONS section
* of a DHCP message to find a specific option type.
* If it is found, a pointer to the specific option
* field is returned, If no option of the specified
* type exists, NULL is returned.
*
*END*-----------------------------------------------------------------*/
static uchar_ptr DHCPSRV_find_option
(
uchar_ptr msgptr,
uint_32 msglen,
uchar option
)
{ /* Body */
uchar optype;
uchar oplen;
for (;;) {
/* Get the next option code */
if (msglen == 0) {
return NULL;
} /* Endif */
optype = ntohc(msgptr);
msgptr++;
msglen--;
if (optype == DHCPOPT_END) {
return NULL;
} /* Endif */
if (optype == DHCPOPT_PAD) {
continue;
} /* Endif */
/* Get the option length */
if (msglen == 0) {
return NULL;
} /* Endif */
oplen = ntohc(msgptr);
msgptr++;
msglen--;
if (msglen < oplen) {
return NULL;
} /* Endif */
if (optype == option) {
return msgptr-2;
} /* Endif */
msgptr += oplen;
msglen -= oplen;
} /* Endfor */
} /* Endbody */
/*FUNCTION*-------------------------------------------------------------
*
* Function Name : DHCPSRV_find_msgtype
* Returned Value : value of the Message Type option
* Comments : This function searches through the OPTIONS section
* of a DHCP message for the message type option. If
* the message type option is is not present, 0 is
* returned.
*
*END*-----------------------------------------------------------------*/
static uchar DHCPSRV_find_msgtype
(
uchar_ptr msgptr,
uint_32 msglen
)
{ /* Body */
uchar msgtype = 0;
msgptr = DHCPSRV_find_option(msgptr, msglen, DHCPOPT_MSGTYPE);
if (msgptr != NULL) {
msgptr++;
if (ntohc(msgptr) == DHCPSIZE_MSGTYPE) {
msgptr++;
msgtype = ntohc(msgptr);
if (!DHCPTYPE_ISVALID(msgtype)) {
msgtype = 0;
} /* Endif */
} /* Endif */
} /* Endif */
return msgtype;
} /* Endbody */
/*FUNCTION*-------------------------------------------------------------
*
* Function Name : DHCPSRV_find_clientid
* Returned Value : IP address associated to client ID
* Comments : This function searches a DHCPSRV_ADDR list for
* an IP address associated to a client. If no
* address is found, NULL is returned.
*
* Notes : This function must be called with the IPLIST
* semaphore locked.
*
*END*-----------------------------------------------------------------*/
static DHCPSRV_ADDR_STRUCT_PTR _PTR_ DHCPSRV_find_clientid
(
DHCPSRV_ADDR_STRUCT_PTR _PTR_ addrhead,
uchar_ptr cid_ptr,
uint_32 cid_len,
uint_32_ptr expire_ptr
)
{ /* Body */
uint_32 i, expire;
boolean found;
expire = 0;
while (*addrhead) {
expire += (*addrhead)->EXPIRE;
if ((*addrhead)->CLIENTID_PTR && (*addrhead)->CLIENTID_LEN == cid_len) {
found = TRUE;
for (i=0; i<cid_len; i++) {
if (cid_ptr[i] != (*addrhead)->CLIENTID_PTR[i]) {
found = FALSE;
break;
} /* Endif */
} /* Endfor */
if (found) {
if (expire_ptr) *expire_ptr = expire;
return addrhead;
} /* Endif */
} /* Endif */
addrhead = &(*addrhead)->NEXT;
} /* Endwhile */
return NULL;
} /* Endbody */
/*FUNCTION*-------------------------------------------------------------
*
* Function Name : DHCPSRV_find_addr
* Returned Value : IP address associated to client ID
* Comments : This function searches a DHCPSRV_ADDR list for
* a specified IP address. If the address is not
* found, NULL is returned.
*
* Notes : This function must be called with the IPLIST
* semaphore locked.
*
*END*-----------------------------------------------------------------*/
static DHCPSRV_ADDR_STRUCT_PTR _PTR_ DHCPSRV_find_addr
(
DHCPSRV_ADDR_STRUCT_PTR _PTR_ addrhead,
_ip_address addr
)
{ /* Body */
while (*addrhead) {
if ((*addrhead)->IP_ADDR == addr) {
return addrhead;
} /* Endif */
addrhead = &(*addrhead)->NEXT;
} /* Endwhile */
return NULL;
} /* Endbody */
/*FUNCTION*-------------------------------------------------------------
*
* Function Name : DHCPSRV_update_clientid
* Returned Value : its first parameter if successful, NULL otherwise
* Comments : This function updates a DHCPSRV_ADDR's client
* ID field with a new one.
*
* Notes : This function must be called with the IPLIST
* semaphore locked.
*
*END*-----------------------------------------------------------------*/
static DHCPSRV_ADDR_STRUCT_PTR _PTR_ DHCPSRV_update_clientid
(
DHCPSRV_ADDR_STRUCT_PTR _PTR_ addrhead,
uchar_ptr cid_ptr,
uint_32 cid_len
)
{ /* Body */
DHCPSRV_ADDR_STRUCT_PTR addr = *addrhead;
uchar_ptr cid;
cid = RTCS_mem_alloc(cid_len);
if (!cid) return NULL;
_mem_set_type(cid, MEM_TYPE_DHCPSRV_CID);
if (addr->CLIENTID_PTR) _mem_free(addr->CLIENTID_PTR);
_mem_copy(cid_ptr, cid, cid_len);
addr->CLIENTID_PTR = cid;
addr->CLIENTID_LEN = cid_len;
return addrhead;
} /* Endbody */
/*FUNCTION*-------------------------------------------------------------
*
* Function Name : DHCPSRV_write_header
* Returned Value : void
* Comments : This function fills the send buffer with the
* initial values needed in a DHCP response.
*
*END*-----------------------------------------------------------------*/
static void DHCPSRV_write_header
(
DHCPSRV_STATE_STRUCT_PTR state,
DHCPSRV_ADDR_STRUCT_PTR lease_ptr,
uint_32 lease_time,
uchar msgtype
)
{ /* Body */
DHCP_HEADER_PTR outp;
DHCP_HEADER_PTR inp;
uchar_ptr optptr;
volatile uint_32 optlen;
uint_32 temp_long;
uint_16 temp_short;
uchar temp_char;
outp = (DHCP_HEADER_PTR)state->SND_BUFFER;
inp = (DHCP_HEADER_PTR)state->RCV_BUFFER;
/* Build a DHCPOFFER, DHCPACK, or DHCPNAK packet */
htonc(outp->OP, DHCPOP_BOOTREPLY);
htonc(outp->HTYPE, ARPLINK_ETHERNET);
temp_char = ntohc(inp->HLEN);
htonc(outp->HLEN, temp_char);
htonc(outp->HOPS, 0);
/* Use client's existing transaction ID */
temp_long = ntohl(inp->XID);
htonl(outp->XID, temp_long);
htons(outp->SECS, 0);
if (ntohl(inp->GIADDR) == 0) {
htons(outp->FLAGS, 0);
} else {
temp_short = ntohs(inp->FLAGS);
htons(outp->FLAGS, temp_short);
} /* Endif */
if (msgtype == DHCPTYPE_DHCPOFFER) {
htonl(outp->CIADDR, 0);
} else {
temp_long = ntohl(inp->CIADDR);
htonl(outp->CIADDR, temp_long);
} /* Endif */
if (msgtype == DHCPTYPE_DHCPNAK) {
htonl(outp->YIADDR, 0);
htonl(outp->SIADDR, 0);
} else {
htonl(outp->YIADDR, lease_ptr->IP_ADDR);
htonl(outp->SIADDR, lease_ptr->OPTIONS->SADDR);
} /* Endif */
htonl(outp->GIADDR, 0);
_mem_copy(inp->CHADDR, outp->CHADDR, sizeof(outp->CHADDR));
if (msgtype == DHCPTYPE_DHCPNAK) {
_mem_zero(outp->SNAME, sizeof(outp->SNAME));
_mem_zero(outp->FILE, sizeof(outp->FILE));
} else {
_mem_copy(lease_ptr->OPTIONS->SNAME, outp->SNAME, sizeof(outp->SNAME));
_mem_copy(lease_ptr->OPTIONS->FILE, outp->FILE, sizeof(outp->FILE));
} /* Endif */
/*
** Fill in the required response options. These are message type,
** subnet mask, and server id.
*/
optlen = sizeof(DHCP_HEADER);
optptr = state->SND_BUFFER + optlen;
/* The Magic Cookie must always be the first thing in the OPTIONS */
htonl(optptr, DHCP_MAGIC);
optptr += DHCPSIZE_MAGIC;
optlen += DHCPSIZE_MAGIC;
#define DHCP_OPTION(type,len,val) \
htonc(optptr, DHCPOPT_ ## type); optptr++; optlen++; \
htonc(optptr, DHCPSIZE_ ## type); optptr++; optlen++; \
hton ## len(optptr, val); \
optptr += DHCPSIZE_ ## type; \
optlen += DHCPSIZE_ ## type
DHCP_OPTION(MSGTYPE, c, msgtype);
if (msgtype != DHCPTYPE_DHCPNAK) {
DHCP_OPTION(SERVERID, l, lease_ptr->OPTIONS->SERVERID);
DHCP_OPTION(MASK, l, lease_ptr->OPTIONS->MASK);
DHCP_OPTION(LEASE, l, lease_time);
} /* Endif */
state->SND_BUFFER_LEN = optlen;
} /* Endbody */
/*FUNCTION*-------------------------------------------------------------
*
* Function Name : DHCPSRV_write_options
* Returned Value : void
* Comments : This function fills the send buffer with the
* options specified by the application.
*
*END*-----------------------------------------------------------------*/
static void DHCPSRV_write_options
(
DHCPSRV_STATE_STRUCT_PTR state,
DHCPSRV_ADDR_STRUCT_PTR lease_ptr
)
{ /* Body */
uchar_ptr inp, outp, scanptr;
int_32 scanlen;
uint_32 copylen;
volatile uchar optval, optlen;
outp = state->SND_BUFFER + state->SND_BUFFER_LEN;
inp = lease_ptr->OPTIONS->OPTION_PTR;
scanptr = inp;
scanlen = sizeof(state->SND_BUFFER) - state->SND_BUFFER_LEN - 1;
if (scanlen > lease_ptr->OPTIONS->OPTION_LEN) {
scanlen = lease_ptr->OPTIONS->OPTION_LEN;
} /* Endif */
copylen = 0;
for (;;) {
if (scanlen < 1) break;
optval = ntohc(scanptr);
scanptr++;
scanlen--;
if (optval == DHCPOPT_END) {
break;
} /* Endif */
if (optval == DHCPOPT_PAD) {
copylen++;
continue;
} /* Endif */
if (scanlen < 1) break;
optlen = ntohc(scanptr);
scanptr++;
scanlen--;
if (scanlen < optlen) break;
scanptr += optlen;
scanlen -= optlen;
copylen += optlen + 2;
} /* Endfor */
_mem_copy(inp, outp, copylen);
state->SND_BUFFER_LEN += copylen;
} /* Endbody */
/*FUNCTION*-------------------------------------------------------------
*
* Function Name : DHCPSRV_write_end
* Returned Value : void
* Comments : This function writes an END option to the
* OPTIONS field.
*
*END*-----------------------------------------------------------------*/
static void DHCPSRV_write_end
(
DHCPSRV_STATE_STRUCT_PTR state
)
{ /* Body */
uchar_ptr optptr;
volatile uint_32 optlen;
optlen = state->SND_BUFFER_LEN;
optptr = state->SND_BUFFER + optlen;
htonc(optptr, DHCPOPT_END);
optlen++;
state->SND_BUFFER_LEN = optlen;
} /* Endbody */
/*FUNCTION*-------------------------------------------------------------
*
* Function Name : DHCPSRV_send
* Returned Value : void
* Comments : This function sends a prebuilt DHCP reply.
*
*END*-----------------------------------------------------------------*/
static void DHCPSRV_send
(
DHCPSRV_STATE_STRUCT_PTR state
)
{ /* Body */
_ip_address giaddr;
sockaddr_in raddr;
giaddr = ntohl(((DHCP_HEADER_PTR)state->RCV_BUFFER)->GIADDR);
if (giaddr) {
raddr.sin_family = AF_INET;
raddr.sin_port = IPPORT_BOOTPS;
raddr.sin_addr.s_addr = giaddr;
} else {
raddr.sin_family = AF_INET;
raddr.sin_port = IPPORT_BOOTPC;
raddr.sin_addr.s_addr = INADDR_BROADCAST;
} /* Endif */
/* Start CR 1131 */
sendto(state->SOCKET, state->SND_BUFFER, state->SND_BUFFER_LEN,
RTCS_MSG_NOLOOP, (sockaddr *)&raddr, sizeof(raddr));
/* End CR 1131 */
} /* Endbody */
/*FUNCTION*-------------------------------------------------------------
*
* Function Name : DHCPSRV_service_discover
* Returned Value : void
* Comments : This function replies to a received DHCPDISCOVER
* message.
*
*END*-----------------------------------------------------------------*/
static void DHCPSRV_service_discover
(
DHCPSRV_STATE_STRUCT_PTR state
)
{ /* Body */
uchar_ptr inp, cid_ptr, opt_ptr;
uint_32 inlen, cid_len;
DHCPSRV_ADDR_STRUCT_PTR addr;
DHCPSRV_ADDR_STRUCT_PTR _PTR_ addrp;
uint_32 time, lease;
boolean leased, avail, newcid;
inp = state->RCV_BUFFER + sizeof(DHCP_HEADER) + 4;
inlen = state->RCV_BUFFER_LEN - sizeof(DHCP_HEADER) - 4;
/* Get the client ID; use CHADDR if none */
cid_ptr = DHCPSRV_find_option(inp, inlen, DHCPOPT_CLIENTID);
if (cid_ptr) {
cid_ptr++;
cid_len = ntohc(cid_ptr);
cid_ptr++;
} else {
DHCP_HEADER_PTR pkt_ptr = (DHCP_HEADER_PTR)state->RCV_BUFFER;
cid_ptr = pkt_ptr->CHADDR;
cid_len = ntohc(pkt_ptr->HLEN);
if (cid_len > sizeof(pkt_ptr->CHADDR)) {
cid_len = sizeof(pkt_ptr->CHADDR);
} /* Endif */
} /* Endif */
addrp = NULL;
RTCS_mutex_lock(&state->IPLIST_SEM);
/* First check whether the client already has a lease */
if (!addrp) {
addrp = DHCPSRV_find_clientid(&state->IP_LEASED, cid_ptr, cid_len, &time);
leased = TRUE;
avail = FALSE;
newcid = FALSE;
} /* Endif */
/* Next check whether the client has been offered a lease */
if (!addrp) {
addrp = DHCPSRV_find_clientid(&state->IP_OFFERED, cid_ptr, cid_len, &time);
leased = FALSE;
avail = FALSE;
newcid = FALSE;
} /* Endif */
/* Next check whether any available address was previously offered/leased to the client */
if (!addrp) {
addrp = DHCPSRV_find_clientid(&state->IP_AVAIL, cid_ptr, cid_len, NULL);
leased = FALSE;
avail = TRUE;
newcid = FALSE;
} /* Endif */
/* Next check whether the client's requested address is available */
if (!addrp) {
_ip_address reqaddr;
opt_ptr = DHCPSRV_find_option(inp, inlen, DHCPOPT_ADDRESS);
if (opt_ptr && ntohc(opt_ptr+1) == DHCPSIZE_ADDRESS) {
reqaddr = ntohl(opt_ptr+2);
} else {
DHCP_HEADER_PTR pkt_ptr = (DHCP_HEADER_PTR)state->RCV_BUFFER;
reqaddr = ntohl(pkt_ptr->CIADDR);
} /* Endif */
addrp = DHCPSRV_find_addr(&state->IP_AVAIL, reqaddr);
leased = FALSE;
avail = TRUE;
newcid = TRUE;
} /* Endif */
/* Finally, offer the first available address */
if (!addrp) {
if (state->IP_AVAIL) {
addrp = &state->IP_AVAIL;
} /* Endif */
leased = FALSE;
avail = TRUE;
newcid = TRUE;
} /* Endif */
if (newcid && addrp) {
addrp = DHCPSRV_update_clientid(addrp, cid_ptr, cid_len);
} /* Endif */
if (addrp) {
/* Determine length of offer */
opt_ptr = DHCPSRV_find_option(inp, inlen, DHCPOPT_LEASE);
if (opt_ptr && ntohc(opt_ptr+1) == DHCPSIZE_LEASE) {
lease = ntohl(opt_ptr+2);
if (lease > (*addrp)->OPTIONS->LEASE) {
lease = (*addrp)->OPTIONS->LEASE;
} /* Endif */
} else if (leased) {
lease = time;
} else {
lease = (*addrp)->OPTIONS->LEASE;
} /* Endif */
(*addrp)->OFFER = lease;
DHCPSRV_write_header (state, *addrp, lease, DHCPTYPE_DHCPOFFER);
DHCPSRV_write_options(state, *addrp);
DHCPSRV_write_end (state);
/* Start CR 1547 */
/* probe the address to see if it is already taken (if so configured) */
if (addrp && DHCPSRV_cfg->FLAGS & DHCPSVR_FLAG_DO_PROBE) {
uint_32 timeout = 50; /* miliseconds */
uint_32 error;
/* note: this will hang the dhserver application while we await the probe result */
error = RTCS_ping((*addrp)->IP_ADDR, &timeout, 0xFACE, 0, 0, 0);
if (error == RTCS_OK) {
/* bad news: someone answered this ping, we can't use this address */
addr = DHCPSRV_lease_stop(addrp);
DHCPSRV_lease_start(&state->IP_TAKEN, addr, DHCPTIME_OFFER);
avail = FALSE;
/* nak this discover, client will send us another */
DHCPSRV_write_header(state, NULL, 0, DHCPTYPE_DHCPNAK);
DHCPSRV_write_end(state);
}
}
/* End CR 1547 */
/* Reserve the offer for at least DHCPTIME_OFFER */
if (avail) {
addr = DHCPSRV_lease_stop(addrp);
DHCPSRV_lease_start(&state->IP_OFFERED, addr, DHCPTIME_OFFER);
} else if (time < DHCPTIME_OFFER) {
DHCPSRV_lease_extend(addrp, DHCPTIME_OFFER - time);
} /* Endif */
} else {
DHCPSRV_write_header(state, NULL, 0, DHCPTYPE_DHCPNAK);
DHCPSRV_write_end(state);
} /* Endif */
RTCS_mutex_unlock(&state->IPLIST_SEM);
DHCPSRV_send(state);
} /* Endbody */
/*FUNCTION*-------------------------------------------------------------
*
* Function Name : DHCPSRV_service_request
* Returned Value : void
* Comments : This function replies to a received DHCPREQUEST
* message.
*
*END*-----------------------------------------------------------------*/
static void DHCPSRV_service_request
(
DHCPSRV_STATE_STRUCT_PTR state
)
{ /* Body */
uchar_ptr inp, cid_ptr, sid_ptr, lease_ptr;
uint_32 inlen, cid_len;
_ip_address serverid = 0;
uint_32 lease = 0;
DHCPSRV_ADDR_STRUCT_PTR addr;
DHCPSRV_ADDR_STRUCT_PTR _PTR_ addrp;
/* Start CR 1599 */
boolean reply=FALSE;
/* End CR 1599 */
inp = state->RCV_BUFFER + sizeof(DHCP_HEADER) + 4;
inlen = state->RCV_BUFFER_LEN - sizeof(DHCP_HEADER) - 4;
/* Get the client ID; use CHADDR if none */
cid_ptr = DHCPSRV_find_option(inp, inlen, DHCPOPT_CLIENTID);
if (cid_ptr) {
cid_ptr++;
cid_len = ntohc(cid_ptr);
cid_ptr++;
} else {
DHCP_HEADER_PTR pkt_ptr = (DHCP_HEADER_PTR)state->RCV_BUFFER;
cid_ptr = pkt_ptr->CHADDR;
cid_len = ntohc(pkt_ptr->HLEN);
if (cid_len > sizeof(pkt_ptr->CHADDR)) {
cid_len = sizeof(pkt_ptr->CHADDR);
} /* Endif */
} /* Endif */
/* Get the server ID */
sid_ptr = DHCPSRV_find_option(inp, inlen, DHCPOPT_SERVERID);
if (sid_ptr && ntohc(sid_ptr+1) == DHCPSIZE_SERVERID) {
sid_ptr += 2;
serverid = ntohl(sid_ptr);
} else {
sid_ptr = NULL;
} /* Endif */
/* Get the requested lease */
lease_ptr = DHCPSRV_find_option(inp, inlen, DHCPOPT_LEASE);
if (lease_ptr && ntohc(lease_ptr+1) == DHCPSIZE_LEASE) {
lease_ptr += 2;
lease = ntohl(lease_ptr);
} else {
lease_ptr = NULL;
} /* Endif */
addrp = NULL;
RTCS_mutex_lock(&state->IPLIST_SEM);
if (!addrp) {
addrp = DHCPSRV_find_clientid(&state->IP_LEASED, cid_ptr, cid_len, NULL);
} /* Endif */
if (!addrp && sid_ptr) {
addrp = DHCPSRV_find_clientid(&state->IP_OFFERED, cid_ptr, cid_len, NULL);
} /* Endif */
/* Start CR 2089 */
/* check whether any available address was previously offered/leased to the client */
if (!addrp) {
addrp = DHCPSRV_find_clientid(&state->IP_AVAIL, cid_ptr, cid_len, NULL);
} /* Endif */
/* End CR 2089 */
if (addrp) {
if (sid_ptr && serverid != (*addrp)->OPTIONS->SERVERID) {
reply = FALSE;
addr = DHCPSRV_lease_stop(addrp);
DHCPSRV_lease_start(&state->IP_AVAIL, addr, 0);
} else if (lease_ptr && lease > (*addrp)->OPTIONS->LEASE) {
DHCPSRV_write_header(state, NULL, 0, DHCPTYPE_DHCPNAK);
DHCPSRV_write_end(state);
reply = TRUE;
} else {
if (!lease_ptr) {
lease = (*addrp)->OFFER;
} /* Endif */
DHCPSRV_write_header (state, *addrp, lease, DHCPTYPE_DHCPACK);
DHCPSRV_write_options(state, *addrp);
DHCPSRV_write_end (state);
reply = TRUE;
addr = DHCPSRV_lease_stop(addrp);
DHCPSRV_lease_start(&state->IP_LEASED, addr, lease);
} /* Endif */
} /* Endif */
RTCS_mutex_unlock(&state->IPLIST_SEM);
if (reply) {
DHCPSRV_send(state);
} /* Endif */
} /* Endbody */
/*FUNCTION*-------------------------------------------------------------
*
* Function Name : DHCPSRV_service_release
* Returned Value : void
* Comments : This function services a received DHCPRELEASE
* message.
*
*END*-----------------------------------------------------------------*/
static void DHCPSRV_service_release
(
DHCPSRV_STATE_STRUCT_PTR state
)
{ /* Body */
} /* Endbody */
/*FUNCTION*-------------------------------------------------------------
*
* Function Name : DHCPSRV_service_decline
* Returned Value : void
* Comments : This function services a received DHCPDECLINE
* message.
*
*END*-----------------------------------------------------------------*/
static void DHCPSRV_service_decline
(
DHCPSRV_STATE_STRUCT_PTR state
)
{ /* Body */
} /* Endbody */
/*FUNCTION*-------------------------------------------------------------
*
* Function Name : DHCPSRV_init
* Returned Value : error code
* Comments : Start the DHCP server.
*
*END*-----------------------------------------------------------------*/
uint_32 DHCPSRV_init
(
char_ptr name,
uint_32 priority,
uint_32 stacksize
)
{ /* Body */
return RTCS_task_create(name, priority, stacksize, DHCPSRV_task, NULL);
} /* Endbody */
/*TASK*-----------------------------------------------------------------
*
* Function Name : DHCPSRV_task
* Returned Value :
* Comments : The DHCP server.
*
*END*-----------------------------------------------------------------*/
void DHCPSRV_task
(
pointer dummy,
pointer creator
)
{ /* Body */
DHCPSRV_STATE_STRUCT state;
sockaddr_in addr;
uint_32 timeout;
uchar_ptr msgptr;
uint_32 msglen;
uchar msgtype;
int_32 error;
state.IP_AVAIL = NULL;
state.IP_OFFERED = NULL;
state.IP_LEASED = NULL;
/* Start CR 1547 */
state.IP_TAKEN = NULL;
state.FLAGS = DHCPSVR_FLAG_DO_PROBE;
/* End CR 1547 */
RTCS_mutex_init(&state.IPLIST_SEM);
state.SOCKET = socket(PF_INET, SOCK_DGRAM, 0);
if (state.SOCKET == RTCS_SOCKET_ERROR) {
RTCS_task_exit(creator, RTCSERR_OUT_OF_SOCKETS);
} /* Endif */
addr.sin_family = AF_INET;
addr.sin_port = IPPORT_BOOTPS;
addr.sin_addr.s_addr = INADDR_ANY;
error = bind(state.SOCKET,(sockaddr *)(&addr), sizeof(sockaddr_in));
if (error != RTCS_OK) {
RTCS_task_exit(creator, error);
} /* Endif */
DHCPSRV_cfg = &state;
RTCS_task_resume_creator(creator, RTCS_OK);
for (;;) {
/* Wait for a message */
timeout = DHCPSRV_expire(&state) * 1000;
error = RTCS_selectset(&state.SOCKET, 1, timeout);
if ((error == 0) || (error == RTCS_ERROR)) continue;
/* Received a message, respond accordingly */
error = recvfrom(state.SOCKET, state.RCV_BUFFER, sizeof(state.RCV_BUFFER), 0, NULL, NULL);
if (error == RTCS_ERROR) continue;
/* The datagram must contain at least a header and a magic cookie */
if (error < sizeof(DHCP_HEADER) + DHCPSIZE_MAGIC) continue;
msgptr = state.RCV_BUFFER + sizeof(DHCP_HEADER);
if (ntohl(msgptr) != DHCP_MAGIC) continue;
msgptr += DHCPSIZE_MAGIC;
msglen = error - sizeof(DHCP_HEADER) - DHCPSIZE_MAGIC;
state.RCV_BUFFER_LEN = error;
/* Update the time before starting any new events */
DHCPSRV_expire(&state);
/* Service the packet */
msgtype = DHCPSRV_find_msgtype(msgptr, msglen);
switch (msgtype) {
case DHCPTYPE_DHCPDISCOVER:
DHCPSRV_service_discover(&state);
break;
case DHCPTYPE_DHCPREQUEST:
DHCPSRV_service_request(&state);
break;
case DHCPTYPE_DHCPRELEASE:
DHCPSRV_service_release(&state);
break;
case DHCPTYPE_DHCPDECLINE:
DHCPSRV_service_decline(&state);
break;
} /* Endswitch */
} /* Endwhile */
} /* Endbody */
/* Start CR 1547 */
/*FUNCION*-----------------------------------------------------------------
*
* Function Name : DHCPSRV_set_config_flag_on
* Returned Value : RTCS_OK if all went well
* Comment : turns on the flags passed in
* : May be called anytime after DHCPSRV_init()
* : Flags are defined in dhcpsrv.h and look like :
* : DHCPSVR_FLAG_*
*
*END*-----------------------------------------------------------------*/
static uint_32 DHCPSRV_set_config_flag_on
(
uint_32 flags /* [IN] flags to govern behaviour of dhcp server */
)
{ /* Body */
RTCS_mutex_lock(&DHCPSRV_cfg->IPLIST_SEM);
DHCPSRV_cfg->FLAGS |= flags;
RTCS_mutex_unlock(&DHCPSRV_cfg->IPLIST_SEM);
return RTCS_OK;
} /* Endbody */
/*FUNCTION*-----------------------------------------------------------------
*
* Function Name : DHCPSRV_set_config_flag_off
* Returned Value : RTCS_OK if all went well
* Comment : Turns off the flags passed in
* : May be called anytime after DHCPSRV_init()
* : Flags are defined in dhcpsrv.h and look like :
* : DHCPSVR_FLAG_*
*
*END*-----------------------------------------------------------------*/
static uint_32 DHCPSRV_set_config_flag_off
(
uint_32 flags /* [IN] flags to govern behaviour of dhcp server */
)
{ /* Body */
RTCS_mutex_lock(&DHCPSRV_cfg->IPLIST_SEM);
DHCPSRV_cfg->FLAGS &= !flags;
RTCS_mutex_unlock(&DHCPSRV_cfg->IPLIST_SEM);
return RTCS_OK;
} /* Endbody */
#endif
/* End CR 1547 */
/* EOF */