Ejemplo n.º 1
0
static boolean_t
stop_requesting(dhcp_smach_t *dsmp, unsigned int n_requests)
{
	uint_t maxreq;

	maxreq = dsmp->dsm_isv6 ? DHCPV6_REQ_MAX_RC : DHCP_MAX_REQUESTS;
	if (n_requests >= maxreq) {

		dhcpmsg(MSG_INFO, "no ACK/NAK/Reply to REQUEST on %s",
		    dsmp->dsm_name);

		request_failed(dsmp);
		return (B_TRUE);
	} else {
		return (B_FALSE);
	}
}
Ejemplo n.º 2
0
static void
accept_v6_message(dhcp_smach_t *dsmp, PKT_LIST *plp, const char *pname,
    uchar_t recv_type)
{
	const dhcpv6_option_t *d6o;
	uint_t olen;
	const char *estr, *msg;
	uint_t msglen;
	int status;

	/* Account for received and processed messages */
	dsmp->dsm_received++;

	/* We don't yet support Reconfigure at all. */
	if (recv_type == DHCPV6_MSG_RECONFIGURE) {
		dhcpmsg(MSG_VERBOSE, "accept_v6_message: ignored Reconfigure "
		    "on %s", dsmp->dsm_name);
		free_pkt_entry(plp);
		return;
	}

	/*
	 * All valid DHCPv6 messages must have our Client ID specified.
	 */
	d6o = dhcpv6_pkt_option(plp, NULL, DHCPV6_OPT_CLIENTID, &olen);
	olen -= sizeof (*d6o);
	if (d6o == NULL || olen != dsmp->dsm_cidlen ||
	    memcmp(d6o + 1, dsmp->dsm_cid, olen) != 0) {
		dhcpmsg(MSG_VERBOSE,
		    "accept_v6_message: discarded %s on %s: %s Client ID",
		    pname, dsmp->dsm_name, d6o == NULL ? "no" : "wrong");
		free_pkt_entry(plp);
		return;
	}

	/*
	 * All valid DHCPv6 messages must have a Server ID specified.
	 *
	 * If this is a Reply and it's not in response to Solicit, Confirm,
	 * Rebind, or Information-Request, then it must also match the Server
	 * ID we're expecting.
	 *
	 * For Reply in the Solicit, Confirm, Rebind, and Information-Request
	 * cases, the Server ID needs to be saved.  This is done inside of
	 * dhcp_bound().
	 */
	d6o = dhcpv6_pkt_option(plp, NULL, DHCPV6_OPT_SERVERID, &olen);
	if (d6o == NULL) {
		dhcpmsg(MSG_DEBUG,
		    "accept_v6_message: discarded %s on %s: no Server ID",
		    pname, dsmp->dsm_name);
		free_pkt_entry(plp);
		return;
	}
	if (recv_type == DHCPV6_MSG_REPLY && dsmp->dsm_state != SELECTING &&
	    dsmp->dsm_state != INIT_REBOOT && dsmp->dsm_state != REBINDING &&
	    dsmp->dsm_state != INFORM_SENT) {
		olen -= sizeof (*d6o);
		if (olen != dsmp->dsm_serveridlen ||
		    memcmp(d6o + 1, dsmp->dsm_serverid, olen) != 0) {
			dhcpmsg(MSG_DEBUG, "accept_v6_message: discarded %s on "
			    "%s: wrong Server ID", pname, dsmp->dsm_name);
			free_pkt_entry(plp);
			return;
		}
	}

	/*
	 * Break out of the switch if the input message needs to be discarded.
	 * Return from the function if the message has been enqueued or
	 * consumed.
	 */
	switch (dsmp->dsm_state) {
	case SELECTING:
		/* A Reply message signifies a Rapid-Commit. */
		if (recv_type == DHCPV6_MSG_REPLY) {
			if (dhcpv6_pkt_option(plp, NULL,
			    DHCPV6_OPT_RAPID_COMMIT, &olen) == NULL) {
				dhcpmsg(MSG_DEBUG, "accept_v6_message: Reply "
				    "on %s lacks Rapid-Commit; ignoring",
				    dsmp->dsm_name);
				break;
			}
			dhcpmsg(MSG_VERBOSE,
			    "accept_v6_message: rapid-commit Reply on %s",
			    dsmp->dsm_name);
			cancel_offer_timer(dsmp);
			goto rapid_commit;
		}

		/* Otherwise, we're looking for Advertisements. */
		if (recv_type != DHCPV6_MSG_ADVERTISE)
			break;

		/*
		 * Special case: if this advertisement has preference 255, then
		 * we must stop right now and select this server.
		 */
		d6o = dhcpv6_pkt_option(plp, NULL, DHCPV6_OPT_PREFERENCE,
		    &olen);
		if (d6o != NULL && olen == sizeof (*d6o) + 1 &&
		    *(const uchar_t *)(d6o + 1) == 255) {
			pkt_smach_enqueue(dsmp, plp);
			dhcpmsg(MSG_DEBUG, "accept_v6_message: preference 255;"
			    " immediate Request on %s", dsmp->dsm_name);
			dhcp_requesting(NULL, dsmp);
		} else {
			pkt_smach_enqueue(dsmp, plp);
		}
		return;

	case PRE_BOUND:
	case BOUND:
		/*
		 * Not looking for anything in these states.  (If we
		 * implemented reconfigure, that might go here.)
		 */
		break;

	case REQUESTING:
	case INIT_REBOOT:
	case RENEWING:
	case REBINDING:
	case INFORM_SENT:
		/*
		 * We're looking for Reply messages.
		 */
		if (recv_type != DHCPV6_MSG_REPLY)
			break;
		dhcpmsg(MSG_VERBOSE,
		    "accept_v6_message: received Reply message on %s",
		    dsmp->dsm_name);
	rapid_commit:
		/*
		 * Extract the status code option.  If one is present and the
		 * request failed, then try to go to another advertisement in
		 * the list or restart the selection machinery.
		 */
		d6o = dhcpv6_pkt_option(plp, NULL, DHCPV6_OPT_STATUS_CODE,
		    &olen);
		status = dhcpv6_status_code(d6o, olen, &estr, &msg, &msglen);
		/*
		 * Check for the UseMulticast status code.  If this is present,
		 * and if we were actually using unicast, then drop back and
		 * try again.  If we weren't using unicast, then just pretend
		 * we never saw this message -- the peer is confused.  (TAHI
		 * does this.)
		 */
		if (status == DHCPV6_STAT_USEMCAST) {
			if (IN6_IS_ADDR_MULTICAST(
			    &dsmp->dsm_send_dest.v6.sin6_addr)) {
				break;
			} else {
				free_pkt_entry(plp);
				dsmp->dsm_send_dest.v6.sin6_addr =
				    ipv6_all_dhcp_relay_and_servers;
				retransmit_now(dsmp);
				return;
			}
		}
		print_server_msg(dsmp, msg, msglen);
		/*
		 * We treat NoBinding at the top level as "success."  Granted,
		 * this doesn't make much sense, but the TAHI test suite does
		 * this.  NoBinding really only makes sense in the context of a
		 * specific IA, as it refers to the GUID:IAID binding, so
		 * ignoring it at the top level is safe.
		 */
		if (status == DHCPV6_STAT_SUCCESS ||
		    status == DHCPV6_STAT_NOBINDING) {
			if (dhcp_bound(dsmp, plp)) {
				/*
				 * dhcp_bound will stop retransmission on
				 * success, if that's called for.
				 */
				server_unicast_option(dsmp, plp);
			} else {
				stop_pkt_retransmission(dsmp);
				dhcpmsg(MSG_WARNING, "accept_v6_message: "
				    "dhcp_bound failed for %s", dsmp->dsm_name);
				(void) remove_hostconf(dsmp->dsm_name,
				    dsmp->dsm_isv6);
				dhcp_restart(dsmp);
			}
		} else {
			dhcpmsg(MSG_WARNING, "accept_v6_message: Reply: %s",
			    estr);
			stop_pkt_retransmission(dsmp);
			free_pkt_entry(plp);
			if (dsmp->dsm_state == INFORM_SENT) {
				(void) set_smach_state(dsmp, INIT);
				ipc_action_finish(dsmp, DHCP_IPC_E_SRVFAILED);
			} else {
				(void) remove_hostconf(dsmp->dsm_name,
				    dsmp->dsm_isv6);
				request_failed(dsmp);
			}
		}
		return;

	case DECLINING:
		/*
		 * We're looking for Reply messages.
		 */
		if (recv_type != DHCPV6_MSG_REPLY)
			break;
		stop_pkt_retransmission(dsmp);
		/*
		 * Extract the status code option.  Note that it's not a
		 * failure if the server reports an error.
		 */
		d6o = dhcpv6_pkt_option(plp, NULL, DHCPV6_OPT_STATUS_CODE,
		    &olen);
		if (dhcpv6_status_code(d6o, olen, &estr, &msg,
		    &msglen) == DHCPV6_STAT_SUCCESS) {
			print_server_msg(dsmp, msg, msglen);
		} else {
			dhcpmsg(MSG_WARNING, "accept_v6_message: Reply: %s",
			    estr);
		}
		free_pkt_entry(plp);
		if (dsmp->dsm_leases == NULL) {
			dhcpmsg(MSG_VERBOSE, "accept_v6_message: %s has no "
			    "leases left", dsmp->dsm_name);
			dhcp_restart(dsmp);
		} else if (dsmp->dsm_lif_wait == 0) {
			(void) set_smach_state(dsmp, BOUND);
		} else {
			(void) set_smach_state(dsmp, PRE_BOUND);
		}
		return;

	case RELEASING:
		/*
		 * We're looking for Reply messages.
		 */
		if (recv_type != DHCPV6_MSG_REPLY)
			break;
		stop_pkt_retransmission(dsmp);
		/*
		 * Extract the status code option.
		 */
		d6o = dhcpv6_pkt_option(plp, NULL, DHCPV6_OPT_STATUS_CODE,
		    &olen);
		if (dhcpv6_status_code(d6o, olen, &estr, &msg,
		    &msglen) == DHCPV6_STAT_SUCCESS) {
			print_server_msg(dsmp, msg, msglen);
		} else {
			dhcpmsg(MSG_WARNING, "accept_v6_message: Reply: %s",
			    estr);
		}
		free_pkt_entry(plp);
		finished_smach(dsmp, DHCP_IPC_SUCCESS);
		return;
	}

	/*
	 * Break from above switch means that the message must be discarded.
	 */
	dhcpmsg(MSG_VERBOSE,
	    "accept_v6_message: discarded v6 %s on %s; state %s",
	    pname, dsmp->dsm_name, dhcp_state_to_string(dsmp->dsm_state));
	free_pkt_entry(plp);
}
Ejemplo n.º 3
0
void absent_packet_list::request_failed(const iterator& itr, timestamp_t now, int reRequestDelay)
{
	BOOST_ASSERT(requesting_packets_.find(*itr) == itr);
	request_failed(*itr, now, reRequestDelay);
}