1/*	$Id: config.c,v 1.1.1.1 2006/12/04 00:45:20 Exp $	*/
2/*	ported from KAME: config.c,v 1.21 2002/09/24 14:20:49 itojun Exp */
3
4/*
5 * Copyright (C) 2002 WIDE Project.
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of the project nor the names of its contributors
17 *    may be used to endorse or promote products derived from this software
18 *    without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 */
32#include <sys/types.h>
33#include <sys/socket.h>
34
35#include <net/if.h>
36
37#include <netinet/in.h>
38
39#include <syslog.h>
40#include <stdlib.h>
41#include <stdio.h>
42#include <string.h>
43#include <ifaddrs.h>
44
45#include "queue.h"
46#include "dhcp6.h"
47#include "config.h"
48#include "common.h"
49
50extern int errno;
51
52static struct dhcp6_ifconf *dhcp6_ifconflist;
53static struct host_conf *host_conflist0, *host_conflist;
54static struct dhcp6_list dnslist0;
55
56enum { DHCPOPTCODE_SEND, DHCPOPTCODE_REQUEST, DHCPOPTCODE_ALLOW };
57
58static int add_options __P((int, struct dhcp6_ifconf *, struct cf_list *));
59static int add_address __P((struct dhcp6_list *, struct dhcp6_addr *));
60static int add_option  __P((struct dhcp6_option_list *, struct cf_list *));
61static int clear_option_list  __P((struct dhcp6_option_list *));
62
63static void clear_ifconf __P((struct dhcp6_ifconf *));
64static void clear_hostconf __P((struct host_conf *));
65
66/* Foxconn added start pling 09/17/2010 */
67static char user_class[MAX_USER_CLASS_LEN];
68int set_dhcpc_user_class(char *str)
69{
70	strcpy(user_class, str);
71    dprintf(LOG_INFO, "Set User-class [%s]", user_class);
72    return 0;
73}
74/* Foxconn added end pling 09/17/2010 */
75
76/* Foxconn added start pling 10/07/2010 */
77/* For testing purposes */
78extern u_int32_t xid_solicit;
79extern u_int32_t xid_request;
80extern u_int32_t duid_time;
81/* Foxconn added end pling 10/07/2010 */
82
83int
84configure_interface(const struct cf_namelist *iflist)
85{
86	const struct cf_namelist *ifp;
87	struct dhcp6_ifconf *ifc;
88
89	for (ifp = iflist; ifp; ifp = ifp->next) {
90		struct cf_list *cfl;
91
92		if ((ifc = malloc(sizeof(*ifc))) == NULL) {
93			dprintf(LOG_ERR, "%s"
94				"memory allocation for %s failed", FNAME,
95				ifp->name);
96			goto bad;
97		}
98		memset(ifc, 0, sizeof(*ifc));
99		ifc->next = dhcp6_ifconflist;
100		dhcp6_ifconflist = ifc;
101
102		if ((ifc->ifname = strdup(ifp->name)) == NULL) {
103			dprintf(LOG_ERR, "%s" "failed to copy ifname", FNAME);
104			goto bad;
105		}
106
107		ifc->server_pref = DH6OPT_PREF_UNDEF;
108		TAILQ_INIT(&ifc->reqopt_list);
109		TAILQ_INIT(&ifc->addr_list);
110		TAILQ_INIT(&ifc->option_list);
111
112		for (cfl = ifp->params; cfl; cfl = cfl->next) {
113			switch(cfl->type) {
114			case DECL_REQUEST:
115				if (dhcp6_mode != DHCP6_MODE_CLIENT) {
116					dprintf(LOG_INFO, "%s" "%s:%d "
117						"client-only configuration",
118						FNAME, configfilename,
119						cfl->line);
120					goto bad;
121				}
122				if (add_options(DHCPOPTCODE_REQUEST,
123						ifc, cfl->list)) {
124					goto bad;
125				}
126				break;
127			case DECL_SEND:
128				if (add_options(DHCPOPTCODE_SEND,
129						ifc, cfl->list)) {
130					goto bad;
131				}
132				break;
133			case DECL_ALLOW:
134				if (add_options(DHCPOPTCODE_ALLOW,
135						ifc, cfl->list)) {
136					goto bad;
137				}
138				break;
139			case DECL_INFO_ONLY:
140				if (dhcp6_mode == DHCP6_MODE_CLIENT)
141                {
142					ifc->send_flags |= DHCIFF_INFO_ONLY;
143                    /* Foxconn added start pling 09/23/2010 */
144                    set_dhcp6c_flags(DHCIFF_INFO_ONLY);
145                    /* Foxconn added end pling 09/23/2010 */
146                }
147				break;
148			case DECL_TEMP_ADDR:
149				if (dhcp6_mode == DHCP6_MODE_CLIENT)
150					ifc->send_flags |= DHCIFF_TEMP_ADDRS;
151				break;
152			case DECL_PREFERENCE:
153				if (dhcp6_mode != DHCP6_MODE_SERVER) {
154					dprintf(LOG_INFO, "%s" "%s:%d "
155						"server-only configuration",
156						FNAME, configfilename,
157						cfl->line);
158					goto bad;
159				}
160				ifc->server_pref = (int)cfl->num;
161				if (ifc->server_pref < 0 ||
162				    ifc->server_pref > 255) {
163					dprintf(LOG_INFO, "%s" "%s:%d "
164						"bad value: %d", FNAME,
165						configfilename, cfl->line,
166						ifc->server_pref);
167					goto bad;
168				}
169				break;
170			case DECL_IAID:
171				if (ifc->iaidinfo.iaid) {
172					dprintf(LOG_ERR, "%s" "%s:%d "
173						"duplicated IAID for %s",
174						FNAME, configfilename,
175						cfl->line, ifc->ifname);
176					goto bad;
177				} else
178					ifc->iaidinfo.iaid = (u_int32_t)cfl->num;
179				break;
180			case DECL_RENEWTIME:
181				if (ifc->iaidinfo.renewtime) {
182					dprintf(LOG_ERR, "%s" "%s:%d "
183						"duplicated renewtime for %s",
184						FNAME, configfilename,
185						cfl->line, ifc->ifname);
186					goto bad;
187				} else
188					ifc->iaidinfo.renewtime = (u_int32_t)cfl->num;
189				break;
190			case DECL_REBINDTIME:
191				if (ifc->iaidinfo.iaid) {
192					dprintf(LOG_ERR, "%s" "%s:%d "
193						"duplicated rebindtime for %s",
194						FNAME, configfilename,
195						cfl->line, ifc->ifname);
196					goto bad;
197				} else
198					ifc->iaidinfo.rebindtime = (u_int32_t)cfl->num;
199				break;
200			case DECL_ADDRESS:
201				if (add_address(&ifc->addr_list, cfl->ptr)) {
202					dprintf(LOG_ERR, "%s" "failed "
203						"to configure ipv6address for %s",
204						FNAME, ifc->ifname);
205					goto bad;
206				}
207				break;
208			case DECL_PREFIX_REQ:
209				/* XX: ToDo */
210				break;
211			case DECL_PREFIX_INFO:
212				break;
213			case DECL_PREFIX_DELEGATION_INTERFACE:
214			        if (add_option(&ifc->option_list, cfl)){
215					dprintf(LOG_ERR, "%s failed to configure prefix-delegation-interface for %s",
216						FNAME, ifc->ifname);
217					goto bad;
218				}
219				break;
220			/* Foxconn added start pling 08/26/2009 */
221			/* Add flag to send dhcpv6 solicit only for DHCP client.
222			 * Used by IPv6 auto detection.
223			 */
224			case DECL_SOLICIT_ONLY:
225				if (dhcp6_mode == DHCP6_MODE_CLIENT)
226				{
227					dprintf(LOG_ERR, "Send DHCPC solicit only!");
228					ifc->send_flags |= DHCIFF_SOLICIT_ONLY;
229				}
230				break;
231			/* Foxconn added end pling 08/26/2009 */
232			/* Foxconn added start pling 09/07/2010 */
233			/* Support user-class for DHCP client */
234			case DECL_USER_CLASS:
235				if (dhcp6_mode == DHCP6_MODE_CLIENT)
236				{
237				    dprintf(LOG_ERR, "%s assign user_class='%s'", FNAME, user_class);
238					if (strlen(user_class))
239						strcpy(ifc->user_class, user_class);
240					else
241						ifc->user_class[0] = '\0';
242				}
243				break;
244			/* Foxconn added end pling 09/07/2010 */
245            /* Foxconn added start pling 09/21/2010 */
246            /* For DHCPv6 readylogo, need to send IANA and IAPD separately.
247             */
248            case DECL_IANA_ONLY:
249                if (dhcp6_mode == DHCP6_MODE_CLIENT)
250                {
251                    dprintf(LOG_ERR, "Accept IANA only!");
252                    set_dhcp6c_flags(DHCIFF_IANA_ONLY);
253                }
254                break;
255            case DECL_IAPD_ONLY:
256                if (dhcp6_mode == DHCP6_MODE_CLIENT)
257                {
258                    dprintf(LOG_ERR, "Accept IAPD only!");
259                    set_dhcp6c_flags(DHCIFF_IAPD_ONLY);
260                }
261                break;
262            /* Foxconn added end pling 09/21/2010 */
263            /* Foxconn added start pling 10/07/2010 */
264            /* For Testing purposes */
265            case DECL_XID_SOL:
266                xid_solicit =  (u_int32_t)cfl->num;
267                break;
268            case DECL_XID_REQ:
269                xid_request = (u_int32_t)cfl->num;
270                break;
271            case DECL_DUID_TIME:
272                duid_time = (u_int32_t)cfl->num;
273                break;
274            /* Foxconn added end pling 10/07/2010 */
275			default:
276				dprintf(LOG_ERR, "%s" "%s:%d "
277					"invalid interface configuration",
278					FNAME, configfilename, cfl->line);
279				goto bad;
280			}
281		}
282	}
283
284	return (0);
285
286  bad:
287	clear_ifconf(dhcp6_ifconflist);
288	dhcp6_ifconflist = NULL;
289	return (-1);
290}
291
292int
293configure_host(const struct cf_namelist *hostlist)
294{
295	const struct cf_namelist *host;
296	struct host_conf *hconf;
297
298	for (host = hostlist; host; host = host->next) {
299		struct cf_list *cfl;
300
301		if ((hconf = malloc(sizeof(*hconf))) == NULL) {
302			dprintf(LOG_ERR, "%s" "memory allocation failed "
303				"for host %s", FNAME, host->name);
304			goto bad;
305		}
306		memset(hconf, 0, sizeof(*hconf));
307		TAILQ_INIT(&hconf->addr_list);
308		TAILQ_INIT(&hconf->addr_binding_list);
309		TAILQ_INIT(&hconf->prefix_list);
310		TAILQ_INIT(&hconf->prefix_binding_list);
311		hconf->next = host_conflist0;
312		host_conflist0 = hconf;
313
314		if ((hconf->name = strdup(host->name)) == NULL) {
315			dprintf(LOG_ERR, "%s" "failed to copy host name: %s",
316				FNAME, host->name);
317			goto bad;
318		}
319
320		for (cfl = host->params; cfl; cfl = cfl->next) {
321			switch(cfl->type) {
322			case DECL_DUID:
323				if (hconf->duid.duid_id) {
324					dprintf(LOG_ERR, "%s" "%s:%d "
325						"duplicated DUID for %s",
326						FNAME, configfilename,
327						cfl->line, host->name);
328					goto bad;
329				}
330				if ((configure_duid((char *)cfl->ptr,
331						    &hconf->duid)) != 0) {
332					dprintf(LOG_ERR, "%s" "%s:%d "
333						"failed to configure "
334						"DUID for %s", FNAME,
335						configfilename, cfl->line,
336						host->name);
337					goto bad;
338				}
339				dprintf(LOG_DEBUG, "%s"
340					"configure DUID for %s: %s", FNAME,
341					host->name, duidstr(&hconf->duid));
342				break;
343			case DECL_PREFIX:
344				if (add_address(&hconf->prefix_list, cfl->ptr)) {
345					dprintf(LOG_ERR, "%s" "failed "
346						"to configure prefix for %s",
347						FNAME, host->name);
348					goto bad;
349				}
350				break;
351			case DECL_IAID:
352				if (hconf->iaidinfo.iaid) {
353					dprintf(LOG_ERR, "%s" "%s:%d "
354						"duplicated IAID for %s",
355						FNAME, configfilename,
356						cfl->line, host->name);
357					goto bad;
358				} else
359					hconf->iaidinfo.iaid = (u_int32_t)cfl->num;
360				break;
361			case DECL_RENEWTIME:
362				if (hconf->iaidinfo.renewtime) {
363					dprintf(LOG_ERR, "%s" "%s:%d "
364						"duplicated renewtime for %s",
365						FNAME, configfilename,
366						cfl->line, host->name);
367					goto bad;
368				} else
369					hconf->iaidinfo.renewtime = (u_int32_t)cfl->num;
370				break;
371			case DECL_REBINDTIME:
372				if (hconf->iaidinfo.rebindtime) {
373					dprintf(LOG_ERR, "%s" "%s:%d "
374						"duplicated rebindtime for %s",
375						FNAME, configfilename,
376						cfl->line, host->name);
377					goto bad;
378				} else
379					hconf->iaidinfo.rebindtime = (u_int32_t)cfl->num;
380				break;
381			case DECL_ADDRESS:
382				if (add_address(&hconf->addr_list, cfl->ptr)) {
383					dprintf(LOG_ERR, "%s" "failed "
384						"to configure ipv6address for %s",
385						FNAME, host->name);
386					goto bad;
387				}
388				break;
389			case DECL_LINKLOCAL:
390				if (IN6_IS_ADDR_UNSPECIFIED(&hconf->linklocal)) {
391					dprintf(LOG_ERR, "%s" "%s:%d "
392						"duplicated linklocal for %s",
393						FNAME, configfilename,
394						cfl->line, host->name);
395					goto bad;
396				} else
397					memcpy(&hconf->linklocal, cfl->ptr,
398							sizeof(hconf->linklocal) );
399				break;
400			default:
401				dprintf(LOG_ERR, "%s: %d invalid host configuration for %s",
402					configfilename, cfl->line, host->name);
403				goto bad;
404			}
405		}
406	}
407
408	return (0);
409
410  bad:
411	/* there is currently nothing special to recover the error */
412	return (-1);
413}
414
415int
416configure_global_option(void)
417{
418	struct cf_list *cl;
419
420	/* DNS servers */
421	if (cf_dns_list && dhcp6_mode != DHCP6_MODE_SERVER) {
422		dprintf(LOG_INFO, "%s" "%s:%d server-only configuration",
423		    FNAME, configfilename, cf_dns_list->line);
424		goto bad;
425	}
426	TAILQ_INIT(&dnslist0);
427	for (cl = cf_dns_list; cl; cl = cl->next) {
428		/* duplication check */
429		if (dhcp6_find_listval(&dnslist0, cl->ptr,
430		    DHCP6_LISTVAL_ADDR6)) {
431			dprintf(LOG_INFO, "%s"
432			    "%s:%d duplicated DNS server: %s", FNAME,
433			    configfilename, cl->line,
434			    in6addr2str((struct in6_addr *)cl->ptr, 0));
435			goto bad;
436		}
437		if (dhcp6_add_listval(&dnslist0, cl->ptr,
438		    DHCP6_LISTVAL_ADDR6) == NULL) {
439			dprintf(LOG_ERR, "%s" "failed to add a DNS server",
440				FNAME);
441			goto bad;
442		}
443	}
444
445	return 0;
446
447  bad:
448	return -1;
449}
450
451
452void
453configure_cleanup(void)
454{
455	clear_ifconf(dhcp6_ifconflist);
456	dhcp6_ifconflist = NULL;
457	clear_hostconf(host_conflist0);
458	host_conflist0 = NULL;
459	dhcp6_clear_list(&dnslist0);
460	TAILQ_INIT(&dnslist0);
461}
462
463void
464configure_commit(void)
465{
466	struct dhcp6_ifconf *ifc;
467	struct dhcp6_if *ifp;
468
469	/* commit interface configuration */
470	for (ifc = dhcp6_ifconflist; ifc; ifc = ifc->next) {
471		if ((ifp = find_ifconfbyname(ifc->ifname)) != NULL) {
472			ifp->send_flags = ifc->send_flags;
473
474			ifp->allow_flags = ifc->allow_flags;
475
476			dhcp6_clear_list(&ifp->reqopt_list);
477			ifp->reqopt_list = ifc->reqopt_list;
478			TAILQ_INIT(&ifc->reqopt_list);
479
480			dhcp6_clear_list(&ifp->addr_list);
481			ifp->addr_list = ifc->addr_list;
482			TAILQ_INIT(&ifc->addr_list);
483
484			dhcp6_clear_list(&ifp->prefix_list);
485			ifp->prefix_list = ifc->prefix_list;
486			TAILQ_INIT(&ifc->prefix_list);
487
488			clear_option_list(&ifp->option_list);
489			ifp->option_list = ifc->option_list;
490			TAILQ_INIT(&ifc->option_list);
491
492			ifp->server_pref = ifc->server_pref;
493
494			/* Foxconn added start pling 09/07/2010 */
495			/* configure user-class */
496			if (dhcp6_mode == DHCP6_MODE_CLIENT)
497			    strcpy(ifp->user_class, ifc->user_class);
498			/* Foxconn added end pling 09/07/2010 */
499
500			memcpy(&ifp->iaidinfo, &ifc->iaidinfo, sizeof(ifp->iaidinfo));
501		}
502	}
503	clear_ifconf(dhcp6_ifconflist);
504
505	/* commit prefix configuration */
506	if (host_conflist) {
507		/* clear previous configuration. (need more work?) */
508		clear_hostconf(host_conflist);
509	}
510	host_conflist = host_conflist0;
511	host_conflist0 = NULL;
512}
513
514static void
515clear_ifconf(struct dhcp6_ifconf *iflist)
516{
517	struct dhcp6_ifconf *ifc, *ifc_next;
518
519	for (ifc = iflist; ifc; ifc = ifc_next) {
520		ifc_next = ifc->next;
521
522		free(ifc->ifname);
523
524		dhcp6_clear_list(&ifc->reqopt_list);
525
526		free(ifc);
527	}
528}
529
530static void
531clear_hostconf(struct host_conf *hlist)
532{
533	struct host_conf *host, *host_next;
534	struct dhcp6_listval *p;
535
536	for (host = hlist; host; host = host_next) {
537		host_next = host->next;
538
539		free(host->name);
540		while ((p = TAILQ_FIRST(&host->prefix_list)) != NULL) {
541			TAILQ_REMOVE(&host->prefix_list, p, link);
542			free(p);
543		}
544		if (host->duid.duid_id)
545			free(host->duid.duid_id);
546		free(host);
547	}
548}
549
550static int
551add_options(int opcode,	struct dhcp6_ifconf *ifc,
552	    struct cf_list *cfl0)
553{
554	struct dhcp6_listval *opt;
555	struct cf_list *cfl;
556	int opttype;
557
558	for (cfl = cfl0; cfl; cfl = cfl->next) {
559		if (opcode ==  DHCPOPTCODE_REQUEST) {
560			for (opt = TAILQ_FIRST(&ifc->reqopt_list); opt;
561			     opt = TAILQ_NEXT(opt, link)) {
562				if (opt->val_num == cfl->type) {
563					dprintf(LOG_INFO, "%s"
564						"duplicated requested"
565						" option: %s", FNAME,
566						dhcp6optstr(cfl->type));
567					goto next; /* ignore it */
568				}
569			}
570		}
571
572		switch(cfl->type) {
573		case DHCPOPT_RAPID_COMMIT:
574			switch(opcode) {
575			case DHCPOPTCODE_SEND:
576				ifc->send_flags |= DHCIFF_RAPID_COMMIT;
577				break;
578			case DHCPOPTCODE_ALLOW:
579				ifc->allow_flags |= DHCIFF_RAPID_COMMIT;
580				break;
581			default:
582				dprintf(LOG_ERR, "%s" "invalid operation (%d) "
583					"for option type (%d)",
584					FNAME, opcode, cfl->type);
585				return (-1);
586			}
587			break;
588		case DHCPOPT_PREFIX_DELEGATION:
589			switch(opcode) {
590			case DHCPOPTCODE_REQUEST:
591				ifc->send_flags |= DHCIFF_PREFIX_DELEGATION;
592				break;
593			default:
594				dprintf(LOG_ERR, "%s" "invalid operation (%d) "
595					"for option type (%d)",
596					FNAME, opcode, cfl->type);
597				return (-1);
598			}
599			break;
600
601		case DHCPOPT_DNS:
602			switch(opcode) {
603			case DHCPOPTCODE_REQUEST:
604				opttype = DH6OPT_DNS_SERVERS;
605				if (dhcp6_add_listval(&ifc->reqopt_list,
606				    &opttype, DHCP6_LISTVAL_NUM) == NULL) {
607					dprintf(LOG_ERR, "%s" "failed to "
608					    "configure an option", FNAME);
609					return (-1);
610				}
611				break;
612			default:
613				dprintf(LOG_ERR, "%s" "invalid operation (%d) "
614					"for option type (%d)",
615					FNAME, opcode, cfl->type);
616				break;
617			}
618			break;
619
620        /* Foxconn added start pling 09/23/2010 */
621        /* To support domain search list for DHCPv6 readylogo tests */
622        case DHCPOPT_DOMAIN_LIST:
623            switch(opcode) {
624                case DHCPOPTCODE_REQUEST:
625                    opttype = DH6OPT_DOMAIN_LIST;
626                    if (dhcp6_add_listval(&ifc->reqopt_list,
627                        &opttype, DHCP6_LISTVAL_NUM) == NULL) {
628                        dprintf(LOG_ERR, "%s" "failed to "
629                            "configure an option", FNAME);
630                        return (-1);
631                    }
632                    break;
633                default:
634                    dprintf(LOG_ERR, "%s" "invalid operation (%d) "
635                        "for option type (%d)",
636                        FNAME, opcode, cfl->type);
637                    break;
638            }
639            break;
640        /* Foxconn added end pling 09/23/2010 */
641
642		default:
643			dprintf(LOG_ERR, "%s"
644				"unknown option type: %d", FNAME, cfl->type);
645				return (-1);
646		}
647
648	next:;
649	}
650
651	return (0);
652}
653
654static int
655add_address(struct dhcp6_list *addr_list,
656	    struct dhcp6_addr *v6addr)
657{
658	struct dhcp6_listval *lv, *val;
659
660	/* avoid invalid addresses */
661	if (IN6_IS_ADDR_RESERVED(&v6addr->addr)) {
662		dprintf(LOG_ERR, "%s" "invalid address: %s",
663			FNAME, in6addr2str(&v6addr->addr, 0));
664		return (-1);
665	}
666
667	/* address duplication check */
668	for (lv = TAILQ_FIRST(addr_list); lv;
669	     lv = TAILQ_NEXT(lv, link)) {
670		if (IN6_ARE_ADDR_EQUAL(&lv->val_dhcp6addr.addr, &v6addr->addr) &&
671		    lv->val_dhcp6addr.plen == v6addr->plen) {
672			dprintf(LOG_ERR, "%s"
673				"duplicated address: %s/%d ", FNAME,
674				in6addr2str(&v6addr->addr, 0), v6addr->plen);
675			return (-1);
676		}
677	}
678	if ((val = (struct dhcp6_listval *)malloc(sizeof(*val))) == NULL)
679		dprintf(LOG_ERR, "%s" "memory allocation failed", FNAME);
680	memset(val, 0, sizeof(*val));
681	memcpy(&val->val_dhcp6addr, v6addr, sizeof(val->val_dhcp6addr));
682	dprintf(LOG_DEBUG, "%s" "add address: %s",
683		FNAME, in6addr2str(&v6addr->addr, 0));
684	TAILQ_INSERT_TAIL(addr_list, val, link);
685	return (0);
686}
687
688int add_option (struct dhcp6_option_list *opts, struct cf_list *cfl)
689{
690	struct dhcp6_option *opt ;
691
692	if ( get_if_option( opts, cfl->type ) != 0L )
693		return (-1);
694
695	switch (cfl->type)
696	{
697	case DECL_PREFIX_DELEGATION_INTERFACE:
698		opt = (struct dhcp6_option*)malloc(sizeof(struct dhcp6_option));
699		opt->type = cfl->type;
700		if ( cfl->ptr != 0L )
701		{
702			opt->len = strlen((char*)(cfl->ptr))+1;
703			opt->val = malloc(opt->len);
704			memcpy(opt->val, cfl->ptr, opt->len);
705		}else
706		{
707			opt->val = malloc(1);
708			opt->len = 0;
709			*((char*)(opt->val))='\0';
710		}
711		TAILQ_INSERT_TAIL(opts, opt, link);
712		break;
713	default:
714	        break;
715	}
716	return (0);
717}
718
719int clear_option_list (struct dhcp6_option_list *opts)
720{
721	struct dhcp6_option *opt;
722	while ((opt = TAILQ_FIRST(opts)) != NULL) {
723		TAILQ_REMOVE(opts, opt, link);
724		free(opt);
725	}
726}
727
728void *get_if_option( struct dhcp6_option_list *opts, int type )
729{
730	struct dhcp6_option *opt;
731	TAILQ_FOREACH( opt, opts, link)
732	{
733		if ( opt->type == type )
734			return opt->val;
735	}
736	return 0L;
737}
738