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 *hwtypep = ARPHRD_PPP; 868 l = 0; 869 return l; 870 default: 871 dprintf(LOG_INFO, "dhcpv6 doesn't support hardware type %d", 872 if_hwaddr.ifr_hwaddr.sa_family); 873 return -1; 874 } 875 memcpy(buf, if_hwaddr.ifr_hwaddr.sa_data, l); 876 dprintf(LOG_DEBUG, "%s found an interface %s hardware %p", 877 FNAME, ifname, buf); 878 return l; 879} 880 881void 882dhcp6_init_options(optinfo) 883 struct dhcp6_optinfo *optinfo; 884{ 885 memset(optinfo, 0, sizeof(*optinfo)); 886 /* for safety */ 887 optinfo->clientID.duid_id = NULL; 888 optinfo->serverID.duid_id = NULL; 889 optinfo->pref = DH6OPT_PREF_UNDEF; 890 TAILQ_INIT(&optinfo->addr_list); 891 /* Foxconn added start pling 09/23/2009 */ 892 TAILQ_INIT(&optinfo->prefix_list); 893 /* Foxconn added end pling 09/23/2009 */ 894 TAILQ_INIT(&optinfo->reqopt_list); 895 TAILQ_INIT(&optinfo->stcode_list); 896 TAILQ_INIT(&optinfo->dns_list.addrlist); 897 /* Foxconn added start pling 01/25/2010 */ 898 TAILQ_INIT(&optinfo->sip_list); 899 TAILQ_INIT(&optinfo->ntp_list); 900 /* Foxconn added end pling 01/25/2010 */ 901 TAILQ_INIT(&optinfo->relay_list); 902 optinfo->dns_list.domainlist = NULL; 903} 904 905void 906dhcp6_clear_options(optinfo) 907 struct dhcp6_optinfo *optinfo; 908{ 909 struct domain_list *dlist, *dlist_next; 910 duidfree(&optinfo->clientID); 911 duidfree(&optinfo->serverID); 912 913 dhcp6_clear_list(&optinfo->addr_list); 914 /* Foxconn added start pling 09/23/2009 */ 915 dhcp6_clear_list(&optinfo->prefix_list); 916 /* Foxconn added end pling 09/23/2009 */ 917 dhcp6_clear_list(&optinfo->reqopt_list); 918 dhcp6_clear_list(&optinfo->stcode_list); 919 dhcp6_clear_list(&optinfo->dns_list.addrlist); 920 relayfree(&optinfo->relay_list); 921 if (dhcp6_mode == DHCP6_MODE_CLIENT) { 922 for (dlist = optinfo->dns_list.domainlist; dlist; dlist = dlist_next) { 923 dlist_next = dlist->next; 924 free(dlist); 925 } 926 } 927 optinfo->dns_list.domainlist = NULL; 928 dhcp6_init_options(optinfo); 929} 930 931int 932dhcp6_copy_options(dst, src) 933 struct dhcp6_optinfo *dst, *src; 934{ 935 if (duidcpy(&dst->clientID, &src->clientID)) 936 goto fail; 937 if (duidcpy(&dst->serverID, &src->serverID)) 938 goto fail; 939 dst->flags = src->flags; 940 941 if (dhcp6_copy_list(&dst->addr_list, &src->addr_list)) 942 goto fail; 943 /* Foxconn added start pling 09/23/2009 */ 944 if (dhcp6_copy_list(&dst->prefix_list, &src->prefix_list)) 945 goto fail; 946 /* Foxconn added end pling 09/23/2009 */ 947 if (dhcp6_copy_list(&dst->reqopt_list, &src->reqopt_list)) 948 goto fail; 949 if (dhcp6_copy_list(&dst->stcode_list, &src->stcode_list)) 950 goto fail; 951 if (dhcp6_copy_list(&dst->dns_list.addrlist, &src->dns_list.addrlist)) 952 goto fail; 953 memcpy(&dst->server_addr, &src->server_addr, sizeof(dst->server_addr)); 954 dst->pref = src->pref; 955 956 return 0; 957 958 fail: 959 /* cleanup temporary resources */ 960 dhcp6_clear_options(dst); 961 return -1; 962} 963 964/* Foxconn added start pling 10/04/2010 */ 965/* Add two extra arguments for DHCP client to use. 966 * These two args are ignored in DHCP server mode (currently) 967 */ 968#if 0 969int 970dhcp6_get_options(p, ep, optinfo) 971 struct dhcp6opt *p, *ep; 972 struct dhcp6_optinfo *optinfo; 973#endif 974int 975dhcp6_get_options(p, ep, optinfo, msgtype, state, send_flags) 976 struct dhcp6opt *p, *ep; 977 struct dhcp6_optinfo *optinfo; 978 int msgtype, state, send_flags; 979/* Foxconn added end pling 10/04/2010 */ 980{ 981 struct dhcp6opt *np, opth; 982 int i, opt, optlen, reqopts, num; 983 char *cp, *val; 984 u_int16_t val16; 985 986 /* Foxconn added start pling 09/24/2009 */ 987 int has_iana = 0; 988 int has_iapd = 0; 989 /* Foxconn added end pling 09/24/2009 */ 990 /* Foxconn added start pling 10/04/2010 */ 991 int has_dns = 0; 992 int has_ntp = 0; 993 int has_sip = 0; 994 /* Foxconn added end pling 10/04/2010 */ 995 /* Foxconn added start pling 01/25/2010 */ 996 char buf[1204]; 997 char tmp_buf[1024]; 998 char command[1024]; 999 /* Foxconn added end pling 01/25/2010 */ 1000 int type_set = 0; // pling added 10/22/2010 1001 1002 for (; p + 1 <= ep; p = np) { 1003 struct duid duid0; 1004 1005 memcpy(&opth, p, sizeof(opth)); 1006 optlen = ntohs(opth.dh6opt_len); 1007 opt = ntohs(opth.dh6opt_type); 1008 1009 cp = (char *)(p + 1); 1010 np = (struct dhcp6opt *)(cp + optlen); 1011 1012 dprintf(LOG_DEBUG, "%s" "get DHCP option %s, len %d", 1013 FNAME, dhcp6optstr(opt), optlen); 1014 1015 /* option length field overrun */ 1016 if (np > ep) { 1017 dprintf(LOG_INFO, 1018 "%s" "malformed DHCP options", FNAME); 1019 return -1; 1020 } 1021 1022 switch (opt) { 1023 case DH6OPT_CLIENTID: 1024 if (optlen == 0) 1025 goto malformed; 1026 duid0.duid_len = optlen; 1027 duid0.duid_id = cp; 1028 dprintf(LOG_DEBUG, " DUID: %s", duidstr(&duid0)); 1029 if (duidcpy(&optinfo->clientID, &duid0)) { 1030 dprintf(LOG_ERR, "%s" "failed to copy DUID", 1031 FNAME); 1032 goto fail; 1033 } 1034 break; 1035 case DH6OPT_SERVERID: 1036 if (optlen == 0) 1037 goto malformed; 1038 duid0.duid_len = optlen; 1039 duid0.duid_id = cp; 1040 dprintf(LOG_DEBUG, " DUID: %s", duidstr(&duid0)); 1041 if (duidcpy(&optinfo->serverID, &duid0)) { 1042 dprintf(LOG_ERR, "%s" "failed to copy DUID", 1043 FNAME); 1044 goto fail; 1045 } 1046 break; 1047 case DH6OPT_ELAPSED_TIME: 1048 if (optlen != sizeof(u_int16_t)) 1049 goto malformed; 1050 memcpy(&val16, cp, sizeof(val16)); 1051 num = ntohs(val16); 1052 dprintf(LOG_DEBUG, " this message elapsed time is: %d", 1053 num); 1054 break; 1055 case DH6OPT_STATUS_CODE: 1056 if (optlen < sizeof(u_int16_t)) 1057 goto malformed; 1058 memcpy(&val16, cp, sizeof(val16)); 1059 num = ntohs(val16); 1060 dprintf(LOG_DEBUG, " this message status code: %s", 1061 dhcp6_stcodestr(num)); 1062 1063 1064 /* need to check duplication? */ 1065 1066 if (dhcp6_add_listval(&optinfo->stcode_list, 1067 &num, DHCP6_LISTVAL_NUM) == NULL) { 1068 dprintf(LOG_ERR, "%s" "failed to copy " 1069 "status code", FNAME); 1070 goto fail; 1071 } 1072 1073 break; 1074 case DH6OPT_ORO: 1075 if ((optlen % 2) != 0 || optlen == 0) 1076 goto malformed; 1077 reqopts = optlen / 2; 1078 for (i = 0, val = cp; i < reqopts; 1079 i++, val += sizeof(u_int16_t)) { 1080 u_int16_t opttype; 1081 1082 memcpy(&opttype, val, sizeof(u_int16_t)); 1083 num = ntohs(opttype); 1084 1085 dprintf(LOG_DEBUG, " requested option: %s", 1086 dhcp6optstr(num)); 1087 1088 if (dhcp6_find_listval(&optinfo->reqopt_list, 1089 &num, DHCP6_LISTVAL_NUM)) { 1090 dprintf(LOG_INFO, "%s" "duplicated " 1091 "option type (%s)", FNAME, 1092 dhcp6optstr(opttype)); 1093 goto nextoption; 1094 } 1095 1096 if (dhcp6_add_listval(&optinfo->reqopt_list, 1097 &num, DHCP6_LISTVAL_NUM) == NULL) { 1098 dprintf(LOG_ERR, "%s" "failed to copy " 1099 "requested option", FNAME); 1100 goto fail; 1101 } 1102 nextoption: ; 1103 } 1104 break; 1105 case DH6OPT_PREFERENCE: 1106 if (optlen != 1) 1107 goto malformed; 1108 optinfo->pref = (u_int8_t)*(u_char *)cp; 1109 dprintf(LOG_DEBUG, "%s" "get option preferrence is %2x", 1110 FNAME, optinfo->pref); 1111 break; 1112 case DH6OPT_RAPID_COMMIT: 1113 if (optlen != 0) 1114 goto malformed; 1115 optinfo->flags |= DHCIFF_RAPID_COMMIT; 1116 break; 1117 case DH6OPT_UNICAST: 1118 if (optlen != sizeof(struct in6_addr) 1119 && dhcp6_mode != DHCP6_MODE_CLIENT) 1120 goto malformed; 1121 optinfo->flags |= DHCIFF_UNICAST; 1122 memcpy(&optinfo->server_addr, 1123 (struct in6_addr *)cp, sizeof(struct in6_addr)); 1124 break; 1125 case DH6OPT_IA_TA: 1126 if (optlen < sizeof(u_int32_t)) 1127 goto malformed; 1128 /* check iaid */ 1129 optinfo->flags |= DHCIFF_TEMP_ADDRS; 1130 optinfo->type = IATA; 1131 dprintf(LOG_DEBUG, "%s" "get option iaid is %u", 1132 FNAME, optinfo->iaidinfo.iaid); 1133 optinfo->iaidinfo.iaid = ntohl(*(u_int32_t *)cp); 1134 if (get_assigned_ipv6addrs(cp + 4, cp + optlen, optinfo)) 1135 goto fail; 1136 break; 1137 case DH6OPT_IA_NA: 1138 case DH6OPT_IA_PD: 1139 /* Foxconn modified start pling 09/23/2009 */ 1140 if (dhcp6_mode == DHCP6_MODE_SERVER || 1141 (dhcp6_mode == DHCP6_MODE_CLIENT && (send_flags & DHCIFF_SOLICIT_ONLY)) || 1142 (dhcp6_mode == DHCP6_MODE_CLIENT && (dhcp6c_flags & DHCIFF_IAPD_ONLY))) { 1143 /* pling modified start 10/22/2010 */ 1144 /* For each packet, we set to one type only (IANA/IAPD) 1145 * but not both. 1146 */ 1147 if (opt == DH6OPT_IA_NA && !type_set) 1148 { 1149 optinfo->type = IANA; 1150 type_set = 1; 1151 } 1152 else if (opt == DH6OPT_IA_PD && !type_set) 1153 { 1154 optinfo->type = IAPD; 1155 type_set = 1; 1156 } 1157 /* pling modified end 10/22/2010 */ 1158 } else { 1159 /* don't set optinfo->type to IAPD as this version 1160 * of dhcp6c can't handle IANA and IAPD concurrently. 1161 */ 1162 if (opt == DH6OPT_IA_NA) 1163 optinfo->type = IANA; 1164 } 1165 /* Foxconn modified end pling 09/23/2009 */ 1166 /* check iaid */ 1167 if (optlen < sizeof(struct dhcp6_iaid_info)) 1168 goto malformed; 1169 if (dhcp6_mode == DHCP6_MODE_CLIENT && opt == DH6OPT_IA_PD) 1170 ;// If this is IAPD, don't modify the IAID 1171 else 1172 optinfo->iaidinfo.iaid = ntohl(*(u_int32_t *)cp); 1173 optinfo->iaidinfo.renewtime = 1174 ntohl(*(u_int32_t *)(cp + sizeof(u_int32_t))); 1175 optinfo->iaidinfo.rebindtime = 1176 ntohl(*(u_int32_t *)(cp + 2 * sizeof(u_int32_t))); 1177 dprintf(LOG_DEBUG, "get option iaid is %u, renewtime %u, " 1178 "rebindtime %u", optinfo->iaidinfo.iaid, 1179 optinfo->iaidinfo.renewtime, optinfo->iaidinfo.rebindtime); 1180 /* Foxconn added start pling 10/07/2010 */ 1181 /* DHCPv6 client readylogo: 1182 * Ignore IA with T1 > T2 */ 1183 if (optinfo->iaidinfo.renewtime > optinfo->iaidinfo.rebindtime) 1184 goto fail; 1185 /* Foxconn added end pling 10/07/2010 */ 1186 if (get_assigned_ipv6addrs(cp + 3 * sizeof(u_int32_t), 1187 cp + optlen, optinfo)) 1188 goto fail; 1189 1190 /* Foxconn added start pling 09/24/2009 */ 1191 if (dhcp6_mode == DHCP6_MODE_CLIENT) { 1192 if (opt == DH6OPT_IA_NA) 1193 has_iana = 1; 1194 else 1195 has_iapd = 1; 1196 } 1197 /* Foxconn added end pling 09/24/2009 */ 1198 break; 1199 case DH6OPT_DNS_SERVERS: 1200 if (optlen % sizeof(struct in6_addr) || optlen == 0) 1201 goto malformed; 1202 for (val = cp; val < cp + optlen; 1203 val += sizeof(struct in6_addr)) { 1204 if (dhcp6_find_listval(&optinfo->dns_list.addrlist, 1205 val, DHCP6_LISTVAL_ADDR6)) { 1206 dprintf(LOG_INFO, "%s" "duplicated " 1207 "DNS address (%s)", FNAME, 1208 in6addr2str((struct in6_addr *)val, 1209 0)); 1210 goto nextdns; 1211 } 1212 1213 if (dhcp6_add_listval(&optinfo->dns_list.addrlist, 1214 val, DHCP6_LISTVAL_ADDR6) == NULL) { 1215 dprintf(LOG_ERR, "%s" "failed to copy " 1216 "DNS address", FNAME); 1217 goto fail; 1218 } 1219 nextdns: ; 1220 } 1221 /* Foxconn added start pling 10/04/2010 */ 1222 if (dhcp6_mode == DHCP6_MODE_CLIENT) 1223 has_dns = 1; 1224 /* Foxconn added end pling 10/04/2010 */ 1225 break; 1226 1227 /* Foxconn added start pling 01/25/2010 */ 1228 case DH6OPT_SIP_SERVERS: 1229 memset(buf, 0, sizeof(buf)); 1230 memset(tmp_buf, 0, sizeof(tmp_buf)); 1231 if (optlen % sizeof(struct in6_addr) || optlen == 0) 1232 goto malformed; 1233 for (val = cp; val < cp + optlen; 1234 val += sizeof(struct in6_addr)) { 1235 if (dhcp6_find_listval(&optinfo->sip_list, 1236 val, DHCP6_LISTVAL_ADDR6)) { 1237 dprintf(LOG_INFO, "%s" "duplicated " 1238 "SIP address (%s)", FNAME, 1239 in6addr2str((struct in6_addr *)val, 1240 0)); 1241 goto nextsip; 1242 } 1243 1244 if (dhcp6_add_listval(&optinfo->sip_list, 1245 val, DHCP6_LISTVAL_ADDR6) == NULL) { 1246 dprintf(LOG_ERR, "%s" "failed to copy " 1247 "SIP address", FNAME); 1248 goto fail; 1249 } 1250 /* Save SIP server to NVRAM */ 1251 sprintf(tmp_buf, "%s ", in6addr2str((struct in6_addr *)val, 0)); 1252 strcat(buf, tmp_buf); 1253 nextsip: ; 1254 } 1255 /* Save SIP server to NVRAM */ 1256 if (dhcp6_mode == DHCP6_MODE_CLIENT && strlen(buf)) { 1257 sprintf(command, "nvram set ipv6_sip_servers=\"%s\"", buf); 1258 system(command); 1259 has_sip = 1; // Foxconn added pling 10/04/2010 1260 } 1261 break; 1262 case DH6OPT_NTP_SERVERS: 1263 memset(buf, 0, sizeof(buf)); 1264 memset(tmp_buf, 0, sizeof(tmp_buf)); 1265 if (optlen % sizeof(struct in6_addr) || optlen == 0) 1266 goto malformed; 1267 for (val = cp; val < cp + optlen; 1268 val += sizeof(struct in6_addr)) { 1269 if (dhcp6_find_listval(&optinfo->ntp_list, 1270 val, DHCP6_LISTVAL_ADDR6)) { 1271 dprintf(LOG_INFO, "%s" "duplicated " 1272 "NTP address (%s)", FNAME, 1273 in6addr2str((struct in6_addr *)val, 1274 0)); 1275 goto nextntp; 1276 } 1277 1278 if (dhcp6_add_listval(&optinfo->ntp_list, 1279 val, DHCP6_LISTVAL_ADDR6) == NULL) { 1280 dprintf(LOG_ERR, "%s" "failed to copy " 1281 "NTP address", FNAME); 1282 goto fail; 1283 } 1284 /* Save SIP server to NVRAM */ 1285 sprintf(tmp_buf, "%s ", in6addr2str((struct in6_addr *)val, 0)); 1286 strcat(buf, tmp_buf); 1287 nextntp: ; 1288 } 1289 /* Save NTP server to NVRAM */ 1290 if (dhcp6_mode == DHCP6_MODE_CLIENT && strlen(buf)) { 1291 sprintf(command, "nvram set ipv6_ntp_servers=\"%s\"", buf); 1292 system(command); 1293 has_ntp = 1; // Foxconn added pling 10/04/2010 1294 } 1295 break; 1296 /* Foxconn added end pling 01/25/2010 */ 1297 1298 case DH6OPT_DOMAIN_LIST: 1299 if (optlen == 0) 1300 goto malformed; 1301 /* dependency on lib resolv */ 1302 for (val = cp; val < cp + optlen;) { 1303 int n; 1304 struct domain_list *dname, *dlist; 1305 dname = malloc(sizeof(*dname)); 1306 if (dname == NULL) { 1307 dprintf(LOG_ERR, "%s" "failed to allocate memory", 1308 FNAME); 1309 goto fail; 1310 } 1311 n = dn_expand(cp, cp + optlen, val, dname->name, MAXDNAME); 1312 if (n < 0) 1313 goto malformed; 1314 else { 1315 val += n; 1316 dprintf(LOG_DEBUG, "expand domain name %s, size %d", 1317 dname->name, strlen(dname->name)); 1318 } 1319 dname->next = NULL; 1320 if (optinfo->dns_list.domainlist == NULL) { 1321 optinfo->dns_list.domainlist = dname; 1322 } else { 1323 for (dlist = optinfo->dns_list.domainlist; dlist; 1324 dlist = dlist->next) { 1325 if (dlist->next == NULL) { 1326 dlist->next = dname; 1327 break; 1328 } 1329 } 1330 } 1331 } 1332 break; 1333 default: 1334 /* no option specific behavior */ 1335 dprintf(LOG_INFO, "%s" 1336 "unknown or unexpected DHCP6 option %s, len %d", 1337 FNAME, dhcp6optstr(opt), optlen); 1338 break; 1339 } 1340 } 1341 1342 /* Foxconn added start pling 09/24/2009 */ 1343 /* Per Netgear spec, an acceptable DHCP advertise 1344 * must have both IANA and IAPD option. 1345 */ 1346 if (dhcp6_mode == DHCP6_MODE_CLIENT) { 1347 /* Foxconn added start pling 09/21/2010 */ 1348 /* Check flag to see if we accept IANA/IAPD only 1349 * for DHCPv6 readylogo test. 1350 */ 1351 if ((dhcp6c_flags & DHCIFF_IANA_ONLY) && has_iana) 1352 { 1353 dprintf(LOG_INFO, "%s" "recv IANA. OK!", FNAME); 1354 } 1355 else 1356 if (dhcp6c_flags & DHCIFF_INFO_ONLY) 1357 { 1358 dprintf(LOG_INFO, "%s" "Info-only. OK!", FNAME); 1359 } 1360 else 1361 if ((dhcp6c_flags & DHCIFF_IAPD_ONLY) && has_iapd) 1362 { 1363 dprintf(LOG_INFO, "%s" "recv IAPD. OK!", FNAME); 1364 } 1365 else 1366 /* Foxconn added end pling 09/21/2010 */ 1367 /* Foxconn added start pling 10/04/2010 */ 1368 /* Handle DHCP messages properly in different states */ 1369 if (state == DHCP6S_INFOREQ && msgtype == DH6_REPLY && 1370 has_dns && has_ntp && has_sip) 1371 { 1372 dprintf(LOG_INFO, "%s" "valid INFOREQ/REPLY. OK!", FNAME); 1373 } 1374 else 1375 if (state == DHCP6S_DECLINE && msgtype == DH6_REPLY) 1376 { 1377 dprintf(LOG_INFO, "%s" "got REPLY to DECLINE.", FNAME); 1378 } 1379 else 1380 /* Foxconn added end pling 10/04/2010 */ 1381 /* Foxconn added start pling 09/16/2011 */ 1382 /* In auto-detect mode, we don't accept Advert pkt with IANA only. */ 1383 if ((send_flags & DHCIFF_SOLICIT_ONLY) && has_iana && !has_iapd) 1384 { 1385 dprintf(LOG_INFO, "%s" "got IANA only in auto-detect mode. NG!", FNAME); 1386 goto fail; 1387 } 1388 else 1389 /* Foxconn added end pling 09/16/2011 */ 1390 /* Foxconn added start pling 10/14/2010 */ 1391 if ((send_flags & DHCIFF_SOLICIT_ONLY) && 1392 (has_iana || has_iapd) ) 1393 { 1394 dprintf(LOG_INFO, "%s" "got IANA/IAPD in auto-detect mode", FNAME); 1395 } 1396 else 1397 /* Foxconn added end pling 10/14/2010 */ 1398 if (!has_iana || !has_iapd) { 1399 dprintf(LOG_INFO, "%s" "no IANA/IAPD", FNAME); 1400 goto fail; 1401 } 1402 } 1403 /* Foxconn added end pling 09/24/2009 */ 1404 1405 return (0); 1406 1407 malformed: 1408 dprintf(LOG_INFO, "%s" "malformed DHCP option: type %d, len %d", 1409 FNAME, opt, optlen); 1410 fail: 1411 dhcp6_clear_options(optinfo); 1412 return (-1); 1413} 1414 1415static int 1416get_assigned_ipv6addrs(p, ep, optinfo) 1417 char *p, *ep; 1418 struct dhcp6_optinfo *optinfo; 1419{ 1420 char *np, *cp; 1421 struct dhcp6opt opth; 1422 struct dhcp6_addr_info ai; 1423 struct dhcp6_prefix_info pi; 1424 struct dhcp6_addr addr6; 1425 int optlen, opt; 1426 u_int16_t val16; 1427 int num; 1428 int has_status_code = 0; /* Foxconn added pling 09/15/2011 */ 1429 1430 /* Foxconn added start pling 12/22/2011 */ 1431 char iapd_valid_lifetime_cmd_buf[1024]; 1432 char iapd_preferred_lifetime_cmd_buf[1024]; 1433 /* Foxconn added end pling 12/22/2011 */ 1434 1435 /* Foxconn modified start pling 09/15/2011 */ 1436 /* To work around IANA/IAPD without status code */ 1437 //for (; p + sizeof(struct dhcp6opt) <= ep; p = np) { 1438 for (; /*p + sizeof(struct dhcp6opt) <= ep*/; p = np) { 1439 1440 if (p + sizeof(struct dhcp6opt) > ep) 1441 { 1442 /* Foxconn added start pling 10/19/2011 */ 1443 /* for server, use original logic (break for loop) */ 1444 if (dhcp6_mode == DHCP6_MODE_SERVER) 1445 break; 1446 /* Foxconn added end pling 10/19/2011 */ 1447 1448 /* Client check status code below */ 1449 if (has_status_code) 1450 break; 1451 else { 1452 has_status_code = 1; 1453 goto no_status_code; 1454 } 1455 } 1456 /* Foxconn modified end pling 09/15/2011 */ 1457 memcpy(&opth, p, sizeof(opth)); 1458 optlen = ntohs(opth.dh6opt_len); 1459 opt = ntohs(opth.dh6opt_type); 1460 cp = p + sizeof(opth); 1461 np = cp + optlen; 1462 dprintf(LOG_DEBUG, " IA address option: %s, " 1463 "len %d", dhcp6optstr(opt), optlen); 1464 1465 if (np > ep) { 1466 dprintf(LOG_INFO, "%s" "malformed DHCP options", 1467 FNAME); 1468 return -1; 1469 } 1470 switch(opt) { 1471 case DH6OPT_STATUS_CODE: 1472 if (optlen < sizeof(val16)) 1473 goto malformed; 1474 memcpy(&val16, cp, sizeof(val16)); 1475 num = ntohs(val16); 1476 dprintf(LOG_INFO, "status code for this address is: %s", 1477 dhcp6_stcodestr(num)); 1478 if (optlen > sizeof(val16)) { 1479 dprintf(LOG_INFO, 1480 "status message for this address is: %-*s", 1481 (int)(optlen-sizeof(val16)), p+(val16)); 1482 } 1483 if (dhcp6_add_listval(&optinfo->stcode_list, 1484 &num, DHCP6_LISTVAL_NUM) == NULL) { 1485 dprintf(LOG_ERR, "%s" "failed to copy " 1486 "status code", FNAME); 1487 goto fail; 1488 } 1489 has_status_code = 1; /* Foxconn added pling 09/15/2011 */ 1490 break; 1491 case DH6OPT_IADDR: 1492 if (optlen < sizeof(ai) - sizeof(u_int32_t)) 1493 goto malformed; 1494 memcpy(&ai, p, sizeof(ai)); 1495 /* copy the information into internal format */ 1496 memset(&addr6, 0, sizeof(addr6)); 1497 memcpy(&addr6.addr, (struct in6_addr *)cp, sizeof(struct in6_addr)); 1498 addr6.preferlifetime = ntohl(ai.preferlifetime); 1499 addr6.validlifetime = ntohl(ai.validlifetime); 1500 dprintf(LOG_DEBUG, " get IAADR address information: " 1501 "%s preferlifetime %d validlifetime %d", 1502 in6addr2str(&addr6.addr, 0), 1503 addr6.preferlifetime, addr6.validlifetime); 1504 /* It shouldn't happen, since Server will do the check before 1505 * sending the data to clients */ 1506 if (addr6.preferlifetime > addr6.validlifetime) { 1507 dprintf(LOG_INFO, "preferred life time" 1508 "(%d) is greater than valid life time" 1509 "(%d)", addr6.preferlifetime, addr6.validlifetime); 1510 goto malformed; 1511 } 1512 if (optlen == sizeof(ai) - sizeof(u_int32_t)) { 1513 addr6.status_code = DH6OPT_STCODE_UNDEFINE; 1514 break; 1515 } 1516 /* address status code might be added after IADDA option */ 1517 memcpy(&opth, p + sizeof(ai), sizeof(opth)); 1518 optlen = ntohs(opth.dh6opt_len); 1519 opt = ntohs(opth.dh6opt_type); 1520 switch(opt) { 1521 case DH6OPT_STATUS_CODE: 1522 if (optlen < sizeof(val16)) 1523 goto malformed; 1524 memcpy(&val16, p + sizeof(ai) + sizeof(opth), sizeof(val16)); 1525 num = ntohs(val16); 1526 dprintf(LOG_INFO, "status code for this address is: %s", 1527 dhcp6_stcodestr(num)); 1528 addr6.status_code = num; 1529 if (optlen > sizeof(val16)) { 1530 dprintf(LOG_INFO, 1531 "status message for this address is: %-*s", 1532 (int)(optlen-sizeof(val16)), p+(val16)); 1533 } 1534 break; 1535 default: 1536 goto malformed; 1537 } 1538 break; 1539 case DH6OPT_IAPREFIX: 1540 if (optlen < sizeof(pi) - sizeof(u_int32_t)) 1541 goto malformed; 1542 memcpy(&pi, p, sizeof(pi)); 1543 /* copy the information into internal format */ 1544 memset(&addr6, 0, sizeof(addr6)); 1545 addr6.preferlifetime = ntohl(pi.preferlifetime); 1546 addr6.validlifetime = ntohl(pi.validlifetime); 1547 addr6.plen = pi.plen; 1548 memcpy(&addr6.addr, &pi.prefix, sizeof(struct in6_addr)); 1549 dprintf(LOG_DEBUG, " get IAPREFIX prefix information: " 1550 "%s/%d preferlifetime %d validlifetime %d", 1551 in6addr2str(&addr6.addr, 0), addr6.plen, 1552 addr6.preferlifetime, addr6.validlifetime); 1553 /* It shouldn't happen, since Server will do the check before 1554 * sending the data to clients */ 1555 if (addr6.preferlifetime > addr6.validlifetime) { 1556 dprintf(LOG_INFO, "preferred life time" 1557 "(%d) is greater than valid life time" 1558 "(%d)", addr6.preferlifetime, addr6.validlifetime); 1559 goto malformed; 1560 } 1561 1562 /* Foxconn added start pling 12/22/2011 */ 1563 /* WNDR4500 TD#156: Record the IAPD valid and preferred lifetime */ 1564 if (dhcp6_mode == DHCP6_MODE_CLIENT) { 1565 sprintf(iapd_valid_lifetime_cmd_buf, 1566 "nvram set RA_AdvValidLifetime_from_IAPD=%u", 1567 addr6.validlifetime); 1568 sprintf(iapd_preferred_lifetime_cmd_buf, 1569 "nvram set RA_AdvPreferredLifetime_from_IAPD=%u", 1570 addr6.preferlifetime); 1571 } 1572 /* Foxconn added end pling 12/22/2011 */ 1573 1574 if (!(dhcp6c_flags & DHCIFF_IAPD_ONLY)) 1575 addr6.type = IAPD; /* Foxconn added pling 01/25/2009 */ 1576 if (optlen == sizeof(pi) - sizeof(u_int32_t)) { 1577 addr6.status_code = DH6OPT_STCODE_UNDEFINE; 1578 break; 1579 } 1580 /* address status code might be added after IADDA option */ 1581 memcpy(&opth, p + sizeof(pi), sizeof(opth)); 1582 optlen = ntohs(opth.dh6opt_len); 1583 opt = ntohs(opth.dh6opt_type); 1584 switch(opt) { 1585 case DH6OPT_STATUS_CODE: 1586 if (optlen < sizeof(val16)) 1587 goto malformed; 1588 memcpy(&val16, p + sizeof(pi) + sizeof(opth), sizeof(val16)); 1589 num = ntohs(val16); 1590 dprintf(LOG_INFO, "status code for this prefix is: %s", 1591 dhcp6_stcodestr(num)); 1592 addr6.status_code = num; 1593 if (optlen > sizeof(val16)) { 1594 dprintf(LOG_INFO, 1595 "status message for this prefix is: %-*s", 1596 (int)(optlen-sizeof(val16)), p+(val16)); 1597 } 1598 break; 1599 default: 1600 goto malformed; 1601 } 1602 break; 1603 default: 1604 goto malformed; 1605 } 1606 1607no_status_code: /* Foxconn added start pling 09/15/2011 */ 1608 /* set up address type */ 1609 /* Foxconn added start pling 09/23/2009 */ 1610 if (addr6.type == IAPD) { 1611 /* Foxconn added start pling 01/25/2010 */ 1612 if (dhcp6_find_listval(&optinfo->prefix_list, 1613 &addr6, DHCP6_LISTVAL_DHCP6ADDR)) { 1614 dprintf(LOG_INFO, "duplicated prefix (%s/%d)", 1615 in6addr2str(&addr6.addr, 0), addr6.plen); 1616 continue; 1617 } 1618 /* Foxconn added end pling 01/25/2010 */ 1619 if (dhcp6_add_listval(&optinfo->prefix_list, &addr6, 1620 DHCP6_LISTVAL_DHCP6ADDR) == NULL) { 1621 dprintf(LOG_ERR, "%s" "failed to copy prefix", FNAME); 1622 goto fail; 1623 } 1624 } else { 1625 /* Foxconn added end pling 09/23/2009 */ 1626 addr6.type = optinfo->type; 1627 if (dhcp6_find_listval(&optinfo->addr_list, 1628 &addr6, DHCP6_LISTVAL_DHCP6ADDR)) { 1629 dprintf(LOG_INFO, "duplicated address (%s/%d)", 1630 in6addr2str(&addr6.addr, 0), addr6.plen); 1631 continue; 1632 } 1633 if (dhcp6_add_listval(&optinfo->addr_list, &addr6, 1634 DHCP6_LISTVAL_DHCP6ADDR) == NULL) { 1635 dprintf(LOG_ERR, "%s" "failed to copy an " 1636 "address", FNAME); 1637 goto fail; 1638 } 1639 /* Foxconn added start pling 09/23/2009 */ 1640 } /* if (addr6.type == IAPD) */ 1641 /* Foxconn added end pling 09/23/2009 */ 1642 } 1643 1644 /* Foxconn added start pling 12/22/2011 */ 1645 /* WNDR4500 TD#156: Set the IAPD valid and preferred lifetime 1646 * to NVRAM for acos rc to use */ 1647 if (dhcp6_mode == DHCP6_MODE_CLIENT) { 1648 system(iapd_valid_lifetime_cmd_buf); 1649 system(iapd_preferred_lifetime_cmd_buf); 1650 system("nvram set RA_use_dynamic_lifetime=1"); 1651 } 1652 /* Foxconn added end pling 12/22/2011 */ 1653 1654 return (0); 1655 1656 malformed: 1657 dprintf(LOG_INFO, 1658 " malformed IA option: type %d, len %d", 1659 opt, optlen); 1660 fail: 1661 return (-1); 1662} 1663 1664#define COPY_OPTION(t, l, v, p) do { \ 1665 if ((void *)(ep) - (void *)(p) < (l) + sizeof(struct dhcp6opt)) { \ 1666 dprintf(LOG_INFO, "%s" "option buffer short for %s", FNAME, dhcp6optstr((t))); \ 1667 goto fail; \ 1668 } \ 1669 opth.dh6opt_type = htons((t)); \ 1670 opth.dh6opt_len = htons((l)); \ 1671 memcpy((p), &opth, sizeof(opth)); \ 1672 if ((l)) \ 1673 memcpy((p) + 1, (v), (l)); \ 1674 (p) = (struct dhcp6opt *)((char *)((p) + 1) + (l)); \ 1675 (len) += sizeof(struct dhcp6opt) + (l); \ 1676 dprintf(LOG_DEBUG, "%s" "set %s", FNAME, dhcp6optstr((t))); \ 1677} while (0) 1678 1679int 1680dhcp6_set_options(bp, ep, optinfo) 1681 struct dhcp6opt *bp, *ep; 1682 struct dhcp6_optinfo *optinfo; 1683{ 1684 struct dhcp6opt *p = bp, opth; 1685 struct dhcp6_listval *stcode; 1686 int len = 0, optlen = 0; 1687 char *tmpbuf = NULL; 1688 1689 if (optinfo->clientID.duid_len) { 1690 COPY_OPTION(DH6OPT_CLIENTID, optinfo->clientID.duid_len, 1691 optinfo->clientID.duid_id, p); 1692 } 1693 1694 if (optinfo->serverID.duid_len) { 1695 COPY_OPTION(DH6OPT_SERVERID, optinfo->serverID.duid_len, 1696 optinfo->serverID.duid_id, p); 1697 } 1698 if (dhcp6_mode == DHCP6_MODE_CLIENT) 1699 { 1700 /* Foxconn modified start pling 10/01/2010 */ 1701 /* Take care of endian issue */ 1702 // COPY_OPTION(DH6OPT_ELAPSED_TIME, 2, &optinfo->elapsed_time, p); 1703 u_int16_t elapsed_time = htons(optinfo->elapsed_time); 1704 COPY_OPTION(DH6OPT_ELAPSED_TIME, 2, &elapsed_time, p); 1705 /* Foxconn modified end pling 10/01/2010 */ 1706 } 1707 1708 /* Foxconn added start pling 09/07/2010 */ 1709 /* For dhcp6c, add user-class if specified */ 1710 if (dhcp6_mode == DHCP6_MODE_CLIENT) 1711 { 1712 /* user class option in this format (RFC3315): 1713 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 1714 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 1715 | OPTION_USER_CLASS | option-len | 1716 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 1717 | user-class-data . 1718 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 1719 1720 user-class-data in this format: 1721 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-...-+-+-+-+-+-+-+ 1722 | user-class-len (2 bytes) | opaque-data | 1723 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-...-+-+-+-+-+-+-+ 1724 */ 1725 int option_len; 1726 unsigned short *user_class_len; 1727 char user_class_data[MAX_USER_CLASS_LEN+2]; 1728 1729 if (strlen(optinfo->user_class)) 1730 { 1731 option_len = strlen(optinfo->user_class) + 2; 1732 user_class_len = (unsigned short *)&user_class_data; 1733 *user_class_len = htons(strlen(optinfo->user_class)); 1734 strcpy(&user_class_data[2], optinfo->user_class); 1735 COPY_OPTION(DH6OPT_USER_CLASS, option_len, user_class_data, p); 1736 } 1737 } 1738 /* Foxconn added end pling 09/07/2010 */ 1739 1740 if (optinfo->flags & DHCIFF_RAPID_COMMIT) 1741 COPY_OPTION(DH6OPT_RAPID_COMMIT, 0, NULL, p); 1742 1743 if ((dhcp6_mode == DHCP6_MODE_SERVER) && (optinfo->flags & DHCIFF_UNICAST)) { 1744 if (!IN6_IS_ADDR_UNSPECIFIED(&optinfo->server_addr)) { 1745 COPY_OPTION(DH6OPT_UNICAST, sizeof(optinfo->server_addr), 1746 &optinfo->server_addr, p); 1747 } 1748 } 1749 switch(optinfo->type) { 1750 int buflen; 1751 char *tp; 1752 u_int32_t iaid; 1753 struct dhcp6_iaid_info opt_iana; 1754 struct dhcp6_iaid_info opt_iapd; 1755 struct dhcp6_prefix_info pi; 1756 struct dhcp6_addr_info ai; 1757 struct dhcp6_status_info status; 1758 struct dhcp6_listval *dp; 1759 case IATA: 1760 case IANA: 1761 if (optinfo->iaidinfo.iaid == 0) 1762 break; 1763 if (optinfo->type == IATA) { 1764 optlen = sizeof(iaid); 1765 dprintf(LOG_DEBUG, "%s" "set IA_TA iaid information: %d", FNAME, 1766 optinfo->iaidinfo.iaid); 1767 iaid = htonl(optinfo->iaidinfo.iaid); 1768 } else if (optinfo->type == IANA) { 1769 optlen = sizeof(opt_iana); 1770 dprintf(LOG_DEBUG, "set IA_NA iaidinfo: " 1771 "iaid %u renewtime %u rebindtime %u", 1772 optinfo->iaidinfo.iaid, optinfo->iaidinfo.renewtime, 1773 optinfo->iaidinfo.rebindtime); 1774 opt_iana.iaid = htonl(optinfo->iaidinfo.iaid); 1775 /* Foxconn modified start pling 01/25/2010 */ 1776 /* Per Netgear spec, use IAID '11' for IAPD in dhcp6c */ 1777 if (dhcp6_mode == DHCP6_MODE_CLIENT) 1778 opt_iana.iaid = htonl(IANA_IAID); 1779 /* Foxconn modified end pling 01/25/2010 */ 1780 opt_iana.renewtime = htonl(optinfo->iaidinfo.renewtime); 1781 opt_iana.rebindtime = htonl(optinfo->iaidinfo.rebindtime); 1782 } 1783 /* Foxconn modified start pling 09/24/2009 */ 1784 if (dhcp6_mode == DHCP6_MODE_SERVER || 1785 dhcp6_mode == DHCP6_MODE_CLIENT && dhcp6c_flags & DHCIFF_IAPD_ONLY) { 1786 buflen = sizeof(opt_iana) + dhcp6_count_list(&optinfo->addr_list) * 1787 (sizeof(ai) + sizeof(status)); 1788 } else { 1789 /* Client don't need to send the status code */ 1790 buflen = sizeof(opt_iana) + dhcp6_count_list(&optinfo->addr_list) * 1791 sizeof(ai); 1792 } 1793 /* Foxconn modified end pling 09/24/2009 */ 1794 tmpbuf = NULL; 1795 if ((tmpbuf = malloc(buflen)) == NULL) { 1796 dprintf(LOG_ERR, "%s" 1797 "memory allocation failed for options", FNAME); 1798 goto fail; 1799 } 1800 if (optinfo->type == IATA) 1801 memcpy(tmpbuf, &iaid, sizeof(iaid)); 1802 else 1803 memcpy(tmpbuf, &opt_iana, sizeof(opt_iana)); 1804 tp = tmpbuf + optlen; 1805 optlen += dhcp6_count_list(&optinfo->addr_list) * sizeof(ai); 1806 if (!TAILQ_EMPTY(&optinfo->addr_list)) { 1807 for (dp = TAILQ_FIRST(&optinfo->addr_list); dp; 1808 dp = TAILQ_NEXT(dp, link)) { 1809 int iaddr_len = 0; 1810 memset(&ai, 0, sizeof(ai)); 1811 ai.dh6_ai_type = htons(DH6OPT_IADDR); 1812 if (dp->val_dhcp6addr.status_code != DH6OPT_STCODE_UNDEFINE) { 1813 /* Foxconn modified start pling 09/24/2009 */ 1814 if (dhcp6_mode == DHCP6_MODE_SERVER) 1815 iaddr_len = sizeof(ai) - sizeof(u_int32_t) 1816 + sizeof(status); 1817 else 1818 iaddr_len = sizeof(ai) - sizeof(u_int32_t); 1819 } else 1820 iaddr_len = sizeof(ai) - sizeof(u_int32_t); 1821 ai.dh6_ai_len = htons(iaddr_len); 1822 ai.preferlifetime = htonl(dp->val_dhcp6addr.preferlifetime); 1823 ai.validlifetime = htonl(dp->val_dhcp6addr.validlifetime); 1824 memcpy(&ai.addr, &dp->val_dhcp6addr.addr, 1825 sizeof(ai.addr)); 1826 memcpy(tp, &ai, sizeof(ai)); 1827 tp += sizeof(ai); 1828 dprintf(LOG_DEBUG, "set IADDR address option len %d: " 1829 "%s preferlifetime %d validlifetime %d", 1830 iaddr_len, in6addr2str(&ai.addr, 0), 1831 ntohl(ai.preferlifetime), 1832 ntohl(ai.validlifetime)); 1833 /* set up address status code if any */ 1834 /* Foxconn added start pling 09/24/2009 */ 1835 /* Don't add status code in client reqeust */ 1836 if (dhcp6_mode == DHCP6_MODE_CLIENT) 1837 ; 1838 else 1839 /* Foxconn added end pling 09/24/2009 */ 1840 if (dp->val_dhcp6addr.status_code != DH6OPT_STCODE_UNDEFINE) { 1841 status.dh6_status_type = htons(DH6OPT_STATUS_CODE); 1842 status.dh6_status_len = 1843 htons(sizeof(status.dh6_status_code)); 1844 status.dh6_status_code = 1845 htons(dp->val_dhcp6addr.status_code); 1846 memcpy(tp, &status, sizeof(status)); 1847 dprintf(LOG_DEBUG, " this address status code: %s", 1848 dhcp6_stcodestr(ntohs(status.dh6_status_code))); 1849 optlen += sizeof(status); 1850 tp += sizeof(status); 1851 } 1852 } 1853 } else if (dhcp6_mode == DHCP6_MODE_SERVER) { 1854 int num; 1855 num = DH6OPT_STCODE_NOADDRAVAIL; 1856 dprintf(LOG_DEBUG, " status code: %s", 1857 dhcp6_stcodestr(num)); 1858 if (dhcp6_add_listval(&optinfo->stcode_list, 1859 &num, DHCP6_LISTVAL_NUM) == NULL) { 1860 dprintf(LOG_ERR, "%s" "failed to copy " 1861 "status code", FNAME); 1862 goto fail; 1863 } 1864 } 1865 if (optinfo->type == IATA) 1866 COPY_OPTION(DH6OPT_IA_TA, optlen, tmpbuf, p); 1867 else if (optinfo->type == IANA) 1868 COPY_OPTION(DH6OPT_IA_NA, optlen, tmpbuf, p); 1869 free(tmpbuf); 1870 /* Foxconn modified start pling 09/22/2009 */ 1871 /* Per Netgear spec, dhcp6c need to send IAPD, 1872 * so we fall through to do IAPD. 1873 */ 1874 if (dhcp6_mode == DHCP6_MODE_SERVER) 1875 break; 1876 /* Foxconn modified end pling 09/22/2009 */ 1877 /* Foxconn added start pling 10/01/2010 */ 1878 /* For DHCPv6 readylogo test, send IANA only */ 1879 if (dhcp6_mode == DHCP6_MODE_CLIENT && 1880 dhcp6c_flags & DHCIFF_IANA_ONLY) 1881 break; 1882 /* Foxconn added end pling 10/01/2010 */ 1883 case IAPD: 1884 /* Foxconn modified start pling 09/22/2009 */ 1885 /* Per Netgear spec, use IAID '11' for IAPD in dhcp6c */ 1886 if (dhcp6_mode == DHCP6_MODE_CLIENT) 1887 optinfo->iaidinfo.iaid = IAPD_IAID; 1888 /* Foxconn modified end pling 09/22/2009 */ 1889 if (optinfo->iaidinfo.iaid == 0) 1890 break; 1891 optlen = sizeof(opt_iapd); 1892 dprintf(LOG_DEBUG, "set IA_PD iaidinfo: " 1893 "iaid %u renewtime %u rebindtime %u", 1894 optinfo->iaidinfo.iaid, optinfo->iaidinfo.renewtime, 1895 optinfo->iaidinfo.rebindtime); 1896 opt_iapd.iaid = htonl(optinfo->iaidinfo.iaid); 1897 opt_iapd.renewtime = htonl(optinfo->iaidinfo.renewtime); 1898 opt_iapd.rebindtime = htonl(optinfo->iaidinfo.rebindtime); 1899 /* Foxconn modified start pling 09/23/2009 */ 1900 /* In DHCP client mode, copy the prefix, 1901 * but not include the status code 1902 */ 1903 if (dhcp6_mode == DHCP6_MODE_SERVER || 1904 dhcp6_mode == DHCP6_MODE_CLIENT && dhcp6c_flags & DHCIFF_IAPD_ONLY) 1905 buflen = sizeof(opt_iapd) + dhcp6_count_list(&optinfo->addr_list) * 1906 (sizeof(pi) + sizeof(status)); 1907 else 1908 buflen = sizeof(opt_iapd) + dhcp6_count_list(&optinfo->prefix_list) * 1909 sizeof(pi); 1910 /* Foxconn modified end pling 09/23/2009 */ 1911 tmpbuf = NULL; 1912 if ((tmpbuf = malloc(buflen)) == NULL) { 1913 dprintf(LOG_ERR, "%s" 1914 "memory allocation failed for options", FNAME); 1915 goto fail; 1916 } 1917 memcpy(tmpbuf, &opt_iapd, sizeof(opt_iapd)); 1918 tp = tmpbuf + optlen; 1919 /* Foxconn modified start pling 09/23/2009 */ 1920 /* IAPD is handle differently in server and client mode */ 1921 if (dhcp6_mode == DHCP6_MODE_SERVER || 1922 dhcp6_mode == DHCP6_MODE_CLIENT && dhcp6c_flags & DHCIFF_IAPD_ONLY) { 1923 optlen += dhcp6_count_list(&optinfo->addr_list) * sizeof(pi); 1924 if (!TAILQ_EMPTY(&optinfo->addr_list)) { 1925 for (dp = TAILQ_FIRST(&optinfo->addr_list); dp; 1926 dp = TAILQ_NEXT(dp, link)) { 1927 int iaddr_len = 0; 1928 memset(&pi, 0, sizeof(pi)); 1929 pi.dh6_pi_type = htons(DH6OPT_IAPREFIX); 1930 if (dp->val_dhcp6addr.status_code != DH6OPT_STCODE_UNDEFINE) 1931 iaddr_len = sizeof(pi) - sizeof(u_int32_t) 1932 + sizeof(status); 1933 else 1934 iaddr_len = sizeof(pi) - sizeof(u_int32_t); 1935 pi.dh6_pi_len = htons(iaddr_len); 1936 pi.preferlifetime = htonl(dp->val_dhcp6addr.preferlifetime); 1937 pi.validlifetime = htonl(dp->val_dhcp6addr.validlifetime); 1938 pi.plen = dp->val_dhcp6addr.plen; 1939 memcpy(&pi.prefix, &dp->val_dhcp6addr.addr, sizeof(pi.prefix)); 1940 memcpy(tp, &pi, sizeof(pi)); 1941 tp += sizeof(pi); 1942 dprintf(LOG_DEBUG, "set IAPREFIX option len %d: " 1943 "%s/%d preferlifetime %d validlifetime %d", 1944 iaddr_len, in6addr2str(&pi.prefix, 0), pi.plen, 1945 ntohl(pi.preferlifetime), ntohl(pi.validlifetime)); 1946 /* set up address status code if any */ 1947 if (dp->val_dhcp6addr.status_code != DH6OPT_STCODE_UNDEFINE) { 1948 status.dh6_status_type = htons(DH6OPT_STATUS_CODE); 1949 status.dh6_status_len = 1950 htons(sizeof(status.dh6_status_code)); 1951 status.dh6_status_code = 1952 htons(dp->val_dhcp6addr.status_code); 1953 memcpy(tp, &status, sizeof(status)); 1954 dprintf(LOG_DEBUG, " this address status code: %s", 1955 dhcp6_stcodestr(ntohs(status.dh6_status_code))); 1956 optlen += sizeof(status); 1957 tp += sizeof(status); 1958 /* copy status message if any */ 1959 } 1960 } 1961 } else if (dhcp6_mode == DHCP6_MODE_SERVER) { 1962 int num; 1963 num = DH6OPT_STCODE_NOPREFIXAVAIL; 1964 dprintf(LOG_DEBUG, " status code: %s", 1965 dhcp6_stcodestr(num)); 1966 if (dhcp6_add_listval(&optinfo->stcode_list, 1967 &num, DHCP6_LISTVAL_NUM) == NULL) { 1968 dprintf(LOG_ERR, "%s" "failed to copy " 1969 "status code", FNAME); 1970 goto fail; 1971 } 1972 } 1973 } else { 1974 /* Client mode */ 1975 /* Use 'prefix_list' instead of 'addr_list' for IAPD */ 1976 optlen += dhcp6_count_list(&optinfo->prefix_list) * sizeof(pi); 1977 if (!TAILQ_EMPTY(&optinfo->prefix_list)) { 1978 for (dp = TAILQ_FIRST(&optinfo->prefix_list); dp; 1979 dp = TAILQ_NEXT(dp, link)) { 1980 int iaddr_len = 0; 1981 memset(&pi, 0, sizeof(pi)); 1982 pi.dh6_pi_type = htons(DH6OPT_IAPREFIX); 1983 if (dp->val_dhcp6addr.status_code != DH6OPT_STCODE_UNDEFINE) 1984 iaddr_len = sizeof(pi) - sizeof(u_int32_t); 1985 else 1986 iaddr_len = sizeof(pi) - sizeof(u_int32_t); 1987 pi.dh6_pi_len = htons(iaddr_len); 1988 pi.preferlifetime = htonl(dp->val_dhcp6addr.preferlifetime); 1989 pi.validlifetime = htonl(dp->val_dhcp6addr.validlifetime); 1990 pi.plen = dp->val_dhcp6addr.plen; 1991 memcpy(&pi.prefix, &dp->val_dhcp6addr.addr, sizeof(pi.prefix)); 1992 memcpy(tp, &pi, sizeof(pi)); 1993 tp += sizeof(pi); 1994 dprintf(LOG_DEBUG, "set IAPREFIX option len %d: " 1995 "%s/%d preferlifetime %d validlifetime %d", 1996 iaddr_len, in6addr2str(&pi.prefix, 0), pi.plen, 1997 ntohl(pi.preferlifetime), ntohl(pi.validlifetime)); 1998 } 1999 } 2000 } 2001 /* Foxconn modified end 09/23/2009 */ 2002 COPY_OPTION(DH6OPT_IA_PD, optlen, tmpbuf, p); 2003 free(tmpbuf); 2004 break; 2005 default: 2006 break; 2007 } 2008 if (dhcp6_mode == DHCP6_MODE_SERVER && optinfo->pref != DH6OPT_PREF_UNDEF) { 2009 u_int8_t p8 = (u_int8_t)optinfo->pref; 2010 dprintf(LOG_DEBUG, "server preference %2x", optinfo->pref); 2011 COPY_OPTION(DH6OPT_PREFERENCE, sizeof(p8), &p8, p); 2012 } 2013 2014 for (stcode = TAILQ_FIRST(&optinfo->stcode_list); stcode; 2015 stcode = TAILQ_NEXT(stcode, link)) { 2016 u_int16_t code; 2017 2018 code = htons(stcode->val_num); 2019 COPY_OPTION(DH6OPT_STATUS_CODE, sizeof(code), &code, p); 2020 } 2021 2022 if (!TAILQ_EMPTY(&optinfo->reqopt_list)) { 2023 struct dhcp6_listval *opt; 2024 u_int16_t *valp; 2025 2026 tmpbuf = NULL; 2027 optlen = dhcp6_count_list(&optinfo->reqopt_list) * 2028 sizeof(u_int16_t); 2029 if ((tmpbuf = malloc(optlen)) == NULL) { 2030 dprintf(LOG_ERR, "%s" 2031 "memory allocation failed for options", FNAME); 2032 goto fail; 2033 } 2034 valp = (u_int16_t *)tmpbuf; 2035 for (opt = TAILQ_FIRST(&optinfo->reqopt_list); opt; 2036 opt = TAILQ_NEXT(opt, link), valp++) { 2037 *valp = htons((u_int16_t)opt->val_num); 2038 } 2039 COPY_OPTION(DH6OPT_ORO, optlen, tmpbuf, p); 2040 free(tmpbuf); 2041 } 2042 2043 if (!TAILQ_EMPTY(&optinfo->dns_list.addrlist)) { 2044 struct in6_addr *in6; 2045 struct dhcp6_listval *d; 2046 2047 tmpbuf = NULL; 2048 optlen = dhcp6_count_list(&optinfo->dns_list.addrlist) * 2049 sizeof(struct in6_addr); 2050 if ((tmpbuf = malloc(optlen)) == NULL) { 2051 dprintf(LOG_ERR, "%s" 2052 "memory allocation failed for DNS options", FNAME); 2053 goto fail; 2054 } 2055 in6 = (struct in6_addr *)tmpbuf; 2056 for (d = TAILQ_FIRST(&optinfo->dns_list.addrlist); d; 2057 d = TAILQ_NEXT(d, link), in6++) { 2058 memcpy(in6, &d->val_addr6, sizeof(*in6)); 2059 } 2060 COPY_OPTION(DH6OPT_DNS_SERVERS, optlen, tmpbuf, p); 2061 free(tmpbuf); 2062 } 2063 2064 /* Foxconn added start pling 01/25/2010 */ 2065 if (!TAILQ_EMPTY(&optinfo->sip_list)) { 2066 struct in6_addr *in6; 2067 struct dhcp6_listval *d; 2068 2069 tmpbuf = NULL; 2070 optlen = dhcp6_count_list(&optinfo->sip_list) * 2071 sizeof(struct in6_addr); 2072 if ((tmpbuf = malloc(optlen)) == NULL) { 2073 dprintf(LOG_ERR, "%s" 2074 "memory allocation failed for SIP options", FNAME); 2075 goto fail; 2076 } 2077 in6 = (struct in6_addr *)tmpbuf; 2078 for (d = TAILQ_FIRST(&optinfo->sip_list); d; 2079 d = TAILQ_NEXT(d, link), in6++) { 2080 memcpy(in6, &d->val_addr6, sizeof(*in6)); 2081 } 2082 COPY_OPTION(DH6OPT_SIP_SERVERS, optlen, tmpbuf, p); 2083 free(tmpbuf); 2084 } 2085 if (!TAILQ_EMPTY(&optinfo->ntp_list)) { 2086 struct in6_addr *in6; 2087 struct dhcp6_listval *d; 2088 2089 tmpbuf = NULL; 2090 optlen = dhcp6_count_list(&optinfo->ntp_list) * 2091 sizeof(struct in6_addr); 2092 if ((tmpbuf = malloc(optlen)) == NULL) { 2093 dprintf(LOG_ERR, "%s" 2094 "memory allocation failed for NTP options", FNAME); 2095 goto fail; 2096 } 2097 in6 = (struct in6_addr *)tmpbuf; 2098 for (d = TAILQ_FIRST(&optinfo->ntp_list); d; 2099 d = TAILQ_NEXT(d, link), in6++) { 2100 memcpy(in6, &d->val_addr6, sizeof(*in6)); 2101 } 2102 COPY_OPTION(DH6OPT_NTP_SERVERS, optlen, tmpbuf, p); 2103 free(tmpbuf); 2104 } 2105 /* Foxconn added end pling 01/25/2010 */ 2106 2107 if (optinfo->dns_list.domainlist != NULL) { 2108 struct domain_list *dlist; 2109 u_char *dst; 2110 optlen = 0; 2111 tmpbuf = NULL; 2112 if ((tmpbuf = malloc(MAXDNAME * MAXDN)) == NULL) { 2113 dprintf(LOG_ERR, "%s" 2114 "memory allocation failed for DNS options", FNAME); 2115 goto fail; 2116 } 2117 dst = tmpbuf; 2118 for (dlist = optinfo->dns_list.domainlist; dlist; dlist = dlist->next) { 2119 int n; 2120 n = dn_comp(dlist->name, dst, MAXDNAME, NULL, NULL); 2121 if (n < 0) { 2122 dprintf(LOG_ERR, "%s" "compress domain name failed", FNAME); 2123 goto fail; 2124 } else 2125 dprintf(LOG_DEBUG, "compress domain name %s", dlist->name); 2126 optlen += n ; 2127 dst += n; 2128 } 2129 COPY_OPTION(DH6OPT_DOMAIN_LIST, optlen, tmpbuf, p); 2130 free(tmpbuf); 2131 } 2132 2133 2134 return (len); 2135 2136 fail: 2137 if (tmpbuf) 2138 free(tmpbuf); 2139 return (-1); 2140} 2141#undef COPY_OPTION 2142 2143void 2144dhcp6_set_timeoparam(ev) 2145 struct dhcp6_event *ev; 2146{ 2147 ev->retrans = 0; 2148 ev->init_retrans = 0; 2149 ev->max_retrans_cnt = 0; 2150 ev->max_retrans_dur = 0; 2151 ev->max_retrans_time = 0; 2152 2153 switch(ev->state) { 2154 case DHCP6S_SOLICIT: 2155 ev->init_retrans = SOL_TIMEOUT; 2156 ev->max_retrans_time = SOL_MAX_RT; 2157 break; 2158 case DHCP6S_INFOREQ: 2159 ev->init_retrans = INF_TIMEOUT; 2160 ev->max_retrans_time = INF_MAX_RT; 2161 break; 2162 case DHCP6S_REQUEST: 2163 ev->init_retrans = REQ_TIMEOUT; 2164 ev->max_retrans_time = REQ_MAX_RT; 2165 ev->max_retrans_cnt = REQ_MAX_RC; 2166 break; 2167 case DHCP6S_RENEW: 2168 ev->init_retrans = REN_TIMEOUT; 2169 ev->max_retrans_time = REN_MAX_RT; 2170 break; 2171 case DHCP6S_REBIND: 2172 ev->init_retrans = REB_TIMEOUT; 2173 ev->max_retrans_time = REB_MAX_RT; 2174 break; 2175 case DHCP6S_DECLINE: 2176 ev->init_retrans = DEC_TIMEOUT; 2177 ev->max_retrans_cnt = DEC_MAX_RC; 2178 break; 2179 case DHCP6S_RELEASE: 2180 ev->init_retrans = REL_TIMEOUT; 2181 ev->max_retrans_cnt = REL_MAX_RC; 2182 break; 2183 case DHCP6S_CONFIRM: 2184 ev->init_retrans = CNF_TIMEOUT; 2185 ev->max_retrans_dur = CNF_MAX_RD; 2186 ev->max_retrans_time = CNF_MAX_RT; 2187 break; 2188 default: 2189 dprintf(LOG_INFO, "%s" "unexpected event state %d on %s", 2190 FNAME, ev->state, ev->ifp->ifname); 2191 exit(1); 2192 } 2193} 2194 2195void 2196dhcp6_reset_timer(ev) 2197 struct dhcp6_event *ev; 2198{ 2199 double n, r; 2200 char *statestr; 2201 struct timeval interval; 2202 2203 switch(ev->state) { 2204 case DHCP6S_INIT: 2205 /* 2206 * The first Solicit message from the client on the interface 2207 * MUST be delayed by a random amount of time between 2208 * MIN_SOL_DELAY and MAX_SOL_DELAY. 2209 * [dhcpv6-28 14.] 2210 */ 2211 /* Foxconn modified start pling 08/26/2009 */ 2212 /* In IPv6 auto mode (when DHCIFF_SOLICIT_ONLY is set), 2213 * send immediately. 2214 */ 2215 if ((ev->ifp->send_flags & DHCIFF_SOLICIT_ONLY)) 2216 ev->retrans = 0; 2217 else 2218 ev->retrans = (random() % (MAX_SOL_DELAY - MIN_SOL_DELAY)) + 2219 MIN_SOL_DELAY; 2220 /* Foxconn modified end pling 08/26/2009 */ 2221 break; 2222 default: 2223 if (ev->timeouts == 0) { 2224 /* 2225 * The first RT MUST be selected to be strictly 2226 * greater than IRT by choosing RAND to be strictly 2227 * greater than 0. 2228 * [dhcpv6-28 14.] 2229 */ 2230 r = (double)((random() % 1000) + 1) / 10000; 2231 n = ev->init_retrans + r * ev->init_retrans; 2232 } else { 2233 r = (double)((random() % 2000) - 1000) / 10000; 2234 2235 if (ev->timeouts == 0) { 2236 n = ev->init_retrans + r * ev->init_retrans; 2237 } else 2238 n = 2 * ev->retrans + r * ev->retrans; 2239 } 2240 if (ev->max_retrans_time && n > ev->max_retrans_time) 2241 n = ev->max_retrans_time + r * ev->max_retrans_time; 2242 /* Foxconn modified start pling 08/26/2009 */ 2243 /* In IPv6 auto mode (when DHCIFF_SOLICIT_ONLY is set), 2244 * then send 1 DHCP Solicit every 1 sec. 2245 */ 2246 if ((ev->ifp->send_flags & DHCIFF_SOLICIT_ONLY)) 2247 ev->retrans = 1000; 2248 else 2249 ev->retrans = (long)n; 2250 /* Foxconn modified end pling 08/26/2009 */ 2251 break; 2252 } 2253 2254 switch(ev->state) { 2255 case DHCP6S_INIT: 2256 statestr = "INIT"; 2257 break; 2258 case DHCP6S_SOLICIT: 2259 statestr = "SOLICIT"; 2260 break; 2261 case DHCP6S_INFOREQ: 2262 statestr = "INFOREQ"; 2263 break; 2264 case DHCP6S_REQUEST: 2265 statestr = "REQUEST"; 2266 break; 2267 case DHCP6S_RENEW: 2268 statestr = "RENEW"; 2269 break; 2270 case DHCP6S_REBIND: 2271 statestr = "REBIND"; 2272 break; 2273 case DHCP6S_CONFIRM: 2274 statestr = "CONFIRM"; 2275 break; 2276 case DHCP6S_DECLINE: 2277 statestr = "DECLINE"; 2278 break; 2279 case DHCP6S_RELEASE: 2280 statestr = "RELEASE"; 2281 break; 2282 case DHCP6S_IDLE: 2283 statestr = "IDLE"; 2284 break; 2285 default: 2286 statestr = "???"; 2287 break; 2288 } 2289 2290 interval.tv_sec = (ev->retrans * 1000) / 1000000; 2291 interval.tv_usec = (ev->retrans * 1000) % 1000000; 2292 dhcp6_set_timer(&interval, ev->timer); 2293 2294 dprintf(LOG_DEBUG, "%s" "reset a timer on %s, " 2295 "state=%s, timeo=%d, retrans=%ld", FNAME, 2296 ev->ifp->ifname, statestr, ev->timeouts, (long) ev->retrans); 2297} 2298 2299int 2300duidcpy(struct duid *dd, const struct duid *ds) 2301{ 2302 dd->duid_len = ds->duid_len; 2303 if ((dd->duid_id = malloc(dd->duid_len)) == NULL) { 2304 dprintf(LOG_ERR, "%s" "len %d memory allocation failed", FNAME, dd->duid_len); 2305 return (-1); 2306 } 2307 memcpy(dd->duid_id, ds->duid_id, dd->duid_len); 2308 2309 return (0); 2310} 2311 2312int 2313duidcmp(const struct duid *d1, 2314 const struct duid *d2) 2315{ 2316 if (d1->duid_len == d2->duid_len) { 2317 return (memcmp(d1->duid_id, d2->duid_id, d1->duid_len)); 2318 } else 2319 return (-1); 2320} 2321 2322void 2323duidfree(duid) 2324 struct duid *duid; 2325{ 2326 dprintf(LOG_DEBUG, "%s" "DUID is %s, DUID_LEN is %d", 2327 FNAME, duidstr(duid), duid->duid_len); 2328 if (duid->duid_id != NULL && duid->duid_len != 0) { 2329 dprintf(LOG_DEBUG, "%s" "removing ID (ID: %s)", 2330 FNAME, duidstr(duid)); 2331 free(duid->duid_id); 2332 duid->duid_id = NULL; 2333 duid->duid_len = 0; 2334 } 2335 duid->duid_len = 0; 2336} 2337 2338char * 2339dhcp6optstr(type) 2340 int type; 2341{ 2342 static char genstr[sizeof("opt_65535") + 1]; 2343 2344 if (type > 65535) 2345 return "INVALID option"; 2346 2347 switch(type) { 2348 case DH6OPT_CLIENTID: 2349 return "client ID"; 2350 case DH6OPT_SERVERID: 2351 return "server ID"; 2352 case DH6OPT_ORO: 2353 return "option request"; 2354 case DH6OPT_PREFERENCE: 2355 return "preference"; 2356 case DH6OPT_STATUS_CODE: 2357 return "status code"; 2358 case DH6OPT_RAPID_COMMIT: 2359 return "rapid commit"; 2360 case DH6OPT_DNS_SERVERS: 2361 return "DNS_SERVERS"; 2362 /* Foxconn added start pling 09/23/2010 */ 2363 case DH6OPT_DOMAIN_LIST: 2364 return "DOMAIN_LIST"; 2365 /* Foxconn added end pling 09/23/2010 */ 2366 /* Foxconn added start pling 01/25/2010 */ 2367 case DH6OPT_SIP_SERVERS: 2368 return "SIP_SERVERS"; 2369 case DH6OPT_NTP_SERVERS: 2370 return "NTP_SERVERS"; 2371 /* Foxconn added end pling 01/25/2010 */ 2372 default: 2373 sprintf(genstr, "opt_%d", type); 2374 return (genstr); 2375 } 2376} 2377 2378char * 2379dhcp6msgstr(type) 2380 int type; 2381{ 2382 static char genstr[sizeof("msg255") + 1]; 2383 2384 if (type > 255) 2385 return "INVALID msg"; 2386 2387 switch(type) { 2388 case DH6_SOLICIT: 2389 return "solicit"; 2390 case DH6_ADVERTISE: 2391 return "advertise"; 2392 case DH6_RENEW: 2393 return "renew"; 2394 case DH6_REBIND: 2395 return "rebind"; 2396 case DH6_REQUEST: 2397 return "request"; 2398 case DH6_REPLY: 2399 return "reply"; 2400 case DH6_CONFIRM: 2401 return "confirm"; 2402 case DH6_RELEASE: 2403 return "release"; 2404 case DH6_DECLINE: 2405 return "decline"; 2406 case DH6_INFORM_REQ: 2407 return "information request"; 2408 case DH6_RECONFIGURE: 2409 return "reconfigure"; 2410 case DH6_RELAY_FORW: 2411 return "relay forwarding"; 2412 case DH6_RELAY_REPL: 2413 return "relay reply"; 2414 default: 2415 sprintf(genstr, "msg%d", type); 2416 return (genstr); 2417 } 2418} 2419 2420char * 2421dhcp6_stcodestr(code) 2422 int code; 2423{ 2424 static char genstr[sizeof("code255") + 1]; 2425 2426 if (code > 255) 2427 return "INVALID code"; 2428 2429 switch(code) { 2430 case DH6OPT_STCODE_SUCCESS: 2431 return "success"; 2432 case DH6OPT_STCODE_UNSPECFAIL: 2433 return "unspec failure"; 2434 case DH6OPT_STCODE_AUTHFAILED: 2435 return "auth fail"; 2436 case DH6OPT_STCODE_ADDRUNAVAIL: 2437 return "address unavailable"; 2438 case DH6OPT_STCODE_NOADDRAVAIL: 2439 return "no addresses"; 2440 case DH6OPT_STCODE_NOBINDING: 2441 return "no binding"; 2442 case DH6OPT_STCODE_CONFNOMATCH: 2443 return "confirm no match"; 2444 case DH6OPT_STCODE_NOTONLINK: 2445 return "not on-link"; 2446 case DH6OPT_STCODE_USEMULTICAST: 2447 return "use multicast"; 2448 default: 2449 sprintf(genstr, "code%d", code); 2450 return (genstr); 2451 } 2452} 2453 2454char * 2455duidstr(const struct duid *duid) 2456{ 2457 int i; 2458 char *cp; 2459 static char duidstr[sizeof("xx:") * 256 + sizeof("...")]; 2460 2461 duidstr[0] ='\0'; 2462 2463 cp = duidstr; 2464 for (i = 0; i < duid->duid_len && i <= 256; i++) { 2465 cp += sprintf(cp, "%s%02x", i == 0 ? "" : ":", 2466 duid->duid_id[i] & 0xff); 2467 } 2468 if (i < duid->duid_len) 2469 sprintf(cp, "%s", "..."); 2470 2471 return (duidstr); 2472} 2473 2474void 2475setloglevel(debuglevel) 2476 int debuglevel; 2477{ 2478 if (foreground) { 2479 switch(debuglevel) { 2480 case 0: 2481 debug_thresh = LOG_ERR; 2482 break; 2483 case 1: 2484 debug_thresh = LOG_INFO; 2485 break; 2486 default: 2487 debug_thresh = LOG_DEBUG; 2488 break; 2489 } 2490 } else { 2491 switch(debuglevel) { 2492 case 0: 2493 setlogmask(LOG_UPTO(LOG_ERR)); 2494 break; 2495 case 1: 2496 setlogmask(LOG_UPTO(LOG_INFO)); 2497 break; 2498 } 2499 } 2500} 2501 2502void 2503dprintf(int level, const char *fmt, ...) 2504{ 2505 va_list ap; 2506 char logbuf[LINE_MAX]; 2507 2508 va_start(ap, fmt); 2509 vsnprintf(logbuf, sizeof(logbuf), fmt, ap); 2510 2511 if (foreground && debug_thresh >= level) { 2512 time_t now; 2513 struct tm *tm_now; 2514 const char *month[] = { 2515 "Jan", "Feb", "Mar", "Apr", "May", "Jun", 2516 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", 2517 }; 2518 2519 if ((now = time(NULL)) < 0) 2520 exit(1); 2521 tm_now = localtime(&now); 2522 fprintf(stderr, "%3s/%02d/%04d %02d:%02d:%02d %s\n", 2523 month[tm_now->tm_mon], tm_now->tm_mday, 2524 tm_now->tm_year + 1900, 2525 tm_now->tm_hour, tm_now->tm_min, tm_now->tm_sec, 2526 logbuf); 2527 } else 2528 syslog(level, "%s", logbuf); 2529} 2530