1/* $Id: client6_addr.c,v 1.1.1.1 2006/12/04 00:45:21 Exp $ */ 2 3/* 4 * Copyright (C) International Business Machines Corp., 2003 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of the project nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32/* Author: Shirley Ma, xma@us.ibm.com */ 33 34#include <sys/types.h> 35#include <sys/time.h> 36#include <sys/socket.h> 37#include <sys/ioctl.h> 38 39#include <linux/ipv6.h> 40 41#include <net/if.h> 42#include <time.h> 43#include <errno.h> 44#include <syslog.h> 45#include <string.h> 46#include <stdio.h> 47#include <stdlib.h> 48#include <unistd.h> 49#include <net/if_arp.h> 50 51#include "queue.h" 52#include "dhcp6.h" 53#include "config.h" 54#include "common.h" 55#include "timer.h" 56#include "lease.h" 57 58static int dhcp6_update_lease __P((struct dhcp6_addr *, struct dhcp6_lease *)); 59static int dhcp6_add_lease __P((struct dhcp6_addr *)); 60struct dhcp6_lease *dhcp6_find_lease __P((struct dhcp6_iaidaddr *, 61 struct dhcp6_addr *)); 62int dhcp6_get_prefixlen __P((struct in6_addr *, struct dhcp6_if *)); 63int client6_ifaddrconf __P((ifaddrconf_cmd_t, struct dhcp6_addr *)); 64u_int32_t get_min_preferlifetime __P((struct dhcp6_iaidaddr *)); 65u_int32_t get_max_validlifetime __P((struct dhcp6_iaidaddr *)); 66struct dhcp6_timer *dhcp6_iaidaddr_timo __P((void *)); 67struct dhcp6_timer *dhcp6_lease_timo __P((void *)); 68 69extern struct dhcp6_iaidaddr client6_iaidaddr; 70extern struct dhcp6_timer *client6_timo __P((void *)); 71extern void client6_send __P((struct dhcp6_event *)); 72extern void free_servers __P((struct dhcp6_if *)); 73extern ssize_t gethwid __P((char *, int, const char *, u_int16_t *)); 74 75extern int nlsock; 76extern FILE *client6_lease_file; 77extern struct dhcp6_iaidaddr client6_iaidaddr; 78extern struct dhcp6_list request_list; 79 80extern char* get_dhcpc_dev_name(void); // Foxconn added pling 09/23/2009 81 82void 83dhcp6_init_iaidaddr(void) 84{ 85 memset(&client6_iaidaddr, 0, sizeof(client6_iaidaddr)); 86 TAILQ_INIT(&client6_iaidaddr.lease_list); 87} 88 89/* Foxconn added start pling 10/04/2010 */ 90static char callback_cmd[256] = ""; 91int dhcp6c_dad_callback(void) 92{ 93 /* Execute our callback function to restart other 94 * user-space apps, such as radvd, dhcp6s, etc 95 */ 96 if (strlen(callback_cmd)) 97 { 98 system(callback_cmd); 99 memset(callback_cmd, 0, sizeof(callback_cmd)); 100 } 101 return 0; 102} 103/* Foxconn added end pling 10/04/2010 */ 104 105int 106dhcp6_add_iaidaddr(struct dhcp6_optinfo *optinfo) 107{ 108 struct dhcp6_listval *lv, *lv_next = NULL; 109 struct timeval timo; 110 struct dhcp6_lease *cl_lease; 111 double d; 112 113 /* Foxconn added start pling 08/15/2009 */ 114 char command[256], command2[256]; 115 memset(command, 0, sizeof(command)); 116 /* Foxconn added end pling 08/15/2009 */ 117 118 /* ignore IA with T1 > T2 */ 119 if (client6_iaidaddr.client6_info.iaidinfo.renewtime > 120 client6_iaidaddr.client6_info.iaidinfo.rebindtime) { 121 dprintf(LOG_INFO, " T1 time is greater than T2 time"); 122 return (0); 123 } 124 memcpy(&client6_iaidaddr.client6_info.iaidinfo, &optinfo->iaidinfo, 125 sizeof(client6_iaidaddr.client6_info.iaidinfo)); 126 client6_iaidaddr.client6_info.type = optinfo->type; 127 duidcpy(&client6_iaidaddr.client6_info.clientid, &optinfo->clientID); 128 if (duidcpy(&client6_iaidaddr.client6_info.serverid, &optinfo->serverID)) { 129 dprintf(LOG_ERR, "%s" "failed to copy server ID %s", 130 FNAME, duidstr(&optinfo->serverID)); 131 return (-1); 132 } 133 /* add new address */ 134 for (lv = TAILQ_FIRST(&optinfo->addr_list); lv; lv = lv_next) { 135 lv_next = TAILQ_NEXT(lv, link); 136 if (lv->val_dhcp6addr.type != IAPD) { 137 lv->val_dhcp6addr.plen = 138 dhcp6_get_prefixlen(&lv->val_dhcp6addr.addr, dhcp6_if); 139 if (lv->val_dhcp6addr.plen == PREFIX_LEN_NOTINRA) { 140 dprintf(LOG_WARNING, 141 "assigned address %s prefix len is not in any RAs" 142 " prefix length using 64 bit instead", 143 in6addr2str(&lv->val_dhcp6addr.addr, 0)); 144 145 /* Foxconn added start pling 08/15/2009 */ 146 sprintf(command, "dhcp6c_up %s %s %d ", 147 get_dhcpc_dev_name(), 148 in6addr2str(&lv->val_dhcp6addr.addr, 0), 149 lv->val_dhcp6addr.plen); 150 /* Foxconn added end pling 08/15/2009 */ 151 } 152 } 153 if ((cl_lease = dhcp6_find_lease(&client6_iaidaddr, 154 &lv->val_dhcp6addr)) != NULL) { 155 dhcp6_update_lease(&lv->val_dhcp6addr, cl_lease); 156 continue; 157 } 158 if (dhcp6_add_lease(&lv->val_dhcp6addr)) { 159 dprintf(LOG_ERR, "%s" "failed to add a new addr lease %s", 160 FNAME, in6addr2str(&lv->val_dhcp6addr.addr, 0)); 161 continue; 162 } 163 } 164 if (TAILQ_EMPTY(&client6_iaidaddr.lease_list)) 165 return 0; 166 167 /* Foxconn added start pling 09/23/2009 */ 168 /* add new prefix (IAPD) */ 169 for (lv = TAILQ_FIRST(&optinfo->prefix_list); lv; lv = lv_next) { 170 lv_next = TAILQ_NEXT(lv, link); 171 if (lv->val_dhcp6addr.type == IAPD) { 172 sprintf(command2, " %s %d &", 173 in6addr2str(&lv->val_dhcp6addr.addr, 0), 174 lv->val_dhcp6addr.plen); 175 /* Foxconn added start pling 10/12/2010 */ 176 if (!strlen(command)) 177 sprintf(command, "dhcp6c_up %s ", get_dhcpc_dev_name()); 178 /* Foxconn added end pling 10/12/2010 */ 179 strcat(command, command2); 180 } 181 } 182 /* Foxconn added end pling 09/23/2009 */ 183 184 /* set up renew T1, rebind T2 timer renew/rebind based on iaid */ 185 /* Should we process IA_TA, IA_NA differently */ 186 if (client6_iaidaddr.client6_info.iaidinfo.renewtime == 0 || 187 client6_iaidaddr.client6_info.iaidinfo.renewtime > 188 client6_iaidaddr.client6_info.iaidinfo.rebindtime) { 189 u_int32_t min_plifetime; 190 min_plifetime = get_min_preferlifetime(&client6_iaidaddr); 191 if (min_plifetime == DHCP6_DURATITION_INFINITE) 192 client6_iaidaddr.client6_info.iaidinfo.renewtime = min_plifetime; 193 else 194 client6_iaidaddr.client6_info.iaidinfo.renewtime = min_plifetime / 2; 195 } 196 if (client6_iaidaddr.client6_info.iaidinfo.rebindtime == 0 || 197 client6_iaidaddr.client6_info.iaidinfo.renewtime > 198 client6_iaidaddr.client6_info.iaidinfo.rebindtime) { 199 client6_iaidaddr.client6_info.iaidinfo.rebindtime = 200 get_min_preferlifetime(&client6_iaidaddr) * 4 / 5; 201 } 202 dprintf(LOG_INFO, "renew time %d, rebind time %d", 203 client6_iaidaddr.client6_info.iaidinfo.renewtime, 204 client6_iaidaddr.client6_info.iaidinfo.rebindtime); 205 if (client6_iaidaddr.client6_info.iaidinfo.renewtime == 0) 206 return (0); 207 if (client6_iaidaddr.client6_info.iaidinfo.renewtime == DHCP6_DURATITION_INFINITE) { 208 client6_iaidaddr.client6_info.iaidinfo.rebindtime = DHCP6_DURATITION_INFINITE; 209 if (strlen(command)) strcpy(callback_cmd, command); 210 return (0); 211 } 212 /* set up start date, and renew timer */ 213 if ((client6_iaidaddr.timer = 214 dhcp6_add_timer(dhcp6_iaidaddr_timo, &client6_iaidaddr)) == NULL) { 215 dprintf(LOG_ERR, "%s" "failed to add a timer for iaid %u", 216 FNAME, client6_iaidaddr.client6_info.iaidinfo.iaid); 217 return (-1); 218 } 219 time(&client6_iaidaddr.start_date); 220 client6_iaidaddr.state = ACTIVE; 221 d = client6_iaidaddr.client6_info.iaidinfo.renewtime; 222 timo.tv_sec = (long)d; 223 timo.tv_usec = 0; 224 dhcp6_set_timer(&timo, client6_iaidaddr.timer); 225 226 /* Foxconn modified start pling 10/04/2010 */ 227 /* Call our callback function to do something useful */ 228 if (strlen(command)) 229 strcpy(callback_cmd, command); 230 //system(command); 231 /* Foxconn modified end pling 10/04/2010 */ 232 233 return (0); 234} 235 236int 237dhcp6_add_lease(addr) 238 struct dhcp6_addr *addr; 239{ 240 struct dhcp6_lease *sp; 241 struct timeval timo; 242 double d; 243 244 dprintf(LOG_DEBUG, "%s" "try to add address %s", FNAME, 245 in6addr2str(&addr->addr, 0)); 246 247 /* ignore meaningless address */ 248 if (addr->status_code != DH6OPT_STCODE_SUCCESS && 249 addr->status_code != DH6OPT_STCODE_UNDEFINE) { 250 dprintf(LOG_ERR, "%s" "not successful status code for %s is %s", FNAME, 251 in6addr2str(&addr->addr, 0), dhcp6_stcodestr(addr->status_code)); 252 return (0); 253 } 254 if (addr->validlifetime == 0 || addr->preferlifetime == 0 || 255 addr->preferlifetime > addr->validlifetime) { 256 dprintf(LOG_ERR, "%s" "invalid address life time for %s", 257 FNAME, in6addr2str(&addr->addr, 0)); 258 return (0); 259 } 260 if ((sp = dhcp6_find_lease(&client6_iaidaddr, addr)) != NULL) { 261 dprintf(LOG_ERR, "%s" "duplicated address: %s", 262 FNAME, in6addr2str(&addr->addr, 0)); 263 return (-1); 264 } 265 if ((sp = (struct dhcp6_lease *)malloc(sizeof(*sp))) == NULL) { 266 dprintf(LOG_ERR, "%s" "failed to allocate memory" 267 " for a addr", FNAME); 268 return (-1); 269 } 270 memset(sp, 0, sizeof(*sp)); 271 memcpy(&sp->lease_addr, addr, sizeof(sp->lease_addr)); 272 sp->iaidaddr = &client6_iaidaddr; 273 time(&sp->start_date); 274 sp->state = ACTIVE; 275 if (write_lease(sp, client6_lease_file) != 0) { 276 dprintf(LOG_ERR, "%s" "failed to write a new lease address %s to lease file", 277 FNAME, in6addr2str(&sp->lease_addr.addr, 0)); 278 if (sp->timer) 279 dhcp6_remove_timer(sp->timer); 280 free(sp); 281 return (-1); 282 } 283 if (sp->lease_addr.type == IAPD) { 284 dprintf(LOG_INFO, "request prefix is %s/%d", 285 in6addr2str(&sp->lease_addr.addr, 0), sp->lease_addr.plen); 286 } else if (client6_ifaddrconf(IFADDRCONF_ADD, addr) != 0) { 287 dprintf(LOG_ERR, "%s" "adding address failed: %s", 288 FNAME, in6addr2str(&addr->addr, 0)); 289 if (sp->timer) 290 dhcp6_remove_timer(sp->timer); 291 free(sp); 292 return (-1); 293 } 294 TAILQ_INSERT_TAIL(&client6_iaidaddr.lease_list, sp, link); 295 /* for infinite lifetime don't do any timer */ 296 if (sp->lease_addr.validlifetime == DHCP6_DURATITION_INFINITE || 297 sp->lease_addr.preferlifetime == DHCP6_DURATITION_INFINITE) { 298 dprintf(LOG_INFO, "%s" "infinity address life time for %s", 299 FNAME, in6addr2str(&addr->addr, 0)); 300 return (0); 301 } 302 /* set up expired timer for lease*/ 303 if ((sp->timer = dhcp6_add_timer(dhcp6_lease_timo, sp)) == NULL) { 304 dprintf(LOG_ERR, "%s" "failed to add a timer for lease %s", 305 FNAME, in6addr2str(&addr->addr, 0)); 306 free(sp); 307 return (-1); 308 } 309 d = sp->lease_addr.preferlifetime; 310 timo.tv_sec = (long)d; 311 timo.tv_usec = 0; 312 dhcp6_set_timer(&timo, sp->timer); 313 return 0; 314} 315 316int 317dhcp6_remove_iaidaddr(struct dhcp6_iaidaddr *iaidaddr) 318{ 319 struct dhcp6_lease *lv, *lv_next; 320 for (lv = TAILQ_FIRST(&iaidaddr->lease_list); lv; lv = lv_next) { 321 lv_next = TAILQ_NEXT(lv, link); 322 (void)dhcp6_remove_lease(lv); 323 } 324 /* 325 if (iaidaddr->client6_info.serverid.duid_id != NULL) 326 duidfree(&iaidaddr->client6_info.serverid); 327 */ 328 if (iaidaddr->timer) 329 dhcp6_remove_timer(iaidaddr->timer); 330 TAILQ_INIT(&iaidaddr->lease_list); 331 return 0; 332} 333 334int 335dhcp6_remove_lease(struct dhcp6_lease *sp) 336{ 337 dprintf(LOG_DEBUG, "%s" "removing address %s", FNAME, 338 in6addr2str(&sp->lease_addr.addr, 0)); 339 sp->state = INVALID; 340 if (write_lease(sp, client6_lease_file) != 0) { 341 dprintf(LOG_INFO, "%s" 342 "failed to write removed lease address %s to lease file", 343 FNAME, in6addr2str(&sp->lease_addr.addr, 0)); 344 return (-1); 345 } 346 if (sp->lease_addr.type == IAPD) { 347 dprintf(LOG_INFO, "request prefix is %s/%d", 348 in6addr2str(&sp->lease_addr.addr, 0), sp->lease_addr.plen); 349 350 } else if (client6_ifaddrconf(IFADDRCONF_REMOVE, &sp->lease_addr) != 0) { 351 dprintf(LOG_INFO, "%s" "removing address %s failed", 352 FNAME, in6addr2str(&sp->lease_addr.addr, 0)); 353 } 354 /* remove expired timer for this lease. */ 355 if (sp->timer) 356 dhcp6_remove_timer(sp->timer); 357 TAILQ_REMOVE(&client6_iaidaddr.lease_list, sp, link); 358 free(sp); 359 /* can't remove expired iaidaddr even there is no lease in this iaidaddr 360 * since the rebind->solicit timer uses this iaidaddr 361 * if(TAILQ_EMPTY(&client6_iaidaddr.lease_list)) 362 * dhcp6_remove_iaidaddr(); 363 */ 364 365 /* Foxconn added start pling 11/30/2010 */ 366 /* WNR3500L TD192: 367 * Execute dhcp6c_down, so that LAN services and GUI 368 * are restarted correctly. 369 */ 370 char command[256]; 371 sprintf(command, "dhcp6c_down %s", get_dhcpc_dev_name()); 372 system(command); 373 /* Foxconn added end pling 11/30/2010 */ 374 375 return 0; 376} 377 378int 379dhcp6_update_iaidaddr(struct dhcp6_optinfo *optinfo, int flag) 380{ 381 struct dhcp6_listval *lv, *lv_next = NULL; 382 struct dhcp6_lease *cl, *cl_next; 383 struct timeval timo; 384 double d; 385 /* Foxconn added start pling 08/15/2009 */ 386 char command[256], command2[256]; 387 memset(command, 0, sizeof(command)); 388 /* Foxconn added end pling 08/15/2009 */ 389 390 if (client6_iaidaddr.client6_info.iaidinfo.renewtime > 391 client6_iaidaddr.client6_info.iaidinfo.rebindtime) { 392 dprintf(LOG_INFO, " T1 time is greater than T2 time"); 393 return (0); 394 } 395 if (flag == ADDR_REMOVE) { 396 for (lv = TAILQ_FIRST(&optinfo->addr_list); lv; lv = lv_next) { 397 lv_next = TAILQ_NEXT(lv, link); 398 cl = dhcp6_find_lease(&client6_iaidaddr, &lv->val_dhcp6addr); 399 if (cl) { 400 /* remove leases */ 401 dhcp6_remove_lease(cl); 402 } 403 } 404 return 0; 405 } 406 /* flag == ADDR_UPDATE */ 407 for (lv = TAILQ_FIRST(&optinfo->addr_list); lv; lv = lv_next) { 408 lv_next = TAILQ_NEXT(lv, link); 409 if (lv->val_dhcp6addr.type != IAPD) { 410 lv->val_dhcp6addr.plen = 411 dhcp6_get_prefixlen(&lv->val_dhcp6addr.addr, dhcp6_if); 412 if (lv->val_dhcp6addr.plen == PREFIX_LEN_NOTINRA) { 413 dprintf(LOG_WARNING, "assigned address %s is not in any RAs" 414 " prefix length using 64 bit instead", 415 in6addr2str(&lv->val_dhcp6addr.addr, 0)); 416 /* Foxconn added start pling 08/15/2009 */ 417 sprintf(command, "dhcp6c_up %s %s %d ", 418 get_dhcpc_dev_name(), 419 in6addr2str(&lv->val_dhcp6addr.addr, 0), 420 lv->val_dhcp6addr.plen); 421 /* Foxconn added end pling 08/15/2009 */ 422 } 423 } 424 if ((cl = dhcp6_find_lease(&client6_iaidaddr, &lv->val_dhcp6addr)) != NULL) { 425 /* update leases */ 426 dhcp6_update_lease(&lv->val_dhcp6addr, cl); 427 continue; 428 } 429 /* need to add the new leases */ 430 if (dhcp6_add_lease(&lv->val_dhcp6addr)) { 431 dprintf(LOG_INFO, "%s" "failed to add a new addr lease %s", 432 FNAME, in6addr2str(&lv->val_dhcp6addr.addr, 0)); 433 continue; 434 } 435 continue; 436 } 437 /* remove leases that not on the updated list */ 438 for (cl = TAILQ_FIRST(&client6_iaidaddr.lease_list); cl; cl = cl_next) { 439 cl_next = TAILQ_NEXT(cl, link); 440 lv = dhcp6_find_listval(&optinfo->addr_list, &cl->lease_addr, 441 DHCP6_LISTVAL_DHCP6ADDR); 442 /* remove leases that not on the updated list */ 443 if (lv == NULL) 444 dhcp6_remove_lease(cl); 445 } 446 /* update server id */ 447 if (client6_iaidaddr.state == REBIND) { 448 if (duidcpy(&client6_iaidaddr.client6_info.serverid, &optinfo->serverID)) { 449 dprintf(LOG_ERR, "%s" "failed to copy server ID", FNAME); 450 return (-1); 451 } 452 } 453 if (TAILQ_EMPTY(&client6_iaidaddr.lease_list)) 454 return (0); 455 456 /* Foxconn added start pling 09/23/2009 */ 457 /* add new prefix (IAPD) */ 458 for (lv = TAILQ_FIRST(&optinfo->prefix_list); lv; lv = lv_next) { 459 lv_next = TAILQ_NEXT(lv, link); 460 if (lv->val_dhcp6addr.type == IAPD) { 461 sprintf(command2, " %s %d &", 462 in6addr2str(&lv->val_dhcp6addr.addr, 0), 463 lv->val_dhcp6addr.plen); 464 /* Foxconn added start pling 10/12/2010 */ 465 if (!strlen(command)) 466 sprintf(command, "dhcp6c_up %s ", get_dhcpc_dev_name()); 467 /* Foxconn added end pling 10/12/2010 */ 468 strcat(command, command2); 469 } 470 } 471 /* Foxconn added end pling 09/23/2009 */ 472 473 /* set up renew T1, rebind T2 timer renew/rebind based on iaid */ 474 /* Should we process IA_TA, IA_NA differently */ 475 if (client6_iaidaddr.client6_info.iaidinfo.renewtime == 0) { 476 u_int32_t min_plifetime; 477 min_plifetime = get_min_preferlifetime(&client6_iaidaddr); 478 if (min_plifetime == DHCP6_DURATITION_INFINITE) 479 client6_iaidaddr.client6_info.iaidinfo.renewtime = min_plifetime; 480 else 481 client6_iaidaddr.client6_info.iaidinfo.renewtime = min_plifetime / 2; 482 } 483 if (client6_iaidaddr.client6_info.iaidinfo.rebindtime == 0) { 484 client6_iaidaddr.client6_info.iaidinfo.rebindtime = 485 get_min_preferlifetime(&client6_iaidaddr) * 4 / 5; 486 } 487 dprintf(LOG_INFO, "renew time %d, rebind time %d", 488 client6_iaidaddr.client6_info.iaidinfo.renewtime, 489 client6_iaidaddr.client6_info.iaidinfo.rebindtime); 490 if (client6_iaidaddr.client6_info.iaidinfo.renewtime == 0) 491 return (0); 492 if (client6_iaidaddr.client6_info.iaidinfo.renewtime == DHCP6_DURATITION_INFINITE) { 493 client6_iaidaddr.client6_info.iaidinfo.rebindtime = DHCP6_DURATITION_INFINITE; 494 if (client6_iaidaddr.timer) 495 dhcp6_remove_timer(client6_iaidaddr.timer); 496 if (strlen(command)) 497 system(command); 498 return (0); 499 } 500 /* update the start date and timer */ 501 if (client6_iaidaddr.timer == NULL) { 502 if ((client6_iaidaddr.timer = 503 dhcp6_add_timer(dhcp6_iaidaddr_timo, &client6_iaidaddr)) == NULL) { 504 dprintf(LOG_ERR, "%s" "failed to add a timer for iaid %u", 505 FNAME, client6_iaidaddr.client6_info.iaidinfo.iaid); 506 return (-1); 507 } 508 } 509 time(&client6_iaidaddr.start_date); 510 client6_iaidaddr.state = ACTIVE; 511 d = client6_iaidaddr.client6_info.iaidinfo.renewtime; 512 timo.tv_sec = (long)d; 513 timo.tv_usec = 0; 514 dhcp6_set_timer(&timo, client6_iaidaddr.timer); 515 516 /* Foxconn added start pling 08/15/2009 */ 517 /* Call our callback function to do something useful */ 518 if (strlen(command)) 519 system(command); 520 /* Foxconn added start pling 08/15/2009 */ 521 522 return 0; 523} 524 525static int 526dhcp6_update_lease(struct dhcp6_addr *addr, struct dhcp6_lease *sp) 527{ 528 struct timeval timo; 529 double d; 530 531 if (addr->status_code != DH6OPT_STCODE_SUCCESS && 532 addr->status_code != DH6OPT_STCODE_UNDEFINE) { 533 dprintf(LOG_ERR, "%s" "not successful status code for %s is %s", FNAME, 534 in6addr2str(&addr->addr, 0), dhcp6_stcodestr(addr->status_code)); 535 dhcp6_remove_lease(sp); 536 return (0); 537 } 538 /* remove leases with validlifetime == 0, and preferlifetime == 0 */ 539 if (addr->validlifetime == 0 || addr->preferlifetime == 0 || 540 addr->preferlifetime > addr->validlifetime) { 541 dprintf(LOG_ERR, "%s" "invalid address life time for %s", 542 FNAME, in6addr2str(&addr->addr, 0)); 543 dhcp6_remove_lease(sp); 544 return (0); 545 } 546 memcpy(&sp->lease_addr, addr, sizeof(sp->lease_addr)); 547 sp->state = ACTIVE; 548 time(&sp->start_date); 549 if (write_lease(sp, client6_lease_file) != 0) { 550 dprintf(LOG_ERR, "%s" 551 "failed to write an updated lease address %s to lease file", 552 FNAME, in6addr2str(&sp->lease_addr.addr, 0)); 553 return (-1); 554 } 555 if (sp->lease_addr.validlifetime == DHCP6_DURATITION_INFINITE || 556 sp->lease_addr.preferlifetime == DHCP6_DURATITION_INFINITE) { 557 dprintf(LOG_INFO, "%s" "infinity address life time for %s", 558 FNAME, in6addr2str(&addr->addr, 0)); 559 if (sp->timer) 560 dhcp6_remove_timer(sp->timer); 561 return (0); 562 } 563 if (sp->timer == NULL) { 564 if ((sp->timer = dhcp6_add_timer(dhcp6_lease_timo, sp)) == NULL) { 565 dprintf(LOG_ERR, "%s" "failed to add a timer for lease %s", 566 FNAME, in6addr2str(&addr->addr, 0)); 567 return (-1); 568 } 569 } 570 d = sp->lease_addr.preferlifetime; 571 timo.tv_sec = (long)d; 572 timo.tv_usec = 0; 573 dhcp6_set_timer(&timo, sp->timer); 574 return (0); 575} 576 577struct dhcp6_lease * 578dhcp6_find_lease(struct dhcp6_iaidaddr *iaidaddr, 579 struct dhcp6_addr *ifaddr) 580{ 581 struct dhcp6_lease *sp; 582 for (sp = TAILQ_FIRST(&iaidaddr->lease_list); sp; 583 sp = TAILQ_NEXT(sp, link)) { 584 /* sp->lease_addr.plen == ifaddr->plen */ 585 dprintf(LOG_DEBUG, "%s" "get address is %s/%d ", FNAME, 586 in6addr2str(&ifaddr->addr, 0), ifaddr->plen); 587 dprintf(LOG_DEBUG, "%s" "lease address is %s/%d ", FNAME, 588 in6addr2str(&sp->lease_addr.addr, 0), ifaddr->plen); 589 if (IN6_ARE_ADDR_EQUAL(&sp->lease_addr.addr, &ifaddr->addr)) { 590 if (sp->lease_addr.type == IAPD) { 591 if (sp->lease_addr.plen == ifaddr->plen) 592 return (sp); 593 } else if (sp->lease_addr.type == IANA || 594 sp->lease_addr.type == IATA) 595 return (sp); 596 } 597 } 598 return (NULL); 599} 600 601struct dhcp6_timer * 602dhcp6_iaidaddr_timo(void *arg) 603{ 604 struct dhcp6_iaidaddr *sp = (struct dhcp6_iaidaddr *)arg; 605 struct dhcp6_event *ev; 606 struct timeval timeo; 607 int dhcpstate; 608 double d = 0; 609 time_t now; /* pling added 12/24/2014 */ 610 611 dprintf(LOG_DEBUG, "client6_iaidaddr timeout for %d, state=%d", 612 client6_iaidaddr.client6_info.iaidinfo.iaid, sp->state); 613 614 dhcp6_clear_list(&request_list); 615 TAILQ_INIT(&request_list); 616 /* ToDo: what kind of opiton Request value, client would like to pass? */ 617 switch(sp->state) { 618 case ACTIVE: 619 /* Foxconn added start pling 12/24/2014 */ 620 /* R7000 TD#559: DHCP lease expiration is calculated based 621 * on system time. Once NTP sync, system changed from 2003->current 622 * time, and lease expires immediately. So add following code to 623 * fallback to Solicit state. 624 */ 625 time(&now); 626 //dprintf(LOG_INFO, "%s" "sp->start_date=0x%08x", FNAME, sp->start_date); 627 628 if (now > 0x50000000 && /* approx 2013-2014 */ 629 sp->start_date < 0x50000000) { /* some time around 2014 */ 630 dprintf(LOG_INFO, "%s" "Lease expired due to NTP update." 631 " Go to solicit and request new ipv6 addresses", 632 FNAME); 633 goto restart_from_solicit; 634 } 635 /* Foxconn added end pling 12/24/2014 */ 636 sp->state = RENEW; 637 dhcpstate = DHCP6S_RENEW; 638 d = sp->client6_info.iaidinfo.rebindtime - sp->client6_info.iaidinfo.renewtime; 639 timeo.tv_sec = (long)d; 640 timeo.tv_usec = 0; 641 break; 642 case RENEW: 643 sp->state = REBIND; 644 dhcpstate = DHCP6S_REBIND; 645 d = get_max_validlifetime(&client6_iaidaddr) - 646 sp->client6_info.iaidinfo.rebindtime; 647 timeo.tv_sec = (long)d; 648 timeo.tv_usec = 0; 649 if (sp->client6_info.serverid.duid_id != NULL) 650 duidfree(&sp->client6_info.serverid); 651 break; 652 case REBIND: 653 dprintf(LOG_INFO, "%s" "failed to rebind a client6_iaidaddr %d" 654 " go to solicit and request new ipv6 addresses", 655 FNAME, client6_iaidaddr.client6_info.iaidinfo.iaid); 656restart_from_solicit: /* pling added 12/24/2014 */ 657 sp->state = INVALID; 658 dhcpstate = DHCP6S_SOLICIT; 659 free_servers(sp->ifp); 660 break; 661 default: 662 return (NULL); 663 } 664 if ((ev = dhcp6_create_event(sp->ifp, dhcpstate)) == NULL) { 665 dprintf(LOG_ERR, "%s" "failed to create a new event", 666 FNAME); 667 return (NULL); 668 } 669 switch(sp->state) { 670 case RENEW: 671 if (duidcpy(&ev->serverid, &sp->client6_info.serverid)) { 672 dprintf(LOG_ERR, "%s" "failed to copy server ID", FNAME); 673 free(ev); 674 return (NULL); 675 } 676 case REBIND: 677 /* BUG: d not set! */ 678 ev->max_retrans_dur = d; 679 break; 680 default: 681 break; 682 } 683 if ((ev->timer = dhcp6_add_timer(client6_timo, ev)) == NULL) { 684 dprintf(LOG_ERR, "%s" "failed to create a new event timer", FNAME); 685 if (sp->state == RENEW) 686 duidfree(&ev->serverid); 687 free(ev); 688 return (NULL); 689 } 690 TAILQ_INSERT_TAIL(&sp->ifp->event_list, ev, link); 691 if (sp->state != INVALID) { 692 struct dhcp6_lease *cl; 693 /* create an address list for renew and rebind */ 694 for (cl = TAILQ_FIRST(&client6_iaidaddr.lease_list); cl; 695 cl = TAILQ_NEXT(cl, link)) { 696 struct dhcp6_listval *lv; 697 /* IA_NA address */ 698 if ((lv = malloc(sizeof(*lv))) == NULL) { 699 dprintf(LOG_ERR, "%s" 700 "failed to allocate memory for an ipv6 addr", FNAME); 701 if (sp->state == RENEW) 702 duidfree(&ev->serverid); 703 free(ev->timer); 704 free(ev); 705 return (NULL); 706 } 707 memcpy(&lv->val_dhcp6addr, &cl->lease_addr, 708 sizeof(lv->val_dhcp6addr)); 709 lv->val_dhcp6addr.status_code = DH6OPT_STCODE_UNDEFINE; 710 TAILQ_INSERT_TAIL(&request_list, lv, link); 711 } 712 dhcp6_set_timer(&timeo, sp->timer); 713 } else { 714 dhcp6_remove_iaidaddr(&client6_iaidaddr); 715 /* remove event data for that event */ 716 sp->timer = NULL; 717 } 718 ev->timeouts = 0; 719 dhcp6_set_timeoparam(ev); 720 dhcp6_reset_timer(ev); 721 client6_send(ev); 722 return (sp->timer); 723} 724 725 726struct dhcp6_timer * 727dhcp6_lease_timo(void *arg) 728{ 729 struct dhcp6_lease *sp = (struct dhcp6_lease *)arg; 730 struct timeval timeo; 731 double d; 732 733 dprintf(LOG_DEBUG, "%s" "lease timeout for %s, state=%d", FNAME, 734 in6addr2str(&sp->lease_addr.addr, 0), sp->state); 735 /* cancel the current event for this lease */ 736 if (sp->state == INVALID) { 737 dprintf(LOG_INFO, "%s" "failed to remove an addr %s", 738 FNAME, in6addr2str(&sp->lease_addr.addr, 0)); 739 dhcp6_remove_lease(sp); 740 return (NULL); 741 } 742 switch(sp->state) { 743 case ACTIVE: 744 sp->state = EXPIRED; 745 d = sp->lease_addr.validlifetime - sp->lease_addr.preferlifetime; 746 timeo.tv_sec = (long)d; 747 timeo.tv_usec = 0; 748 dhcp6_set_timer(&timeo, sp->timer); 749 break; 750 case EXPIRED: 751 sp->state = INVALID; 752 dhcp6_remove_lease(sp); 753 default: 754 return (NULL); 755 } 756 return (sp->timer); 757} 758 759int 760client6_ifaddrconf(ifaddrconf_cmd_t cmd, struct dhcp6_addr *ifaddr) 761{ 762 struct in6_ifreq req; 763 struct dhcp6_if *ifp = client6_iaidaddr.ifp; 764 unsigned long ioctl_cmd; 765 char *cmdstr; 766 int s, errno; 767 768 switch(cmd) { 769 case IFADDRCONF_ADD: 770 cmdstr = "add"; 771 ioctl_cmd = SIOCSIFADDR; 772 break; 773 case IFADDRCONF_REMOVE: 774 cmdstr = "remove"; 775 ioctl_cmd = SIOCDIFADDR; 776 break; 777 default: 778 return (-1); 779 } 780 781 if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { 782 dprintf(LOG_ERR, "%s" "can't open a temporary socket: %s", 783 FNAME, strerror(errno)); 784 return (-1); 785 } 786 memset(&req, 0, sizeof(req)); 787 req.ifr6_ifindex = if_nametoindex(ifp->ifname); 788 memcpy(&req.ifr6_addr, &ifaddr->addr, sizeof(req.ifr6_addr)); 789 790 req.ifr6_prefixlen = ifaddr->plen; 791 792 if (ioctl(s, ioctl_cmd, &req) && errno != EEXIST) { 793 dprintf(LOG_NOTICE, "%s" "failed to %s an address on %s: %s", 794 FNAME, cmdstr, ifp->ifname, strerror(errno)); 795 close(s); 796 return (-1); 797 } 798 799 dprintf(LOG_DEBUG, "%s" "%s an address %s on %s", FNAME, cmdstr, 800 in6addr2str(&ifaddr->addr, 0), ifp->ifname); 801 close(s); 802 return (0); 803} 804 805 806int 807get_iaid(const char *ifname, const struct iaid_table *iaidtab, int num_device) 808{ 809 struct hardware hdaddr; 810 struct iaid_table *temp = (struct iaid_table *)iaidtab; 811 int i; 812 hdaddr.len = gethwid(hdaddr.data, 6, ifname, &hdaddr.type); 813 for (i = 0; i < num_device; i++, temp++) { 814 if (!memcmp(temp->hwaddr.data, hdaddr.data, temp->hwaddr.len) 815 && hdaddr.len == temp->hwaddr.len && hdaddr.type == temp->hwaddr.type) { 816 dprintf(LOG_DEBUG, "%s"" found interface %s iaid %u", 817 FNAME, ifname, temp->iaid); 818 return temp->iaid; 819 } else 820 continue; 821 } 822 return 0; 823} 824 825int 826create_iaid(struct iaid_table *iaidtab, int num_device) 827{ 828 struct iaid_table *temp = iaidtab; 829 char buff[1024]; 830 struct ifconf ifc; 831 struct ifreq *ifr; 832 int i; 833 834 ifc.ifc_len = sizeof(buff); 835 ifc.ifc_buf = buff; 836 if (ioctl(nlsock, SIOCGIFCONF, &ifc) < 0) { 837 dprintf(LOG_ERR, "%s" "ioctl SIOCGIFCONF", FNAME); 838 return -1; 839 } 840 841 ifr = ifc.ifc_req; 842 for (i = ifc.ifc_len / sizeof(struct ifreq); --i >= 0 && num_device < MAX_DEVICE; 843 ifr++) { 844 if (!strcmp(ifr->ifr_name, "lo")) continue; 845 temp->hwaddr.len = gethwid(temp->hwaddr.data, sizeof(temp->hwaddr.data), ifr->ifr_name, &temp->hwaddr.type); 846 switch (temp->hwaddr.type) { 847 case ARPHRD_ETHER: 848 case ARPHRD_IEEE802: 849 memcpy(&temp->iaid, temp->hwaddr.data, sizeof(temp->iaid)); 850 break; 851 case ARPHRD_PPP: 852 temp->iaid = do_hash(ifr->ifr_name,sizeof(ifr->ifr_name)) 853 + if_nametoindex(ifr->ifr_name); 854 break; 855 default: 856 dprintf(LOG_INFO, "doesn't support %s address family %d", 857 ifr->ifr_name, temp->hwaddr.type); 858 continue; 859 } 860 dprintf(LOG_DEBUG, "%s"" create iaid %u for interface %s", 861 FNAME, temp->iaid, ifr->ifr_name); 862 num_device++; 863 temp++; 864 } 865 return num_device; 866} 867