Files
m241Neelima/components/ip_net2-6.9/ipdhcps/src/ipdhcps_db.c
T
2026-07-30 11:19:44 +05:30

3553 lines
99 KiB
C

/*
******************************************************************************
* INTERPEAK SOURCE FILE
*
* Document no: @(#) $Name: VXWORKS_ITER40_2019102207 $ $RCSfile: ipdhcps_db.c,v $ $Revision: 1.54.10.14 $
* $Source: /home/interpeak/CVSRoot/ipdhcps/src/ipdhcps_db.c,v $
* $Author: jwang9 $
* $State: Exp $ $Locker: $
*
* INTERPEAK_COPYRIGHT_STRING
*
* Design and implementation by Jonas Rendel <jonas@interpeak.se>
******************************************************************************
*/
/*
****************************************************************************
* 1 DESCRIPTION
****************************************************************************
*/
/*
****************************************************************************
* 2 CONFIGURATION
****************************************************************************
*/
#include "ipdhcps_config.h"
/*
****************************************************************************
* 3 INCLUDE FILES
****************************************************************************
*/
#define IPCOM_USE_CLIB_PROTO
#include <ipcom.h>
#include <ipcom_cstyle.h>
#include <ipcom_err.h>
#include <ipcom_os.h>
#include <ipcom_shell.h>
#include <ipcom_sock.h>
#include <ipcom_syslog.h>
#include <ipcom_tmo2.h>
#include <ipcom_type.h>
#include <ipcom_time.h>
#include "ipdhcps.h"
#include "ipdhcps_h.h"
/*
****************************************************************************
* 4 DEFINES
****************************************************************************
*/
/*
*===========================================================================
* Hash callback orders
*===========================================================================
*/
#define IPDHCPS_HASH_CB_ORDER_DELETE (0)
#define IPDHCPS_HASH_CB_ORDER_FIND_HOST (1)
#define IPDHCPS_HASH_CB_ORDER_CHECK_EXPIRY (2)
#define IPDHCPS_HASH_CB_ORDER_UPDATE_OPTION_LIST (3)
/*
*===========================================================================
* Sec -> msec convert macro
*===========================================================================
*/
#define IPDHCPS_MSEC(time) (time * 1000)
/*
****************************************************************************
* 5 TYPES
****************************************************************************
*/
/*
*===========================================================================
* Ipdhcps_host_key_struct
*===========================================================================
* Contains all data needed to create/find a host lease in the lease database
*
*/
typedef struct Ipdhcps_host_key_struct
{
Ipdhcps_subnet *subnet;
Ip_size_t hlen;
Ip_u8 *haddr;
Ip_size_t cid_len;
Ip_u8 *cid;
}
Ipdhcps_host_key;
/*
*===========================================================================
* Ipdhcps_hash_cb_info_struct
*===========================================================================
* Used for passing data in and out from hash callback routines
*/
typedef struct Ipdhcps_hash_cb_info_struct
{
Ip_u32 order; /* Hash callback order */
void* in_data; /* Pointer to data forwarded to callback function */
void* out_data; /* Pointer to data forwarded from callback function */
}
Ipdhcps_hash_cb_info;
/*
*===========================================================================
* Ipdhcps_subnet_find_struct
*===========================================================================
* Used for passing data in and out from subnet hash table
*/
typedef struct Ipdhcps_subnet_find_info_struct
{
Ip_u32 addr;
Ip_bool found;
Ipdhcps_subnet *subnet;
}
Ipdhcps_subnet_find_info;
/*
*===========================================================================
* Ipdhcps_host_lease_find_struct
*===========================================================================
* Used for passing data in and out from lease hash table
*/
typedef struct Ipdhcps_host_lease_find_info_struct
{
Ip_u32 addr;
Ip_bool found;
}
Ipdhcps_host_lease_find_info;
/*
*===========================================================================
* Ipdhcps_class_find_id_struct
*===========================================================================
* Used for searching the class hash tables.
*/
typedef struct Ipdhcps_class_find_id_struct
{
char *name;
Ipdhcps_class *client_class;
}
Ipdhcps_class_find_id;
/*
****************************************************************************
* 6 EXTERN PROTOTYPES
****************************************************************************
*/
IP_EXTERN Ipdhcps_data ipdhcpsc;
IP_EXTERN const char *ipdhcps_binding_state_str[];
/*
****************************************************************************
* 7 LOCAL PROTOTYPES
****************************************************************************
*/
IP_STATIC void ipdhcps_list_init(Ipdhcps_list *head);
IP_STATIC void ipdhcps_list_remove_from(void *entry);
IP_STATIC void ipdhcps_list_add_to(void *h, void *entry);
IP_STATIC void ipdhcps_lease_table_free(Ipcom_hash *ht);
IP_STATIC void ipdhcps_lease_table_cb(Ipdhcps_lease *l, Ipdhcps_hash_cb_info *info);
IP_STATIC unsigned ipdhcps_do_hash(Ip_size_t len, Ip_u8 *data);
IP_STATIC Ip_err ipdhcps_subnet_do_delete(Ipdhcps_subnet *s);
IP_STATIC void ipdhcps_subnet_delete_cb(Ipdhcps_subnet *s, void *data);
IP_STATIC Ipdhcps_subnet *ipdhcps_subnet_new(Ip_u32 subnet);
IP_STATIC unsigned ipdhcps_subnet_hash(Ipdhcps_subnet* s);
IP_STATIC unsigned ipdhcps_subnet_key_hash(Ip_u32 *key);
IP_STATIC Ip_bool ipdhcps_subnet_match(Ipdhcps_subnet *s, Ip_u32 *key);
IP_STATIC void ipdhcps_interface_subnet_map(Ipdhcps_subnet *subnet);
IP_STATIC unsigned ipdhcps_host_hash(Ipdhcps_host *host);
IP_STATIC Ipdhcps_host* ipdhcps_host_new(Ip_u32 inaddr,
Ip_size_t hwa_len,
Ip_u8 *hwaddr,
Ip_size_t cid_len,
Ip_u8 *cid);
IP_STATIC Ip_err ipdhcps_host_do_delete(Ipdhcps_host *h);
IP_STATIC void ipdhcps_host_delete_cb(Ipdhcps_host *h, void *data);
IP_STATIC void ipdhcps_option_set_do_delete(Ipdhcps_option *o, Ipdhcps_node *node);
IP_STATIC unsigned ipdhcps_lease_hash(void *obj);
IP_STATIC unsigned ipdhcps_host_key_hash(Ip_u32 *key);
IP_STATIC Ip_bool ipdhcps_host_lease_match(void *obj, void* key);
IP_STATIC Ip_err ipdhcps_pool_do_delete(Ipdhcps_pool *p);
IP_STATIC Ip_err ipdhcps_pool_new(Ipdhcps_subnet *s,
Ipdhcps_list *head,
Ip_u32 addr_min,
Ip_u32 addr_max,
char *classname);
IP_STATIC unsigned ipdhcps_class_hash(Ipdhcps_class *c);
IP_STATIC Ip_err ipdhcps_class_new(Ipdhcps_subnet *s,
Ipdhcps_classinfo *client_class);
IP_STATIC Ip_bool ipdhcps_pool_config_sane(Ipdhcps_list *head,
Ip_u32 addr_min,
Ip_u32 arr_max);
IP_STATIC Ip_err ipdhcps_option_set_add(Ipdhcps_node *node, Ip_u8 *options, Ip_u16 type);
IP_STATIC void ipdhcps_host_lease_cmp(Ipdhcps_lease *l, Ipdhcps_host_lease_find_info *info);
/*
****************************************************************************
* 8 DATA
****************************************************************************
*/
IP_STATIC char logbuf[50];
/*
****************************************************************************
* 9 STATIC FUNCTIONS
****************************************************************************
*/
/*
*===========================================================================
* ipdhcps_lease_table_cb
*===========================================================================
* Description: Common hash table callback function.
*
* Parameters: obj - pointer to hash object.
* data - pointer to hash callback info struct
*
* Returns: -
*
*/
IP_STATIC void
ipdhcps_lease_table_cb(Ipdhcps_lease *l,Ipdhcps_hash_cb_info *info)
{
Ip_u32 now;
switch(info->order)
{
case IPDHCPS_HASH_CB_ORDER_DELETE:
(void)ipdhcps_lease_delete(l);
break;
case IPDHCPS_HASH_CB_ORDER_FIND_HOST:
if(*(Ip_u32*)(info->in_data) == l->yiaddr)
info->out_data = l;
break;
case IPDHCPS_HASH_CB_ORDER_CHECK_EXPIRY:
now = (Ip_u32)ipcom_time(0);
if(now >= (Ip_u32)l->expires)
{
if(l->binding_state == IPDHCPS_BINDING_STATE_ACTIVE)
{
/* This lease has expired */
l->binding_state = IPDHCPS_BINDING_STATE_EXPIRED;
/* Avoid overflow */
if(now > now + ipdhcpsc.config.in_expired_state_max_time)
now = 0;
l->expires = now + ipdhcpsc.config.in_expired_state_max_time;
}
else if((l->binding_state == IPDHCPS_BINDING_STATE_ABANDONED) ||
(l->binding_state == IPDHCPS_BINDING_STATE_OFFERED) ||
(l->binding_state == IPDHCPS_BINDING_STATE_RELEASED) ||
(l->binding_state == IPDHCPS_BINDING_STATE_EXPIRED) ||
(l->binding_state == IPDHCPS_BINDING_STATE_BOOTP))
{
/* This lease can be used again. Release it.*/
IPCOM_LOG2(DEBUG,
"ipdhcps_daemon :: freeing %s lease with address %s",
ipdhcps_binding_state_str[l->binding_state],
ipcom_inet_ntop(IP_AF_INET,
&l->yiaddr,
logbuf,
sizeof(logbuf)));
(void)ipdhcps_lease_delete(l);
}
}
break;
default:
break;
}
}
/*
*===========================================================================
* ipdhcps_lease_table_free
*===========================================================================
* Description: Releases all elements in a hash table and finally frees
* the hash table itself
*
* Parameters: ht - Pointer to hash table.
* Returns: -
*
*/
IP_STATIC void
ipdhcps_lease_table_free(Ipcom_hash* ht)
{
Ipdhcps_hash_cb_info info;
info.order = IPDHCPS_HASH_CB_ORDER_DELETE;
ipcom_hash_for_each(ht,
(Ipcom_hash_foreach_cb_func)ipdhcps_lease_table_cb,
&info);
ipcom_hash_delete(ht);
}
/*
*===========================================================================
* ipdhcps_list_init
*===========================================================================
* Description: Initiates an linked list used by IPDHCPS
* Parameters: head - pointer to list head
* Returns: -
*
*/
IP_STATIC void
ipdhcps_list_init(Ipdhcps_list *head)
{
head->next = IP_NULL;
head->prev = IP_NULL;
}
/*
*===========================================================================
* ipdhcps_list_remove_from
*===========================================================================
* Description: Removes an entry from a linked list used by IPDHCPS.
*
* Parameters: entry p- pointer to entry in list.
* Returns: -
*
*/
IP_STATIC void
ipdhcps_list_remove_from(void *entry)
{
Ipdhcps_list *node =(Ipdhcps_list*) entry;
if(node->prev != IP_NULL)
node->prev->next = node->next;
if(node->next != IP_NULL)
node->next->prev = node->prev;
}
/*
*===========================================================================
* ipdhcps_list_add_to
*===========================================================================
* Description: Adds an entry to a linked list used by IPDHCPS.
*
* Parameters: h - pointer to list head
* entry - pointer to list entry
* Returns: -
*
*/
IP_STATIC void
ipdhcps_list_add_to(void *h,
void *entry)
{
Ipdhcps_list *head =(Ipdhcps_list*)h;
Ipdhcps_list *node =(Ipdhcps_list*)entry;
node->next = head->next;
node->prev = head;
if(node->next != IP_NULL)
node->next->prev = entry;
if(node->prev != IP_NULL)
node->prev->next = entry;
}
/*
*===========================================================================
* ipdhcps_host_hash
*===========================================================================
* Description: Hash calculation routine for hashing subnets.
* Parameters: obj - pointer to subnet descriptor.
* Returns: hash result
*
*/
IP_STATIC unsigned
ipdhcps_host_hash(Ipdhcps_host *host)
{
return(unsigned)(host->lease.yiaddr);
}
/*
*===========================================================================
* ipdhcps_host_key_hash
*===========================================================================
* Description: Hash calculation routine for hashing subnet keys.
* Parameters: obj - pointer to key descriptor.
* Returns: hash result
*
*/
IP_STATIC unsigned
ipdhcps_host_key_hash(Ip_u32 *key)
{
return(unsigned) *key;
}
/*
*===========================================================================
* ipdhcps_host_match
*===========================================================================
* Description: Host to key match routine. Called when searching for a
* host in host database.
*
* Parameters: obj - pointer to subnet descriptor
* key - pointer to key(ip address)
*
* Returns: IP_TRUE - match
* IP_FALSE - no match
*/
IP_STATIC Ip_bool
ipdhcps_host_match(Ipdhcps_host *host, Ip_u32 *key)
{
if (host->lease.yiaddr == *key)
return IP_TRUE;
else
return IP_FALSE;
}
/*
*===========================================================================
* ipdhcps_host_do_delete
*===========================================================================
* Description: Host destructor/checkout callback. Removes the host
* descriptor from the database and releases all its allocated
* resources.
*
* Parameters: obj - pointer to subnet descriptor.
*
* Returns: IPCOM_SUCCESS - success
* other - failure
*
*/
IP_STATIC Ip_err
ipdhcps_host_do_delete(Ipdhcps_host *h)
{
Ip_err retval;
Ipdhcps_pool *p;
Ipdhcps_subnet* subnet= IP_NULL;
Ip_u32 req_addr=0;
/* Remove from hash table */
retval = ipcom_hash_remove(ipdhcpsc.host_head, h);
req_addr = h->lease.yiaddr;
/* Remove from lease data base */
ipdhcps_lease_delete(&h->lease);
subnet = ipdhcps_subnet_find_matching(req_addr);
if(subnet != IP_NULL)
{
req_addr = ip_ntohl(req_addr);
IPDHCPS_LIST_FOREACH(p, (&subnet->pools), Ipdhcps_pool*)
{
if((req_addr <= p->yiaddr_max) && (req_addr >= p->yiaddr_min))
{
p->leases[req_addr - p->yiaddr_min]->binding_state = IPDHCPS_BINDING_STATE_FREE;
}
}
}
if(retval == IPCOM_SUCCESS)
{
/* Delete this record and all its resources */
if (h->node.option_head != IP_NULL)
{
ipcom_hash_for_each(h->node.option_head,
(Ipcom_hash_foreach_cb_func)ipdhcps_option_set_do_delete,
&h->node);
ipcom_hash_delete(h->node.option_head);
}
ipcom_free(h);
}
return retval;
}
/*
*===========================================================================
* ipdhcps_host_delete_cb
*===========================================================================
* Description:
*
* Parameters: h - host descriptor.
* data - not used.
*
* Returns:
*
*/
IP_STATIC void
ipdhcps_host_delete_cb(Ipdhcps_host *h, void *data)
{
(void)data;
(void)ipdhcps_host_do_delete(h);
}
/*
*===========================================================================
* ipdhcps_host_new
*===========================================================================
* Description: Host descriptor contructor function.
*
* Parameters: inaddr - IP address of host.
* hwa_len - lenght of hosts link layer address
* hwaddr - pointer to hosts link layer address
* cid_len - length of host client identifier
* cid - pointer to client identifier
*
* Returns: pointer to host descriptor - success
* IP_NULL - failure
*/
IP_STATIC Ipdhcps_host *
ipdhcps_host_new(Ip_u32 inaddr, Ip_size_t hwa_len, Ip_u8 *hwaddr, Ip_size_t cid_len, Ip_u8 *cid)
{
Ipdhcps_host *h;
Ipdhcps_pool *p;
Ipdhcps_subnet* subnet= IP_NULL;
Ip_u32 req_addr=0;
h = ipcom_malloc(sizeof(Ipdhcps_host));
if(h != IP_NULL)
{
ipcom_memset(h, 0, sizeof(Ipdhcps_host));
if(cid != IP_NULL)
{
if (cid[0] == '\\' && cid[1] == '0')
{
cid_len--;
cid++;
cid[0] = '\0';
}
/* Allocate space for a user identifier */
h->lease.cid = ipcom_malloc(cid_len + 1);
if(h->lease.cid == IP_NULL)
{
ipcom_free(h);
return (Ipdhcps_host*)IP_NULL;
}
ipcom_memcpy(h->lease.cid, cid, cid_len);
h->lease.cid[cid_len] = 0;
h->lease.cid_len = cid_len;
}
/* Init remaining parts of host lease descriptor */
ipcom_memcpy(h->lease.chaddr.haddr, hwaddr, hwa_len);
h->lease.chaddr.hlen = hwa_len;
h->lease.yiaddr = inaddr;
h->lease.binding_state = IPDHCPS_BINDING_STATE_PERMANENT;
h->lease.lease_time = (Ip_time_t)IPDHCPS_LEASE_TIME_PERMANENT;
h->lease.parent = &h->node;
/* Attach host to host list*/
if (ipdhcpsc.host_head == IP_NULL)
{
ipdhcpsc.host_head = ipcom_hash_new((Ipcom_hash_obj_func)ipdhcps_host_hash,
(Ipcom_hash_key_func)ipdhcps_host_key_hash,
(Ipcom_hash_cmp_func)ipdhcps_host_match);
if (ipdhcpsc.host_head == IP_NULL)
{
ipcom_free(h);
return IP_NULL;
}
}
ipcom_hash_add(ipdhcpsc.host_head, h);
/* Add to permanent lease to database */
ipdhcps_lease_add(&h->lease);
req_addr = ip_ntohl(inaddr);
subnet = ipdhcps_subnet_find_matching(inaddr);
if(subnet != IP_NULL)
{
IPDHCPS_LIST_FOREACH(p, (&subnet->pools), Ipdhcps_pool*)
{
if((req_addr <= p->yiaddr_max) && (req_addr >= p->yiaddr_min))
{
p->leases[req_addr - p->yiaddr_min]->binding_state = IPDHCPS_BINDING_STATE_PERMANENT;
}
}
}
}
return h;
}
/*
*===========================================================================
* ipdhcps_do_hash
*===========================================================================
* Description: Common hash calculation routine used when hashing leases
*
* Parameters: len - length of key to hash
* data - key to hash
*
* Returns: hash result
*
*/
IP_STATIC unsigned
ipdhcps_do_hash(Ip_size_t len, Ip_u8 *data)
{
Ip_size_t i;
unsigned result = 0;
for(i = 0; i < len; i++)
result = result * 32 + (unsigned)data[i];
return result;
}
/*
*===========================================================================
* ipdhcps_lease_hash
*===========================================================================
* Description: Lease hash routine. Determines if to hash on client
* identifier or link layer address.
*
* Parameters: obj - Pointer to lease
*
* Returns: hash result
*/
IP_STATIC unsigned
ipdhcps_lease_hash(void *obj)
{
Ipdhcps_lease *lease = (Ipdhcps_lease*)obj;
unsigned result;
if(lease->cid != IP_NULL)
{
/* Create hash value based on client identifier */
result = ipdhcps_do_hash(lease->cid_len, lease->cid);
}
else
{
/* Create hash value based on hwaddr */
result = ipdhcps_do_hash(lease->chaddr.hlen, lease->chaddr.haddr);
}
return(result);
}
/*
*===========================================================================
* ipdhcps_lease_key_hash
*===========================================================================
* Description: Lease key hash routine. Generates a hash value based on
* client identifier or link layer address.
*
* Parameters: key - pointer to host key structure
*
* Returns: hash result
*/
IP_STATIC unsigned
ipdhcps_host_lease_key_hash(Ipdhcps_host_key *k)
{
unsigned result;
if(k->cid != IP_NULL)
{
/* Create hash value based on client identifier */
result = ipdhcps_do_hash(k->cid_len, k->cid);
}
else
{
/* Create hash value based on hwaddr */
result = ipdhcps_do_hash(k->hlen, k->haddr);
}
return (result);
}
/*
*===========================================================================
* ipdhcps_host_lease_match
*===========================================================================
* Description: Lease to host matching routine. Called when searching for
* a lease in the lease database.
* Verifies that:
* 1. lease is not abandoned
* 2. cid of key and lease is the same
* and/or
* 3. link layer address of key and lease is the same
* 4. lease IP address is on the same subnet as
* calling client.
*
* Parameters: obj - pointer to lease descriptor.
* key - pointer to host key descriptor.
*
* Returns: IP_TRUE - key and lease matches
* IP_FALSE - key and lease do not match
*
*/
IP_STATIC Ip_bool
ipdhcps_host_lease_match(void *obj, void* key)
{
Ip_bool retval;
Ip_u32 mask = 0;
Ipdhcps_host_key *k = (Ipdhcps_host_key*)key;
Ipdhcps_lease *lease = (Ipdhcps_lease*)obj;
Ipdhcps_option *o;
if(lease->binding_state == IPDHCPS_BINDING_STATE_ABANDONED)
IPDHCPS_LEAVE(IP_FALSE);
if(k->cid_len != lease->cid_len)
IPDHCPS_LEAVE(IP_FALSE);
if(k->cid_len > 0)
{
/* Do a user id verification */
if(ipcom_memcmp(k->cid, lease->cid, k->cid_len) != 0)
IPDHCPS_LEAVE(IP_FALSE);
if((k->hlen > 0) &&(lease->chaddr.hlen > 0))
{
/* Do a hw address verification too */
if(ipcom_memcmp(k->haddr, lease->chaddr.haddr, k->hlen) != 0)
IPDHCPS_LEAVE(IP_FALSE);
}
}
else if(k->hlen > 0)
{
/* Try a hw address verification instead*/
if(k->hlen != lease->chaddr.hlen)
IPDHCPS_LEAVE(IP_FALSE);
/* Do a hw address verification */
if(ipcom_memcmp(k->haddr, lease->chaddr.haddr, k->hlen) != 0)
IPDHCPS_LEAVE(IP_FALSE);
}
else
{
/* Nothing to verify on */
IPDHCPS_LEAVE(IP_FALSE);
}
/* So, far we have a match. Check if we have a subnet descriptor */
if(ipdhcpsc.config.no_strict_subnet_match == IP_FALSE && (k->subnet != IP_NULL) &&(k->subnet != ipdhcpsc.default_net))
{
o = ipdhcps_option_set_find(&k->subnet->node, IPDHCPS_OPTCODE_SUBNET_MASK);
if(o != IP_NULL)
ipcom_memcpy(&mask, &o->opt[IPDHCPS_OPT_DATA], o->opt[IPDHCPS_OPT_LEN]);
/* Check if the host address is on this subnet */
if((lease->yiaddr & mask) != k->subnet->addr)
IPDHCPS_LEAVE(IP_FALSE);
}
/* We have a match */
retval = IP_TRUE;
leave:
return retval;
}
/*
*===========================================================================
* ipdhcps_class_hash
*===========================================================================
* Description: Hash calculation routine for hashing classes.
* Parameters: obj - pointer to subnet descriptor.
* Returns: hash result
*
*/
IP_STATIC unsigned
ipdhcps_class_hash(Ipdhcps_class *c)
{
return ipcom_hash_update(c->data, IPDHCPS_OPT_TOTAL_LEN(c->data[IPDHCPS_OPT_LEN]), 0);
}
/*
*===========================================================================
* ipdhcps_class_key_hash
*===========================================================================
* Description: Hash calculation routine for hashing class keys.
* Parameters: key - pointer to key descriptor.
* Returns: hash result
*
*/
IP_STATIC unsigned
ipdhcps_class_key_hash(Ip_u8 *key)
{
return ipcom_hash_update(key, IPDHCPS_OPT_TOTAL_LEN(key[IPDHCPS_OPT_LEN]), 0);
}
/*
*===========================================================================
* ipdhcps_class_match
*===========================================================================
* Description: Class to key match routine. Called when searching for a
* class in class database.
*
* Parameters: class - pointer to class descriptor
* key - pointer to key
*
* Returns: IP_TRUE - match
* IP_FALSE - no match
*/
IP_STATIC Ip_bool
ipdhcps_class_match(Ipdhcps_class *c, char *key)
{
if (ipcom_memcmp(c->data, key,IPDHCPS_OPT_TOTAL_LEN(key[IPDHCPS_OPT_LEN])) == 0)
return IP_TRUE;
else
return IP_FALSE;
}
/*
*===========================================================================
* ipdhcps_subnet_do_delete
*===========================================================================
* Description: Subnet destructor/checkout callback. Removes the subnet
* descriptor from the database and releases all its allocated
* resources.
*
* Parameters: obj - pointer to subnet descriptor.
*
* Returns: IPCOM_SUCCESS - success
* other - failure
*
*/
IP_STATIC Ip_err
ipdhcps_subnet_do_delete(Ipdhcps_subnet *s)
{
Ip_err retval;
Ipdhcps_pool *p, *p_next;
Ipdhcps_if *i;
if(s != IP_NULL)
{
/* Remove from hash table */
retval = ipcom_hash_remove(ipdhcpsc.subnet_head, s);
if(retval == IPCOM_SUCCESS)
{
/* Delete this record and all its resources */
if (s->node.option_head != IP_NULL)
{
ipcom_hash_for_each(s->node.option_head,
(Ipcom_hash_foreach_cb_func)ipdhcps_option_set_do_delete,
&s->node);
ipcom_hash_delete(s->node.option_head);
}
for (p = (Ipdhcps_pool*)s->pools.next; p != IP_NULL; p = p_next)
{
p_next = (Ipdhcps_pool*)p->node.next;
ipdhcps_pool_do_delete(p);
}
IPDHCPS_LIST_FOREACH(i, (&ipdhcpsc.if_head), Ipdhcps_if*)
{
if (i->local_subnet == s)
i->local_subnet = ipdhcpsc.default_net;
}
ipcom_free(s);
}
}
else
retval = IPCOM_ERR_FAILED;
return retval;
}
/*
*===========================================================================
* ipdhcps_subnet_delete_cb
*===========================================================================
* Description:
*
* Parameters: h - subnet descriptor.
* data - not used.
*
* Returns:
*
*/
IP_STATIC void
ipdhcps_subnet_delete_cb(Ipdhcps_subnet *s, void *data)
{
(void)data;
(void)ipdhcps_subnet_do_delete(s);
}
/*
*===========================================================================
* ipdhcps_subnet_new
*===========================================================================
* Description: Subnet constructor routine.
* Parameters: subnet - subnet address.
* Returns: pointer to subnet descriptor.
*
*/
IP_STATIC Ipdhcps_subnet *
ipdhcps_subnet_new(Ip_u32 subnet)
{
Ipdhcps_subnet *s;
s = ipcom_calloc(1, sizeof(Ipdhcps_subnet));
if(s != IP_NULL)
{
s->addr = subnet;
ipdhcps_list_init(&s->pools);
}
return s;
}
/*
*===========================================================================
* ipdhcps_pool_find
*===========================================================================
* Description: Search routine to find a certain address pool in a
* certain pool list.
*
* Parameters: head - pool list head
* addr_min - first address in pool
* addr_max - last address in pool
*
* Returns: pointer to pool descriptor - found
* IP_NULL - not found
*
*/
IP_STATIC Ipdhcps_pool*
ipdhcps_pool_find(Ipdhcps_list *head, Ip_u32 addr_min, Ip_u32 addr_max)
{
Ipdhcps_pool *p;
IPDHCPS_LIST_FOREACH(p, head, Ipdhcps_pool*)
if((p->yiaddr_min == addr_min) && (p->yiaddr_max == addr_max))
break;
return (p);
}
/*
*===========================================================================
* ipdhcps_class_search_name
*===========================================================================
* Description: Callback search routine to find a certain class.
*
* Parameters: class - class descriptor
* id - identification data
*
* Returns: pointer to pool descriptor - found
* IP_NULL - not found
*
*/
IP_STATIC void
ipdhcps_class_search_name(Ipdhcps_class *client_class, Ipdhcps_class_find_id *id)
{
if (id->client_class == IP_NULL)
{
if (ipcom_strcmp(client_class->name, id->name) == 0)
id->client_class = client_class;
}
}
/*
*===========================================================================
* ipdhcps_pool_config_sane
*===========================================================================
* Description: Checks if a an address pool specified by first and last
* address is ok and does not overlap existing pools in
* in a certain list of pools.
*
* Parameters: head - pointer to pool list head
* addr_min - first address
* addr_max - last address
*
* Returns: IP_TRUE - ok
* IP_FALSE - not ok
*/
IP_STATIC Ip_bool
ipdhcps_pool_config_sane(Ipdhcps_list *head, Ip_u32 addr_min, Ip_u32 addr_max)
{
Ipdhcps_pool *p;
/* Is the range sane? */
if(addr_max < addr_min)
return IP_FALSE;
/* Check for pool with overlapping address range */
IPDHCPS_LIST_FOREACH(p, head, Ipdhcps_pool*)
if(((addr_min >= p->yiaddr_min) && (addr_min <= p->yiaddr_max))
|| ((addr_max >= p->yiaddr_min) && (addr_max <= p->yiaddr_max)))
return IP_FALSE;
return IP_TRUE;
}
/*
*===========================================================================
* ipdhcps_pool_do_delete
*===========================================================================
* Description: Pool destructor/checkout callback.
* Parameters: p - pointer to pool descriptor.
*
* Returns: IPCOM_SUCCESS - success
* other - failure
*/
IP_STATIC Ip_err
ipdhcps_pool_do_delete(Ipdhcps_pool *p)
{
Ip_u32 i;
/* Remove pool from list*/
ipdhcps_list_remove_from(p);
/* Destroy lease records */
for(i = 0; i <= (p->yiaddr_max - p->yiaddr_min); i++)
{
/* Deregister from lease database */
ipdhcps_lease_delete(p->leases[i]);
ipcom_free(p->leases[i]);
}
if (p->class_id != IP_NULL)
ipcom_free(p->class_id);
ipcom_free(p);
return IPCOM_SUCCESS;
}
/*
*===========================================================================
* ipdhcps_pool_new
*===========================================================================
* Description: Pool constructor routine.
*
* Parameters: s - pointer to subnet on which to attach pool
* head - pointer to pool list head
* addr_min - first address in pool
* addr_max - last address in pool
*
* Returns: IPCOM_SUCCESS - success
* other - failure
*/
IP_STATIC Ip_err
ipdhcps_pool_new(Ipdhcps_subnet *s,
Ipdhcps_list *head,
Ip_u32 addr_min,
Ip_u32 addr_max,
char *classname)
{
Ip_err retval;
Ip_u32 i;
Ip_u32 range;
Ipdhcps_pool *p;
/* Range of addresses from first to last, inclusive */
range = addr_max - addr_min + 1;
/* Allocate pool descriptor w. extra space for lease array */
p = ipcom_calloc(1, sizeof(Ipdhcps_pool) + (range * sizeof(Ipdhcps_lease*)));
if(p == IP_NULL)
IPDHCPS_LEAVE(IPCOM_ERR_NO_MEMORY);
p->yiaddr_min = addr_min;
p->yiaddr_max = addr_max;
if (classname != IP_NULL)
{
Ipdhcps_class *c = ipdhcps_class_find_by_name(s, classname);
if (c == IP_NULL)
IPDHCPS_LEAVE(IPCOM_ERR_NOT_FOUND);
p->class_id = ipcom_malloc(IPDHCPS_OPT_TOTAL_LEN(c->data[IPDHCPS_OPT_LEN]));
if (p->class_id == IP_NULL)
IPDHCPS_LEAVE(IPCOM_ERR_NO_MEMORY);
ipcom_memcpy(p->class_id, c->data, IPDHCPS_OPT_TOTAL_LEN(c->data[IPDHCPS_OPT_LEN]));
}
/* Setup lease descriptors */
for(i = 0; i <= range; i++)
{
p->leases[i] = ipcom_malloc(sizeof(Ipdhcps_lease));
if(p->leases[i] == IP_NULL)
IPDHCPS_LEAVE(IPCOM_ERR_NO_MEMORY);
ipcom_memset(p->leases[i], 0, sizeof(Ipdhcps_lease));
p->leases[i]->yiaddr = ip_htonl(p->yiaddr_min + i);
p->leases[i]->parent = &s->node;
}
/* Attach pool first in pool list*/
ipdhcps_list_add_to(head, p);
retval = IPCOM_SUCCESS;
leave:
if((retval != IPCOM_SUCCESS) && (p != IP_NULL))
{
/* Release memory on failure*/
/* fix the coverity defect no use to if(p->leases != IP_NULL) */
{
for(i = 0; i <= range; i++)
{
if(p->leases[i] != IP_NULL)
ipcom_free(p->leases[i]);
}
}
ipcom_free(p);
}
return retval;
}
/*
*===========================================================================
* ipdhcps_class_do_delete
*===========================================================================
* Description: Pool destructor/checkout callback.
* Parameters: p - pointer to pool descriptor.
*
* Returns: IPCOM_SUCCESS - success
* other - failure
*/
IP_STATIC Ip_err
ipdhcps_class_do_delete(Ipdhcps_class *c, Ipcom_hash *head)
{
ipcom_hash_remove(head, c);
ipcom_free(c->name);
ipcom_free(c->data);
ipcom_free(c->priv_data);
if (c->node.option_head != IP_NULL)
{
ipcom_hash_for_each(c->node.option_head,
(Ipcom_hash_foreach_cb_func)ipdhcps_option_set_do_delete,
&c->node);
ipcom_hash_delete(c->node.option_head);
}
ipcom_free(c);
return IPCOM_SUCCESS;
}
/*
*===========================================================================
* ipdhcps_class_new
*===========================================================================
* Description: Class constructor routine.
*
* Parameters: s - pointer to subnet on which to attach pool
* client_class - class information passed from user
*
* Returns: IPCOM_SUCCESS - success
* other - failure
*/
IP_STATIC Ip_err
ipdhcps_class_new(Ipdhcps_subnet *s,
Ipdhcps_classinfo *client_class)
{
Ip_err retval;
Ipdhcps_class *c = IP_NULL;
char *classname = IP_NULL;
Ip_bool is_string = IP_FALSE;
Ip_u8 *data = IP_NULL;
if (IP_NULL == client_class)
IPDHCPS_LEAVE(IPCOM_ERR_INVALID_ARG);
classname = client_class->name;
is_string = client_class->data_is_string;
data = client_class->data;
if ((classname == IP_NULL) || (data == IP_NULL))
IPDHCPS_LEAVE(IPCOM_ERR_INVALID_ARG);
c = ipcom_calloc(1, sizeof(Ipdhcps_class));
if(c == IP_NULL)
IPDHCPS_LEAVE(IPCOM_ERR_NO_MEMORY);
c->name = ipcom_strdup(classname);
c->data = ipcom_malloc((Ip_size_t)IPDHCPS_OPT_TOTAL_LEN(data[IPDHCPS_OPT_LEN]));
c->data_is_string = is_string;
if (client_class->priv_data_len)
{
c->priv_data = ipcom_calloc(1, client_class->priv_data_len);
if (IP_NULL == c->priv_data)
IPDHCPS_LEAVE(IPCOM_ERR_NO_MEMORY);
}
if (c->data == IP_NULL)
IPDHCPS_LEAVE(IPCOM_ERR_NO_MEMORY);
ipcom_memcpy(c->data, data, (Ip_size_t)IPDHCPS_OPT_TOTAL_LEN(data[IPDHCPS_OPT_LEN]));
if (s->class_head == IP_NULL)
{
s->class_head = ipcom_hash_new((Ipcom_hash_obj_func)ipdhcps_class_hash,
(Ipcom_hash_key_func)ipdhcps_class_key_hash,
(Ipcom_hash_cmp_func)ipdhcps_class_match);
if (s->class_head == IP_NULL)
IPDHCPS_LEAVE(IPCOM_ERR_NO_MEMORY);
}
else
{
if (ipdhcps_class_find_by_name(s, classname) != IP_NULL)
IPDHCPS_LEAVE(IPCOM_ERR_ALREADY_INSTALLED);
if (ipdhcps_class_find_by_id(s, c->data) != IP_NULL)
IPDHCPS_LEAVE(IPCOM_ERR_ALREADY_INSTALLED);
}
ipcom_hash_add(s->class_head, c);
return IPCOM_SUCCESS;
leave:
if (c != IP_NULL)
{
if (c->name != IP_NULL)
ipcom_free(c->name);
if (c->data)
ipcom_free(c->data);
ipcom_free(c);
}
return retval;
}
/*
*===========================================================================
* ipdhcps_subnet_hash
*===========================================================================
* Description: Hash calculation routine for hashing subnets.
* Parameters: obj - pointer to subnet descriptor.
* Returns: hash result
*
*/
IP_STATIC unsigned
ipdhcps_subnet_hash(Ipdhcps_subnet *s)
{
return (unsigned)s->addr;
}
/*
*===========================================================================
* ipdhcps_subnet_key_hash
*===========================================================================
* Description: Hash calculation routine for hashing subnet keys.
* Parameters: obj - pointer to key descriptor.
* Returns: hash result
*
*/
IP_STATIC unsigned
ipdhcps_subnet_key_hash(Ip_u32 *key)
{
return (unsigned) *key;
}
/*
*===========================================================================
* ipdhcps_subnet_match
*===========================================================================
* Description: Subnet to key match routine. Called when searching for a
* subnet in subnet database.
* If ip address in key masked with current subnet mask equals
* current subnet address we have a match.
*
* Parameters: obj - pointer to subnet descriptor
* key - pointer to key(ip address)
*
* Returns: IP_TRUE - match
* IP_FALSE - no match
*/
IP_STATIC Ip_bool
ipdhcps_subnet_match(Ipdhcps_subnet *s, Ip_u32 *addr)
{
if(s->addr == *addr)
return IP_TRUE;
else
return IP_FALSE;
}
/*
*===========================================================================
* ipdhcps_subnet_cmp
*===========================================================================
* Description: Host address to subnet compar routine. Called when searching
* for a matching subnet in subnet database.
*
* Parameters: s - pointer to subnet descriptor
* info - pointer to search info
*
* Returns:
*/
IP_STATIC void
ipdhcps_subnet_cmp(Ipdhcps_subnet *s, Ipdhcps_subnet_find_info *info)
{
Ip_u32 mask = 0;
Ipdhcps_option *o;
if (info->found == IP_TRUE)
return;
if (s->addr == IP_INADDR_ANY)
return;
o = ipdhcps_option_set_find(&s->node, IPDHCPS_OPTCODE_SUBNET_MASK);
if(o != IP_NULL)
ipcom_memcpy(&mask, &o->opt[IPDHCPS_OPT_DATA], o->opt[IPDHCPS_OPT_LEN]);
if((s->addr == (info->addr & mask)))
{
info->found = IP_TRUE;
info->subnet = s;
}
}
/*
*===========================================================================
* ipdhcps_host_lease_cmp
*===========================================================================
* Description: Compare routine for checking if host address exists in lease
* database.
*
* Parameters: l - pointer to lease descriptor
* info - pointer to search info
*
* Returns:
*/
IP_STATIC void
ipdhcps_host_lease_cmp(Ipdhcps_lease *l, Ipdhcps_host_lease_find_info *info)
{
if (info->found == IP_TRUE)
return;
if (l->yiaddr == info->addr)
info->found = IP_TRUE;
}
/*
*===========================================================================
* ipdhcps_option_hash
*===========================================================================
* Description: Hash calculation routine for hashing subnets.
* Parameters: obj - pointer to subnet descriptor.
* Returns: hash result
*
*/
IP_STATIC unsigned
ipdhcps_option_hash(Ipdhcps_option *o)
{
return(unsigned)(o->code);
}
/*
*===========================================================================
* ipdhcps_option_key_hash
*===========================================================================
* Description: Hash calculation routine for hashing subnet keys.
* Parameters: obj - pointer to key descriptor.
* Returns: hash result
*
*/
IP_STATIC unsigned
ipdhcps_option_key_hash(Ip_u16 *key)
{
return (unsigned) *key;
}
/*
*===========================================================================
* ipdhcps_option_match
*===========================================================================
* Description: Option to key match. Called when searching for an
* option in a option hash table.
*
* Parameters: obj - pointer to option descriptor
* key - pointer to key (option code)
*
* Returns: IP_TRUE - match
* IP_FALSE - no match
*/
IP_STATIC Ip_bool
ipdhcps_option_match(Ipdhcps_option *o, Ip_u16 *key)
{
if(o->code == *key)
return IP_TRUE;
else
return IP_FALSE;
}
/*
*===========================================================================
* ipdhcps_option_do_delete
*===========================================================================
* Description: A "for each" callback used for emptying an option hash table
*
* Parameters: obj - pointer to option descriptor
* head - pointer to hash table
*
* Returns: -
*/
IP_STATIC void
ipdhcps_option_set_do_delete(Ipdhcps_option *o, Ipdhcps_node *node)
{
if (o != IP_NULL && node != IP_NULL && node->option_head != IP_NULL)
{
ipcom_hash_remove(node->option_head, o);
ipcom_free(o);
}
}
/*
*===========================================================================
* ipdhcps_option_add_check
*===========================================================================
* Description: Check default-lease-time, max-lease-time and min-lease-time.
*
* Parameters: options - pointer to array of options in dhcp format
* type - the type of the option
*
* Returns: IPCOM_SUCCESS - success
* other - failure
*
*/
IP_STATIC void
ipdhcps_option_add_check(Ipdhcps_node *node, Ip_u8 *options, Ip_u16 type)
{
Ip_u32 deft = 0;
Ip_u32 maxt = 0xFFFFFFFF;
Ip_u32 mint = 0;
Ip_u32 datatype = 0;
Ip_u8 *data;
Ip_u8 *dataconf;
Ipdhcps_option *o = IP_NULL;
datatype = IPDHCPS_OPT_CREATE(options[IPDHCPS_OPT_CODE],type);
if (datatype == IPDHCPS_CONFCODE_LEASE_TIME_DFLT)
{
o = ipdhcps_option_set_find(node, IPDHCPS_CONFCODE_LEASE_TIME_MAX);
if (o != IP_NULL)
{
data = &o->opt[IPDHCPS_OPT_DATA];
maxt = *(Ip_u32 *)data;
}
o = ipdhcps_option_set_find(node, IPDHCPS_CONFCODE_LEASE_TIME_MIN);
if (o != IP_NULL)
{
data = &o->opt[IPDHCPS_OPT_DATA];
mint = *(Ip_u32 *)data;
}
dataconf = &options[IPDHCPS_OPT_DATA];
deft = *(Ip_u32 *)dataconf;
if(deft > maxt)
{
*(Ip_u32 *)dataconf = maxt;
IPCOM_LOG0(WARNING, "default_lease_time is changed " \
"to the value of max_lease_time");
return;
}
if(deft < mint)
{
*(Ip_u32 *)dataconf = mint;
IPCOM_LOG0(WARNING, "default_lease_time is changed " \
"to the value of min_lease_time");
return;
}
}
if (datatype == IPDHCPS_CONFCODE_LEASE_TIME_MAX)
{
dataconf = &options[IPDHCPS_OPT_DATA];
maxt = *(Ip_u32 *)dataconf;
o = ipdhcps_option_set_find(node, IPDHCPS_CONFCODE_LEASE_TIME_DFLT);
if (o != IP_NULL)
{
data = &o->opt[IPDHCPS_OPT_DATA];
deft = *(Ip_u32 *)data;
}
else
{
deft = maxt;
}
o = ipdhcps_option_set_find(node, IPDHCPS_CONFCODE_LEASE_TIME_MIN);
if (o != IP_NULL)
{
data = &o->opt[IPDHCPS_OPT_DATA];
mint = *(Ip_u32 *)data;
}
if(maxt < deft)
{
*(Ip_u32 *)dataconf = deft;
IPCOM_LOG0(WARNING, "max_lease_time is changed " \
"to the value of default_lease_time");
return;
}
if(maxt < mint)
{
*(Ip_u32 *)dataconf = mint;
IPCOM_LOG0(WARNING, "max_lease_time is changed " \
"to the value of min_lease_time");
return;
}
}
if (datatype == IPDHCPS_CONFCODE_LEASE_TIME_MIN)
{
dataconf = &options[IPDHCPS_OPT_DATA];
mint = *(Ip_u32 *)dataconf;
o = ipdhcps_option_set_find(node, IPDHCPS_CONFCODE_LEASE_TIME_DFLT);
if (o != IP_NULL)
{
data = &o->opt[IPDHCPS_OPT_DATA];
deft = *(Ip_u32 *)data;
}
else
{
deft = mint;
}
o = ipdhcps_option_set_find(node, IPDHCPS_CONFCODE_LEASE_TIME_MAX);
if (o != IP_NULL)
{
data = &o->opt[IPDHCPS_OPT_DATA];
maxt = *(Ip_u32 *)data;
}
if(mint > maxt)
{
*(Ip_u32 *)dataconf = maxt;
IPCOM_LOG0(WARNING, "min_lease_time is changed " \
"to the value of max_lease_time");
return;
}
if(mint > deft)
{
*(Ip_u32 *)dataconf = deft;
IPCOM_LOG0(WARNING, "min_lease_time is changed " \
"to the value of default_lease_time");
return;
}
}
return;
}
/*
*===========================================================================
* ipdhcps_option_set_add
*===========================================================================
* Description: Add a number of options to a option set list.
* If option set list is empty we first create a list with
* references to the default list.
*
* Parameters: head - pointer to option set list head
* default - pointer top default option set list head
* options - pointer to array of options in dhcp format
*
* Returns: IPCOM_SUCCESS - success
* other - failure
*
*/
IP_STATIC Ip_err
ipdhcps_option_set_add(Ipdhcps_node *node, Ip_u8 *options, Ip_u16 type)
{
Ip_err retval;
Ipdhcps_option *o = IP_NULL;
if (node->option_head == IP_NULL)
node->option_head = ipcom_hash_new((Ipcom_hash_obj_func)ipdhcps_option_hash,
(Ipcom_hash_key_func)ipdhcps_option_key_hash,
(Ipcom_hash_cmp_func)ipdhcps_option_match);
if (node->option_head == IP_NULL)
IPDHCPS_LEAVE(IPCOM_ERR_NO_MEMORY);
/*
* Check each option in the attached raw option list and
* add each of them to the hash table
*/
while(options != IP_NULL)
{
if (ipdhcps_option_valid(options, type) == IP_FALSE)
{
/* Skip option if it is not valid */
options = ipdhcps_option_get_next(options);
continue;
}
ipdhcps_option_add_check(node, options, type);
o = ipdhcps_option_set_find(node, (Ip_u16)IPDHCPS_OPT_CREATE(options[IPDHCPS_OPT_CODE],type));
if (o != IP_NULL)
ipdhcps_option_set_do_delete(o, node);
o = ipcom_malloc((Ip_size_t)(sizeof(o) + IPDHCPS_OPT_TOTAL_LEN(options[IPDHCPS_OPT_LEN])));
if (o == IP_NULL)
IPDHCPS_LEAVE(IPCOM_ERR_NO_MEMORY);
o->code = (Ip_u16)IPDHCPS_OPT_CREATE(options[IPDHCPS_OPT_CODE],type);
ipcom_memcpy(&o->opt, options, (Ip_size_t)IPDHCPS_OPT_TOTAL_LEN(options[IPDHCPS_OPT_LEN]));
/* Add it to hash table */
retval = ipcom_hash_add(node->option_head, o);
if (retval != IPCOM_SUCCESS)
goto leave;
/* Get next option */
options = ipdhcps_option_get_next(options);
}
return IPCOM_SUCCESS;
leave:
if (o != IP_NULL)
ipcom_free(o);
return retval;
}
/*
*===========================================================================
* ipdhcps_interface_delete_cb
*===========================================================================
* Description: Interface destructor callback.
* Parameters: i - pointer to interface descriptor
*
* Returns: IPCOM_SUCCESS - success
*
*/
IP_GLOBAL Ip_err
ipdhcps_interface_do_delete(Ipdhcps_if *i)
{
ipdhcps_list_remove_from(i);
ipcom_free(i);
return IPCOM_SUCCESS;
}
/*
*===========================================================================
* ipdhcps_interface_subnet_map
*===========================================================================
* Description: Checks if a specified subnet is local to any of the
* interfaces used by IPDHCP. If so the "local subnet" shortcut
* the interface is initiated with a pointer to the subnet.
*
* Parameters: subnet - pointer to subnet descriptor
*
* Returns: -
*
*/
IP_STATIC void
ipdhcps_interface_subnet_map(Ipdhcps_subnet *subnet)
{
Ipdhcps_if *i;
Ip_u32 mask = 0;
Ipdhcps_option *o;
o = ipdhcps_option_set_find(&subnet->node,IPDHCPS_OPTCODE_SUBNET_MASK);
if(o != IP_NULL)
ipcom_memcpy(&mask, &o->opt[IPDHCPS_OPT_DATA], o->opt[IPDHCPS_OPT_LEN]);
IPDHCPS_LIST_FOREACH(i, (&ipdhcpsc.if_head), Ipdhcps_if*)
if(subnet->addr == (i->siaddr & mask))
i->local_subnet = subnet;
}
/*
*===========================================================================
* ipdhcps_default_net_create
*===========================================================================
* Description: Creates the default net and inititates it with the default
* configurations.
* Parameters: -
* Returns: IPCOM_SUCCESS - success
* other - failure
*
*/
IP_STATIC Ip_err
ipdhcps_default_net_create(void)
{
Ip_err retval;
Ip_u8 buf[100];
Ip_size_t i;
/* Create a subnet descriptor for global/default values */
ipdhcpsc.default_net = ipdhcps_subnet_new(0);
if(ipdhcpsc.default_net == IP_NULL)
IPDHCPS_LEAVE(IPCOM_ERR_NO_MEMORY);
/* Add it to subnet hash table */
(void) ipcom_hash_add(ipdhcpsc.subnet_head, ipdhcpsc.default_net);
/*
* Set up default config values
*/
i=0;
/* Default lease time */
buf[i++] = IPDHCPS_OPT_CODE_CREATE(IPDHCPS_CONFCODE_LEASE_TIME_DFLT);
buf[i++] = sizeof(Ip_size_t);
ipcom_memcpy(&buf[i],
&ipdhcpsc.config.default_lease_time,
sizeof(Ip_size_t));
i += sizeof(Ip_size_t);
/* Max lease time */
buf[i++] = IPDHCPS_OPT_CODE_CREATE(IPDHCPS_CONFCODE_LEASE_TIME_MAX);
buf[i++] = sizeof(Ip_size_t);
ipcom_memcpy(&buf[i],
&ipdhcpsc.config.max_lease_time,
sizeof(Ip_size_t));
i += sizeof(Ip_size_t);
/* Min lease time */
buf[i++] = IPDHCPS_OPT_CODE_CREATE(IPDHCPS_CONFCODE_LEASE_TIME_MIN);
buf[i++] = sizeof(Ip_size_t);
ipcom_memcpy(&buf[i],
&ipdhcpsc.config.min_lease_time,
sizeof(Ip_size_t));
i += sizeof(Ip_size_t);
/* Renewal time */
buf[i++] = IPDHCPS_OPT_CODE_CREATE(IPDHCPS_CONFCODE_RENEWAL_TIME);
buf[i++] = sizeof(Ip_size_t);
ipcom_memcpy(&buf[i],
&ipdhcpsc.config.renewal_time,
sizeof(Ip_size_t));
i += sizeof(Ip_size_t);
/* Renewal time */
buf[i++] = IPDHCPS_OPT_CODE_CREATE(IPDHCPS_CONFCODE_REBINDING_TIME);
buf[i++] = sizeof(Ip_size_t);
ipcom_memcpy(&buf[i],
&ipdhcpsc.config.rebinding_time,
sizeof(Ip_size_t));
i += sizeof(Ip_size_t);
/* Accept bootp clients by default */
buf[i++] = IPDHCPS_OPT_CODE_CREATE(IPDHCPS_CONFCODE_ALLOW_BOOTP);
buf[i++] = 1;
buf[i++] =(Ip_u8)ipdhcpsc.config.allow_bootp;
/*No dynamic addresses for bootp clients by default */
buf[i++] = IPDHCPS_OPT_CODE_CREATE(IPDHCPS_CONFCODE_ALLOW_DYNAMIC_BOOTP);
buf[i++] = 1;
buf[i++] =(Ip_u8)ipdhcpsc.config.allow_dynamic_bootp;
/* Default tftp server = NULL */
buf[i++] = IPDHCPS_OPT_CODE_CREATE(IPDHCPS_CONFCODE_NEXT_SERVER_NAME);
buf[i++] = 1;
buf[i++] = IP_NULL;
/* Default tftp server = NULL */
buf[i++] = IPDHCPS_OPT_CODE_CREATE(IPDHCPS_CONFCODE_NEXT_SERVER_IP);
buf[i++] = 4;
buf[i++] = 0;
buf[i++] = 0;
buf[i++] = 0;
buf[i++] = 0;
/* Default boot file */
buf[i++] = IPDHCPS_OPT_CODE_CREATE(IPDHCPS_CONFCODE_BOOT_FILE);
buf[i++] = 1;
buf[i++] = IP_NULL;
/* Default config for ICMP address probing */
buf[i++] = IPDHCPS_OPT_CODE_CREATE(IPDHCPS_CONFCODE_DO_ICMP_ADDRESS_CHECK);
buf[i++] = 1;
buf[i++] = (Ip_u8)ipdhcpsc.config.do_icmp_address_check;
buf[i] = IPDHCPS_OPT_CODE_CREATE(IPDHCPS_CONFCODE_END);
/* Setup default config option set */
if(ipdhcps_option_set_add(&ipdhcpsc.defaults, buf, IPDHCPS_OPT_CONF) != IPCOM_SUCCESS)
IPDHCPS_LEAVE(IPCOM_ERR_FAILED);
/* Setup default config options on default net */
if(ipdhcps_option_set_add(&ipdhcpsc.default_net->node, buf, IPDHCPS_OPT_CONF) != IPCOM_SUCCESS)
IPDHCPS_LEAVE(IPCOM_ERR_FAILED);
i = 0;
/* Default config for authorized relay agents. Check if entry fits first */
if ((Ip_u32)sizeof(buf) >= (Ip_u32)IPDHCPS_OPT_TOTAL_LEN(ipdhcpsc.config.no_of_authorized_agents * sizeof(Ip_u32)))
{
buf[i++] = IPDHCPS_OPT_CODE_CREATE(IPDHCPS_CONFCODE_AUTHORIZED_AGENTS);
buf[i++] = (Ip_u8)(ipdhcpsc.config.no_of_authorized_agents * sizeof(Ip_u32));
ipcom_memcpy(&buf[i],
ipdhcpsc.config.authorized_agents,
(Ip_size_t)(ipdhcpsc.config.no_of_authorized_agents * sizeof(Ip_u32)));
buf[IPDHCPS_OPT_TOTAL_LEN(ipdhcpsc.config.no_of_authorized_agents * sizeof(Ip_u32))] = IPDHCPS_OPT_CODE_CREATE(IPDHCPS_CONFCODE_END);
/* Setup default config option set */
if(ipdhcps_option_set_add(&ipdhcpsc.defaults, buf, IPDHCPS_OPT_CONF) != IPCOM_SUCCESS)
IPDHCPS_LEAVE(IPCOM_ERR_FAILED);
/* Setup default config options on default net */
if(ipdhcps_option_set_add(&ipdhcpsc.default_net->node, buf, IPDHCPS_OPT_CONF) != IPCOM_SUCCESS)
IPDHCPS_LEAVE(IPCOM_ERR_FAILED);
}
i = 0;
/* Default authentication */
buf[i++] = IPDHCPS_OPT_CODE_CREATE(IPDHCPS_CONFCODE_RA_AUTHENTICATION);
buf[i++] = 1;
buf[i++] = IP_NULL;
/* Setup default config option set */
if (ipdhcps_option_set_add(&ipdhcpsc.defaults, buf, IPDHCPS_OPT_CONF) != IPCOM_SUCCESS)
IPDHCPS_LEAVE(IPCOM_ERR_FAILED);
i = 0;
/* Default drop policy */
buf[i++] = IPDHCPS_OPT_CODE_CREATE(IPDHCPS_CONFCODE_RA_DROP);
buf[i++] = 1;
buf[i++] = (Ip_u8)IP_FALSE;
/* Setup default config option set */
if (ipdhcps_option_set_add(&ipdhcpsc.defaults, buf, IPDHCPS_OPT_CONF) != IPCOM_SUCCESS)
IPDHCPS_LEAVE(IPCOM_ERR_FAILED);
retval = IPCOM_SUCCESS;
leave:
return retval;
}
/*
****************************************************************************
* 10 GLOBAL FUNCTIONS
****************************************************************************
*/
/*
*===========================================================================
* ipdhcps_sweep_db_cb
*===========================================================================
* Description: Timeout routine periodically called to sweep through
* the lease data base and relese entries of certain status.
*
* Parameters: tmo - pointer to timeout descriptor
* cookie - pointer to cookie(not used)
*
* Returns: IP_TRUE (ordering timer reset)
*
*/
IP_GLOBAL Ip_bool
ipdhcps_sweep_db_cb(void *cookie)
{
Ipdhcps_hash_cb_info info;
(void)cookie;
info.order = IPDHCPS_HASH_CB_ORDER_CHECK_EXPIRY;
info.in_data = ipdhcpsc.lease_htable;
IPDHCPS_LOCK();
ipcom_hash_for_each(ipdhcpsc.lease_htable,
(Ipcom_hash_foreach_cb_func)ipdhcps_lease_table_cb,
&info);
IPDHCPS_UNLOCK();
return IP_TRUE;
}
/*
*===========================================================================
* ipdhcps_db_init
*===========================================================================
* Description: Allocates resources for and intiates the IPDHCPS database
* Parameters: -
* Returns: IPCOM_SUCCESS - success
* other - failure
*/
IP_GLOBAL Ip_err
ipdhcps_db_init(void)
{
Ip_err retval;
/* Clear logbuf */
ipcom_memset(logbuf, 0, sizeof(logbuf));
/* Create subnet hash table */
ipdhcpsc.subnet_head = ipcom_hash_new((Ipcom_hash_obj_func)ipdhcps_subnet_hash,
(Ipcom_hash_key_func)ipdhcps_subnet_key_hash,
(Ipcom_hash_cmp_func)ipdhcps_subnet_match);
if(ipdhcpsc.subnet_head == IP_NULL)
IPDHCPS_LEAVE(IPCOM_ERR_NO_MEMORY);
/* Create lease db hash table */
ipdhcpsc.lease_htable = ipcom_hash_new((Ipcom_hash_obj_func)ipdhcps_lease_hash,
(Ipcom_hash_key_func)ipdhcps_host_lease_key_hash,
(Ipcom_hash_cmp_func)ipdhcps_host_lease_match);
if(ipdhcpsc.lease_htable == IP_NULL)
IPDHCPS_LEAVE(IPCOM_ERR_NO_MEMORY);
ipdhcps_list_init(&ipdhcpsc.if_head);
/* Setup default net */
if(ipdhcps_default_net_create() != IPCOM_SUCCESS)
IPDHCPS_LEAVE(IPCOM_ERR_NO_MEMORY);
retval = IPCOM_SUCCESS;
leave:
return retval;
}
/*
*===========================================================================
* ipdhcps_interface_find
*===========================================================================
* Description: Releases all resources allocated for the IPDHCPS database
* Parameters: -
* Returns: IPCOM_SUCCESS
*
*/
IP_GLOBAL Ip_err
ipdhcps_db_destroy(void)
{
Ipdhcps_if *i;
/* Cancel db sweep routine */
(void)ipcom_tmo2_cancel(&ipdhcpsc.sweep_db_tmo);
for(i = (Ipdhcps_if*)ipdhcpsc.if_head.next; i != IP_NULL;)
{
Ipdhcps_if *ni = ((Ipdhcps_if*)(i->node.next));
ipdhcps_interface_do_delete(i);
i = ni;
}
if (ipdhcpsc.host_head != IP_NULL)
{
ipcom_hash_for_each(ipdhcpsc.host_head,
(Ipcom_hash_foreach_cb_func)ipdhcps_host_delete_cb,
ipdhcpsc.host_head);
ipcom_hash_delete(ipdhcpsc.host_head);
}
if (ipdhcpsc.defaults.option_head != IP_NULL)
{
ipcom_hash_for_each(ipdhcpsc.defaults.option_head,
(Ipcom_hash_foreach_cb_func)ipdhcps_option_set_do_delete,
&ipdhcpsc.defaults);
ipcom_hash_delete(ipdhcpsc.defaults.option_head);
}
if (ipdhcpsc.subnet_head != IP_NULL)
{
ipcom_hash_for_each(ipdhcpsc.subnet_head,
(Ipcom_hash_foreach_cb_func)ipdhcps_subnet_delete_cb,
ipdhcpsc.subnet_head);
ipcom_hash_delete(ipdhcpsc.subnet_head);
}
/* Free allocated resources */
ipdhcps_lease_table_free(ipdhcpsc.lease_htable);
return IPCOM_SUCCESS;
}
/*
*===========================================================================
* ipdhcps_interface_find
*===========================================================================
* Description: Search routine for interfaces used by IPDHCPS.
* Parameters: ifindex - interface index
*
* Returns: pointer to interface dexcriptor - found
* IP_NULL - not found
*
*/
IP_GLOBAL Ipdhcps_if *
ipdhcps_interface_find(int ifindex)
{
Ipdhcps_if *ift;
IPDHCPS_LIST_FOREACH(ift, (&ipdhcpsc.if_head), Ipdhcps_if*)
if(ift->ifindex == ifindex)
break;
return ift;
}
/*
*===========================================================================
* ipdhcps_interface_new
*===========================================================================
* Description: Interface constructor routine.
*
* Parameters: ifindex - inteface index
* ifname - interface name
* addr - interface main IPv4 address
*
* Returns: IPCOM_SUCCESS - success
* other - failure
*/
IP_GLOBAL Ip_err
ipdhcps_interface_new(int ifindex, const char *ifname, Ip_u32 addr)
{
Ip_err retval;
Ipdhcps_if *ift;
if (ipcom_strlen(ifname) >= IP_IFNAMSIZ)
IPDHCPS_LEAVE(IPCOM_ERR_FAILED);
/* Check if interface is already added */
IPDHCPS_LIST_FOREACH(ift, (&ipdhcpsc.if_head), Ipdhcps_if*)
if(ift->ifindex == ifindex)
IPDHCPS_LEAVE(IPCOM_ERR_ALREADY_INSTALLED);
/* Allocate a new interface descriptor */
if((ift = ipcom_malloc(sizeof(Ipdhcps_if))) == IP_NULL)
IPDHCPS_LEAVE(IPCOM_ERR_NO_MEMORY);
/* Init interface descriptor. */
ipcom_memset(ift, 0, sizeof(Ipdhcps_if));
ipcom_strcpy(ift->ifname, ifname);
ift->ifindex = ifindex;
ift->siaddr = addr;
ift->local_subnet = ipdhcpsc.default_net;
if (ipdhcpsc.config.enable_new_interface_when_found == IP_TRUE)
ift->enabled = IP_TRUE;
else
ift->enabled = IP_FALSE;
IPCOM_LOG2(INFO,
"ipdhcps_daemon :: adding interface %s[%d]",
ift->ifname, ift->ifindex);
/* Do not use interface with no main address set */
ift->functional = addr != IP_INADDR_ANY ? IP_TRUE : IP_FALSE;
/* Insert first into interface list. */
ipdhcps_list_add_to(&ipdhcpsc.if_head, ift);
retval = IPCOM_SUCCESS;
leave:
return retval;
}
/*
*===========================================================================
* ipdhcps_host_find
*===========================================================================
* Description: Host search routine.
* Parameters: addr - hosts IPv4 address.
*
* Returns: pointer to host descriptor - success
* IP_NULL - failure
*/
IP_GLOBAL Ipdhcps_host *
ipdhcps_host_find(Ip_u32 addr)
{
if (ipdhcpsc.host_head != IP_NULL)
return (Ipdhcps_host*)ipcom_hash_get(ipdhcpsc.host_head, &addr);
else
return IP_NULL;
}
/*
*===========================================================================
* ipdhcps_subnet_find
*===========================================================================
* Description: Returns pointer to subnet descriptor that is identified by
* specified address.
* Parameters: addr - subnet IP address
*
* Returns: Pointer to subnet descriptor - success
* IP_NULL - not found.
*
*/
IP_GLOBAL Ipdhcps_subnet *
ipdhcps_subnet_find(Ip_u32 addr)
{
if (ipdhcpsc.subnet_head != IP_NULL)
return (Ipdhcps_subnet*)ipcom_hash_get(ipdhcpsc.subnet_head, &addr);
else
return IP_NULL;
}
/*
*===========================================================================
* ipdhcps_subnet_find_matching
*===========================================================================
* Description: Returns pointer to subnet descriptor that matches
* specified address.
* Parameters: addr - subnet IP address
*
* Returns: Pointer to subnet descriptor - success
* IP_NULL - not found.
*
*/
IP_GLOBAL Ipdhcps_subnet *
ipdhcps_subnet_find_matching(Ip_u32 addr)
{
Ipdhcps_subnet_find_info info;
if (ipdhcpsc.subnet_head != IP_NULL)
{
info.addr = addr;
info.found = IP_FALSE;
info.subnet = IP_NULL;
ipcom_hash_for_each(ipdhcpsc.subnet_head,
(Ipcom_hash_foreach_cb_func)ipdhcps_subnet_cmp,
&info);
if (info.found == IP_TRUE)
return info.subnet;
}
return IP_NULL;
}
/*
*===========================================================================
* ipdhcps_option_set_find
*===========================================================================
* Description: Returns pointer to an option descriptor as
* specified by the option code.
*
* Parameters: head - option set list to search in.
* code - option code to search for.
*
* Returns: pointer to an option set descriptor - found
* IP_NULL - not found
*
*/
IP_GLOBAL Ipdhcps_option*
ipdhcps_option_set_find(Ipdhcps_node *node, Ip_u16 code)
{
Ipdhcps_option *o = IP_NULL;
if (node->option_head != IP_NULL)
o = ipcom_hash_get(node->option_head, &code);
return o;
}
/*
*===========================================================================
* ipdhcps_option_set_find_most_valid
*===========================================================================
* Description: Returns pointer to an option descriptor as
* specified by the option code. First checks
* the primary source, then the secondary and
* last the default source.
*
* Parameters: primary - primary list to search in.
* secondary -
* code - option code to search for.
*
* Returns: pointer to an option set descriptor - found
* IP_NULL - not found
*
*/
IP_GLOBAL Ip_u8 *
ipdhcps_option_set_find_most_valid(Ipdhcps_handle *handle, int code)
{
Ipdhcps_option *o = IP_NULL;
/* Search by specific class */
if (handle->client_class != IP_NULL)
o = ipdhcps_option_set_find(&handle->client_class->node, (Ip_u16)code);
/* Search by specific host */
if (o == IP_NULL && handle->lease != IP_NULL && handle->lease->parent != IP_NULL)
o = ipdhcps_option_set_find(handle->lease->parent, (Ip_u16)code);
/* Search by specific subnet */
if (o == IP_NULL && handle->subnet != IP_NULL)
o = ipdhcps_option_set_find(&handle->subnet->node, (Ip_u16)code);
/* Search default net */
if (o == IP_NULL)
o = ipdhcps_option_set_find(&ipdhcpsc.default_net->node, (Ip_u16)code);
/* Search system defaults */
if (o == IP_NULL)
o = ipdhcps_option_set_find(&ipdhcpsc.defaults, (Ip_u16)code);
if (o != IP_NULL)
return o->opt;
else
return IP_NULL;
}
/*
*===========================================================================
* ipdhcps_host_lease_find
*===========================================================================
* Description: Returns pointer to lease descriptor as specifed by
* subnet, link-layer address and client identifier.
*
* Parameters: subnet - pointer to subnet descriptor
* hwa_len - link-layer address length
* hwaddr - link-layer address
* cid_len - length of client identifier
* cid - pointer to client identifer
*
* Returns: Pointer to lease descriptor - found
* IP_NULL - not found
*
*/
IP_GLOBAL Ipdhcps_lease*
ipdhcps_host_lease_find(Ipdhcps_subnet* subnet,
Ip_size_t hwa_len,
Ip_u8 *hwaddr,
Ip_u8 cid_len,
Ip_u8 *cid)
{
Ipdhcps_host_key key;
/* Build a hash search key */
key.subnet = subnet;
key.hlen = hwa_len;
key.haddr = hwaddr;
key.cid_len = cid_len;
key.cid = cid;
return(ipcom_hash_get(ipdhcpsc.lease_htable,
&key));
}
/*
*===========================================================================
* ipdhcps_host_lease_checkout
*===========================================================================
* Description: Checks out a new lease on a specifed subnet and with a
* possibly with a specified IP address.
*
* Parameters: subnet - Pointer to subnet descriptor
* req_addr - Requested address
*
* Returns: Pointer to lease descriptor - success
* IP_NULL - failure
*
*/
IP_GLOBAL Ipdhcps_lease*
ipdhcps_host_lease_checkout(Ipdhcps_subnet* subnet,
Ip_u32 req_addr,
Ip_u8 *client_class)
{
Ipdhcps_pool *p;
Ipdhcps_lease *requested_lease = IP_NULL;
Ipdhcps_lease *first_free_lease = IP_NULL;
Ipdhcps_lease *first_avail_lease = IP_NULL;
Ipdhcps_lease *returned_lease;
Ip_u32 i;
req_addr = ip_ntohl(req_addr);
/* Check if requested address is valid and not occupied */
IPDHCPS_LIST_FOREACH(p, (&subnet->pools), Ipdhcps_pool*)
{
/* Do some class verifications */
if (client_class == IP_NULL && p->class_id != IP_NULL)
continue;
if (ipdhcpsc.config.strict_vender_class_id_match == IP_TRUE && client_class != IP_NULL && p->class_id == IP_NULL)
continue;
if (client_class != IP_NULL && p->class_id != IP_NULL)
{
if ((client_class[IPDHCPS_OPT_CODE] != p->class_id[IPDHCPS_OPT_CODE])
|| (client_class[IPDHCPS_OPT_LEN] != p->class_id[IPDHCPS_OPT_LEN])
|| (ipcom_memcmp(&client_class[IPDHCPS_OPT_DATA], &p->class_id[IPDHCPS_OPT_DATA], (Ip_size_t)p->class_id[IPDHCPS_OPT_LEN]) != 0))
continue;
}
if((req_addr <= p->yiaddr_max) && (req_addr >= p->yiaddr_min))
{
/* Found requested lease */
if(p->leases[req_addr - p->yiaddr_min]->binding_state
== IPDHCPS_BINDING_STATE_FREE)
{
/* Lease can be used by client */
requested_lease = p->leases[req_addr - p->yiaddr_min];
first_free_lease = requested_lease;
break;
}
else if(first_free_lease != IP_NULL)
{
/* Requested lease can not be used, but we have found a free one */
break;
}
}
if(first_free_lease == IP_NULL)
{
for(i = 0; i <= (p->yiaddr_max - p->yiaddr_min); i++)
{
if(p->leases[i]->binding_state == IPDHCPS_BINDING_STATE_FREE)
{
first_free_lease = p->leases[i];
break;
}
else if((first_avail_lease == IP_NULL) &&
((p->leases[i]->binding_state == IPDHCPS_BINDING_STATE_EXPIRED) ||
(p->leases[i]->binding_state == IPDHCPS_BINDING_STATE_RELEASED)))
{
first_avail_lease = p->leases[i];
}
}
}
}
returned_lease = requested_lease != IP_NULL ? requested_lease : first_free_lease;
returned_lease = returned_lease != IP_NULL ? returned_lease : first_avail_lease;
if(returned_lease == IP_NULL)
{
/* We have no leases to offer */
IPCOM_LOG0(DEBUG,"ipdhcps_daemon :: no leases to offer client");
}
else if(returned_lease == first_avail_lease)
{
/* This lease was not free. Print a warning */
IPCOM_LOG2(WARNING,
"ipdhcps_daemon :: reusing %s lease with address %s for new client",
ipdhcps_binding_state_str[returned_lease->binding_state],
ipcom_inet_ntop(IP_AF_INET,
&returned_lease->yiaddr,
logbuf,
sizeof(logbuf)));
/* Delete it from lease database */
(void)ipdhcps_lease_delete(returned_lease);
}
return(returned_lease);
}
/*
*===========================================================================
* ipdhcps_lease_delete
*===========================================================================
* Description: Removes lease from lease database.
*
* Parameters: obj - pointer to lease descriptor.
*
* Returns: IPCOM_SUCCESS - success
* other - failure
*
*/
IP_GLOBAL Ip_err
ipdhcps_lease_delete(Ipdhcps_lease *lease)
{
Ip_err retval = IPCOM_ERR_INVALID_ARG;
if (lease != IP_NULL)
{
retval = ipcom_hash_remove(ipdhcpsc.lease_htable, lease);
if(retval == IPCOM_SUCCESS)
if(lease->binding_state != IPDHCPS_BINDING_STATE_PERMANENT)
{
/* Clear dynamic lease descriptor */
if(lease->cid != IP_NULL)
ipcom_free(lease->cid);
lease->cid_len = 0;
lease->cid = 0;
lease->binding_state = IPDHCPS_BINDING_STATE_FREE;
lease->lease_time = 0;
lease->expires = 0;
}
}
return retval;
}
/*
*===========================================================================
* ipdhcps_lease_add
*===========================================================================
* Description: Lease checkin callback. Adds lease to lease database.
*
* Parameters: obj - pointer to lease object.
*
* Returns: IPCOM_SUCCESS - success
* other - failure
*
*/
IP_GLOBAL Ip_err
ipdhcps_lease_add(Ipdhcps_lease *l)
{
return(ipcom_hash_add(ipdhcpsc.lease_htable, l));
}
/*
*===========================================================================
* ipdhcps_interface_for_each
*===========================================================================
* Description: Apply supplied callback for each interface descriptor
* found in database.
*
* Parameters: cb - Pointer to callback function.
* data - user supplied data.
*
* Returns: IPCOM_SUCCESS - success
* other - failure
*
*/
IP_GLOBAL Ip_err
ipdhcps_interface_for_each(void (*cb)(void *obj, void *data), void* data)
{
Ipdhcps_if *i;
if(ipdhcpsc.opened != IP_TRUE)
return(IPCOM_ERR_NOT_OPENED);
IPDHCPS_LOCK();
IPDHCPS_LIST_FOREACH(i, (&ipdhcpsc.if_head), Ipdhcps_if*)
(*cb)(i,data);
IPDHCPS_UNLOCK();
return IPCOM_SUCCESS;
}
/*
*===========================================================================
* ipdhcps_host_for_each
*===========================================================================
* Description: Apply supplied callback for each host descriptor
* found in database.
*
* Parameters: cb - Pointer to callback function.
* data - user supplied data.
*
* Returns: IPCOM_SUCCESS - success
* other - failure
*
*/
IP_GLOBAL Ip_err
ipdhcps_host_for_each(Ipdhcps_foreach_cb cb, void* data)
{
if(ipdhcpsc.opened != IP_TRUE)
return(IPCOM_ERR_NOT_OPENED);
IPDHCPS_LOCK();
if (ipdhcpsc.host_head != IP_NULL)
ipcom_hash_for_each(ipdhcpsc.host_head, cb, data);
IPDHCPS_UNLOCK();
return IPCOM_SUCCESS;
}
/*
*===========================================================================
* ipdhcps_subnet_for_each
*===========================================================================
* Description: Apply supplied callback for each subnet descriptor
* found in database.
*
* Parameters: cb - Pointer to callback function.
* data - user supplied data.
*
* Returns: IPCOM_SUCCESS - success
* other - failure
*
*/
IP_GLOBAL Ip_err
ipdhcps_subnet_for_each(void (*cb)(void *obj, void *data), void* data)
{
if(ipdhcpsc.opened != IP_TRUE)
return(IPCOM_ERR_NOT_OPENED);
IPDHCPS_LOCK();
ipcom_hash_for_each(ipdhcpsc.subnet_head, cb, data);
IPDHCPS_UNLOCK();
return IPCOM_SUCCESS;
}
/*
*===========================================================================
* ipdhcps_lease_for_each
*===========================================================================
* Description: Apply supplied callback for each lease descriptor
* found in database.
*
* Parameters: cb - Pointer to callback function.
* data - user supplied data.
*
* Returns: IPCOM_SUCCESS - success
* other - failure
*
*/
IP_GLOBAL Ip_err
ipdhcps_lease_for_each(void (*cb)(void *obj, void *data), void* data)
{
if(ipdhcpsc.opened != IP_TRUE)
return(IPCOM_ERR_NOT_OPENED);
IPDHCPS_LOCK();
ipcom_hash_for_each(ipdhcpsc.lease_htable, cb, data);
IPDHCPS_UNLOCK();
return IPCOM_SUCCESS;
}
/*
*===========================================================================
* ipdhcps_pool_for_each
*===========================================================================
* Description: Apply supplied callback for each pool descriptor
* matching supplied address to subnet.
*
* Parameters: addr - Subnet address.
* cb - Pointer to callback function.
* data - user supplied data.
*
* Returns: IPCOM_SUCCESS - success
* other - failure
*
*
*/
IP_GLOBAL Ip_err
ipdhcps_pool_for_each(Ip_u32 inaddr,
void (*cb)(void *obj, void *data),
void* data)
{
Ip_err retval;
Ipdhcps_subnet *s;
Ipdhcps_pool *p;
if(ipdhcpsc.opened != IP_TRUE)
return(IPCOM_ERR_NOT_OPENED);
IPDHCPS_LOCK();
if((s = ipdhcps_subnet_find(inaddr)) == IP_NULL)
IPDHCPS_LEAVE(IPCOM_ERR_NOT_FOUND);
IPDHCPS_LIST_FOREACH(p,(&s->pools), Ipdhcps_pool*)
(*cb)(p, data);
retval = IPCOM_SUCCESS;
leave:
IPDHCPS_UNLOCK();
return retval;
}
/*
*===========================================================================
* ipdhcps_option_for_each
*===========================================================================
* Description: Apply supplied callback for each pool descriptor
* matching supplied address to subnet/host.
*
* Parameters: addr - Subnet/host address.
* cb - Pointer to callback function.
* data - user supplied data.
*
* Returns: IPCOM_SUCCESS - success
* other - failure
*
*/
IP_GLOBAL Ip_err
ipdhcps_option_for_each(Ip_u32 inaddr,
char *client_class,
void (*cb)(void *obj, void *data),
void* data)
{
Ip_err retval;
Ipdhcps_host *h;
Ipdhcps_class *c;
Ipdhcps_subnet *s;
Ipcom_hash *head;
if(ipdhcpsc.opened != IP_TRUE)
return(IPCOM_ERR_NOT_OPENED);
IPDHCPS_LOCK();
if((s = ipdhcps_subnet_find(inaddr)) != IP_NULL)
{
if (client_class != IP_NULL)
{
c = ipdhcps_class_find_by_name(s, client_class);
if (c == IP_NULL)
IPDHCPS_LEAVE(IPCOM_ERR_INVALID_CONFIG);
head = c->node.option_head;
}
else
head = s->node.option_head;
}
else if((h = ipdhcps_host_find(inaddr)) != IP_NULL)
head = h->node.option_head;
else
IPDHCPS_LEAVE(IPCOM_ERR_INVALID_CONFIG);
if(head)
ipcom_hash_for_each(head, (Ipcom_hash_foreach_cb_func)cb, data);
retval = IPCOM_SUCCESS;
leave:
IPDHCPS_UNLOCK();
return retval;
}
/*
*===========================================================================
* ipdhcps_class_for_each
*===========================================================================
* Description: Apply supplied callback for each class descriptor
* found in database.
*
* Parameters: cb - Pointer to callback function.
* data - user supplied data.
*
* Returns: IPCOM_SUCCESS - success
* other - failure
*
*/
IP_GLOBAL Ip_err
ipdhcps_class_for_each(Ip_u32 subnet, void (*cb)(void *obj, void *data), void* data)
{
Ipdhcps_subnet *s;
if(ipdhcpsc.opened != IP_TRUE)
return(IPCOM_ERR_NOT_OPENED);
IPDHCPS_LOCK();
s = ipdhcps_subnet_find(subnet);
if (s != IP_NULL && s->class_head != IP_NULL)
ipcom_hash_for_each(s->class_head, cb, data);
IPDHCPS_UNLOCK();
return IPCOM_SUCCESS;
}
/*
*===========================================================================
* ipdhcps_class_find_by_name
*===========================================================================
* Description: Search routine to find a certain class on a
* certain subnet.
*
* Parameters: s - subnet
* classname - class name
*
* Returns: pointer to pool descriptor - found
* IP_NULL - not found
*
*/
IP_GLOBAL Ipdhcps_class*
ipdhcps_class_find_by_name(Ipdhcps_subnet *s, char *name)
{
Ipdhcps_class_find_id id;
id.name = name;
id.client_class = IP_NULL;
if (s != IP_NULL && s->class_head != IP_NULL)
ipcom_hash_for_each(s->class_head, (Ipcom_hash_foreach_cb_func)ipdhcps_class_search_name, &id);
return id.client_class;
}
/*
*===========================================================================
* ipdhcps_class_find_by_id
*===========================================================================
* Description: Search routine to find a certain class on a
* certain subnet.
*
* Parameters: s - subnet
* classname - class name
*
* Returns: pointer to pool descriptor - found
* IP_NULL - not found
*
*/
IP_GLOBAL Ipdhcps_class*
ipdhcps_class_find_by_id(Ipdhcps_subnet *s, Ip_u8 *id)
{
if (s != IP_NULL && s->class_head != IP_NULL)
return (Ipdhcps_class*)ipcom_hash_get(s->class_head, id);
else
return IP_NULL;
}
/*
****************************************************************************
* 11 PUBLIC FUNCTIONS
****************************************************************************
*/
/*
*===========================================================================
* ipdhcps_interface_status_set
*===========================================================================
* Description: Set status for an interface handled by IPDHCPS.
* Parameters: ifname - name of interface.
* status - IP_TRUE=enable, IP_FALSE=disable
*
* Returns: IPCOM_SUCCESS - success
* other - failure
*/
IP_PUBLIC Ip_err
ipdhcps_interface_status_set(char* ifname, Ip_bool status)
{
Ip_err retval;
Ipdhcps_if *i;
if(ipdhcpsc.opened != IP_TRUE)
return (IPCOM_ERR_NOT_OPENED);
IPDHCPS_LOCK();
IPDHCPS_LIST_FOREACH(i, (&ipdhcpsc.if_head), Ipdhcps_if*)
if(ipcom_strcmp(ifname, i->ifname) == 0)
{
i->enabled = status;
IPDHCPS_LEAVE(IPCOM_SUCCESS);
}
retval = IPCOM_ERR_NOT_FOUND;
leave:
IPDHCPS_UNLOCK();
return retval;
}
/*
*===========================================================================
* Ipdhcps_subnet_add
*===========================================================================
* Description: Add a new subnet to the DHCP server configuration
* Parameters: subnet - Net address. Must be in network byte order.
*
* netmask - Subnet mask. Must be in network byte order.
* pools - Array of address pools to be mapped to the
* subnet
* n_pools - Size of pool array.
* dhcp_options - Byte array of dhcp options specific to this subnet.
* Standard DHCP format (code,len,data,code,len,data..)
* conf_options - Byte array of configuration options specific to
* this subnet.
* Standard DHCP format (code,len,data,code,len,data..)
*
* NOTE 1: DHCP options are always stored in network byte
* order.
* NOTE 2: Configuration options are always stored in host byte
* order.
* Returns:
* IPCOM_SUCCESS - OK.
* IPCOM_ERR_NOT_OPENED - DHCP server not opened yet.
* IPCOM_ERR_ALREADY_INSTALLED - Subnet already exists.
* IPCOM_ERR_NO_MEMORY - Out of memory.
*
*
*/
IP_PUBLIC Ip_err
ipdhcps_subnet_add(Ip_u32 subnet,
Ipdhcps_poolinfo pools[],
Ip_u32 n_pools,
Ip_u8 *dhcp_options,
Ip_u8 *config_options)
{
Ip_err retval;
Ip_u32 i;
Ipdhcps_subnet *s = IP_NULL;
if(ipdhcpsc.opened != IP_TRUE)
return(IPCOM_ERR_NOT_OPENED);
IPDHCPS_LOCK();
if (subnet == IP_INADDR_ANY)
IPDHCPS_LEAVE(IPCOM_ERR_INVALID_ARG);
if (ipdhcps_subnet_find(subnet) != IP_NULL)
IPDHCPS_LEAVE(IPCOM_ERR_ALREADY_INSTALLED);
s = ipdhcps_subnet_new(subnet);
if (s == IP_NULL)
IPDHCPS_LEAVE(IPCOM_ERR_NO_MEMORY);
for (i = 0; i < n_pools; i++)
{
if (ipdhcps_pool_config_sane(&s->pools,
ip_ntohl(pools[i].first_addr),
ip_ntohl(pools[i].last_addr)) != IP_TRUE)
{
IPDHCPS_LEAVE(IPCOM_ERR_INVALID_CONFIG);
}
if (ipdhcps_pool_new(s,
&s->pools,
ip_ntohl(pools[i].first_addr),
ip_ntohl(pools[i].last_addr),
pools[i].classname) != IPCOM_SUCCESS)
{
IPDHCPS_LEAVE(IPCOM_ERR_NO_MEMORY);
}
}
/* Add DHCP options */
if (ipdhcps_option_set_add(&s->node, dhcp_options, IPDHCPS_OPT_DHCP) != IPCOM_SUCCESS)
IPDHCPS_LEAVE(IPCOM_ERR_INVALID_CONFIG);
/* Add configuration options */
if (ipdhcps_option_set_add(&s->node, config_options, IPDHCPS_OPT_CONF) != IPCOM_SUCCESS)
IPDHCPS_LEAVE(IPCOM_ERR_INVALID_CONFIG);
/*
* If the subnet is directly attached to any
* of our interfaces we create a shortcut to it.
*/
ipdhcps_interface_subnet_map(s);
/* Add to hash table */
retval = ipcom_hash_add(ipdhcpsc.subnet_head, s);
leave:
if ((retval != IPCOM_SUCCESS) &&(s != IP_NULL))
{
/* Release buffers upon failure */
ipdhcps_subnet_do_delete(s);
}
IPDHCPS_UNLOCK();
return retval;
}
/*
*===========================================================================
* Ipdhcps_subnet_delete
*===========================================================================
* Description: Delete a subnet from the IPDHCPS configuration.
* Parameters: subnet - Net address of the subnet. Must be in network byte
* order.
*
* NOTE! The subnet address INADDR_ANY(0) is regarded
* illegal here.
*
* Returns: IPCOM_SUCCESS - OK.
* IPCOM_ERR_NOT_OPENED - DHCP server not opened yet.
* IPCOM_ERR_NOT_FOUND - Subnet does not exist.
* IPCOM_ERR_INVALID_ARG - Invalid net address.
*
*/
IP_PUBLIC Ip_err
ipdhcps_subnet_delete(Ip_u32 subnet)
{
Ip_err retval;
Ipdhcps_subnet *s;
if(ipdhcpsc.opened != IP_TRUE)
return(IPCOM_ERR_NOT_OPENED);
IPDHCPS_LOCK();
if(subnet == IP_INADDR_ANY)
IPDHCPS_LEAVE(IPCOM_ERR_INVALID_ARG);
if((s = ipdhcps_subnet_find(subnet)) == IP_NULL)
IPDHCPS_LEAVE(IPCOM_ERR_NOT_FOUND);
retval = ipdhcps_subnet_do_delete(s);
leave:
IPDHCPS_UNLOCK();
return retval;
}
/*
*===========================================================================
* Ipdhcps_host_add
*===========================================================================
* Description: Add a permanent host to the IPDHCPS configuration.
* Parameters: addr - Permanent host IP address in network byte order.
* hwaddr - Link layer address (MAC).
* len - Length of link layer address.
* dhcp_options - Byte array of dhcp options specific to this
* subnet.
* Standard DHCP format (code,len,data,code,len,data..)
* conf_options - Byte array of configuration options specific
* to this subnet.
* Standard DHCP format (code,len,data,code,len,data..)
*
* NOTE 1: DHCP options are always stored in network byte
* order.
* NOTE 2: Configuration options are always stored in host byte
* order.
* NOTE 3: It is allowed to leave out the hwaddr if a client
* identifier is specified in the DHCP option list
* (DHCP option 61). IPDHCPS will then use only this id
* for client identification.
* If both a hwaddr and a client identifier is specified the
* IPDHCPS will identify the client first by its id and then
* by hwaddr.
* Returns:
* IPCOM_SUCCESS - success
* other - failure
*/
IP_PUBLIC Ip_err
ipdhcps_host_add(Ip_u32 addr,
Ip_u8 *hwaddr,
Ip_u8 len,
Ip_u8 *dhcp_options,
Ip_u8 *conf_options)
{
Ip_err retval;
Ip_u8 *cid = IP_NULL;
Ip_u8 cid_len = 0;
Ipdhcps_host *host = IP_NULL;
Ip_u8 *cid_opt;
Ipdhcps_host_lease_find_info info;
if(ipdhcpsc.opened != IP_TRUE)
return(IPCOM_ERR_NOT_OPENED);
IPDHCPS_LOCK();
/*
* Determine if we are going to reference this host by its
* hardware address or by a possible client identifier.
*/
cid_opt = ipdhcps_option_find(dhcp_options,
IPDHCPS_OPTCODE_CLIENT_IDENTIFIER);
if(cid_opt != IP_NULL)
{
cid = &cid_opt[IPDHCPS_OPT_DATA];
cid_len = cid_opt[IPDHCPS_OPT_LEN];
}
else
{
/* No client id. Check if we have a hw address */
if(hwaddr == IP_NULL)
IPDHCPS_LEAVE(IPCOM_ERR_INVALID_CONFIG);
}
/* Check if we already have a host with this finger print in lease database */
if (ipdhcpsc.lease_htable != IP_NULL)
{
info.addr = addr;
info.found = IP_FALSE;
ipcom_hash_for_each(ipdhcpsc.lease_htable,
(Ipcom_hash_foreach_cb_func)ipdhcps_host_lease_cmp,
&info);
if (info.found == IP_TRUE)
IPDHCPS_LEAVE(IPCOM_ERR_ALREADY_INSTALLED);
if(ipdhcps_host_lease_find(ipdhcps_subnet_find_matching(addr),
(Ip_size_t)len,
hwaddr,
cid_len,
cid) != IP_NULL)
IPDHCPS_LEAVE(IPCOM_ERR_ALREADY_INSTALLED);
}
/* Add the host */
if((host = ipdhcps_host_new(addr,
(Ip_size_t)len,
hwaddr,
(Ip_size_t)cid_len,
cid)) == IP_NULL)
IPDHCPS_LEAVE(IPCOM_ERR_NO_MEMORY);
/* Add configuration options */
if(ipdhcps_option_set_add(&host->node, conf_options, IPDHCPS_OPT_CONF) != IPCOM_SUCCESS)
IPDHCPS_LEAVE(IPCOM_ERR_INVALID_CONFIG);
/* Add dhcp options to the host */
retval = ipdhcps_option_set_add(&host->node, dhcp_options, IPDHCPS_OPT_DHCP);
leave:
if ((retval != IPCOM_SUCCESS) && (host != IP_NULL))
{
/* Release resources upon faliure */
(void)ipdhcps_host_do_delete(host);
}
IPDHCPS_UNLOCK();
return retval;
}
/*
*===========================================================================
* Ipdhcps_host_delete
*===========================================================================
* Description: Deletes a permanent host declaration from the IPDHCPS
* configuration.
* Parameters: addr - IP address of host to delete in network byte order.
*
* Returns: IPCOM_SUCCESS - success
* other - failure
*/
IP_PUBLIC Ip_err
ipdhcps_host_delete(Ip_u32 addr)
{
Ip_err retval;
Ipdhcps_host *h;
if(ipdhcpsc.opened != IP_TRUE)
return(IPCOM_ERR_NOT_OPENED);
IPDHCPS_LOCK();
if((h = ipdhcps_host_find(addr)) == IP_NULL)
IPDHCPS_LEAVE(IPCOM_ERR_NOT_FOUND);
retval = ipdhcps_host_do_delete(h);
leave:
IPDHCPS_UNLOCK();
return retval;
}
/*
*===========================================================================
* Ipdhcps_pool_add
*===========================================================================
* Description: Add a new address pool to an existing subnet declaration
* in the IPDHCPS configuration.
* Parameters: subnet - Subnet IP address in network byte order.
* pool - Address pool to be mapped to the subnet.
*
* NOTE: The value IP_INADDR_ANY for subnet will add
* the pool to the global default configuration.
*
* Returns: IPCOM_SUCCESS - success
* other - failure
*
*/
IP_PUBLIC Ip_err
ipdhcps_pool_add(Ip_u32 subnet, Ipdhcps_poolinfo *pool)
{
Ip_err retval;
Ipdhcps_subnet *s;
if(ipdhcpsc.opened != IP_TRUE)
return(IPCOM_ERR_NOT_OPENED);
IPDHCPS_LOCK();
if(subnet == 0)
s = ipdhcpsc.default_net;
else
{
s = ipdhcps_subnet_find(subnet);
if(s == IP_NULL)
IPDHCPS_LEAVE(IPCOM_ERR_NOT_FOUND);
}
if(ipdhcps_pool_config_sane(&s->pools,
ip_ntohl(pool->first_addr),
ip_ntohl(pool->last_addr)) != IP_TRUE)
IPDHCPS_LEAVE(IPCOM_ERR_INVALID_CONFIG);
if(ipdhcps_pool_new(s,
&s->pools,
ip_ntohl(pool->first_addr),
ip_ntohl(pool->last_addr),
pool->classname) != IPCOM_SUCCESS)
IPDHCPS_LEAVE(IPCOM_ERR_NO_MEMORY);
retval = IPCOM_SUCCESS;
leave:
IPDHCPS_UNLOCK();
return retval;
}
/*
*===========================================================================
* Ipdhcps_pool_delete
*===========================================================================
* Description: Delete an address pool on an exiating subnet in the
* IPDHCPS configuration.
* Parameters: subnet - Subnet IP address in network byte order.
* pool - Address pool to be mapped to the subnet.
*
* NOTE: The value IP_INADDR_ANY for subnet will delete
* the pool from the global default configuration.
*
* Returns: IPCOM_SUCCESS - success
* other - failure
*/
IP_PUBLIC Ip_err
ipdhcps_pool_delete(Ip_u32 subnet, Ipdhcps_poolinfo *pool)
{
Ip_err retval;
Ipdhcps_pool *p;
Ipdhcps_subnet *s;
if(ipdhcpsc.opened != IP_TRUE)
return(IPCOM_ERR_NOT_OPENED);
IPDHCPS_LOCK();
if((s = ipdhcps_subnet_find(subnet)) == IP_NULL)
IPDHCPS_LEAVE(IPCOM_ERR_NOT_FOUND);
if((p = ipdhcps_pool_find(&s->pools,
ip_ntohl(pool->first_addr),
ip_ntohl(pool->last_addr))) == IP_NULL)
IPDHCPS_LEAVE(IPCOM_ERR_NOT_FOUND);
/* Delete pool */
retval = ipdhcps_pool_do_delete(p);
leave:
IPDHCPS_UNLOCK();
return retval;
}
/*
*===========================================================================
* Ipdhcps_class_add
*===========================================================================
* Description: Add a class definition to a certain subnet
* in the IPDHCPS configuration.
* Parameters: subnet - Subnet IP address in network byte order.
* class - Class identifying info.
*
*
* NOTE: The value IP_INADDR_ANY for subnet will add
* the class to the global default configuration.
*
* Returns: IPCOM_SUCCESS - success
* other - failure
*
*/
IP_PUBLIC Ip_err
ipdhcps_class_add(Ip_u32 subnet, Ipdhcps_classinfo *client_class)
{
Ip_err retval;
Ipdhcps_subnet *s;
if(ipdhcpsc.opened != IP_TRUE)
return(IPCOM_ERR_NOT_OPENED);
IPDHCPS_LOCK();
if(subnet == 0)
s = ipdhcpsc.default_net;
else
{
s = ipdhcps_subnet_find(subnet);
if(s == IP_NULL)
IPDHCPS_LEAVE(IPCOM_ERR_NOT_FOUND);
}
retval = ipdhcps_class_new(s, client_class);
leave:
IPDHCPS_UNLOCK();
return retval;
}
/*
*===========================================================================
* Ipdhcps_class_delete
*===========================================================================
* Description: Delete a client class on an exiating subnet in the
* IPDHCPS configuration.
* Parameters: subnet - Subnet IP address in network byte order.
* client_class - Class identifying info.
*
* NOTE: The value IP_INADDR_ANY for subnet will delete
* the class from the global default configuration.
*
* Returns: IPCOM_SUCCESS - success
* other - failure
*/
IP_PUBLIC Ip_err
ipdhcps_class_delete(Ip_u32 subnet, char *classname)
{
Ip_err retval;
Ipdhcps_class *c;
Ipdhcps_subnet *s;
if(ipdhcpsc.opened != IP_TRUE)
return(IPCOM_ERR_NOT_OPENED);
IPDHCPS_LOCK();
if((s = ipdhcps_subnet_find(subnet)) == IP_NULL)
IPDHCPS_LEAVE(IPCOM_ERR_NOT_FOUND);
if((c = ipdhcps_class_find_by_name(s, classname)) == IP_NULL)
IPDHCPS_LEAVE(IPCOM_ERR_NOT_FOUND);
/* Delete class */
retval = ipdhcps_class_do_delete(c, s->class_head);
leave:
IPDHCPS_UNLOCK();
return retval;
}
/*
*===========================================================================
* Ipdhcps_option_add
*===========================================================================
* Description: Add a new set of DHCP or CONFIG options to an existing address
* entity (either a subnet or a host). An option that already
* exists on the entity will be replaced by the new one in the
* set.
*
* Parameters: addr - IP address to either a subnet or host.
*
* NOTE 1: DHCP options are always stored in network byte
* order.
* NOTE 2: The value IP_INADDR_ANY (0) of addr will make IPDHCPS
* apply the options on the global default dhcp
* option set.
*
* Returns: IPCOM_SUCCESS - success
* other - failure
*/
IP_PUBLIC Ip_err
ipdhcps_option_add(Ip_u32 addr, char *client_class, Ip_u16 type, Ip_u8 *opt)
{
Ip_err retval;
Ipdhcps_host *h;
Ipdhcps_subnet *s;
Ipdhcps_class *c;
Ipdhcps_node *node;
if(ipdhcpsc.opened != IP_TRUE)
return(IPCOM_ERR_NOT_OPENED);
IPDHCPS_LOCK();
if((s = ipdhcps_subnet_find(addr)) != IP_NULL)
{
if (IPDHCPS_OPTCODE_SUBNET_MASK == IPDHCPS_OPT_CREATE(opt[IPDHCPS_OPT_CODE] ,type))
IPDHCPS_LEAVE(IPCOM_ERR_FAILED);
if (client_class != IP_NULL)
{
c = ipdhcps_class_find_by_name(s, client_class);
if (c == IP_NULL)
IPDHCPS_LEAVE(IPCOM_ERR_NOT_FOUND);
node = &c->node;
}
else
node = &s->node;
}
else if((h = ipdhcps_host_find(addr)) != IP_NULL)
node = &h->node;
else
IPDHCPS_LEAVE(IPCOM_ERR_NOT_FOUND);
if(ipdhcps_option_set_add(node, opt, type) != IPCOM_SUCCESS)
IPDHCPS_LEAVE(IPCOM_ERR_FAILED);
retval = IPCOM_SUCCESS;
leave:
IPDHCPS_UNLOCK();
return retval;
}
/*
*===========================================================================
* ipdhcps_option_delete
*===========================================================================
* Description: Delete a set of DHCP or CONFIG options on an existing address
* entity (either a subnet or a host).
*
* NOTE! No error will be reported if a certain opiton in
* the set does not exist on the entity.
*
* Parameters: addr - IP address to either a subnet or host.
*
* NOTE! The value IP_INADDR_ANY (0) of addr will make IPDHCPS
* apply the options on the global default configuration
* set.
*
* Returns: IPCOM_SUCCESS - success
* other - failure
*
*/
IP_PUBLIC Ip_err
ipdhcps_option_delete(Ip_u32 addr, char* client_class, Ip_u16 type, Ip_u8 option_code)
{
Ip_err retval;
Ipdhcps_host *h;
Ipdhcps_subnet *s;
Ipdhcps_class *c;
Ipdhcps_option *o;
Ipdhcps_node *node;
if(ipdhcpsc.opened != IP_TRUE)
return(IPCOM_ERR_NOT_OPENED);
IPDHCPS_LOCK();
if((s = ipdhcps_subnet_find(addr)) != IP_NULL)
{
if (IPDHCPS_OPTCODE_SUBNET_MASK == IPDHCPS_OPT_CREATE(option_code ,type) )
IPDHCPS_LEAVE(IPCOM_ERR_FAILED);
if (client_class != IP_NULL)
{
c = ipdhcps_class_find_by_name(s, client_class);
if (c == IP_NULL)
IPDHCPS_LEAVE(IPCOM_ERR_NOT_FOUND);
node = &c->node;
}
else
node = &s->node;
}
else if((h = ipdhcps_host_find(addr)) != IP_NULL)
node = &h->node;
else
IPDHCPS_LEAVE(IPCOM_ERR_NOT_FOUND);
if((o = ipdhcps_option_set_find(node, (Ip_u16)IPDHCPS_OPT_CREATE(type,option_code))) == IP_NULL)
IPDHCPS_LEAVE(IPCOM_ERR_NOT_FOUND);
ipdhcps_option_set_do_delete(o, node);
retval = IPCOM_SUCCESS;
leave:
IPDHCPS_UNLOCK();
return retval;
}
/*
****************************************************************************
* END OF FILE
****************************************************************************
*/