bool socket_priority_set;
bool ipv6_acquired;
bool bootp;
+ bool send_release;
};
static const uint8_t default_req_opts[] = {
return 0;
}
+int sd_dhcp_client_set_send_release(sd_dhcp_client *client, int enable) {
+ assert_return(client, -EINVAL);
+
+ client->send_release = enable;
+
+ return 0;
+}
+
static void client_set_state(sd_dhcp_client *client, DHCPState state) {
assert(client);
return r;
}
-int sd_dhcp_client_send_release(sd_dhcp_client *client) {
+static int client_send_release(sd_dhcp_client *client) {
_cleanup_free_ DHCPPacket *release = NULL;
size_t optoffset, optlen;
int r;
- if (!sd_dhcp_client_is_running(client) || !client->lease || client->bootp)
- return 0; /* do nothing */
+ assert(client);
+
+ if (!client->send_release)
+ return 0; /* disabled */
+
+ if (!client->lease || client->bootp)
+ return 0; /* there is nothing to be released */
r = client_message_init(client, DHCP_RELEASE, &release, &optlen, &optoffset);
if (r < 0)
return r;
log_dhcp_client(client, "RELEASE");
-
- /* This function is mostly called when stopping daemon. Hence, do not call client_stop() or
- * client_restart(). Otherwise, the notification callback will be called again and we may easily
- * enter an infinite loop. */
- client_initialize(client);
- return 1; /* sent and stopped. */
+ return 0;
}
int sd_dhcp_client_send_decline(sd_dhcp_client *client) {
}
int sd_dhcp_client_stop(sd_dhcp_client *client) {
+ int r;
+
if (!client)
return 0;
DHCP_CLIENT_DONT_DESTROY(client);
+ r = client_send_release(client);
+ if (r < 0)
+ log_dhcp_client_errno(client, r,
+ "Failed to send DHCP release message, ignoring: %m");
+
client_stop(client, SD_DHCP_CLIENT_EVENT_STOP);
return 0;
log_link_debug(link, "DHCP client is stopped. Acquiring IPv4 link-local address.");
if (link->dhcp_lease) {
- if (link->network->dhcp_send_release) {
- r = sd_dhcp_client_send_release(client);
- if (r < 0)
- log_link_full_errno(link,
- ERRNO_IS_DISCONNECT(r) ? LOG_DEBUG : LOG_WARNING,
- r, "Failed to send DHCP RELEASE, ignoring: %m");
- }
-
r = dhcp4_lease_lost(link);
if (r < 0) {
link_enter_failed(link);
return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to %s BOOTP: %m",
enable_disable(link->network->dhcp_use_bootp));
+ r = sd_dhcp_client_set_send_release(link->dhcp_client, link->network->dhcp_send_release);
+ if (r < 0)
+ return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to %s sending release message on stop: %m",
+ enable_disable(link->network->dhcp_send_release));
+
r = sd_dhcp_client_attach_event(link->dhcp_client, link->manager->event, 0);
if (r < 0)
return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to attach event to DHCPv4 client: %m");
return 0;
}
+static bool link_should_drop_dhcp4_config(Link *link, Network *network) {
+ assert(link);
+ assert(link->network);
+
+ if (!link_dhcp4_enabled(link))
+ /* DHCP client is now disabled. */
+ return true;
+
+ if (link->dhcp_client && link->network->dhcp_use_bootp &&
+ network && !network->dhcp_use_bootp && network->dhcp_send_release)
+ /* The client was enabled as a DHCP client and sending release message is requested, and now
+ * the client is enabled as a BOOTP client. In this case, we need to release the previous
+ * lease, and hence all DHCPv4 configurations (address, routes, DNS servers, and so on) needs
+ * to be dropped. */
+ return true;
+
+ return false;
+}
+
int link_drop_dhcp4_config(Link *link, Network *network) {
- int r, ret = 0;
+ int ret = 0;
assert(link);
assert(link->network);
if (link->network == network)
return 0; /* .network file is unchanged. It is not necessary to reconfigure the client. */
- if (!link_dhcp4_enabled(link)) {
- /* DHCP client is disabled. Stop the client if it is running and drop the lease. */
+ if (link_should_drop_dhcp4_config(link, network)) {
+ /* Stop the client if it is running and drop the lease. */
ret = sd_dhcp_client_stop(link->dhcp_client);
/* Also explicitly drop DHCPv4 address and routes. Why? This is for the case when the DHCPv4
RET_GATHER(ret, dhcp4_remove_address_and_routes(link, /* only_marked= */ false));
}
- if (link->dhcp_client && link->network->dhcp_use_bootp &&
- network && !network->dhcp_use_bootp && network->dhcp_send_release) {
- /* If the client was enabled as a DHCP client, and is now enabled as a BOOTP client, release
- * the previous lease. Note, this can be easily fail, e.g. when the interface is down. Hence,
- * ignore any failures here. */
- r = sd_dhcp_client_send_release(link->dhcp_client);
- if (r < 0)
- log_link_full_errno(link, ERRNO_IS_DISCONNECT(r) ? LOG_DEBUG : LOG_WARNING, r,
- "Failed to send DHCP RELEASE, ignoring: %m");
- }
-
/* Even if the client is currently enabled and also enabled in the new .network file, detailed
* settings for the client may be different. Let's unref() the client. But do not unref() the lease.
* it will be unref()ed later when a new lease is acquired. */
int sd_dhcp_client_set_bootp(
sd_dhcp_client *client,
int bootp);
+int sd_dhcp_client_set_send_release(sd_dhcp_client *client, int enable);
int sd_dhcp_client_add_option(sd_dhcp_client *client, sd_dhcp_option *v);
int sd_dhcp_client_add_vendor_option(sd_dhcp_client *client, sd_dhcp_option *v);
int sd_dhcp_client_is_running(sd_dhcp_client *client);
int sd_dhcp_client_stop(sd_dhcp_client *client);
int sd_dhcp_client_start(sd_dhcp_client *client);
-int sd_dhcp_client_send_release(sd_dhcp_client *client);
int sd_dhcp_client_send_decline(sd_dhcp_client *client);
int sd_dhcp_client_send_renew(sd_dhcp_client *client);
int sd_dhcp_client_set_ipv6_connectivity(sd_dhcp_client *client, int have);