1/* $Id: dhcp6c.c,v 1.1.1.1 2006/12/04 00:45:23 Exp $ */ 2/* ported from KAME: dhcp6c.c,v 1.97 2002/09/24 14:20:49 itojun 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 <sys/uio.h> 36#include <sys/stat.h> 37#include <sys/ioctl.h> 38#include <unistd.h> 39#include <errno.h> 40#if TIME_WITH_SYS_TIME 41# include <sys/time.h> 42# include <sys/timeb.h> 43# include <time.h> 44#else 45# if HAVE_SYS_TIME_H 46# include <sys/time.h> 47# else 48# include <time.h> 49# endif 50#endif 51#include <net/if.h> 52#include <linux/sockios.h> 53#if defined(__FreeBSD__) && __FreeBSD__ >= 3 54#include <net/if_var.h> 55#endif 56 57#include <arpa/inet.h> 58#include <netdb.h> 59 60#include <signal.h> 61#include <stdio.h> 62#include <stdarg.h> 63#include <syslog.h> 64#include <stdlib.h> 65#include <unistd.h> 66#include <string.h> 67#include <err.h> 68#include <ifaddrs.h> 69 70#include "queue.h" 71#include "dhcp6.h" 72#include "config.h" 73#include "common.h" 74#include "timer.h" 75#include "lease.h" 76 77static int debug = 0; 78static u_long sig_flags = 0; 79#define SIGF_TERM 0x1 80#define SIGF_HUP 0x2 81#define SIGF_CLEAN 0x4 82 83#define DHCP6S_VALID_REPLY(a) \ 84 (a == DHCP6S_REQUEST || a == DHCP6S_RENEW || \ 85 a == DHCP6S_REBIND || a == DHCP6S_DECLINE || \ 86 a == DHCP6S_RELEASE || a == DHCP6S_CONFIRM || \ 87 a == DHCP6S_INFOREQ) 88 89 90const dhcp6_mode_t dhcp6_mode = DHCP6_MODE_CLIENT; 91 92static char *device = NULL; 93static int num_device = 0; 94static struct iaid_table iaidtab[100]; 95static u_int8_t client6_request_flag = 0; 96static char leasename[100]; 97 98#define CLIENT6_RELEASE_ADDR 0x1 99#define CLIENT6_CONFIRM_ADDR 0x2 100#define CLIENT6_REQUEST_ADDR 0x4 101#define CLIENT6_DECLINE_ADDR 0x8 102 103#define CLIENT6_INFO_REQ 0x10 104 105int insock; /* inbound udp port */ 106//int outsock; /* outbound udp port */ // Foxconn removed pling 08/15/2009 107int nlsock; 108 109extern char *raproc_file; 110extern char *ifproc_file; 111extern struct ifproc_info *dadlist; 112extern FILE *client6_lease_file; 113extern struct dhcp6_iaidaddr client6_iaidaddr; 114FILE *dhcp6_resolv_file; 115static const struct sockaddr_in6 *sa6_allagent; 116static struct duid client_duid; 117 118static void usage __P((void)); 119static void client6_init __P((char *)); 120static void client6_ifinit __P((char *)); 121void free_servers __P((struct dhcp6_if *)); 122static void free_resources __P((struct dhcp6_if *)); 123static int create_request_list __P((int)); 124static void client6_mainloop __P((void)); 125static void process_signals __P((void)); 126static struct dhcp6_serverinfo *find_server __P((struct dhcp6_if *, 127 struct duid *)); 128static struct dhcp6_serverinfo *allocate_newserver __P((struct dhcp6_if *, struct dhcp6_optinfo *)); 129static struct dhcp6_serverinfo *select_server __P((struct dhcp6_if *)); 130void client6_send __P((struct dhcp6_event *)); 131int client6_send_newstate __P((struct dhcp6_if *, int)); 132static void client6_recv __P((void)); 133static int client6_recvadvert __P((struct dhcp6_if *, struct dhcp6 *, 134 ssize_t, struct dhcp6_optinfo *)); 135static int client6_recvreply __P((struct dhcp6_if *, struct dhcp6 *, 136 ssize_t, struct dhcp6_optinfo *)); 137static void client6_signal __P((int)); 138static struct dhcp6_event *find_event_withid __P((struct dhcp6_if *, 139 u_int32_t)); 140static struct dhcp6_timer *check_lease_file_timo __P((void *)); 141static struct dhcp6_timer *check_link_timo __P((void *)); 142static struct dhcp6_timer *check_dad_timo __P((void *)); 143static void setup_check_timer __P((struct dhcp6_if *)); 144static void setup_interface __P((char *)); 145struct dhcp6_timer *client6_timo __P((void *)); 146extern int client6_ifaddrconf __P((ifaddrconf_cmd_t, struct dhcp6_addr *)); 147extern struct dhcp6_timer *syncfile_timo __P((void *)); 148extern int radvd_parse (struct dhcp6_iaidaddr *, int); 149 150#define DHCP6C_CONF "/tmp/dhcp6c.conf" 151#define DHCP6C_USER_CONF "/tmp/dhcp6c_user.conf" // Foxconn added pling 09/27/2010 152#define DHCP6C_PIDFILE "/var/run/dhcpv6/dhcp6c.pid" 153#define DUID_FILE "/tmp/dhcp6c_duid" 154 155static int pid; 156char client6_lease_temp[256]; 157struct dhcp6_list request_list; 158struct dhcp6_list request_prefix_list; // Foxconn added pling 09/24/2009 159 160/* Foxconn added start pling 10/07/2010 */ 161/* For testing purpose */ 162u_int32_t xid_solicit = 0; 163u_int32_t xid_request = 0; 164/* Foxconn added end pling 10/07/2010 */ 165 166/* Foxconn added start pling 09/07/2010 */ 167/* User secondary conf file to store info such as user-class */ 168int parse_user_file(char *user_file) 169{ 170 FILE *fp = NULL; 171 char line[1024]; 172 char user_class_key[] = "user_class"; 173 char *newline1; 174 char *newline2; 175 176 /* Initial client user class to empty string */ 177 set_dhcpc_user_class(""); 178 179 fp = fopen(user_file, "r"); 180 if (fp != NULL) 181 { 182 while (!feof(fp)) 183 { 184 fgets(line, sizeof(line), fp); 185 186 /* Remove trailing newline characters, if any */ 187 newline1 = strstr(line, "\r"); 188 newline2 = strstr(line, "\n"); 189 if (newline1) 190 *newline1 = '\0'; 191 if (newline2) 192 *newline2 = '\0'; 193 194 /* Extract the key */ 195 if (strncmp(line, user_class_key, strlen(user_class_key)) == 0) 196 set_dhcpc_user_class(&line[strlen(user_class_key)+1]); 197 } 198 fclose(fp); 199 } 200 return 0; 201} 202/* Foxconn added end pling 09/07/2010 */ 203 204/* Foxconn added start pling 09/23/2009 */ 205/* Return the interface where dhcp is run on */ 206char* get_dhcpc_dev_name(void) 207{ 208 return device; 209} 210/* Foxconn added end pling 09/23/2009 */ 211 212int 213main(argc, argv) 214 int argc; 215 char **argv; 216{ 217 int ch; 218 char *progname, *conffile = DHCP6C_CONF; 219 char *user_file = DHCP6C_USER_CONF; 220 FILE *pidfp; 221 char *addr; 222 223 pid = getpid(); 224 srandom(time(NULL) & pid); 225 226 if ((progname = strrchr(*argv, '/')) == NULL) 227 progname = *argv; 228 else 229 progname++; 230 231 TAILQ_INIT(&request_list); 232 TAILQ_INIT(&request_prefix_list); // Foxconn added pling 09/23/2009 233 234 /* Foxconn modified start pling 09/17/2010 */ 235 /* Since 'user class' string may contain any printable char. 236 * The current dhcp6s config file parsing (using yyparse) 237 * can't handle this properly. 238 * So we put user-class string in a separate file, 239 * specified using '-u' option. 240 */ 241 //while ((ch = getopt(argc, argv, "c:r:R:P:dDfI")) != -1) { 242 while ((ch = getopt(argc, argv, "c:u:r:R:P:dDfI")) != -1) { 243 /* Foxconn modified end pling 09/17/2010 */ 244 switch (ch) { 245 case 'c': 246 conffile = optarg; 247 break; 248 /* Foxconn added start pling 09/17/2010 */ 249 /* Another config file to store info, such as user-class, etc */ 250 case 'u': 251 user_file = optarg; 252 break; 253 /* Foxconn added end pling 09/17/2010 */ 254 case 'P': 255 client6_request_flag |= CLIENT6_REQUEST_ADDR; 256 for (addr = strtok(optarg, " "); addr; addr = strtok(NULL, " ")) { 257 struct dhcp6_listval *lv; 258 if ((lv = (struct dhcp6_listval *)malloc(sizeof(*lv))) 259 == NULL) { 260 dprintf(LOG_ERR, "failed to allocate memory"); 261 exit(1); 262 } 263 memset(lv, 0, sizeof(*lv)); 264 if (inet_pton(AF_INET6, strtok(addr, "/"), 265 &lv->val_dhcp6addr.addr) < 1) { 266 dprintf(LOG_ERR, 267 "invalid ipv6address for release"); 268 usage(); 269 exit(1); 270 } 271 lv->val_dhcp6addr.type = IAPD; 272 lv->val_dhcp6addr.plen = atoi(strtok(NULL, "/")); 273 lv->val_dhcp6addr.status_code = DH6OPT_STCODE_UNDEFINE; 274 TAILQ_INSERT_TAIL(&request_list, lv, link); 275 } 276 break; 277 278 case 'R': 279 client6_request_flag |= CLIENT6_REQUEST_ADDR; 280 for (addr = strtok(optarg, " "); addr; addr = strtok(NULL, " ")) { 281 struct dhcp6_listval *lv; 282 if ((lv = (struct dhcp6_listval *)malloc(sizeof(*lv))) 283 == NULL) { 284 dprintf(LOG_ERR, "failed to allocate memory"); 285 exit(1); 286 } 287 memset(lv, 0, sizeof(*lv)); 288 if (inet_pton(AF_INET6, addr, &lv->val_dhcp6addr.addr) < 1) { 289 dprintf(LOG_ERR, 290 "invalid ipv6address for release"); 291 usage(); 292 exit(1); 293 } 294 lv->val_dhcp6addr.type = IANA; 295 lv->val_dhcp6addr.status_code = DH6OPT_STCODE_UNDEFINE; 296 TAILQ_INSERT_TAIL(&request_list, lv, link); 297 } 298 break; 299 case 'r': 300 client6_request_flag |= CLIENT6_RELEASE_ADDR; 301 if (strcmp(optarg, "all")) { 302 for (addr = strtok(optarg, " "); addr; 303 addr = strtok(NULL, " ")) { 304 struct dhcp6_listval *lv; 305 if ((lv = (struct dhcp6_listval *)malloc(sizeof(*lv))) 306 == NULL) { 307 dprintf(LOG_ERR, "failed to allocate memory"); 308 exit(1); 309 } 310 memset(lv, 0, sizeof(*lv)); 311 if (inet_pton(AF_INET6, addr, 312 &lv->val_dhcp6addr.addr) < 1) { 313 dprintf(LOG_ERR, 314 "invalid ipv6address for release"); 315 usage(); 316 exit(1); 317 } 318 lv->val_dhcp6addr.type = IANA; 319 TAILQ_INSERT_TAIL(&request_list, lv, link); 320 } 321 } 322 break; 323 case 'I': 324 client6_request_flag |= CLIENT6_INFO_REQ; 325 break; 326 case 'd': 327 debug = 1; 328 break; 329 case 'D': 330 debug = 2; 331 break; 332 case 'f': 333 foreground++; 334 break; 335 default: 336 usage(); 337 exit(0); 338 } 339 } 340 argc -= optind; 341 argv += optind; 342 343 if (argc != 1) { 344 usage(); 345 exit(0); 346 } 347 device = argv[0]; 348 349 if (foreground == 0) { 350 if (daemon(0, 0) < 0) 351 err(1, "daemon"); 352 openlog(progname, LOG_NDELAY|LOG_PID, LOG_DAEMON); 353 } 354 setloglevel(debug); 355 356 /* dump current PID */ 357 if ((pidfp = fopen(DHCP6C_PIDFILE, "w")) != NULL) { 358 fprintf(pidfp, "%d\n", pid); 359 fclose(pidfp); 360 } 361 362 ifinit(device); 363 364 /* Foxconn added start pling 09/17/2010 */ 365 /* Parse the second conf file, before reading original config file */ 366 parse_user_file(user_file); 367 /* Foxconn added end pling 09/17/2010 */ 368 369 if ((cfparse(conffile)) != 0) { 370 dprintf(LOG_ERR, "%s" "failed to parse configuration file", 371 FNAME); 372 exit(1); 373 } 374 375 /* Foxconn added start pling 01/25/2010 */ 376 /* Clear SIP and NTP servers params upon restart */ 377 system("nvram set ipv6_sip_servers=\"\""); 378 system("nvram set ipv6_ntp_servers=\"\""); 379 /* Foxconn added end pling 01/25/2010 */ 380 381 client6_init(device); 382 client6_ifinit(device); 383 client6_mainloop(); 384 exit(0); 385} 386 387static void 388usage() 389{ 390 391 fprintf(stderr, 392 "usage: dhcpc [-c configfile] [-r all or (ipv6address ipv6address...)]\n" 393 " [-R (ipv6 address ipv6address...) [-dDIf] interface\n"); 394} 395 396/*------------------------------------------------------------*/ 397 398void 399client6_init(device) 400 char *device; 401{ 402 struct addrinfo hints, *res; 403 static struct sockaddr_in6 sa6_allagent_storage; 404 int error, on = 1; 405 struct dhcp6_if *ifp; 406 int ifidx; 407 char linklocal[64]; 408 struct in6_addr lladdr; 409 410 ifidx = if_nametoindex(device); 411 if (ifidx == 0) { 412 dprintf(LOG_ERR, "if_nametoindex(%s)", device); 413 exit(1); 414 } 415 416 /* get our DUID */ 417 if (get_duid(DUID_FILE, device, &client_duid)) { 418 dprintf(LOG_ERR, "%s" "failed to get a DUID", FNAME); 419 exit(1); 420 } 421 if (get_linklocal(device, &lladdr) < 0) { 422 exit(1); 423 } 424 if (inet_ntop(AF_INET6, &lladdr, linklocal, sizeof(linklocal)) < 0) { 425 exit(1); 426 } 427 dprintf(LOG_DEBUG, "link local addr is %s", linklocal); 428 429 memset(&hints, 0, sizeof(hints)); 430 hints.ai_family = PF_INET6; 431 hints.ai_socktype = SOCK_DGRAM; 432 hints.ai_protocol = IPPROTO_UDP; 433 hints.ai_flags = 0; 434 error = getaddrinfo(linklocal, DH6PORT_DOWNSTREAM, &hints, &res); 435 if (error) { 436 dprintf(LOG_ERR, "%s" "getaddrinfo: %s", 437 FNAME, strerror(error)); 438 exit(1); 439 } 440 insock = socket(res->ai_family, res->ai_socktype, res->ai_protocol); 441 if (insock < 0) { 442 dprintf(LOG_ERR, "%s" "socket(inbound)", FNAME); 443 exit(1); 444 } 445#ifdef IPV6_RECVPKTINFO 446 if (setsockopt(insock, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on, 447 sizeof(on)) < 0) { 448 dprintf(LOG_ERR, "%s" 449 "setsockopt(inbound, IPV6_RECVPKTINFO): %s", 450 FNAME, strerror(errno)); 451 exit(1); 452 } 453#else 454 if (setsockopt(insock, IPPROTO_IPV6, IPV6_PKTINFO, &on, 455 sizeof(on)) < 0) { 456 dprintf(LOG_ERR, "%s" 457 "setsockopt(inbound, IPV6_PKTINFO): %s", 458 FNAME, strerror(errno)); 459 exit(1); 460 } 461#endif 462 ((struct sockaddr_in6 *)(res->ai_addr))->sin6_scope_id = ifidx; 463 dprintf(LOG_DEBUG, "res addr is %s/%d", addr2str(res->ai_addr), res->ai_addrlen); 464 if (bind(insock, res->ai_addr, res->ai_addrlen) < 0) { 465 dprintf(LOG_ERR, "%s" "bind(inbound): %s", 466 FNAME, strerror(errno)); 467 exit(1); 468 } 469 freeaddrinfo(res); 470 471 hints.ai_flags = 0; 472 error = getaddrinfo(linklocal, DH6PORT_UPSTREAM, &hints, &res); 473 if (error) { 474 dprintf(LOG_ERR, "%s" "getaddrinfo: %s", 475 FNAME, gai_strerror(error)); 476 exit(1); 477 } 478 /* Foxconn removed start pling 08/15/2009 */ 479#if 0 480 outsock = socket(res->ai_family, res->ai_socktype, res->ai_protocol); 481 if (outsock < 0) { 482 dprintf(LOG_ERR, "%s" "socket(outbound): %s", 483 FNAME, strerror(errno)); 484 exit(1); 485 } 486 if (setsockopt(outsock, IPPROTO_IPV6, IPV6_MULTICAST_IF, 487 &ifidx, sizeof(ifidx)) < 0) { 488 dprintf(LOG_ERR, "%s" 489 "setsockopt(outbound, IPV6_MULTICAST_IF): %s", 490 FNAME, strerror(errno)); 491 exit(1); 492 } 493 ((struct sockaddr_in6 *)(res->ai_addr))->sin6_scope_id = ifidx; 494 if (bind(outsock, res->ai_addr, res->ai_addrlen) < 0) { 495 dprintf(LOG_ERR, "%s" "bind(outbound): %s", 496 FNAME, strerror(errno)); 497 exit(1); 498 } 499#endif 500 /* Foxconn removed end pling 08/15/2009 */ 501 freeaddrinfo(res); 502 /* open a socket to watch the off-on link for confirm messages */ 503 if ((nlsock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { 504 dprintf(LOG_ERR, "%s" "open a socket: %s", 505 FNAME, strerror(errno)); 506 exit(1); 507 } 508 memset(&hints, 0, sizeof(hints)); 509 hints.ai_family = PF_INET6; 510 hints.ai_socktype = SOCK_DGRAM; 511 hints.ai_protocol = IPPROTO_UDP; 512 error = getaddrinfo(DH6ADDR_ALLAGENT, DH6PORT_UPSTREAM, &hints, &res); 513 if (error) { 514 dprintf(LOG_ERR, "%s" "getaddrinfo: %s", 515 FNAME, gai_strerror(error)); 516 exit(1); 517 } 518 memcpy(&sa6_allagent_storage, res->ai_addr, res->ai_addrlen); 519 sa6_allagent = (const struct sockaddr_in6 *)&sa6_allagent_storage; 520 freeaddrinfo(res); 521 522 /* client interface configuration */ 523 if ((ifp = find_ifconfbyname(device)) == NULL) { 524 dprintf(LOG_ERR, "%s" "interface %s not configured", 525 FNAME, device); 526 exit(1); 527 } 528 //ifp->outsock = outsock; // Foxconn removed pling 08/15/2009 529 530 if (signal(SIGHUP, client6_signal) == SIG_ERR) { 531 dprintf(LOG_WARNING, "%s" "failed to set signal: %s", 532 FNAME, strerror(errno)); 533 exit(1); 534 } 535 if (signal(SIGTERM|SIGKILL, client6_signal) == SIG_ERR) { 536 dprintf(LOG_WARNING, "%s" "failed to set signal: %s", 537 FNAME, strerror(errno)); 538 exit(1); 539 } 540 if (signal(SIGINT, client6_signal) == SIG_ERR) { 541 dprintf(LOG_WARNING, "%s" "failed to set signal: %s", 542 FNAME, strerror(errno)); 543 exit(1); 544 } 545} 546 547static void 548client6_ifinit(char *device) 549{ 550 struct dhcp6_if *ifp = dhcp6_if; 551 struct dhcp6_event *ev; 552 char iaidstr[20]; 553 554 dhcp6_init_iaidaddr(); 555 /* get iaid for each interface */ 556 if (num_device == 0) { 557 if ((num_device = create_iaid(&iaidtab[0], num_device)) < 0) 558 exit(1); 559 /* Foxconn modified start pling 08/20/2009 */ 560 /* Per Netgear spec, use 1 as the IAID for IA_NA */ 561 //ifp->iaidinfo.iaid = get_iaid(ifp->ifname, &iaidtab[0], num_device); 562 ifp->iaidinfo.iaid = 1; //get_iaid(ifp->ifname, &iaidtab[0], num_device); 563 /* Foxconn modified end pling 08/20/2009 */ 564 if (ifp->iaidinfo.iaid == 0) { 565 dprintf(LOG_DEBUG, "%s" 566 "interface %s iaid failed to be created", 567 FNAME, ifp->ifname); 568 exit(1); 569 } 570 dprintf(LOG_DEBUG, "%s" "interface %s iaid is %u", 571 FNAME, ifp->ifname, ifp->iaidinfo.iaid); 572 } 573 client6_iaidaddr.ifp = ifp; 574 memcpy(&client6_iaidaddr.client6_info.iaidinfo, &ifp->iaidinfo, 575 sizeof(client6_iaidaddr.client6_info.iaidinfo)); 576 duidcpy(&client6_iaidaddr.client6_info.clientid, &client_duid); 577 /* parse the lease file */ 578 strcpy(leasename, PATH_CLIENT6_LEASE); 579 sprintf(iaidstr, "%u", ifp->iaidinfo.iaid); 580 strcat(leasename, iaidstr); 581 if ((client6_lease_file = 582 init_leases(leasename)) == NULL) { 583 dprintf(LOG_ERR, "%s" "failed to parse lease file", FNAME); 584 exit(1); 585 } 586 strcpy(client6_lease_temp, leasename); 587 strcat(client6_lease_temp, "XXXXXX"); 588 client6_lease_file = 589 sync_leases(client6_lease_file, leasename, client6_lease_temp); 590 if (client6_lease_file == NULL) 591 exit(1); 592 if (!TAILQ_EMPTY(&client6_iaidaddr.lease_list)) { 593 struct dhcp6_listval *lv; 594 if (!(client6_request_flag & CLIENT6_REQUEST_ADDR) && 595 !(client6_request_flag & CLIENT6_RELEASE_ADDR)) 596 client6_request_flag |= CLIENT6_CONFIRM_ADDR; 597 if (TAILQ_EMPTY(&request_list)) { 598 if (create_request_list(1) < 0) 599 exit(1); 600 } else if (client6_request_flag & CLIENT6_RELEASE_ADDR) { 601 for (lv = TAILQ_FIRST(&request_list); lv; 602 lv = TAILQ_NEXT(lv, link)) { 603 if (dhcp6_find_lease(&client6_iaidaddr, 604 &lv->val_dhcp6addr) == NULL) { 605 dprintf(LOG_INFO, "this address %s is not" 606 " leased by this client", 607 in6addr2str(&lv->val_dhcp6addr.addr,0)); 608 exit(0); 609 } 610 } 611 } 612 } else if (client6_request_flag & CLIENT6_RELEASE_ADDR) { 613 dprintf(LOG_INFO, "no ipv6 addresses are leased by client"); 614 exit(0); 615 } 616 setup_interface(ifp->ifname); 617 ifp->link_flag |= IFF_RUNNING; 618 619 /* get addrconf prefix from kernel */ 620 (void)get_if_rainfo(ifp); 621 622 /* set up check link timer and sync file timer */ 623 if ((ifp->link_timer = 624 dhcp6_add_timer(check_link_timo, ifp)) < 0) { 625 dprintf(LOG_ERR, "%s" "failed to create a timer", FNAME); 626 exit(1); 627 } 628 if ((ifp->sync_timer = dhcp6_add_timer(check_lease_file_timo, ifp)) < 0) { 629 dprintf(LOG_ERR, "%s" "failed to create a timer", FNAME); 630 exit(1); 631 } 632 /* DAD timer set up after getting the address */ 633 ifp->dad_timer = NULL; 634 /* create an event for the initial delay */ 635 if ((ev = dhcp6_create_event(ifp, DHCP6S_INIT)) == NULL) { 636 dprintf(LOG_ERR, "%s" "failed to create an event", 637 FNAME); 638 exit(1); 639 } 640 ifp->servers = NULL; 641 ev->ifp->current_server = NULL; 642 TAILQ_INSERT_TAIL(&ifp->event_list, ev, link); 643 if ((ev->timer = dhcp6_add_timer(client6_timo, ev)) == NULL) { 644 dprintf(LOG_ERR, "%s" "failed to add a timer for %s", 645 FNAME, ifp->ifname); 646 exit(1); 647 } 648 dhcp6_reset_timer(ev); 649} 650 651static void 652free_resources(struct dhcp6_if *ifp) 653{ 654 struct dhcp6_event *ev, *ev_next; 655 struct dhcp6_lease *sp, *sp_next; 656 struct stat buf; 657 if (client6_iaidaddr.client6_info.type == IAPD && 658 !TAILQ_EMPTY(&client6_iaidaddr.lease_list)) 659 radvd_parse(&client6_iaidaddr, ADDR_REMOVE); 660 else { 661 for (sp = TAILQ_FIRST(&client6_iaidaddr.lease_list); sp; sp = sp_next) { 662 sp_next = TAILQ_NEXT(sp, link); 663 if (client6_ifaddrconf(IFADDRCONF_REMOVE, &sp->lease_addr) != 0) 664 dprintf(LOG_INFO, "%s" "deconfiging address %s failed", 665 FNAME, in6addr2str(&sp->lease_addr.addr, 0)); 666 } 667 } 668 dprintf(LOG_DEBUG, "%s" " remove all events on interface", FNAME); 669 /* cancel all outstanding events for each interface */ 670 for (ev = TAILQ_FIRST(&ifp->event_list); ev; ev = ev_next) { 671 ev_next = TAILQ_NEXT(ev, link); 672 dhcp6_remove_event(ev); 673 } 674 { 675 /* restore /etc/radv.conf.bak back to /etc/radvd.conf */ 676 if (!lstat(RADVD_CONF_BAK_FILE, &buf)) 677 rename(RADVD_CONF_BAK_FILE, RADVD_CONF_FILE); 678 /* restore /etc/resolv.conf.dhcpv6.bak back to /etc/resolv.conf */ 679 if (!lstat(RESOLV_CONF_BAK_FILE, &buf)) { 680 if (rename(RESOLV_CONF_BAK_FILE, RESOLV_CONF_FILE)) 681 dprintf(LOG_ERR, "%s" " failed to backup resolv.conf", FNAME); 682 } 683 } 684 free_servers(ifp); 685} 686 687static void 688process_signals() 689{ 690 if ((sig_flags & SIGF_TERM)) { 691 dprintf(LOG_INFO, FNAME "exiting"); 692 693 /* Foxconn added start pling 09/10/2010 */ 694 /* Release IANA/IAPD before exiting */ 695 create_request_list(0); 696 client6_send_newstate(dhcp6_if, DHCP6S_RELEASE); 697 /* Foxconn added end pling 09/10/2010 */ 698 699 free_resources(dhcp6_if); 700 unlink(DHCP6C_PIDFILE); 701 exit(0); 702 } 703 if ((sig_flags & SIGF_HUP)) { 704 dprintf(LOG_INFO, FNAME "restarting"); 705 706 /* Foxconn added start pling 09/10/2010 */ 707 /* Release IANA/IAPD before restarting */ 708 create_request_list(0); 709 client6_send_newstate(dhcp6_if, DHCP6S_RELEASE); 710 /* Foxconn added end pling 09/10/2010 */ 711 712 free_resources(dhcp6_if); 713 client6_ifinit(device); 714 } 715 if ((sig_flags & SIGF_CLEAN)) { 716 717 /* Foxconn added start pling 09/10/2010 */ 718 /* Release IANA/IAPD before exiting */ 719 create_request_list(0); 720 client6_send_newstate(dhcp6_if, DHCP6S_RELEASE); 721 /* Foxconn added end pling 09/10/2010 */ 722 723 free_resources(dhcp6_if); 724 exit(0); 725 } 726 sig_flags = 0; 727} 728 729static void 730client6_mainloop() 731{ 732 struct timeval *w; 733 int ret; 734 fd_set r; 735 736 while(1) { 737 if (sig_flags) 738 process_signals(); 739 w = dhcp6_check_timer(); 740 741 FD_ZERO(&r); 742 FD_SET(insock, &r); 743 744 ret = select(insock + 1, &r, NULL, NULL, w); 745 switch (ret) { 746 case -1: 747 if (errno != EINTR) { 748 dprintf(LOG_ERR, "%s" "select: %s", 749 FNAME, strerror(errno)); 750 exit(1); 751 } 752 break; 753 case 0: /* timeout */ 754 break; /* dhcp6_check_timer() will treat the case */ 755 default: /* received a packet */ 756 client6_recv(); 757 } 758 } 759} 760 761struct dhcp6_timer * 762client6_timo(arg) 763 void *arg; 764{ 765 struct dhcp6_event *ev = (struct dhcp6_event *)arg; 766 struct dhcp6_if *ifp; 767 struct timeval now; 768 769 ifp = ev->ifp; 770 ev->timeouts++; 771 gettimeofday(&now, NULL); 772 if ((ev->max_retrans_cnt && ev->timeouts >= ev->max_retrans_cnt) || 773 (ev->max_retrans_dur && (now.tv_sec - ev->start_time.tv_sec) 774 >= ev->max_retrans_dur)) { 775 dprintf(LOG_INFO, "%s" "no responses were received", FNAME); 776 777 /* Foxconn added start pling 10/07/2010 */ 778 /* WNR3500L TD170, after multiple re-transmit of REQUEST 779 * message, if we did not receive a valid response, 780 * go back to SOLICIT state */ 781 if (ev->state == DHCP6S_REQUEST) { 782 ev->timeouts = 0; 783 free_servers(ifp); 784 ev->state = DHCP6S_SOLICIT; 785 dhcp6_set_timeoparam(ev); 786 client6_send(ev); 787 dhcp6_reset_timer(ev); 788 return (ev->timer); 789 } 790 /* Foxconn added end pling 10/07/2010 */ 791 792 dhcp6_remove_event(ev); 793 return (NULL); 794 } 795 796 switch(ev->state) { 797 case DHCP6S_INIT: 798 /* From INIT state client could 799 * go to CONFIRM state if the client reboots; 800 * go to RELEASE state if the client issues a release; 801 * go to INFOREQ state if the client requests info-only; 802 * go to SOLICIT state if the client requests addresses; 803 */ 804 ev->timeouts = 0; /* indicate to generate a new XID. */ 805 /* 806 * three cases client send information request: 807 * 1. configuration file includes information-only 808 * 2. command line includes -I 809 * 3. check interface flags if managed bit isn't set and 810 * if otherconf bit set by RA 811 * and information-only, conmand line -I are not set. 812 */ 813 if ((ifp->send_flags & DHCIFF_INFO_ONLY) || 814 /* Foxconn modified start pling 09/15/2011 */ 815 /* Ignore the "M" and "O" flags in RA. Just send DHCP solicit */ 816 (client6_request_flag & CLIENT6_INFO_REQ) /* || 817 (!(ifp->ra_flag & IF_RA_MANAGED) && 818 (ifp->ra_flag & IF_RA_OTHERCONF))*/ ) 819 /* Foxconn modified end pling 09/15/2011 */ 820 ev->state = DHCP6S_INFOREQ; 821 else if (client6_request_flag & CLIENT6_RELEASE_ADDR) 822 /* do release */ 823 ev->state = DHCP6S_RELEASE; 824 else if (client6_request_flag & CLIENT6_CONFIRM_ADDR) { 825 struct dhcp6_listval *lv; 826 /* do confirm for reboot for IANA, IATA*/ 827 if (client6_iaidaddr.client6_info.type == IAPD) 828 ev->state = DHCP6S_REBIND; 829 else 830 ev->state = DHCP6S_CONFIRM; 831 for (lv = TAILQ_FIRST(&request_list); lv; 832 lv = TAILQ_NEXT(lv, link)) { 833 lv->val_dhcp6addr.preferlifetime = 0; 834 lv->val_dhcp6addr.validlifetime = 0; 835 } 836 } else 837 ev->state = DHCP6S_SOLICIT; 838 dhcp6_set_timeoparam(ev); 839 840 /* Foxconn added start pling 10/14/2010 */ 841 /* In auto-detect mode, we only send the SOLICIT messages 842 * 3 times. 843 */ 844 if (ifp->send_flags & DHCIFF_SOLICIT_ONLY) { 845 ev->max_retrans_cnt = SOL_MAX_RC_AUTODETECT; 846 dprintf(LOG_ERR, "%s" "Set SOLICIT message to %d times", 847 FNAME, SOL_MAX_RC_AUTODETECT); 848 } 849 /* Foxconn added end pling 10/14/2010 */ 850 851 case DHCP6S_SOLICIT: 852 if (ifp->servers) { 853 ifp->current_server = select_server(ifp); 854 if (ifp->current_server == NULL) { 855 /* this should not happen! */ 856 dprintf(LOG_ERR, "%s" "can't find a server", 857 FNAME); 858 exit(1); 859 } 860 /* if get the address assginment break */ 861 if (!TAILQ_EMPTY(&client6_iaidaddr.lease_list)) { 862 dhcp6_remove_event(ev); 863 return (NULL); 864 } 865 ev->timeouts = 0; 866 ev->state = DHCP6S_REQUEST; 867 dhcp6_set_timeoparam(ev); 868 } 869 /* Foxconn added start pling 10/14/2010 */ 870 /* In auto-detect mode, we need to send two SOLICIT 871 * messages, one with IANA+IAPD, one with IAPD only. 872 */ 873 if (ifp->send_flags & DHCIFF_SOLICIT_ONLY) { 874 client6_send(ev); 875 ifp->send_flags |= DHCIFF_PREFIX_DELEGATION; 876 client6_send(ev); 877 ifp->send_flags &=~ DHCIFF_PREFIX_DELEGATION; 878 break; /* don't fall through */ 879 } 880 /* Foxconn added end pling 10/14/2010 */ 881 //case DHCP6S_INFOREQ: // Foxconn removed pling 10/05/2010 */ 882 case DHCP6S_REQUEST: 883 client6_send(ev); 884 break; 885 886 /* Foxconn added start pling 10/05/2010 */ 887 /* Use different function to send INFO-REQ */ 888 case DHCP6S_INFOREQ: 889 client6_send_info_req(ev); 890 break; 891 /* Foxconn added end pling 10/05/2010 */ 892 893 case DHCP6S_RELEASE: 894 case DHCP6S_DECLINE: 895 case DHCP6S_CONFIRM: 896 case DHCP6S_RENEW: 897 case DHCP6S_REBIND: 898 if (!TAILQ_EMPTY(&request_list)) 899 client6_send(ev); 900 else { 901 dprintf(LOG_INFO, "%s" 902 "all information to be updated were canceled", 903 FNAME); 904 dhcp6_remove_event(ev); 905 return (NULL); 906 } 907 break; 908 default: 909 break; 910 } 911 dhcp6_reset_timer(ev); 912 return (ev->timer); 913} 914 915static struct dhcp6_serverinfo * 916select_server(ifp) 917 struct dhcp6_if *ifp; 918{ 919 struct dhcp6_serverinfo *s; 920 921 for (s = ifp->servers; s; s = s->next) { 922 if (s->active) { 923 dprintf(LOG_DEBUG, "%s" "picked a server (ID: %s)", 924 FNAME, duidstr(&s->optinfo.serverID)); 925 return (s); 926 } 927 } 928 929 return (NULL); 930} 931 932static void 933client6_signal(sig) 934 int sig; 935{ 936 937 dprintf(LOG_INFO, FNAME "received a signal (%d)", sig); 938 939 switch (sig) { 940 case SIGTERM: 941 sig_flags |= SIGF_TERM; 942 break; 943 case SIGHUP: 944 sig_flags |= SIGF_HUP; 945 break; 946 case SIGINT: 947 case SIGKILL: 948 sig_flags |= SIGF_CLEAN; 949 break; 950 default: 951 break; 952 } 953} 954 955void 956client6_send(ev) 957 struct dhcp6_event *ev; 958{ 959 struct dhcp6_if *ifp; 960 char buf[BUFSIZ]; 961 struct sockaddr_in6 dst; 962 struct dhcp6 *dh6; 963 struct dhcp6_optinfo optinfo; 964 ssize_t optlen, len; 965 struct timeval duration, now; 966 967 ifp = ev->ifp; 968 969 dh6 = (struct dhcp6 *)buf; 970 memset(dh6, 0, sizeof(*dh6)); 971 972 switch(ev->state) { 973 case DHCP6S_SOLICIT: 974 dh6->dh6_msgtype = DH6_SOLICIT; 975 break; 976 case DHCP6S_REQUEST: 977 if (ifp->current_server == NULL) { 978 dprintf(LOG_ERR, "%s" "assumption failure", FNAME); 979 exit(1); 980 } 981 dh6->dh6_msgtype = DH6_REQUEST; 982 break; 983 case DHCP6S_RENEW: 984 if (ifp->current_server == NULL) { 985 dprintf(LOG_ERR, "%s" "assumption failure", FNAME); 986 exit(1); 987 } 988 dh6->dh6_msgtype = DH6_RENEW; 989 break; 990 case DHCP6S_DECLINE: 991 if (ifp->current_server == NULL) { 992 dprintf(LOG_ERR, "%s" "assumption failure", FNAME); 993 exit(1); 994 } 995 dh6->dh6_msgtype = DH6_DECLINE; 996 break; 997 case DHCP6S_INFOREQ: 998 dh6->dh6_msgtype = DH6_INFORM_REQ; 999 break; 1000 case DHCP6S_REBIND: 1001 dh6->dh6_msgtype = DH6_REBIND; 1002 break; 1003 case DHCP6S_CONFIRM: 1004 dh6->dh6_msgtype = DH6_CONFIRM; 1005 break; 1006 case DHCP6S_RELEASE: 1007 dh6->dh6_msgtype = DH6_RELEASE; 1008 break; 1009 default: 1010 dprintf(LOG_ERR, "%s" "unexpected state %d", FNAME, ev->state); 1011 exit(1); 1012 } 1013 /* 1014 * construct options 1015 */ 1016 dhcp6_init_options(&optinfo); 1017 if (ev->timeouts == 0) { 1018 gettimeofday(&ev->start_time, NULL); 1019 optinfo.elapsed_time = 0; 1020 /* 1021 * A client SHOULD generate a random number that cannot easily 1022 * be guessed or predicted to use as the transaction ID for 1023 * each new message it sends. 1024 * 1025 * A client MUST leave the transaction-ID unchanged in 1026 * retransmissions of a message. [dhcpv6-26 15.1] 1027 */ 1028 ev->xid = random() & DH6_XIDMASK; 1029 1030 /* Foxconn added start pling 10/07/2010 */ 1031 /* For Testing purposes !!! */ 1032 if (ev->state == DHCP6S_SOLICIT && xid_solicit) { 1033 dprintf(LOG_DEBUG, "%s" 1034 "**TESTING** Use user-defined xid_sol %lu", FNAME, xid_solicit); 1035 ev->xid = xid_solicit & DH6_XIDMASK; 1036 } else if (ev->state == DHCP6S_REQUEST && xid_request) { 1037 dprintf(LOG_DEBUG, "%s" 1038 "**TESTING** Use user-defined xid_req %lu", FNAME, xid_request); 1039 ev->xid = xid_request & DH6_XIDMASK; 1040 } 1041 /* Foxconn added end pling 10/07/2010 */ 1042 1043 dprintf(LOG_DEBUG, "%s" "ifp %p event %p a new XID (%x) is generated", 1044 FNAME, ifp, ev, ev->xid); 1045 } else { 1046 unsigned int etime; 1047 gettimeofday(&now, NULL); 1048 timeval_sub(&now, &(ev->start_time), &duration); 1049 optinfo.elapsed_time = 1050 etime = (duration.tv_sec) * 100 + (duration.tv_usec) / 10000; 1051 if (etime > DHCP6_ELAPSEDTIME_MAX) 1052 optinfo.elapsed_time = DHCP6_ELAPSEDTIME_MAX; 1053 else 1054 optinfo.elapsed_time = etime; 1055 } 1056 dh6->dh6_xid &= ~ntohl(DH6_XIDMASK); 1057 dh6->dh6_xid |= htonl(ev->xid); 1058 len = sizeof(*dh6); 1059 1060 1061 /* server ID */ 1062 switch(ev->state) { 1063 case DHCP6S_REQUEST: 1064 case DHCP6S_RENEW: 1065 case DHCP6S_DECLINE: 1066 if (&ifp->current_server->optinfo == NULL) 1067 exit(1); 1068 dprintf(LOG_DEBUG, "current server ID %s", 1069 duidstr(&ifp->current_server->optinfo.serverID)); 1070 if (duidcpy(&optinfo.serverID, 1071 &ifp->current_server->optinfo.serverID)) { 1072 dprintf(LOG_ERR, "%s" "failed to copy server ID", 1073 FNAME); 1074 goto end; 1075 } 1076 break; 1077 case DHCP6S_RELEASE: 1078 if (duidcpy(&optinfo.serverID, &client6_iaidaddr.client6_info.serverid)) { 1079 dprintf(LOG_ERR, "%s" "failed to copy server ID", FNAME); 1080 goto end; 1081 } 1082 break; 1083 } 1084 /* client ID */ 1085 if (duidcpy(&optinfo.clientID, &client_duid)) { 1086 dprintf(LOG_ERR, "%s" "failed to copy client ID", FNAME); 1087 goto end; 1088 } 1089 1090 /* Foxconn added start pling 09/07/2010 */ 1091 /* User-class */ 1092 strcpy(optinfo.user_class, ifp->user_class); 1093 /* Foxconn added end pling 09/07/2010 */ 1094 1095 /* option request options */ 1096 /* Foxconn added start pling 10/01/2010 */ 1097 /* DHCPv6 readylogo: DHCP confirm message should not 1098 * have request for DNS/Domain list. 1099 */ 1100 if (ev->state != DHCP6S_CONFIRM) 1101 /* Foxconn added end pling 10/01/2010 */ 1102 if (dhcp6_copy_list(&optinfo.reqopt_list, &ifp->reqopt_list)) { 1103 dprintf(LOG_ERR, "%s" "failed to copy requested options", 1104 FNAME); 1105 goto end; 1106 } 1107 1108 switch(ev->state) { 1109 case DHCP6S_SOLICIT: 1110 /* rapid commit */ 1111 if (ifp->send_flags & DHCIFF_RAPID_COMMIT) 1112 optinfo.flags |= DHCIFF_RAPID_COMMIT; 1113 if (!(ifp->send_flags & DHCIFF_INFO_ONLY) || 1114 (client6_request_flag & CLIENT6_REQUEST_ADDR)) { 1115 memcpy(&optinfo.iaidinfo, &client6_iaidaddr.client6_info.iaidinfo, 1116 sizeof(optinfo.iaidinfo)); 1117 if (ifp->send_flags & DHCIFF_PREFIX_DELEGATION) 1118 optinfo.type = IAPD; 1119 else if (ifp->send_flags & DHCIFF_TEMP_ADDRS) 1120 optinfo.type = IATA; 1121 else 1122 optinfo.type = IANA; 1123 } 1124 /* support for client preferred ipv6 address */ 1125 if (client6_request_flag & CLIENT6_REQUEST_ADDR) { 1126 if (dhcp6_copy_list(&optinfo.addr_list, &request_list)) 1127 goto end; 1128 } 1129 /* Foxconn added start pling 10/14/2010 */ 1130 /* In auto-detect mode, we need to send two SOLICIT 1131 * messages. 2nd one has IAPD only. 1132 */ 1133 if ((ifp->send_flags & DHCIFF_SOLICIT_ONLY) && 1134 (ifp->send_flags & DHCIFF_PREFIX_DELEGATION)) { 1135 optinfo.type = IAPD; 1136 } 1137 /* Foxconn added end pling 10/14/2010 */ 1138 break; 1139 case DHCP6S_REQUEST: 1140 if (!(ifp->send_flags & DHCIFF_INFO_ONLY)) { 1141 /* Foxconn modified start pling 08/20/2009 */ 1142 /* Should copy 'current_server's addr info */ 1143#if 0 1144 memcpy(&optinfo.iaidinfo, &client6_iaidaddr.client6_info.iaidinfo, 1145 sizeof(optinfo.iaidinfo)); 1146#endif 1147 memcpy(&optinfo.iaidinfo, &(ifp->current_server->optinfo.iaidinfo), 1148 sizeof(optinfo.iaidinfo)); 1149 if (dhcp6_copy_list(&optinfo.addr_list, &(ifp->current_server->optinfo.addr_list))) 1150 goto end; 1151 if (dhcp6_copy_list(&optinfo.prefix_list, 1152 &(ifp->current_server->optinfo.prefix_list))) 1153 goto end; 1154 /* Foxconn modified end pling 08/20/2009 */ 1155 dprintf(LOG_DEBUG, "%s IAID is %u", FNAME, optinfo.iaidinfo.iaid); 1156 if (ifp->send_flags & DHCIFF_TEMP_ADDRS) 1157 optinfo.type = IATA; 1158 else if (ifp->send_flags & DHCIFF_PREFIX_DELEGATION) 1159 optinfo.type = IAPD; 1160 else 1161 optinfo.type = IANA; 1162 } 1163 break; 1164 case DHCP6S_RENEW: 1165 case DHCP6S_REBIND: 1166 case DHCP6S_RELEASE: 1167 case DHCP6S_CONFIRM: 1168 case DHCP6S_DECLINE: 1169 memcpy(&optinfo.iaidinfo, &client6_iaidaddr.client6_info.iaidinfo, 1170 sizeof(optinfo.iaidinfo)); 1171 optinfo.type = client6_iaidaddr.client6_info.type; 1172 if (ev->state == DHCP6S_CONFIRM) { 1173 optinfo.iaidinfo.renewtime = 0; 1174 optinfo.iaidinfo.rebindtime = 0; 1175 } 1176 if (!TAILQ_EMPTY(&request_list)) { 1177 if (dhcp6_copy_list(&optinfo.addr_list, &request_list)) 1178 goto end; 1179 } else { 1180 if (ev->state == DHCP6S_RELEASE) { 1181 dprintf(LOG_INFO, "release empty address list"); 1182 exit(1); 1183 } 1184 } 1185 /* Foxconn added start pling 09/24/2009 */ 1186 /* PUt the IAPD prefix in the DHCP packet */ 1187 if (!TAILQ_EMPTY(&request_prefix_list)) { 1188 if (dhcp6_copy_list(&optinfo.prefix_list, &request_prefix_list)) 1189 goto end; 1190 } 1191 /* Foxconn added end pling 09/24/2009 */ 1192 if (client6_request_flag & CLIENT6_RELEASE_ADDR) { 1193 if (dhcp6_update_iaidaddr(&optinfo, ADDR_REMOVE)) { 1194 dprintf(LOG_INFO, "client release failed"); 1195 exit(1); 1196 } 1197 if (client6_iaidaddr.client6_info.type == IAPD) 1198 radvd_parse(&client6_iaidaddr, ADDR_REMOVE); 1199 } 1200 break; 1201 default: 1202 break; 1203 } 1204 /* set options in the message */ 1205 if ((optlen = dhcp6_set_options((struct dhcp6opt *)(dh6 + 1), 1206 (struct dhcp6opt *)(buf + sizeof(buf)), 1207 &optinfo)) < 0) { 1208 dprintf(LOG_INFO, "%s" "failed to construct options", FNAME); 1209 goto end; 1210 } 1211 len += optlen; 1212 1213 /* 1214 * Unless otherwise specified, a client sends DHCP messages to the 1215 * All_DHCP_Relay_Agents_and_Servers or the DHCP_Anycast address. 1216 * [dhcpv6-26 Section 13.] 1217 * Our current implementation always follows the case. 1218 */ 1219 switch(ev->state) { 1220 case DHCP6S_REQUEST: 1221 case DHCP6S_RENEW: 1222 case DHCP6S_DECLINE: 1223 case DHCP6S_RELEASE: 1224 if (ifp->current_server && 1225 !IN6_IS_ADDR_UNSPECIFIED(&ifp->current_server->server_addr)) { 1226 struct addrinfo hints, *res; 1227 int error; 1228 memset(&hints, 0, sizeof(hints)); 1229 hints.ai_family = PF_INET6; 1230 hints.ai_socktype = SOCK_DGRAM; 1231 hints.ai_protocol = IPPROTO_UDP; 1232 error = getaddrinfo(in6addr2str(&ifp->current_server->server_addr,0), 1233 DH6PORT_UPSTREAM, &hints, &res); 1234 if (error) { 1235 dprintf(LOG_ERR, "%s" "getaddrinfo: %s", 1236 FNAME, gai_strerror(error)); 1237 exit(1); 1238 } 1239 memcpy(&dst, res->ai_addr, res->ai_addrlen); 1240 break; 1241 } 1242 default: 1243 dst = *sa6_allagent; 1244 break; 1245 } 1246 dst.sin6_scope_id = ifp->linkid; 1247 dprintf(LOG_DEBUG, "send dst if %s addr is %s scope id is %d", 1248 ifp->ifname, addr2str((struct sockaddr *)&dst), ifp->linkid); 1249 /* Foxconn modified start pling 08/15/2009 */ 1250 /* why use 'outsock' here? */ 1251 //if (sendto(ifp->outsock, buf, len, MSG_DONTROUTE, (struct sockaddr *)&dst, 1252 if (sendto(insock, buf, len, MSG_DONTROUTE, (struct sockaddr *)&dst, 1253 /* Foxconn modified end pling 08/15/2009 */ 1254 sizeof(dst)) == -1) { 1255 dprintf(LOG_ERR, FNAME "transmit failed: %s", strerror(errno)); 1256 goto end; 1257 } 1258 1259 dprintf(LOG_DEBUG, "%s" "send %s to %s", FNAME, 1260 dhcp6msgstr(dh6->dh6_msgtype), 1261 addr2str((struct sockaddr *)&dst)); 1262 1263 end: 1264 dhcp6_clear_options(&optinfo); 1265 return; 1266} 1267 1268/* Foxconn added end pling 01/25/2010 */ 1269void 1270client6_send_info_req(ev) 1271 struct dhcp6_event *ev; 1272{ 1273 struct dhcp6_if *ifp; 1274 char buf[BUFSIZ]; 1275 struct sockaddr_in6 dst; 1276 struct dhcp6 *dh6; 1277 struct dhcp6_optinfo optinfo; 1278 ssize_t optlen, len; 1279 struct timeval duration, now; 1280 1281 ifp = ev->ifp; 1282 1283 dh6 = (struct dhcp6 *)buf; 1284 memset(dh6, 0, sizeof(*dh6)); 1285 1286 dh6->dh6_msgtype = DH6_INFORM_REQ; 1287 1288 /* 1289 * construct options 1290 */ 1291 dhcp6_init_options(&optinfo); 1292 if (ev->timeouts == 0) { 1293 gettimeofday(&ev->start_time, NULL); 1294 optinfo.elapsed_time = 0; 1295 /* 1296 * A client SHOULD generate a random number that cannot easily 1297 * be guessed or predicted to use as the transaction ID for 1298 * each new message it sends. 1299 * 1300 * A client MUST leave the transaction-ID unchanged in 1301 * retransmissions of a message. [dhcpv6-26 15.1] 1302 */ 1303 ev->xid = random() & DH6_XIDMASK; 1304 dprintf(LOG_DEBUG, "%s" "ifp %p event %p a new XID (%x) is generated", 1305 FNAME, ifp, ev, ev->xid); 1306 } else { 1307 unsigned int etime; 1308 gettimeofday(&now, NULL); 1309 timeval_sub(&now, &(ev->start_time), &duration); 1310 optinfo.elapsed_time = 1311 etime = (duration.tv_sec) * 100 + (duration.tv_usec) / 10000; 1312 if (etime > DHCP6_ELAPSEDTIME_MAX) 1313 optinfo.elapsed_time = DHCP6_ELAPSEDTIME_MAX; 1314 else 1315 optinfo.elapsed_time = etime; 1316 } 1317 dh6->dh6_xid &= ~ntohl(DH6_XIDMASK); 1318 dh6->dh6_xid |= htonl(ev->xid); 1319 len = sizeof(*dh6); 1320 1321 /* client ID */ 1322 if (duidcpy(&optinfo.clientID, &client_duid)) { 1323 dprintf(LOG_ERR, "%s" "failed to copy client ID", FNAME); 1324 goto end; 1325 } 1326 1327 /* Foxconn added start pling 09/07/2010 */ 1328 /* User-class */ 1329 strcpy(optinfo.user_class, ifp->user_class); 1330 /* Foxconn added end pling 09/07/2010 */ 1331 1332 /* option request options */ 1333 if (dhcp6_copy_list(&optinfo.reqopt_list, &ifp->reqopt_list)) { 1334 dprintf(LOG_ERR, "%s" "failed to copy requested options", 1335 FNAME); 1336 goto end; 1337 } 1338 1339 /* set options in the message */ 1340 if ((optlen = dhcp6_set_options((struct dhcp6opt *)(dh6 + 1), 1341 (struct dhcp6opt *)(buf + sizeof(buf)), 1342 &optinfo)) < 0) { 1343 dprintf(LOG_INFO, "%s" "failed to construct options", FNAME); 1344 goto end; 1345 } 1346 len += optlen; 1347 1348 /* Special hack to add SIP server and NTP server options */ 1349 buf[len-3] += 4; 1350 buf[len++] = 0; 1351 buf[len++] = DH6OPT_SIP_SERVERS; 1352 buf[len++] = 0; 1353 buf[len++] = DH6OPT_NTP_SERVERS; 1354 1355 /* 1356 * Unless otherwise specified, a client sends DHCP messages to the 1357 * All_DHCP_Relay_Agents_and_Servers or the DHCP_Anycast address. 1358 * [dhcpv6-26 Section 13.] 1359 * Our current implementation always follows the case. 1360 */ 1361 switch(ev->state) { 1362 case DHCP6S_REQUEST: 1363 case DHCP6S_RENEW: 1364 case DHCP6S_DECLINE: 1365 case DHCP6S_RELEASE: 1366 if (ifp->current_server && 1367 !IN6_IS_ADDR_UNSPECIFIED(&ifp->current_server->server_addr)) { 1368 struct addrinfo hints, *res; 1369 int error; 1370 memset(&hints, 0, sizeof(hints)); 1371 hints.ai_family = PF_INET6; 1372 hints.ai_socktype = SOCK_DGRAM; 1373 hints.ai_protocol = IPPROTO_UDP; 1374 error = getaddrinfo(in6addr2str(&ifp->current_server->server_addr,0), 1375 DH6PORT_UPSTREAM, &hints, &res); 1376 if (error) { 1377 dprintf(LOG_ERR, "%s" "getaddrinfo: %s", 1378 FNAME, gai_strerror(error)); 1379 exit(1); 1380 } 1381 memcpy(&dst, res->ai_addr, res->ai_addrlen); 1382 break; 1383 } 1384 default: 1385 dst = *sa6_allagent; 1386 break; 1387 } 1388 dst.sin6_scope_id = ifp->linkid; 1389 dprintf(LOG_DEBUG, "send dst if %s addr is %s scope id is %d", 1390 ifp->ifname, addr2str((struct sockaddr *)&dst), ifp->linkid); 1391 /* Foxconn modified start pling 08/15/2009 */ 1392 /* why use 'outsock' here? */ 1393 //if (sendto(ifp->outsock, buf, len, MSG_DONTROUTE, (struct sockaddr *)&dst, 1394 if (sendto(insock, buf, len, MSG_DONTROUTE, (struct sockaddr *)&dst, 1395 /* Foxconn modified end pling 08/15/2009 */ 1396 sizeof(dst)) == -1) { 1397 dprintf(LOG_ERR, FNAME "transmit failed: %s", strerror(errno)); 1398 goto end; 1399 } 1400 1401 dprintf(LOG_DEBUG, "%s" "send %s to %s", FNAME, 1402 dhcp6msgstr(dh6->dh6_msgtype), 1403 addr2str((struct sockaddr *)&dst)); 1404 1405 end: 1406 dhcp6_clear_options(&optinfo); 1407 return; 1408} 1409/* Foxconn added end pling 01/25/2010 */ 1410 1411static void 1412client6_recv() 1413{ 1414 char rbuf[BUFSIZ], cmsgbuf[BUFSIZ]; 1415 struct msghdr mhdr; 1416 struct iovec iov; 1417 struct sockaddr_storage from; 1418 struct dhcp6_if *ifp; 1419 struct dhcp6opt *p, *ep; 1420 struct dhcp6_optinfo optinfo; 1421 ssize_t len; 1422 struct dhcp6 *dh6; 1423 struct cmsghdr *cm; 1424 struct in6_pktinfo *pi = NULL; 1425 1426 memset(&iov, 0, sizeof(iov)); 1427 memset(&mhdr, 0, sizeof(mhdr)); 1428 1429 iov.iov_base = (caddr_t)rbuf; 1430 iov.iov_len = sizeof(rbuf); 1431 mhdr.msg_name = (caddr_t)&from; 1432 mhdr.msg_namelen = sizeof(from); 1433 mhdr.msg_iov = &iov; 1434 mhdr.msg_iovlen = 1; 1435 mhdr.msg_control = (caddr_t)cmsgbuf; 1436 mhdr.msg_controllen = sizeof(cmsgbuf); 1437 if ((len = recvmsg(insock, &mhdr, 0)) < 0) { 1438 dprintf(LOG_ERR, "%s" "recvmsg: %s", FNAME, strerror(errno)); 1439 return; 1440 } 1441 1442 /* detect receiving interface */ 1443 for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(&mhdr); cm; 1444 cm = (struct cmsghdr *)CMSG_NXTHDR(&mhdr, cm)) { 1445 if (cm->cmsg_level == IPPROTO_IPV6 && 1446 cm->cmsg_type == IPV6_PKTINFO && 1447 cm->cmsg_len == CMSG_LEN(sizeof(struct in6_pktinfo))) { 1448 pi = (struct in6_pktinfo *)(CMSG_DATA(cm)); 1449 } 1450 } 1451 if (pi == NULL) { 1452 dprintf(LOG_NOTICE, "%s" "failed to get packet info", FNAME); 1453 return; 1454 } 1455 if ((ifp = find_ifconfbyid(pi->ipi6_ifindex)) == NULL) { 1456 dprintf(LOG_INFO, "%s" "unexpected interface (%d)", FNAME, 1457 (unsigned int)pi->ipi6_ifindex); 1458 return; 1459 } 1460 dprintf(LOG_DEBUG, "receive packet info ifname %s, addr is %s scope id is %d", 1461 ifp->ifname, in6addr2str(&pi->ipi6_addr, 0), pi->ipi6_ifindex); 1462 dh6 = (struct dhcp6 *)rbuf; 1463 1464 dprintf(LOG_DEBUG, "%s" "receive %s from %s scope id %d %s", FNAME, 1465 dhcp6msgstr(dh6->dh6_msgtype), 1466 addr2str((struct sockaddr *)&from), 1467 ((struct sockaddr_in6 *)&from)->sin6_scope_id, 1468 ifp->ifname); 1469 1470 /* get options */ 1471 dhcp6_init_options(&optinfo); 1472 p = (struct dhcp6opt *)(dh6 + 1); 1473 ep = (struct dhcp6opt *)((char *)dh6 + len); 1474 1475 /* Foxconn modified start pling 10/04/2010 */ 1476 /* Pass some extra arguments to 'dhcp6_get_options' 1477 * to better determine whether this packet is ok or not. 1478 */ 1479 struct dhcp6_event *ev; 1480 ev = find_event_withid(ifp, ntohl(dh6->dh6_xid) & DH6_XIDMASK); 1481 if (ev == NULL) { 1482 dprintf(LOG_INFO, "%s" "XID mismatch", FNAME); 1483 return; 1484 } 1485 if (dhcp6_get_options(p, ep, &optinfo, dh6->dh6_msgtype, 1486 ev->state, ifp->send_flags) < 0) { 1487 //if (dhcp6_get_options(p, ep, &optinfo) < 0) { 1488 /* Foxconn modified end pling 10/04/2010 */ 1489 dprintf(LOG_INFO, "%s" "failed to parse options", FNAME); 1490#ifdef TEST 1491 return; 1492#endif 1493 } 1494 1495 switch(dh6->dh6_msgtype) { 1496 case DH6_ADVERTISE: 1497 (void)client6_recvadvert(ifp, dh6, len, &optinfo); 1498 break; 1499 case DH6_REPLY: 1500 (void)client6_recvreply(ifp, dh6, len, &optinfo); 1501 break; 1502 default: 1503 dprintf(LOG_INFO, "%s" "received an unexpected message (%s) " 1504 "from %s", FNAME, dhcp6msgstr(dh6->dh6_msgtype), 1505 addr2str((struct sockaddr *)&from)); 1506 break; 1507 } 1508 1509 dhcp6_clear_options(&optinfo); 1510 return; 1511} 1512 1513static int 1514client6_recvadvert(ifp, dh6, len, optinfo0) 1515 struct dhcp6_if *ifp; 1516 struct dhcp6 *dh6; 1517 ssize_t len; 1518 struct dhcp6_optinfo *optinfo0; 1519{ 1520 struct dhcp6_serverinfo *newserver; 1521 struct dhcp6_event *ev; 1522 struct dhcp6_listval *lv; 1523 1524 /* find the corresponding event based on the received xid */ 1525 ev = find_event_withid(ifp, ntohl(dh6->dh6_xid) & DH6_XIDMASK); 1526 if (ev == NULL) { 1527 dprintf(LOG_INFO, "%s" "XID mismatch", FNAME); 1528 return -1; 1529 } 1530 /* if server policy doesn't allow rapid commit 1531 if (ev->state != DHCP6S_SOLICIT || 1532 (ifp->send_flags & DHCIFF_RAPID_COMMIT)) { 1533 */ 1534 if (ev->state != DHCP6S_SOLICIT) { 1535 dprintf(LOG_INFO, "%s" "unexpected advertise", FNAME); 1536 return -1; 1537 } 1538 1539 /* packet validation based on Section 15.3 of dhcpv6-26. */ 1540 if (optinfo0->serverID.duid_len == 0) { 1541 dprintf(LOG_INFO, "%s" "no server ID option", FNAME); 1542 return -1; 1543 } else { 1544 dprintf(LOG_DEBUG, "%s" "server ID: %s, pref=%2x", FNAME, 1545 duidstr(&optinfo0->serverID), 1546 optinfo0->pref); 1547 } 1548 if (optinfo0->clientID.duid_len == 0) { 1549 dprintf(LOG_INFO, "%s" "no client ID option", FNAME); 1550 return -1; 1551 } 1552 if (duidcmp(&optinfo0->clientID, &client_duid)) { 1553 dprintf(LOG_INFO, "%s" "client DUID mismatch", FNAME); 1554 return -1; 1555 } 1556 1557 /* 1558 * The client MUST ignore any Advertise message that includes a Status 1559 * Code option containing any error. 1560 */ 1561 for (lv = TAILQ_FIRST(&optinfo0->stcode_list); lv; 1562 lv = TAILQ_NEXT(lv, link)) { 1563 dprintf(LOG_INFO, "%s" "status code: %s", 1564 FNAME, dhcp6_stcodestr(lv->val_num)); 1565 if (lv->val_num != DH6OPT_STCODE_SUCCESS) { 1566 return (-1); 1567 } 1568 } 1569 1570 /* ignore the server if it is known */ 1571 if (find_server(ifp, &optinfo0->serverID)) { 1572 dprintf(LOG_INFO, "%s" "duplicated server (ID: %s)", 1573 FNAME, duidstr(&optinfo0->serverID)); 1574 return -1; 1575 } 1576 1577 /* Foxconn added start pling 08/26/2009 */ 1578 /* In Ipv6 auto mode, write result to a file */ 1579 if (ifp->send_flags & DHCIFF_SOLICIT_ONLY) { 1580 FILE *fp = NULL; 1581 /* Foxconn modified start pling 10/14/2010 */ 1582 /* For auto-detect mode, if recv ADVERTISE mesg with 1583 * IAPD-only, write to different file. 1584 */ 1585 if (optinfo0->type == IAPD) 1586 fp = fopen("/tmp/wan_dhcp6c_iapd", "w"); 1587 else 1588 fp = fopen("/tmp/wan_dhcp6c", "w"); 1589 /* Foxconn modified end pling 10/14/2010 */ 1590 if (fp) { 1591 fprintf(fp, "1"); 1592 fclose(fp); 1593 } 1594 return 0; 1595 } 1596 /* Foxconn added end pling 08/26/2009 */ 1597 1598 newserver = allocate_newserver(ifp, optinfo0); 1599 if (newserver == NULL) 1600 return (-1); 1601 1602 /* Foxconn added start pling 08/21/2009 */ 1603 /* for some reason, 'allocate_newserver' did not copy 1604 * the IAID info. So we do it here... 1605 */ 1606 memcpy(&(newserver->optinfo.iaidinfo), 1607 &(optinfo0->iaidinfo), 1608 sizeof(struct dhcp6_iaid_info)); 1609 /* Foxconn added end pling 08/21/2009 */ 1610 1611 /* if the server has an extremely high preference, just use it. */ 1612 if (newserver->pref == DH6OPT_PREF_MAX) { 1613 ev->timeouts = 0; 1614 ev->state = DHCP6S_REQUEST; 1615 ifp->current_server = newserver; 1616 dhcp6_set_timeoparam(ev); 1617 dhcp6_reset_timer(ev); 1618 client6_send(ev); 1619 1620 } else if (ifp->servers->next == NULL) { 1621 struct timeval *rest, elapsed, tv_rt, tv_irt, timo; 1622 1623 rest = dhcp6_timer_rest(ev->timer); 1624 tv_rt.tv_sec = (ev->retrans * 1000) / 1000000; 1625 tv_rt.tv_usec = (ev->retrans * 1000) % 1000000; 1626 tv_irt.tv_sec = (ev->init_retrans * 1000) / 1000000; 1627 tv_irt.tv_usec = (ev->init_retrans * 1000) % 1000000; 1628 timeval_sub(&tv_rt, rest, &elapsed); 1629 if (TIMEVAL_LEQ(elapsed, tv_irt)) 1630 timeval_sub(&tv_irt, &elapsed, &timo); 1631 else 1632 timo.tv_sec = timo.tv_usec = 0; 1633 1634 dprintf(LOG_DEBUG, "%s" "reset timer for %s to %d.%06d", 1635 FNAME, ifp->ifname, 1636 (int)timo.tv_sec, (int)timo.tv_usec); 1637 1638 dhcp6_set_timer(&timo, ev->timer); 1639 } 1640 /* if the client send preferred addresses reqeust in SOLICIT */ 1641 if (!TAILQ_EMPTY(&optinfo0->addr_list)) 1642 dhcp6_copy_list(&request_list, &optinfo0->addr_list); 1643 /* Foxconn added start pling 09/23/2009 */ 1644 /* Store IAPD to the request_prefix_list, for later use by DHCP renew */ 1645 if (!TAILQ_EMPTY(&optinfo0->prefix_list)) 1646 dhcp6_copy_list(&request_prefix_list, &optinfo0->prefix_list); 1647 /* Foxconn added end pling 09/23/2009 */ 1648 return 0; 1649} 1650 1651static struct dhcp6_serverinfo * 1652find_server(ifp, duid) 1653 struct dhcp6_if *ifp; 1654 struct duid *duid; 1655{ 1656 struct dhcp6_serverinfo *s; 1657 1658 for (s = ifp->servers; s; s = s->next) { 1659 if (duidcmp(&s->optinfo.serverID, duid) == 0) 1660 return (s); 1661 } 1662 1663 return (NULL); 1664} 1665 1666static struct dhcp6_serverinfo * 1667allocate_newserver(ifp, optinfo) 1668 struct dhcp6_if *ifp; 1669 struct dhcp6_optinfo *optinfo; 1670{ 1671 struct dhcp6_serverinfo *newserver, **sp; 1672 1673 /* keep the server */ 1674 if ((newserver = malloc(sizeof(*newserver))) == NULL) { 1675 dprintf(LOG_ERR, "%s" "memory allocation failed for server", 1676 FNAME); 1677 return (NULL); 1678 } 1679 memset(newserver, 0, sizeof(*newserver)); 1680 dhcp6_init_options(&newserver->optinfo); 1681 if (dhcp6_copy_options(&newserver->optinfo, optinfo)) { 1682 dprintf(LOG_ERR, "%s" "failed to copy options", FNAME); 1683 free(newserver); 1684 return (NULL); 1685 } 1686 dprintf(LOG_DEBUG, "%s" "new server DUID %s, len %d ", 1687 FNAME, duidstr(&newserver->optinfo.serverID), 1688 newserver->optinfo.serverID.duid_len); 1689 if (optinfo->pref != DH6OPT_PREF_UNDEF) 1690 newserver->pref = optinfo->pref; 1691 if (optinfo->flags & DHCIFF_UNICAST) 1692 memcpy(&newserver->server_addr, &optinfo->server_addr, 1693 sizeof(newserver->server_addr)); 1694 newserver->active = 1; 1695 for (sp = &ifp->servers; *sp; sp = &(*sp)->next) { 1696 if ((*sp)->pref != DH6OPT_PREF_MAX && 1697 (*sp)->pref < newserver->pref) { 1698 break; 1699 } 1700 } 1701 newserver->next = *sp; 1702 *sp = newserver; 1703 return newserver; 1704} 1705 1706void 1707free_servers(ifp) 1708 struct dhcp6_if *ifp; 1709{ 1710 struct dhcp6_serverinfo *sp, *sp_next; 1711 /* free all servers we've seen so far */ 1712 for (sp = ifp->servers; sp; sp = sp_next) { 1713 sp_next = sp->next; 1714 dprintf(LOG_DEBUG, "%s" "removing server (ID: %s)", 1715 FNAME, duidstr(&sp->optinfo.serverID)); 1716 dhcp6_clear_options(&sp->optinfo); 1717 free(sp); 1718 } 1719 ifp->servers = NULL; 1720 ifp->current_server = NULL; 1721} 1722 1723static int not_on_link_count = 0; // Foxconn added pling 10/07/2010 1724 1725static int 1726client6_recvreply(ifp, dh6, len, optinfo) 1727 struct dhcp6_if *ifp; 1728 struct dhcp6 *dh6; 1729 ssize_t len; 1730 struct dhcp6_optinfo *optinfo; 1731{ 1732 struct dhcp6_listval *lv; 1733 struct dhcp6_event *ev; 1734 int addr_status_code = DH6OPT_STCODE_UNSPECFAIL; 1735 struct dhcp6_serverinfo *newserver; 1736 int newstate = 0; 1737 /* find the corresponding event based on the received xid */ 1738 dprintf(LOG_DEBUG, "%s" "reply message XID is (%x)", 1739 FNAME, ntohl(dh6->dh6_xid) & DH6_XIDMASK); 1740 ev = find_event_withid(ifp, ntohl(dh6->dh6_xid) & DH6_XIDMASK); 1741 if (ev == NULL) { 1742 dprintf(LOG_INFO, "%s" "XID mismatch", FNAME); 1743 return -1; 1744 } 1745 1746 if (!(DHCP6S_VALID_REPLY(ev->state)) && 1747 (ev->state != DHCP6S_SOLICIT || 1748 !(optinfo->flags & DHCIFF_RAPID_COMMIT))) { 1749 dprintf(LOG_INFO, "%s" "unexpected reply", FNAME); 1750 return -1; 1751 } 1752 1753 dhcp6_clear_list(&request_list); 1754 1755 /* A Reply message must contain a Server ID option */ 1756 if (optinfo->serverID.duid_len == 0) { 1757 dprintf(LOG_INFO, "%s" "no server ID option", FNAME); 1758 return -1; 1759 } 1760 dprintf(LOG_DEBUG, "%s" "serverID is %s len is %d", FNAME, 1761 duidstr(&optinfo->serverID), optinfo->serverID.duid_len); 1762 /* get current server */ 1763 switch (ev->state) { 1764 case DHCP6S_SOLICIT: 1765 case DHCP6S_CONFIRM: 1766 case DHCP6S_REBIND: 1767 newserver = allocate_newserver(ifp, optinfo); 1768 if (newserver == NULL) 1769 return (-1); 1770 ifp->current_server = newserver; 1771 duidcpy(&client6_iaidaddr.client6_info.serverid, 1772 &ifp->current_server->optinfo.serverID); 1773 break; 1774 default: 1775 break; 1776 } 1777 /* 1778 * DUID in the Client ID option (which must be contained for our 1779 * client implementation) must match ours. 1780 */ 1781 if (optinfo->clientID.duid_len == 0) { 1782 dprintf(LOG_INFO, "%s" "no client ID option", FNAME); 1783 return -1; 1784 } 1785 if (duidcmp(&optinfo->clientID, &client_duid)) { 1786 dprintf(LOG_INFO, "%s" "client DUID mismatch", FNAME); 1787 return -1; 1788 } 1789 1790 if (!TAILQ_EMPTY(&optinfo->dns_list.addrlist) || 1791 optinfo->dns_list.domainlist != NULL) { 1792 resolv_parse(&optinfo->dns_list); 1793 } 1794 /* 1795 * The client MAY choose to report any status code or message from the 1796 * status code option in the Reply message. 1797 * [dhcpv6-26 Section 18.1.8] 1798 */ 1799 addr_status_code = 0; 1800 for (lv = TAILQ_FIRST(&optinfo->stcode_list); lv; 1801 lv = TAILQ_NEXT(lv, link)) { 1802 dprintf(LOG_INFO, "%s" "status code: %s", 1803 FNAME, dhcp6_stcodestr(lv->val_num)); 1804 switch (lv->val_num) { 1805 case DH6OPT_STCODE_SUCCESS: 1806 case DH6OPT_STCODE_UNSPECFAIL: 1807 case DH6OPT_STCODE_NOADDRAVAIL: 1808 case DH6OPT_STCODE_NOPREFIXAVAIL: 1809 case DH6OPT_STCODE_NOBINDING: 1810 case DH6OPT_STCODE_NOTONLINK: 1811 case DH6OPT_STCODE_USEMULTICAST: 1812 if (addr_status_code == 0) // Foxconn added pling 10/07/2010, don't override error status if already set 1813 addr_status_code = lv->val_num; 1814 default: 1815 break; 1816 } 1817 } 1818 switch (addr_status_code) { 1819 case DH6OPT_STCODE_UNSPECFAIL: 1820 case DH6OPT_STCODE_USEMULTICAST: 1821 dprintf(LOG_INFO, "%s" "status code: %s", FNAME, 1822 dhcp6_stcodestr(addr_status_code)); 1823 /* retransmit the message with multicast address */ 1824 /* how many time allow the retransmission with error status code? */ 1825 return -1; 1826 } 1827 1828 /* 1829 * Update configuration information to be renewed or rebound 1830 * declined, confirmed, released. 1831 * Note that the returned list may be empty, in which case 1832 * the waiting information should be removed. 1833 */ 1834 switch (ev->state) { 1835 case DHCP6S_SOLICIT: 1836 if (optinfo->iaidinfo.iaid == 0) 1837 break; 1838 else if (!optinfo->flags & DHCIFF_RAPID_COMMIT) { 1839 newstate = DHCP6S_REQUEST; 1840 break; 1841 } 1842 case DHCP6S_REQUEST: 1843 /* NotOnLink: 1. SOLICIT 1844 * NoAddrAvail: Information Request */ 1845 switch(addr_status_code) { 1846 case DH6OPT_STCODE_NOTONLINK: 1847 dprintf(LOG_DEBUG, "%s" 1848 "got a NotOnLink reply for request/rapid commit," 1849 " sending solicit.", FNAME); 1850 /* Foxconn modified start pling 10/07/2010 */ 1851 /* WNR3500L TD170, need to send request without any IP for 1852 * 3 times, then back to solicit state. 1853 */ 1854 //newstate = DHCP6S_SOLICIT; 1855 not_on_link_count++; 1856 if (not_on_link_count <= REQ_MAX_RC_NOTONLINK) { 1857 /* Clear the IA / PD address, so they won't appear in the 1858 * request pkt. */ 1859 dhcp6_clear_list(&(ifp->current_server->optinfo.addr_list)); 1860 dhcp6_clear_list(&(ifp->current_server->optinfo.prefix_list)); 1861 newstate = DHCP6S_REQUEST; 1862 } else { 1863 /* Three times, back to SOLICIT state */ 1864 not_on_link_count = 0; 1865 free_servers(ifp); 1866 newstate = DHCP6S_SOLICIT; 1867 } 1868 /* Foxconn modified end pling 10/07/2010 */ 1869 break; 1870 case DH6OPT_STCODE_NOADDRAVAIL: 1871 case DH6OPT_STCODE_NOPREFIXAVAIL: 1872 dprintf(LOG_DEBUG, "%s" 1873 "got a NoAddrAvail reply for request/rapid commit," 1874 " sending inforeq.", FNAME); 1875 not_on_link_count = 0; // Foxconn added pling 10/07/2010 1876 optinfo->iaidinfo.iaid = 0; 1877 newstate = DHCP6S_INFOREQ; 1878 break; 1879 case DH6OPT_STCODE_SUCCESS: 1880 case DH6OPT_STCODE_UNDEFINE: 1881 default: 1882 not_on_link_count = 0; // Foxconn added pling 10/07/2010 1883 if (!TAILQ_EMPTY(&optinfo->addr_list)) { 1884 (void)get_if_rainfo(ifp); 1885 dhcp6_add_iaidaddr(optinfo); 1886 if (optinfo->type == IAPD) { 1887 radvd_parse(&client6_iaidaddr, ADDR_UPDATE); 1888 /* Foxconn added start pling 10/12/2010 */ 1889 /* 1. Execute callback now as IAPD only does not need DAD. 1890 * 2. Send Info-req to get additional info 1891 */ 1892 dhcp6c_dad_callback(); 1893 newstate = DHCP6S_INFOREQ; 1894 /* Foxconn added end pling 10/12/2010 */ 1895 } 1896 else if (ifp->dad_timer == NULL && (ifp->dad_timer = 1897 dhcp6_add_timer(check_dad_timo, ifp)) < 0) { 1898 dprintf(LOG_INFO, "%s" "failed to create a timer for " 1899 " DAD", FNAME); 1900 } 1901 setup_check_timer(ifp); 1902 /* Foxconn removed start pling 10/05/2010 */ 1903 /* WNR3500L TD#175, send info-req after we complete the 1904 * DAD check. */ 1905 //client6_send_info_req(ev); 1906 /* Foxconn removed end pling 10/05/2010 */ 1907 } 1908 break; 1909 } 1910 break; 1911 case DHCP6S_RENEW: 1912 case DHCP6S_REBIND: 1913 if (client6_request_flag & CLIENT6_CONFIRM_ADDR) 1914 goto rebind_confirm; 1915 /* NoBinding for RENEW, REBIND, send REQUEST */ 1916 switch(addr_status_code) { 1917 case DH6OPT_STCODE_NOBINDING: 1918 /* Foxconn modified start pling 10/01/2014 */ 1919 /* R7000 TD486: WAN IPv6 address not update if receive 1920 * status code "Not-On-Link", and "No-binding" 1921 * Copy code from above "NOTONLINK" handling */ 1922#if 0 1923 newstate = DHCP6S_REQUEST; 1924 dprintf(LOG_DEBUG, "%s" 1925 "got a NoBinding reply, sending request.", FNAME); 1926 dhcp6_remove_iaidaddr(&client6_iaidaddr); 1927 break; 1928#endif 1929 case DH6OPT_STCODE_NOTONLINK: 1930 case DH6OPT_STCODE_NOADDRAVAIL: 1931 case DH6OPT_STCODE_NOPREFIXAVAIL: 1932 case DH6OPT_STCODE_UNSPECFAIL: 1933 dprintf(LOG_DEBUG, "%s" "got a NotOnLink reply for renew/rebind", FNAME); 1934 dhcp6_remove_iaidaddr(&client6_iaidaddr); 1935 not_on_link_count++; 1936 if (not_on_link_count <= REQ_MAX_RC_NOTONLINK) { 1937 /* Clear the IA / PD address, so they won't appear in the 1938 * request pkt. */ 1939 dhcp6_clear_list(&(ifp->current_server->optinfo.addr_list)); 1940 dhcp6_clear_list(&(ifp->current_server->optinfo.prefix_list)); 1941 newstate = DHCP6S_REQUEST; 1942 } else { 1943 /* Three times, back to SOLICIT state */ 1944 not_on_link_count = 0; 1945 free_servers(ifp); 1946 newstate = DHCP6S_SOLICIT; 1947 } 1948 break; 1949 /* Foxconn modified end pling 10/01/2014 */ 1950 1951 /* Foxconn removed start pling 10/01/2014 */ 1952 /* Handle these status codes above */ 1953#if 0 1954 case DH6OPT_STCODE_NOADDRAVAIL: 1955 case DH6OPT_STCODE_NOPREFIXAVAIL: 1956 case DH6OPT_STCODE_UNSPECFAIL: 1957 break; 1958#endif 1959 /* Foxconn removed end pling 10/01/2014 */ 1960 1961 case DH6OPT_STCODE_SUCCESS: 1962 case DH6OPT_STCODE_UNDEFINE: 1963 default: 1964 dhcp6_update_iaidaddr(optinfo, ADDR_UPDATE); 1965 if (optinfo->type == IAPD) 1966 radvd_parse(&client6_iaidaddr, ADDR_UPDATE); 1967 /* Foxconn added start pling 12/22/2011 */ 1968 /* WNDR4500 TD#156: Send signal to radvd to refresh 1969 * the prefix lifetime */ 1970 system("killall -SIGUSR1 radvd"); 1971 /* Foxconn added end pling 12/22/2011 */ 1972 /* Foxconn added start pling 01/25/2010 */ 1973 /* Send info-req to get SIP server and NTP server */ 1974 client6_send_info_req(ev); 1975 /* Foxconn added end pling 01/25/2010 */ 1976 break; 1977 } 1978 break; 1979 case DHCP6S_CONFIRM: 1980 /* NOtOnLink for a Confirm, send SOLICIT message */ 1981rebind_confirm: client6_request_flag &= ~CLIENT6_CONFIRM_ADDR; 1982 switch(addr_status_code) { 1983 struct timeb now; 1984 struct timeval timo; 1985 time_t offset; 1986 case DH6OPT_STCODE_NOTONLINK: 1987 case DH6OPT_STCODE_NOBINDING: 1988 case DH6OPT_STCODE_NOADDRAVAIL: 1989 dprintf(LOG_DEBUG, "%s" 1990 "got a NotOnLink reply for confirm, sending solicit.", FNAME); 1991 /* remove event data list */ 1992 free_servers(ifp); 1993 newstate = DHCP6S_SOLICIT; 1994 break; 1995 case DH6OPT_STCODE_SUCCESS: 1996 case DH6OPT_STCODE_UNDEFINE: 1997 dprintf(LOG_DEBUG, "%s" "got an expected reply for confirm", FNAME); 1998 ftime(&now); 1999 client6_iaidaddr.state = ACTIVE; 2000 if ((client6_iaidaddr.timer = dhcp6_add_timer(dhcp6_iaidaddr_timo, 2001 &client6_iaidaddr)) == NULL) { 2002 dprintf(LOG_ERR, "%s" "failed to add a timer for iaid %u", 2003 FNAME, client6_iaidaddr.client6_info.iaidinfo.iaid); 2004 return (-1); 2005 } 2006 if (client6_iaidaddr.client6_info.iaidinfo.renewtime == 0) { 2007 client6_iaidaddr.client6_info.iaidinfo.renewtime 2008 = get_min_preferlifetime(&client6_iaidaddr)/2; 2009 } 2010 if (client6_iaidaddr.client6_info.iaidinfo.rebindtime == 0) { 2011 client6_iaidaddr.client6_info.iaidinfo.rebindtime 2012 = (get_min_preferlifetime(&client6_iaidaddr)*4)/5; 2013 } 2014 offset = now.time - client6_iaidaddr.start_date; 2015 if ( offset > client6_iaidaddr.client6_info.iaidinfo.renewtime) 2016 timo.tv_sec = 0; 2017 else 2018 timo.tv_sec = client6_iaidaddr.client6_info.iaidinfo.renewtime - offset; 2019 timo.tv_usec = 0; 2020 dhcp6_set_timer(&timo, client6_iaidaddr.timer); 2021 /* check DAD */ 2022 if (optinfo->type != IAPD && ifp->dad_timer == NULL && 2023 (ifp->dad_timer = dhcp6_add_timer(check_dad_timo, ifp)) < 0) { 2024 dprintf(LOG_INFO, "%s" "failed to create a timer for " 2025 " DAD", FNAME); 2026 } 2027 setup_check_timer(ifp); 2028 break; 2029 default: 2030 break; 2031 } 2032 break; 2033 case DHCP6S_DECLINE: 2034 /* send REQUEST message to server with none decline address */ 2035 dprintf(LOG_DEBUG, "%s" 2036 "got an expected reply for decline, sending request.", FNAME); 2037 /* Foxconn modified start pling 10/04/2010 */ 2038 /* Should restart the 4-packet process, from SOLICIT */ 2039#if 0 2040 create_request_list(0); 2041 /* remove event data list */ 2042 newstate = DHCP6S_REQUEST; 2043#endif 2044 free_servers(ifp); 2045 newstate = DHCP6S_SOLICIT; 2046 /* Foxconn modified end pling 10/04/2010 */ 2047 break; 2048 case DHCP6S_RELEASE: 2049 dprintf(LOG_INFO, "%s" "got an expected release, exit.", FNAME); 2050 dhcp6_remove_event(ev); 2051 exit(0); 2052 default: 2053 break; 2054 } 2055 dhcp6_remove_event(ev); 2056 if (newstate) { 2057 client6_send_newstate(ifp, newstate); 2058 } else 2059 dprintf(LOG_DEBUG, "%s" "got an expected reply, sleeping.", FNAME); 2060 TAILQ_INIT(&request_list); 2061 return 0; 2062} 2063 2064int 2065client6_send_newstate(ifp, state) 2066 struct dhcp6_if *ifp; 2067 int state; 2068{ 2069 struct dhcp6_event *ev; 2070 if ((ev = dhcp6_create_event(ifp, state)) == NULL) { 2071 dprintf(LOG_ERR, "%s" "failed to create an event", 2072 FNAME); 2073 return (-1); 2074 } 2075 if ((ev->timer = dhcp6_add_timer(client6_timo, ev)) == NULL) { 2076 dprintf(LOG_ERR, "%s" "failed to add a timer for %s", 2077 FNAME, ifp->ifname); 2078 free(ev); 2079 return(-1); 2080 } 2081 TAILQ_INSERT_TAIL(&ifp->event_list, ev, link); 2082 ev->timeouts = 0; 2083 dhcp6_set_timeoparam(ev); 2084 /* Foxconn added start pling 10/07/2010 */ 2085 /* WNR3500L TD170, modify the maximum re-send counter of 2086 * Request message to 3 if a "NotOnLink" status is 2087 * received. 2088 */ 2089 if (state == DHCP6S_REQUEST && not_on_link_count) 2090 ev->max_retrans_cnt = REQ_MAX_RC_NOTONLINK; 2091 /* Foxconn added end pling 10/07/2010 */ 2092 dhcp6_reset_timer(ev); 2093 2094 /* Foxconn modified start pling 10/05/2010 */ 2095 /* Use diff function to send INFO-REQ */ 2096 if (state == DHCP6S_INFOREQ) 2097 client6_send_info_req(ev); 2098 else 2099 client6_send(ev); 2100 /* Foxconn modified end pling 10/05/2010 */ 2101 return 0; 2102} 2103 2104static struct dhcp6_event * 2105find_event_withid(ifp, xid) 2106 struct dhcp6_if *ifp; 2107 u_int32_t xid; 2108{ 2109 struct dhcp6_event *ev; 2110 2111 for (ev = TAILQ_FIRST(&ifp->event_list); ev; 2112 ev = TAILQ_NEXT(ev, link)) { 2113 dprintf(LOG_DEBUG, "%s" "ifp %p event %p id is %x", 2114 FNAME, ifp, ev, ev->xid); 2115 if (ev->xid == xid) 2116 return (ev); 2117 } 2118 2119 return (NULL); 2120} 2121 2122static int 2123create_request_list(int reboot) 2124{ 2125 struct dhcp6_lease *cl; 2126 struct dhcp6_listval *lv; 2127 /* create an address list for release all/confirm */ 2128 for (cl = TAILQ_FIRST(&client6_iaidaddr.lease_list); cl; 2129 cl = TAILQ_NEXT(cl, link)) { 2130 /* IANA, IAPD */ 2131 if ((lv = malloc(sizeof(*lv))) == NULL) { 2132 dprintf(LOG_ERR, "%s" 2133 "failed to allocate memory for an ipv6 addr", FNAME); 2134 exit(1); 2135 } 2136 memcpy(&lv->val_dhcp6addr, &cl->lease_addr, 2137 sizeof(lv->val_dhcp6addr)); 2138 lv->val_dhcp6addr.status_code = DH6OPT_STCODE_UNDEFINE; 2139 TAILQ_INSERT_TAIL(&request_list, lv, link); 2140 /* config the interface for reboot */ 2141 if (reboot && client6_iaidaddr.client6_info.type != IAPD && 2142 (client6_request_flag & CLIENT6_CONFIRM_ADDR)) { 2143 if (client6_ifaddrconf(IFADDRCONF_ADD, &cl->lease_addr) != 0) { 2144 dprintf(LOG_INFO, "config address failed: %s", 2145 in6addr2str(&cl->lease_addr.addr, 0)); 2146 return (-1); 2147 } 2148 } 2149 } 2150 /* update radvd.conf for prefix delegation */ 2151 if (reboot && client6_iaidaddr.client6_info.type == IAPD && 2152 (client6_request_flag & CLIENT6_CONFIRM_ADDR)) 2153 radvd_parse(&client6_iaidaddr, ADDR_UPDATE); 2154 return (0); 2155} 2156 2157static void setup_check_timer(struct dhcp6_if *ifp) 2158{ 2159 double d; 2160 struct timeval timo; 2161 d = DHCP6_CHECKLINK_TIME; 2162 timo.tv_sec = (long)d; 2163 timo.tv_usec = 0; 2164 dprintf(LOG_DEBUG, "set timer for checking link ..."); 2165 dhcp6_set_timer(&timo, ifp->link_timer); 2166 if (ifp->dad_timer != NULL) { 2167 d = DHCP6_CHECKDAD_TIME; 2168 timo.tv_sec = (long)d; 2169 timo.tv_usec = 0; 2170 dprintf(LOG_DEBUG, "set timer for checking DAD ..."); 2171 dhcp6_set_timer(&timo, ifp->dad_timer); 2172 } 2173 d = DHCP6_SYNCFILE_TIME; 2174 timo.tv_sec = (long)d; 2175 timo.tv_usec = 0; 2176 dprintf(LOG_DEBUG, "set timer for syncing file ..."); 2177 dhcp6_set_timer(&timo, ifp->sync_timer); 2178 return; 2179} 2180 2181static struct dhcp6_timer 2182*check_lease_file_timo(void *arg) 2183{ 2184 struct dhcp6_if *ifp = (struct dhcp6_if *)arg; 2185 double d; 2186 struct timeval timo; 2187 struct stat buf; 2188 FILE *file; 2189 stat(leasename, &buf); 2190 strcpy(client6_lease_temp, leasename); 2191 strcat(client6_lease_temp, "XXXXXX"); 2192 if (buf.st_size > MAX_FILE_SIZE) { 2193 file = sync_leases(client6_lease_file, leasename, client6_lease_temp); 2194 if ( file != NULL) 2195 client6_lease_file = file; 2196 } 2197 d = DHCP6_SYNCFILE_TIME; 2198 timo.tv_sec = (long)d; 2199 timo.tv_usec = 0; 2200 dhcp6_set_timer(&timo, ifp->sync_timer); 2201 return ifp->sync_timer; 2202} 2203/*Foxconn tab tseng added, 2013/07/23, for dhcp6c wan ipv6 DAD*/ 2204#define flag_wan_DAD "/proc/ipv6_wan_DAD_detected" 2205static int check_wan_DAD() 2206{ 2207 FILE* fp; 2208 char buf[64]; 2209 int ret; 2210 if (( fp = fopen(flag_wan_DAD, "r")) == NULL) { 2211 dprintf(LOG_ERR, "check_wan_DAD : can't open /proc/ipv6_wan_DAD_detected\n"); 2212 return (-1); 2213 } 2214 fgets(buf, sizeof(buf), fp); 2215 ret=atoi(buf); 2216 //DAD detected : ret=1, else : ret=0 2217 return ret; 2218} 2219/*Foxconn tab tseng added end, 2013/07/23, for dhcp6c wan ipv6 DAD*/ 2220 2221static struct dhcp6_timer 2222*check_dad_timo(void *arg) 2223{ 2224 struct dhcp6_if *ifp = (struct dhcp6_if *)arg; 2225 int newstate = DHCP6S_REQUEST; // Foxconn modified pling 10/04/2010 2226 if (client6_iaidaddr.client6_info.type == IAPD) 2227 goto end; 2228 dprintf(LOG_DEBUG, "enter checking dad ..."); 2229 if (dad_parse(ifproc_file) < 0) { 2230 dprintf(LOG_ERR, "parse /proc/net/if_inet6 failed"); 2231 goto end; 2232 } 2233 //if (TAILQ_EMPTY(&request_list)) 2234 if (TAILQ_EMPTY(&request_list) && !check_wan_DAD())//Foxconn tab tseng modified, 2013/07/23 2235 goto end; 2236 /* remove RENEW timer for client6_iaidaddr */ 2237 if (client6_iaidaddr.timer != NULL) 2238 dhcp6_remove_timer(client6_iaidaddr.timer); 2239 newstate = DHCP6S_DECLINE; 2240 client6_send_newstate(ifp, newstate); 2241end: 2242 /* one time check for DAD */ 2243 dhcp6_remove_timer(ifp->dad_timer); 2244 ifp->dad_timer = NULL; 2245 2246 /* Foxconn added start pling 10/04/2010 */ 2247 /* Send info-req to get DNS/SIP/NTP, etc, per Netgear spec. */ 2248 if (newstate != DHCP6S_DECLINE) { 2249 dhcp6c_dad_callback(); 2250 dprintf(LOG_DEBUG, "send info-req"); 2251 newstate = DHCP6S_INFOREQ; 2252 client6_send_newstate(ifp, newstate); 2253 } 2254 /* Foxconn added end pling 10/04/2010 */ 2255 2256 return NULL; 2257} 2258 2259static struct dhcp6_timer 2260*check_link_timo(void *arg) 2261{ 2262 struct dhcp6_if *ifp = (struct dhcp6_if *)arg; 2263 struct ifreq ifr; 2264 struct timeval timo; 2265 double d; 2266 int newstate; 2267 dprintf(LOG_DEBUG, "enter checking link ..."); 2268 strncpy(ifr.ifr_name, dhcp6_if->ifname, IFNAMSIZ); 2269 if (ioctl(nlsock, SIOCGIFFLAGS, &ifr) < 0) { 2270 dprintf(LOG_DEBUG, "ioctl SIOCGIFFLAGS failed"); 2271 goto settimer; 2272 } 2273 if (ifr.ifr_flags & IFF_RUNNING) { 2274 /* check previous flag 2275 * set current flag UP */ 2276 if (ifp->link_flag & IFF_RUNNING) { 2277 goto settimer; 2278 } 2279 /* check current state ACTIVE */ 2280 if (client6_iaidaddr.state == ACTIVE) { 2281 /* remove timer for renew/rebind 2282 * send confirm for ipv6address or 2283 * rebind for prefix delegation */ 2284 dhcp6_remove_timer(client6_iaidaddr.timer); 2285 client6_request_flag &= CLIENT6_CONFIRM_ADDR; 2286 create_request_list(0); 2287 if (client6_iaidaddr.client6_info.type == IAPD) 2288 newstate = DHCP6S_REBIND; 2289 else 2290 newstate = DHCP6S_CONFIRM; 2291 client6_send_newstate(ifp, newstate); 2292 } 2293 dprintf(LOG_INFO, "interface is from down to up"); 2294 ifp->link_flag |= IFF_RUNNING; 2295 } else { 2296 dprintf(LOG_INFO, "interface is down"); 2297 /* set flag_prev flag DOWN */ 2298 ifp->link_flag &= ~IFF_RUNNING; 2299 } 2300settimer: 2301 d = DHCP6_CHECKLINK_TIME; 2302 timo.tv_sec = (long)d; 2303 timo.tv_usec = 0; 2304 dhcp6_set_timer(&timo, ifp->link_timer); 2305 return ifp->link_timer; 2306} 2307 2308static void 2309setup_interface(char *ifname) 2310{ 2311 struct ifreq ifr; 2312 /* check the interface */ 2313 strncpy(ifr.ifr_name, ifname, IFNAMSIZ); 2314again: 2315 if (ioctl(nlsock, SIOCGIFFLAGS, &ifr) < 0) { 2316 dprintf(LOG_ERR, "ioctl SIOCGIFFLAGS failed"); 2317 exit(1); 2318 } 2319 if (!ifr.ifr_flags & IFF_UP) { 2320 ifr.ifr_flags |= IFF_UP; 2321 if (ioctl(nlsock, SIOCSIFFLAGS, &ifr) < 0) { 2322 dprintf(LOG_ERR, "ioctl SIOCSIFFLAGS failed"); 2323 exit(1); 2324 } 2325 if (ioctl(nlsock, SIOCGIFFLAGS, &ifr) < 0) { 2326 dprintf(LOG_ERR, "ioctl SIOCGIFFLAGS failed"); 2327 exit(1); 2328 } 2329 } 2330 if (!ifr.ifr_flags & IFF_RUNNING) { 2331 dprintf(LOG_INFO, "NIC is not connected to the network, " 2332 "please connect it. dhcp6c is sleeping ..."); 2333 sleep(10); 2334 goto again; 2335 } 2336 return; 2337} 2338