2
0
mirror of https://gitlab.isc.org/isc-projects/dhcp synced 2025-08-22 01:49:35 +00:00

-n [master]

26510
 Add support for classes in the IPv6 code
This commit is contained in:
Shawn Routhier 2013-08-27 14:20:09 -07:00
parent a7341359cc
commit 01fa619fab
9 changed files with 1403 additions and 456 deletions

View File

@ -72,6 +72,9 @@ work on other platforms. Please report any problems and suggested fixes to
- Add support in v6 for on-commit, on-expire and on-release.
[ISC-Bugs #27912
- Add support for using classes with v6.
[ISC-Bugs #26510]
Changes since 4.2.5
- Address static analysis warnings.

View File

@ -1231,6 +1231,8 @@ intern(char *atom, enum dhcp_token dfv) {
return PACKET;
if (!strcasecmp (atom + 1, "ool"))
return POOL;
if (!strcasecmp (atom + 1, "ool6"))
return POOL6;
if (!strcasecmp (atom + 1, "refix6"))
return PREFIX6;
if (!strcasecmp (atom + 1, "seudo"))

View File

@ -32,6 +32,8 @@
* ``http://www.nominum.com''.
*/
/*! \file includes/dhcpd.h */
#include "config.h"
#ifndef __CYGWIN32__
@ -933,9 +935,7 @@ struct shared_network {
struct subnet *subnets;
struct interface_info *interface;
struct pool *pools;
struct ipv6_pool **ipv6_pools; /* NULL-terminated array */
int last_ipv6_pool; /* offset of last IPv6 pool
used to issue a lease */
struct ipv6_pond *ipv6_pond;
struct group *group;
#if defined (FAILOVER_PROTOCOL)
dhcp_failover_state_t *failover_peer;
@ -1530,6 +1530,26 @@ extern ia_hash_t *ia_na_active;
extern ia_hash_t *ia_ta_active;
extern ia_hash_t *ia_pd_active;
/*!
*
* \brief ipv6_pool structure
*
* This structure is part of a range of addresses or prefixes.
* A range6 or prefix6 statement will map to one or more of these
* with each pool being a simple block of the form xxxx/yyy and
* all the pools adding up to comprise the entire range. When
* choosing an address or prefix the code will walk through the
* pools until it finds one that is available.
*
* The naming for this structure is unfortunate as there is also
* a v4 pool structure and the two are not equivalent. The v4
* pool matches the ipv6_pond structure. I considered changing the
* name of this structure but concluded that doing so would be worse
* than leaving it as is. Changing it adds some risk and makes for
* larger differences between the 4.1 & 4.2 code and the 4.3 code.
*
*/
struct ipv6_pool {
int refcnt; /* reference count */
u_int16_t pool_type; /* IA_xx */
@ -1545,6 +1565,34 @@ struct ipv6_pool {
struct shared_network *shared_network; /* shared_network for
this pool */
struct subnet *subnet; /* subnet for this pool */
struct ipv6_pond *ipv6_pond; /* pond for this pool */
};
/*!
*
* \brief ipv6_pond structure
*
* This structure is the ipv6 version of the v4 pool structure.
* It contains the address and prefix information via the pointers
* to the ipv6_pools and the allowability of this pool for a given
* client via the permit lists and the valid TIMEs.
*
*/
struct ipv6_pond {
int refcnt;
struct ipv6_pond *next;
struct group *group;
struct shared_network *shared_network; /* backpointer to the enclosing
shared network */
struct permit *permit_list; /* allow clients from this list */
struct permit *prohibit_list; /* deny clients from this list */
TIME valid_from; /* deny pool use before this date */
TIME valid_until; /* deny pool use after this date */
struct ipv6_pool **ipv6_pools; /* NULL-terminated array */
int last_ipv6_pool; /* offset of last IPv6 pool
used to issue a lease */
};
/* Flags and state for dhcp_ddns_cb_t */
@ -1945,14 +1993,17 @@ int parse_ip6_addr_expr(struct expression **, struct parse *);
int parse_ip6_prefix(struct parse *, struct iaddr *, u_int8_t *);
void parse_address_range (struct parse *, struct group *, int,
struct pool *, struct lease **);
void parse_address_range6(struct parse *cfile, struct group *group);
void parse_prefix6(struct parse *cfile, struct group *group);
void parse_address_range6(struct parse *cfile, struct group *group,
struct ipv6_pond *);
void parse_prefix6(struct parse *cfile, struct group *group,
struct ipv6_pond *);
void parse_fixed_prefix6(struct parse *cfile, struct host_decl *host_decl);
void parse_ia_na_declaration(struct parse *);
void parse_ia_ta_declaration(struct parse *);
void parse_ia_pd_declaration(struct parse *);
void parse_server_duid(struct parse *cfile);
void parse_server_duid_conf(struct parse *cfile);
void parse_pool6_statement (struct parse *, struct group *, int);
/* ddns.c */
int ddns_updates(struct packet *, struct lease *, struct lease *,
@ -3549,6 +3600,13 @@ isc_result_t find_ipv6_pool(struct ipv6_pool **pool, u_int16_t type,
const struct in6_addr *addr);
isc_boolean_t ipv6_in_pool(const struct in6_addr *addr,
const struct ipv6_pool *pool);
isc_result_t ipv6_pond_allocate(struct ipv6_pond **pond,
const char *file, int line);
isc_result_t ipv6_pond_reference(struct ipv6_pond **pond,
struct ipv6_pond *src,
const char *file, int line);
isc_result_t ipv6_pond_dereference(struct ipv6_pond **pond,
const char *file, int line);
isc_result_t renew_leases(struct ia_xx *ia);
isc_result_t release_leases(struct ia_xx *ia);

View File

@ -3,7 +3,7 @@
Tokens for config file lexer and parser. */
/*
* Copyright (c) 2011-2012 by Internet Systems Consortium, Inc. ("ISC")
* Copyright (c) 2011-2013 by Internet Systems Consortium, Inc. ("ISC")
* Copyright (c) 2004,2007-2009 by Internet Systems Consortium, Inc. ("ISC")
* Copyright (c) 1996-2003 by Internet Software Consortium
*
@ -365,7 +365,8 @@ enum dhcp_token {
GETHOSTBYNAME = 665,
PRIMARY6 = 666,
SECONDARY6 = 667,
TOKEN_INFINIBAND = 668
TOKEN_INFINIBAND = 668,
POOL6 = 669
};
#define is_identifier(x) ((x) >= FIRST_TOKEN && \

File diff suppressed because it is too large Load Diff

View File

@ -265,8 +265,8 @@ group {
.SH ADDRESS POOLS
.PP
The
.B pool
declaration can be used to specify a pool of addresses that will be
\fBpool\fR and \fBpool6\fR
declarations can be used to specify a pool of addresses that will be
treated differently than another pool of addresses, even on the same
network segment or subnet. For example, you may want to provide a
large set of addresses that can be assigned to DHCP clients that are
@ -316,6 +316,14 @@ deny list, then only those clients that do not match any entries on
the deny list will be eligible. If both permit and deny lists exist
for a pool, then only clients that match the permit list and do not
match the deny list will be allowed access.
.PP
The \fBpool6\fR declaration is similar to the \fBpool6\fR declaration.
Currently it is only allowed within a \fBsubnet6\fR declaration, and
may not be included directly in a shared network declaration.
In addition to the \fBrange6\fR statement it allows the \fBprefix6\fR
statement to be included. You may include \fBrange6\fR statements
for both NA and TA and \fBprefixy6\fR statements in a single
\fBpool6\fR statement.
.SH DYNAMIC ADDRESS ALLOCATION
Address allocation is actually only done when a client is in the INIT
state and has sent a DHCPDISCOVER message. If the client thinks it
@ -442,7 +450,7 @@ this last method, change the "my state" line to:
.PP
.nf
.B failover peer "\fIname\fB" state {
.B my state partner-down;
.B my state partner-down;.
.B peer state \fIstate\fB at \fIdate\fB;
.B }
.fi
@ -894,6 +902,10 @@ total number of clients within a particular class or subclass that may
hold leases at one time, and it is possible to specify automatic
subclassing based on the contents of the client packet.
.PP
Classing support for DHCPv6 clients was addded in 4.3.0. It follows
the same rules as for DHCPv4 except that support for billing classes
has not been added yet.
.PP
To add clients to classes based on conditional evaluation, you can
specify a matching expression in the class statement:
.PP

View File

@ -14,6 +14,8 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/*! \file server/dhcpv6.c */
#include "dhcpd.h"
#ifdef DHCPv6
@ -989,83 +991,112 @@ try_client_v6_address(struct iasubopt **addr,
return result;
}
/*
* Get an IPv6 address for the client.
/*!
*
* addr is the result (should be a pointer to NULL on entry)
* packet is the information about the packet from the client
* requested_iaaddr is a hint from the client
* client_id is the DUID for the client
* \brief Get an IPv6 address for the client.
*
* Attempt to find a usable address for the client. We walk through
* the ponds checking for permit and deny then through the pools
* seeing if they have an available address.
*
* \param reply = the state structure for the current work on this request
* if we create a lease we return it using reply->lease
*
* \return
* ISC_R_SUCCESS = we were able to find an address and are returning a
* pointer to the lease
* ISC_R_NORESOURCES = there don't appear to be any free addresses. This
* is probabalistic. We don't exhaustively try the
* address range, instead we hash the duid and if
* the address derived from the hash is in use we
* hash the address. After a number of failures we
* conclude the pool is basically full.
*/
static isc_result_t
pick_v6_address(struct iasubopt **addr, struct shared_network *shared_network,
const struct data_string *client_id)
pick_v6_address(struct reply_state *reply)
{
struct ipv6_pool *p;
struct ipv6_pool *p = NULL;
struct ipv6_pond *pond;
int i;
int start_pool;
unsigned int attempts;
char tmp_buf[INET6_ADDRSTRLEN];
struct iasubopt **addr = &reply->lease;
/*
* No address pools, we're done.
* Do a quick walk through of the ponds and pools
* to see if we have any NA address pools
*/
if (shared_network->ipv6_pools == NULL) {
for (pond = reply->shared->ipv6_pond; pond != NULL; pond = pond->next) {
if (pond->ipv6_pools == NULL)
continue;
for (i = 0; (p = pond->ipv6_pools[i]) != NULL; i++) {
if (p->pool_type == D6O_IA_NA)
break;
}
if (p != NULL)
break;
}
/* If we get here and p is NULL we have no useful pools */
if (p == NULL) {
log_debug("Unable to pick client address: "
"no IPv6 pools on this shared network");
return ISC_R_NORESOURCES;
}
for (i = 0;; i++) {
p = shared_network->ipv6_pools[i];
if (p == NULL) {
log_debug("Unable to pick client address: "
"no IPv6 address pools "
"on this shared network");
return ISC_R_NORESOURCES;
}
if (p->pool_type == D6O_IA_NA) {
break;
}
}
/*
* Otherwise try to get a lease from the first subnet possible.
*
* We start looking at the last pool we allocated from, unless
* it had a collision trying to allocate an address. This will
* tend to move us into less-filled pools.
* We have at least one pool that could provide an address
* Now we walk through the ponds and pools again and check
* to see if the client is permitted and if an address is
* available
*
* Within a given pond we start looking at the last pool we
* allocated from, unless it had a collision trying to allocate
* an address. This will tend to move us into less-filled pools.
*/
start_pool = shared_network->last_ipv6_pool;
i = start_pool;
do {
p = shared_network->ipv6_pools[i];
if ((p->pool_type == D6O_IA_NA) &&
(create_lease6(p, addr, &attempts, client_id,
cur_time + 120) == ISC_R_SUCCESS)) {
/*
* Record the pool used (or next one if there
* was a collision).
*/
if (attempts > 1) {
i++;
if (shared_network->ipv6_pools[i] == NULL) {
i = 0;
for (pond = reply->shared->ipv6_pond; pond != NULL; pond = pond->next) {
if (((pond->prohibit_list != NULL) &&
(permitted(reply->packet, pond->prohibit_list))) ||
((pond->permit_list != NULL) &&
(!permitted(reply->packet, pond->permit_list))))
continue;
start_pool = pond->last_ipv6_pool;
i = start_pool;
do {
p = pond->ipv6_pools[i];
if ((p->pool_type == D6O_IA_NA) &&
(create_lease6(p, addr, &attempts,
&reply->ia->iaid_duid,
cur_time + 120) == ISC_R_SUCCESS)) {
/*
* Record the pool used (or next one if there
* was a collision).
*/
if (attempts > 1) {
i++;
if (pond->ipv6_pools[i] == NULL) {
i = 0;
}
}
pond->last_ipv6_pool = i;
log_debug("Picking pool address %s",
inet_ntop(AF_INET6, &((*addr)->addr),
tmp_buf, sizeof(tmp_buf)));
return (ISC_R_SUCCESS);
}
shared_network->last_ipv6_pool = i;
log_debug("Picking pool address %s",
inet_ntop(AF_INET6, &((*addr)->addr),
tmp_buf, sizeof(tmp_buf)));
return ISC_R_SUCCESS;
}
i++;
if (shared_network->ipv6_pools[i] == NULL) {
i = 0;
}
} while (i != start_pool);
i++;
if (pond->ipv6_pools[i] == NULL) {
i = 0;
}
} while (i != start_pool);
}
/*
* If we failed to pick an IPv6 address from any of the subnets.
@ -1134,72 +1165,97 @@ try_client_v6_prefix(struct iasubopt **pref,
return result;
}
/*
* Get an IPv6 prefix for the client.
/*!
*
* pref is the result (should be a pointer to NULL on entry)
* packet is the information about the packet from the client
* requested_iaprefix is a hint from the client
* plen is -1 or the requested prefix length
* client_id is the DUID for the client
* \brief Get an IPv6 prefix for the client.
*
* Attempt to find a usable prefix for the client. We walk through
* the ponds checking for permit and deny then through the pools
* seeing if they have an available prefix.
*
* \param reply = the state structure for the current work on this request
* if we create a lease we return it using reply->lease
*
* \return
* ISC_R_SUCCESS = we were able to find an prefix and are returning a
* pointer to the lease
* ISC_R_NORESOURCES = there don't appear to be any free addresses. This
* is probabalistic. We don't exhaustively try the
* address range, instead we hash the duid and if
* the address derived from the hash is in use we
* hash the address. After a number of failures we
* conclude the pool is basically full.
*/
static isc_result_t
pick_v6_prefix(struct iasubopt **pref, int plen,
struct shared_network *shared_network,
const struct data_string *client_id)
pick_v6_prefix(struct reply_state *reply)
{
struct ipv6_pool *p;
struct ipv6_pool *p = NULL;
struct ipv6_pond *pond;
int i;
unsigned int attempts;
char tmp_buf[INET6_ADDRSTRLEN];
struct iasubopt **pref = &reply->lease;
/*
* No prefix pools, we're done.
* Do a quick walk through of the ponds and pools
* to see if we have any prefix pools
*/
if (shared_network->ipv6_pools == NULL) {
for (pond = reply->shared->ipv6_pond; pond != NULL; pond = pond->next) {
if (pond->ipv6_pools == NULL)
continue;
for (i = 0; (p = pond->ipv6_pools[i]) != NULL; i++) {
if (p->pool_type == D6O_IA_PD)
break;
}
if (p != NULL)
break;
}
/* If we get here and p is NULL we have no useful pools */
if (p == NULL) {
log_debug("Unable to pick client prefix: "
"no IPv6 pools on this shared network");
return ISC_R_NORESOURCES;
}
for (i = 0;; i++) {
p = shared_network->ipv6_pools[i];
if (p == NULL) {
log_debug("Unable to pick client prefix: "
"no IPv6 prefix pools "
"on this shared network");
return ISC_R_NORESOURCES;
}
if (p->pool_type == D6O_IA_PD) {
break;
}
}
/*
* Otherwise try to get a prefix.
* We have at least one pool that could provide a prefix
* Now we walk through the ponds and pools again and check
* to see if the client is permitted and if an prefix is
* available
*
*/
for (i = 0;; i++) {
p = shared_network->ipv6_pools[i];
if (p == NULL) {
break;
}
if (p->pool_type != D6O_IA_PD) {
continue;
}
/*
* Try only pools with the requested prefix length if any.
*/
if ((plen >= 0) && (p->units != plen)) {
for (pond = reply->shared->ipv6_pond; pond != NULL; pond = pond->next) {
if (((pond->prohibit_list != NULL) &&
(permitted(reply->packet, pond->prohibit_list))) ||
((pond->permit_list != NULL) &&
(!permitted(reply->packet, pond->permit_list))))
continue;
}
if (create_prefix6(p, pref, &attempts, client_id,
cur_time + 120) == ISC_R_SUCCESS) {
log_debug("Picking pool prefix %s/%u",
inet_ntop(AF_INET6, &((*pref)->addr),
tmp_buf, sizeof(tmp_buf)),
(unsigned) (*pref)->plen);
return ISC_R_SUCCESS;
for (i = 0; (p = pond->ipv6_pools[i]) != NULL; i++) {
if (p->pool_type != D6O_IA_PD) {
continue;
}
/*
* Try only pools with the requested prefix length if any.
*/
if ((reply->preflen >= 0) && (p->units != reply->preflen)) {
continue;
}
if (create_prefix6(p, pref, &attempts, &reply->ia->iaid_duid,
cur_time + 120) == ISC_R_SUCCESS) {
log_debug("Picking pool prefix %s/%u",
inet_ntop(AF_INET6, &((*pref)->addr),
tmp_buf, sizeof(tmp_buf)),
(unsigned) (*pref)->plen);
return (ISC_R_SUCCESS);
}
}
}
@ -1258,6 +1314,7 @@ lease_to_client(struct data_string *reply_ret,
#if defined (RFC3315_PRE_ERRATA_2010_08)
isc_boolean_t no_resources_avail = ISC_FALSE;
#endif
int i;
memset(&packet_oro, 0, sizeof(packet_oro));
@ -1298,20 +1355,26 @@ lease_to_client(struct data_string *reply_ret,
* valid for the shared network the client is on.
*/
if (find_hosts_by_uid(&reply.host, client_id->data, client_id->len,
MDL))
MDL)) {
packet->known = 1;
seek_shared_host(&reply.host, reply.shared);
}
if ((reply.host == NULL) &&
find_hosts_by_option(&reply.host, packet, packet->options, MDL))
find_hosts_by_option(&reply.host, packet, packet->options, MDL)) {
packet->known = 1;
seek_shared_host(&reply.host, reply.shared);
}
/*
* Check for 'hardware' matches last, as some of the synthesis methods
* are not considered to be as reliable.
*/
if ((reply.host == NULL) &&
find_hosts_by_duid_chaddr(&reply.host, client_id))
find_hosts_by_duid_chaddr(&reply.host, client_id)) {
packet->known = 1;
seek_shared_host(&reply.host, reply.shared);
}
/* Process the client supplied IA's onto the reply buffer. */
reply.ia_count = 0;
@ -1412,6 +1475,17 @@ lease_to_client(struct data_string *reply_ret,
reply.shared->group, root_group,
NULL);
/* Execute statements from class scopes. */
for (i = reply.packet->class_count; i > 0; i--) {
execute_statements_in_scope(NULL, reply.packet,
NULL, NULL,
reply.packet->options,
reply.opt_state,
&global_scope,
reply.packet->classes[i - 1]->group,
reply.shared->group, NULL);
}
/* Bring in any configuration from a host record. */
if (reply.host != NULL)
execute_statements_in_scope(NULL, reply.packet,
@ -2183,7 +2257,7 @@ reply_process_addr(struct reply_state *reply, struct option_cache *addr) {
log_fatal("Impossible condition at %s:%d.", MDL);
scope = &reply->lease->scope;
group = reply->lease->ipv6_pool->subnet->group;
group = reply->lease->ipv6_pool->ipv6_pond->group;
}
/*
@ -2254,6 +2328,7 @@ reply_process_addr(struct reply_state *reply, struct option_cache *addr) {
static isc_boolean_t
address_is_owned(struct reply_state *reply, struct iaddr *addr) {
int i;
struct ipv6_pond *pond;
/*
* This faults out addresses that don't match fixed addresses.
@ -2280,7 +2355,16 @@ address_is_owned(struct reply_state *reply, struct iaddr *addr) {
if (lease6_usable(tmp) == ISC_FALSE) {
return (ISC_FALSE);
}
pond = tmp->ipv6_pool->ipv6_pond;
if (((pond->prohibit_list != NULL) &&
(permitted(reply->packet, pond->prohibit_list))) ||
((pond->permit_list != NULL) &&
(!permitted(reply->packet, pond->permit_list))))
return (ISC_FALSE);
iasubopt_reference(&reply->lease, tmp, MDL);
return (ISC_TRUE);
}
}
@ -2416,7 +2500,7 @@ reply_process_ia_ta(struct reply_state *reply, struct option_cache *ia) {
goto bad_temp;
status = reply_process_is_addressed(reply,
&reply->lease->scope,
reply->shared->group);
reply->lease->ipv6_pool->ipv6_pond->group);
if (status != ISC_R_SUCCESS)
goto bad_temp;
status = reply_process_send_addr(reply, &tmp_addr);
@ -2621,7 +2705,8 @@ static isc_boolean_t
temporary_is_available(struct reply_state *reply, struct iaddr *addr) {
struct in6_addr tmp_addr;
struct subnet *subnet;
struct ipv6_pool *pool;
struct ipv6_pool *pool = NULL;
struct ipv6_pond *pond = NULL;
int i;
memcpy(&tmp_addr, addr->iabuf, sizeof(tmp_addr));
@ -2656,14 +2741,25 @@ temporary_is_available(struct reply_state *reply, struct iaddr *addr) {
/*
* Verify that this address is in a temporary pool and try to get it.
*/
if (reply->shared->ipv6_pools == NULL)
return ISC_FALSE;
for (i = 0 ; (pool = reply->shared->ipv6_pools[i]) != NULL ; i++) {
if (pool->pool_type != D6O_IA_TA)
for (pond = reply->shared->ipv6_pond; pond != NULL; pond = pond->next) {
if (((pond->prohibit_list != NULL) &&
(permitted(reply->packet, pond->prohibit_list))) ||
((pond->permit_list != NULL) &&
(!permitted(reply->packet, pond->permit_list))))
continue;
if (ipv6_in_pool(&tmp_addr, pool))
for (i = 0 ; (pool = pond->ipv6_pools[i]) != NULL ; i++) {
if (pool->pool_type != D6O_IA_TA)
continue;
if (ipv6_in_pool(&tmp_addr, pool))
break;
}
if (pool != NULL)
break;
}
if (pool == NULL)
return ISC_FALSE;
if (lease6_exists(pool, &tmp_addr))
@ -2684,60 +2780,83 @@ temporary_is_available(struct reply_state *reply, struct iaddr *addr) {
*/
static isc_result_t
find_client_temporaries(struct reply_state *reply) {
struct shared_network *shared;
int i;
struct ipv6_pool *p;
isc_result_t status;
struct ipv6_pond *pond;
isc_result_t status = ISC_R_NORESOURCES;;
unsigned int attempts;
struct iaddr send_addr;
/*
* No pools, we're done.
* Do a quick walk through of the ponds and pools
* to see if we have any prefix pools
*/
shared = reply->shared;
if (shared->ipv6_pools == NULL) {
for (pond = reply->shared->ipv6_pond; pond != NULL; pond = pond->next) {
if (pond->ipv6_pools == NULL)
continue;
for (i = 0; (p = pond->ipv6_pools[i]) != NULL; i++) {
if (p->pool_type == D6O_IA_TA)
break;
}
if (p != NULL)
break;
}
/* If we get here and p is NULL we have no useful pools */
if (p == NULL) {
log_debug("Unable to get client addresses: "
"no IPv6 pools on this shared network");
return ISC_R_NORESOURCES;
}
status = ISC_R_NORESOURCES;
for (i = 0;; i++) {
p = shared->ipv6_pools[i];
if (p == NULL) {
break;
}
if (p->pool_type != D6O_IA_TA) {
/*
* We have at least one pool that could provide an address
* Now we walk through the ponds and pools again and check
* to see if the client is permitted and if an address is
* available
*/
for (pond = reply->shared->ipv6_pond; pond != NULL; pond = pond->next) {
if (((pond->prohibit_list != NULL) &&
(permitted(reply->packet, pond->prohibit_list))) ||
((pond->permit_list != NULL) &&
(!permitted(reply->packet, pond->permit_list))))
continue;
}
/*
* Get an address in this temporary pool.
*/
status = create_lease6(p, &reply->lease, &attempts,
&reply->client_id, cur_time + 120);
if (status != ISC_R_SUCCESS) {
log_debug("Unable to get a temporary address.");
goto cleanup;
}
for (i = 0; (p = pond->ipv6_pools[i]) != NULL; i++) {
if (p->pool_type != D6O_IA_TA) {
continue;
}
status = reply_process_is_addressed(reply,
&reply->lease->scope,
reply->lease->ipv6_pool->subnet->group);
if (status != ISC_R_SUCCESS) {
goto cleanup;
/*
* Get an address in this temporary pool.
*/
status = create_lease6(p, &reply->lease, &attempts,
&reply->client_id, cur_time + 120);
if (status != ISC_R_SUCCESS) {
log_debug("Unable to get a temporary address.");
goto cleanup;
}
status = reply_process_is_addressed(reply,
&reply->lease->scope,
pond->group);
if (status != ISC_R_SUCCESS) {
goto cleanup;
}
send_addr.len = 16;
memcpy(send_addr.iabuf, &reply->lease->addr, 16);
status = reply_process_send_addr(reply, &send_addr);
if (status != ISC_R_SUCCESS) {
goto cleanup;
}
/*
* reply->lease can't be null as we use it above
* add check if that changes
*/
iasubopt_dereference(&reply->lease, MDL);
}
send_addr.len = 16;
memcpy(send_addr.iabuf, &reply->lease->addr, 16);
status = reply_process_send_addr(reply, &send_addr);
if (status != ISC_R_SUCCESS) {
goto cleanup;
}
/*
* reply->lease can't be null as we use it above
* add check if that changes
*/
iasubopt_dereference(&reply->lease, MDL);
}
cleanup:
@ -2754,7 +2873,8 @@ find_client_temporaries(struct reply_state *reply) {
static isc_result_t
reply_process_try_addr(struct reply_state *reply, struct iaddr *addr) {
isc_result_t status = ISC_R_ADDRNOTAVAIL;
struct ipv6_pool *pool;
struct ipv6_pool *pool = NULL;
struct ipv6_pond *pond = NULL;
int i;
struct data_string data_addr;
@ -2762,18 +2882,61 @@ reply_process_try_addr(struct reply_state *reply, struct iaddr *addr) {
(addr == NULL) || (reply->lease != NULL))
return (DHCP_R_INVALIDARG);
if (reply->shared->ipv6_pools == NULL)
/*
* Do a quick walk through of the ponds and pools
* to see if we have any NA address pools
*/
for (pond = reply->shared->ipv6_pond; pond != NULL; pond = pond->next) {
if (pond->ipv6_pools == NULL)
continue;
for (i = 0; ; i++) {
pool = pond->ipv6_pools[i];
if ((pool == NULL) ||
(pool->pool_type == D6O_IA_NA))
break;
}
if (pool != NULL)
break;
}
/* If we get here and p is NULL we have no useful pools */
if (pool == NULL) {
return (ISC_R_ADDRNOTAVAIL);
}
memset(&data_addr, 0, sizeof(data_addr));
data_addr.len = addr->len;
data_addr.data = addr->iabuf;
for (i = 0 ; (pool = reply->shared->ipv6_pools[i]) != NULL ; i++) {
if (pool->pool_type != D6O_IA_NA)
/*
* We have at least one pool that could provide an address
* Now we walk through the ponds and pools again and check
* to see if the client is permitted and if an address is
* available
*
* Within a given pond we start looking at the last pool we
* allocated from, unless it had a collision trying to allocate
* an address. This will tend to move us into less-filled pools.
*/
for (pond = reply->shared->ipv6_pond; pond != NULL; pond = pond->next) {
if (((pond->prohibit_list != NULL) &&
(permitted(reply->packet, pond->prohibit_list))) ||
((pond->permit_list != NULL) &&
(!permitted(reply->packet, pond->permit_list))))
continue;
status = try_client_v6_address(&reply->lease, pool,
&data_addr);
for (i = 0 ; (pool = pond->ipv6_pools[i]) != NULL ; i++) {
if (pool->pool_type != D6O_IA_NA)
continue;
status = try_client_v6_address(&reply->lease, pool,
&data_addr);
if (status == ISC_R_SUCCESS)
break;
}
if (status == ISC_R_SUCCESS)
break;
}
@ -2812,18 +2975,28 @@ find_client_address(struct reply_state *reply) {
if (reply->old_ia != NULL) {
for (i = 0 ; i < reply->old_ia->num_iasubopt ; i++) {
struct shared_network *candidate_shared;
struct ipv6_pond *pond;
lease = reply->old_ia->iasubopt[i];
candidate_shared = lease->ipv6_pool->shared_network;
pond = lease->ipv6_pool->ipv6_pond;
/*
* Look for the best lease on the client's shared
* network.
* network, that is still permitted
*/
if ((candidate_shared == reply->shared) &&
(lease6_usable(lease) == ISC_TRUE)) {
best_lease = lease_compare(lease, best_lease);
}
if ((candidate_shared != reply->shared) ||
(lease6_usable(lease) != ISC_TRUE))
continue;
if (((pond->prohibit_list != NULL) &&
(permitted(reply->packet, pond->prohibit_list))) ||
((pond->permit_list != NULL) &&
(!permitted(reply->packet, pond->permit_list))))
continue;
best_lease = lease_compare(lease, best_lease);
}
}
@ -2831,8 +3004,7 @@ find_client_address(struct reply_state *reply) {
* abandoned lease.
*/
if ((best_lease == NULL) || (best_lease->state == FTS_ABANDONED)) {
status = pick_v6_address(&reply->lease, reply->shared,
&reply->ia->iaid_duid);
status = pick_v6_address(reply);
} else if (best_lease != NULL) {
iasubopt_reference(&reply->lease, best_lease, MDL);
status = ISC_R_SUCCESS;
@ -2859,7 +3031,7 @@ find_client_address(struct reply_state *reply) {
* be desirable to place the group attachment directly in the pool.
*/
scope = &reply->lease->scope;
group = reply->lease->ipv6_pool->subnet->group;
group = reply->lease->ipv6_pool->ipv6_pond->group;
send_addr.len = 16;
memcpy(send_addr.iabuf, &reply->lease->addr, 16);
@ -2886,6 +3058,7 @@ reply_process_is_addressed(struct reply_state *reply,
struct option_cache *oc;
struct option_state *tmp_options = NULL;
struct on_star *on_star;
int i;
/* Initialize values we will cleanup. */
memset(&data, 0, sizeof(data));
@ -2925,6 +3098,15 @@ reply_process_is_addressed(struct reply_state *reply,
reply->packet->options, reply->opt_state,
scope, group, root_group, on_star);
/* Execute statements from class scopes. */
for (i = reply->packet->class_count; i > 0; i--) {
execute_statements_in_scope(NULL, reply->packet, NULL, NULL,
reply->packet->options,
reply->opt_state, scope,
reply->packet->classes[i - 1]->group,
group, on_star);
}
/*
* If there is a host record, over-ride with values configured there,
* without re-evaluating configuration from the previously executed
@ -3043,6 +3225,15 @@ reply_process_is_addressed(struct reply_state *reply,
reply->packet->options, reply->reply_ia,
scope, group, root_group, NULL);
/* Execute statements from class scopes. */
for (i = reply->packet->class_count; i > 0; i--) {
execute_statements_in_scope(NULL, reply->packet, NULL, NULL,
reply->packet->options,
reply->reply_ia, scope,
reply->packet->classes[i - 1]->group,
group, NULL);
}
/*
* And bring in host record configuration, if any, but not to overlap
* the previous group or its common enclosers.
@ -3540,6 +3731,7 @@ reply_process_prefix(struct reply_state *reply, struct option_cache *pref) {
struct option_cache *oc;
struct data_string iapref, data;
isc_result_t status = ISC_R_SUCCESS;
struct group *group;
/* Initializes values that will be cleaned up. */
memset(&iapref, 0, sizeof(iapref));
@ -3681,11 +3873,19 @@ reply_process_prefix(struct reply_state *reply, struct option_cache *pref) {
log_fatal("Impossible condition at %s:%d.", MDL);
scope = &global_scope;
/* Find the static prefixe's subnet. */
if (find_grouped_subnet(&reply->subnet, reply->shared,
tmp_pref.lo_addr, MDL) == 0)
log_fatal("Impossible condition at %s:%d.", MDL);
group = reply->subnet->group;
subnet_dereference(&reply->subnet, MDL);
} else {
if (reply->lease == NULL)
log_fatal("Impossible condition at %s:%d.", MDL);
scope = &reply->lease->scope;
group = reply->lease->ipv6_pool->ipv6_pond->group;
}
/*
@ -3729,7 +3929,7 @@ reply_process_prefix(struct reply_state *reply, struct option_cache *pref) {
goto cleanup;
}
status = reply_process_is_prefixed(reply, scope, reply->shared->group);
status = reply_process_is_prefixed(reply, scope, group);
if (status != ISC_R_SUCCESS)
goto cleanup;
@ -3757,6 +3957,7 @@ static isc_boolean_t
prefix_is_owned(struct reply_state *reply, struct iaddrcidrnet *pref) {
struct iaddrcidrnetlist *l;
int i;
struct ipv6_pond *pond;
/*
* This faults out prefixes that don't match fixed prefixes.
@ -3785,6 +3986,14 @@ prefix_is_owned(struct reply_state *reply, struct iaddrcidrnet *pref) {
if (lease6_usable(tmp) == ISC_FALSE) {
return (ISC_FALSE);
}
pond = tmp->ipv6_pool->ipv6_pond;
if (((pond->prohibit_list != NULL) &&
(permitted(reply->packet, pond->prohibit_list))) ||
((pond->permit_list != NULL) &&
(!permitted(reply->packet, pond->permit_list))))
return (ISC_FALSE);
iasubopt_reference(&reply->lease, tmp, MDL);
return (ISC_TRUE);
}
@ -3801,7 +4010,8 @@ static isc_result_t
reply_process_try_prefix(struct reply_state *reply,
struct iaddrcidrnet *pref) {
isc_result_t status = ISC_R_ADDRNOTAVAIL;
struct ipv6_pool *pool;
struct ipv6_pool *pool = NULL;
struct ipv6_pond *pond = NULL;
int i;
struct data_string data_pref;
@ -3809,8 +4019,26 @@ reply_process_try_prefix(struct reply_state *reply,
(pref == NULL) || (reply->lease != NULL))
return (DHCP_R_INVALIDARG);
if (reply->shared->ipv6_pools == NULL)
/*
* Do a quick walk through of the ponds and pools
* to see if we have any prefix pools
*/
for (pond = reply->shared->ipv6_pond; pond != NULL; pond = pond->next) {
if (pond->ipv6_pools == NULL)
continue;
for (i = 0; (pool = pond->ipv6_pools[i]) != NULL; i++) {
if (pool->pool_type == D6O_IA_PD)
break;
}
if (pool != NULL)
break;
}
/* If we get here and p is NULL we have no useful pools */
if (pool == NULL) {
return (ISC_R_ADDRNOTAVAIL);
}
memset(&data_pref, 0, sizeof(data_pref));
data_pref.len = 17;
@ -3822,13 +4050,33 @@ reply_process_try_prefix(struct reply_state *reply,
data_pref.buffer->data[0] = (u_int8_t) pref->bits;
memcpy(data_pref.buffer->data + 1, pref->lo_addr.iabuf, 16);
for (i = 0 ; (pool = reply->shared->ipv6_pools[i]) != NULL ; i++) {
if (pool->pool_type != D6O_IA_PD)
/*
* We have at least one pool that could provide a prefix
* Now we walk through the ponds and pools again and check
* to see if the client is permitted and if an prefix is
* available
*
*/
for (pond = reply->shared->ipv6_pond; pond != NULL; pond = pond->next) {
if (((pond->prohibit_list != NULL) &&
(permitted(reply->packet, pond->prohibit_list))) ||
((pond->permit_list != NULL) &&
(!permitted(reply->packet, pond->permit_list))))
continue;
status = try_client_v6_prefix(&reply->lease, pool,
&data_pref);
/* If we found it in this pool (either in use or available),
there is no need to look further. */
for (i = 0; (pool = pond->ipv6_pools[i]) != NULL; i++) {
if (pool->pool_type != D6O_IA_PD) {
continue;
}
status = try_client_v6_prefix(&reply->lease, pool,
&data_pref);
/* If we found it in this pool (either in use or available),
there is no need to look further. */
if ( (status == ISC_R_SUCCESS) || (status == ISC_R_ADDRINUSE) )
break;
}
if ( (status == ISC_R_SUCCESS) || (status == ISC_R_ADDRINUSE) )
break;
}
@ -3849,6 +4097,7 @@ find_client_prefix(struct reply_state *reply) {
struct iasubopt *prefix, *best_prefix = NULL;
struct binding_scope **scope;
int i;
struct group *group;
if (reply->static_prefixes > 0) {
struct iaddrcidrnetlist *l;
@ -3870,27 +4119,48 @@ find_client_prefix(struct reply_state *reply) {
memcpy(&send_pref, &l->cidrnet, sizeof(send_pref));
scope = &global_scope;
/* Find the static prefixe's subnet. */
if (find_grouped_subnet(&reply->subnet, reply->shared,
send_pref.lo_addr, MDL) == 0)
log_fatal("Impossible condition at %s:%d.", MDL);
group = reply->subnet->group;
subnet_dereference(&reply->subnet, MDL);
goto send_pref;
}
if (reply->old_ia != NULL) {
for (i = 0 ; i < reply->old_ia->num_iasubopt ; i++) {
struct shared_network *candidate_shared;
struct ipv6_pond *pond;
prefix = reply->old_ia->iasubopt[i];
candidate_shared = prefix->ipv6_pool->shared_network;
pond = prefix->ipv6_pool->ipv6_pond;
/*
* Consider this prefix if it is in a global pool or
* if it is scoped in a pool under the client's shared
* network.
*/
if (((candidate_shared == NULL) ||
(candidate_shared == reply->shared)) &&
(lease6_usable(prefix) == ISC_TRUE)) {
best_prefix = prefix_compare(reply, prefix,
best_prefix);
}
if (((candidate_shared != NULL) &&
(candidate_shared != reply->shared)) ||
(lease6_usable(prefix) != ISC_TRUE))
continue;
/*
* And check if the prefix is still permitted
*/
if (((pond->prohibit_list != NULL) &&
(permitted(reply->packet, pond->prohibit_list))) ||
((pond->permit_list != NULL) &&
(!permitted(reply->packet, pond->permit_list))))
continue;
best_prefix = prefix_compare(reply, prefix,
best_prefix);
}
}
@ -3898,8 +4168,7 @@ find_client_prefix(struct reply_state *reply) {
* abandoned prefix.
*/
if ((best_prefix == NULL) || (best_prefix->state == FTS_ABANDONED)) {
status = pick_v6_prefix(&reply->lease, reply->preflen,
reply->shared, &reply->client_id);
status = pick_v6_prefix(reply);
} else if (best_prefix != NULL) {
iasubopt_reference(&reply->lease, best_prefix, MDL);
status = ISC_R_SUCCESS;
@ -3922,13 +4191,14 @@ find_client_prefix(struct reply_state *reply) {
log_fatal("Impossible condition at %s:%d.", MDL);
scope = &reply->lease->scope;
group = reply->lease->ipv6_pool->ipv6_pond->group;
send_pref.lo_addr.len = 16;
memcpy(send_pref.lo_addr.iabuf, &reply->lease->addr, 16);
send_pref.bits = (int) reply->lease->plen;
send_pref:
status = reply_process_is_prefixed(reply, scope, reply->shared->group);
status = reply_process_is_prefixed(reply, scope, group);
if (status != ISC_R_SUCCESS)
return status;
@ -3949,6 +4219,7 @@ reply_process_is_prefixed(struct reply_state *reply,
struct option_cache *oc;
struct option_state *tmp_options = NULL;
struct on_star *on_star;
int i;
/* Initialize values we will cleanup. */
memset(&data, 0, sizeof(data));
@ -3988,6 +4259,15 @@ reply_process_is_prefixed(struct reply_state *reply,
reply->packet->options, reply->opt_state,
scope, group, root_group, on_star);
/* Execute statements from class scopes. */
for (i = reply->packet->class_count; i > 0; i--) {
execute_statements_in_scope(NULL, reply->packet, NULL, NULL,
reply->packet->options,
reply->opt_state, scope,
reply->packet->classes[i - 1]->group,
group, on_star);
}
/*
* If there is a host record, over-ride with values configured there,
* without re-evaluating configuration from the previously executed
@ -4091,6 +4371,15 @@ reply_process_is_prefixed(struct reply_state *reply,
reply->packet->options, reply->reply_ia,
scope, group, root_group, NULL);
/* Execute statements from class scopes. */
for (i = reply->packet->class_count; i > 0; i--) {
execute_statements_in_scope(NULL, reply->packet, NULL, NULL,
reply->packet->options,
reply->reply_ia, scope,
reply->packet->classes[i - 1]->group,
group, NULL);
}
/*
* And bring in host record configuration, if any, but not to overlap
* the previous group or its common enclosers.
@ -5888,6 +6177,10 @@ dhcpv6_discard(struct packet *packet) {
static void
build_dhcpv6_reply(struct data_string *reply, struct packet *packet) {
memset(reply, 0, sizeof(*reply));
/* Classify the client */
classify_client(packet);
switch (packet->dhcpv6_msg_type) {
case DHCPV6_SOLICIT:
dhcpv6_solicit(reply, packet);

View File

@ -25,23 +25,109 @@
*
* A brief description of the IPv6 structures as reverse engineered.
*
* There are three major data strucutes involved in the database:
* There are four major data structures in the lease configuraion.
*
* - shared_network - The shared network is the outer enclosing scope for a
* network region that shares a broadcast domain. It is
* composed of one or more subnets all of which are valid
* in the given region. The share network may be
* explicitly defined or implicitly created if there is
* only a subnet statement. This structrure is shared
* with v4. Each shared network statment or naked subnet
* will map to one of these structures
*
* - subnet - The subnet structure mostly specifies the address range
* that could be valid in a given region. This structute
* doesn't include the addresses that the server can delegate
* those are in the ipv6_pool. This structure is also shared
* with v4. Each subnet statement will map to one of these
* structures.
*
* - ipv6_pond - The pond structure is a grouping of the address and prefix
* information via the pointers to the ipv6_pool and the
* allowability of this pool for given clinets via the permit
* lists and the valid TIMEs. This is equivilent to the v4
* pool structure and would have been named ip6_pool except
* that the name was already in use. Generally each pool6
* statement will map to one of these structures. In addition
* there may be one or for each group of naked range6 and
* prefix6 statements within a shared network that share
* the same group of statements.
*
* - ipv6_pool - this contains information about a pool of addresses or prefixes
* that the server is using. This includes a hash table that
* tracks the active items and a pair of heap tables one for
* active items and one for non-active items. The heap tables
* are used to determine the next items to be modified due to
* timing events (expire mostly).
* that the server is using. This includes a hash table that
* tracks the active items and a pair of heap tables one for
* active items and one for non-active items. The heap tables
* are used to determine the next items to be modified due to
* timing events (expire mostly).
*
* The linkages then look like this:
* \verbatim
*+--------------+ +-------------+
*|Shared Network| | ipv6_pond |
*| group | | group |
*| | | permit info |
*| | | next ---->
*| ponds ---->| |
*| |<---- shared |
*| Subnets | | pools |
*+-----|--------+ +------|------+
* | ^ | ^
* | | v |
* | | +-----------|-+
* | | | ipv6_pool | |
* | | | type | |
* | | | ipv6_pond |
* | | | |
* | | | next ---->
* | | | |
* | | | subnet |
* | | +-----|-------+
* | | |
* | | v
* | | +-------------+
* | | | subnet |
* | +---------- shared |
* +----------->| |
* | group |
* +-------------+
*
* The shared network contains a list of all the subnets that are on a broadcast
* doamin. These can be used to determine if an address makes sense in a given
* domain, but the subnets do not contain the addresses the server can delegate.
* Those are stored in the ponds and pools.
*
* In the simple case to find an acceptable address the server would first find
* the shared network the client is on based on either the interface used to
* receive the request or the relay agent's information. From the shared
* network the server will walk through it's list of ponds. For each pond it
* will evaluate the permit information against the (already done) classification.
* If it finds an acceptable pond it will then walk through the pools for that
* pond. The server first checks the type of the pool (NA, TA and PD) agaisnt the
* request and if they match it attemps to find an address within that pool. On
* success the address is used, on failure the server steps to the next pool and
* if necessary to the next pond.
*
* When the server is successful in finding an address it will execute any
* statements assocaited with the pond, then the subnet, then the shared
* network the group field is for in the above picture).
*
* In configurations that don't include either a shared network or a pool6
* statement (or both) the missing pieces are created.
*
*
* There are three major data structuress involved in the lease database:
*
* - ipv6_pool - see above
* - ia_xx - this contains information about a single IA from a request
* normally it will contain one pointer to a lease for the client
* but it may contain more in some circumstances. There are 3
* hash tables to aid in accessing these one each for NA, TA and PD.
* - iasubopt- the v6 lease structure. These are created dynamically when
* a client asks for something and will eventually be destroyed
* if the client doesn't re-ask for that item. A lease has space
* for backpointers to the IA and to the pool to which it belongs.
* The pool backpointer is always filled, the IA pointer may not be.
* - iasubopt - the v6 lease structure. These are created dynamically when
* a client asks for something and will eventually be destroyed
* if the client doesn't re-ask for that item. A lease has space
* for backpointers to the IA and to the pool to which it belongs.
* The pool backpointer is always filled, the IA pointer may not be.
*
* In normal use we then have something like this:
*
@ -523,11 +609,27 @@ lease_index_changed(void *iasubopt, unsigned int new_heap_index) {
}
/*
* Create a new IPv6 lease pool structure.
/*!
*
* - pool must be a pointer to a (struct ipv6_pool *) pointer previously
* initialized to NULL
* \brief Create a new IPv6 lease pool structure
*
* Allocate space for a new ipv6_pool structure and return a reference
* to it, includes setting the reference count to 1.
*
* \param pool = space for returning a referenced pointer to the pool.
* This must point to a space that has been initialzied
* to NULL by the caller.
* \param[in] type = The type of the pool NA, TA or PD
* \param[in] start_addr = The first address in the range for the pool
* \param[in] bits = The contiguous bits of the pool
*
* \return
* ISC_R_SUCCESS = The pool was successfully created, pool points to it.
* DHCP_R_INVALIDARG = One of the arugments was invalid, pool has not been
* modified
* ISC_R_NOMEMORY = The system wasn't able to allocate memory, pool has
* not been modified.
*/
isc_result_t
ipv6_pool_allocate(struct ipv6_pool **pool, u_int16_t type,
@ -576,11 +678,24 @@ ipv6_pool_allocate(struct ipv6_pool **pool, u_int16_t type,
return ISC_R_SUCCESS;
}
/*
* Reference an IPv6 pool structure.
/*!
*
* - pool must be a pointer to a (struct pool *) pointer previously
* initialized to NULL
* \brief reference an IPv6 pool structure.
*
* This function genreates a reference to an ipv6_pool structure
* and increments the reference count on the structure.
*
* \param[out] pool = space for returning a referenced pointer to the pool.
* This must point to a space that has been initialzied
* to NULL by the caller.
* \param[in] src = A pointer to the pool to reference. This must not be
* NULL.
*
* \return
* ISC_R_SUCCESS = The pool was successfully referenced, pool now points
* to src.
* DHCP_R_INVALIDARG = One of the arugments was invalid, pool has not been
* modified.
*/
isc_result_t
ipv6_pool_reference(struct ipv6_pool **pool, struct ipv6_pool *src,
@ -634,12 +749,24 @@ dereference_heap_entry(void *value, void *dummy) {
iasubopt_dereference(&iasubopt, MDL);
}
/*
* Dereference an IPv6 pool structure.
/*!
*
* If it is the last reference, then the memory for the
* structure is freed.
* \brief de-reference an IPv6 pool structure.
*
* This function decrements the reference count in an ipv6_pool structure.
* If this was the last reference then the memory for the structure is
* freed.
*
* \param[in] pool = A pointer to the pointer to the pool that should be
* de-referenced. On success the pointer to the pool
* is cleared. It must not be NULL and must not point
* to NULL.
*
* \return
* ISC_R_SUCCESS = The pool was successfully de-referenced, pool now points
* to NULL
* DHCP_R_INVALIDARG = One of the arugments was invalid, pool has not been
* modified.
*/
isc_result_t
ipv6_pool_dereference(struct ipv6_pool **pool, const char *file, int line) {
@ -804,7 +931,7 @@ static struct in6_addr resany;
/*
* Create a lease for the given address and client duid.
*
* - pool must be a pointer to a (struct pool *) pointer previously
* - pool must be a pointer to a (struct ipv6_pool *) pointer previously
* initialized to NULL
*
* Right now we simply hash the DUID, and if we get a collision, we hash
@ -1255,6 +1382,7 @@ move_lease_to_active(struct ipv6_pool *pool, struct iasubopt *lease) {
}
/*!
*
* \brief Renew a lease in the pool.
*
* The hard_lifetime_end_time of the lease should be set to
@ -1277,8 +1405,8 @@ move_lease_to_active(struct ipv6_pool *pool, struct iasubopt *lease) {
* If the lease is moving to active we call that routine
* which will move it from the inactive list to the active list.
*
* \param pool a pool the lease belongs to
* \param lease the lease to be renewed
* \param pool = a pool the lease belongs to
* \param lease = the lease to be renewed
*
* \return result of the renew operation (ISC_R_SUCCESS if successful,
ISC_R_NOMEMORY when run out of memory)
@ -1518,7 +1646,7 @@ build_prefix6(struct in6_addr *pref,
/*
* Create a lease for the given prefix and client duid.
*
* - pool must be a pointer to a (struct pool *) pointer previously
* - pool must be a pointer to a (struct ipv6_pool *) pointer previously
* initialized to NULL
*
* Right now we simply hash the DUID, and if we get a collision, we hash
@ -2190,4 +2318,128 @@ mark_interfaces_unavailable(void) {
}
}
/*!
* \brief Create a new IPv6 pond structure.
*
* Allocate space for a new ipv6_pond structure and return a reference
* to it, includes setting the reference count to 1.
*
* \param pond = space for returning a referenced pointer to the pond.
* This must point to a space that has been initialzied
* to NULL by the caller.
*
* \return
* ISC_R_SUCCESS = The pond was successfully created, pond points to it.
* DHCP_R_INVALIDARG = One of the arugments was invalid, pond has not been
* modified
* ISC_R_NOMEMORY = The system wasn't able to allocate memory, pond has
* not been modified.
*/
isc_result_t
ipv6_pond_allocate(struct ipv6_pond **pond, const char *file, int line) {
struct ipv6_pond *tmp;
if (pond == NULL) {
log_error("%s(%d): NULL pointer reference", file, line);
return DHCP_R_INVALIDARG;
}
if (*pond != NULL) {
log_error("%s(%d): non-NULL pointer", file, line);
return DHCP_R_INVALIDARG;
}
tmp = dmalloc(sizeof(*tmp), file, line);
if (tmp == NULL) {
return ISC_R_NOMEMORY;
}
tmp->refcnt = 1;
*pond = tmp;
return ISC_R_SUCCESS;
}
/*!
*
* \brief reference an IPv6 pond structure.
*
* This function genreates a reference to an ipv6_pond structure
* and increments the reference count on the structure.
*
* \param[out] pond = space for returning a referenced pointer to the pond.
* This must point to a space that has been initialzied
* to NULL by the caller.
* \param[in] src = A pointer to the pond to reference. This must not be
* NULL.
*
* \return
* ISC_R_SUCCESS = The pond was successfully referenced, pond now points
* to src.
* DHCP_R_INVALIDARG = One of the arugments was invalid, pond has not been
* modified.
*/
isc_result_t
ipv6_pond_reference(struct ipv6_pond **pond, struct ipv6_pond *src,
const char *file, int line) {
if (pond == NULL) {
log_error("%s(%d): NULL pointer reference", file, line);
return DHCP_R_INVALIDARG;
}
if (*pond != NULL) {
log_error("%s(%d): non-NULL pointer", file, line);
return DHCP_R_INVALIDARG;
}
if (src == NULL) {
log_error("%s(%d): NULL pointer reference", file, line);
return DHCP_R_INVALIDARG;
}
*pond = src;
src->refcnt++;
return ISC_R_SUCCESS;
}
/*!
*
* \brief de-reference an IPv6 pond structure.
*
* This function decrements the reference count in an ipv6_pond structure.
* If this was the last reference then the memory for the structure is
* freed.
*
* \param[in] pond = A pointer to the pointer to the pond that should be
* de-referenced. On success the pointer to the pond
* is cleared. It must not be NULL and must not point
* to NULL.
*
* \return
* ISC_R_SUCCESS = The pond was successfully de-referenced, pond now points
* to NULL
* DHCP_R_INVALIDARG = One of the arugments was invalid, pond has not been
* modified.
*/
isc_result_t
ipv6_pond_dereference(struct ipv6_pond **pond, const char *file, int line) {
struct ipv6_pond *tmp;
if ((pond == NULL) || (*pond == NULL)) {
log_error("%s(%d): NULL pointer", file, line);
return DHCP_R_INVALIDARG;
}
tmp = *pond;
*pond = NULL;
tmp->refcnt--;
if (tmp->refcnt < 0) {
log_error("%s(%d): negative refcnt", file, line);
tmp->refcnt = 0;
}
if (tmp->refcnt == 0) {
dfree(tmp, file, line);
}
return ISC_R_SUCCESS;
}
/* unittest moved to server/tests/mdb6_unittest.c */

View File

@ -28,7 +28,7 @@ statement.
Then run the server as root, in debug mode:
# touch /tmp/test.leases
# dhcpd -cf test-a.conf -lf /tmp/test.leases -d
# dhcpd -6 -cf test-a.conf -lf /tmp/test.leases -d
You can invoke the scripts then: