static GSList *
nm_dhcp_systemd_get_lease_ip_configs (const char *iface,
                                      int ifindex,
                                      const char *uuid,
                                      gboolean ipv6,
                                      guint32 default_route_metric)
{
	GSList *leases = NULL;
	gs_free char *path = NULL;
	sd_dhcp_lease *lease = NULL;
	NMIP4Config *ip4_config;
	int r;

	if (ipv6)
		return NULL;

	path = get_leasefile_path (iface, uuid, FALSE);
	r = dhcp_lease_load (&lease, path);
	if (r == 0 && lease) {
		ip4_config = lease_to_ip4_config (iface, ifindex, lease, NULL, default_route_metric, FALSE, NULL);
		if (ip4_config)
			leases = g_slist_append (leases, ip4_config);
		sd_dhcp_lease_unref (lease);
	}

	return leases;
}
Example #2
0
static void test_addr_acq_acquired(sd_dhcp_client *client, int event,
                                   void *userdata) {
        sd_event *e = userdata;
        sd_dhcp_lease *lease;
        struct in_addr addr;

        assert_se(client);
        assert_se(event == DHCP_EVENT_IP_ACQUIRE);

        assert_se(sd_dhcp_client_get_lease(client, &lease) >= 0);
        assert_se(lease);

        assert_se(sd_dhcp_lease_get_address(lease, &addr) >= 0);
        assert_se(memcmp(&addr.s_addr, &test_addr_acq_ack[44],
                      sizeof(addr.s_addr)) == 0);

        assert_se(sd_dhcp_lease_get_netmask(lease, &addr) >= 0);
        assert_se(memcmp(&addr.s_addr, &test_addr_acq_ack[285],
                      sizeof(addr.s_addr)) == 0);

        assert_se(sd_dhcp_lease_get_router(lease, &addr) >= 0);
        assert_se(memcmp(&addr.s_addr, &test_addr_acq_ack[308],
                      sizeof(addr.s_addr)) == 0);

        if (verbose)
                printf("  DHCP address acquired\n");

        sd_dhcp_lease_unref(lease);
        sd_event_exit(e, 0);
}
Example #3
0
static int client_handle_ack(sd_dhcp_client *client, DHCPMessage *ack,
                             size_t len) {
        _cleanup_dhcp_lease_unref_ sd_dhcp_lease *lease = NULL;
        int r;

        r = dhcp_lease_new(&lease);
        if (r < 0)
                return r;

        r = dhcp_option_parse(ack, len, dhcp_lease_parse_options, lease);
        if (r == DHCP_NAK) {
                log_dhcp_client(client, "NAK");
                return DHCP_EVENT_NO_LEASE;
        }

        if (r != DHCP_ACK) {
                log_dhcp_client(client, "receieved message was not an ACK, ignoring");
                return -ENOMSG;
        }

        lease->next_server = ack->siaddr;

        lease->address = ack->yiaddr;

        if (lease->address == INADDR_ANY ||
            lease->server_address == INADDR_ANY ||
            lease->lifetime == 0) {
                log_dhcp_client(client, "receieved lease lacks address, server "
                                "address or lease lifetime, ignoring");
                return -ENOMSG;
        }

        if (lease->subnet_mask == INADDR_ANY) {
                r = dhcp_lease_set_default_subnet_mask(lease);
                if (r < 0) {
                        log_dhcp_client(client, "receieved lease lacks subnet "
                                        "mask, and a fallback one can not be "
                                        "generated, ignoring");
                        return -ENOMSG;
                }
        }

        r = DHCP_EVENT_IP_ACQUIRE;
        if (client->lease) {
                if (client->lease->address != lease->address ||
                    client->lease->subnet_mask != lease->subnet_mask ||
                    client->lease->router != lease->router) {
                        r = DHCP_EVENT_IP_CHANGE;
                }

                client->lease = sd_dhcp_lease_unref(client->lease);
        }

        client->lease = lease;
        lease = NULL;

        log_dhcp_client(client, "ACK");

        return r;
}
static int client_stop(sd_dhcp_client *client, int error) {
        assert_return(client, -EINVAL);

        client->receive_message =
                sd_event_source_unref(client->receive_message);

        if (client->fd >= 0)
                close_nointr_nofail(client->fd);
        client->fd = -1;

        client->timeout_resend = sd_event_source_unref(client->timeout_resend);

        client->timeout_t1 = sd_event_source_unref(client->timeout_t1);
        client->timeout_t2 = sd_event_source_unref(client->timeout_t2);
        client->timeout_expire = sd_event_source_unref(client->timeout_expire);

        client->attempt = 1;

        client_notify(client, error);

        client->start_time = 0;
        client->secs = 0;
        client->state = DHCP_STATE_INIT;

        if (client->lease)
                client->lease = sd_dhcp_lease_unref(client->lease);

        log_dhcp_client(client, "STOPPED");

        return 0;
}
Example #5
0
static int dhcp_lease_renew(sd_dhcp_client *client, Link *link) {
        sd_dhcp_lease *lease;
        struct in_addr address;
        struct in_addr netmask;
        uint32_t lifetime = CACHE_INFO_INFINITY_LIFE_TIME;
        int r;

        assert(link);
        assert(client);
        assert(link->network);

        r = sd_dhcp_client_get_lease(client, &lease);
        if (r < 0) {
                log_link_warning(link, "DHCP error: no lease %s",
                                 strerror(-r));
                return r;
        }

        sd_dhcp_lease_unref(link->dhcp_lease);
        link->dhcp4_configured = false;
        link->dhcp_lease = sd_dhcp_lease_ref(lease);

        r = sd_dhcp_lease_get_address(lease, &address);
        if (r < 0) {
                log_link_warning(link, "DHCP error: no address: %s",
                                 strerror(-r));
                return r;
        }

        r = sd_dhcp_lease_get_netmask(lease, &netmask);
        if (r < 0) {
                log_link_warning(link, "DHCP error: no netmask: %s",
                                 strerror(-r));
                return r;
        }

        if (!link->network->dhcp_critical) {
                r = sd_dhcp_lease_get_lifetime(link->dhcp_lease,
                                               &lifetime);
                if (r < 0) {
                        log_link_warning(link,
                                         "DHCP error: no lifetime: %s",
                                         strerror(-r));
                        return r;
                }
        }

        r = dhcp4_update_address(link, &address, &netmask, lifetime);
        if (r < 0) {
                log_link_warning(link, "could not update IP address: %s",
                                 strerror(-r));
                link_enter_failed(link);
                return r;
        }

        return 0;
}
Example #6
0
static int client_handle_offer(sd_dhcp_client *client, DHCPMessage *offer,
                               size_t len) {
        _cleanup_dhcp_lease_unref_ sd_dhcp_lease *lease = NULL;
        int r;

        r = dhcp_lease_new(&lease);
        if (r < 0)
                return r;

        r = dhcp_option_parse(offer, len, dhcp_lease_parse_options, lease);
        if (r != DHCP_OFFER) {
                log_dhcp_client(client, "receieved message was not an OFFER, ignoring");
                return -ENOMSG;
        }

        lease->next_server = offer->siaddr;

        lease->address = offer->yiaddr;

        if (lease->address == INADDR_ANY ||
            lease->server_address == INADDR_ANY ||
            lease->lifetime == 0) {
                log_dhcp_client(client, "receieved lease lacks address, server "
                                "address or lease lifetime, ignoring");
                return -ENOMSG;
        }

        if (lease->subnet_mask == INADDR_ANY) {
                r = dhcp_lease_set_default_subnet_mask(lease);
                if (r < 0) {
                        log_dhcp_client(client, "receieved lease lacks subnet "
                                        "mask, and a fallback one can not be "
                                        "generated, ignoring");
                        return -ENOMSG;
                }
        }

        sd_dhcp_lease_unref(client->lease);
        client->lease = lease;
        lease = NULL;

        log_dhcp_client(client, "OFFER");

        return 0;
}
Example #7
0
sd_dhcp_client *sd_dhcp_client_unref(sd_dhcp_client *client) {
        if (client && REFCNT_DEC(client->n_ref) <= 0) {
                log_dhcp_client(client, "UNREF");

                client_initialize(client);

                client->receive_message =
                        sd_event_source_unref(client->receive_message);

                sd_dhcp_client_detach_event(client);

                sd_dhcp_lease_unref(client->lease);

                free(client->req_opts);
                free(client);

                return NULL;
        }

        return client;
}
Example #8
0
static int client_initialize(sd_dhcp_client *client) {
        assert_return(client, -EINVAL);

        client->receive_message =
                sd_event_source_unref(client->receive_message);

        client->fd = asynchronous_close(client->fd);

        client->timeout_resend = sd_event_source_unref(client->timeout_resend);

        client->timeout_t1 = sd_event_source_unref(client->timeout_t1);
        client->timeout_t2 = sd_event_source_unref(client->timeout_t2);
        client->timeout_expire = sd_event_source_unref(client->timeout_expire);

        client->attempt = 1;

        client->state = DHCP_STATE_INIT;
        client->xid = 0;

        if (client->lease)
                client->lease = sd_dhcp_lease_unref(client->lease);

        return 0;
}
Example #9
0
static int dhcp_lease_lost(Link *link) {
        _cleanup_address_free_ Address *address = NULL;
        struct in_addr addr;
        struct in_addr netmask;
        struct in_addr gateway;
        unsigned prefixlen = 0;
        int r;

        assert(link);
        assert(link->dhcp_lease);

        log_link_warning(link, "DHCP lease lost");

        if (link->network->dhcp_use_routes) {
                _cleanup_free_ sd_dhcp_route **routes = NULL;
                int n, i;

                n = sd_dhcp_lease_get_routes(link->dhcp_lease, &routes);
                if (n >= 0) {
                        for (i = 0; i < n; i++) {
                                _cleanup_route_free_ Route *route = NULL;

                                r = route_new(&route);
                                if (r >= 0) {
                                        route->family = AF_INET;
                                        assert_se(sd_dhcp_route_get_gateway(routes[i], &route->gw.in) >= 0);
                                        assert_se(sd_dhcp_route_get_destination(routes[i], &route->dst.in) >= 0);
                                        assert_se(sd_dhcp_route_get_destination_prefix_length(routes[i], &route->dst_prefixlen) >= 0);

                                        route_remove(route, link,
                                                     link_route_remove_handler);
                                }
                        }
                }
        }

        r = address_new(&address);
        if (r >= 0) {
                r = sd_dhcp_lease_get_router(link->dhcp_lease, &gateway);
                if (r >= 0) {
                        _cleanup_route_free_ Route *route_gw = NULL;
                        _cleanup_route_free_ Route *route = NULL;

                        r = route_new(&route_gw);
                        if (r >= 0) {
                                route_gw->family = AF_INET;
                                route_gw->dst.in = gateway;
                                route_gw->dst_prefixlen = 32;
                                route_gw->scope = RT_SCOPE_LINK;

                                route_remove(route_gw, link,
                                             link_route_remove_handler);
                        }

                        r = route_new(&route);
                        if (r >= 0) {
                                route->family = AF_INET;
                                route->gw.in = gateway;

                                route_remove(route, link,
                                             link_route_remove_handler);
                        }
                }

                r = sd_dhcp_lease_get_address(link->dhcp_lease, &addr);
                if (r >= 0) {
                        r = sd_dhcp_lease_get_netmask(link->dhcp_lease, &netmask);
                        if (r >= 0)
                                prefixlen = in_addr_netmask_to_prefixlen(&netmask);

                        address->family = AF_INET;
                        address->in_addr.in = addr;
                        address->prefixlen = prefixlen;

                        address_remove(address, link, link_address_remove_handler);
                }
        }

        if (link->network->dhcp_use_mtu) {
                uint16_t mtu;

                r = sd_dhcp_lease_get_mtu(link->dhcp_lease, &mtu);
                if (r >= 0 && link->original_mtu != mtu) {
                        r = link_set_mtu(link, link->original_mtu);
                        if (r < 0) {
                                log_link_warning(link,
                                                 "DHCP error: could not reset MTU");
                                link_enter_failed(link);
                                return r;
                        }
                }
        }

        if (link->network->dhcp_use_hostname) {
                const char *hostname = NULL;

                if (link->network->dhcp_hostname)
                        hostname = link->network->dhcp_hostname;
                else
                        (void) sd_dhcp_lease_get_hostname(link->dhcp_lease, &hostname);

                if (hostname) {
                        /* If a hostname was set due to the lease, then unset it now. */
                        r = manager_set_hostname(link->manager, NULL);
                        if (r < 0)
                                log_link_warning_errno(link, r, "Failed to reset transient hostname: %m");
                }
        }

        link->dhcp_lease = sd_dhcp_lease_unref(link->dhcp_lease);
        link_dirty(link);
        link->dhcp4_configured = false;

        return 0;
}
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;
}
Example #11
0
static int dhcp_lease_lost(Link *link) {
        _cleanup_address_free_ Address *address = NULL;
        struct in_addr addr;
        struct in_addr netmask;
        struct in_addr gateway;
        unsigned prefixlen = 0;
        int r;

        assert(link);
        assert(link->dhcp_lease);

        log_link_warning(link, "DHCP lease lost");

        if (link->network->dhcp_routes) {
                struct sd_dhcp_route *routes;
                int n, i;

                n = sd_dhcp_lease_get_routes(link->dhcp_lease, &routes);
                if (n >= 0) {
                        for (i = 0; i < n; i++) {
                                _cleanup_route_free_ Route *route = NULL;

                                r = route_new_dynamic(&route, RTPROT_UNSPEC);
                                if (r >= 0) {
                                        route->family = AF_INET;
                                        route->in_addr.in = routes[i].gw_addr;
                                        route->dst_addr.in = routes[i].dst_addr;
                                        route->dst_prefixlen = routes[i].dst_prefixlen;

                                        route_drop(route, link,
                                                   &link_route_drop_handler);
                                }
                        }
                }
        }

        r = address_new_dynamic(&address);
        if (r >= 0) {
                r = sd_dhcp_lease_get_router(link->dhcp_lease, &gateway);
                if (r >= 0) {
                        _cleanup_route_free_ Route *route_gw = NULL;
                        _cleanup_route_free_ Route *route = NULL;

                        r = route_new_dynamic(&route_gw, RTPROT_UNSPEC);
                        if (r >= 0) {
                                route_gw->family = AF_INET;
                                route_gw->dst_addr.in = gateway;
                                route_gw->dst_prefixlen = 32;
                                route_gw->scope = RT_SCOPE_LINK;

                                route_drop(route_gw, link,
                                           &link_route_drop_handler);
                        }

                        r = route_new_dynamic(&route, RTPROT_UNSPEC);
                        if (r >= 0) {
                                route->family = AF_INET;
                                route->in_addr.in = gateway;

                                route_drop(route, link,
                                           &link_route_drop_handler);
                        }
                }

                r = sd_dhcp_lease_get_address(link->dhcp_lease, &addr);
                if (r >= 0) {
                        r = sd_dhcp_lease_get_netmask(link->dhcp_lease, &netmask);
                        if (r >= 0)
                                prefixlen = in_addr_netmask_to_prefixlen(&netmask);

                        address->family = AF_INET;
                        address->in_addr.in = addr;
                        address->prefixlen = prefixlen;

                        address_drop(address, link, &link_address_drop_handler);
                }
        }

        if (link->network->dhcp_mtu) {
                uint16_t mtu;

                r = sd_dhcp_lease_get_mtu(link->dhcp_lease, &mtu);
                if (r >= 0 && link->original_mtu != mtu) {
                        r = link_set_mtu(link, link->original_mtu);
                        if (r < 0) {
                                log_link_warning(link,
                                                 "DHCP error: could not reset MTU");
                                link_enter_failed(link);
                                return r;
                        }
                }
        }

        if (link->network->dhcp_hostname) {
                const char *hostname = NULL;

                if (!link->network->hostname)
                        r = sd_dhcp_lease_get_hostname(link->dhcp_lease, &hostname);
                else
                        hostname = link->network->hostname;

                if (r >= 0 || hostname) {
                        r = link_set_hostname(link, hostname);
                        if (r < 0)
                                log_link_error_errno(link, r,
                                                     "Failed to set transient hostname to '%s': %m",
                                                     hostname);

                }
        }

        link->dhcp_lease = sd_dhcp_lease_unref(link->dhcp_lease);
        link->dhcp4_configured = false;

        return 0;
}
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;
}