diff options
Diffstat (limited to 'cfparse.y')
-rw-r--r-- | cfparse.y | 1340 |
1 files changed, 1340 insertions, 0 deletions
diff --git a/cfparse.y b/cfparse.y new file mode 100644 index 0000000..dcac3d7 --- /dev/null +++ b/cfparse.y @@ -0,0 +1,1340 @@ +/* $KAME: cfparse.y,v 1.36 2005/05/03 06:46:00 jinmei Exp $ */ + +/* + * Copyright (C) 2002 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. + */ +%{ +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/queue.h> +#include <sys/time.h> + +#include <netinet/in.h> + +#include <arpa/inet.h> + +#include <stdlib.h> +#include <string.h> + +#include "dhcp6.h" +#include "config.h" +#include "common.h" + +extern int lineno; +extern int cfdebug; + +extern void yywarn __P((char *, ...)) + __attribute__((__format__(__printf__, 1, 2))); +extern void yyerror __P((char *, ...)) + __attribute__((__format__(__printf__, 1, 2))); + +#define MAKE_NAMELIST(l, n, p) do { \ + (l) = (struct cf_namelist *)malloc(sizeof(*(l))); \ + if ((l) == NULL) { \ + yywarn("can't allocate memory"); \ + if (p) cleanup_cflist(p); \ + return (-1); \ + } \ + memset((l), 0, sizeof(*(l))); \ + l->line = lineno; \ + l->name = (n); \ + l->params = (p); \ + } while (0) + +#define MAKE_CFLIST(l, t, pp, pl) do { \ + (l) = (struct cf_list *)malloc(sizeof(*(l))); \ + if ((l) == NULL) { \ + yywarn("can't allocate memory"); \ + if (pp) free(pp); \ + if (pl) cleanup_cflist(pl); \ + return (-1); \ + } \ + memset((l), 0, sizeof(*(l))); \ + l->line = lineno; \ + l->type = (t); \ + l->ptr = (pp); \ + l->list = (pl); \ + l->tail = (l); \ + } while (0) + +static struct cf_namelist *iflist_head, *hostlist_head, *iapdlist_head; +static struct cf_namelist *addrpoollist_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; +struct cf_list *cf_sip_list, *cf_sip_name_list; +struct cf_list *cf_nis_list, *cf_nis_name_list; +struct cf_list *cf_nisp_list, *cf_nisp_name_list; +struct cf_list *cf_bcmcs_list, *cf_bcmcs_name_list; +long long cf_refreshtime = -1; + +extern int yylex __P((void)); +extern int cfswitch_buffer __P((char *)); +static int add_namelist __P((struct cf_namelist *, struct cf_namelist **)); +static void cleanup __P((void)); +static void cleanup_namelist __P((struct cf_namelist *)); +static void cleanup_cflist __P((struct cf_list *)); +%} + +%token INTERFACE IFNAME +%token PREFIX_INTERFACE SLA_ID SLA_LEN DUID_ID +%token ID_ASSOC IA_PD IAID IA_NA +%token ADDRESS +%token REQUEST SEND ALLOW PREFERENCE +%token HOST HOSTNAME DUID +%token OPTION RAPID_COMMIT DNS_SERVERS DNS_NAME NTP_SERVERS REFRESHTIME +%token SIP_SERVERS SIP_NAME +%token NIS_SERVERS NIS_NAME +%token NISP_SERVERS NISP_NAME +%token BCMCS_SERVERS BCMCS_NAME +%token INFO_ONLY +%token SCRIPT DELAYEDKEY +%token AUTHENTICATION PROTOCOL ALGORITHM DELAYED RECONFIG HMACMD5 MONOCOUNTER +%token AUTHNAME RDM KEY +%token KEYINFO REALM KEYID SECRET KEYNAME EXPIRE +%token ADDRPOOL POOLNAME RANGE TO ADDRESS_POOL +%token INCLUDE + +%token NUMBER SLASH EOS BCL ECL STRING QSTRING PREFIX INFINITY +%token COMMA + +%union { + long long num; + 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 +%type <list> iapdconf_list iapdconf prefix_interface +%type <list> ianaconf_list ianaconf +%type <list> authparam_list authparam +%type <list> keyparam_list keyparam +%type <prefix> addressparam prefixparam +%type <range> rangeparam +%type <pool> poolparam + +%% +statements: + /* empty */ + | statements statement + ; + +statement: + interface_statement + | host_statement + | option_statement + | ia_statement + | authentication_statement + | key_statement + | addrpool_statement + | include_statement + ; + +interface_statement: + INTERFACE IFNAME BCL declarations ECL EOS + { + struct cf_namelist *ifl; + + MAKE_NAMELIST(ifl, $2, $4); + + if (add_namelist(ifl, &iflist_head)) + return (-1); + } + ; + +host_statement: + HOST HOSTNAME BCL declarations ECL EOS + { + struct cf_namelist *host; + + MAKE_NAMELIST(host, $2, $4); + + if (add_namelist(host, &hostlist_head)) + return (-1); + } + ; + +option_statement: + OPTION DNS_SERVERS address_list EOS + { + if (cf_dns_list == NULL) + cf_dns_list = $3; + else { + cf_dns_list->tail->next = $3; + cf_dns_list->tail = $3->tail; + } + } + | OPTION DNS_NAME QSTRING EOS + { + struct cf_list *l; + + MAKE_CFLIST(l, CFLISTENT_GENERIC, $3, NULL); + + if (cf_dns_name_list == NULL) { + cf_dns_name_list = l; + cf_dns_name_list->tail = l; + cf_dns_name_list->next = NULL; + } else { + cf_dns_name_list->tail->next = l; + cf_dns_name_list->tail = l->tail; + } + } + | OPTION NTP_SERVERS address_list EOS + { + if (cf_ntp_list == NULL) + cf_ntp_list = $3; + else { + cf_ntp_list->tail->next = $3; + cf_ntp_list->tail = $3->tail; + } + } + | OPTION SIP_SERVERS address_list EOS + { + if (cf_sip_list == NULL) + cf_sip_list = $3; + else { + cf_sip_list->tail->next = $3; + cf_sip_list->tail = $3->tail; + } + } + | OPTION SIP_NAME QSTRING EOS + { + struct cf_list *l; + + MAKE_CFLIST(l, CFLISTENT_GENERIC, $3, NULL); + + if (cf_sip_name_list == NULL) { + cf_sip_name_list = l; + cf_sip_name_list->tail = l; + cf_sip_name_list->next = NULL; + } else { + cf_sip_name_list->tail->next = l; + cf_sip_name_list->tail = l->tail; + } + } + | OPTION NIS_SERVERS address_list EOS + { + if (cf_nis_list == NULL) + cf_nis_list = $3; + else { + cf_nis_list->tail->next = $3; + cf_nis_list->tail = $3->tail; + } + } + | OPTION NIS_NAME QSTRING EOS + { + struct cf_list *l; + + MAKE_CFLIST(l, CFLISTENT_GENERIC, $3, NULL); + + if (cf_nis_name_list == NULL) { + cf_nis_name_list = l; + cf_nis_name_list->tail = l; + cf_nis_name_list->next = NULL; + } else { + cf_nis_name_list->tail->next = l; + cf_nis_name_list->tail = l->tail; + } + } + | OPTION NISP_SERVERS address_list EOS + { + if (cf_nisp_list == NULL) + cf_nisp_list = $3; + else { + cf_nisp_list->tail->next = $3; + cf_nisp_list->tail = $3->tail; + } + } + | OPTION NISP_NAME QSTRING EOS + { + struct cf_list *l; + + MAKE_CFLIST(l, CFLISTENT_GENERIC, $3, NULL); + + if (cf_nisp_name_list == NULL) { + cf_nisp_name_list = l; + cf_nisp_name_list->tail = l; + cf_nisp_name_list->next = NULL; + } else { + cf_nisp_name_list->tail->next = l; + cf_nisp_name_list->tail = l->tail; + } + } + | OPTION BCMCS_SERVERS address_list EOS + { + if (cf_bcmcs_list == NULL) + cf_bcmcs_list = $3; + else { + cf_bcmcs_list->tail->next = $3; + cf_bcmcs_list->tail = $3->tail; + } + } + | OPTION BCMCS_NAME QSTRING EOS + { + struct cf_list *l; + + MAKE_CFLIST(l, CFLISTENT_GENERIC, $3, NULL); + + if (cf_bcmcs_name_list == NULL) { + cf_bcmcs_name_list = l; + cf_bcmcs_name_list->tail = l; + cf_bcmcs_name_list->next = NULL; + } else { + cf_bcmcs_name_list->tail->next = l; + cf_bcmcs_name_list->tail = l->tail; + } + } + | OPTION REFRESHTIME NUMBER EOS + { + if (cf_refreshtime == -1) { + cf_refreshtime = $3; + if (cf_refreshtime < -1 || + cf_refreshtime > 0xffffffff) { + /* + * refresh time should not be negative + * according to the lex definition, + * but check it for safety. + */ + yyerror("refresh time is out of range"); + } + if (cf_refreshtime < DHCP6_IRT_MINIMUM) { + /* + * the value MUST NOT be smaller than + * IRT_MINIMUM. + */ + yyerror("refresh time is too small " + "(must not be smaller than %d)", + DHCP6_IRT_MINIMUM); + } + } else { + yywarn("multiple refresh times (ignored)"); + } + } + ; + +ia_statement: + ID_ASSOC IA_PD IAID BCL iapdconf_list ECL EOS + { + struct cf_namelist *iapd; + + MAKE_NAMELIST(iapd, $3, $5); + + if (add_namelist(iapd, &iapdlist_head)) + return (-1); + } + | ID_ASSOC IA_PD BCL iapdconf_list ECL EOS + { + struct cf_namelist *iapd; + char *zero; + + if ((zero = strdup("0")) == NULL) { + yywarn("can't allocate memory"); + return (-1); + } + MAKE_NAMELIST(iapd, zero, $4); + + if (add_namelist(iapd, &iapdlist_head)) + return (-1); + } + | ID_ASSOC IA_NA IAID BCL ianaconf_list ECL EOS + { + struct cf_namelist *iana; + + MAKE_NAMELIST(iana, $3, $5); + + if (add_namelist(iana, &ianalist_head)) + return (-1); + } + | ID_ASSOC IA_NA BCL ianaconf_list ECL EOS + { + struct cf_namelist *iana; + char *zero; + + if ((zero = strdup("0")) == NULL) { + yywarn("can't allocate memory"); + return (-1); + } + MAKE_NAMELIST(iana, zero, $4); + + if (add_namelist(iana, &ianalist_head)) + return (-1); + } + ; + +authentication_statement: + AUTHENTICATION AUTHNAME BCL authparam_list ECL EOS + { + struct cf_namelist *authinfo; + + MAKE_NAMELIST(authinfo, $2, $4); + + if (add_namelist(authinfo, &authinfolist_head)) + return (-1); + } + ; + +key_statement: + KEYINFO KEYNAME BCL keyparam_list ECL EOS + { + struct cf_namelist *key; + + MAKE_NAMELIST(key, $2, $4); + + if (add_namelist(key, &keylist_head)) + return (-1); + } + ; + +include_statement: + INCLUDE QSTRING EOS + { + if (cfswitch_buffer($2)) { + free($2); + return (-1); + } + free($2); + } + ; + +addrpool_statement: + ADDRPOOL POOLNAME BCL declarations ECL EOS + { + struct cf_namelist *pool; + + MAKE_NAMELIST(pool, $2, $4); + + if (add_namelist(pool, &addrpoollist_head)) + return (-1); + } + ; + +address_list: + { $$ = NULL; } + | address_list address_list_ent + { + struct cf_list *head; + + if ((head = $1) == NULL) { + $2->next = NULL; + $2->tail = $2; + head = $2; + } else { + head->tail->next = $2; + head->tail = $2->tail; + } + + $$ = head; + } + ; + +address_list_ent: + STRING + { + struct cf_list *l; + struct in6_addr a0, *a; + + if (inet_pton(AF_INET6, $1, &a0) != 1) { + yywarn("invalid IPv6 address: %s", $1); + free($1); + return (-1); + } + if ((a = malloc(sizeof(*a))) == NULL) { + yywarn("can't allocate memory"); + return (-1); + } + *a = a0; + + MAKE_CFLIST(l, CFLISTENT_GENERIC, a, NULL); + + $$ = l; + } + ; + +declarations: + { $$ = NULL; } + | declarations declaration + { + struct cf_list *head; + + if ((head = $1) == NULL) { + $2->next = NULL; + $2->tail = $2; + head = $2; + } else { + head->tail->next = $2; + head->tail = $2->tail; + } + + $$ = head; + } + ; + +declaration: + SEND dhcpoption_list EOS + { + struct cf_list *l; + + MAKE_CFLIST(l, DECL_SEND, NULL, $2); + + $$ = l; + } + | REQUEST dhcpoption_list EOS + { + struct cf_list *l; + + MAKE_CFLIST(l, DECL_REQUEST, NULL, $2); + + $$ = l; + } + | INFO_ONLY EOS + { + struct cf_list *l; + + MAKE_CFLIST(l, DECL_INFO_ONLY, NULL, NULL); + /* no value */ + $$ = l; + } + | ALLOW dhcpoption EOS + { + struct cf_list *l; + + MAKE_CFLIST(l, DECL_ALLOW, NULL, $2); + + $$ = l; + } + | DUID DUID_ID EOS + { + struct cf_list *l; + + MAKE_CFLIST(l, DECL_DUID, $2, NULL); + + $$ = l; + } + | ADDRESS addressparam EOS + { + struct cf_list *l; + + MAKE_CFLIST(l, DECL_ADDRESS, $2,NULL); + + $$ = l; + } + | PREFIX prefixparam EOS + { + struct cf_list *l; + + MAKE_CFLIST(l, DECL_PREFIX, $2, NULL); + + $$ = l; + } + | PREFERENCE NUMBER EOS + { + struct cf_list *l; + + MAKE_CFLIST(l, DECL_PREFERENCE, NULL, NULL); + l->num = $2; + + $$ = l; + } + | SCRIPT QSTRING EOS + { + struct cf_list *l; + + MAKE_CFLIST(l, DECL_SCRIPT, $2, NULL); + + $$ = l; + } + | DELAYEDKEY STRING EOS + { + struct cf_list *l; + + MAKE_CFLIST(l, DECL_DELAYEDKEY, $2, NULL); + + $$ = 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: + dhcpoption + { + $$ = $1; + } + | dhcpoption COMMA dhcpoption_list + { + $1->next = $3; + $1->tail = $3->tail; + + $$ = $1; + } + ; + +dhcpoption: + RAPID_COMMIT + { + struct cf_list *l; + + MAKE_CFLIST(l, DHCPOPT_RAPID_COMMIT, NULL, NULL); + /* no value */ + $$ = l; + } + | AUTHENTICATION AUTHNAME + { + struct cf_list *l; + + MAKE_CFLIST(l, DHCPOPT_AUTHINFO, NULL, NULL); + l->ptr = $2; + $$ = l; + } + | IA_PD NUMBER + { + struct cf_list *l; + + MAKE_CFLIST(l, DHCPOPT_IA_PD, NULL, NULL); + l->num = $2; + $$ = l; + } + | IA_NA NUMBER + { + struct cf_list *l; + + MAKE_CFLIST(l, DHCPOPT_IA_NA, NULL, NULL); + l->num = $2; + $$ = l; + } + | SIP_SERVERS + { + struct cf_list *l; + + MAKE_CFLIST(l, DHCPOPT_SIP, NULL, NULL); + /* currently no value */ + $$ = l; + } + | SIP_NAME + { + struct cf_list *l; + + MAKE_CFLIST(l, DHCPOPT_SIPNAME, NULL, NULL); + /* currently no value */ + $$ = l; + } + | DNS_SERVERS + { + struct cf_list *l; + + MAKE_CFLIST(l, DHCPOPT_DNS, NULL, NULL); + /* currently no value */ + $$ = l; + } + | DNS_NAME + { + struct cf_list *l; + + MAKE_CFLIST(l, DHCPOPT_DNSNAME, NULL, NULL); + /* currently no value */ + $$ = l; + } + | NTP_SERVERS + { + struct cf_list *l; + + MAKE_CFLIST(l, DHCPOPT_NTP, NULL, NULL); + /* currently no value */ + $$ = l; + } + | REFRESHTIME + { + struct cf_list *l; + + MAKE_CFLIST(l, DHCPOPT_REFRESHTIME, NULL, NULL); + /* currently no value */ + $$ = l; + } + | NIS_SERVERS + { + struct cf_list *l; + + MAKE_CFLIST(l, DHCPOPT_NIS, NULL, NULL); + /* currently no value */ + $$ = l; + } + | NIS_NAME + { + struct cf_list *l; + + MAKE_CFLIST(l, DHCPOPT_NISNAME, NULL, NULL); + /* currently no value */ + $$ = l; + } + | NISP_SERVERS + { + struct cf_list *l; + + MAKE_CFLIST(l, DHCPOPT_NISP, NULL, NULL); + /* currently no value */ + $$ = l; + } + | NISP_NAME + { + struct cf_list *l; + + MAKE_CFLIST(l, DHCPOPT_NISPNAME, NULL, NULL); + /* currently no value */ + $$ = l; + } + | BCMCS_SERVERS + { + struct cf_list *l; + + MAKE_CFLIST(l, DHCPOPT_BCMCS, NULL, NULL); + /* currently no value */ + $$ = l; + } + | BCMCS_NAME + { + struct cf_list *l; + + MAKE_CFLIST(l, DHCPOPT_BCMCSNAME, NULL, NULL); + /* currently no value */ + $$ = l; + } + ; + +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 + { + struct dhcp6_prefix pconf0, *pconf; + + memset(&pconf0, 0, sizeof(pconf0)); + if (inet_pton(AF_INET6, $1, &pconf0.addr) != 1) { + yywarn("invalid IPv6 address: %s", $1); + free($1); + return (-1); + } + free($1); + /* validate other parameters later */ + pconf0.plen = 128; /* XXX this field is ignored */ + if ($2 < 0) + pconf0.pltime = DHCP6_DURATION_INFINITE; + else + pconf0.pltime = (u_int32_t)$2; + pconf0.vltime = pconf0.pltime; + + if ((pconf = malloc(sizeof(*pconf))) == NULL) { + yywarn("can't allocate memory"); + return (-1); + } + *pconf = pconf0; + + $$ = pconf; + } + | STRING duration duration + { + struct dhcp6_prefix pconf0, *pconf; + + memset(&pconf0, 0, sizeof(pconf0)); + if (inet_pton(AF_INET6, $1, &pconf0.addr) != 1) { + yywarn("invalid IPv6 address: %s", $1); + free($1); + return (-1); + } + free($1); + /* validate other parameters later */ + pconf0.plen = 128; /* XXX */ + if ($2 < 0) + pconf0.pltime = DHCP6_DURATION_INFINITE; + else + pconf0.pltime = (u_int32_t)$2; + if ($3 < 0) + pconf0.vltime = DHCP6_DURATION_INFINITE; + else + pconf0.vltime = (u_int32_t)$3; + + if ((pconf = malloc(sizeof(*pconf))) == NULL) { + yywarn("can't allocate memory"); + return (-1); + } + *pconf = pconf0; + + $$ = pconf; + } + ; + +prefixparam: + STRING SLASH NUMBER duration + { + struct dhcp6_prefix pconf0, *pconf; + + memset(&pconf0, 0, sizeof(pconf0)); + if (inet_pton(AF_INET6, $1, &pconf0.addr) != 1) { + yywarn("invalid IPv6 address: %s", $1); + free($1); + return (-1); + } + free($1); + /* validate other parameters later */ + pconf0.plen = $3; + if ($4 < 0) + pconf0.pltime = DHCP6_DURATION_INFINITE; + else + pconf0.pltime = (u_int32_t)$4; + pconf0.vltime = pconf0.pltime; + + if ((pconf = malloc(sizeof(*pconf))) == NULL) { + yywarn("can't allocate memory"); + return (-1); + } + *pconf = pconf0; + + $$ = pconf; + } + | STRING SLASH NUMBER duration duration + { + struct dhcp6_prefix pconf0, *pconf; + + memset(&pconf0, 0, sizeof(pconf0)); + if (inet_pton(AF_INET6, $1, &pconf0.addr) != 1) { + yywarn("invalid IPv6 address: %s", $1); + free($1); + return (-1); + } + free($1); + /* validate other parameters later */ + pconf0.plen = $3; + if ($4 < 0) + pconf0.pltime = DHCP6_DURATION_INFINITE; + else + pconf0.pltime = (u_int32_t)$4; + if ($5 < 0) + pconf0.vltime = DHCP6_DURATION_INFINITE; + else + pconf0.vltime = (u_int32_t)$5; + + if ((pconf = malloc(sizeof(*pconf))) == NULL) { + yywarn("can't allocate memory"); + return (-1); + } + *pconf = pconf0; + + $$ = 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_DURATION_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_DURATION_INFINITE; + else + pool->pltime = (u_int32_t)$2; + if ($3 < 0) + pool->vltime = DHCP6_DURATION_INFINITE; + else + pool->vltime = (u_int32_t)$3; + + $$ = pool; + } + ; + +duration: + INFINITY + { + $$ = -1; + } + | NUMBER + { + $$ = $1; + } + ; + +iapdconf_list: + { $$ = NULL; } + | iapdconf_list iapdconf + { + struct cf_list *head; + + if ((head = $1) == NULL) { + $2->next = NULL; + $2->tail = $2; + head = $2; + } else { + head->tail->next = $2; + head->tail = $2->tail; + } + + $$ = head; + } + ; + +iapdconf: + prefix_interface { $$ = $1; } + | PREFIX prefixparam EOS + { + struct cf_list *l; + + MAKE_CFLIST(l, IACONF_PREFIX, $2, NULL); + + $$ = l; + } + ; + +prefix_interface: + PREFIX_INTERFACE IFNAME BCL ifparams ECL EOS + { + struct cf_list *ifl; + + MAKE_CFLIST(ifl, IACONF_PIF, $2, $4); + $$ = ifl; + } + ; + +ifparams: + { $$ = NULL; } + | ifparams ifparam + { + struct cf_list *head; + + if ((head = $1) == NULL) { + $2->next = NULL; + $2->tail = $2; + head = $2; + } else { + head->tail->next = $2; + head->tail = $2->tail; + } + + $$ = head; + } + ; + +ifparam: + SLA_ID NUMBER EOS + { + struct cf_list *l; + + MAKE_CFLIST(l, IFPARAM_SLA_ID, NULL, NULL); + l->num = $2; + $$ = l; + } + | SLA_LEN NUMBER EOS + { + struct cf_list *l; + + MAKE_CFLIST(l, IFPARAM_SLA_LEN, NULL, NULL); + l->num = $2; + $$ = l; + } + ; + +ianaconf_list: + { $$ = NULL; } + | ianaconf_list ianaconf + { + struct cf_list *head; + + if ((head = $1) == NULL) { + $2->next = NULL; + $2->tail = $2; + head = $2; + } else { + head->tail->next = $2; + head->tail = $2->tail; + } + + $$ = head; + } + ; + +ianaconf: + ADDRESS addressparam EOS + { + struct cf_list *l; + + MAKE_CFLIST(l, IACONF_ADDR, $2, NULL); + + $$ = l; + } + ; + +authparam_list: + { $$ = NULL; } + | authparam_list authparam + { + struct cf_list *head; + + if ((head = $1) == NULL) { + $2->next = NULL; + $2->tail = $2; + head = $2; + } else { + head->tail->next = $2; + head->tail = $2->tail; + } + + $$ = head; + } + ; + +authparam: + PROTOCOL authproto EOS + { + struct cf_list *l; + + MAKE_CFLIST(l, AUTHPARAM_PROTO, NULL, NULL); + l->num = $2; + $$ = l; + } + | ALGORITHM authalg EOS + { + struct cf_list *l; + + MAKE_CFLIST(l, AUTHPARAM_ALG, NULL, NULL); + l->num = $2; + $$ = l; + } + | RDM authrdm EOS + { + struct cf_list *l; + + MAKE_CFLIST(l, AUTHPARAM_RDM, NULL, NULL); + l->num = $2; + $$ = l; + } + | KEY STRING EOS + { + struct cf_list *l; + + MAKE_CFLIST(l, AUTHPARAM_KEY, NULL, NULL); + l->ptr = $2; + $$ = l; + } + ; + +authproto: + DELAYED { $$ = DHCP6_AUTHPROTO_DELAYED; } + | RECONFIG { $$ = DHCP6_AUTHPROTO_RECONFIG; } + ; + +authalg: + HMACMD5 { $$ = DHCP6_AUTHALG_HMACMD5; } + ; + +authrdm: + MONOCOUNTER { $$ = DHCP6_AUTHRDM_MONOCOUNTER; } + ; + +keyparam_list: + { $$ = NULL; } + | keyparam_list keyparam + { + struct cf_list *head; + + if ((head = $1) == NULL) { + $2->next = NULL; + $2->tail = $2; + head = $2; + } else { + head->tail->next = $2; + head->tail = $2->tail; + } + + $$ = head; + } + ; + +keyparam: + REALM QSTRING EOS + { + struct cf_list *l; + + MAKE_CFLIST(l, KEYPARAM_REALM, NULL, NULL); + l->ptr = $2; + $$ = l; + } + | KEYID NUMBER EOS + { + struct cf_list *l; + + MAKE_CFLIST(l, KEYPARAM_KEYID, NULL, NULL); + l->num = $2; + $$ = l; + } + | SECRET QSTRING EOS + { + struct cf_list *l; + + MAKE_CFLIST(l, KEYPARAM_SECRET, NULL, NULL); + l->ptr = $2; + $$ = l; + } + | EXPIRE QSTRING EOS + { + struct cf_list *l; + + MAKE_CFLIST(l, KEYPARAM_EXPIRE, NULL, NULL); + l->ptr = $2; + $$ = l; + } + ; + +%% +/* supplement routines for configuration */ +static int +add_namelist(new, headp) + struct cf_namelist *new, **headp; +{ + struct cf_namelist *n; + + /* check for duplicated configuration */ + for (n = *headp; n; n = n->next) { + if (strcmp(n->name, new->name) == 0) { + yywarn("duplicated name: %s (ignored)", + new->name); + cleanup_namelist(new); + return (0); + } + } + + new->next = *headp; + *headp = new; + + return (0); +} + +/* free temporary resources */ +static void +cleanup() +{ + cleanup_namelist(iflist_head); + iflist_head = NULL; + cleanup_namelist(hostlist_head); + hostlist_head = NULL; + cleanup_namelist(iapdlist_head); + iapdlist_head = NULL; + cleanup_namelist(ianalist_head); + ianalist_head = NULL; + cleanup_namelist(authinfolist_head); + authinfolist_head = NULL; + cleanup_namelist(keylist_head); + keylist_head = NULL; + cleanup_namelist(addrpoollist_head); + addrpoollist_head = NULL; + + cleanup_cflist(cf_sip_list); + cf_sip_list = NULL; + cleanup_cflist(cf_sip_name_list); + cf_sip_name_list = NULL; + cleanup_cflist(cf_dns_list); + cf_dns_list = NULL; + cleanup_cflist(cf_dns_name_list); + cf_dns_name_list = NULL; + cleanup_cflist(cf_ntp_list); + cf_ntp_list = NULL; + cleanup_cflist(cf_nis_list); + cf_nis_list = NULL; + cleanup_cflist(cf_nis_name_list); + cf_nis_name_list = NULL; + cleanup_cflist(cf_nisp_list); + cf_nisp_list = NULL; + cleanup_cflist(cf_nisp_name_list); + cf_nisp_name_list = NULL; + cleanup_cflist(cf_bcmcs_list); + cf_bcmcs_list = NULL; + cleanup_cflist(cf_bcmcs_name_list); + cf_bcmcs_name_list = NULL; +} + +static void +cleanup_namelist(head) + struct cf_namelist *head; +{ + struct cf_namelist *ifp, *ifp_next; + + for (ifp = head; ifp; ifp = ifp_next) { + ifp_next = ifp->next; + cleanup_cflist(ifp->params); + free(ifp->name); + free(ifp); + } +} + +static void +cleanup_cflist(p) + struct cf_list *p; +{ + struct cf_list *n; + + if (p == NULL) + return; + + n = p->next; + if (p->type == DECL_ADDRESSPOOL) { + free(((struct dhcp6_poolspec *)p->ptr)->name); + } + if (p->ptr) + free(p->ptr); + if (p->list) + cleanup_cflist(p->list); + free(p); + + cleanup_cflist(n); +} + +#define config_fail() \ + do { cleanup(); configure_cleanup(); return (-1); } while(0) + +int +cf_post_config() +{ + if (configure_keys(keylist_head)) + config_fail(); + + if (configure_authinfo(authinfolist_head)) + config_fail(); + + if (configure_ia(iapdlist_head, IATYPE_PD)) + config_fail(); + + if (configure_ia(ianalist_head, IATYPE_NA)) + config_fail(); + + if (configure_pool(addrpoollist_head)) + config_fail(); + + if (configure_interface(iflist_head)) + config_fail(); + + if (configure_host(hostlist_head)) + config_fail(); + + if (configure_global_option()) + config_fail(); + + configure_commit(); + cleanup(); + return (0); +} +#undef config_fail + +void +cf_init() +{ + iflist_head = NULL; +} |