1/*	$Id: common.c,v 1.1.1.1 2006/12/04 00:45:20 Exp $	*/
2/*	ported from KAME: common.c,v 1.65 2002/12/06 01:41:29 suz Exp	*/
3
4/*
5 * Copyright (C) 1998 and 1999 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
33#include <sys/types.h>
34#include <sys/socket.h>
35#include <linux/sockios.h>
36#include <sys/ioctl.h>
37
38#if TIME_WITH_SYS_TIME
39# include <sys/time.h>
40# include <time.h>
41#else
42# if HAVE_SYS_TIME_H
43#  include <sys/time.h>
44# else
45#  include <time.h>
46# endif
47#endif
48#include <net/if.h>
49#if defined(__FreeBSD__) && __FreeBSD__ >= 3
50#include <net/if_var.h>
51#endif
52#include <net/if_arp.h>
53
54#include <netinet/in.h>
55#include <errno.h>
56#include <limits.h>
57#include <stdio.h>
58#include <stdarg.h>
59#include <syslog.h>
60#include <stdlib.h>
61#include <unistd.h>
62#include <string.h>
63#include <err.h>
64#include <netdb.h>
65#include <ifaddrs.h>
66#include <resolv.h>
67
68#ifdef HAVE_GETIFADDRS
69# ifdef HAVE_IFADDRS_H
70#  define USE_GETIFADDRS
71#  include <ifaddrs.h>
72# endif
73#endif
74
75#include "queue.h"
76#include "dhcp6.h"
77#include "config.h"
78#include "common.h"
79#include "timer.h"
80#include "lease.h"
81
82int foreground;
83int debug_thresh;
84struct dhcp6_if *dhcp6_if;
85struct dns_list dnslist;
86/* Foxconn added start pling 01/25/2010 */
87struct dhcp6_list siplist;
88struct dhcp6_list ntplist;
89/* Foxconn added end pling 01/25/2010 */
90static struct host_conf *host_conflist;
91static int in6_matchflags __P((struct sockaddr *, char *, int));
92ssize_t gethwid __P((char *, int, const char *, u_int16_t *));
93static int get_assigned_ipv6addrs __P((char *, char *,
94					struct dhcp6_optinfo *));
95
96/* Foxconn added start pling 10/07/2010 */
97/* For testing purpose */
98u_int32_t duid_time = 0;
99/* Foxconn added end pling 10/07/2010 */
100
101/* Foxconn added start pling 09/21/2010 */
102/* Global flags for dhcpc configuration, e.g. IANA_ONLY, IAPD_ONLY */
103static u_int32_t   dhcp6c_flags = 0;
104int set_dhcp6c_flags(u_int32_t flags)
105{
106    dhcp6c_flags |= flags;
107    return 0;
108}
109/* Foxconn added end pling 09/21/2010 */
110
111struct dhcp6_if *
112find_ifconfbyname(const char *ifname)
113{
114	struct dhcp6_if *ifp;
115
116	for (ifp = dhcp6_if; ifp; ifp = ifp->next) {
117		if (strcmp(ifp->ifname, ifname) == 0)
118			return (ifp);
119	}
120
121	return (NULL);
122}
123
124struct dhcp6_if *
125find_ifconfbyid(unsigned int id)
126{
127	struct dhcp6_if *ifp;
128
129	for (ifp = dhcp6_if; ifp; ifp = ifp->next) {
130		if (ifp->ifid == id)
131			return (ifp);
132	}
133
134	return (NULL);
135}
136
137struct host_conf *
138find_hostconf(const struct duid *duid)
139{
140	struct host_conf *host;
141
142	for (host = host_conflist; host; host = host->next) {
143		if (host->duid.duid_len == duid->duid_len &&
144		    memcmp(host->duid.duid_id, duid->duid_id,
145			   host->duid.duid_len) == 0) {
146			return (host);
147		}
148	}
149
150	return (NULL);
151}
152void
153ifinit(const char *ifname)
154{
155	struct dhcp6_if *ifp;
156
157	if ((ifp = find_ifconfbyname(ifname)) != NULL) {
158		dprintf(LOG_NOTICE, "%s" "duplicated interface: %s",
159			FNAME, ifname);
160		return;
161	}
162
163	if ((ifp = malloc(sizeof(*ifp))) == NULL) {
164		dprintf(LOG_ERR, "%s" "malloc failed", FNAME);
165		goto die;
166	}
167	memset(ifp, 0, sizeof(*ifp));
168
169	TAILQ_INIT(&ifp->event_list);
170
171	if ((ifp->ifname = strdup(ifname)) == NULL) {
172		dprintf(LOG_ERR, "%s" "failed to copy ifname", FNAME);
173		goto die;
174	}
175
176	if ((ifp->ifid = if_nametoindex(ifname)) == 0) {
177		dprintf(LOG_ERR, "%s" "invalid interface(%s): %s", FNAME,
178			ifname, strerror(errno));
179		goto die;
180	}
181#ifdef HAVE_SCOPELIB
182	if (inet_zoneid(AF_INET6, 2, ifname, &ifp->linkid)) {
183		dprintf(LOG_ERR, "%s" "failed to get link ID for %s",
184			FNAME, ifname);
185		goto die;
186	}
187#else
188	ifp->linkid = ifp->ifid;
189#endif
190	if (get_linklocal(ifname, &ifp->linklocal) < 0)
191		goto die;
192	ifp->next = dhcp6_if;
193	dhcp6_if = ifp;
194	return;
195
196  die:
197	exit(1);
198}
199
200int
201dhcp6_copy_list(struct dhcp6_list *dst,
202		const struct dhcp6_list *src)
203{
204	const struct dhcp6_listval *ent;
205	struct dhcp6_listval *dent;
206
207	for (ent = TAILQ_FIRST(src); ent; ent = TAILQ_NEXT(ent, link)) {
208		if ((dent = malloc(sizeof(*dent))) == NULL)
209			goto fail;
210
211		memset(dent, 0, sizeof(*dent));
212		memcpy(&dent->uv, &ent->uv, sizeof(ent->uv));
213
214		TAILQ_INSERT_TAIL(dst, dent, link);
215	}
216
217	return 0;
218
219  fail:
220	dhcp6_clear_list(dst);
221	return -1;
222}
223
224void
225dhcp6_clear_list(head)
226	struct dhcp6_list *head;
227{
228	struct dhcp6_listval *v;
229
230	while ((v = TAILQ_FIRST(head)) != NULL) {
231		TAILQ_REMOVE(head, v, link);
232		free(v);
233	}
234
235	return;
236}
237
238void
239relayfree(head)
240	struct relay_list *head;
241{
242	struct relay_listval *v;
243
244	while ((v = TAILQ_FIRST(head)) != NULL) {
245		TAILQ_REMOVE(head, v, link);
246		if (v->intf_id != NULL) {
247			if (v->intf_id->intf_id != NULL)
248				free(v->intf_id->intf_id);
249			free (v->intf_id);
250		}
251		free(v);
252	}
253
254	return;
255}
256
257int
258dhcp6_count_list(head)
259	struct dhcp6_list *head;
260{
261	struct dhcp6_listval *v;
262	int i;
263
264	for (i = 0, v = TAILQ_FIRST(head); v; v = TAILQ_NEXT(v, link))
265		i++;
266
267	return i;
268}
269
270struct dhcp6_listval *
271dhcp6_find_listval(head, val, type)
272	struct dhcp6_list *head;
273	void *val;
274	dhcp6_listval_type_t type;
275{
276	struct dhcp6_listval *lv;
277
278	for (lv = TAILQ_FIRST(head); lv; lv = TAILQ_NEXT(lv, link)) {
279		switch(type) {
280		case DHCP6_LISTVAL_NUM:
281			if (lv->val_num == *(int *)val)
282				return (lv);
283			break;
284		case DHCP6_LISTVAL_ADDR6:
285			if (IN6_ARE_ADDR_EQUAL(&lv->val_addr6,
286			    (struct in6_addr *)val)) {
287				return (lv);
288			}
289			break;
290		case DHCP6_LISTVAL_DHCP6ADDR:
291			if (IN6_ARE_ADDR_EQUAL(&lv->val_dhcp6addr.addr,
292			    &((struct dhcp6_addr *)val)->addr) &&
293			    (lv->val_dhcp6addr.plen == ((struct dhcp6_addr *)val)->plen)) {
294				return (lv);
295			}
296			break;
297		/* DHCP6_LISTVAL_DHCP6LEASE is missing? */
298		}
299
300	}
301
302	return (NULL);
303}
304
305struct dhcp6_listval *
306dhcp6_add_listval(head, val, type)
307	struct dhcp6_list *head;
308	void *val;
309	dhcp6_listval_type_t type;
310{
311	struct dhcp6_listval *lv;
312
313	if ((lv = malloc(sizeof(*lv))) == NULL) {
314		dprintf(LOG_ERR, "%s" "failed to allocate memory for list "
315		    "entry", FNAME);
316		return (NULL);
317	}
318	memset(lv, 0, sizeof(*lv));
319
320	switch(type) {
321	case DHCP6_LISTVAL_NUM:
322		lv->val_num = *(int *)val;
323		break;
324	case DHCP6_LISTVAL_ADDR6:
325		lv->val_addr6 = *(struct in6_addr *)val;
326		break;
327	case DHCP6_LISTVAL_DHCP6ADDR:
328		lv->val_dhcp6addr = *(struct dhcp6_addr *)val;
329		break;
330	default:
331		dprintf(LOG_ERR, "%s" "unexpected list value type (%d)",
332		    FNAME, type);
333		return (NULL);
334	}
335	TAILQ_INSERT_TAIL(head, lv, link);
336	return (lv);
337}
338
339struct dhcp6_event *
340dhcp6_create_event(ifp, state)
341	struct dhcp6_if *ifp;
342	int state;
343{
344	struct dhcp6_event *ev;
345
346	if ((ev = malloc(sizeof(*ev))) == NULL) {
347		dprintf(LOG_ERR, "%s" "failed to allocate memory for an event",
348			FNAME);
349		return (NULL);
350	}
351	/* for safety */
352	memset(ev, 0, sizeof(*ev));
353	ev->serverid.duid_id = NULL;
354
355	ev->ifp = ifp;
356	ev->state = state;
357	TAILQ_INIT(&ev->data_list);
358	dprintf(LOG_DEBUG, "%s" "create an event %p xid %d for state %d",
359		FNAME, ev, ev->xid, ev->state);
360	return (ev);
361}
362
363void
364dhcp6_remove_event(ev)
365	struct dhcp6_event *ev;
366{
367	dprintf(LOG_DEBUG, "%s" "removing an event %p on %s, state=%d, xid=%x", FNAME,
368		ev, ev->ifp->ifname, ev->state, ev->xid);
369
370	if (!TAILQ_EMPTY(&ev->data_list)) {
371		dprintf(LOG_ERR, "%s" "assumption failure: "
372			"event data list is not empty", FNAME);
373		exit(1);
374	}
375	if (ev->serverid.duid_id != NULL)
376		duidfree(&ev->serverid);
377	if (ev->timer)
378		dhcp6_remove_timer(ev->timer);
379	TAILQ_REMOVE(&ev->ifp->event_list, ev, link);
380	free(ev);
381	ev = NULL;
382}
383
384
385int
386getifaddr(addr, ifnam, prefix, plen, strong, ignoreflags)
387	struct in6_addr *addr;
388	char *ifnam;
389	struct in6_addr *prefix;
390	int plen;
391	int strong;		/* if strong host model is required or not */
392	int ignoreflags;
393{
394	struct ifaddrs *ifap, *ifa;
395	struct sockaddr_in6 sin6;
396	int error = -1;
397
398	if (getifaddrs(&ifap) != 0) {
399		err(1, "getifaddr: getifaddrs");
400		/*NOTREACHED*/
401	}
402
403	for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
404		int s1, s2;
405
406		if (strong && strcmp(ifnam, ifa->ifa_name) != 0)
407			continue;
408
409		/* in any case, ignore interfaces in different scope zones. */
410		if ((s1 = in6_addrscopebyif(prefix, ifnam)) < 0 ||
411		    (s2 = in6_addrscopebyif(prefix, ifa->ifa_name)) < 0 ||
412		     s1 != s2)
413			continue;
414
415		if (ifa->ifa_addr->sa_family != AF_INET6)
416			continue;
417		if (sizeof(*(ifa->ifa_addr)) > sizeof(sin6))
418			continue;
419
420		if (in6_matchflags(ifa->ifa_addr, ifa->ifa_name, ignoreflags))
421			continue;
422
423		memcpy(&sin6, ifa->ifa_addr, sizeof(sin6));
424#ifdef __KAME__
425		if (IN6_IS_ADDR_LINKLOCAL(&sin6.sin6_addr)) {
426			sin6.sin6_addr.s6_addr[2] = 0;
427			sin6.sin6_addr.s6_addr[3] = 0;
428		}
429#endif
430		if (plen % 8 == 0) {
431			if (memcmp(&sin6.sin6_addr, prefix, plen / 8) != 0)
432				continue;
433		} else {
434			struct in6_addr a, m;
435			int i;
436
437			memcpy(&a, &sin6.sin6_addr, sizeof(a));
438			memset(&m, 0, sizeof(m));
439			memset(&m, 0xff, plen / 8);
440			m.s6_addr[plen / 8] = (0xff00 >> (plen % 8)) & 0xff;
441			for (i = 0; i < sizeof(a); i++)
442				a.s6_addr[i] &= m.s6_addr[i];
443
444			if (memcmp(&a, prefix, plen / 8) != 0 ||
445			    a.s6_addr[plen / 8] !=
446			    (prefix->s6_addr[plen / 8] & m.s6_addr[plen / 8]))
447				continue;
448		}
449		memcpy(addr, &sin6.sin6_addr, sizeof(*addr));
450#ifdef __KAME__
451		if (IN6_IS_ADDR_LINKLOCAL(addr))
452			addr->s6_addr[2] = addr->s6_addr[3] = 0;
453#endif
454		error = 0;
455		break;
456	}
457
458	freeifaddrs(ifap);
459	return (error);
460}
461
462int
463in6_addrscopebyif(addr, ifnam)
464	struct in6_addr *addr;
465	char *ifnam;
466{
467	u_int ifindex;
468
469	if ((ifindex = if_nametoindex(ifnam)) == 0)
470		return (-1);
471
472	if (IN6_IS_ADDR_LINKLOCAL(addr) || IN6_IS_ADDR_MC_LINKLOCAL(addr))
473		return (ifindex);
474
475	if (IN6_IS_ADDR_SITELOCAL(addr) || IN6_IS_ADDR_MC_SITELOCAL(addr))
476		return (1);
477
478	if (IN6_IS_ADDR_MC_ORGLOCAL(addr))
479		return (1);
480
481	return (1);		/* treat it as global */
482}
483
484const char *
485getdev(addr)
486	struct sockaddr_in6 *addr;
487{
488	struct ifaddrs *ifap, *ifa;
489	struct sockaddr_in6 *a6;
490	static char ret_ifname[IFNAMSIZ+1];
491
492	if (getifaddrs(&ifap) != 0) {
493		err(1, "getdev: getifaddrs");
494		/* NOTREACHED */
495	}
496
497	for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
498		if (ifa->ifa_addr->sa_family != AF_INET6)
499			continue;
500
501		a6 = (struct sockaddr_in6 *)ifa->ifa_addr;
502		if (!IN6_ARE_ADDR_EQUAL(&a6->sin6_addr, &addr->sin6_addr) ||
503		    a6->sin6_scope_id != addr->sin6_scope_id)
504			continue;
505
506		break;
507	}
508
509	if (ifa)
510		strncpy(ret_ifname, ifa->ifa_name, IFNAMSIZ);
511	freeifaddrs(ifap);
512
513	return (ifa ? ret_ifname : NULL);
514}
515
516int
517transmit_sa(s, sa, buf, len)
518	int s;
519	struct sockaddr_in6 *sa;
520	char *buf;
521	size_t len;
522{
523	int error;
524
525	error = sendto(s, buf, len, MSG_DONTROUTE, (struct sockaddr *)sa, sizeof(*sa));
526
527	return (error != len) ? -1 : 0;
528}
529
530long
531random_between(x, y)
532	long x;
533	long y;
534{
535	long ratio;
536
537	ratio = 1 << 16;
538	while ((y - x) * ratio < (y - x))
539		ratio = ratio / 2;
540	return x + ((y - x) * (ratio - 1) / random() & (ratio - 1));
541}
542
543int
544prefix6_mask(in6, plen)
545	struct in6_addr *in6;
546	int plen;
547{
548	struct sockaddr_in6 mask6;
549	int i;
550
551	if (sa6_plen2mask(&mask6, plen))
552		return (-1);
553
554	for (i = 0; i < 16; i++)
555		in6->s6_addr[i] &= mask6.sin6_addr.s6_addr[i];
556
557	return (0);
558}
559
560int
561sa6_plen2mask(sa6, plen)
562	struct sockaddr_in6 *sa6;
563	int plen;
564{
565	u_char *cp;
566
567	if (plen < 0 || plen > 128)
568		return (-1);
569
570	memset(sa6, 0, sizeof(*sa6));
571	sa6->sin6_family = AF_INET6;
572
573	for (cp = (u_char *)&sa6->sin6_addr; plen > 7; plen -= 8)
574		*cp++ = 0xff;
575	*cp = 0xff << (8 - plen);
576
577	return (0);
578}
579
580char *
581addr2str(sa)
582	struct sockaddr *sa;
583{
584	static char addrbuf[8][NI_MAXHOST];
585	static int round = 0;
586	char *cp;
587
588	round = (round + 1) & 7;
589	cp = addrbuf[round];
590
591	if (getnameinfo(sa, NI_MAXSERV, cp, NI_MAXHOST, NULL,
592				0, NI_NUMERICHOST) != 0)
593		dprintf(LOG_ERR, "%s getnameinfo return error", FNAME);
594
595	return (cp);
596}
597
598char *
599in6addr2str(in6, scopeid)
600	struct in6_addr *in6;
601	int scopeid;
602{
603	struct sockaddr_in6 sa6;
604
605	memset(&sa6, 0, sizeof(sa6));
606	sa6.sin6_family = AF_INET6;
607	sa6.sin6_addr = *in6;
608	sa6.sin6_scope_id = scopeid;
609
610	return (addr2str((struct sockaddr *)&sa6));
611}
612
613/* return IPv6 address scope type. caller assumes that smaller is narrower. */
614int
615in6_scope(addr)
616	struct in6_addr *addr;
617{
618	int scope;
619
620	if (addr->s6_addr[0] == 0xfe) {
621		scope = addr->s6_addr[1] & 0xc0;
622
623		switch (scope) {
624		case 0x80:
625			return 2; /* link-local */
626			break;
627		case 0xc0:
628			return 5; /* site-local */
629			break;
630		default:
631			return 14; /* global: just in case */
632			break;
633		}
634	}
635
636	/* multicast scope. just return the scope field */
637	if (addr->s6_addr[0] == 0xff)
638		return (addr->s6_addr[1] & 0x0f);
639
640	if (bcmp(&in6addr_loopback, addr, sizeof(addr) - 1) == 0) {
641		if (addr->s6_addr[15] == 1) /* loopback */
642			return 1;
643		if (addr->s6_addr[15] == 0) /* unspecified */
644			return 0;
645	}
646
647	return 14;		/* global */
648}
649
650static int
651in6_matchflags(addr, ifnam, flags)
652	struct sockaddr *addr;
653	char *ifnam;
654	int flags;
655{
656	int s;
657	struct ifreq ifr;
658
659	if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
660		warn("in6_matchflags: socket(DGRAM6)");
661		return (-1);
662	}
663	memset(&ifr, 0, sizeof(ifr));
664	strncpy(ifr.ifr_name, ifnam, sizeof(ifr.ifr_name));
665	ifr.ifr_addr = *(struct sockaddr *)addr;
666
667	if (ioctl(s, SIOCGIFFLAGS, &ifr) < 0) {
668		warn("in6_matchflags: ioctl(SIOCGIFFLAGS, %s)",
669		     addr2str(addr));
670		close(s);
671		return (-1);
672	}
673
674	close(s);
675
676	return (ifr.ifr_ifru.ifru_flags & flags);
677}
678
679int
680configure_duid(const char *str,
681	       struct duid *duid)
682{
683	const char *cp;
684	char  *bp, *idbuf = NULL;
685	int duidlen, slen;
686	unsigned int x;
687
688	/* calculate DUID len */
689	slen = strlen(str);
690	if (slen < 2)
691		goto bad;
692	duidlen = 1;
693	slen -= 2;
694	if ((slen % 3) != 0)
695		goto bad;
696	duidlen += (slen / 3);
697	if (duidlen > 256) {
698		dprintf(LOG_ERR, "%s" "too long DUID (%d)", FNAME, duidlen);
699		return (-1);
700	}
701
702	if ((idbuf = (char *)malloc(duidlen)) == NULL) {
703		dprintf(LOG_ERR, "%s" "memory allocation failed", FNAME);
704		return (-1);
705	}
706
707	for (cp = str, bp = idbuf; *cp;) {
708		if (*cp == ':') {
709			cp++;
710			continue;
711		}
712
713		if (sscanf(cp, "%02x", &x) != 1)
714			goto bad;
715		*bp = x;
716		cp += 2;
717		bp++;
718	}
719
720	duid->duid_len = duidlen;
721	duid->duid_id = idbuf;
722	dprintf(LOG_DEBUG, "configure duid is %s", duidstr(duid));
723	return (0);
724
725  bad:
726	if (idbuf)
727		free(idbuf);
728	dprintf(LOG_ERR, "%s" "assumption failure (bad string)", FNAME);
729	return (-1);
730}
731
732int
733get_duid(const 	char *idfile, const char *ifname,
734	 struct duid *duid)
735{
736	FILE *fp = NULL;
737	u_int16_t len = 0, hwtype;
738	struct dhcp6_duid_type1 *dp; /* we only support the type1 DUID */
739	char tmpbuf[256];	/* DUID should be no more than 256 bytes */
740
741	if ((fp = fopen(idfile, "r")) == NULL && errno != ENOENT)
742		dprintf(LOG_NOTICE, "%s" "failed to open DUID file: %s",
743		    FNAME, idfile);
744
745	if (fp) {
746		/* decode length */
747		if (fread(&len, sizeof(len), 1, fp) != 1) {
748			dprintf(LOG_ERR, "%s" "DUID file corrupted", FNAME);
749			goto fail;
750		}
751	} else {
752		int l;
753
754		if ((l = gethwid(tmpbuf, sizeof(tmpbuf), ifname, &hwtype)) < 0) {
755			dprintf(LOG_INFO, "%s"
756			    "failed to get a hardware address", FNAME);
757			goto fail;
758		}
759		len = l + sizeof(struct dhcp6_duid_type1);
760	}
761
762	memset(duid, 0, sizeof(*duid));
763	duid->duid_len = len;
764	if ((duid->duid_id = (char *)malloc(len)) == NULL) {
765		dprintf(LOG_ERR, "%s" "failed to allocate memory", FNAME);
766		goto fail;
767	}
768
769	/* copy (and fill) the ID */
770	if (fp) {
771		if (fread(duid->duid_id, len, 1, fp) != 1) {
772			dprintf(LOG_ERR, "%s" "DUID file corrupted", FNAME);
773			goto fail;
774		}
775
776		dprintf(LOG_DEBUG, "%s"
777		    "extracted an existing DUID from %s: %s", FNAME,
778		    idfile, duidstr(duid));
779	} else {
780		u_int64_t t64;
781
782		dp = (struct dhcp6_duid_type1 *)duid->duid_id;
783		/* Foxconn modifed start pling 04/26/2011 */
784		/* Netgear Router Spec requires DUID to be type DUID-LL, not DUID-LLT */
785		/* dp->dh6duid1_type = htons(1); */ /* type 1 */
786		dp->dh6duid1_type = htons(3); /* type 3: DUID-LL */
787		/* Foxconn modifed end pling 04/26/2011 */
788		dp->dh6duid1_hwtype = htons(hwtype);
789		/* time is Jan 1, 2000 (UTC), modulo 2^32 */
790		t64 = (u_int64_t)(time(NULL) - 946684800);
791        /* Foxconn added start pling 10/07/2010 */
792        /* For testing purposes !!! */
793        if (duid_time) {
794            dprintf(LOG_DEBUG, "%s"
795                "**TESTING** Use user-defined duid_time %lu", FNAME, duid_time);
796            t64 = (u_int64_t)duid_time;
797        }
798        /* Foxconn added end pling 10/07/2010 */
799		/* Foxconn removed start pling 04/26/2011 */
800		/* Netgear Router Spec requires DUID to be type DUID-LL, not DUID-LLT */
801		/* dp->dh6duid1_time = htonl((u_long)(t64 & 0xffffffff)); */
802		/* Foxconn removed end pling 04/26/2011 */
803		memcpy((void *)(dp + 1), tmpbuf, (len - sizeof(*dp)));
804
805		dprintf(LOG_DEBUG, "%s" "generated a new DUID: %s", FNAME,
806			duidstr(duid));
807	}
808
809	/* save the (new) ID to the file for next time */
810	if (!fp) {
811		if ((fp = fopen(idfile, "w+")) == NULL) {
812			dprintf(LOG_ERR, "%s"
813			    "failed to open DUID file for save", FNAME);
814			goto fail;
815		}
816		if ((fwrite(&len, sizeof(len), 1, fp)) != 1) {
817			dprintf(LOG_ERR, "%s" "failed to save DUID", FNAME);
818			goto fail;
819		}
820		if ((fwrite(duid->duid_id, len, 1, fp)) != 1) {
821			dprintf(LOG_ERR, "%s" "failed to save DUID", FNAME);
822			goto fail;
823		}
824
825		dprintf(LOG_DEBUG, "%s" "saved generated DUID to %s", FNAME,
826			idfile);
827	}
828
829	if (fp)
830		fclose(fp);
831	return (0);
832
833  fail:
834	if (fp)
835		fclose(fp);
836	if (duid->duid_id != NULL) {
837		duidfree(duid);
838	}
839	return (-1);
840}
841
842ssize_t
843gethwid(buf, len, ifname, hwtypep)
844	char *buf;
845	int len;
846	const char *ifname;
847	u_int16_t *hwtypep;
848{
849	int skfd;
850	ssize_t l;
851	struct ifreq if_hwaddr;
852
853	if ((skfd = socket(AF_INET6, SOCK_DGRAM, 0 )) < 0)
854		return -1;
855
856	strcpy(if_hwaddr.ifr_name, ifname);
857	if (ioctl(skfd, SIOCGIFHWADDR, &if_hwaddr) < 0)
858		return -1;
859	/* only support Ethernet */
860	switch (if_hwaddr.ifr_hwaddr.sa_family) {
861	case ARPHRD_ETHER:
862	case ARPHRD_IEEE802:
863		*hwtypep = ARPHRD_ETHER;
864		l = 6;
865		break;
866	case ARPHRD_PPP:
867#if 0
868		*hwtypep = ARPHRD_PPP;
869		l = 0;
870		return l;
871#else
872		*hwtypep = ARPHRD_ETHER;
873		l = 6;
874		strcpy(if_hwaddr.ifr_name, "eth0");
875		if (ioctl(skfd, SIOCGIFHWADDR, &if_hwaddr) < 0)
876			return -1;
877		break;
878#endif
879	default:
880		dprintf(LOG_INFO, "dhcpv6 doesn't support hardware type %d",
881			if_hwaddr.ifr_hwaddr.sa_family);
882		return -1;
883	}
884	memcpy(buf, if_hwaddr.ifr_hwaddr.sa_data, l);
885	dprintf(LOG_DEBUG, "%s found an interface %s hardware %p",
886		FNAME, ifname, buf);
887	return l;
888}
889
890void
891dhcp6_init_options(optinfo)
892	struct dhcp6_optinfo *optinfo;
893{
894	memset(optinfo, 0, sizeof(*optinfo));
895	/* for safety */
896	optinfo->clientID.duid_id = NULL;
897	optinfo->serverID.duid_id = NULL;
898	optinfo->pref = DH6OPT_PREF_UNDEF;
899	TAILQ_INIT(&optinfo->addr_list);
900	/* Foxconn added start pling 09/23/2009 */
901	TAILQ_INIT(&optinfo->prefix_list);
902	/* Foxconn added end pling 09/23/2009 */
903	TAILQ_INIT(&optinfo->reqopt_list);
904	TAILQ_INIT(&optinfo->stcode_list);
905	TAILQ_INIT(&optinfo->dns_list.addrlist);
906    /* Foxconn added start pling 01/25/2010 */
907	TAILQ_INIT(&optinfo->sip_list);
908	TAILQ_INIT(&optinfo->ntp_list);
909    /* Foxconn added end pling 01/25/2010 */
910	TAILQ_INIT(&optinfo->relay_list);
911	optinfo->dns_list.domainlist = NULL;
912}
913
914void
915dhcp6_clear_options(optinfo)
916	struct dhcp6_optinfo *optinfo;
917{
918	struct domain_list *dlist, *dlist_next;
919	duidfree(&optinfo->clientID);
920	duidfree(&optinfo->serverID);
921
922	dhcp6_clear_list(&optinfo->addr_list);
923	/* Foxconn added start pling 09/23/2009 */
924	dhcp6_clear_list(&optinfo->prefix_list);
925	/* Foxconn added end pling 09/23/2009 */
926	dhcp6_clear_list(&optinfo->reqopt_list);
927	dhcp6_clear_list(&optinfo->stcode_list);
928	dhcp6_clear_list(&optinfo->dns_list.addrlist);
929	relayfree(&optinfo->relay_list);
930	if (dhcp6_mode == DHCP6_MODE_CLIENT) {
931		for (dlist = optinfo->dns_list.domainlist; dlist; dlist = dlist_next) {
932			dlist_next = dlist->next;
933			free(dlist);
934		}
935	}
936	optinfo->dns_list.domainlist = NULL;
937	dhcp6_init_options(optinfo);
938}
939
940int
941dhcp6_copy_options(dst, src)
942	struct dhcp6_optinfo *dst, *src;
943{
944	if (duidcpy(&dst->clientID, &src->clientID))
945		goto fail;
946	if (duidcpy(&dst->serverID, &src->serverID))
947		goto fail;
948	dst->flags = src->flags;
949
950	if (dhcp6_copy_list(&dst->addr_list, &src->addr_list))
951		goto fail;
952	/* Foxconn added start pling 09/23/2009 */
953	if (dhcp6_copy_list(&dst->prefix_list, &src->prefix_list))
954		goto fail;
955	/* Foxconn added end pling 09/23/2009 */
956	if (dhcp6_copy_list(&dst->reqopt_list, &src->reqopt_list))
957		goto fail;
958	if (dhcp6_copy_list(&dst->stcode_list, &src->stcode_list))
959		goto fail;
960	if (dhcp6_copy_list(&dst->dns_list.addrlist, &src->dns_list.addrlist))
961		goto fail;
962	memcpy(&dst->server_addr, &src->server_addr, sizeof(dst->server_addr));
963	dst->pref = src->pref;
964
965	return 0;
966
967  fail:
968	/* cleanup temporary resources */
969	dhcp6_clear_options(dst);
970	return -1;
971}
972
973/* Foxconn added start pling 10/04/2010 */
974/* Add two extra arguments for DHCP client to use.
975 * These two args are ignored in DHCP server mode (currently)
976 */
977#if 0
978int
979dhcp6_get_options(p, ep, optinfo)
980	struct dhcp6opt *p, *ep;
981	struct dhcp6_optinfo *optinfo;
982#endif
983int
984dhcp6_get_options(p, ep, optinfo, msgtype, state, send_flags)
985    struct dhcp6opt *p, *ep;
986    struct dhcp6_optinfo *optinfo;
987    int msgtype, state, send_flags;
988/* Foxconn added end pling 10/04/2010 */
989{
990	struct dhcp6opt *np, opth;
991	int i, opt, optlen, reqopts, num;
992	char *cp, *val;
993	u_int16_t val16;
994
995    /* Foxconn added start pling 09/24/2009 */
996    int has_iana = 0;
997    int has_iapd = 0;
998    /* Foxconn added end pling 09/24/2009 */
999    /* Foxconn added start pling 10/04/2010 */
1000    int has_dns = 0;
1001    int has_ntp = 0;
1002    int has_sip = 0;
1003    /* Foxconn added end pling 10/04/2010 */
1004    /* Foxconn added start pling 01/25/2010 */
1005    char buf[1204];
1006    char tmp_buf[1024];
1007    char command[1024];
1008    /* Foxconn added end pling 01/25/2010 */
1009    int  type_set = 0;      // pling added 10/22/2010
1010
1011	for (; p + 1 <= ep; p = np) {
1012		struct duid duid0;
1013
1014		memcpy(&opth, p, sizeof(opth));
1015		optlen = ntohs(opth.dh6opt_len);
1016		opt = ntohs(opth.dh6opt_type);
1017
1018		cp = (char *)(p + 1);
1019		np = (struct dhcp6opt *)(cp + optlen);
1020
1021		dprintf(LOG_DEBUG, "%s" "get DHCP option %s, len %d",
1022		    FNAME, dhcp6optstr(opt), optlen);
1023
1024		/* option length field overrun */
1025		if (np > ep) {
1026			dprintf(LOG_INFO,
1027			    "%s" "malformed DHCP options", FNAME);
1028			return -1;
1029		}
1030
1031		switch (opt) {
1032		case DH6OPT_CLIENTID:
1033			if (optlen == 0)
1034				goto malformed;
1035			duid0.duid_len = optlen;
1036			duid0.duid_id = cp;
1037			dprintf(LOG_DEBUG, "  DUID: %s", duidstr(&duid0));
1038			if (duidcpy(&optinfo->clientID, &duid0)) {
1039				dprintf(LOG_ERR, "%s" "failed to copy DUID",
1040					FNAME);
1041				goto fail;
1042			}
1043			break;
1044		case DH6OPT_SERVERID:
1045			if (optlen == 0)
1046				goto malformed;
1047			duid0.duid_len = optlen;
1048			duid0.duid_id = cp;
1049			dprintf(LOG_DEBUG, "  DUID: %s", duidstr(&duid0));
1050			if (duidcpy(&optinfo->serverID, &duid0)) {
1051				dprintf(LOG_ERR, "%s" "failed to copy DUID",
1052					FNAME);
1053				goto fail;
1054			}
1055			break;
1056		case DH6OPT_ELAPSED_TIME:
1057			if (optlen != sizeof(u_int16_t))
1058				goto malformed;
1059			memcpy(&val16, cp, sizeof(val16));
1060			num = ntohs(val16);
1061			dprintf(LOG_DEBUG, " this message elapsed time is: %d",
1062				num);
1063			break;
1064		case DH6OPT_STATUS_CODE:
1065			if (optlen < sizeof(u_int16_t))
1066				goto malformed;
1067			memcpy(&val16, cp, sizeof(val16));
1068			num = ntohs(val16);
1069			dprintf(LOG_DEBUG, "  this message status code: %s",
1070			    dhcp6_stcodestr(num));
1071
1072
1073			/* need to check duplication? */
1074
1075			if (dhcp6_add_listval(&optinfo->stcode_list,
1076			    &num, DHCP6_LISTVAL_NUM) == NULL) {
1077				dprintf(LOG_ERR, "%s" "failed to copy "
1078				    "status code", FNAME);
1079				goto fail;
1080			}
1081
1082			break;
1083		case DH6OPT_ORO:
1084			if ((optlen % 2) != 0 || optlen == 0)
1085				goto malformed;
1086			reqopts = optlen / 2;
1087			for (i = 0, val = cp; i < reqopts;
1088			     i++, val += sizeof(u_int16_t)) {
1089				u_int16_t opttype;
1090
1091				memcpy(&opttype, val, sizeof(u_int16_t));
1092				num = ntohs(opttype);
1093
1094				dprintf(LOG_DEBUG, "  requested option: %s",
1095					dhcp6optstr(num));
1096
1097				if (dhcp6_find_listval(&optinfo->reqopt_list,
1098				    &num, DHCP6_LISTVAL_NUM)) {
1099					dprintf(LOG_INFO, "%s" "duplicated "
1100					    "option type (%s)", FNAME,
1101					    dhcp6optstr(opttype));
1102					goto nextoption;
1103				}
1104
1105				if (dhcp6_add_listval(&optinfo->reqopt_list,
1106				    &num, DHCP6_LISTVAL_NUM) == NULL) {
1107					dprintf(LOG_ERR, "%s" "failed to copy "
1108					    "requested option", FNAME);
1109					goto fail;
1110				}
1111			nextoption: ;
1112			}
1113			break;
1114		case DH6OPT_PREFERENCE:
1115			if (optlen != 1)
1116				goto malformed;
1117			optinfo->pref = (u_int8_t)*(u_char *)cp;
1118			dprintf(LOG_DEBUG, "%s" "get option preferrence is %2x",
1119					FNAME, optinfo->pref);
1120			break;
1121		case DH6OPT_RAPID_COMMIT:
1122			if (optlen != 0)
1123				goto malformed;
1124			optinfo->flags |= DHCIFF_RAPID_COMMIT;
1125			break;
1126		case DH6OPT_UNICAST:
1127			if (optlen != sizeof(struct in6_addr)
1128			    && dhcp6_mode != DHCP6_MODE_CLIENT)
1129				goto malformed;
1130			optinfo->flags |= DHCIFF_UNICAST;
1131			memcpy(&optinfo->server_addr,
1132			       (struct in6_addr *)cp, sizeof(struct in6_addr));
1133			break;
1134		case DH6OPT_IA_TA:
1135			if (optlen < sizeof(u_int32_t))
1136				goto malformed;
1137			/* check iaid */
1138			optinfo->flags |= DHCIFF_TEMP_ADDRS;
1139			optinfo->type = IATA;
1140			dprintf(LOG_DEBUG, "%s" "get option iaid is %u",
1141				FNAME, optinfo->iaidinfo.iaid);
1142			optinfo->iaidinfo.iaid = ntohl(*(u_int32_t *)cp);
1143			if (get_assigned_ipv6addrs(cp + 4, cp + optlen, optinfo))
1144				goto fail;
1145			break;
1146		case DH6OPT_IA_NA:
1147		case DH6OPT_IA_PD:
1148		/* Foxconn modified start pling 09/23/2009 */
1149			if (dhcp6_mode == DHCP6_MODE_SERVER ||
1150					(dhcp6_mode == DHCP6_MODE_CLIENT && (send_flags & DHCIFF_SOLICIT_ONLY)) ||
1151					(dhcp6_mode == DHCP6_MODE_CLIENT && (dhcp6c_flags & DHCIFF_IAPD_ONLY))) {
1152				/* pling modified start 10/22/2010 */
1153				/* For each packet, we set to one type only (IANA/IAPD)
1154				 * but not both.
1155				 */
1156				if (opt == DH6OPT_IA_NA && type_set<2)
1157				{
1158					optinfo->type = IANA;
1159					type_set = 2;
1160				}
1161				else if (opt == DH6OPT_IA_PD && !type_set)
1162				{
1163					optinfo->type = IAPD;
1164					type_set = 1;
1165				}
1166				/* pling modified end 10/22/2010 */
1167			} else {
1168				/* don't set optinfo->type to IAPD as this version
1169				 * of dhcp6c can't handle IANA and IAPD concurrently.
1170				 */
1171				if (opt == DH6OPT_IA_NA)
1172					optinfo->type = IANA;
1173			}
1174			/* Foxconn modified end pling 09/23/2009 */
1175			/* check iaid */
1176			if (optlen < sizeof(struct dhcp6_iaid_info))
1177				goto malformed;
1178			if (dhcp6_mode == DHCP6_MODE_CLIENT && opt == DH6OPT_IA_PD)
1179				;// If this is IAPD, don't modify the IAID
1180			else
1181				optinfo->iaidinfo.iaid = ntohl(*(u_int32_t *)cp);
1182			optinfo->iaidinfo.renewtime =
1183				ntohl(*(u_int32_t *)(cp + sizeof(u_int32_t)));
1184			optinfo->iaidinfo.rebindtime =
1185				ntohl(*(u_int32_t *)(cp + 2 * sizeof(u_int32_t)));
1186			dprintf(LOG_DEBUG, "get option iaid is %u, renewtime %u, "
1187				"rebindtime %u", optinfo->iaidinfo.iaid,
1188				optinfo->iaidinfo.renewtime, optinfo->iaidinfo.rebindtime);
1189			/* Foxconn added start pling 10/07/2010 */
1190			/* DHCPv6 client readylogo:
1191			 * Ignore IA with T1 > T2 */
1192			if (optinfo->iaidinfo.renewtime > optinfo->iaidinfo.rebindtime)
1193				goto fail;
1194			/* Foxconn added end pling 10/07/2010 */
1195			if (get_assigned_ipv6addrs(cp + 3 * sizeof(u_int32_t),
1196						cp + optlen, optinfo))
1197				goto fail;
1198
1199			/* Foxconn added start pling 09/24/2009 */
1200			if (dhcp6_mode == DHCP6_MODE_CLIENT) {
1201				if (opt == DH6OPT_IA_NA)
1202					has_iana = 1;
1203				else
1204					has_iapd = 1;
1205			}
1206			/* Foxconn added end pling 09/24/2009 */
1207			break;
1208		case DH6OPT_DNS_SERVERS:
1209			if (optlen % sizeof(struct in6_addr) || optlen == 0)
1210				goto malformed;
1211			for (val = cp; val < cp + optlen;
1212			     val += sizeof(struct in6_addr)) {
1213				if (dhcp6_find_listval(&optinfo->dns_list.addrlist,
1214				    val, DHCP6_LISTVAL_ADDR6)) {
1215					dprintf(LOG_INFO, "%s" "duplicated "
1216					    "DNS address (%s)", FNAME,
1217					    in6addr2str((struct in6_addr *)val,
1218						0));
1219					goto nextdns;
1220				}
1221
1222				if (dhcp6_add_listval(&optinfo->dns_list.addrlist,
1223				    val, DHCP6_LISTVAL_ADDR6) == NULL) {
1224					dprintf(LOG_ERR, "%s" "failed to copy "
1225					    "DNS address", FNAME);
1226					goto fail;
1227				}
1228			nextdns: ;
1229			}
1230            /* Foxconn added start pling 10/04/2010 */
1231            if (dhcp6_mode == DHCP6_MODE_CLIENT)
1232                has_dns = 1;
1233            /* Foxconn added end pling 10/04/2010 */
1234			break;
1235
1236        /* Foxconn added start pling 01/25/2010 */
1237        case DH6OPT_SIP_SERVERS:
1238            memset(buf, 0, sizeof(buf));
1239            memset(tmp_buf, 0, sizeof(tmp_buf));
1240            if (optlen % sizeof(struct in6_addr) || optlen == 0)
1241                goto malformed;
1242            for (val = cp; val < cp + optlen;
1243                 val += sizeof(struct in6_addr)) {
1244                if (dhcp6_find_listval(&optinfo->sip_list,
1245                    val, DHCP6_LISTVAL_ADDR6)) {
1246                    dprintf(LOG_INFO, "%s" "duplicated "
1247                        "SIP address (%s)", FNAME,
1248                        in6addr2str((struct in6_addr *)val,
1249                        0));
1250                    goto nextsip;
1251                }
1252
1253                if (dhcp6_add_listval(&optinfo->sip_list,
1254                    val, DHCP6_LISTVAL_ADDR6) == NULL) {
1255                        dprintf(LOG_ERR, "%s" "failed to copy "
1256                        "SIP address", FNAME);
1257                    goto fail;
1258                }
1259                /* Save SIP server to NVRAM */
1260                sprintf(tmp_buf, "%s ", in6addr2str((struct in6_addr *)val, 0));
1261                strcat(buf, tmp_buf);
1262            nextsip: ;
1263            }
1264            /* Save SIP server to NVRAM */
1265            if (dhcp6_mode == DHCP6_MODE_CLIENT && strlen(buf)) {
1266                sprintf(command, "nvram set ipv6_sip_servers=\"%s\"", buf);
1267                system(command);
1268                has_sip = 1;    // Foxconn added pling 10/04/2010
1269            }
1270            break;
1271		case DH6OPT_NTP_SERVERS:
1272            memset(buf, 0, sizeof(buf));
1273            memset(tmp_buf, 0, sizeof(tmp_buf));
1274			if (optlen % sizeof(struct in6_addr) || optlen == 0)
1275				goto malformed;
1276			for (val = cp; val < cp + optlen;
1277			     val += sizeof(struct in6_addr)) {
1278				if (dhcp6_find_listval(&optinfo->ntp_list,
1279				    val, DHCP6_LISTVAL_ADDR6)) {
1280					dprintf(LOG_INFO, "%s" "duplicated "
1281					    "NTP address (%s)", FNAME,
1282					    in6addr2str((struct in6_addr *)val,
1283						0));
1284					goto nextntp;
1285				}
1286
1287				if (dhcp6_add_listval(&optinfo->ntp_list,
1288				    val, DHCP6_LISTVAL_ADDR6) == NULL) {
1289					dprintf(LOG_ERR, "%s" "failed to copy "
1290					    "NTP address", FNAME);
1291					goto fail;
1292				}
1293                /* Save SIP server to NVRAM */
1294                sprintf(tmp_buf, "%s ", in6addr2str((struct in6_addr *)val, 0));
1295                strcat(buf, tmp_buf);
1296			nextntp: ;
1297			}
1298            /* Save NTP server to NVRAM */
1299            if (dhcp6_mode == DHCP6_MODE_CLIENT && strlen(buf)) {
1300                sprintf(command, "nvram set ipv6_ntp_servers=\"%s\"", buf);
1301                system(command);
1302                has_ntp = 1;    // Foxconn added pling 10/04/2010
1303            }
1304			break;
1305        /* Foxconn added end pling 01/25/2010 */
1306
1307		case DH6OPT_DOMAIN_LIST:
1308			if (optlen == 0)
1309				goto malformed;
1310			/* dependency on lib resolv */
1311			for (val = cp; val < cp + optlen;) {
1312				int n;
1313				struct domain_list *dname, *dlist;
1314				dname = malloc(sizeof(*dname));
1315				if (dname == NULL) {
1316					dprintf(LOG_ERR, "%s" "failed to allocate memory",
1317						FNAME);
1318					goto fail;
1319				}
1320				n =  dn_expand(cp, cp + optlen, val, dname->name, MAXDNAME);
1321				if (n < 0)
1322					goto malformed;
1323				else {
1324					val += n;
1325					dprintf(LOG_DEBUG, "expand domain name %s, size %d",
1326						dname->name, strlen(dname->name));
1327				}
1328				dname->next = NULL;
1329				if (optinfo->dns_list.domainlist == NULL) {
1330					optinfo->dns_list.domainlist = dname;
1331				} else {
1332					for (dlist = optinfo->dns_list.domainlist; dlist;
1333					     dlist = dlist->next) {
1334						if (dlist->next == NULL) {
1335							dlist->next = dname;
1336							break;
1337						}
1338					}
1339				}
1340			}
1341			break;
1342		default:
1343			/* no option specific behavior */
1344			dprintf(LOG_INFO, "%s"
1345			    "unknown or unexpected DHCP6 option %s, len %d",
1346			    FNAME, dhcp6optstr(opt), optlen);
1347			break;
1348		}
1349	}
1350
1351    /* Foxconn added start pling 09/24/2009 */
1352    /* Per Netgear spec, an acceptable DHCP advertise
1353     *  must have both IANA and IAPD option.
1354     */
1355    if (dhcp6_mode == DHCP6_MODE_CLIENT) {
1356        /* Foxconn added start pling 09/21/2010 */
1357        /* Check flag to see if we accept IANA/IAPD only
1358         *  for DHCPv6 readylogo test.
1359         */
1360        if ((dhcp6c_flags & DHCIFF_IANA_ONLY) && has_iana)
1361        {
1362            dprintf(LOG_INFO, "%s" "recv IANA. OK!", FNAME);
1363        }
1364        else
1365        if (dhcp6c_flags & DHCIFF_INFO_ONLY)
1366        {
1367            dprintf(LOG_INFO, "%s" "Info-only. OK!", FNAME);
1368        }
1369        else
1370        if  ((dhcp6c_flags & DHCIFF_IAPD_ONLY) && has_iapd)
1371        {
1372            dprintf(LOG_INFO, "%s" "recv IAPD. OK!", FNAME);
1373        }
1374        else
1375        /* Foxconn added end pling 09/21/2010 */
1376        /* Foxconn added start pling 10/04/2010 */
1377        /* Handle DHCP messages properly in different states */
1378        if (state == DHCP6S_INFOREQ && msgtype == DH6_REPLY &&
1379            has_dns && has_ntp && has_sip)
1380        {
1381            dprintf(LOG_INFO, "%s" "valid INFOREQ/REPLY. OK!", FNAME);
1382        }
1383        else
1384        if (state == DHCP6S_DECLINE && msgtype == DH6_REPLY)
1385        {
1386            dprintf(LOG_INFO, "%s" "got REPLY to DECLINE.", FNAME);
1387        }
1388        else
1389        /* Foxconn added end pling 10/04/2010 */
1390        /* Foxconn added start pling 09/16/2011 */
1391        /* In auto-detect mode, we don't accept Advert pkt with IANA only. */
1392        if ((send_flags & DHCIFF_SOLICIT_ONLY) && has_iana && !has_iapd)
1393        {
1394            dprintf(LOG_INFO, "%s" "got IANA only in auto-detect mode. NG!", FNAME);
1395            goto fail;
1396        }
1397        else
1398        /* Foxconn added end pling 09/16/2011 */
1399        /* Foxconn added start pling 10/14/2010 */
1400        if ((send_flags & DHCIFF_SOLICIT_ONLY) &&
1401            (has_iana || has_iapd) )
1402        {
1403            dprintf(LOG_INFO, "%s" "got IANA/IAPD in auto-detect mode", FNAME);
1404        }
1405        else
1406        /* Foxconn added end pling 10/14/2010 */
1407        if (!has_iana || !has_iapd) {
1408            dprintf(LOG_INFO, "%s" "no IANA/IAPD", FNAME);
1409            goto fail;
1410        }
1411    }
1412    /* Foxconn added end pling 09/24/2009 */
1413
1414	return (0);
1415
1416  malformed:
1417	dprintf(LOG_INFO, "%s" "malformed DHCP option: type %d, len %d",
1418	    FNAME, opt, optlen);
1419  fail:
1420	dhcp6_clear_options(optinfo);
1421	return (-1);
1422}
1423
1424static int
1425get_assigned_ipv6addrs(p, ep, optinfo)
1426	char *p, *ep;
1427	struct dhcp6_optinfo *optinfo;
1428{
1429	char *np, *cp;
1430	struct dhcp6opt opth;
1431	struct dhcp6_addr_info ai;
1432	struct dhcp6_prefix_info pi;
1433	struct dhcp6_addr addr6;
1434	int optlen, opt;
1435	u_int16_t val16;
1436	int num;
1437    int has_status_code = 0;    /* Foxconn added pling 09/15/2011 */
1438
1439	/* Foxconn added start pling 12/22/2011 */
1440	char iapd_valid_lifetime_cmd_buf[1024];
1441	char iapd_preferred_lifetime_cmd_buf[1024];
1442	/* Foxconn added end pling 12/22/2011 */
1443
1444    /* Foxconn modified start pling 09/15/2011 */
1445    /* To work around IANA/IAPD without status code */
1446	//for (; p + sizeof(struct dhcp6opt) <= ep; p = np) {
1447	for (; /*p + sizeof(struct dhcp6opt) <= ep*/; p = np) {
1448
1449        if (p + sizeof(struct dhcp6opt) > ep)
1450        {
1451            /* Foxconn added start pling 10/19/2011 */
1452            /* for server, use original logic (break for loop) */
1453            if (dhcp6_mode == DHCP6_MODE_SERVER)
1454                break;
1455            /* Foxconn added end pling 10/19/2011 */
1456
1457            /* Client check status code below */
1458            if (has_status_code)
1459                break;
1460            else {
1461                has_status_code = 1;
1462                goto no_status_code;
1463            }
1464        }
1465    /* Foxconn modified end pling 09/15/2011 */
1466		memcpy(&opth, p, sizeof(opth));
1467		optlen =  ntohs(opth.dh6opt_len);
1468		opt = ntohs(opth.dh6opt_type);
1469		cp = p + sizeof(opth);
1470		np = cp + optlen;
1471		dprintf(LOG_DEBUG, "  IA address option: %s, "
1472			"len %d", dhcp6optstr(opt), optlen);
1473
1474		if (np > ep) {
1475			dprintf(LOG_INFO, "%s" "malformed DHCP options",
1476			    FNAME);
1477			return -1;
1478		}
1479		switch(opt) {
1480		case DH6OPT_STATUS_CODE:
1481			if (optlen < sizeof(val16))
1482				goto malformed;
1483			memcpy(&val16, cp, sizeof(val16));
1484			num = ntohs(val16);
1485			dprintf(LOG_INFO, "status code for this address is: %s",
1486				dhcp6_stcodestr(num));
1487			if (optlen > sizeof(val16)) {
1488				dprintf(LOG_INFO,
1489					"status message for this address is: %-*s",
1490					(int)(optlen-sizeof(val16)), p+(val16));
1491			}
1492			if (dhcp6_add_listval(&optinfo->stcode_list,
1493			    &num, DHCP6_LISTVAL_NUM) == NULL) {
1494				dprintf(LOG_ERR, "%s" "failed to copy "
1495				    "status code", FNAME);
1496				goto fail;
1497			}
1498            has_status_code = 1;    /* Foxconn added pling 09/15/2011 */
1499			break;
1500		case DH6OPT_IADDR:
1501			if (optlen < sizeof(ai) - sizeof(u_int32_t))
1502				goto malformed;
1503			memcpy(&ai, p, sizeof(ai));
1504			/* copy the information into internal format */
1505			memset(&addr6, 0, sizeof(addr6));
1506			memcpy(&addr6.addr, (struct in6_addr *)cp, sizeof(struct in6_addr));
1507			addr6.preferlifetime = ntohl(ai.preferlifetime);
1508			addr6.validlifetime = ntohl(ai.validlifetime);
1509			dprintf(LOG_DEBUG, "  get IAADR address information: "
1510			    "%s preferlifetime %d validlifetime %d",
1511			    in6addr2str(&addr6.addr, 0),
1512			    addr6.preferlifetime, addr6.validlifetime);
1513			/* It shouldn't happen, since Server will do the check before
1514			 * sending the data to clients */
1515			if (addr6.preferlifetime > addr6.validlifetime) {
1516				dprintf(LOG_INFO, "preferred life time"
1517				    "(%d) is greater than valid life time"
1518				    "(%d)", addr6.preferlifetime, addr6.validlifetime);
1519				goto malformed;
1520			}
1521			if (optlen == sizeof(ai) - sizeof(u_int32_t)) {
1522				addr6.status_code = DH6OPT_STCODE_UNDEFINE;
1523				break;
1524			}
1525			/* address status code might be added after IADDA option */
1526			memcpy(&opth, p + sizeof(ai), sizeof(opth));
1527			optlen =  ntohs(opth.dh6opt_len);
1528			opt = ntohs(opth.dh6opt_type);
1529			switch(opt) {
1530			case DH6OPT_STATUS_CODE:
1531				if (optlen < sizeof(val16))
1532					goto malformed;
1533				memcpy(&val16, p + sizeof(ai) + sizeof(opth), sizeof(val16));
1534				num = ntohs(val16);
1535				dprintf(LOG_INFO, "status code for this address is: %s",
1536					dhcp6_stcodestr(num));
1537				addr6.status_code = num;
1538				if (optlen > sizeof(val16)) {
1539					dprintf(LOG_INFO,
1540						"status message for this address is: %-*s",
1541						(int)(optlen-sizeof(val16)), p+(val16));
1542				}
1543				break;
1544			default:
1545				goto malformed;
1546			}
1547			break;
1548		case DH6OPT_IAPREFIX:
1549			if (optlen < sizeof(pi) - sizeof(u_int32_t))
1550			       goto malformed;
1551			memcpy(&pi, p, sizeof(pi));
1552			/* copy the information into internal format */
1553			memset(&addr6, 0, sizeof(addr6));
1554			addr6.preferlifetime = ntohl(pi.preferlifetime);
1555			addr6.validlifetime = ntohl(pi.validlifetime);
1556			addr6.plen = pi.plen;
1557			memcpy(&addr6.addr, &pi.prefix, sizeof(struct in6_addr));
1558			dprintf(LOG_DEBUG, "  get IAPREFIX prefix information: "
1559			    "%s/%d preferlifetime %d validlifetime %d",
1560			    in6addr2str(&addr6.addr, 0), addr6.plen,
1561			    addr6.preferlifetime, addr6.validlifetime);
1562			/* It shouldn't happen, since Server will do the check before
1563			 * sending the data to clients */
1564			if (addr6.preferlifetime > addr6.validlifetime) {
1565				dprintf(LOG_INFO, "preferred life time"
1566				    "(%d) is greater than valid life time"
1567				    "(%d)", addr6.preferlifetime, addr6.validlifetime);
1568				goto malformed;
1569			}
1570
1571			/* Foxconn added start pling 12/22/2011 */
1572			/* WNDR4500 TD#156: Record the IAPD valid and preferred lifetime */
1573			if (dhcp6_mode == DHCP6_MODE_CLIENT) {
1574				sprintf(iapd_valid_lifetime_cmd_buf,
1575						"nvram set RA_AdvValidLifetime_from_IAPD=%u",
1576						addr6.validlifetime);
1577				sprintf(iapd_preferred_lifetime_cmd_buf,
1578						"nvram set RA_AdvPreferredLifetime_from_IAPD=%u",
1579						addr6.preferlifetime);
1580			}
1581			/* Foxconn added end pling 12/22/2011 */
1582
1583            if (!(dhcp6c_flags & DHCIFF_IAPD_ONLY))
1584    			addr6.type = IAPD;      /* Foxconn added pling 01/25/2009 */
1585			if (optlen == sizeof(pi) - sizeof(u_int32_t)) {
1586				addr6.status_code = DH6OPT_STCODE_UNDEFINE;
1587				break;
1588			}
1589			/* address status code might be added after IADDA option */
1590			memcpy(&opth, p + sizeof(pi), sizeof(opth));
1591			optlen =  ntohs(opth.dh6opt_len);
1592			opt = ntohs(opth.dh6opt_type);
1593			switch(opt) {
1594			case DH6OPT_STATUS_CODE:
1595				if (optlen < sizeof(val16))
1596					goto malformed;
1597				memcpy(&val16, p + sizeof(pi) + sizeof(opth), sizeof(val16));
1598				num = ntohs(val16);
1599				dprintf(LOG_INFO, "status code for this prefix is: %s",
1600					dhcp6_stcodestr(num));
1601				addr6.status_code = num;
1602				if (optlen > sizeof(val16)) {
1603					dprintf(LOG_INFO,
1604						"status message for this prefix is: %-*s",
1605						(int)(optlen-sizeof(val16)), p+(val16));
1606				}
1607				break;
1608			default:
1609				goto malformed;
1610			}
1611			break;
1612		default:
1613			goto malformed;
1614		}
1615
1616no_status_code: /* Foxconn added start pling 09/15/2011 */
1617		/* set up address type */
1618		/* Foxconn added start pling 09/23/2009 */
1619		if (addr6.type == IAPD) {
1620		    /* Foxconn added start pling 01/25/2010 */
1621    		if (dhcp6_find_listval(&optinfo->prefix_list,
1622	    			&addr6, DHCP6_LISTVAL_DHCP6ADDR)) {
1623		    	dprintf(LOG_INFO, "duplicated prefix (%s/%d)",
1624			    	in6addr2str(&addr6.addr, 0), addr6.plen);
1625    			continue;
1626	    	}
1627		    /* Foxconn added end pling 01/25/2010 */
1628			if (dhcp6_add_listval(&optinfo->prefix_list, &addr6,
1629			    DHCP6_LISTVAL_DHCP6ADDR) == NULL) {
1630				dprintf(LOG_ERR, "%s" "failed to copy prefix", FNAME);
1631				goto fail;
1632			}
1633		} else {
1634		/* Foxconn added end pling 09/23/2009 */
1635		addr6.type = optinfo->type;
1636		if (dhcp6_find_listval(&optinfo->addr_list,
1637				&addr6, DHCP6_LISTVAL_DHCP6ADDR)) {
1638			dprintf(LOG_INFO, "duplicated address (%s/%d)",
1639				in6addr2str(&addr6.addr, 0), addr6.plen);
1640			continue;
1641		}
1642		if (dhcp6_add_listval(&optinfo->addr_list, &addr6,
1643		    DHCP6_LISTVAL_DHCP6ADDR) == NULL) {
1644			dprintf(LOG_ERR, "%s" "failed to copy an "
1645			    "address", FNAME);
1646			goto fail;
1647		}
1648		/* Foxconn added start pling 09/23/2009 */
1649		} /* if (addr6.type == IAPD) */
1650		/* Foxconn added end pling 09/23/2009 */
1651	}
1652
1653	/* Foxconn added start pling 12/22/2011 */
1654	/* WNDR4500 TD#156: Set the IAPD valid and preferred lifetime
1655	 * to NVRAM for acos rc to use */
1656	if (dhcp6_mode == DHCP6_MODE_CLIENT) {
1657		system(iapd_valid_lifetime_cmd_buf);
1658		system(iapd_preferred_lifetime_cmd_buf);
1659		system("nvram set RA_use_dynamic_lifetime=1");
1660	}
1661	/* Foxconn added end pling 12/22/2011 */
1662
1663	return (0);
1664
1665  malformed:
1666	dprintf(LOG_INFO,
1667		"  malformed IA option: type %d, len %d",
1668		opt, optlen);
1669  fail:
1670	return (-1);
1671}
1672
1673#define COPY_OPTION(t, l, v, p) do { \
1674	if ((void *)(ep) - (void *)(p) < (l) + sizeof(struct dhcp6opt)) { \
1675		dprintf(LOG_INFO, "%s" "option buffer short for %s", FNAME, dhcp6optstr((t))); \
1676		goto fail; \
1677	} \
1678	opth.dh6opt_type = htons((t)); \
1679	opth.dh6opt_len = htons((l)); \
1680	memcpy((p), &opth, sizeof(opth)); \
1681	if ((l)) \
1682		memcpy((p) + 1, (v), (l)); \
1683	(p) = (struct dhcp6opt *)((char *)((p) + 1) + (l)); \
1684 	(len) += sizeof(struct dhcp6opt) + (l); \
1685	dprintf(LOG_DEBUG, "%s" "set %s", FNAME, dhcp6optstr((t))); \
1686} while (0)
1687
1688int
1689dhcp6_set_options(bp, ep, optinfo)
1690	struct dhcp6opt *bp, *ep;
1691	struct dhcp6_optinfo *optinfo;
1692{
1693	struct dhcp6opt *p = bp, opth;
1694	struct dhcp6_listval *stcode;
1695	int len = 0, optlen = 0;
1696	char *tmpbuf = NULL;
1697
1698	if (optinfo->clientID.duid_len) {
1699		COPY_OPTION(DH6OPT_CLIENTID, optinfo->clientID.duid_len,
1700			    optinfo->clientID.duid_id, p);
1701	}
1702
1703	if (optinfo->serverID.duid_len) {
1704		COPY_OPTION(DH6OPT_SERVERID, optinfo->serverID.duid_len,
1705			    optinfo->serverID.duid_id, p);
1706	}
1707	if (dhcp6_mode == DHCP6_MODE_CLIENT)
1708    {
1709        /* Foxconn modified start pling 10/01/2010 */
1710        /* Take care of endian issue */
1711		// COPY_OPTION(DH6OPT_ELAPSED_TIME, 2, &optinfo->elapsed_time, p);
1712        u_int16_t elapsed_time = htons(optinfo->elapsed_time);
1713        COPY_OPTION(DH6OPT_ELAPSED_TIME, 2, &elapsed_time, p);
1714        /* Foxconn modified end pling 10/01/2010 */
1715    }
1716
1717    /* Foxconn added start pling 09/07/2010 */
1718    /* For dhcp6c, add user-class if specified */
1719    if (dhcp6_mode == DHCP6_MODE_CLIENT)
1720    {
1721        /* user class option in this format (RFC3315):
1722        0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
1723        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1724        | OPTION_USER_CLASS               | option-len                  |
1725        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1726        | user-class-data                                               .
1727        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1728
1729         user-class-data in this format:
1730        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-...-+-+-+-+-+-+-+
1731        | user-class-len (2 bytes)        | opaque-data                 |
1732        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-...-+-+-+-+-+-+-+
1733         */
1734        int option_len;
1735        unsigned short *user_class_len;
1736        char user_class_data[MAX_USER_CLASS_LEN+2];
1737
1738        if (strlen(optinfo->user_class))
1739        {
1740            option_len = strlen(optinfo->user_class) + 2;
1741            user_class_len = (unsigned short *)&user_class_data;
1742            *user_class_len = htons(strlen(optinfo->user_class));
1743            strcpy(&user_class_data[2], optinfo->user_class);
1744            COPY_OPTION(DH6OPT_USER_CLASS, option_len, user_class_data, p);
1745        }
1746    }
1747    /* Foxconn added end pling 09/07/2010 */
1748
1749	if (optinfo->flags & DHCIFF_RAPID_COMMIT)
1750		COPY_OPTION(DH6OPT_RAPID_COMMIT, 0, NULL, p);
1751
1752	if ((dhcp6_mode == DHCP6_MODE_SERVER) && (optinfo->flags & DHCIFF_UNICAST)) {
1753		if (!IN6_IS_ADDR_UNSPECIFIED(&optinfo->server_addr)) {
1754			COPY_OPTION(DH6OPT_UNICAST, sizeof(optinfo->server_addr),
1755				    &optinfo->server_addr, p);
1756		}
1757	}
1758	switch(optinfo->type) {
1759	int buflen;
1760	char *tp;
1761	u_int32_t iaid;
1762	struct dhcp6_iaid_info opt_iana;
1763	struct dhcp6_iaid_info opt_iapd;
1764	struct dhcp6_prefix_info pi;
1765	struct dhcp6_addr_info ai;
1766	struct dhcp6_status_info status;
1767	struct dhcp6_listval *dp;
1768	case IATA:
1769	case IANA:
1770		/* Foxconn added start pling 06/04/2014 */
1771		/* For iOS device compatibility */
1772		if (dhcp6_mode == DHCP6_MODE_SERVER)
1773		{
1774			dprintf(LOG_DEBUG, "%s" "DHCP server don't check IAID!", FNAME);
1775		}
1776		else
1777		/* Foxconn added end pling 06/04/2014 */
1778		if (optinfo->iaidinfo.iaid == 0)
1779			break;
1780		if (optinfo->type == IATA) {
1781			optlen = sizeof(iaid);
1782			dprintf(LOG_DEBUG, "%s" "set IA_TA iaid information: %d", FNAME,
1783				optinfo->iaidinfo.iaid);
1784			iaid = htonl(optinfo->iaidinfo.iaid);
1785		} else if (optinfo->type == IANA) {
1786			optlen = sizeof(opt_iana);
1787			dprintf(LOG_DEBUG, "set IA_NA iaidinfo: "
1788		   		"iaid %u renewtime %u rebindtime %u",
1789		   		optinfo->iaidinfo.iaid, optinfo->iaidinfo.renewtime,
1790		   		optinfo->iaidinfo.rebindtime);
1791			opt_iana.iaid = htonl(optinfo->iaidinfo.iaid);
1792		    /* Foxconn modified start pling 01/25/2010 */
1793    		/* Per Netgear spec, use IAID '11' for IAPD in dhcp6c */
1794	    	if (dhcp6_mode == DHCP6_MODE_CLIENT)
1795		    	opt_iana.iaid = htonl(IANA_IAID);
1796    		/* Foxconn modified end pling 01/25/2010 */
1797			opt_iana.renewtime = htonl(optinfo->iaidinfo.renewtime);
1798			opt_iana.rebindtime = htonl(optinfo->iaidinfo.rebindtime);
1799		}
1800        /* Foxconn modified start pling 09/24/2009 */
1801		if (dhcp6_mode == DHCP6_MODE_SERVER ||
1802            dhcp6_mode == DHCP6_MODE_CLIENT && dhcp6c_flags & DHCIFF_IAPD_ONLY) {
1803		    buflen = sizeof(opt_iana) + dhcp6_count_list(&optinfo->addr_list) *
1804			    	(sizeof(ai) + sizeof(status));
1805        } else {
1806            /* Client don't need to send the status code */
1807		    buflen = sizeof(opt_iana) + dhcp6_count_list(&optinfo->addr_list) *
1808			    	 sizeof(ai);
1809        }
1810        /* Foxconn modified end pling 09/24/2009 */
1811		tmpbuf = NULL;
1812		if ((tmpbuf = malloc(buflen)) == NULL) {
1813			dprintf(LOG_ERR, "%s"
1814				"memory allocation failed for options", FNAME);
1815			goto fail;
1816		}
1817		if (optinfo->type == IATA)
1818			memcpy(tmpbuf, &iaid, sizeof(iaid));
1819		else
1820			memcpy(tmpbuf, &opt_iana, sizeof(opt_iana));
1821		tp = tmpbuf + optlen;
1822		optlen += dhcp6_count_list(&optinfo->addr_list) * sizeof(ai);
1823		if (!TAILQ_EMPTY(&optinfo->addr_list)) {
1824			for (dp = TAILQ_FIRST(&optinfo->addr_list); dp;
1825			     dp = TAILQ_NEXT(dp, link)) {
1826				int iaddr_len = 0;
1827				memset(&ai, 0, sizeof(ai));
1828				ai.dh6_ai_type = htons(DH6OPT_IADDR);
1829				if (dp->val_dhcp6addr.status_code != DH6OPT_STCODE_UNDEFINE) {
1830                    /* Foxconn modified start pling 09/24/2009 */
1831		            if (dhcp6_mode == DHCP6_MODE_SERVER)
1832					    iaddr_len = sizeof(ai) - sizeof(u_int32_t)
1833						    		+ sizeof(status);
1834                    else
1835					    iaddr_len = sizeof(ai) - sizeof(u_int32_t);
1836                } else
1837					iaddr_len = sizeof(ai) - sizeof(u_int32_t);
1838				ai.dh6_ai_len = htons(iaddr_len);
1839				ai.preferlifetime = htonl(dp->val_dhcp6addr.preferlifetime);
1840				ai.validlifetime = htonl(dp->val_dhcp6addr.validlifetime);
1841				memcpy(&ai.addr, &dp->val_dhcp6addr.addr,
1842			       		sizeof(ai.addr));
1843				memcpy(tp, &ai, sizeof(ai));
1844				tp += sizeof(ai);
1845				dprintf(LOG_DEBUG, "set IADDR address option len %d: "
1846			    		"%s preferlifetime %d validlifetime %d",
1847			    		iaddr_len, in6addr2str(&ai.addr, 0),
1848			    		ntohl(ai.preferlifetime),
1849					ntohl(ai.validlifetime));
1850				/* set up address status code if any */
1851                /* Foxconn added start pling 09/24/2009 */
1852                /* Don't add status code in client reqeust */
1853		        if (dhcp6_mode == DHCP6_MODE_CLIENT)
1854                    ;
1855                else
1856                /* Foxconn added end pling 09/24/2009 */
1857				if (dp->val_dhcp6addr.status_code != DH6OPT_STCODE_UNDEFINE) {
1858					status.dh6_status_type = htons(DH6OPT_STATUS_CODE);
1859					status.dh6_status_len =
1860						htons(sizeof(status.dh6_status_code));
1861					status.dh6_status_code =
1862						htons(dp->val_dhcp6addr.status_code);
1863					memcpy(tp, &status, sizeof(status));
1864					dprintf(LOG_DEBUG, "  this address status code: %s",
1865			    		dhcp6_stcodestr(ntohs(status.dh6_status_code)));
1866					optlen += sizeof(status);
1867					tp += sizeof(status);
1868                }
1869			}
1870		} else if (dhcp6_mode == DHCP6_MODE_SERVER) {
1871			int num;
1872			num = DH6OPT_STCODE_NOADDRAVAIL;
1873			dprintf(LOG_DEBUG, "  status code: %s",
1874			    dhcp6_stcodestr(num));
1875			if (dhcp6_add_listval(&optinfo->stcode_list,
1876			    &num, DHCP6_LISTVAL_NUM) == NULL) {
1877				dprintf(LOG_ERR, "%s" "failed to copy "
1878				    "status code", FNAME);
1879				goto fail;
1880			}
1881		}
1882		if (optinfo->type == IATA)
1883			COPY_OPTION(DH6OPT_IA_TA, optlen, tmpbuf, p);
1884		else if (optinfo->type == IANA)
1885			COPY_OPTION(DH6OPT_IA_NA, optlen, tmpbuf, p);
1886		free(tmpbuf);
1887		/* Foxconn modified start pling 09/22/2009 */
1888		/* Per Netgear spec, dhcp6c need to send IAPD,
1889		 *  so we fall through to do IAPD.
1890		 */
1891		if (dhcp6_mode == DHCP6_MODE_SERVER)
1892			break;
1893		/* Foxconn modified end pling 09/22/2009 */
1894        /* Foxconn added start pling 10/01/2010 */
1895        /* For DHCPv6 readylogo test, send IANA only */
1896        if (dhcp6_mode == DHCP6_MODE_CLIENT &&
1897            dhcp6c_flags & DHCIFF_IANA_ONLY)
1898            break;
1899        /* Foxconn added end pling 10/01/2010 */
1900	case IAPD:
1901		/* Foxconn modified start pling 09/22/2009 */
1902		/* Per Netgear spec, use IAID '11' for IAPD in dhcp6c */
1903		if (dhcp6_mode == DHCP6_MODE_CLIENT)
1904			optinfo->iaidinfo.iaid = IAPD_IAID;
1905		/* Foxconn modified end pling 09/22/2009 */
1906		if (optinfo->iaidinfo.iaid == 0)
1907			break;
1908		optlen = sizeof(opt_iapd);
1909		dprintf(LOG_DEBUG, "set IA_PD iaidinfo: "
1910		 	"iaid %u renewtime %u rebindtime %u",
1911		  	optinfo->iaidinfo.iaid, optinfo->iaidinfo.renewtime,
1912		   	optinfo->iaidinfo.rebindtime);
1913		opt_iapd.iaid = htonl(optinfo->iaidinfo.iaid);
1914		opt_iapd.renewtime = htonl(optinfo->iaidinfo.renewtime);
1915		opt_iapd.rebindtime = htonl(optinfo->iaidinfo.rebindtime);
1916		/* Foxconn modified start pling 09/23/2009 */
1917        /* In DHCP client mode, copy the prefix,
1918         * but not include the status code
1919         */
1920		if (dhcp6_mode == DHCP6_MODE_SERVER ||
1921            dhcp6_mode == DHCP6_MODE_CLIENT && dhcp6c_flags & DHCIFF_IAPD_ONLY)
1922		    buflen = sizeof(opt_iapd) + dhcp6_count_list(&optinfo->addr_list) *
1923			    	(sizeof(pi) + sizeof(status));
1924        else
1925    		buflen = sizeof(opt_iapd) + dhcp6_count_list(&optinfo->prefix_list) *
1926 	    			sizeof(pi);
1927		/* Foxconn modified end pling 09/23/2009 */
1928		tmpbuf = NULL;
1929		if ((tmpbuf = malloc(buflen)) == NULL) {
1930			dprintf(LOG_ERR, "%s"
1931				"memory allocation failed for options", FNAME);
1932			goto fail;
1933		}
1934		memcpy(tmpbuf, &opt_iapd, sizeof(opt_iapd));
1935		tp = tmpbuf + optlen;
1936		/* Foxconn modified start pling 09/23/2009 */
1937        /* IAPD is handle differently in server and client mode */
1938		if (dhcp6_mode == DHCP6_MODE_SERVER ||
1939            dhcp6_mode == DHCP6_MODE_CLIENT && dhcp6c_flags & DHCIFF_IAPD_ONLY) {
1940		    optlen += dhcp6_count_list(&optinfo->addr_list) * sizeof(pi);
1941    		if (!TAILQ_EMPTY(&optinfo->addr_list)) {
1942	    		for (dp = TAILQ_FIRST(&optinfo->addr_list); dp;
1943			        dp = TAILQ_NEXT(dp, link)) {
1944    				int iaddr_len = 0;
1945	    			memset(&pi, 0, sizeof(pi));
1946		    		pi.dh6_pi_type = htons(DH6OPT_IAPREFIX);
1947			    	if (dp->val_dhcp6addr.status_code != DH6OPT_STCODE_UNDEFINE)
1948    					iaddr_len = sizeof(pi) - sizeof(u_int32_t)
1949	    					+ sizeof(status);
1950				    else
1951					    iaddr_len = sizeof(pi) - sizeof(u_int32_t);
1952    				pi.dh6_pi_len = htons(iaddr_len);
1953	    			pi.preferlifetime = htonl(dp->val_dhcp6addr.preferlifetime);
1954		    		pi.validlifetime = htonl(dp->val_dhcp6addr.validlifetime);
1955			    	pi.plen = dp->val_dhcp6addr.plen;
1956				    memcpy(&pi.prefix, &dp->val_dhcp6addr.addr, sizeof(pi.prefix));
1957    				memcpy(tp, &pi, sizeof(pi));
1958	    			tp += sizeof(pi);
1959		    		dprintf(LOG_DEBUG, "set IAPREFIX option len %d: "
1960			        		"%s/%d preferlifetime %d validlifetime %d",
1961			        		iaddr_len, in6addr2str(&pi.prefix, 0), pi.plen,
1962			    	    	ntohl(pi.preferlifetime), ntohl(pi.validlifetime));
1963    				/* set up address status code if any */
1964    				if (dp->val_dhcp6addr.status_code != DH6OPT_STCODE_UNDEFINE) {
1965	    				status.dh6_status_type = htons(DH6OPT_STATUS_CODE);
1966		    			status.dh6_status_len =
1967			    			htons(sizeof(status.dh6_status_code));
1968				    	status.dh6_status_code =
1969					    	htons(dp->val_dhcp6addr.status_code);
1970    					memcpy(tp, &status, sizeof(status));
1971	    				dprintf(LOG_DEBUG, "  this address status code: %s",
1972		    	    		dhcp6_stcodestr(ntohs(status.dh6_status_code)));
1973			    		optlen += sizeof(status);
1974				    	tp += sizeof(status);
1975					    /* copy status message if any */
1976    				}
1977                }
1978		    } else if (dhcp6_mode == DHCP6_MODE_SERVER) {
1979			    int num;
1980    			num = DH6OPT_STCODE_NOPREFIXAVAIL;
1981	    		dprintf(LOG_DEBUG, "  status code: %s",
1982		    	    dhcp6_stcodestr(num));
1983			    if (dhcp6_add_listval(&optinfo->stcode_list,
1984			        &num, DHCP6_LISTVAL_NUM) == NULL) {
1985    				dprintf(LOG_ERR, "%s" "failed to copy "
1986	    			    "status code", FNAME);
1987		    		goto fail;
1988			    }
1989    		}
1990        } else {
1991            /* Client mode */
1992            /* Use 'prefix_list' instead of 'addr_list' for IAPD */
1993    		optlen += dhcp6_count_list(&optinfo->prefix_list) * sizeof(pi);
1994	    	if (!TAILQ_EMPTY(&optinfo->prefix_list)) {
1995		    	for (dp = TAILQ_FIRST(&optinfo->prefix_list); dp;
1996			         dp = TAILQ_NEXT(dp, link)) {
1997				    int iaddr_len = 0;
1998    				memset(&pi, 0, sizeof(pi));
1999	    			pi.dh6_pi_type = htons(DH6OPT_IAPREFIX);
2000		    		if (dp->val_dhcp6addr.status_code != DH6OPT_STCODE_UNDEFINE)
2001					    iaddr_len = sizeof(pi) - sizeof(u_int32_t);
2002    				else
2003	    				iaddr_len = sizeof(pi) - sizeof(u_int32_t);
2004		    		pi.dh6_pi_len = htons(iaddr_len);
2005			    	pi.preferlifetime = htonl(dp->val_dhcp6addr.preferlifetime);
2006				    pi.validlifetime = htonl(dp->val_dhcp6addr.validlifetime);
2007    				pi.plen = dp->val_dhcp6addr.plen;
2008	    			memcpy(&pi.prefix, &dp->val_dhcp6addr.addr, sizeof(pi.prefix));
2009		    		memcpy(tp, &pi, sizeof(pi));
2010			    	tp += sizeof(pi);
2011				    dprintf(LOG_DEBUG, "set IAPREFIX option len %d: "
2012			    	    	"%s/%d preferlifetime %d validlifetime %d",
2013			    		    iaddr_len, in6addr2str(&pi.prefix, 0), pi.plen,
2014    			    		ntohl(pi.preferlifetime), ntohl(pi.validlifetime));
2015                }
2016			}
2017		}
2018        /* Foxconn modified end 09/23/2009 */
2019		COPY_OPTION(DH6OPT_IA_PD, optlen, tmpbuf, p);
2020		free(tmpbuf);
2021		break;
2022	default:
2023		break;
2024	}
2025	if (dhcp6_mode == DHCP6_MODE_SERVER && optinfo->pref != DH6OPT_PREF_UNDEF) {
2026		u_int8_t p8 = (u_int8_t)optinfo->pref;
2027		dprintf(LOG_DEBUG, "server preference %2x", optinfo->pref);
2028		COPY_OPTION(DH6OPT_PREFERENCE, sizeof(p8), &p8, p);
2029	}
2030
2031	for (stcode = TAILQ_FIRST(&optinfo->stcode_list); stcode;
2032	     stcode = TAILQ_NEXT(stcode, link)) {
2033		u_int16_t code;
2034
2035		code = htons(stcode->val_num);
2036		COPY_OPTION(DH6OPT_STATUS_CODE, sizeof(code), &code, p);
2037	}
2038
2039	if (!TAILQ_EMPTY(&optinfo->reqopt_list)) {
2040		struct dhcp6_listval *opt;
2041		u_int16_t *valp;
2042
2043		tmpbuf = NULL;
2044		optlen = dhcp6_count_list(&optinfo->reqopt_list) *
2045			sizeof(u_int16_t);
2046		if ((tmpbuf = malloc(optlen)) == NULL) {
2047			dprintf(LOG_ERR, "%s"
2048			    "memory allocation failed for options", FNAME);
2049			goto fail;
2050		}
2051		valp = (u_int16_t *)tmpbuf;
2052		for (opt = TAILQ_FIRST(&optinfo->reqopt_list); opt;
2053		     opt = TAILQ_NEXT(opt, link), valp++) {
2054			*valp = htons((u_int16_t)opt->val_num);
2055		}
2056		COPY_OPTION(DH6OPT_ORO, optlen, tmpbuf, p);
2057		free(tmpbuf);
2058	}
2059
2060	if (!TAILQ_EMPTY(&optinfo->dns_list.addrlist)) {
2061		struct in6_addr *in6;
2062		struct dhcp6_listval *d;
2063
2064		tmpbuf = NULL;
2065		optlen = dhcp6_count_list(&optinfo->dns_list.addrlist) *
2066			sizeof(struct in6_addr);
2067		if ((tmpbuf = malloc(optlen)) == NULL) {
2068			dprintf(LOG_ERR, "%s"
2069			    "memory allocation failed for DNS options", FNAME);
2070			goto fail;
2071		}
2072		in6 = (struct in6_addr *)tmpbuf;
2073		for (d = TAILQ_FIRST(&optinfo->dns_list.addrlist); d;
2074		     d = TAILQ_NEXT(d, link), in6++) {
2075			memcpy(in6, &d->val_addr6, sizeof(*in6));
2076		}
2077		COPY_OPTION(DH6OPT_DNS_SERVERS, optlen, tmpbuf, p);
2078		free(tmpbuf);
2079	}
2080
2081    /* Foxconn added start pling 01/25/2010 */
2082	if (!TAILQ_EMPTY(&optinfo->sip_list)) {
2083		struct in6_addr *in6;
2084		struct dhcp6_listval *d;
2085
2086		tmpbuf = NULL;
2087		optlen = dhcp6_count_list(&optinfo->sip_list) *
2088			sizeof(struct in6_addr);
2089		if ((tmpbuf = malloc(optlen)) == NULL) {
2090			dprintf(LOG_ERR, "%s"
2091			    "memory allocation failed for SIP options", FNAME);
2092			goto fail;
2093		}
2094		in6 = (struct in6_addr *)tmpbuf;
2095		for (d = TAILQ_FIRST(&optinfo->sip_list); d;
2096		     d = TAILQ_NEXT(d, link), in6++) {
2097			memcpy(in6, &d->val_addr6, sizeof(*in6));
2098		}
2099		COPY_OPTION(DH6OPT_SIP_SERVERS, optlen, tmpbuf, p);
2100		free(tmpbuf);
2101	}
2102	if (!TAILQ_EMPTY(&optinfo->ntp_list)) {
2103		struct in6_addr *in6;
2104		struct dhcp6_listval *d;
2105
2106		tmpbuf = NULL;
2107		optlen = dhcp6_count_list(&optinfo->ntp_list) *
2108			sizeof(struct in6_addr);
2109		if ((tmpbuf = malloc(optlen)) == NULL) {
2110			dprintf(LOG_ERR, "%s"
2111			    "memory allocation failed for NTP options", FNAME);
2112			goto fail;
2113		}
2114		in6 = (struct in6_addr *)tmpbuf;
2115		for (d = TAILQ_FIRST(&optinfo->ntp_list); d;
2116		     d = TAILQ_NEXT(d, link), in6++) {
2117			memcpy(in6, &d->val_addr6, sizeof(*in6));
2118		}
2119		COPY_OPTION(DH6OPT_NTP_SERVERS, optlen, tmpbuf, p);
2120		free(tmpbuf);
2121	}
2122    /* Foxconn added end pling 01/25/2010 */
2123	/*
2124	if (optinfo->dns_list.domainlist != NULL) {
2125		struct domain_list *dlist;
2126		u_char *dst;
2127		optlen = 0;
2128		tmpbuf = NULL;
2129		if ((tmpbuf = malloc(MAXDNAME * MAXDN)) == NULL) {
2130			dprintf(LOG_ERR, "%s"
2131			    "memory allocation failed for DNS options", FNAME);
2132			goto fail;
2133		}
2134		dst = tmpbuf;
2135printf("run here\n\n\n");
2136		for (dlist = optinfo->dns_list.domainlist; dlist; dlist = dlist->next) {
2137			int n=0;
2138			n = dn_comp(dlist->name, dst, MAXDNAME, NULL, NULL);
2139			if (n < 0) {
2140				dprintf(LOG_ERR, "%s" "compress domain name failed", FNAME);
2141				goto fail;
2142			} else
2143				dprintf(LOG_DEBUG, "compress domain name %s", dlist->name);
2144			optlen += n ;
2145			dst += n;
2146		}
2147		COPY_OPTION(DH6OPT_DOMAIN_LIST, optlen, tmpbuf, p);
2148		free(tmpbuf);
2149	}
2150	*/
2151
2152
2153	return (len);
2154
2155  fail:
2156	if (tmpbuf)
2157		free(tmpbuf);
2158	return (-1);
2159}
2160#undef COPY_OPTION
2161
2162void
2163dhcp6_set_timeoparam(ev)
2164	struct dhcp6_event *ev;
2165{
2166	ev->retrans = 0;
2167	ev->init_retrans = 0;
2168	ev->max_retrans_cnt = 0;
2169	ev->max_retrans_dur = 0;
2170	ev->max_retrans_time = 0;
2171
2172	switch(ev->state) {
2173	case DHCP6S_SOLICIT:
2174		ev->init_retrans = SOL_TIMEOUT;
2175		ev->max_retrans_time = SOL_MAX_RT;
2176		break;
2177	case DHCP6S_INFOREQ:
2178		ev->init_retrans = INF_TIMEOUT;
2179		ev->max_retrans_time = INF_MAX_RT;
2180		break;
2181	case DHCP6S_REQUEST:
2182		ev->init_retrans = REQ_TIMEOUT;
2183		ev->max_retrans_time = REQ_MAX_RT;
2184		ev->max_retrans_cnt = REQ_MAX_RC;
2185		break;
2186	case DHCP6S_RENEW:
2187		ev->init_retrans = REN_TIMEOUT;
2188		ev->max_retrans_time = REN_MAX_RT;
2189		break;
2190	case DHCP6S_REBIND:
2191		ev->init_retrans = REB_TIMEOUT;
2192		ev->max_retrans_time = REB_MAX_RT;
2193		break;
2194        case DHCP6S_DECLINE:
2195                ev->init_retrans = DEC_TIMEOUT;
2196                ev->max_retrans_cnt = DEC_MAX_RC;
2197                break;
2198        case DHCP6S_RELEASE:
2199                ev->init_retrans = REL_TIMEOUT;
2200                ev->max_retrans_cnt = REL_MAX_RC;
2201                break;
2202        case DHCP6S_CONFIRM:
2203                ev->init_retrans = CNF_TIMEOUT;
2204                ev->max_retrans_dur = CNF_MAX_RD;
2205                ev->max_retrans_time = CNF_MAX_RT;
2206		break;
2207	default:
2208		dprintf(LOG_INFO, "%s" "unexpected event state %d on %s",
2209		    FNAME, ev->state, ev->ifp->ifname);
2210		exit(1);
2211	}
2212}
2213
2214void
2215dhcp6_reset_timer(ev)
2216	struct dhcp6_event *ev;
2217{
2218	double n, r;
2219	char *statestr;
2220	struct timeval interval;
2221
2222	switch(ev->state) {
2223	case DHCP6S_INIT:
2224		/*
2225		 * The first Solicit message from the client on the interface
2226		 * MUST be delayed by a random amount of time between
2227		 * MIN_SOL_DELAY and MAX_SOL_DELAY.
2228		 * [dhcpv6-28 14.]
2229		 */
2230        /* Foxconn modified start pling 08/26/2009 */
2231        /* In IPv6 auto mode (when DHCIFF_SOLICIT_ONLY is set),
2232         * send immediately.
2233         */
2234        if ((ev->ifp->send_flags & DHCIFF_SOLICIT_ONLY))
2235            ev->retrans = 0;
2236        else
2237		    ev->retrans = (random() % (MAX_SOL_DELAY - MIN_SOL_DELAY)) +
2238			    MIN_SOL_DELAY;
2239        /* Foxconn modified end pling 08/26/2009 */
2240		break;
2241	default:
2242		if (ev->timeouts == 0) {
2243			/*
2244			 * The first RT MUST be selected to be strictly
2245			 * greater than IRT by choosing RAND to be strictly
2246			 * greater than 0.
2247			 * [dhcpv6-28 14.]
2248			 */
2249			r = (double)((random() % 1000) + 1) / 10000;
2250			n = ev->init_retrans + r * ev->init_retrans;
2251		} else {
2252			r = (double)((random() % 2000) - 1000) / 10000;
2253
2254			if (ev->timeouts == 0) {
2255				n = ev->init_retrans + r * ev->init_retrans;
2256			} else
2257				n = 2 * ev->retrans + r * ev->retrans;
2258		}
2259		if (ev->max_retrans_time && n > ev->max_retrans_time)
2260			n = ev->max_retrans_time + r * ev->max_retrans_time;
2261        /* Foxconn modified start pling 08/26/2009 */
2262        /* In IPv6 auto mode (when DHCIFF_SOLICIT_ONLY is set),
2263         * then send 1 DHCP Solicit every 1 sec.
2264         */
2265        if ((ev->ifp->send_flags & DHCIFF_SOLICIT_ONLY))
2266            ev->retrans = 1000;
2267        else
2268    		ev->retrans = (long)n;
2269        /* Foxconn modified end pling 08/26/2009 */
2270		break;
2271	}
2272
2273	switch(ev->state) {
2274	case DHCP6S_INIT:
2275		statestr = "INIT";
2276		break;
2277	case DHCP6S_SOLICIT:
2278		statestr = "SOLICIT";
2279		break;
2280	case DHCP6S_INFOREQ:
2281		statestr = "INFOREQ";
2282		break;
2283	case DHCP6S_REQUEST:
2284		statestr = "REQUEST";
2285		break;
2286	case DHCP6S_RENEW:
2287		statestr = "RENEW";
2288		break;
2289	case DHCP6S_REBIND:
2290		statestr = "REBIND";
2291		break;
2292	case DHCP6S_CONFIRM:
2293		statestr = "CONFIRM";
2294		break;
2295	case DHCP6S_DECLINE:
2296		statestr = "DECLINE";
2297		break;
2298	case DHCP6S_RELEASE:
2299		statestr = "RELEASE";
2300		break;
2301	case DHCP6S_IDLE:
2302		statestr = "IDLE";
2303		break;
2304	default:
2305		statestr = "???";
2306		break;
2307	}
2308
2309	interval.tv_sec = (ev->retrans * 1000) / 1000000;
2310	interval.tv_usec = (ev->retrans * 1000) % 1000000;
2311	dhcp6_set_timer(&interval, ev->timer);
2312
2313	dprintf(LOG_DEBUG, "%s" "reset a timer on %s, "
2314		"state=%s, timeo=%d, retrans=%ld", FNAME,
2315		ev->ifp->ifname, statestr, ev->timeouts, (long) ev->retrans);
2316}
2317
2318int
2319duidcpy(struct duid *dd, const struct duid *ds)
2320{
2321	dd->duid_len = ds->duid_len;
2322	if ((dd->duid_id = malloc(dd->duid_len)) == NULL) {
2323		dprintf(LOG_ERR, "%s" "len %d memory allocation failed", FNAME, dd->duid_len);
2324		return (-1);
2325	}
2326	memcpy(dd->duid_id, ds->duid_id, dd->duid_len);
2327
2328	return (0);
2329}
2330
2331int
2332duidcmp(const struct duid *d1,
2333	const struct duid *d2)
2334{
2335	if (d1->duid_len == d2->duid_len) {
2336		return (memcmp(d1->duid_id, d2->duid_id, d1->duid_len));
2337	} else
2338		return (-1);
2339}
2340
2341void
2342duidfree(duid)
2343	struct duid *duid;
2344{
2345	dprintf(LOG_DEBUG, "%s" "DUID is %s, DUID_LEN is %d",
2346			FNAME, duidstr(duid), duid->duid_len);
2347	if (duid->duid_id != NULL && duid->duid_len != 0) {
2348		dprintf(LOG_DEBUG, "%s" "removing ID (ID: %s)",
2349		    FNAME, duidstr(duid));
2350		free(duid->duid_id);
2351		duid->duid_id = NULL;
2352		duid->duid_len = 0;
2353	}
2354	duid->duid_len = 0;
2355}
2356
2357char *
2358dhcp6optstr(type)
2359	int type;
2360{
2361	static char genstr[sizeof("opt_65535") + 1];
2362
2363	if (type > 65535)
2364		return "INVALID option";
2365
2366	switch(type) {
2367	case DH6OPT_CLIENTID:
2368		return "client ID";
2369	case DH6OPT_SERVERID:
2370		return "server ID";
2371	case DH6OPT_ORO:
2372		return "option request";
2373	case DH6OPT_PREFERENCE:
2374		return "preference";
2375	case DH6OPT_STATUS_CODE:
2376		return "status code";
2377	case DH6OPT_RAPID_COMMIT:
2378		return "rapid commit";
2379	case DH6OPT_DNS_SERVERS:
2380		return "DNS_SERVERS";
2381    /* Foxconn added start pling 09/23/2010 */
2382    case DH6OPT_DOMAIN_LIST:
2383        return "DOMAIN_LIST";
2384    /* Foxconn added end pling 09/23/2010 */
2385    /* Foxconn added start pling 01/25/2010 */
2386	case DH6OPT_SIP_SERVERS:
2387		return "SIP_SERVERS";
2388	case DH6OPT_NTP_SERVERS:
2389		return "NTP_SERVERS";
2390    /* Foxconn added end pling 01/25/2010 */
2391	default:
2392		sprintf(genstr, "opt_%d", type);
2393		return (genstr);
2394	}
2395}
2396
2397char *
2398dhcp6msgstr(type)
2399	int type;
2400{
2401	static char genstr[sizeof("msg255") + 1];
2402
2403	if (type > 255)
2404		return "INVALID msg";
2405
2406	switch(type) {
2407	case DH6_SOLICIT:
2408		return "solicit";
2409	case DH6_ADVERTISE:
2410		return "advertise";
2411	case DH6_RENEW:
2412		return "renew";
2413	case DH6_REBIND:
2414		return "rebind";
2415	case DH6_REQUEST:
2416		return "request";
2417	case DH6_REPLY:
2418		return "reply";
2419	case DH6_CONFIRM:
2420		return "confirm";
2421	case DH6_RELEASE:
2422		return "release";
2423	case DH6_DECLINE:
2424		return "decline";
2425	case DH6_INFORM_REQ:
2426		return "information request";
2427	case DH6_RECONFIGURE:
2428		return "reconfigure";
2429	case DH6_RELAY_FORW:
2430		return "relay forwarding";
2431	case DH6_RELAY_REPL:
2432		return "relay reply";
2433	default:
2434		sprintf(genstr, "msg%d", type);
2435		return (genstr);
2436	}
2437}
2438
2439char *
2440dhcp6_stcodestr(code)
2441	int code;
2442{
2443	static char genstr[sizeof("code255") + 1];
2444
2445	if (code > 255)
2446		return "INVALID code";
2447
2448	switch(code) {
2449	case DH6OPT_STCODE_SUCCESS:
2450		return "success";
2451	case DH6OPT_STCODE_UNSPECFAIL:
2452		return "unspec failure";
2453	case DH6OPT_STCODE_AUTHFAILED:
2454		return "auth fail";
2455	case DH6OPT_STCODE_ADDRUNAVAIL:
2456		return "address unavailable";
2457	case DH6OPT_STCODE_NOADDRAVAIL:
2458		return "no addresses";
2459	case DH6OPT_STCODE_NOBINDING:
2460		return "no binding";
2461	case DH6OPT_STCODE_CONFNOMATCH:
2462		return "confirm no match";
2463	case DH6OPT_STCODE_NOTONLINK:
2464		return "not on-link";
2465	case DH6OPT_STCODE_USEMULTICAST:
2466		return "use multicast";
2467	default:
2468		sprintf(genstr, "code%d", code);
2469		return (genstr);
2470	}
2471}
2472
2473char *
2474duidstr(const struct duid *duid)
2475{
2476	int i;
2477	char *cp;
2478	static char duidstr[sizeof("xx:") * 256 + sizeof("...")];
2479
2480	duidstr[0] ='\0';
2481
2482	cp = duidstr;
2483	for (i = 0; i < duid->duid_len && i <= 256; i++) {
2484		cp += sprintf(cp, "%s%02x", i == 0 ? "" : ":",
2485			      duid->duid_id[i] & 0xff);
2486	}
2487	if (i < duid->duid_len)
2488		sprintf(cp, "%s", "...");
2489
2490	return (duidstr);
2491}
2492
2493void
2494setloglevel(debuglevel)
2495	int debuglevel;
2496{
2497	if (foreground) {
2498		switch(debuglevel) {
2499		case 0:
2500			debug_thresh = LOG_ERR;
2501			break;
2502		case 1:
2503			debug_thresh = LOG_INFO;
2504			break;
2505		default:
2506			debug_thresh = LOG_DEBUG;
2507			break;
2508		}
2509	} else {
2510		switch(debuglevel) {
2511		case 0:
2512			setlogmask(LOG_UPTO(LOG_ERR));
2513			break;
2514		case 1:
2515			setlogmask(LOG_UPTO(LOG_INFO));
2516			break;
2517		}
2518	}
2519}
2520
2521void
2522dprintf(int level, const char *fmt, ...)
2523{
2524	va_list ap;
2525	char logbuf[LINE_MAX];
2526
2527	va_start(ap, fmt);
2528	vsnprintf(logbuf, sizeof(logbuf), fmt, ap);
2529
2530	if (foreground && debug_thresh >= level) {
2531		time_t now;
2532		struct tm *tm_now;
2533		const char *month[] = {
2534			"Jan", "Feb", "Mar", "Apr", "May", "Jun",
2535			"Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
2536		};
2537
2538		if ((now = time(NULL)) < 0)
2539			exit(1);
2540		tm_now = localtime(&now);
2541		fprintf(stderr, "%3s/%02d/%04d %02d:%02d:%02d %s\n",
2542			month[tm_now->tm_mon], tm_now->tm_mday,
2543			tm_now->tm_year + 1900,
2544			tm_now->tm_hour, tm_now->tm_min, tm_now->tm_sec,
2545			logbuf);
2546	} else
2547		syslog(level, "%s", logbuf);
2548}
2549