1/*	$Id: server6_parse.y,v 1.1.1.1 2006/12/04 00:45:34 Exp $	*/
2
3/*
4 * Copyright (C) International Business Machines  Corp., 2003
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the project nor the names of its contributors
16 *    may be used to endorse or promote products derived from this software
17 *    without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32/* Author: Shirley Ma, xma@us.ibm.com */
33
34%{
35
36#include <stdio.h>
37#include <string.h>
38#include <stdlib.h>
39#include <syslog.h>
40#include <errno.h>
41#include <sys/socket.h>
42#include <net/if.h>
43#include <netinet/in.h>
44#include "queue.h"
45#include "dhcp6.h"
46#include "config.h"
47#include "common.h"
48#include "server6_conf.h"
49#include "hash.h"
50#include "lease.h"
51
52extern int num_lines;
53extern char *sfyytext;
54extern int sock;
55static struct interface *ifnetworklist = NULL;
56static struct link_decl *linklist = NULL;
57static struct host_decl *hostlist = NULL;
58static struct pool_decl *poollist = NULL;
59
60static struct interface *ifnetwork = NULL;
61static struct link_decl *link = NULL;
62static struct host_decl *host = NULL;
63static struct pool_decl *pool = NULL;
64static struct scopelist *currentscope = NULL;
65static struct scopelist *currentgroup = NULL;
66static int allow = 0;
67
68static void cleanup(void);
69void sfyyerror(char *msg);
70
71#define ABORT	do { cleanup(); YYABORT; } while (0)
72
73extern int sfyylex __P((void));
74%}
75%token	<str>	INTERFACE IFNAME
76%token	<str>	PREFIX
77%token	<str>	LINK
78%token	<str>	RELAY
79
80%token	<str>	STRING
81%token	<num>	NUMBER
82%token	<snum>	SIGNEDNUMBER
83%token	<dec>	DECIMAL
84%token	<bool>	BOOLEAN
85%token	<addr>	IPV6ADDR
86%token 	<str>	INFINITY
87
88%token	<str>	HOST
89%token	<str>	POOL
90%token	<str>	RANGE
91%token	<str>	GROUP
92%token	<str>	LINKLOCAL
93%token	<str>	OPTION ALLOW SEND
94%token	<str>	PREFERENCE
95%token	<str>	RENEWTIME
96%token	<str>	REBINDTIME
97%token	<str>	RAPIDCOMMIT
98%token	<str>	ADDRESS
99%token	<str>	VALIDLIFETIME
100%token	<str>	PREFERLIFETIME
101%token	<str>	UNICAST
102%token	<str>	TEMPIPV6ADDR
103%token	<str>	DNS_SERVERS
104%token	<str>	SIP_SERVERS
105%token	<str>	NTP_SERVERS
106%token	<str>	DUID DUID_ID
107%token	<str>	IAID IAIDINFO
108%token  <str>	INFO_ONLY
109%token	<str>	TO
110
111%token	<str>	BAD_TOKEN
112%type	<str>	name
113%type   <num>	number_or_infinity
114%type	<dhcp6addr>	hostaddr6 hostprefix6 addr6para v6address
115
116%union {
117	unsigned int	num;
118	int 	snum;
119	char	*str;
120	int 	dec;
121	int	bool;
122	struct in6_addr	addr;
123	struct dhcp6_addr *dhcp6addr;
124}
125%%
126statements
127	:
128	| statements networkdef
129	;
130
131networkdef
132	: ifdef
133	| groupdef
134	| confdecl
135	| linkdef
136	;
137
138ifdef
139	: ifhead '{' ifbody  '}' ';'
140	{
141		if (linklist) {
142			ifnetwork->linklist = linklist;
143			linklist = NULL;
144		}
145		if (hostlist) {
146			ifnetwork->hostlist = hostlist;
147			hostlist = NULL;
148		}
149		if (currentgroup)
150			ifnetwork->group = currentgroup->scope;
151
152		dprintf(LOG_DEBUG, "interface definition for %s is ok", ifnetwork->name);
153		ifnetwork->next = ifnetworklist;
154		ifnetworklist = ifnetwork;
155		ifnetwork = NULL;
156
157		globalgroup->iflist = ifnetworklist;
158
159		/* leave interface scope we know the current scope is not point to NULL*/
160		currentscope = pop_double_list(currentscope);
161	}
162	;
163
164ifhead
165	: INTERFACE IFNAME
166	{
167		struct interface *temp_if = ifnetworklist;
168		while (temp_if)
169		{
170			if (!strcmp(temp_if->name, $2))
171			{
172				dprintf(LOG_ERR, "duplicate interface definition for %s",
173					temp_if->name);
174				ABORT;
175			}
176			temp_if = temp_if->next;
177		}
178		ifnetwork = (struct interface *)malloc(sizeof(*ifnetwork));
179		if (ifnetwork == NULL) {
180			dprintf(LOG_ERR, "failed to allocate memory");
181			ABORT;
182		}
183		memset(ifnetwork, 0, sizeof(*ifnetwork));
184		TAILQ_INIT(&ifnetwork->ifscope.dnslist.addrlist);
185		TAILQ_INIT(&ifnetwork->ifscope.siplist);
186		TAILQ_INIT(&ifnetwork->ifscope.ntplist);
187		strncpy(ifnetwork->name, $2, strlen($2));
188		if (get_linklocal(ifnetwork->name, &ifnetwork->linklocal) < 0) {
189			dprintf(LOG_ERR, "get device %s linklocal failed", ifnetwork->name);
190		}
191
192		/* check device, if the device is not available,
193		 * it is OK, it might be added later
194		 * so keep this in the configuration file.
195		 */
196		if (if_nametoindex(ifnetwork->name) == 0) {
197			dprintf(LOG_ERR, "this device %s doesn't exist.", $2);
198		}
199		/* set up hw_addr, link local, primary ipv6addr */
200		/* enter interface scope */
201		currentscope = push_double_list(currentscope, &ifnetwork->ifscope);
202		if (currentscope == NULL)
203			ABORT;
204	}
205	;
206ifbody
207	:
208	| ifbody ifparams
209	;
210
211ifparams
212	: linkdef
213	| hostdef
214	| groupdef
215	| confdecl
216	;
217
218linkdef
219	: linkhead '{' linkbody '}' ';'
220	{
221		if (poollist) {
222			link->poollist = poollist;
223			poollist = NULL;
224		}
225		if (currentgroup)
226			link->group = currentgroup->scope;
227
228		link->next = linklist;
229		linklist = link;
230		link = NULL;
231		/* leave iink scope we know the current scope is not point to NULL*/
232		currentscope = pop_double_list(currentscope);
233	}
234	;
235
236linkhead
237	: LINK name
238	{
239		struct link_decl *temp_sub = linklist;
240		/* memory allocation for link */
241		link = (struct link_decl *)malloc(sizeof(*link));
242		if (link == NULL) {
243			dprintf(LOG_ERR, "failed to allocate memory");
244			ABORT;
245		}
246		memset(link, 0, sizeof(*link));
247		TAILQ_INIT(&link->linkscope.dnslist.addrlist);
248		TAILQ_INIT(&link->linkscope.siplist);
249		TAILQ_INIT(&link->linkscope.ntplist);
250		while (temp_sub) {
251			if (!strcmp(temp_sub->name, $2))
252			{
253				dprintf(LOG_ERR, "duplicate link definition for %s", $2);
254				ABORT;
255			}
256			temp_sub = temp_sub->next;
257		}
258		/* link set */
259		strncpy(link->name, $2, strlen($2));
260		if (ifnetwork)
261			link->network = ifnetwork;
262		else {
263			/* create a ifnetwork for this interface */
264		}
265		link->relaylist = NULL;
266		link->seglist = NULL;
267		/* enter link scope */
268		currentscope = push_double_list(currentscope, &link->linkscope);
269		if (currentscope == NULL)
270			ABORT;
271	}
272	;
273
274linkbody
275	:
276	| linkbody linkparams
277	;
278
279linkparams
280	: pooldef
281	| rangedef
282	| prefixdef
283	| hostdef
284	| groupdef
285	| confdecl
286	| relaylist
287	;
288
289relaylist
290	: relaylist relaypara
291	| relaypara
292	;
293
294relaypara
295	: RELAY IPV6ADDR '/' NUMBER ';'
296	{
297		struct v6addrlist *temprelay;
298		if (!link) {
299			dprintf(LOG_ERR, "relay must be defined under link");
300			ABORT;
301		}
302		temprelay = (struct v6addrlist *)malloc(sizeof(*temprelay));
303		if (temprelay == NULL) {
304			dprintf(LOG_ERR, "failed to allocate memory");
305			ABORT;
306		}
307		memset(temprelay, 0, sizeof(*temprelay));
308		memcpy(&temprelay->v6addr.addr, &$2, sizeof(temprelay->v6addr.addr));
309		temprelay->v6addr.plen = $4;
310		temprelay->next = link->relaylist;
311		link->relaylist = temprelay;
312		temprelay = NULL;
313	}
314	;
315
316pooldef
317	: poolhead '{' poolbody '}' ';'
318	{
319		if (currentgroup)
320			pool->group = currentgroup->scope;
321		pool->next = poollist;
322		poollist = pool;
323		pool = NULL;
324		/* leave pool scope we know the current scope is not point to NULL*/
325		currentscope = pop_double_list(currentscope);
326	}
327	;
328
329poolhead
330	: POOL
331	{
332		if (!link) {
333			dprintf(LOG_ERR, "pooldef must be defined under link");
334			ABORT;
335		}
336		pool = (struct pool_decl *)malloc(sizeof(*pool));
337		if (pool == NULL) {
338			dprintf(LOG_ERR, "fail to allocate memory");
339			ABORT;
340		}
341		memset(pool, 0, sizeof(*pool));
342		TAILQ_INIT(&pool->poolscope.dnslist.addrlist);
343		TAILQ_INIT(&pool->poolscope.siplist);
344		TAILQ_INIT(&pool->poolscope.ntplist);
345		if (link)
346			pool->link = link;
347
348		/* enter pool scope */
349		currentscope = push_double_list(currentscope, &pool->poolscope);
350		if (currentscope == NULL)
351			ABORT;
352	}
353	;
354
355poolbody
356	:
357	| poolbody poolparas
358	;
359
360poolparas
361	: hostdef
362	| groupdef
363	| rangedef
364	| prefixdef
365	| confdecl
366	;
367
368prefixdef
369	: PREFIX IPV6ADDR '/' NUMBER ';'
370	{
371		struct v6prefix *v6prefix, *v6prefix0;
372		struct v6addr *prefix;
373		if (!link) {
374			dprintf(LOG_ERR, "prefix must be defined under link");
375			ABORT;
376		}
377		v6prefix = (struct v6prefix *)malloc(sizeof(*v6prefix));
378		if (v6prefix == NULL) {
379			dprintf(LOG_ERR, "failed to allocate memory");
380			ABORT;
381		}
382		memset(v6prefix, 0, sizeof(*v6prefix));
383		v6prefix->link = link;
384		if (pool)
385			v6prefix->pool = pool;
386		/* make sure the range ipv6 address within the prefixaddr */
387		if ($4 > 128 || $4 < 0) {
388			dprintf(LOG_ERR, "invalid prefix length in line %d", num_lines);
389			ABORT;
390		}
391		prefix = getprefix(&$2, $4);
392		for (v6prefix0 = link->prefixlist; v6prefix0; v6prefix0 = v6prefix0->next) {
393			if (IN6_ARE_ADDR_EQUAL(prefix, &v6prefix0->prefix.addr) &&
394					$4 == v6prefix0->prefix.plen)  {
395				dprintf(LOG_ERR, "duplicated prefix defined within same link");
396				ABORT;
397			}
398		}
399		/* check the assigned prefix is not reserved pv6 addresses */
400		if (IN6_IS_ADDR_RESERVED(prefix)) {
401			dprintf(LOG_ERR, "config reserved prefix");
402			ABORT;
403		}
404		memcpy(&v6prefix->prefix, prefix, sizeof(v6prefix->prefix));
405		v6prefix->next = link->prefixlist;
406		link->prefixlist = v6prefix;
407		free(prefix);
408	}
409	;
410
411rangedef
412	: RANGE IPV6ADDR TO IPV6ADDR '/' NUMBER ';'
413	{
414		struct v6addrseg *seg, *temp_seg;
415		struct v6addr *prefix1, *prefix2;
416		if (!link) {
417			dprintf(LOG_ERR, "range must be defined under link");
418			ABORT;
419		}
420		seg = (struct v6addrseg *)malloc(sizeof(*seg));
421		if (seg == NULL) {
422			dprintf(LOG_ERR, "failed to allocate memory");
423			ABORT;
424		}
425		memset(seg, 0, sizeof(*seg));
426		temp_seg = link->seglist;
427		seg->link = link;
428		if (pool)
429			seg->pool = pool;
430		/* make sure the range ipv6 address within the prefixaddr */
431		if ($6 > 128 || $6 < 0) {
432			dprintf(LOG_ERR, "invalid prefix length in line %d", num_lines);
433			ABORT;
434		}
435		prefix1 = getprefix(&$2, $6);
436		prefix2 = getprefix(&$4, $6);
437		if (!prefix1 || !prefix2) {
438			dprintf(LOG_ERR, "address range defined error");
439			ABORT;
440		}
441		if (ipv6addrcmp(&prefix1->addr, &prefix2->addr)) {
442			dprintf(LOG_ERR,
443				"address range defined doesn't in the same prefix range");
444			ABORT;
445		}
446		if (ipv6addrcmp(&$2, &$4) < 0) {
447			memcpy(&seg->min, &$2, sizeof(seg->min));
448			memcpy(&seg->max, &$4, sizeof(seg->max));
449		} else {
450			memcpy(&seg->max, &$2, sizeof(seg->max));
451			memcpy(&seg->min, &$4, sizeof(seg->min));
452		}
453		/* check the assigned addresses are not reserved ipv6 addresses */
454		if (IN6_IS_ADDR_RESERVED(&seg->max) || IN6_IS_ADDR_RESERVED(&seg->max)) {
455			dprintf(LOG_ERR, "config reserved ipv6address");
456			ABORT;
457		}
458
459		memcpy(&seg->prefix, prefix1, sizeof(seg->prefix));
460		memcpy(&seg->free, &seg->min, sizeof(seg->free));
461		if (pool)
462			seg->pool = pool;
463		/* make sure there is no overlap in the rangelist */
464		/* the segaddr is sorted by prefix len, thus most specific
465		   ipv6 address is going to be assigned.
466		 */
467		if (!temp_seg) {
468			seg->next = NULL;
469			seg->prev = NULL;
470			link->seglist = seg;
471		} else {
472			for (; temp_seg; temp_seg = temp_seg->next) {
473				if ( prefix1->plen < temp_seg->prefix.plen) {
474					if (temp_seg->next == NULL) {
475						temp_seg->next = seg;
476						seg->prev = temp_seg;
477						seg->next = NULL;
478						break;
479					}
480					continue;
481				}
482				if (prefix1->plen == temp_seg->prefix.plen) {
483	     				if (!(ipv6addrcmp(&seg->min, &temp_seg->max) > 0
484					    || ipv6addrcmp(&seg->max, &temp_seg->min) < 0)) {
485		   				dprintf(LOG_ERR, "overlap range addr defined");
486		   				ABORT;
487					}
488				}
489				if (temp_seg->prev == NULL) {
490					link->seglist = seg;
491					seg->prev = NULL;
492				} else {
493					temp_seg->prev->next = seg;
494					seg->prev = temp_seg->prev;
495				}
496				temp_seg->prev = seg;
497				seg->next = temp_seg;
498				break;
499			}
500		}
501		free(prefix1);
502		free(prefix2);
503	}
504	;
505
506groupdef
507	: grouphead '{' groupbody  '}' ';'
508	{
509		/* return to prev group scope if any */
510		currentgroup = pop_double_list(currentgroup);
511
512		/* leave current group scope */
513		currentscope = pop_double_list(currentscope);
514	}
515	;
516
517groupbody
518	:
519	| groupbody groupparas
520	;
521
522groupparas
523	: hostdef
524	| pooldef
525	| linkdef
526	| rangedef
527	| prefixdef
528	| ifdef
529	| confdecl
530	;
531
532grouphead
533	: GROUP
534	{
535		struct scope *groupscope;
536		groupscope = (struct scope *)malloc(sizeof(*groupscope));
537		if (groupscope == NULL) {
538			dprintf(LOG_ERR, "group memory allocation failed");
539			ABORT;
540		}
541		memset(groupscope, 0, sizeof(*groupscope));
542		TAILQ_INIT(&groupscope->dnslist.addrlist);
543		TAILQ_INIT(&groupscope->siplist);
544		TAILQ_INIT(&groupscope->ntplist);
545		/* set up current group */
546		currentgroup = push_double_list(currentgroup, groupscope);
547		if (currentgroup == NULL)
548			ABORT;
549
550		/* enter group scope  */
551		currentscope = push_double_list(currentscope, groupscope);
552		if (currentscope == NULL)
553			ABORT;
554	}
555	;
556
557hostdef
558	: hosthead '{' hostbody '}' ';'
559	{
560		struct host_decl *temp_host = hostlist;
561		while (temp_host)
562		{
563			if (temp_host->iaidinfo.iaid == host->iaidinfo.iaid) {
564				dprintf(LOG_ERR, "duplicated host %d redefined",
565					host->iaidinfo.iaid);
566				ABORT;
567			}
568			temp_host = temp_host->next;
569		}
570		if (currentgroup)
571			host->group = currentgroup->scope;
572		host->next = hostlist;
573		hostlist = host;
574		host = NULL;
575		/* leave host scope we know the current scope is not point to NULL*/
576		currentscope = pop_double_list(currentscope);
577	}
578	;
579
580
581hosthead
582	: HOST name
583	{
584		struct host_decl *temp_host = hostlist;
585		while (temp_host)
586		{
587			if (!strcmp(temp_host->name, $2)) {
588				dprintf(LOG_ERR, "duplicated host %s redefined", $2);
589				ABORT;
590			}
591			temp_host = temp_host->next;
592		}
593		host = (struct host_decl *)malloc(sizeof(*host));
594		if (host == NULL) {
595			dprintf(LOG_ERR, "fail to allocate memory");
596			ABORT;
597		}
598		memset(host, 0, sizeof(*host));
599		TAILQ_INIT(&host->addrlist);
600		TAILQ_INIT(&host->prefixlist);
601		TAILQ_INIT(&host->hostscope.dnslist.addrlist);
602		TAILQ_INIT(&host->hostscope.siplist);
603		TAILQ_INIT(&host->hostscope.ntplist);
604		host->network = ifnetwork;
605		strncpy(host->name, $2, strlen($2));
606		/* enter host scope */
607		currentscope = push_double_list(currentscope, &host->hostscope);
608		if (currentscope == NULL)
609			ABORT;
610	}
611	;
612
613hostbody
614	: hostbody hostdecl
615	| hostdecl
616	;
617
618hostdecl
619	: DUID DUID_ID ';'
620	{
621		if (host == NULL) {
622			dprintf(LOG_DEBUG, "duid should be defined under host decl");
623			ABORT;
624		}
625		configure_duid($2, &host->cid);
626	}
627	| iaiddef
628	| hostparas
629	;
630
631iaiddef
632	: IAIDINFO '{' iaidbody '}' ';'
633	{
634	}
635	;
636
637iaidbody
638	: iaidbody RENEWTIME number_or_infinity ';'
639	{
640		host->iaidinfo.renewtime = $3;
641	}
642	| iaidbody REBINDTIME number_or_infinity ';'
643	{
644		host->iaidinfo.rebindtime = $3;
645	}
646	| iaidpara
647	;
648
649iaidpara
650	: IAID NUMBER ';'
651	{
652		if (host == NULL) {
653			dprintf(LOG_DEBUG, "iaid should be defined under host decl");
654			ABORT;
655		}
656		host->iaidinfo.iaid = $2;
657	}
658	;
659
660hostparas
661	: hostparas hostpara
662	| hostpara
663	;
664
665hostpara
666	: hostaddr6
667	{
668		if (host == NULL) {
669			dprintf(LOG_DEBUG, "address should be defined under host decl");
670			ABORT;
671		}
672		dhcp6_add_listval(&host->addrlist, $1, DHCP6_LISTVAL_DHCP6ADDR);
673		if (hash_add(host_addr_hash_table, &($1->addr), $1) != 0) {
674			dprintf(LOG_ERR, "%s" "hash add lease failed for %s",
675				FNAME, in6addr2str(&($1->addr), 0));
676			free($1);
677			return (-1);
678		}
679	}
680	| hostprefix6
681	{
682		if (host == NULL) {
683			dprintf(LOG_DEBUG, "prefix should be defined under host decl");
684			ABORT;
685		}
686		dhcp6_add_listval(&host->prefixlist, $1, DHCP6_LISTVAL_DHCP6ADDR);
687	}
688	| optiondecl
689	;
690
691hostaddr6
692	: ADDRESS '{' addr6para '}' ';'
693	{
694		$3->type = IANA;
695		$$ = $3;
696	}
697	;
698
699hostprefix6
700	: PREFIX '{' addr6para '}' ';'
701	{
702		$3->type = IAPD;
703		$$ = $3;
704	}
705	;
706
707addr6para
708	: addr6para VALIDLIFETIME number_or_infinity ';'
709	{
710		$1->validlifetime = $3;
711	}
712	| addr6para PREFERLIFETIME number_or_infinity ';'
713	{
714		$1->preferlifetime = $3;
715	}
716	| v6address
717	{
718		$$ = $1;
719	}
720	;
721
722v6address
723	: IPV6ADDR '/' NUMBER ';'
724	{
725		struct dhcp6_addr *temp;
726		temp = (struct dhcp6_addr *)malloc(sizeof(*temp));
727		if (temp == NULL) {
728			dprintf(LOG_ERR, "v6addr memory allocation failed");
729			ABORT;
730		}
731		memset(temp, 0, sizeof(*temp));
732		memcpy(&temp->addr, &$1, sizeof(temp->addr));
733		if ($3 > 128 || $3 < 0) {
734			dprintf(LOG_ERR, "invalid prefix length in line %d", num_lines);
735			ABORT;
736		}
737		temp->plen = $3;
738		$$ = temp;
739	}
740	;
741
742optiondecl
743	: optionhead optionpara
744	;
745
746optionhead
747	: SEND
748	{
749		if (!currentscope) {
750			currentscope = push_double_list(currentscope, &globalgroup->scope);
751			if (currentscope == NULL)
752				ABORT;
753		}
754	}
755	| ALLOW
756	{
757		if (!currentscope) {
758			currentscope = push_double_list(currentscope, &globalgroup->scope);
759			if (currentscope == NULL)
760				ABORT;
761		}
762		allow = 1;
763	}
764	| OPTION
765	{
766		if (!currentscope) {
767			currentscope = push_double_list(currentscope, &globalgroup->scope);
768			if (currentscope == NULL)
769				ABORT;
770		}
771	}
772	;
773
774optionpara
775	: RAPIDCOMMIT ';'
776	{
777		if (allow)
778			currentscope->scope->allow_flags |= DHCIFF_RAPID_COMMIT;
779		else
780			currentscope->scope->send_flags |= DHCIFF_RAPID_COMMIT;
781	}
782	| TEMPIPV6ADDR ';'
783	{
784		if (allow)
785			currentscope->scope->allow_flags |= DHCIFF_TEMP_ADDRS;
786		else
787			currentscope->scope->send_flags |= DHCIFF_TEMP_ADDRS;
788	}
789	| UNICAST ';'
790	{
791		if (allow)
792			currentscope->scope->allow_flags |= DHCIFF_UNICAST;
793		else
794			currentscope->scope->send_flags |= DHCIFF_UNICAST;
795	}
796	| INFO_ONLY ';'
797	{
798		if (allow)
799			currentscope->scope->allow_flags |= DHCIFF_INFO_ONLY;
800		else
801			currentscope->scope->send_flags |= DHCIFF_INFO_ONLY;
802	}
803	| DNS_SERVERS dns_paras ';'
804	{
805	}
806	| SIP_SERVERS sip_paras ';'
807	{
808	}
809	| NTP_SERVERS ntp_paras ';'
810	{
811	}
812	;
813
814dns_paras
815	: dns_paras dns_para
816	| dns_para
817	;
818
819dns_para
820	: IPV6ADDR
821	{
822		dhcp6_add_listval(&currentscope->scope->dnslist.addrlist, &$1,
823			DHCP6_LISTVAL_ADDR6);
824	}
825
826sip_paras
827	: sip_paras sip_para
828	| sip_para
829	;
830
831sip_para
832	: IPV6ADDR
833	{
834		dhcp6_add_listval(&currentscope->scope->siplist, &$1,
835			DHCP6_LISTVAL_ADDR6);
836	}
837
838ntp_paras
839	: ntp_paras ntp_para
840	| ntp_para
841	;
842
843ntp_para
844	: IPV6ADDR
845	{
846		dhcp6_add_listval(&currentscope->scope->ntplist, &$1,
847			DHCP6_LISTVAL_ADDR6);
848	}
849
850	| STRING
851	{
852		struct domain_list *domainname, *temp;
853		int len = 0;
854		domainname = (struct domain_list *)malloc(sizeof(*domainname));
855		if (domainname == NULL)
856			ABORT;
857		len = strlen($1);
858		if (len > MAXDNAME)
859			ABORT;
860		strncpy(domainname->name, $1, len);
861		domainname->name[len] = '\0';
862		domainname->next = NULL;
863		if (currentscope->scope->dnslist.domainlist == NULL) {
864			currentscope->scope->dnslist.domainlist = domainname;
865			dprintf(LOG_DEBUG, "add domain name %s", domainname->name);
866		} else {
867			for (temp = currentscope->scope->dnslist.domainlist; temp;
868			     temp = temp->next) {
869				if (temp->next == NULL) {
870					dprintf(LOG_DEBUG, "add domain name %s",
871						domainname->name);
872					temp->next = domainname;
873					break;
874				}
875			}
876		}
877	}
878	;
879
880confdecl
881	: paradecl
882	| optiondecl
883	;
884
885paradecl
886	: RENEWTIME number_or_infinity ';'
887	{
888		if (!currentscope) {
889			currentscope = push_double_list(currentscope, &globalgroup->scope);
890			if (currentscope == NULL)
891				ABORT;
892		}
893		currentscope->scope->renew_time = $2;
894	}
895	| REBINDTIME number_or_infinity ';'
896	{
897		if (!currentscope) {
898			currentscope = push_double_list(currentscope, &globalgroup->scope);
899			if (currentscope == NULL)
900				ABORT;
901		}
902		currentscope->scope->rebind_time = $2;
903	}
904	| VALIDLIFETIME number_or_infinity ';'
905	{
906		if (!currentscope) {
907			currentscope = push_double_list(currentscope, &globalgroup->scope);
908			if (currentscope == NULL)
909				ABORT;
910		}
911		currentscope->scope->valid_life_time = $2;
912		if (currentscope->scope->prefer_life_time != 0 &&
913		    currentscope->scope->valid_life_time <
914		    currentscope->scope->prefer_life_time) {
915			dprintf(LOG_ERR, "%s"
916				"validlifetime is less than preferlifetime", FNAME);
917			ABORT;
918		}
919	}
920	| PREFERLIFETIME number_or_infinity ';'
921	{
922		if (!currentscope) {
923			currentscope = push_double_list(currentscope, &globalgroup->scope);
924			if (currentscope == NULL)
925				ABORT;
926		}
927		currentscope->scope->prefer_life_time = $2;
928		if (currentscope->scope->valid_life_time != 0 &&
929		    currentscope->scope->valid_life_time <
930		    currentscope->scope->prefer_life_time) {
931			dprintf(LOG_ERR, "%s"
932				"validlifetime is less than preferlifetime", FNAME);
933			ABORT;
934		}
935	}
936	| PREFERENCE NUMBER ';'
937	{
938		if (!currentscope) {
939			currentscope = push_double_list(currentscope, &globalgroup->scope);
940			if (currentscope == NULL)
941				ABORT;
942		}
943		if ($2 < 0 || $2 > 255)
944			dprintf(LOG_ERR, "%s" "bad server preference number", FNAME);
945		currentscope->scope->server_pref = $2;
946	}
947	;
948
949number_or_infinity
950	: NUMBER
951	{
952		$$ = $1;
953	}
954	| INFINITY
955	{
956		$$ = DHCP6_DURATITION_INFINITE;
957	}
958	;
959
960name
961	: STRING
962	{
963		$$ = $1;
964	}
965	;
966
967%%
968
969
970static
971void cleanup(void)
972{
973	/* it is not necessary to free all the pre malloc(), if it fails,
974	 * exit will free them automatically.
975	 */
976}
977
978void
979sfyyerror(char *msg)
980{
981	cleanup();
982	dprintf(LOG_ERR, "%s in line %d: %s ", msg, num_lines, sfyytext);
983}
984