Пример #1
0
static int
add_address(struct dhcp6_list *addr_list,
	    struct dhcp6_addr *v6addr)
{
	struct dhcp6_listval *lv, *val;
	
	/* avoid invalid addresses */
	if (IN6_IS_ADDR_RESERVED(&v6addr->addr)) {
		dprintf(LOG_ERR, "%s" "invalid address: %s",
			FNAME, in6addr2str(&v6addr->addr, 0));
		return (-1);
	}

	/* address duplication check */
	for (lv = TAILQ_FIRST(addr_list); lv;
	     lv = TAILQ_NEXT(lv, link)) {
		if (IN6_ARE_ADDR_EQUAL(&lv->val_dhcp6addr.addr, &v6addr->addr) &&
		    lv->val_dhcp6addr.plen == v6addr->plen) {
			dprintf(LOG_ERR, "%s"
				"duplicated address: %s/%d ", FNAME,
				in6addr2str(&v6addr->addr, 0), v6addr->plen);
			return (-1);
		}
	}
	if ((val = (struct dhcp6_listval *)malloc(sizeof(*val))) == NULL)
		dprintf(LOG_ERR, "%s" "memory allocation failed", FNAME);
	memset(val, 0, sizeof(*val));
	memcpy(&val->val_dhcp6addr, v6addr, sizeof(val->val_dhcp6addr));
	dprintf(LOG_DEBUG, "%s" "add address: %s",
		FNAME, in6addr2str(&v6addr->addr, 0));
	TAILQ_INSERT_TAIL(addr_list, val, link);
	return (0);
}
Пример #2
0
int
configure_global_option(void)
{
	struct cf_list *cl;

	/* DNS servers */
	if (cf_dns_list && dhcp6_mode != DHCP6_MODE_SERVER) {
		dprintf(LOG_INFO, "%s" "%s:%d server-only configuration",
		    FNAME, configfilename, cf_dns_list->line);
		goto bad;
	}
	TAILQ_INIT(&dnslist0);
	for (cl = cf_dns_list; cl; cl = cl->next) {
		/* duplication check */
		if (dhcp6_find_listval(&dnslist0, cl->ptr,
		    DHCP6_LISTVAL_ADDR6)) {
			dprintf(LOG_INFO, "%s"
			    "%s:%d duplicated DNS server: %s", FNAME,
			    configfilename, cl->line,
			    in6addr2str((struct in6_addr *)cl->ptr, 0));
			goto bad;
		}
		if (dhcp6_add_listval(&dnslist0, cl->ptr,
		    DHCP6_LISTVAL_ADDR6) == NULL) {
			dprintf(LOG_ERR, "%s" "failed to add a DNS server", 
				FNAME);
			goto bad;
		}
	}

	return 0;

  bad:
	return -1;
}
Пример #3
0
int dad_parse(const char *file, struct dhcp6_list *dad_list) {
    int i = 0;
    int len = 0;
    int ret = 0;
    FILE *fp = NULL;
    char buf[55];               /* max line length in /proc/net/if_inet6 */
    char addrbuf[64];
    char *tmp = NULL;
    struct in6_addr addr6;
    struct ifproc_info *ifinfo = NULL;

    if (file == NULL) {
        dhcpv6_dprintf(LOG_ERR, "dad_parse: NULL filename");
        return -1;
    }

    memset(&buf, '\0', sizeof(buf));
    memset(&addr6, 0, sizeof(addr6));

    if ((fp = fopen(file, "r")) == NULL) {
        if (errno == ENOENT) {
            return 0;
        }

        dhcpv6_dprintf(LOG_ERR, "dad_parse: fopen(%s): %s", file,
                       strerror(errno));
        return -1;
    }

    while (fgets(buf, sizeof(buf), fp) != NULL) {
        /* read address */
        if ((tmp = strtok(buf, " \n")) == NULL) {
            continue;
        }

        len = 0;

        for (i = 0; i < 32; i += 4) {
            strncpy(addrbuf + len, &tmp[i], 4);
            len += 4;

            if (i < 28) {
                strcpy(addrbuf + len, ":");
                len += 1;
            } else {
                strcpy(addrbuf + len, "\0");
            }
        }

        if (inet_pton(AF_INET6, addrbuf, &addr6) < 1) {
            dhcpv6_dprintf(LOG_ERR, "failed to parse %s from %s",
                           addrbuf, file);
            abort();
        }

        if ((ifinfo = malloc(sizeof(*ifinfo))) == NULL) {
            dhcpv6_dprintf(LOG_ERR, "memory allocation failure");
            abort();
        }

        memcpy(&ifinfo->addr, &addr6, sizeof(ifinfo->addr));

        /* read the index */
        if ((tmp = strtok(NULL, " \n")) == NULL) {
            continue;
        }

        ifinfo->index = strtol(tmp, NULL, 16);
        if ((errno == EINVAL) || (errno == ERANGE)) {
            dhcpv6_dprintf(LOG_ERR, "error reading index from %s", file);
            goto fail;
        }

        /* read the prefix length */
        if ((tmp = strtok(NULL, " \n")) == NULL) {
            continue;
        }

        ifinfo->plen = strtol(tmp, NULL, 16);
        if ((errno == EINVAL) || (errno == ERANGE)) {
            dhcpv6_dprintf(LOG_ERR, "error reading prefix length from %s", file);
            goto fail;
        }

        /* read the scope */
        if ((tmp = strtok(NULL, " \n")) == NULL) {
            continue;
        }

        ifinfo->scope = strtol(tmp, NULL, 16);
        if ((errno == EINVAL) || (errno == ERANGE)) {
            dhcpv6_dprintf(LOG_ERR, "error reading scope from %s", file);
            goto fail;
        }

        /* read the flags */
        if ((tmp = strtok(NULL, " \n")) == NULL) {
            continue;
        }

        ifinfo->flags = strtol(tmp, NULL, 16);
        if ((errno == EINVAL) || (errno == ERANGE)) {
            dhcpv6_dprintf(LOG_ERR, "error reading flags from %s", file);
            goto fail;
        }

        if (ifinfo->flags == DAD_FLAGS) {
            dhcpv6_dprintf(LOG_INFO, "duplicated IPv6 address %s detected",
                           in6addr2str(&ifinfo->addr, 0));
        } else {
            free(ifinfo);
            ifinfo = NULL;
            continue;
        }

        /* read the interface name */
        if ((tmp = strtok(NULL, " \n")) == NULL) {
            continue;
        }

        if (strcmp(tmp, dhcp6_if->ifname)) {
            free(ifinfo);
            ifinfo = NULL;
            continue;
        } else {
            struct dhcp6_listval *lv;

            strncpy(ifinfo->name, tmp, IF_NAMESIZE);
            ifinfo->next = NULL;

            /* check address on client6_iaidaddr list */
            if ((lv = malloc(sizeof(*lv))) == NULL) {
                dhcpv6_dprintf(LOG_ERR, "memory allocation failure");
                abort();
            }

            memcpy(&lv->val_dhcp6addr.addr, &ifinfo->addr,
                   sizeof(lv->val_dhcp6addr.addr));
            lv->val_dhcp6addr.type = IANA;
            lv->val_dhcp6addr.plen = ifinfo->plen;
            lv->val_dhcp6addr.status_code = DH6OPT_STCODE_UNDEFINE;
            lv->val_dhcp6addr.preferlifetime = 0;
            lv->val_dhcp6addr.validlifetime = 0;
            TAILQ_INSERT_TAIL(dad_list, lv, link);
        }
    }

out:
    if (fclose(fp) == EOF) {
        fprintf(stderr, "%s (%d): %s\n", __func__, __LINE__, strerror(errno));
        fflush(stderr);
        abort();
    }

    return ret;

fail:
    dhcp6_clear_list(dad_list);
    ret = -1;
    goto out;
}
int
client6_script(
	char *scriptpath,
	int state,
	struct dhcp6_optinfo *optinfo
)
{
	int i, dnsservers, ntpservers, dnsnamelen, envc, elen, ret = 0;
	int sipservers, sipnamelen;
	int nisservers, nisnamelen;
	int nispservers, nispnamelen;
	int bcmcsservers, bcmcsnamelen;
	char **envp, *s;
	char reason[] = "REASON=NBI";
	struct dhcp6_listval *v;
	pid_t pid, wpid;

	/* if a script is not specified, do nothing */
	if (scriptpath == NULL || strlen(scriptpath) == 0)
		return -1;

	/* initialize counters */
	dnsservers = 0;
	ntpservers = 0;
	dnsnamelen = 0;
	sipservers = 0;
	sipnamelen = 0;
	nisservers = 0;
	nisnamelen = 0;
	nispservers = 0;
	nispnamelen = 0;
	bcmcsservers = 0;
	bcmcsnamelen = 0;
	envc = 2;     /* we at least include the reason and the terminator */

	/* count the number of variables */
	for (v = TAILQ_FIRST(&optinfo->dns_list); v; v = TAILQ_NEXT(v, link))
		dnsservers++;
	envc += dnsservers ? 1 : 0;
	for (v = TAILQ_FIRST(&optinfo->dnsname_list); v;
	    v = TAILQ_NEXT(v, link)) {
		dnsnamelen += v->val_vbuf.dv_len;
	}
	envc += dnsnamelen ? 1 : 0;
	for (v = TAILQ_FIRST(&optinfo->ntp_list); v; v = TAILQ_NEXT(v, link))
		ntpservers++;
	envc += ntpservers ? 1 : 0;
	for (v = TAILQ_FIRST(&optinfo->sip_list); v; v = TAILQ_NEXT(v, link))
		sipservers++;
	envc += sipservers ? 1 : 0;
	for (v = TAILQ_FIRST(&optinfo->sipname_list); v;
	    v = TAILQ_NEXT(v, link)) {
		sipnamelen += v->val_vbuf.dv_len;
	}
	envc += sipnamelen ? 1 : 0;

	for (v = TAILQ_FIRST(&optinfo->nis_list); v; v = TAILQ_NEXT(v, link))
		nisservers++;
	envc += nisservers ? 1 : 0;
	for (v = TAILQ_FIRST(&optinfo->nisname_list); v;
	    v = TAILQ_NEXT(v, link)) {
		nisnamelen += v->val_vbuf.dv_len;
	}
	envc += nisnamelen ? 1 : 0;

	for (v = TAILQ_FIRST(&optinfo->nisp_list); v; v = TAILQ_NEXT(v, link))
		nispservers++;
	envc += nispservers ? 1 : 0;
	for (v = TAILQ_FIRST(&optinfo->nispname_list); v;
	    v = TAILQ_NEXT(v, link)) {
		nispnamelen += v->val_vbuf.dv_len;
	}
	envc += nispnamelen ? 1 : 0;

	for (v = TAILQ_FIRST(&optinfo->bcmcs_list); v; v = TAILQ_NEXT(v, link))
		bcmcsservers++;
	envc += bcmcsservers ? 1 : 0;
	for (v = TAILQ_FIRST(&optinfo->bcmcsname_list); v;
	    v = TAILQ_NEXT(v, link)) {
		bcmcsnamelen += v->val_vbuf.dv_len;
	}
	envc += bcmcsnamelen ? 1 : 0;

	/* allocate an environments array */
	if ((envp = malloc(sizeof (char *) * envc)) == NULL) {
		dprintf(LOG_NOTICE, FNAME,
		    "failed to allocate environment buffer");
		return -1;
	}
	memset(envp, 0, sizeof (char *) * envc);

	/*
	 * Copy the parameters as environment variables
	 */
	i = 0;
	/* reason */
	if ((envp[i++] = strdup(reason)) == NULL) {
		dprintf(LOG_NOTICE, FNAME,
		    "failed to allocate reason strings");
		ret = -1;
		goto clean;
	}
	/* "var=addr1 addr2 ... addrN" + null char for termination */
	if (dnsservers) {
		elen = sizeof (dnsserver_str) +
		    (INET6_ADDRSTRLEN + 1) * dnsservers + 1;
		if ((s = envp[i++] = malloc(elen)) == NULL) {
			dprintf(LOG_NOTICE, FNAME,
			    "failed to allocate strings for DNS servers");
			ret = -1;
			goto clean;
		}
		memset(s, 0, elen);
		snprintf(s, elen, "%s=", dnsserver_str);
		for (v = TAILQ_FIRST(&optinfo->dns_list); v;
		    v = TAILQ_NEXT(v, link)) {
			char *addr;

			addr = in6addr2str(&v->val_addr6, 0);
			strlcat(s, addr, elen);
			strlcat(s, " ", elen);
		}
	}
	if (ntpservers) {
		elen = sizeof (ntpserver_str) +
		    (INET6_ADDRSTRLEN + 1) * ntpservers + 1;
		if ((s = envp[i++] = malloc(elen)) == NULL) {
			dprintf(LOG_NOTICE, FNAME,
			    "failed to allocate strings for NTP servers");
			ret = -1;
			goto clean;
		}
		memset(s, 0, elen);
		snprintf(s, elen, "%s=", ntpserver_str);
		for (v = TAILQ_FIRST(&optinfo->ntp_list); v;
		    v = TAILQ_NEXT(v, link)) {
			char *addr;

			addr = in6addr2str(&v->val_addr6, 0);
			strlcat(s, addr, elen);
			strlcat(s, " ", elen);
		}
	}

	if (dnsnamelen) {
		elen = sizeof (dnsname_str) + dnsnamelen + 1;
		if ((s = envp[i++] = malloc(elen)) == NULL) {
			dprintf(LOG_NOTICE, FNAME,
			    "failed to allocate strings for DNS name");
			ret = -1;
			goto clean;
		}
		memset(s, 0, elen);
		snprintf(s, elen, "%s=", dnsname_str);
		for (v = TAILQ_FIRST(&optinfo->dnsname_list); v;
		    v = TAILQ_NEXT(v, link)) {
			strlcat(s, v->val_vbuf.dv_buf, elen);
			strlcat(s, " ", elen);
		}
	}

	if (sipservers) {
		elen = sizeof (sipserver_str) +
		    (INET6_ADDRSTRLEN + 1) * sipservers + 1;
		if ((s = envp[i++] = malloc(elen)) == NULL) {
			dprintf(LOG_NOTICE, FNAME,
			    "failed to allocate strings for SIP servers");
			ret = -1;
			goto clean;
		}
		memset(s, 0, elen);
		snprintf(s, elen, "%s=", sipserver_str);
		for (v = TAILQ_FIRST(&optinfo->sip_list); v;
		    v = TAILQ_NEXT(v, link)) {
			char *addr;

			addr = in6addr2str(&v->val_addr6, 0);
			strlcat(s, addr, elen);
			strlcat(s, " ", elen);
		}
	}
	if (sipnamelen) {
		elen = sizeof (sipname_str) + sipnamelen + 1;
		if ((s = envp[i++] = malloc(elen)) == NULL) {
			dprintf(LOG_NOTICE, FNAME,
			    "failed to allocate strings for SIP domain name");
			ret = -1;
			goto clean;
		}
		memset(s, 0, elen);
		snprintf(s, elen, "%s=", sipname_str);
		for (v = TAILQ_FIRST(&optinfo->sipname_list); v;
		    v = TAILQ_NEXT(v, link)) {
			strlcat(s, v->val_vbuf.dv_buf, elen);
			strlcat(s, " ", elen);
		}
	}

	if (nisservers) {
		elen = sizeof (nisserver_str) +
		    (INET6_ADDRSTRLEN + 1) * nisservers + 1;
		if ((s = envp[i++] = malloc(elen)) == NULL) {
			dprintf(LOG_NOTICE, FNAME,
			    "failed to allocate strings for NIS servers");
			ret = -1;
			goto clean;
		}
		memset(s, 0, elen);
		snprintf(s, elen, "%s=", nisserver_str);
		for (v = TAILQ_FIRST(&optinfo->nis_list); v;
		    v = TAILQ_NEXT(v, link)) {
			char *addr;

			addr = in6addr2str(&v->val_addr6, 0);
			strlcat(s, addr, elen);
			strlcat(s, " ", elen);
		}
	}
	if (nisnamelen) {
		elen = sizeof (nisname_str) + nisnamelen + 1;
		if ((s = envp[i++] = malloc(elen)) == NULL) {
			dprintf(LOG_NOTICE, FNAME,
			    "failed to allocate strings for NIS domain name");
			ret = -1;
			goto clean;
		}
		memset(s, 0, elen);
		snprintf(s, elen, "%s=", nisname_str);
		for (v = TAILQ_FIRST(&optinfo->nisname_list); v;
		    v = TAILQ_NEXT(v, link)) {
			strlcat(s, v->val_vbuf.dv_buf, elen);
			strlcat(s, " ", elen);
		}
	}

	if (nispservers) {
		elen = sizeof (nispserver_str) +
		    (INET6_ADDRSTRLEN + 1) * nispservers + 1;
		if ((s = envp[i++] = malloc(elen)) == NULL) {
			dprintf(LOG_NOTICE, FNAME,
			    "failed to allocate strings for NIS+ servers");
			ret = -1;
			goto clean;
		}
		memset(s, 0, elen);
		snprintf(s, elen, "%s=", nispserver_str);
		for (v = TAILQ_FIRST(&optinfo->nisp_list); v;
		    v = TAILQ_NEXT(v, link)) {
			char *addr;

			addr = in6addr2str(&v->val_addr6, 0);
			strlcat(s, addr, elen);
			strlcat(s, " ", elen);
		}
	}
	if (nispnamelen) {
		elen = sizeof (nispname_str) + nispnamelen + 1;
		if ((s = envp[i++] = malloc(elen)) == NULL) {
			dprintf(LOG_NOTICE, FNAME,
			    "failed to allocate strings for NIS+ domain name");
			ret = -1;
			goto clean;
		}
		memset(s, 0, elen);
		snprintf(s, elen, "%s=", nispname_str);
		for (v = TAILQ_FIRST(&optinfo->nispname_list); v;
		    v = TAILQ_NEXT(v, link)) {
			strlcat(s, v->val_vbuf.dv_buf, elen);
			strlcat(s, " ", elen);
		}
	}

	if (bcmcsservers) {
		elen = sizeof (bcmcsserver_str) +
		    (INET6_ADDRSTRLEN + 1) * bcmcsservers + 1;
		if ((s = envp[i++] = malloc(elen)) == NULL) {
			dprintf(LOG_NOTICE, FNAME,
			    "failed to allocate strings for BCMC servers");
			ret = -1;
			goto clean;
		}
		memset(s, 0, elen);
		snprintf(s, elen, "%s=", bcmcsserver_str);
		for (v = TAILQ_FIRST(&optinfo->bcmcs_list); v;
		    v = TAILQ_NEXT(v, link)) {
			char *addr;

			addr = in6addr2str(&v->val_addr6, 0);
			strlcat(s, addr, elen);
			strlcat(s, " ", elen);
		}
	}
	if (bcmcsnamelen) {
		elen = sizeof (bcmcsname_str) + bcmcsnamelen + 1;
		if ((s = envp[i++] = malloc(elen)) == NULL) {
			dprintf(LOG_NOTICE, FNAME,
			    "failed to allocate strings for BCMC domain name");
			ret = -1;
			goto clean;
		}
		memset(s, 0, elen);
		snprintf(s, elen, "%s=", bcmcsname_str);
		for (v = TAILQ_FIRST(&optinfo->bcmcsname_list); v;
		    v = TAILQ_NEXT(v, link)) {
			strlcat(s, v->val_vbuf.dv_buf, elen);
			strlcat(s, " ", elen);
		}
	}

	/* launch the script */
	pid = fork();
	if (pid < 0) {
		dprintf(LOG_ERR, FNAME, "failed to fork: %s", strerror(errno));
		ret = -1;
		goto clean;
	} else if (pid) {
		int wstatus;

		do {
			wpid = wait(&wstatus);
		} while (wpid != pid && wpid > 0);

		if (wpid < 0)
			dprintf(LOG_ERR, FNAME, "wait: %s", strerror(errno));
		else {
			dprintf(LOG_DEBUG, FNAME,
			    "script \"%s\" terminated", scriptpath);
		}
	} else {
		char *argv[2];
		int fd;

		argv[0] = scriptpath;
		argv[1] = NULL;

		if (safefile(scriptpath)) {
			dprintf(LOG_ERR, FNAME,
			    "script \"%s\" cannot be executed safely",
			    scriptpath);
			exit(1);
		}

		if (foreground == 0 && (fd = open("/dev/null", O_RDWR)) != -1) {
			dup2(fd, STDIN_FILENO);
			dup2(fd, STDOUT_FILENO);
			dup2(fd, STDERR_FILENO);
			if (fd > STDERR_FILENO)
				close(fd);
		}

		execve(scriptpath, argv, envp);

		dprintf(LOG_ERR, FNAME, "child: exec failed: %s",
		    strerror(errno));
		exit(0);
	}

  clean:
	for (i = 0; i < envc; i++)
		free(envp[i]);
	free(envp);

	return ret;
}
Пример #5
0
//void
//update_ia(iatype, ialist, ifp, serverid, authparam)
void
update_ia(
	iatype_t iatype,
	struct dhcp6_list *ialist,
	struct dhcp6_if *ifp,
	struct duid *serverid,
	struct authparam *authparam)
{
	struct ia *ia;
	struct ia_conf *iac;
	struct iapd_conf *iapdc;
	struct iana_conf *ianac;
	struct dhcp6_listval *iav, *siav;
	struct timeval timo;

    /* iav指向的是一个具体的节点,该节点的内容则是在iav->val_ia中给出 */
	for (iav = TAILQ_FIRST(ialist); iav; iav = TAILQ_NEXT(iav, link)) {
		/* if we're not interested in this IA, ignore it. */
        /* 根据配置文件中的配置来判断是否这个iac存在 */
		if ((iac = find_iaconf(&ifp->iaconf_list, iatype,
		    iav->val_ia.iaid)) == NULL) {
			continue;
		}

		/* validate parameters */
		/*
		 * If a client receives an IA_NA with T1 greater than T2, and
		 * both T1 and T2 are greater than 0, the client discards the
		 * IA_NA option and processes the remainder of the message as
		 * though the server had not included the invalid IA_NA option.
		 * [RFC3315 22.4]
		 * We apply the same rule to IA_PD as well.
		 */
		if (iav->val_ia.t2 != 0 && iav->val_ia.t1 > iav->val_ia.t2) {
			dprintf(LOG_INFO, FNAME,
			    "invalid IA: T1(%lu) > T2(%lu)",
			    iav->val_ia.t1, iav->val_ia.t2);
			continue;
		}

		/* locate the local IA or make a new one */
		ia = get_ia(iatype, ifp, iac, iav, serverid);
		if (ia == NULL) {
			dprintf(LOG_WARNING, FNAME, "failed to get an IA "
			    "type: %s, ID: %u", iastr(iac->type), iac->iaid);
			continue;
		}

		/* update authentication parameters */
		if (update_authparam(ia, authparam)) {
			dprintf(LOG_WARNING, FNAME, "failed to update "
			    "authentication param for IA "
			    "type: %s, ID: %u", iastr(iac->type), iac->iaid);
			remove_ia(ia);
			continue;
		}

		/* update IA configuration information */
		for (siav = TAILQ_FIRST(&iav->sublist); siav;
		    siav = TAILQ_NEXT(siav, link)) {
			switch (siav->type) {
			case DHCP6_LISTVAL_PREFIX6:
				/* add or update the prefix */
				iapdc = (struct iapd_conf *)iac;
				if (update_prefix(ia, &siav->val_prefix6,
				    &iapdc->iapd_pif_list, ifp, &ia->ctl,
				    callback)) {
					dprintf(LOG_NOTICE, FNAME,
					    "failed to update a prefix %s/%d",
					    in6addr2str(&siav->val_prefix6.addr, 0),
					    siav->val_prefix6.plen);
				}
				break;
			case DHCP6_LISTVAL_STATEFULADDR6:
				ianac = (struct iana_conf *)iac;
				if (update_address(ia, &siav->val_statefuladdr6,
				    ifp, &ia->ctl, callback)) {
					dprintf(LOG_NOTICE, FNAME,
					    "failed to update an address %s",
					    in6addr2str(&siav->val_statefuladdr6.addr, 0));
				}
				break;
			case DHCP6_LISTVAL_STCODE:
				dprintf(LOG_INFO, FNAME,
				    "status code for %s-%lu: %s",
				    iastr(iatype), iav->val_ia.iaid,
				    dhcp6_stcodestr(siav->val_num16));
				if ((ia->state == IAS_RENEW ||
				    ia->state == IAS_REBIND) &&
				    siav->val_num16 == DH6OPT_STCODE_NOBINDING) {
					/*
					 * For each IA in the original Renew or
					 * Rebind message, the client
					 * sends a Request message if the IA
					 * contained a Status Code option
					 * with the NoBinding status.
					 * [RFC3315 18.1.8]
					 * XXX: what about the PD case?
					 */
					dprintf(LOG_INFO, FNAME,
					    "receive NoBinding against "
					    "renew/rebind for %s-%lu",
					    iastr(ia->conf->type),
					    ia->conf->iaid);
					reestablish_ia(ia);
					goto nextia;
				}
				break;
			default:
				dprintf(LOG_ERR, FNAME, "impossible case");
				goto nextia;
			}
		}

		/* see if this IA is still valid.  if not, remove it. */
		if (ia->ctl == NULL || !(*ia->ctl->isvalid)(ia->ctl)) {
			dprintf(LOG_DEBUG, FNAME, "IA %s-%lu is invalidated",
			    iastr(ia->conf->type), ia->conf->iaid);
			remove_ia(ia);
			continue;
		}

		/* if T1 or T2 is 0, determine appropriate values locally. */
		if (ia->t1 == 0 || ia->t2 == 0) {
			u_int32_t duration;

			if (ia->ctl && ia->ctl->duration)
				duration = (*ia->ctl->duration)(ia->ctl);
			else
				duration = 1800; /* 30min. XXX: no rationale */

			if (ia->t1 == 0) {
				if (duration == DHCP6_DURATION_INFINITE)
					ia->t1 = DHCP6_DURATION_INFINITE;
				else
					ia->t1 = duration / 2;
			}
			if (ia->t2 == 0) {
				if (duration == DHCP6_DURATION_INFINITE)
					ia->t2 = DHCP6_DURATION_INFINITE;
				else
					ia->t2 = duration * 4 / 5;
			}

			/* make sure T1 <= T2 */
			if (ia->t1 > ia->t2)
				ia->t1 = ia->t2 * 5 / 8;

			dprintf(LOG_INFO, FNAME, "T1(%lu) and/or T2(%lu) "
			    "is locally determined",  ia->t1, ia->t2);
		}

		/*
		 * Be proactive for too-small timeout values.  Note that
		 * the adjusted values may make some information expire
		 * without renewal.
		 */
		if (ia->t2 < DHCP6_DURATION_MIN) {
			dprintf(LOG_INFO, FNAME, "T1 (%lu) or T2 (%lu) "
			    "is too small", ia->t1, ia->t2);
			ia->t2 = DHCP6_DURATION_MIN;
			ia->t1 = ia->t2 * 5 / 8;
			dprintf(LOG_INFO, "", "  adjusted to %lu and %lu",
			    ia->t1, ia->t2);
		}

		/* set up a timer for this IA. */
		if (ia->t1 == DHCP6_DURATION_INFINITE) {
			if (ia->timer)
				dhcp6_remove_timer(&ia->timer);
		} else {
			if (ia->timer == NULL)
				ia->timer = dhcp6_add_timer(ia_timo, ia);
			if (ia->timer == NULL) {
				dprintf(LOG_ERR, FNAME,
				    "failed to add IA timer");
				remove_ia(ia); /* XXX */
				continue;
			}
			timo.tv_sec = ia->t1;
			timo.tv_usec = 0;

            loginfo(FUNC, "set renew time: %d second", timo.tv_sec);
            
			dhcp6_set_timer(&timo, ia->timer);
		}

        /* 更新这个ia的状态为ACTIVE,接下来就可以使用renew来更新了 */
		ia->state = IAS_ACTIVE;

	  nextia:
		;
	}
}