Commit 1d9774ab authored by Francis Dupont's avatar Francis Dupont

Cleanup IA_NA dependencies

parent 96b620e5
......@@ -43,8 +43,11 @@ struct option *default_requested_options[NUM_DEFAULT_REQUESTED_OPTS + 1];
static void parse_client_default_duid(struct parse *cfile);
static void parse_client6_lease_statement(struct parse *cfile);
#ifdef DHCPv6
static struct dhc6_ia *parse_client6_ia_statement(struct parse *cfile);
static struct dhc6_ia *parse_client6_ia_na_statement(struct parse *cfile);
static struct dhc6_ia *parse_client6_ia_ta_statement(struct parse *cfile);
static struct dhc6_ia *parse_client6_ia_pd_statement(struct parse *cfile);
static struct dhc6_addr *parse_client6_iaaddr_statement(struct parse *cfile);
static struct dhc6_addr *parse_client6_iaprefix_statement(struct parse *cfile);
#endif /* DHCPv6 */
/* client-conf-file :== client-declarations END_OF_FILE
......@@ -1292,7 +1295,29 @@ parse_client6_lease_statement(struct parse *cfile)
switch(token) {
case IA_NA:
*ia = parse_client6_ia_statement(cfile);
*ia = parse_client6_ia_na_statement(cfile);
if (*ia != NULL) {
ia = &(*ia)->next;
has_ia = 1;
}
no_semi = 1;
break;
case IA_TA:
*ia = parse_client6_ia_ta_statement(cfile);
if (*ia != NULL) {
ia = &(*ia)->next;
has_ia = 1;
}
no_semi = 1;
break;
case IA_PD:
*ia = parse_client6_ia_pd_statement(cfile);
if (*ia != NULL) {
ia = &(*ia)->next;
has_ia = 1;
......@@ -1461,7 +1486,7 @@ parse_client6_lease_statement(struct parse *cfile)
*/
#ifdef DHCPv6
static struct dhc6_ia *
parse_client6_ia_statement(struct parse *cfile)
parse_client6_ia_na_statement(struct parse *cfile)
{
struct data_string id;
struct option_cache *oc = NULL;
......@@ -1476,6 +1501,7 @@ parse_client6_ia_statement(struct parse *cfile)
skip_to_semi(cfile);
return NULL;
}
ia->ia_type = D6O_IA_NA;
/* Get IAID. */
memset(&id, 0, sizeof(id));
......@@ -1593,6 +1619,260 @@ parse_client6_ia_statement(struct parse *cfile)
}
#endif /* DHCPv6 */
/* Parse an ia_ta object from the client lease.
*/
#ifdef DHCPv6
static struct dhc6_ia *
parse_client6_ia_ta_statement(struct parse *cfile)
{
struct data_string id;
struct option_cache *oc = NULL;
struct dhc6_ia *ia;
struct dhc6_addr **addr;
const char *val;
int token, no_semi;
ia = dmalloc(sizeof(*ia), MDL);
if (ia == NULL) {
parse_warn(cfile, "Out of memory allocating IA_TA state.");
skip_to_semi(cfile);
return NULL;
}
ia->ia_type = D6O_IA_TA;
/* Get IAID. */
memset(&id, 0, sizeof(id));
if (parse_cshl(&id, cfile)) {
if (id.len == 4)
memcpy(ia->iaid, id.data, 4);
else {
parse_warn(cfile, "Expecting IAID of length 4, got %d.",
id.len);
skip_to_semi(cfile);
dfree(ia, MDL);
return NULL;
}
data_string_forget(&id, MDL);
} else {
parse_warn(cfile, "Expecting IAID.");
skip_to_semi(cfile);
dfree(ia, MDL);
return NULL;
}
token = next_token(NULL, NULL, cfile);
if (token != LBRACE) {
parse_warn(cfile, "Expecting open curly brace.");
skip_to_semi(cfile);
dfree(ia, MDL);
return NULL;
}
option_state_allocate(&ia->options, MDL);
if (ia->options == NULL) {
parse_warn(cfile, "Unable to allocate option state.");
skip_to_rbrace(cfile, 1);
dfree(ia, MDL);
return NULL;
}
addr = &ia->addrs;
token = next_token(&val, NULL, cfile);
while (token != RBRACE) {
no_semi = 0;
switch (token) {
case STARTS:
token = next_token(&val, NULL, cfile);
if (token == NUMBER) {
ia->starts = atoi(val);
} else {
parse_warn(cfile, "Expecting a number.");
skip_to_semi(cfile);
no_semi = 1;
}
break;
/* No RENEW or REBIND */
case IAADDR:
*addr = parse_client6_iaaddr_statement(cfile);
if (*addr != NULL)
addr = &(*addr)->next;
no_semi = 1;
break;
case OPTION:
if (parse_option_decl(&oc, cfile)) {
save_option(oc->option->universe,
ia->options, oc);
option_cache_dereference(&oc, MDL);
}
no_semi = 1;
break;
default:
parse_warn(cfile, "Unexpected token.");
no_semi = 1;
skip_to_semi(cfile);
break;
}
if (!no_semi)
parse_semi(cfile);
token = next_token(&val, NULL, cfile);
if (token == END_OF_FILE) {
parse_warn(cfile, "Unexpected end of file.");
break;
}
}
return ia;
}
#endif /* DHCPv6 */
/* Parse an ia_pd object from the client lease.
*/
#ifdef DHCPv6
static struct dhc6_ia *
parse_client6_ia_pd_statement(struct parse *cfile)
{
struct data_string id;
struct option_cache *oc = NULL;
struct dhc6_ia *ia;
struct dhc6_addr **pref;
const char *val;
int token, no_semi;
ia = dmalloc(sizeof(*ia), MDL);
if (ia == NULL) {
parse_warn(cfile, "Out of memory allocating IA_PD state.");
skip_to_semi(cfile);
return NULL;
}
ia->ia_type = D6O_IA_PD;
/* Get IAID. */
memset(&id, 0, sizeof(id));
if (parse_cshl(&id, cfile)) {
if (id.len == 4)
memcpy(ia->iaid, id.data, 4);
else {
parse_warn(cfile, "Expecting IAID of length 4, got %d.",
id.len);
skip_to_semi(cfile);
dfree(ia, MDL);
return NULL;
}
data_string_forget(&id, MDL);
} else {
parse_warn(cfile, "Expecting IAID.");
skip_to_semi(cfile);
dfree(ia, MDL);
return NULL;
}
token = next_token(NULL, NULL, cfile);
if (token != LBRACE) {
parse_warn(cfile, "Expecting open curly brace.");
skip_to_semi(cfile);
dfree(ia, MDL);
return NULL;
}
option_state_allocate(&ia->options, MDL);
if (ia->options == NULL) {
parse_warn(cfile, "Unable to allocate option state.");
skip_to_rbrace(cfile, 1);
dfree(ia, MDL);
return NULL;
}
pref = &ia->addrs;
token = next_token(&val, NULL, cfile);
while (token != RBRACE) {
no_semi = 0;
switch (token) {
case STARTS:
token = next_token(&val, NULL, cfile);
if (token == NUMBER) {
ia->starts = atoi(val);
} else {
parse_warn(cfile, "Expecting a number.");
skip_to_semi(cfile);
no_semi = 1;
}
break;
case RENEW:
token = next_token(&val, NULL, cfile);
if (token == NUMBER) {
ia->renew = atoi(val);
} else {
parse_warn(cfile, "Expecting a number.");
skip_to_semi(cfile);
no_semi = 1;
}
break;
case REBIND:
token = next_token(&val, NULL, cfile);
if (token == NUMBER) {
ia->rebind = atoi(val);
} else {
parse_warn(cfile, "Expecting a number.");
skip_to_semi(cfile);
no_semi = 1;
}
break;
case IAPREFIX:
*pref = parse_client6_iaprefix_statement(cfile);
if (*pref != NULL)
pref = &(*pref)->next;
no_semi = 1;
break;
case OPTION:
if (parse_option_decl(&oc, cfile)) {
save_option(oc->option->universe,
ia->options, oc);
option_cache_dereference(&oc, MDL);
}
no_semi = 1;
break;
default:
parse_warn(cfile, "Unexpected token.");
no_semi = 1;
skip_to_semi(cfile);
break;
}
if (!no_semi)
parse_semi(cfile);
token = next_token(&val, NULL, cfile);
if (token == END_OF_FILE) {
parse_warn(cfile, "Unexpected end of file.");
break;
}
}
return ia;
}
#endif /* DHCPv6 */
/* Parse an iaaddr {} structure. */
#ifdef DHCPv6
static struct dhc6_addr *
......@@ -1701,6 +1981,114 @@ parse_client6_iaaddr_statement(struct parse *cfile)
}
#endif /* DHCPv6 */
/* Parse an iaprefix {} structure. */
#ifdef DHCPv6
static struct dhc6_addr *
parse_client6_iaprefix_statement(struct parse *cfile)
{
struct option_cache *oc = NULL;
struct dhc6_addr *pref;
const char *val;
int token, no_semi;
pref = dmalloc(sizeof(*pref), MDL);
if (pref == NULL) {
parse_warn(cfile, "Unable to allocate IAPREFIX state.");
skip_to_semi(cfile);
return NULL;
}
/* Get IP prefix. */
if (!parse_ip6_prefix(cfile, &pref->address, &pref->plen)) {
skip_to_semi(cfile);
dfree(pref, MDL);
return NULL;
}
token = next_token(NULL, NULL, cfile);
if (token != LBRACE) {
parse_warn(cfile, "Expecting open curly bracket.");
skip_to_semi(cfile);
dfree(pref, MDL);
return NULL;
}
option_state_allocate(&pref->options, MDL);
if (pref->options == NULL) {
parse_warn(cfile, "Unable to allocate option state.");
skip_to_semi(cfile);
dfree(pref, MDL);
return NULL;
}
token = next_token(&val, NULL, cfile);
while (token != RBRACE) {
no_semi = 0;
switch (token) {
case STARTS:
token = next_token(&val, NULL, cfile);
if (token == NUMBER) {
pref->starts = atoi(val);
} else {
parse_warn(cfile, "Expecting a number.");
skip_to_semi(cfile);
no_semi = 1;
}
break;
case PREFERRED_LIFE:
token = next_token(&val, NULL, cfile);
if (token == NUMBER) {
pref->preferred_life = atoi(val);
} else {
parse_warn(cfile, "Expecting a number.");
skip_to_semi(cfile);
no_semi = 1;
}
break;
case MAX_LIFE:
token = next_token(&val, NULL, cfile);
if (token == NUMBER) {
pref->max_life = atoi(val);
} else {
parse_warn(cfile, "Expecting a number.");
skip_to_semi(cfile);
no_semi = 1;
}
break;
case OPTION:
if (parse_option_decl(&oc, cfile)) {
save_option(oc->option->universe,
pref->options, oc);
option_cache_dereference(&oc, MDL);
}
no_semi = 1;
break;
default:
parse_warn(cfile, "Unexpected token.");
skip_to_rbrace(cfile, 1);
no_semi = 1;
break;
}
if (!no_semi)
parse_semi(cfile);
token = next_token(&val, NULL, cfile);
if (token == END_OF_FILE) {
parse_warn(cfile, "Unexpected end of file.");
break;
}
}
return pref;
}
#endif /* DHCPv6 */
void parse_string_list (cfile, lp, multiple)
struct parse *cfile;
struct string_list **lp;
......
This diff is collapsed.
......@@ -2487,6 +2487,7 @@ write_client6_lease(struct client_state *client, struct dhc6_lease *lease,
struct dhc6_ia *ia;
struct dhc6_addr *addr;
int stat;
const char *ianame;
/* This should include the current lease. */
if (!rewrite && (leases_written++ > 20)) {
......@@ -2516,21 +2517,44 @@ write_client6_lease(struct client_state *client, struct dhc6_lease *lease,
return ISC_R_IOERROR;
for (ia = lease->bindings ; ia != NULL ; ia = ia->next) {
stat = fprintf(leaseFile, " ia-na %s {\n",
print_hex_1(4, ia->iaid, 12));
switch (ia->ia_type) {
case D6O_IA_NA:
default:
ianame = "ia-na";
break;
case D6O_IA_TA:
ianame = "ia-ta";
break;
case D6O_IA_PD:
ianame = "ia-pd";
break;
}
stat = fprintf(leaseFile, " %s %s {\n",
ianame, print_hex_1(4, ia->iaid, 12));
if (stat <= 0)
return ISC_R_IOERROR;
stat = fprintf(leaseFile, " starts %d;\n"
" renew %u;\n"
" rebind %u;\n",
(int)ia->starts, ia->renew, ia->rebind);
if (ia->ia_type != D6O_IA_TA)
stat = fprintf(leaseFile, " starts %d;\n"
" renew %u;\n"
" rebind %u;\n",
(int)ia->starts, ia->renew, ia->rebind);
else
stat = fprintf(leaseFile, " starts %d;\n",
(int)ia->starts);
if (stat <= 0)
return ISC_R_IOERROR;
for (addr = ia->addrs ; addr != NULL ; addr = addr->next) {
stat = fprintf(leaseFile, " iaaddr %s {\n",
piaddr(addr->address));
if (ia->ia_type != D6O_IA_PD)
stat = fprintf(leaseFile,
" iaaddr %s {\n",
piaddr(addr->address));
else
stat = fprintf(leaseFile,
" iaprefix %s/%d {\n",
piaddr(addr->address),
(int)addr->plen);
if (stat <= 0)
return ISC_R_IOERROR;
......
......@@ -951,8 +951,14 @@ intern(char *atom, enum dhcp_token dfv) {
case 'i':
if (!strcasecmp(atom+1, "a-na"))
return IA_NA;
if (!strcasecmp(atom+1, "a-ta"))
return IA_TA;
if (!strcasecmp(atom+1, "a-pd"))
return IA_PD;
if (!strcasecmp(atom+1, "aaddr"))
return IAADDR;
if (!strcasecmp(atom+1, "aprefix"))
return IAPREFIX;
if (!strcasecmp (atom + 1, "nclude"))
return INCLUDE;
if (!strcasecmp (atom + 1, "nteger"))
......
......@@ -434,6 +434,47 @@ parse_ip6_addr_expr(struct expression **expr,
return make_const_data(expr, addr.iabuf, addr.len, 0, 1, MDL);
}
/*
* ip6-prefix :== ip6-address "/" NUMBER
*/
int
parse_ip6_prefix(struct parse *cfile, struct iaddr *addr, u_int8_t *plen) {
enum dhcp_token token;
const char *val;
int n;
if (!parse_ip6_addr(cfile, addr)) {
return 0;
}
token = next_token(&val, NULL, cfile);
if (token != SLASH) {
parse_warn(cfile, "Slash expected.");
if (token != SEMI)
skip_to_semi(cfile);
return 0;
}
token = next_token(&val, NULL, cfile);
if (token != NUMBER) {
parse_warn(cfile, "Number expected.");
if (token != SEMI)
skip_to_semi(cfile);
return 0;
}
n = atoi(val);
if ((n < 0) || (n > 128)) {
parse_warn(cfile, "Invalid IPv6 prefix length.");
skip_to_semi(cfile);
return 0;
}
if (!is_cidr_mask_valid(addr, n)) {
parse_warn(cfile, "network mask too short.");
skip_to_semi(cfile);
return 0;
}
*plen = n;
return 1;
}
/*
* ip-address-with-subnet :== ip-address |
* ip-address "/" NUMBER
......
......@@ -889,6 +889,7 @@ struct client_lease {
struct dhc6_addr {
struct dhc6_addr *next;
struct iaddr address;
u_int8_t plen;
/* Address state flags. */
#define DHC6_ADDR_DEPREFFED 0x01
......@@ -905,6 +906,7 @@ struct dhc6_addr {
struct dhc6_ia {
struct dhc6_ia *next;
unsigned char iaid[4];
u_int16_t ia_type;
TIME starts;
u_int32_t renew;
......@@ -1308,6 +1310,7 @@ typedef struct hash_table iaaddr_hash_t;
struct iaaddr {
int refcnt; /* reference count */
struct in6_addr addr; /* IPv6 address */
u_int8_t plen; /* unused/placeholder */
binding_state_t state; /* state */
struct binding_scope *scope; /* "set var = value;" */
time_t valid_lifetime_end_time; /* time address expires */
......@@ -1326,12 +1329,14 @@ struct iaaddr {
struct ia_na {
int refcnt; /* reference count */
struct data_string iaid_duid; /* from the client */
u_int16_t ia_type; /* IA_NA or IA_TA */
int num_iaaddr; /* number of IAADDR for this IA_NA */
int max_iaaddr; /* space available for IAADDR */
struct iaaddr **iaaddr; /* pointers to the various IAADDRs */
};
extern ia_na_hash_t *ia_active;
extern ia_na_hash_t *ia_na_active;
extern ia_na_hash_t *ia_ta_active;
struct ipv6_pool {
int refcnt; /* reference count */
......@@ -1350,6 +1355,51 @@ struct ipv6_pool {
extern struct ipv6_pool **pools;
extern int num_pools;
/* Sames thing for IA_PDs */
typedef struct hash_table ia_pd_hash_t;
typedef struct hash_table iaprefix_hash_t;
struct iaprefix {
/* Must keep the same layout than iaaddr */
int refcnt; /* reference count */
struct in6_addr pref; /* IPv6 prefix */
u_int8_t plen; /* prefix length */
binding_state_t state; /* state */
struct binding_scope *scope; /* "set var = value;" */
time_t valid_lifetime_end_time; /* time prefix expires */
struct ia_pd *ia_pd; /* IA for this prefix */
struct ipv6_ppool *ipv6_ppool; /* pool for this prefix */
int heap_index; /* index into heap, or -1
(internal use only) */
};