3553 lines
99 KiB
C
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
|
|
****************************************************************************
|
|
*/
|