static void
bound4_handle (NMDhcpSystemd *self)
{
	NMDhcpSystemdPrivate *priv = NM_DHCP_SYSTEMD_GET_PRIVATE (self);
	const char *iface = nm_dhcp_client_get_iface (NM_DHCP_CLIENT (self));
	sd_dhcp_lease *lease;
	NMIP4Config *ip4_config;
	GHashTable *options;
	GError *error = NULL;
	int r;

	r = sd_dhcp_client_get_lease (priv->client4, &lease);
	if (r < 0 || !lease) {
		_LOGW ("no lease!");
		nm_dhcp_client_set_state (NM_DHCP_CLIENT (self), NM_DHCP_STATE_FAIL, NULL, NULL);
		return;
	}

	_LOGD ("lease available");

	options = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, g_free);
	ip4_config = lease_to_ip4_config (iface,
	                                  nm_dhcp_client_get_ifindex (NM_DHCP_CLIENT (self)),
	                                  lease,
	                                  options,
	                                  nm_dhcp_client_get_priority (NM_DHCP_CLIENT (self)),
	                                  TRUE,
	                                  &error);
	if (ip4_config) {
		const uint8_t *client_id = NULL;
		size_t client_id_len = 0;
		uint8_t type = 0;

		add_requests_to_options (options, dhcp4_requests);
		dhcp_lease_save (lease, priv->lease_file);

		sd_dhcp_client_get_client_id(priv->client4, &type, &client_id, &client_id_len);
		if (client_id)
			_save_client_id (self, type, client_id, client_id_len);

		nm_dhcp_client_set_state (NM_DHCP_CLIENT (self),
		                          NM_DHCP_STATE_BOUND,
		                          G_OBJECT (ip4_config),
		                          options);
	} else {
		_LOGW ("%s", error->message);
		nm_dhcp_client_set_state (NM_DHCP_CLIENT (self), NM_DHCP_STATE_FAIL, NULL, NULL);
		g_clear_error (&error);
	}

	g_hash_table_destroy (options);
	g_clear_object (&ip4_config);
}
static gboolean
ip4_start (NMDhcpClient *client, const char *dhcp_anycast_addr, const char *last_ip4_address)
{
	NMDhcpSystemd *self = NM_DHCP_SYSTEMD (client);
	NMDhcpSystemdPrivate *priv = NM_DHCP_SYSTEMD_GET_PRIVATE (self);
	const char *iface = nm_dhcp_client_get_iface (client);
	const GByteArray *hwaddr;
	sd_dhcp_lease *lease = NULL;
	GBytes *override_client_id;
	const uint8_t *client_id = NULL;
	size_t client_id_len = 0;
	struct in_addr last_addr = { 0 };
	const char *hostname, *fqdn;
	int r, i;
	gboolean success = FALSE;
	guint16 arp_type;

	g_assert (priv->client4 == NULL);
	g_assert (priv->client6 == NULL);

	g_free (priv->lease_file);
	priv->lease_file = get_leasefile_path (iface, nm_dhcp_client_get_uuid (client), FALSE);

	r = sd_dhcp_client_new (&priv->client4);
	if (r < 0) {
		_LOGW ("failed to create client (%d)", r);
		return FALSE;
	}

	_LOGT ("dhcp-client4: set %p", priv->client4);

	r = sd_dhcp_client_attach_event (priv->client4, NULL, 0);
	if (r < 0) {
		_LOGW ("failed to attach event (%d)", r);
		goto error;
	}

	hwaddr = nm_dhcp_client_get_hw_addr (client);
	if (hwaddr) {
		arp_type= get_arp_type (hwaddr);
		if (arp_type == ARPHRD_NONE) {
			_LOGW ("failed to determine ARP type");
			goto error;
		}

		r = sd_dhcp_client_set_mac (priv->client4,
		                            hwaddr->data,
		                            hwaddr->len,
		                            arp_type);
		if (r < 0) {
			_LOGW ("failed to set MAC address (%d)", r);
			goto error;
		}
	}

	r = sd_dhcp_client_set_index (priv->client4, nm_dhcp_client_get_ifindex (client));
	if (r < 0) {
		_LOGW ("failed to set ifindex (%d)", r);
		goto error;
	}

	r = sd_dhcp_client_set_callback (priv->client4, dhcp_event_cb, client);
	if (r < 0) {
		_LOGW ("failed to set callback (%d)", r);
		goto error;
	}

	r = sd_dhcp_client_set_request_broadcast (priv->client4, true);
	if (r < 0) {
		_LOGW ("failed to enable broadcast mode (%d)", r);
		goto error;
	}

	dhcp_lease_load (&lease, priv->lease_file);

	if (last_ip4_address)
		inet_pton (AF_INET, last_ip4_address, &last_addr);
	else if (lease)
		sd_dhcp_lease_get_address (lease, &last_addr);

	if (last_addr.s_addr) {
		r = sd_dhcp_client_set_request_address (priv->client4, &last_addr);
		if (r < 0) {
			_LOGW ("failed to set last IPv4 address (%d)", r);
			goto error;
		}
	}

	override_client_id = nm_dhcp_client_get_client_id (client);
	if (override_client_id) {
		client_id = g_bytes_get_data (override_client_id, &client_id_len);
		g_assert (client_id && client_id_len);
		sd_dhcp_client_set_client_id (priv->client4,
		                              client_id[0],
		                              client_id + 1,
		                              client_id_len - 1);
	} else if (lease) {
		r = sd_dhcp_lease_get_client_id (lease, (const void **) &client_id, &client_id_len);
		if (r == 0 && client_id_len) {
			sd_dhcp_client_set_client_id (priv->client4,
			                              client_id[0],
			                              client_id + 1,
			                              client_id_len - 1);
			_save_client_id (NM_DHCP_SYSTEMD (client),
			                 client_id[0],
			                 client_id + 1,
			                 client_id_len - 1);
		}
	}


	/* Add requested options */
	for (i = 0; dhcp4_requests[i].name; i++) {
		if (dhcp4_requests[i].include)
			sd_dhcp_client_set_request_option (priv->client4, dhcp4_requests[i].num);
	}

	hostname = nm_dhcp_client_get_hostname (client);
	if (hostname) {
		char *prefix, *dot;

		prefix = strdup (hostname);
		dot = strchr (prefix, '.');
		/* get rid of the domain */
		if (dot)
			*dot = '\0';

		r = sd_dhcp_client_set_hostname (priv->client4, prefix);
		free (prefix);

		if (r < 0) {
			_LOGW ("failed to set DHCP hostname (%d)", r);
			goto error;
		}
	}

	fqdn = nm_dhcp_client_get_fqdn (client);
	if (fqdn) {
		r = sd_dhcp_client_set_hostname (priv->client4, fqdn);
		if (r < 0) {
			_LOGW ("failed to set DHCP FQDN (%d)", r);
			goto error;
		}
	}

	r = sd_dhcp_client_start (priv->client4);
	if (r < 0) {
		_LOGW ("failed to start client (%d)", r);
		goto error;
	}

	nm_dhcp_client_start_timeout (client);

	success = TRUE;

error:
	sd_dhcp_lease_unref (lease);
	if (!success)
		priv->client4 = sd_dhcp_client_unref (priv->client4);
	return success;
}
static gboolean
ip4_start (NMDhcpClient *client, const char *dhcp_anycast_addr, const char *last_ip4_address)
{
	NMDhcpSystemdPrivate *priv = NM_DHCP_SYSTEMD_GET_PRIVATE (client);
	const char *iface = nm_dhcp_client_get_iface (client);
	const GByteArray *hwaddr;
	sd_dhcp_lease *lease = NULL;
	GBytes *override_client_id;
	const uint8_t *client_id = NULL;
	size_t client_id_len = 0;
	struct in_addr last_addr = { 0 };
	const char *hostname;
	int r, i;
	gboolean success = FALSE;

	g_assert (priv->client4 == NULL);
	g_assert (priv->client6 == NULL);

	g_free (priv->lease_file);
	priv->lease_file = get_leasefile_path (iface, nm_dhcp_client_get_uuid (client), FALSE);

	r = sd_dhcp_client_new (&priv->client4);
	if (r < 0) {
		nm_log_warn (LOGD_DHCP4, "(%s): failed to create DHCPv4 client (%d)", iface, r);
		return FALSE;
	}

	r = sd_dhcp_client_attach_event (priv->client4, NULL, 0);
	if (r < 0) {
		nm_log_warn (LOGD_DHCP4, "(%s): failed to attach DHCP event (%d)", iface, r);
		goto error;
	}

	hwaddr = nm_dhcp_client_get_hw_addr (client);
	if (hwaddr) {
		r = sd_dhcp_client_set_mac (priv->client4,
		                            hwaddr->data,
		                            hwaddr->len,
		                            get_arp_type (hwaddr));
		if (r < 0) {
			nm_log_warn (LOGD_DHCP4, "(%s): failed to set DHCP MAC address (%d)", iface, r);
			goto error;
		}
	}

	r = sd_dhcp_client_set_index (priv->client4, nm_dhcp_client_get_ifindex (client));
	if (r < 0) {
		nm_log_warn (LOGD_DHCP4, "(%s): failed to set DHCP ifindex (%d)", iface, r);
		goto error;
	}

	r = sd_dhcp_client_set_callback (priv->client4, dhcp_event_cb, client);
	if (r < 0) {
		nm_log_warn (LOGD_DHCP4, "(%s): failed to set DHCP callback (%d)", iface, r);
		goto error;
	}

	r = sd_dhcp_client_set_request_broadcast (priv->client4, true);
	if (r < 0) {
		nm_log_warn (LOGD_DHCP4, "(%s): failed to set DHCP broadcast (%d)", iface, r);
		goto error;
	}

	dhcp_lease_load (&lease, priv->lease_file);

	if (last_ip4_address)
		inet_pton (AF_INET, last_ip4_address, &last_addr);
	else if (lease)
		sd_dhcp_lease_get_address (lease, &last_addr);

	if (last_addr.s_addr) {
		r = sd_dhcp_client_set_request_address (priv->client4, &last_addr);
		if (r < 0) {
			nm_log_warn (LOGD_DHCP4, "(%s): failed to set last IPv4 address (%d)", iface, r);
			goto error;
		}
	}

	override_client_id = nm_dhcp_client_get_client_id (client);
	if (override_client_id) {
		client_id = g_bytes_get_data (override_client_id, &client_id_len);
		g_assert (client_id && client_id_len);
		sd_dhcp_client_set_client_id (priv->client4,
		                              client_id[0],
		                              client_id + 1,
		                              client_id_len - 1);
	} else if (lease) {
		r = sd_dhcp_lease_get_client_id (lease, (const void **) &client_id, &client_id_len);
		if (r == 0 && client_id_len) {
			sd_dhcp_client_set_client_id (priv->client4,
			                              client_id[0],
			                              client_id + 1,
			                              client_id_len - 1);
			_save_client_id (NM_DHCP_SYSTEMD (client),
			                 client_id[0],
			                 client_id + 1,
			                 client_id_len - 1);
		}
	}


	/* Add requested options */
	for (i = 0; dhcp4_requests[i].name; i++) {
		if (dhcp4_requests[i].include)
			sd_dhcp_client_set_request_option (priv->client4, dhcp4_requests[i].num);
	}

	hostname = nm_dhcp_client_get_hostname (client);
	if (hostname) {
		r = sd_dhcp_client_set_hostname (priv->client4, hostname);
		if (r < 0) {
			nm_log_warn (LOGD_DHCP4, "(%s): failed to set DHCP hostname (%d)", iface, r);
			goto error;
		}
	}

	r = sd_dhcp_client_start (priv->client4);
	if (r < 0) {
		nm_log_warn (LOGD_DHCP4, "(%s): failed to start DHCP (%d)", iface, r);
		goto error;
	}

	success = TRUE;

error:
	sd_dhcp_lease_unref (lease);
	if (!success)
		priv->client4 = sd_dhcp_client_unref (priv->client4);
	return success;
}