aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSUZUKI, Shinsuke <suz@kame.net>2006-01-26 06:21:37 +0000
committerSUZUKI, Shinsuke <suz@kame.net>2006-01-26 06:21:37 +0000
commitd859b0a9117ccd0c5b42e6ba56da47d955516026 (patch)
treede087126d87a42118b0b0d1f2ec460c9eb6fa133
parente137e82e0a14b4b60f165b2621a25fbc8c040c2c (diff)
supported IA-NA address-pool
ToDo: IA-PD prefix-pool, write a manual
-rw-r--r--CHANGES4
-rw-r--r--Makefile.in4
-rw-r--r--cfparse.y135
-rw-r--r--cftoken.l17
-rw-r--r--config.c472
-rw-r--r--config.h42
-rw-r--r--dhcp6s.c175
-rw-r--r--lease.c257
-rw-r--r--lease.h39
9 files changed, 1142 insertions, 3 deletions
diff --git a/CHANGES b/CHANGES
index 85d7418..0da41c1 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,7 @@
+2006-01-26 SUZUKI, Shinsuke <suz@kame.net>
+ * supported IA-NA address-pool
+ ToDo: IA-PD prefix-pool, write a manual
+
2006-01-19 SUZUKI, Shinsuke <suz@kame.net>
* corrected the condition for detecting unwanted incoming messages
* missing initialization in dhcp6c
diff --git a/Makefile.in b/Makefile.in
index 20ddf8a..338f080 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -25,7 +25,7 @@
# SUCH DAMAGE.
#
-# $Id: Makefile.in,v 1.4 2005-12-11 06:33:57 suzsuz Exp $
+# $Id: Makefile.in,v 1.5 2006-01-26 06:21:37 suzsuz Exp $
# $KAME: Makefile.in,v 1.45 2005/10/16 16:25:38 suz Exp $
#
@@ -60,7 +60,7 @@ GENSRCS=cfparse.c cftoken.c
CLIENTOBJS= dhcp6c.o common.o config.o prefixconf.o dhcp6c_ia.o timer.o \
dhcp6c_script.o if.o base64.o auth.o dhcp6_ctl.o addrconf.o \
$(GENSRCS:%.c=%.o)
-SERVOBJS= dhcp6s.o common.o if.o config.o timer.o \
+SERVOBJS= dhcp6s.o common.o if.o config.o timer.o lease.o \
base64.o auth.o dhcp6_ctl.o $(GENSRCS:%.c=%.o)
RELAYOBJS = dhcp6relay.o common.o timer.o
LITECLIENTOBJS= dhcp6lc.o common.o if.o timer.o dhcp6c_script.o
diff --git a/cfparse.y b/cfparse.y
index 8f24a2e..2a862d4 100644
--- a/cfparse.y
+++ b/cfparse.y
@@ -83,6 +83,7 @@ extern void yyerror __P((char *, ...))
} while (0)
static struct cf_namelist *iflist_head, *hostlist_head, *iapdlist_head;
+static struct cf_namelist *poollist_head;
static struct cf_namelist *authinfolist_head, *keylist_head;
static struct cf_namelist *ianalist_head;
struct cf_list *cf_dns_list, *cf_dns_name_list, *cf_ntp_list;
@@ -109,6 +110,7 @@ static void cleanup_cflist __P((struct cf_list *));
%token AUTHENTICATION PROTOCOL ALGORITHM DELAYED RECONFIG HMACMD5 MONOCOUNTER
%token AUTHNAME RDM KEY
%token KEYINFO REALM KEYID SECRET KEYNAME EXPIRE
+%token POOL POOLNAME RANGE TO ADDRESS_POOL
%token NUMBER SLASH EOS BCL ECL STRING QSTRING PREFIX INFINITY
%token COMMA
@@ -118,9 +120,12 @@ static void cleanup_cflist __P((struct cf_list *));
char* str;
struct cf_list *list;
struct dhcp6_prefix *prefix;
+ struct dhcp6_range *range;
+ struct dhcp6_poolspec *pool;
}
%type <str> IFNAME HOSTNAME AUTHNAME KEYNAME DUID_ID STRING QSTRING IAID
+%type <str> POOLNAME
%type <num> NUMBER duration authproto authalg authrdm
%type <list> declaration declarations dhcpoption ifparam ifparams
%type <list> address_list address_list_ent dhcpoption_list
@@ -129,6 +134,8 @@ static void cleanup_cflist __P((struct cf_list *));
%type <list> authparam_list authparam
%type <list> keyparam_list keyparam
%type <prefix> addressparam prefixparam
+%type <range> rangeparam
+%type <pool> poolparam
%%
statements:
@@ -143,6 +150,7 @@ statement:
| ia_statement
| authentication_statement
| key_statement
+ | pool_statement
;
interface_statement:
@@ -328,6 +336,18 @@ key_statement:
}
;
+pool_statement:
+ POOL POOLNAME BCL declarations ECL EOS
+ {
+ struct cf_namelist *pool;
+
+ MAKE_NAMELIST(pool, $2, $4);
+
+ if (add_namelist(pool, &poollist_head))
+ return (-1);
+ }
+ ;
+
address_list:
{ $$ = NULL; }
| address_list address_list_ent
@@ -470,6 +490,22 @@ declaration:
$$ = l;
}
+ | RANGE rangeparam EOS
+ {
+ struct cf_list *l;
+
+ MAKE_CFLIST(l, DECL_RANGE, $2, NULL);
+
+ $$ = l;
+ }
+ | ADDRESS_POOL poolparam EOS
+ {
+ struct cf_list *l;
+
+ MAKE_CFLIST(l, DECL_ADDRESSPOOL, $2, NULL);
+
+ $$ = l;
+ }
;
dhcpoption_list:
@@ -568,6 +604,37 @@ dhcpoption:
}
;
+rangeparam:
+ STRING TO STRING
+ {
+ struct dhcp6_range range0, *range;
+
+ memset(&range0, 0, sizeof(range0));
+ if (inet_pton(AF_INET6, $1, &range0.min) != 1) {
+ yywarn("invalid IPv6 address: %s", $1);
+ free($1);
+ free($3);
+ return (-1);
+ }
+ if (inet_pton(AF_INET6, $3, &range0.max) != 1) {
+ yywarn("invalid IPv6 address: %s", $3);
+ free($1);
+ free($3);
+ return (-1);
+ }
+ free($1);
+ free($3);
+
+ if ((range = malloc(sizeof(*range))) == NULL) {
+ yywarn("can't allocate memory");
+ return (-1);
+ }
+ *range = range0;
+
+ $$ = range;
+ }
+ ;
+
addressparam:
STRING duration
{
@@ -686,6 +753,62 @@ prefixparam:
$$ = pconf;
}
+poolparam:
+ STRING duration
+ {
+ struct dhcp6_poolspec* pool;
+
+ if ((pool = malloc(sizeof(*pool))) == NULL) {
+ yywarn("can't allocate memory");
+ free($1);
+ return (-1);
+ }
+ if ((pool->name = strdup($1)) == NULL) {
+ yywarn("can't allocate memory");
+ free($1);
+ return (-1);
+ }
+ free($1);
+
+ /* validate other parameters later */
+ if ($2 < 0)
+ pool->pltime = DHCP6_DURATITION_INFINITE;
+ else
+ pool->pltime = (u_int32_t)$2;
+ pool->vltime = pool->pltime;
+
+ $$ = pool;
+ }
+ | STRING duration duration
+ {
+ struct dhcp6_poolspec* pool;
+
+ if ((pool = malloc(sizeof(*pool))) == NULL) {
+ yywarn("can't allocate memory");
+ free($1);
+ return (-1);
+ }
+ if ((pool->name = strdup($1)) == NULL) {
+ yywarn("can't allocate memory");
+ free($1);
+ return (-1);
+ }
+ free($1);
+
+ /* validate other parameters later */
+ if ($2 < 0)
+ pool->pltime = DHCP6_DURATITION_INFINITE;
+ else
+ pool->pltime = (u_int32_t)$2;
+ if ($3 < 0)
+ pool->vltime = DHCP6_DURATITION_INFINITE;
+ else
+ pool->vltime = (u_int32_t)$3;
+
+ $$ = pool;
+ }
+ ;
+
duration:
INFINITY
{
@@ -967,6 +1090,8 @@ cleanup()
authinfolist_head = NULL;
cleanup_namelist(keylist_head);
keylist_head = NULL;
+ cleanup_namelist(poollist_head);
+ poollist_head = NULL;
cleanup_cflist(cf_sip_list);
cf_sip_list = NULL;
@@ -1004,6 +1129,11 @@ cleanup_cflist(p)
return;
n = p->next;
+#ifdef USE_POOL
+ if (p->type == DECL_ADDRESSPOOL) {
+ free(((struct dhcp6_poolspec *)p->ptr)->name);
+ }
+#endif
if (p->ptr)
free(p->ptr);
if (p->list)
@@ -1031,6 +1161,11 @@ cf_post_config()
if (configure_ia(ianalist_head, IATYPE_NA))
config_fail();
+#ifdef USE_POOL
+ if (configure_pool(poollist_head))
+ config_fail();
+#endif /* USE_POOL */
+
if (configure_interface(iflist_head))
config_fail();
diff --git a/cftoken.l b/cftoken.l
index c31cbf8..a329cb0 100644
--- a/cftoken.l
+++ b/cftoken.l
@@ -110,6 +110,7 @@ ecl \}
%s S_AUTH
%s S_KEY
%s S_SECRET
+%s S_POOL
%%
%{
@@ -136,6 +137,15 @@ ecl \}
return (HOSTNAME);
}
+ /* pool configuration */
+<S_CNF>pool { DECHO; BEGIN S_POOL; return (POOL); }
+<S_POOL>{string} {
+ DECHO;
+ yylval.str = strdup(yytext);
+ BEGIN S_CNF;
+ return (POOLNAME);
+}
+
<S_CNF>duid { DECHO; BEGIN S_DUID; return (DUID); }
<S_DUID>{duid} {
DECHO;
@@ -160,6 +170,13 @@ ecl \}
/* send */
<S_CNF>send { DECHO; return (SEND); }
+ /* range */
+<S_CNF>range { DECHO; return (RANGE); }
+<S_CNF>to { DECHO; return (TO); }
+
+ /* address-pool */
+<S_CNF>address-pool { DECHO; return (ADDRESS_POOL); }
+
/* DHCP options */
<S_CNF>option { DECHO; return (OPTION); }
diff --git a/config.c b/config.c
index a9357f5..1db285f 100644
--- a/config.c
+++ b/config.c
@@ -58,6 +58,9 @@
#include <common.h>
#include <auth.h>
#include <base64.h>
+#ifdef USE_POOL
+#include <lease.h>
+#endif /* USE_POOL */
extern int errno;
@@ -72,6 +75,19 @@ static struct keyinfo *key_list, *key_list0;
static struct authinfo *auth_list, *auth_list0;
static struct dhcp6_list siplist0, sipnamelist0, dnslist0, dnsnamelist0, ntplist0;
static long long optrefreshtime0;
+#ifdef USE_POOL
+#ifndef DHCP6_DYNAMIC_HOSTCONF_MAX
+#define DHCP6_DYNAMIC_HOSTCONF_MAX 1024
+#endif
+struct dynamic_hostconf {
+ TAILQ_ENTRY(dynamic_hostconf) link;
+ struct host_conf *host;
+};
+static TAILQ_HEAD(dynamic_hostconf_listhead, dynamic_hostconf)
+ dynamic_hostconf_head;
+static unsigned int dynamic_hostconf_count;
+static struct pool_conf *pool_conflist, *pool_conflist0;
+#endif /* USE_POOL */
enum { DHCPOPTCODE_SEND, DHCPOPTCODE_REQUEST, DHCPOPTCODE_ALLOW };
@@ -94,6 +110,9 @@ struct dhcp6_ifconf {
struct authinfo *authinfo; /* authentication information
* (no need to clear) */
+#ifdef USE_POOL
+ struct dhcp6_poolspec pool;
+#endif
};
extern struct cf_list *cf_dns_list, *cf_dns_name_list, *cf_ntp_list;
@@ -115,6 +134,13 @@ static void clear_authinfo __P((struct authinfo *));
static int configure_duid __P((char *, struct duid *));
static int get_default_ifid __P((struct prefix_ifconf *));
static char *qstrdup __P((char *));
+#ifdef USE_POOL
+static void clear_poolconf __P((struct pool_conf *));
+static struct pool_conf *create_pool __P((char *, struct dhcp6_range *));
+struct host_conf *find_dynamic_hostconf __P((struct duid *));
+static int in6_addr_cmp __P((struct in6_addr *, struct in6_addr *));
+static void in6_addr_inc __P((struct in6_addr *));
+#endif /* USE_POOL */
int
configure_interface(iflist)
@@ -233,6 +259,45 @@ configure_interface(iflist)
cp += strlen(ifc->scriptpath) - 1;
*cp = '\0'; /* clear the terminating quote */
break;
+#ifdef USE_POOL
+ case DECL_ADDRESSPOOL:
+ {
+ struct dhcp6_poolspec* spec;
+ struct pool_conf* pool;
+
+ spec = (struct dhcp6_poolspec *)cfl->ptr;
+
+ for (pool = pool_conflist0; pool; pool = pool->next)
+ if (strcmp(spec->name, pool->name) == 0)
+ break;
+ if (pool == NULL) {
+ dprintf(LOG_ERR, FNAME, "%s:%d "
+ "pool '%s' not found",
+ configfilename, cfl->line,
+ spec->name);
+ goto bad;
+ }
+ if (spec->vltime != DHCP6_DURATITION_INFINITE &&
+ (spec->pltime == DHCP6_DURATITION_INFINITE ||
+ spec->pltime > spec->vltime)) {
+ dprintf(LOG_ERR, FNAME, "%s:%d ",
+ configfilename, cfl->line,
+ "specified a larger preferred lifetime "
+ "than valid lifetime");
+ goto bad;
+ }
+ ifc->pool = *spec;
+ if ((ifc->pool.name = strdup(spec->name)) == NULL) {
+ dprintf(LOG_ERR, FNAME,
+ "memory allocation failed");
+ goto bad;
+ }
+ dprintf(LOG_DEBUG, FNAME,
+ "pool '%s' is specified to the interface '%s'",
+ ifc->pool.name, ifc->ifname);
+ }
+ break;
+#endif /* USE_POOL */
default:
dprintf(LOG_ERR, FNAME, "%s:%d "
"invalid interface configuration",
@@ -534,6 +599,45 @@ configure_host(hostlist)
"delayed auth with %s (keyid=%08x)",
host->name, hconf->delayedkey->keyid);
break;
+#ifdef USE_POOL
+ case DECL_ADDRESSPOOL:
+ {
+ struct dhcp6_poolspec* spec;
+ struct pool_conf *pool;
+
+ spec = (struct dhcp6_poolspec *)cfl->ptr;
+
+ for (pool = pool_conflist0; pool; pool = pool->next)
+ if (strcmp(spec->name, pool->name) == 0)
+ break;
+ if (pool == NULL) {
+ dprintf(LOG_ERR, FNAME, "%s:%d "
+ "pool '%s' not found",
+ configfilename, cfl->line,
+ spec->name);
+ goto bad;
+ }
+ if (spec->vltime != DHCP6_DURATITION_INFINITE &&
+ (spec->pltime == DHCP6_DURATITION_INFINITE ||
+ spec->pltime > spec->vltime)) {
+ dprintf(LOG_ERR, FNAME, "%s:%d ",
+ configfilename, cfl->line,
+ "specified a larger preferred lifetime "
+ "than valid lifetime");
+ goto bad;
+ }
+ hconf->pool = *spec;
+ if ((hconf->pool.name = strdup(spec->name)) == NULL) {
+ dprintf(LOG_ERR, FNAME,
+ "memory allocation failed");
+ goto bad;
+ }
+ dprintf(LOG_DEBUG, FNAME,
+ "pool '%s' is specified to the host '%s'",
+ hconf->pool.name, hconf->name);
+ }
+ break;
+#endif /* USE_POOL */
default:
dprintf(LOG_ERR, FNAME, "%s:%d "
"invalid host configuration for %s",
@@ -1210,6 +1314,9 @@ configure_cleanup()
dhcp6_clear_list(&ntplist0);
TAILQ_INIT(&ntplist0);
optrefreshtime0 = -1;
+#ifdef USE_POOL
+ clear_poolconf(pool_conflist0);
+#endif /* USE_POOL */
}
void
@@ -1258,6 +1365,10 @@ configure_commit()
ifp->authalgorithm = ifc->authinfo->algorithm;
ifp->authrdm = ifc->authinfo->rdm;
}
+#ifdef USE_POOL
+ ifp->pool = ifc->pool;
+ ifc->pool.name = NULL;
+#endif
}
clear_ifconf(dhcp6_ifconflist);
@@ -1307,6 +1418,12 @@ configure_commit()
/* commit information refresh time */
optrefreshtime = optrefreshtime0;
+#ifdef USE_POOL
+ /* commit pool configuration */
+ clear_poolconf(pool_conflist);
+ pool_conflist = pool_conflist0;
+ pool_conflist0 = NULL;
+#endif /* USE_POOL */
}
static void
@@ -1326,6 +1443,10 @@ clear_ifconf(iflist)
if (ifc->scriptpath)
free(ifc->scriptpath);
+#ifdef USE_POOL
+ if (ifc->pool.name)
+ free(ifc->pool.name);
+#endif
free(ifc);
}
}
@@ -1384,6 +1505,10 @@ clear_hostconf(hlist)
dhcp6_clear_list(&host->addr_list);
if (host->duid.duid_id)
free(host->duid.duid_id);
+#ifdef USE_POOL
+ if (host->pool.name)
+ free(host->pool.name);
+#endif
free(host);
}
}
@@ -1699,6 +1824,12 @@ find_hostconf(duid)
{
struct host_conf *host;
+#ifdef USE_POOL
+ if ((host = find_dynamic_hostconf(duid)) != NULL) {
+ return (host);
+ }
+#endif /* USE_POOL */
+
for (host = host_conflist; host; host = host->next) {
if (host->duid.duid_len == duid->duid_len &&
memcmp(host->duid.duid_id, duid->duid_id,
@@ -1779,3 +1910,344 @@ qstrdup(qstr)
return (dup);
}
+
+#ifdef USE_POOL
+int
+configure_pool(poollist)
+ struct cf_namelist *poollist;
+{
+ struct cf_namelist *plp;
+
+ dprintf(LOG_DEBUG, FNAME, "called");
+
+ if (poollist && dhcp6_mode != DHCP6_MODE_SERVER) {
+ dprintf(LOG_ERR, FNAME, "%s:%d "
+ "pool statement is server-only",
+ configfilename, poollist->line);
+ goto bad;
+ }
+
+ for (plp = poollist; plp; plp = plp->next) {
+ struct pool_conf *pool = NULL;
+ struct dhcp6_range *range = NULL;
+ struct cf_list *cfl;
+
+ for (cfl = plp->params; cfl; cfl = cfl->next) {
+ switch(cfl->type) {
+ case DECL_RANGE:
+ range = cfl->ptr;
+ break;
+ default:
+ dprintf(LOG_ERR, FNAME, "%s:%d "
+ "invalid pool configuration",
+ configfilename, cfl->line);
+ goto bad;
+ }
+ }
+
+ if (!range) {
+ dprintf(LOG_ERR, FNAME, "%s:%d "
+ "pool '%s' has no range declaration",
+ configfilename, plp->line,
+ plp->name);
+ goto bad;
+ }
+ if ((pool = create_pool(plp->name, range)) == NULL) {
+ dprintf(LOG_ERR, FNAME,
+ "faled to craete pool '%s'", plp->name);
+ goto bad;
+ }
+ pool->next = pool_conflist0;
+ pool_conflist0 = pool;
+ }
+
+ return (0);
+
+ bad:
+ /* there is currently nothing special to recover the error */
+ return (-1);
+}
+
+static void
+clear_poolconf(plist)
+ struct pool_conf *plist;
+{
+ struct pool_conf *pool, *pool_next;
+
+ dprintf(LOG_DEBUG, FNAME, "called");
+
+ for (pool = plist; pool; pool = pool_next) {
+ pool_next = pool->next;
+ free(pool->name);
+ free(pool);
+ }
+}
+
+struct host_conf *
+create_dynamic_hostconf(duid, pool)
+ struct duid *duid;
+ struct dhcp6_poolspec *pool;
+{
+ struct dynamic_hostconf *dynconf = NULL;
+ struct host_conf *host;
+ char* strid = NULL;
+ static int init = 1;
+
+ if (init) {
+ TAILQ_INIT(&dynamic_hostconf_head);
+ dynamic_hostconf_count = 0;
+ init = 0;
+ }
+
+ if (dynamic_hostconf_count >= DHCP6_DYNAMIC_HOSTCONF_MAX) {
+ struct dynamic_hostconf_listhead *head = &dynamic_hostconf_head;
+
+ dprintf(LOG_DEBUG, FNAME, "reached to the max count (count=%lu)",
+ dynamic_hostconf_count);
+
+ /* Find the last entry that doesn't need authentication */
+ TAILQ_FOREACH_REVERSE(dynconf, head, dynamic_hostconf_listhead, link)
+ if (dynconf->host->delayedkey == NULL)
+ break;
+ if (dynconf == NULL)
+ dynconf = TAILQ_LAST(head, dynamic_hostconf_listhead);
+ TAILQ_REMOVE(head, dynconf, link);
+ dynamic_hostconf_count--;
+ clear_hostconf(dynconf->host);
+ } else {
+ if ((dynconf = malloc(sizeof(*dynconf))) == NULL) {
+ dprintf(LOG_ERR, FNAME, "memory allocation failed");
+ return (NULL);
+ }
+ }
+ memset(dynconf, 0, sizeof(*dynconf));
+
+ if ((host = malloc(sizeof(*host))) == NULL) {
+ dprintf(LOG_ERR, FNAME, "memory allocation failed");
+ return (NULL);
+ }
+ memset(host, 0, sizeof(*host));
+ TAILQ_INIT(&host->prefix_list);
+ TAILQ_INIT(&host->addr_list);
+
+ if ((strid = duidstr(duid)) == NULL)
+ strid = "???";
+ if ((host->name = strdup(strid)) == NULL) {
+ dprintf(LOG_ERR, FNAME, "memory allocation failed");
+ goto bad;
+ }
+ if (duidcpy(&host->duid, duid) != 0) {
+ goto bad;
+ }
+ if (pool->name) {
+ if ((host->pool.name = strdup(pool->name)) == NULL) {
+ dprintf(LOG_ERR, FNAME, "memory allocation failed");
+ goto bad;
+ }
+ }
+ host->pool.pltime = pool->pltime;
+ host->pool.vltime = pool->vltime;
+
+ dynconf->host = host;
+ TAILQ_INSERT_HEAD(&dynamic_hostconf_head, dynconf, link);
+ dynamic_hostconf_count++;
+
+ dprintf(LOG_DEBUG, FNAME, "created host_conf (name=%s)", host->name);
+
+ return (host);
+
+bad:
+ if (host)
+ clear_hostconf(host); /* host->next must be NULL */
+ if (dynconf)
+ free(dynconf);
+
+ return (NULL);
+}
+
+struct host_conf *
+find_dynamic_hostconf(duid)
+ struct duid *duid;
+{
+ struct dynamic_hostconf *dynconf = NULL;
+
+ TAILQ_FOREACH(dynconf, &dynamic_hostconf_head, link) {
+ if (dynconf->host->duid.duid_len == duid->duid_len &&
+ memcmp(dynconf->host->duid.duid_id, duid->duid_id,
+ duid->duid_len) == 0)
+ break;
+ }
+
+ if (dynconf) {
+ /* relocation */
+ TAILQ_REMOVE(&dynamic_hostconf_head, dynconf, link);
+ TAILQ_INSERT_HEAD(&dynamic_hostconf_head, dynconf, link);
+
+ return (dynconf->host);
+ }
+
+ return (NULL);
+}
+
+struct pool_conf *
+create_pool(name, range)
+ char *name;
+ struct dhcp6_range *range;
+{
+ struct pool_conf *pool = NULL;
+
+ if (!name || !range) {
+ return (NULL);
+ }
+
+ dprintf(LOG_DEBUG, FNAME, "name=%s, range=%s->%s", name,
+ in6addr2str(&range->min, 0), in6addr2str(&range->max, 0));
+
+ if (in6_addr_cmp(&range->min, &range->max) >= 0) {
+ dprintf(LOG_ERR, FNAME, "invalid address range %s->%s",
+ in6addr2str(&range->min, 0),
+ in6addr2str(&range->max, 0));
+ return (NULL);
+ }
+
+ if ((pool = malloc(sizeof(struct pool_conf))) == NULL) {
+ dprintf(LOG_ERR, FNAME, "memory allocation failed");
+ return (NULL);
+ }
+ if ((pool->name = strdup(name)) == NULL) {
+ dprintf(LOG_ERR, FNAME, "memory allocation failed");
+ return (NULL);
+ }
+ pool->cur = pool->min = range->min;
+ pool->max = range->max;
+
+ return (pool);
+}
+
+struct pool_conf *
+find_pool(name)
+ const char *name;
+{
+ struct pool_conf *pool = NULL;
+
+ if (!name)
+ return (NULL);
+
+ dprintf(LOG_DEBUG, FNAME, "name=%s", name);
+
+ for (pool = pool_conflist; pool; pool = pool->next) {
+ if (strcmp(name, pool->name) == 0) {
+ dprintf(LOG_DEBUG, FNAME, "found (name=%s)", name);
+ return (pool);
+ }
+ }
+
+ dprintf(LOG_DEBUG, FNAME, "not found (name=%s)", name);
+
+ return (NULL);
+}
+
+int
+get_free_address_from_pool(pool, addr)
+ struct pool_conf *pool;
+ struct in6_addr *addr;
+{
+ int found = 0;
+ int round = 0;
+ struct in6_addr first;
+
+ if (!pool || !addr)
+ return (0);
+
+ dprintf(LOG_DEBUG, FNAME, "called (pool=%s)", pool->name);
+
+ memcpy(&first, &pool->cur, sizeof(first));
+
+ while (!found) {
+ if (!is_leased(&pool->cur) &&
+ !IN6_IS_ADDR_MULTICAST(&pool->cur) &&
+ !IN6_IS_ADDR_LINKLOCAL(&pool->cur) &&
+ !IN6_IS_ADDR_SITELOCAL(&pool->cur)) {
+ memcpy(addr, &pool->cur, sizeof(*addr));
+ found = 1;
+ dprintf(LOG_DEBUG, FNAME, "found %s",
+ in6addr2str(addr, 0));
+ }
+
+ if (in6_addr_cmp(&pool->cur, &pool->max) == 0) {
+ memcpy(&pool->next, &pool->min, sizeof(pool->next));
+ round = 1;
+ } else {
+ in6_addr_inc(&pool->cur);
+ }
+
+ dprintf(LOG_DEBUG, FNAME, "next address %s",
+ in6addr2str(&pool->cur, 0));
+
+ if (round && !found &&
+ in6_addr_cmp(&pool->cur, &first) == 0) {
+ dprintf(LOG_NOTICE, FNAME, "no available address");
+ break;
+ }
+ }
+
+ return (found);
+}
+
+int
+is_available_in_pool(pool, addr)
+ struct pool_conf *pool;
+ struct in6_addr *addr;
+{
+ if (!pool || !addr)
+ return (0);
+
+ dprintf(LOG_DEBUG, FNAME, "pool=%s, addr=%s",
+ pool->name, in6addr2str(addr, 0));
+
+ if (in6_addr_cmp(addr, &pool->min) >= 0 &&
+ in6_addr_cmp(addr, &pool->max) <= 0 &&
+ !is_leased(addr) &&
+ !IN6_IS_ADDR_MULTICAST(addr) &&
+ !IN6_IS_ADDR_LINKLOCAL(addr) &&
+ !IN6_IS_ADDR_SITELOCAL(addr)) {
+ return (1);
+ }
+
+ dprintf(LOG_DEBUG, FNAME, "unavailable address (pool=%s, addr=%s)",
+ pool->name, in6addr2str(addr, 0));
+
+ return (0);
+}
+
+static int
+in6_addr_cmp(addr1, addr2)
+ struct in6_addr *addr1, *addr2;
+{
+ int i;
+
+ for (i = 0; i < 16; i++) {
+ if (addr1->s6_addr[i] != addr2->s6_addr[i]) {
+ if (addr1->s6_addr[i] > addr2->s6_addr[i])
+ return (1);
+ else
+ return (-1);
+ }
+ }
+
+ return (0);
+}
+
+static void
+in6_addr_inc(addr)
+ struct in6_addr *addr;
+{
+ int i;
+
+ for (i = 15; i >= 0; i--) {
+ if (++(addr->s6_addr[i]) != 0x00)
+ break;
+ }
+}
+#endif /* USE_POOL */
+
diff --git a/config.h b/config.h
index 156a93a..3ffb793 100644
--- a/config.h
+++ b/config.h
@@ -33,6 +33,29 @@
TAILQ_HEAD(ia_conflist, ia_conf);
TAILQ_HEAD(pifc_list, prefix_ifconf);
+#ifdef USE_POOL
+struct dhcp6_poolspec {
+ char* name;
+ u_int32_t pltime;
+ u_int32_t vltime;
+};
+
+struct dhcp6_range {
+ struct in6_addr min;
+ struct in6_addr max;
+};
+
+struct pool_conf {
+ struct pool_conf *next;
+
+ char* name;
+
+ struct in6_addr min;
+ struct in6_addr max;
+ struct in6_addr cur;
+};
+#endif /* USE_POOL */
+
/* per-interface information */
struct dhcp6_if {
struct dhcp6_if *next;
@@ -55,7 +78,9 @@ struct dhcp6_if {
#define DHCIFF_RAPID_COMMIT 0x2
int server_pref; /* server preference (server only) */
-
+#ifdef USE_POOL
+ struct dhcp6_poolspec pool; /* address pool (server only) */
+#endif
char *scriptpath; /* path to config script (client only) */
struct dhcp6_list reqopt_list;
@@ -197,6 +222,10 @@ struct host_conf {
struct dhcp6_list prefix_list;
/* address to be assigned for the host */
struct dhcp6_list addr_list;
+#ifdef USE_POOL
+ /* address pool from which addresses are assigned for the host */
+ struct dhcp6_poolspec pool;
+#endif
/* secret key shared with the client for delayed authentication */
struct keyinfo *delayedkey;
@@ -241,6 +270,7 @@ struct cf_list {
enum { DECL_SEND, DECL_ALLOW, DECL_INFO_ONLY, DECL_REQUEST, DECL_DUID,
DECL_PREFIX, DECL_PREFERENCE, DECL_SCRIPT, DECL_DELAYEDKEY,
DECL_ADDRESS,
+ DECL_RANGE, DECL_ADDRESSPOOL, /* USE_POOL */
IFPARAM_SLA_ID, IFPARAM_SLA_LEN,
DHCPOPT_RAPID_COMMIT, DHCPOPT_AUTHINFO,
DHCPOPT_DNS, DHCPOPT_DNSNAME,
@@ -287,3 +317,13 @@ extern struct dhcp6_prefix *find_prefix6 __P((struct dhcp6_list *,
struct dhcp6_prefix *));
extern struct ia_conf *find_iaconf __P((struct ia_conflist *, int, u_int32_t));
extern struct keyinfo *find_key __P((char *, size_t, u_int32_t));
+#ifdef USE_POOL
+extern int configure_pool __P((struct cf_namelist *));
+extern struct pool_conf *find_pool __P((const char *));
+extern int is_available_in_pool __P((struct pool_conf *, struct in6_addr *));
+extern int get_free_address_from_pool __P((struct pool_conf *,
+ struct in6_addr *));
+struct host_conf *create_dynamic_hostconf __P((struct duid *,
+ struct dhcp6_poolspec *));
+#endif /* USE_POOL */
+
diff --git a/dhcp6s.c b/dhcp6s.c
index 6a448e1..7d626dd 100644
--- a/dhcp6s.c
+++ b/dhcp6s.c
@@ -74,6 +74,10 @@
#include <base64.h>
#include <control.h>
#include <dhcp6_ctl.h>
+#ifdef USE_POOL
+#include <signal.h>
+#include <lease.h>
+#endif
#define DUID_FILE LOCALDBDIR "/dhcp6s_duid"
#define DHCP6S_CONF SYSCONFDIR "/dhcp6s.conf"
@@ -185,6 +189,10 @@ static int make_ia __P((struct dhcp6_listval *, struct dhcp6_list *,
struct dhcp6_list *, struct host_conf *, int));
static int make_match_ia __P((struct dhcp6_listval *, struct dhcp6_list *,
struct dhcp6_list *));
+#ifdef USE_POOL
+static int make_iana_from_pool __P((struct dhcp6_poolspec *,
+ struct dhcp6_listval *, struct dhcp6_list *));
+#endif
static void calc_ia_timo __P((struct dhcp6_ia *, struct dhcp6_list *,
struct host_conf *));
static void update_binding_duration __P((struct dhcp6_binding *));
@@ -332,6 +340,12 @@ server6_init()
static struct sockaddr_in6 sa6_any_relay_storage;
TAILQ_INIT(&dhcp6_binding_head);
+#ifdef USE_POOL
+ if (lease_init() != 0) {
+ dprintf(LOG_ERR, FNAME, "failed to initialize the lease table");
+ exit(1);
+ }
+#endif
ifidx = if_nametoindex(device);
if (ifidx == 0) {
@@ -1239,6 +1253,14 @@ react_solicit(ifp, dh6, len, optinfo, from, fromlen, relayinfohead)
struct dhcp6_list conflist;
struct dhcp6_listval *iana;
+#ifdef USE_POOL
+ if (client_conf == NULL && ifp->pool.name) {
+ if ((client_conf = create_dynamic_hostconf(&optinfo->clientID,
+ &ifp->pool)) == NULL)
+ dprintf(LOG_NOTICE, FNAME,
+ "failed to make host configuration");
+ }
+#endif
TAILQ_INIT(&conflist);
/* make a local copy of the configured addresses */
@@ -1448,6 +1470,14 @@ react_request(ifp, pi, dh6, len, optinfo, from, fromlen, relayinfohead)
struct dhcp6_list conflist;
struct dhcp6_listval *iana;
+#ifdef USE_POOL
+ if (client_conf == NULL && ifp->pool.name) {
+ if ((client_conf = create_dynamic_hostconf(&optinfo->clientID,
+ &ifp->pool)) == NULL)
+ dprintf(LOG_NOTICE, FNAME,
+ "failed to make host configuration");
+ }
+#endif
TAILQ_INIT(&conflist);
/* make a local copy of the configured prefixes */
@@ -2163,6 +2193,9 @@ release_binding_ia(iap, retlist, optinfo)
lvia->val_prefix6.plen);
break;
case DHCP6_LISTVAL_IANA:
+#ifdef USE_POOL
+ release_address(&lvia->val_prefix6.addr);
+#endif
dprintf(LOG_DEBUG, FNAME,
"bound address %s "
"has been released",
@@ -2397,8 +2430,17 @@ make_ia(spec, conflist, retlist, client_conf, do_binding)
* trivial case:
* if the configuration is empty, we cannot make any IA.
*/
+#ifdef USE_POOL
+ if (TAILQ_EMPTY(conflist)) {
+ if (spec->type != DHCP6_LISTVAL_IANA ||
+ client_conf->pool.name == NULL) {
+ return (0);
+ }
+ }
+#else
if (TAILQ_EMPTY(conflist))
return (0);
+#endif /* USE_POOL */
TAILQ_INIT(&ialist);
@@ -2406,10 +2448,43 @@ make_ia(spec, conflist, retlist, client_conf, do_binding)
for (specia = TAILQ_FIRST(&spec->sublist); specia;
specia = TAILQ_NEXT(specia, link)) {
/* try to find an IA that matches the spec best. */
+#ifdef USE_POOL
+ if (!TAILQ_EMPTY(conflist)) {
+ if (make_match_ia(specia, conflist, &ialist))
+ found++;
+ } else if (spec->type == DHCP6_LISTVAL_IANA &&
+ client_conf->pool.name != NULL) {
+ if (make_iana_from_pool(&client_conf->pool, specia, &ialist))
+ found++;
+ }
+#else
if (make_match_ia(specia, conflist, &ialist))
found++;
+#endif /* USE_POOL */
}
if (found == 0) {
+#ifdef USE_POOL
+ if (!TAILQ_EMPTY(conflist)) {
+ struct dhcp6_listval *v;
+
+ /* use the first IA in the configuration list */
+ for (v = TAILQ_FIRST(conflist); v; v = TAILQ_NEXT(v, link)) {
+ if (spec->type != DHCP6_LISTVAL_IANA)
+ break; /* always use the first IA for non-IANA */
+ if (!is_leased(&v->val_statefuladdr6.addr))
+ break;
+ }
+ if (v && dhcp6_add_listval(&ialist, v->type, &v->uv, NULL)) {
+ found = 1;
+ TAILQ_REMOVE(conflist, v, link);
+ dhcp6_clear_listval(v);
+ }
+ } else if (spec->type == DHCP6_LISTVAL_IANA &&
+ client_conf->pool.name != NULL) {
+ if (make_iana_from_pool(&client_conf->pool, NULL, &ialist))
+ found = 1;
+ }
+#else
struct dhcp6_listval *v;
/* use the first IA in the configuration list */
@@ -2419,6 +2494,7 @@ make_ia(spec, conflist, retlist, client_conf, do_binding)
TAILQ_REMOVE(conflist, v, link);
dhcp6_clear_listval(v);
}
+#endif /* USE_POOL */
}
if (found) {
memset(&ia, 0, sizeof(ia));
@@ -2467,6 +2543,10 @@ make_match_ia(spec, conflist, retlist)
break;
case DHCP6_LISTVAL_STATEFULADDR6:
/* No "partial match" for addresses */
+#ifdef USE_POOL
+ if (is_leased(&spec->val_statefuladdr6.addr))
+ match = 0;
+#endif
break;
default:
dprintf(LOG_ERR, FNAME, "unsupported IA type");
@@ -2490,6 +2570,52 @@ make_match_ia(spec, conflist, retlist)
return (matched);
}
+#ifdef USE_POOL
+/* making sublist of iana */
+static int
+make_iana_from_pool(poolspec, spec, retlist)
+ struct dhcp6_poolspec *poolspec;
+ struct dhcp6_listval *spec;
+ struct dhcp6_list *retlist;
+{
+ struct dhcp6_statefuladdr saddr;
+ struct pool_conf *pool;
+ int found = 0;
+
+ dprintf(LOG_DEBUG, FNAME, "called");
+
+ if ((pool = find_pool(poolspec->name)) == NULL) {
+ dprintf(LOG_ERR, FNAME, "pool '%s' not found", poolspec->name);
+ return (0);
+ }
+
+ if (spec) {
+ memcpy(&saddr.addr, &spec->val_statefuladdr6.addr, sizeof(saddr.addr));
+ if (is_available_in_pool(pool, &saddr.addr)) {
+ found = 1;
+ }
+ } else {
+ if (get_free_address_from_pool(pool, &saddr.addr)) {
+ found = 1;
+ }
+ }
+
+ if (found) {
+ saddr.pltime = poolspec->pltime;
+ saddr.vltime = poolspec->vltime;
+
+ if (!dhcp6_add_listval(retlist, DHCP6_LISTVAL_STATEFULADDR6,
+ &saddr, NULL)) {
+ return (0);
+ }
+ }
+
+ dprintf(LOG_DEBUG, FNAME, "returns (found=%d)", found);
+
+ return (found);
+}
+#endif /* USE_POOL */
+
static void
calc_ia_timo(ia, ialist, client_conf)
struct dhcp6_ia *ia;
@@ -2629,6 +2755,35 @@ add_binding(clientid, btype, iatype, iaid, val0)
"failed to copy binding data");
goto fail;
}
+#ifdef USE_POOL
+ /* lease address */
+ if (iatype == DHCP6_LISTVAL_IANA) {
+ struct dhcp6_list *ia_list = &binding->val_list;
+ struct dhcp6_listval *lv, *lv_next;
+
+ for (lv = TAILQ_FIRST(ia_list); lv; lv = lv_next) {
+ lv_next = TAILQ_NEXT(lv, link);
+
+ if (lv->type != DHCP6_LISTVAL_STATEFULADDR6) {
+ dprintf(LOG_ERR, FNAME,
+ "unexpected binding value type(%d)", lv->type);
+ continue;
+ }
+
+ if (!lease_address(&lv->val_statefuladdr6.addr)) {
+ dprintf(LOG_NOTICE, FNAME,
+ "cannot lease address %s",
+ in6addr2str(&lv->val_statefuladdr6.addr, 0));
+ TAILQ_REMOVE(ia_list, lv, link);
+ dhcp6_clear_listval(lv);
+ }
+ }
+ if (TAILQ_EMPTY(ia_list)) {
+ dprintf(LOG_NOTICE, FNAME, "cannot lease any address");
+ goto fail;
+ }
+ }
+#endif /* USE_POOL */
break;
default:
dprintf(LOG_ERR, FNAME, "unexpected binding type(%d)", btype);
@@ -2734,6 +2889,22 @@ free_binding(binding)
/* free configuration info in a type dependent manner. */
switch (binding->type) {
case DHCP6_BINDING_IA:
+#ifdef USE_POOL
+ /* releaes address */
+ if (binding->iatype == DHCP6_LISTVAL_IANA) {
+ struct dhcp6_list *ia_list = &binding->val_list;
+ struct dhcp6_listval *lv;
+
+ for (lv = TAILQ_FIRST(ia_list); lv; lv = TAILQ_NEXT(lv, link)) {
+ if (lv->type != DHCP6_LISTVAL_STATEFULADDR6) {
+ dprintf(LOG_ERR, FNAME,
+ "unexpected binding value type(%d)", lv->type);
+ continue;
+ }
+ release_address(&lv->val_statefuladdr6.addr);
+ }
+ }
+#endif /* USE_POOL */
dhcp6_clear_list(&binding->val_list);
break;
default:
@@ -2783,6 +2954,10 @@ binding_timo(arg)
in6addr2str(&iav->val_prefix6.addr, 0),
iav->val_prefix6.plen,
bindingstr(binding));
+#ifdef USE_POOL
+ if (binding->iatype == DHCP6_LISTVAL_IANA)
+ release_address(&iav->val_prefix6.addr);
+#endif
TAILQ_REMOVE(ia_list, iav, link);
dhcp6_clear_listval(iav);
}
diff --git a/lease.c b/lease.c
new file mode 100644
index 0000000..7189315
--- /dev/null
+++ b/lease.c
@@ -0,0 +1,257 @@
+#include <sys/types.h>
+#include <unistd.h>
+#include <syslog.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/queue.h>
+#include <netinet/in.h>
+#include "dhcp6.h"
+#include "config.h"
+#include "common.h"
+
+#ifndef FALSE
+#define FALSE 0
+#define TRUE !FALSE
+#endif
+
+struct hash_entry {
+ LIST_ENTRY(hash_entry) list;
+ char val[];
+};
+
+LIST_HEAD(hash_head, hash_entry);
+
+typedef unsigned int (*pfn_hash_t)(void *val) ;
+typedef int (*pfh_hash_match_t)(void *val1, void *val2);
+
+struct hash_table {
+ struct hash_head *table;
+ unsigned int size;
+ pfn_hash_t hash;
+ pfh_hash_match_t match;
+};
+
+#ifndef DHCP6_LEASE_TABLE_SIZE
+#define DHCP6_LEASE_TABLE_SIZE 256
+#endif
+
+static struct hash_table dhcp6_lease_table;
+
+static unsigned int in6_addr_hash __P((void *));
+static int in6_addr_match __P((void *, void *));
+
+static int hash_table_init __P((struct hash_table *, unsigned int,
+ pfn_hash_t, pfh_hash_match_t));
+static void hash_table_cleanup __P((struct hash_table *));
+static int hash_table_add __P((struct hash_table *, void *, unsigned int));
+static int hash_table_remove __P((struct hash_table *, void *));
+static struct hash_entry * hash_table_find __P((struct hash_table *, void *));
+
+int
+lease_init(void)
+{
+ dprintf(LOG_DEBUG, FNAME, "called");
+
+ if (hash_table_init(&dhcp6_lease_table, DHCP6_LEASE_TABLE_SIZE,
+ in6_addr_hash, in6_addr_match) != 0) {
+ return (-1);
+ }
+
+ return (0);
+}
+
+void
+lease_cleanup(void)
+{
+ hash_table_cleanup(&dhcp6_lease_table);
+}
+
+int
+lease_address(addr)
+ struct in6_addr *addr;
+{
+ if (!addr)
+ return (FALSE);
+
+ dprintf(LOG_DEBUG, FNAME, "addr=%s", in6addr2str(addr, 0));
+
+ if (hash_table_find(&dhcp6_lease_table, addr)) {
+ dprintf(LOG_WARNING, FNAME, "already leased: %s",
+ in6addr2str(addr, 0));
+ return (FALSE);
+ }
+
+ if (hash_table_add(&dhcp6_lease_table, addr, sizeof(*addr)) != 0) {
+ return (FALSE);
+ }
+
+ return (TRUE);
+}
+
+void
+release_address(addr)
+ struct in6_addr *addr;
+{
+ if (!addr)
+ return;
+
+ dprintf(LOG_DEBUG, FNAME, "addr=%s", in6addr2str(addr, 0));
+
+ if (hash_table_remove(&dhcp6_lease_table, addr) != 0) {
+ dprintf(LOG_WARNING, FNAME, "not found: %s", in6addr2str(addr, 0));
+ }
+}
+
+int
+is_leased(addr)
+ struct in6_addr *addr;
+{
+ return (hash_table_find(&dhcp6_lease_table, addr) != NULL);
+}
+
+static unsigned int
+in6_addr_hash(val)
+ void *val;
+{
+ u_int8_t *addr = ((struct in6_addr *)val)->s6_addr;
+ unsigned int hash = 0;
+ int i;
+
+ for (i = 0; i < 16; i++) {
+ hash += addr[i];
+ }
+
+ return (hash);
+}
+
+static int
+in6_addr_match(val1, val2)
+ void *val1, *val2;
+{
+ struct in6_addr * addr1 = val1;
+ struct in6_addr * addr2 = val2;
+
+ return (memcmp(addr1->s6_addr, addr2->s6_addr, 16) == 0);
+}
+
+/*
+ * hash table
+ */
+static int
+hash_table_init(table, size, hash, match)
+ struct hash_table *table;
+ unsigned int size;
+ pfn_hash_t hash;
+ pfh_hash_match_t match;
+{
+ int i;
+
+ if (!table || !hash || !match) {
+ return (-1);
+ }
+
+ if ((table->table = malloc(sizeof(*table->table) * size)) == NULL) {
+ return (-1);
+ }
+
+ for (i = 0; i < size; i++)
+ LIST_INIT(&table->table[i]);
+
+ table->size = size;
+ table->hash = hash;
+ table->match = match;
+
+ return (0);
+}
+
+static void
+hash_table_cleanup(table)
+ struct hash_table *table;
+{
+ int i;
+
+ if (!table) {
+ return;
+ }
+
+ for (i = 0; i < table->size; i++) {
+ while (!LIST_EMPTY(&table->table[i])) {
+ struct hash_entry *entry = LIST_FIRST(&table->table[i]);
+ LIST_REMOVE(entry, list);
+ free(entry);
+ }
+ }
+ free(table->table);
+ memset(table, 0, sizeof(*table));
+}
+
+static int
+hash_table_add(table, val, size)
+ struct hash_table *table;
+ void *val;
+ unsigned int size;
+{
+ struct hash_entry *entry = NULL;
+ int i = 0;
+
+ if (!table || !val) {
+ return (-1);
+ }
+
+ if ((entry = malloc(sizeof(*entry) + size)) == NULL) {
+ return (-1);
+ }
+ memset(entry, 0, sizeof(*entry));
+ memcpy(entry->val, val, size);
+
+ i = table->hash(val) % table->size;
+ LIST_INSERT_HEAD(&table->table[i], entry, list);
+
+ return (0);
+}
+
+static int
+hash_table_remove(table, val)
+ struct hash_table *table;
+ void *val;
+{
+ struct hash_entry *entry;
+
+ if (!table || !val) {
+ return (-1);
+ }
+
+ if ((entry = hash_table_find(table, val)) == NULL) {
+ return (-1);
+ }
+
+ LIST_REMOVE(entry, list);
+ free(entry);
+
+ return (0);
+}
+
+static struct hash_entry *
+hash_table_find(table, val)
+ struct hash_table *table;
+ void *val;
+{
+ struct hash_entry *entry;
+ int i;
+
+ if (!table || !val) {
+ return (NULL);
+ }
+
+ i = table->hash(val) % table->size;
+ LIST_FOREACH(entry, &table->table[i], list)
+ {
+ if (table->match(val, entry->val)) {
+ return (entry);
+ }
+ }
+
+ return (NULL);
+}
+
diff --git a/lease.h b/lease.h
new file mode 100644
index 0000000..f556eb7
--- /dev/null
+++ b/lease.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 1998 and 1999 WIDE Project.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef __LEASE_H_DEFINED
+#define __LEASE_H_DEFINED
+
+extern int lease_init __P((void));
+extern void lease_cleanup __P((void));
+extern int lease_address __P((struct in6_addr *));
+extern void release_address __P((struct in6_addr *));
+extern int is_addr_leased __P((struct in6_addr *));
+
+#endif