Exemplo n.º 1
0
/* ARGSUSED */
void
dhcp_renew(iu_tq_t *tqp, void *arg)
{
	dhcp_lease_t *dlp = arg;
	dhcp_smach_t *dsmp = dlp->dl_smach;
	uint32_t	t2;

	dhcpmsg(MSG_VERBOSE, "dhcp_renew: T1 timer expired on %s",
	    dsmp->dsm_name);

	dlp->dl_t1.dt_id = -1;

	if (dsmp->dsm_state == RENEWING || dsmp->dsm_state == REBINDING) {
		dhcpmsg(MSG_DEBUG, "dhcp_renew: already renewing");
		release_lease(dlp);
		return;
	}

	/*
	 * Sanity check: don't send packets if we're past T2, or if we're
	 * extremely close.
	 */

	t2 = dsmp->dsm_curstart_monosec + dlp->dl_t2.dt_start;
	if (monosec() + TOO_CLOSE >= t2) {
		dhcpmsg(MSG_DEBUG, "dhcp_renew: %spast T2 on %s",
		    monosec() > t2 ? "" : "almost ", dsmp->dsm_name);
		release_lease(dlp);
		return;
	}

	/*
	 * If there isn't an async event pending, or if we can cancel the one
	 * that's there, then try to renew by sending an extension request.  If
	 * that fails, we'll try again when the next timer fires.
	 */
	if (!async_cancel(dsmp) || !async_start(dsmp, DHCP_EXTEND, B_FALSE) ||
	    !dhcp_extending(dsmp)) {
		if (monosec() + RETRY_DELAY < t2) {
			/*
			 * Try again in RETRY_DELAY seconds; user command
			 * should be gone.
			 */
			init_timer(&dlp->dl_t1, RETRY_DELAY);
			(void) set_smach_state(dsmp, BOUND);
			if (!schedule_lease_timer(dlp, &dlp->dl_t1,
			    dhcp_renew)) {
				dhcpmsg(MSG_INFO, "dhcp_renew: unable to "
				    "reschedule renewal around user command "
				    "on %s; will wait for rebind",
				    dsmp->dsm_name);
			}
		} else {
			dhcpmsg(MSG_DEBUG, "dhcp_renew: user busy on %s; will "
			    "wait for rebind", dsmp->dsm_name);
		}
	}
	release_lease(dlp);
}
Exemplo n.º 2
0
static uint32_t
next_extend_time(monosec_t limit_monosec)
{
	monosec_t	current_monosec = monosec();

	if (limit_monosec - current_monosec < DHCP_REBIND_MIN)
		return (0);

	return ((limit_monosec - current_monosec) / 2);
}
Exemplo n.º 3
0
/* ARGSUSED */
static boolean_t
stop_extending(dhcp_smach_t *dsmp, unsigned int n_requests)
{
	dhcp_lease_t *dlp;

	/*
	 * If we're renewing and rebind time is soon approaching, then don't
	 * schedule
	 */
	if (dsmp->dsm_state == RENEWING) {
		monosec_t t2;

		t2 = 0;
		for (dlp = dsmp->dsm_leases; dlp != NULL; dlp = dlp->dl_next) {
			if (dlp->dl_t2.dt_start > t2)
				t2 = dlp->dl_t2.dt_start;
		}
		t2 += dsmp->dsm_curstart_monosec;
		if (monosec() + TOO_CLOSE >= t2) {
			dhcpmsg(MSG_DEBUG, "stop_extending: %spast T2 on %s",
			    monosec() > t2 ? "" : "almost ", dsmp->dsm_name);
			return (B_TRUE);
		}
	}

	/*
	 * Note that returning B_TRUE cancels both this transmission and the
	 * one that would occur at dsm_send_timeout, and that for v4 we cut the
	 * time in half for each retransmission.  Thus we check here against
	 * half of the minimum.
	 */
	if (!dsmp->dsm_isv6 &&
	    dsmp->dsm_send_timeout < DHCP_REBIND_MIN * MILLISEC / 2) {
		dhcpmsg(MSG_DEBUG, "stop_extending: next retry would be in "
		    "%d.%03d; stopping", dsmp->dsm_send_timeout / MILLISEC,
		    dsmp->dsm_send_timeout % MILLISEC);
		return (B_TRUE);
	}

	/* Otherwise, w stop only when the next timer (rebind, expire) fires */
	return (B_FALSE);
}
Exemplo n.º 4
0
/* ARGSUSED */
void
dhcp_renew(iu_tq_t *tqp, void *arg)
{
	struct ifslist *ifsp = (struct ifslist *)arg;
	uint32_t	next;


	ifsp->if_timer[DHCP_T1_TIMER] = -1;

	if (check_ifs(ifsp) == 0) {
		(void) release_ifs(ifsp);
		return;
	}

	/*
	 * sanity check: don't send packets if we're past t2.
	 */

	if (monosec() > (ifsp->if_curstart_monosec + ifsp->if_t2))
		return;

	next = next_extend_time(ifsp->if_curstart_monosec + ifsp->if_t2);

	/*
	 * if there isn't an async event pending, then try to renew.
	 */

	if (!async_pending(ifsp))
		if (async_start(ifsp, DHCP_EXTEND, B_FALSE) != 0)

			/*
			 * try to send extend.  if we don't succeed,
			 * async_timeout() will clean us up.
			 */

			(void) dhcp_extending(ifsp);

	/*
	 * if we're within DHCP_REBIND_MIN seconds of REBINDING, don't
	 * reschedule ourselves.
	 */

	if (next == 0)
		return;

	/*
	 * no big deal if we can't reschedule; we still have the REBIND
	 * state to save us.
	 */

	(void) schedule_ifs_timer(ifsp, DHCP_T1_TIMER, next, dhcp_renew);
}
Exemplo n.º 5
0
/* ARGSUSED */
void
dhcp_rebind(iu_tq_t *tqp, void *arg)
{
	dhcp_lease_t	*dlp = arg;
	dhcp_smach_t	*dsmp = dlp->dl_smach;
	int		nlifs;
	dhcp_lif_t	*lif;
	boolean_t	some_valid;
	uint32_t	expiremax;
	DHCPSTATE	oldstate;

	dhcpmsg(MSG_VERBOSE, "dhcp_rebind: T2 timer expired on %s",
	    dsmp->dsm_name);

	dlp->dl_t2.dt_id = -1;

	if ((oldstate = dsmp->dsm_state) == REBINDING) {
		dhcpmsg(MSG_DEBUG, "dhcp_renew: already rebinding");
		release_lease(dlp);
		return;
	}

	/*
	 * Sanity check: don't send packets if we've already expired on all of
	 * the addresses.  We compute the maximum expiration time here, because
	 * it won't matter for v4 (there's only one lease) and for v6 we need
	 * to know when the last lease ages away.
	 */

	some_valid = B_FALSE;
	expiremax = monosec();
	lif = dlp->dl_lifs;
	for (nlifs = dlp->dl_nlifs; nlifs > 0; nlifs--, lif = lif->lif_next) {
		uint32_t expire;

		expire = dsmp->dsm_curstart_monosec + lif->lif_expire.dt_start;
		if (expire > expiremax) {
			expiremax = expire;
			some_valid = B_TRUE;
		}
	}
	if (!some_valid) {
		dhcpmsg(MSG_DEBUG, "dhcp_rebind: all leases expired on %s",
		    dsmp->dsm_name);
		release_lease(dlp);
		return;
	}

	/*
	 * This is our first venture into the REBINDING state, so reset the
	 * server address.  We know the renew timer has already been cancelled
	 * (or we wouldn't be here).
	 */
	if (dsmp->dsm_isv6) {
		dsmp->dsm_server = ipv6_all_dhcp_relay_and_servers;
	} else {
		IN6_IPADDR_TO_V4MAPPED(htonl(INADDR_BROADCAST),
		    &dsmp->dsm_server);
	}

	/* {Bound,Renew}->rebind transitions cannot fail */
	(void) set_smach_state(dsmp, REBINDING);

	/*
	 * If there isn't an async event pending, or if we can cancel the one
	 * that's there, then try to rebind by sending an extension request.
	 * If that fails, we'll clean up when the lease expires.
	 */
	if (!async_cancel(dsmp) || !async_start(dsmp, DHCP_EXTEND, B_FALSE) ||
	    !dhcp_extending(dsmp)) {
		if (monosec() + RETRY_DELAY < expiremax) {
			/*
			 * Try again in RETRY_DELAY seconds; user command
			 * should be gone.
			 */
			init_timer(&dlp->dl_t2, RETRY_DELAY);
			(void) set_smach_state(dsmp, oldstate);
			if (!schedule_lease_timer(dlp, &dlp->dl_t2,
			    dhcp_rebind)) {
				dhcpmsg(MSG_INFO, "dhcp_rebind: unable to "
				    "reschedule rebind around user command on "
				    "%s; lease may expire", dsmp->dsm_name);
			}
		} else {
			dhcpmsg(MSG_WARNING, "dhcp_rebind: user busy on %s; "
			    "will expire", dsmp->dsm_name);
		}
	}
	release_lease(dlp);
}
Exemplo n.º 6
0
time_t
monosec_to_time(monosec_t abs_monosec)
{
	return (abs_monosec - monosec()) + time(NULL);
}
Exemplo n.º 7
0
int
dhcp_extending(struct ifslist *ifsp)
{
	dhcp_pkt_t		*dpkt;

	if (ifsp->if_state == BOUND) {
		ifsp->if_neg_monosec	= monosec();
		ifsp->if_state		= RENEWING;
		ifsp->if_bad_offers	= 0;
		ifsp->if_sent		= 0;
		ifsp->if_received	= 0;
	}

	dhcpmsg(MSG_DEBUG, "dhcp_extending: registering dhcp_acknak on %s",
	    ifsp->if_name);

	if (register_acknak(ifsp) == 0) {

		ipc_action_finish(ifsp, DHCP_IPC_E_MEMORY);
		async_finish(ifsp);

		dhcpmsg(MSG_WARNING, "dhcp_extending: cannot register "
		    "dhcp_acknak for %s, not sending renew request",
		    ifsp->if_name);

		return (0);
	}

	/*
	 * assemble DHCPREQUEST message.  The max dhcp message size
	 * option is set to the interface max, minus the size of the udp and
	 * ip headers.
	 */

	dpkt = init_pkt(ifsp, REQUEST);
	dpkt->pkt->ciaddr.s_addr = ifsp->if_addr.s_addr;

	add_pkt_opt16(dpkt, CD_MAX_DHCP_SIZE, htons(ifsp->if_max -
			sizeof (struct udpiphdr)));
	add_pkt_opt32(dpkt, CD_LEASE_TIME, htonl(DHCP_PERM));

	add_pkt_opt(dpkt, CD_CLASS_ID, class_id, class_id_len);
	add_pkt_opt(dpkt, CD_REQUEST_LIST, ifsp->if_prl, ifsp->if_prllen);
	/*
	 * if_reqhost was set for this interface in dhcp_selecting()
	 * if the REQUEST_HOSTNAME option was set and a host name was
	 * found.
	 */
	if (ifsp->if_reqhost != NULL) {
		add_pkt_opt(dpkt, CD_HOSTNAME, ifsp->if_reqhost,
		    strlen(ifsp->if_reqhost));
	}
	add_pkt_opt(dpkt, CD_END, NULL, 0);

	/*
	 * if we can't send the packet, leave the event handler registered
	 * anyway, since we're not expecting to get any other types of
	 * packets in other than ACKs/NAKs anyway.
	 */

	return (send_pkt(ifsp, dpkt, ifsp->if_server.s_addr, NULL));
}
Exemplo n.º 8
0
/* ARGSUSED */
void
dhcp_rebind(iu_tq_t *tqp, void *arg)
{
	struct ifslist *ifsp = (struct ifslist *)arg;
	uint32_t	next;

	ifsp->if_timer[DHCP_T2_TIMER] = -1;

	if (check_ifs(ifsp) == 0) {
		(void) release_ifs(ifsp);
		return;
	}

	/*
	 * sanity check: don't send packets if we've already expired.
	 */

	if (monosec() > (ifsp->if_curstart_monosec + ifsp->if_lease))
		return;

	next = next_extend_time(ifsp->if_curstart_monosec + ifsp->if_lease);

	/*
	 * if this is our first venture into the REBINDING state, then
	 * reset the server address.  we know the renew timer has
	 * already been cancelled (or we wouldn't be here).
	 */

	if (ifsp->if_state == RENEWING) {
		ifsp->if_state = REBINDING;
		ifsp->if_server.s_addr = htonl(INADDR_BROADCAST);
	}

	/*
	 * if there isn't an async event pending, then try to rebind.
	 */

	if (!async_pending(ifsp))
		if (async_start(ifsp, DHCP_EXTEND, B_FALSE) != 0)

			/*
			 * try to send extend.  if we don't succeed,
			 * async_timeout() will clean us up.
			 */

			(void) dhcp_extending(ifsp);

	/*
	 * if we're within DHCP_REBIND_MIN seconds of EXPIRE, don't
	 * reschedule ourselves.
	 */

	if (next == 0) {
		dhcpmsg(MSG_WARNING, "dhcp_rebind: lease on %s expires in less "
		    "than %i seconds!", ifsp->if_name, DHCP_REBIND_MIN);
		return;
	}

	if (schedule_ifs_timer(ifsp, DHCP_T2_TIMER, next, dhcp_rebind) == 0)

		/*
		 * we'll just end up in dhcp_expire(), but it sure sucks.
		 */

		dhcpmsg(MSG_CRIT, "dhcp_rebind: cannot reschedule another "
		    "rebind attempt; lease may expire for %s", ifsp->if_name);
}