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