From 9917da2c71f75426b7a2891db0d5797ab8b0481f Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Wed, 5 Jan 2011 16:23:00 -0600 Subject: [PATCH] dhcp: add DHCP lease release capability --- src/dhcp-manager/nm-dhcp-client.c | 16 +++--- src/dhcp-manager/nm-dhcp-client.h | 25 +++++---- src/dhcp-manager/nm-dhcp-dhclient.c | 79 ++++++++++++++++++++--------- src/dhcp-manager/nm-dhcp-dhcpcd.c | 6 ++- src/dhcp-manager/nm-dhcp-manager.c | 2 +- src/nm-device.c | 55 ++++++++++++++------ src/nm-device.h | 2 + 7 files changed, 123 insertions(+), 62 deletions(-) diff --git a/src/dhcp-manager/nm-dhcp-client.c b/src/dhcp-manager/nm-dhcp-client.c index 3a8b194081..c4dfec64d7 100644 --- a/src/dhcp-manager/nm-dhcp-client.c +++ b/src/dhcp-manager/nm-dhcp-client.c @@ -136,10 +136,10 @@ watch_cleanup (NMDHCPClient *self) } } -static void -stop_process (GPid pid, const char *iface) +void +nm_dhcp_client_stop_pid (GPid pid, const char *iface, guint timeout_secs) { - int i = 15; /* 3 seconds */ + int i = (timeout_secs ? timeout_secs : 3) * 5; /* default 3 seconds */ g_return_if_fail (pid > 0); @@ -183,7 +183,7 @@ stop_process (GPid pid, const char *iface) } static void -real_stop (NMDHCPClient *self) +real_stop (NMDHCPClient *self, gboolean release) { NMDHCPClientPrivate *priv; @@ -196,7 +196,7 @@ real_stop (NMDHCPClient *self) /* Clean up the watch handler since we're explicitly killing the daemon */ watch_cleanup (self); - stop_process (priv->pid, priv->iface); + nm_dhcp_client_stop_pid (priv->pid, priv->iface, 0); priv->info_only = FALSE; } @@ -376,7 +376,7 @@ nm_dhcp_client_stop_existing (const char *pid_file, const char *binary_name) exe = proc_contents; if (!strcmp (exe, binary_name)) - stop_process ((GPid) tmp, NULL); + nm_dhcp_client_stop_pid ((GPid) tmp, NULL, 0); } } @@ -387,7 +387,7 @@ nm_dhcp_client_stop_existing (const char *pid_file, const char *binary_name) } void -nm_dhcp_client_stop (NMDHCPClient *self) +nm_dhcp_client_stop (NMDHCPClient *self, gboolean release) { NMDHCPClientPrivate *priv; @@ -398,7 +398,7 @@ nm_dhcp_client_stop (NMDHCPClient *self) /* Kill the DHCP client */ if (!priv->dead) { - NM_DHCP_CLIENT_GET_CLASS (self)->stop (self); + NM_DHCP_CLIENT_GET_CLASS (self)->stop (self, release); priv->dead = TRUE; nm_log_info (LOGD_DHCP, "(%s): canceled DHCP transaction, DHCP client pid %d", diff --git a/src/dhcp-manager/nm-dhcp-client.h b/src/dhcp-manager/nm-dhcp-client.h index f357170b9c..19c7365edc 100644 --- a/src/dhcp-manager/nm-dhcp-client.h +++ b/src/dhcp-manager/nm-dhcp-client.h @@ -76,18 +76,19 @@ typedef struct { /* Methods */ - GPid (*ip4_start) (NMDHCPClient *self, - NMSettingIP4Config *s_ip4, - guint8 *anycast_addr, - const char *hostname); + GPid (*ip4_start) (NMDHCPClient *self, + NMSettingIP4Config *s_ip4, + guint8 *anycast_addr, + const char *hostname); - GPid (*ip6_start) (NMDHCPClient *self, - NMSettingIP6Config *s_ip6, - guint8 *anycast_addr, - const char *hostname, - gboolean info_only); + GPid (*ip6_start) (NMDHCPClient *self, + NMSettingIP6Config *s_ip6, + guint8 *anycast_addr, + const char *hostname, + gboolean info_only); - void (*stop) (NMDHCPClient *self); + void (*stop) (NMDHCPClient *self, + gboolean release); /* Signals */ void (*state_changed) (NMDHCPClient *self, NMDHCPState state); @@ -116,7 +117,7 @@ gboolean nm_dhcp_client_start_ip6 (NMDHCPClient *self, const char *hostname, gboolean info_only); -void nm_dhcp_client_stop (NMDHCPClient *self); +void nm_dhcp_client_stop (NMDHCPClient *self, gboolean release); void nm_dhcp_client_new_options (NMDHCPClient *self, GHashTable *options, @@ -133,5 +134,7 @@ NMIP6Config *nm_dhcp_client_get_ip6_config (NMDHCPClient *self, gboolean test) /* Backend helpers */ void nm_dhcp_client_stop_existing (const char *pid_file, const char *binary_name); +void nm_dhcp_client_stop_pid (GPid pid, const char *iface, guint timeout_secs); + #endif /* NM_DHCP_CLIENT_H */ diff --git a/src/dhcp-manager/nm-dhcp-dhclient.c b/src/dhcp-manager/nm-dhcp-dhclient.c index f6f2a540dc..75684459f6 100644 --- a/src/dhcp-manager/nm-dhcp-dhclient.c +++ b/src/dhcp-manager/nm-dhcp-dhclient.c @@ -411,15 +411,15 @@ dhclient_child_setup (gpointer user_data G_GNUC_UNUSED) static GPid dhclient_start (NMDHCPClient *client, - const char *ip_opt, - const char *mode_opt) + const char *mode_opt, + gboolean release) { NMDHCPDhclientPrivate *priv = NM_DHCP_DHCLIENT_GET_PRIVATE (client); GPtrArray *argv = NULL; GPid pid = -1; GError *error = NULL; const char *iface, *uuid; - char *binary_name, *cmd_str; + char *binary_name, *cmd_str, *pid_file = NULL; gboolean ipv6; guint log_domain; @@ -436,28 +436,33 @@ dhclient_start (NMDHCPClient *client, nm_log_warn (log_domain, "(%s): ISC dhcp3 does not support IPv6", iface); return -1; } -#else - g_return_val_if_fail (ip_opt != NULL, -1); #endif - priv->pid_file = g_strdup_printf (LOCALSTATEDIR "/run/dhclient%s-%s.pid", - ipv6 ? "6" : "", - iface); - if (!priv->pid_file) { - nm_log_warn (log_domain, "(%s): not enough memory for dhcpcd options.", iface); - return -1; - } - if (!g_file_test (priv->path, G_FILE_TEST_EXISTS)) { nm_log_warn (log_domain, "%s does not exist.", priv->path); return -1; } + pid_file = g_strdup_printf (LOCALSTATEDIR "/run/dhclient%s-%s.pid", + ipv6 ? "6" : "", + iface); + if (!pid_file) { + nm_log_warn (log_domain, "(%s): not enough memory for dhcpcd options.", iface); + return -1; + } + /* Kill any existing dhclient from the pidfile */ binary_name = g_path_get_basename (priv->path); - nm_dhcp_client_stop_existing (priv->pid_file, binary_name); + nm_dhcp_client_stop_existing (pid_file, binary_name); g_free (binary_name); + if (release) { + /* release doesn't use the pidfile after killing an old client */ + g_free (pid_file); + pid_file = NULL; + } + + g_free (priv->lease_file); priv->lease_file = get_leasefile_for_iface (iface, uuid, ipv6); if (!priv->lease_file) { nm_log_warn (log_domain, "(%s): not enough memory for dhclient options.", iface); @@ -469,17 +474,26 @@ dhclient_start (NMDHCPClient *client, g_ptr_array_add (argv, (gpointer) "-d"); + if (release) + g_ptr_array_add (argv, (gpointer) "-r"); + #if !defined(DHCLIENT_V3) - g_ptr_array_add (argv, (gpointer) ip_opt); - if (mode_opt) - g_ptr_array_add (argv, (gpointer) mode_opt); + if (ipv6) { + g_ptr_array_add (argv, (gpointer) "-6"); + if (mode_opt) + g_ptr_array_add (argv, (gpointer) mode_opt); + } else { + g_ptr_array_add (argv, (gpointer) "-4"); + } #endif g_ptr_array_add (argv, (gpointer) "-sf"); /* Set script file */ g_ptr_array_add (argv, (gpointer) ACTION_SCRIPT_PATH ); - g_ptr_array_add (argv, (gpointer) "-pf"); /* Set pid file */ - g_ptr_array_add (argv, (gpointer) priv->pid_file); + if (pid_file) { + g_ptr_array_add (argv, (gpointer) "-pf"); /* Set pid file */ + g_ptr_array_add (argv, (gpointer) pid_file); + } g_ptr_array_add (argv, (gpointer) "-lf"); /* Set lease file */ g_ptr_array_add (argv, (gpointer) priv->lease_file); @@ -501,8 +515,10 @@ dhclient_start (NMDHCPClient *client, nm_log_warn (log_domain, "dhclient failed to start: '%s'", error->message); g_error_free (error); pid = -1; - } else + } else { nm_log_info (log_domain, "dhclient started with pid %d", pid); + priv->pid_file = pid_file; + } g_ptr_array_free (argv, TRUE); return pid; @@ -525,7 +541,7 @@ real_ip4_start (NMDHCPClient *client, return -1; } - return dhclient_start (client, "-4", NULL); + return dhclient_start (client, NULL, FALSE); } static GPid @@ -535,21 +551,34 @@ real_ip6_start (NMDHCPClient *client, const char *hostname, gboolean info_only) { - return dhclient_start (client, "-6", info_only ? "-S" : "-N"); + return dhclient_start (client, info_only ? "-S" : "-N", FALSE); } static void -real_stop (NMDHCPClient *client) +real_stop (NMDHCPClient *client, gboolean release) { NMDHCPDhclientPrivate *priv = NM_DHCP_DHCLIENT_GET_PRIVATE (client); /* Chain up to parent */ - NM_DHCP_CLIENT_CLASS (nm_dhcp_dhclient_parent_class)->stop (client); + NM_DHCP_CLIENT_CLASS (nm_dhcp_dhclient_parent_class)->stop (client, release); if (priv->conf_file) remove (priv->conf_file); - if (priv->pid_file) + if (priv->pid_file) { remove (priv->pid_file); + g_free (priv->pid_file); + priv->pid_file = NULL; + } + + if (release) { + GPid rpid; + + rpid = dhclient_start (client, NULL, TRUE); + if (rpid > 0) { + /* Wait a few seconds for the release to happen */ + nm_dhcp_client_stop_pid (rpid, nm_dhcp_client_get_iface (client), 5); + } + } } /***************************************************/ diff --git a/src/dhcp-manager/nm-dhcp-dhcpcd.c b/src/dhcp-manager/nm-dhcp-dhcpcd.c index 4fb703c480..237661fe47 100644 --- a/src/dhcp-manager/nm-dhcp-dhcpcd.c +++ b/src/dhcp-manager/nm-dhcp-dhcpcd.c @@ -170,15 +170,17 @@ real_ip6_start (NMDHCPClient *client, } static void -real_stop (NMDHCPClient *client) +real_stop (NMDHCPClient *client, gboolean release) { NMDHCPDhcpcdPrivate *priv = NM_DHCP_DHCPCD_GET_PRIVATE (client); /* Chain up to parent */ - NM_DHCP_CLIENT_CLASS (nm_dhcp_dhcpcd_parent_class)->stop (client); + NM_DHCP_CLIENT_CLASS (nm_dhcp_dhcpcd_parent_class)->stop (client, release); if (priv->pid_file) remove (priv->pid_file); + + /* FIXME: implement release... */ } /***************************************************/ diff --git a/src/dhcp-manager/nm-dhcp-manager.c b/src/dhcp-manager/nm-dhcp-manager.c index a1e3e5e24d..d3c064199c 100644 --- a/src/dhcp-manager/nm-dhcp-manager.c +++ b/src/dhcp-manager/nm-dhcp-manager.c @@ -429,7 +429,7 @@ client_start (NMDHCPManager *self, /* Kill any old client instance */ client = get_client_for_iface (self, iface, ipv6); if (client) { - nm_dhcp_client_stop (client); + nm_dhcp_client_stop (client, FALSE); remove_client (self, client); } diff --git a/src/nm-device.c b/src/nm-device.c index 34a9c23a2f..b9701a399e 100644 --- a/src/nm-device.c +++ b/src/nm-device.c @@ -184,8 +184,8 @@ static NMActStageReturn dhcp6_start (NMDevice *self, NMDeviceStateReason *reason); static void addrconf6_cleanup (NMDevice *self); -static void dhcp6_cleanup (NMDevice *self, gboolean stop); -static void dhcp4_cleanup (NMDevice *self, gboolean stop); +static void dhcp6_cleanup (NMDevice *self, gboolean stop, gboolean release); +static void dhcp4_cleanup (NMDevice *self, gboolean stop, gboolean release); static void @@ -1467,7 +1467,7 @@ dhcp_timeout (NMDHCPClient *client, gpointer user_data) if (!nm_device_get_act_request (device)) return; - nm_dhcp_client_stop (client); + nm_dhcp_client_stop (client, FALSE); if (nm_device_get_state (device) == NM_DEVICE_STATE_IP_CONFIG) { if (nm_dhcp_client_get_ipv6 (client)) @@ -1480,17 +1480,16 @@ dhcp_timeout (NMDHCPClient *client, gpointer user_data) static NMActStageReturn dhcp4_start (NMDevice *self, NMConnection *connection, - NMSettingIP4Config *s_ip4, NMDeviceStateReason *reason) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); NMSettingConnection *s_con; + NMSettingIP4Config *s_ip4; guint8 *anycast = NULL; s_con = (NMSettingConnection *) nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION); g_assert (s_con); - - /* Begin a DHCP transaction on the interface */ + s_ip4 = (NMSettingIP4Config *) nm_connection_get_setting (connection, NM_TYPE_SETTING_IP4_CONFIG); if (priv->dhcp_anycast_address) anycast = priv->dhcp_anycast_address->data; @@ -1500,6 +1499,7 @@ dhcp4_start (NMDevice *self, g_object_unref (priv->dhcp4_config); priv->dhcp4_config = nm_dhcp4_config_new (); + /* Begin DHCP on the interface */ g_warn_if_fail (priv->dhcp4_client == NULL); priv->dhcp4_client = nm_dhcp_manager_start_ip4 (priv->dhcp_manager, nm_device_get_ip_iface (self), @@ -1525,6 +1525,31 @@ dhcp4_start (NMDevice *self, return NM_ACT_STAGE_RETURN_POSTPONE; } +gboolean +nm_device_dhcp4_renew (NMDevice *self, gboolean release) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + NMActStageReturn ret; + NMDeviceStateReason reason; + NMActRequest *req; + NMConnection *connection; + + g_return_val_if_fail (priv->dhcp4_client != NULL, FALSE); + + /* Terminate old DHCP instance and release the old lease */ + dhcp4_cleanup (self, TRUE, TRUE); + + req = nm_device_get_act_request (self); + g_assert (req); + connection = nm_act_request_get_connection (req); + g_assert (connection); + + /* Start DHCP again on the interface */ + ret = dhcp4_start (self, connection, &reason); + + return (ret != NM_ACT_STAGE_RETURN_FAILURE); +} + static NMActStageReturn real_act_stage3_ip4_config_start (NMDevice *self, NMDeviceStateReason *reason) { @@ -1554,7 +1579,7 @@ real_act_stage3_ip4_config_start (NMDevice *self, NMDeviceStateReason *reason) method = nm_setting_ip4_config_get_method (s_ip4); if (!s_ip4 || !method || !strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_AUTO)) { - ret = dhcp4_start (self, connection, s_ip4, reason); + ret = dhcp4_start (self, connection, reason); } else if (s_ip4 && !strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_LINK_LOCAL)) { GError *error = NULL; const char *iface = nm_device_get_iface (self); @@ -2675,7 +2700,7 @@ delayed_transitions_clear (NMDevice *self) } static void -dhcp4_cleanup (NMDevice *self, gboolean stop) +dhcp4_cleanup (NMDevice *self, gboolean stop, gboolean release) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); @@ -2698,7 +2723,7 @@ dhcp4_cleanup (NMDevice *self, gboolean stop) } if (stop) - nm_dhcp_client_stop (priv->dhcp4_client); + nm_dhcp_client_stop (priv->dhcp4_client, release); g_object_unref (priv->dhcp4_client); priv->dhcp4_client = NULL; @@ -2706,7 +2731,7 @@ dhcp4_cleanup (NMDevice *self, gboolean stop) } static void -dhcp6_cleanup (NMDevice *self, gboolean stop) +dhcp6_cleanup (NMDevice *self, gboolean stop, gboolean release) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); @@ -2730,7 +2755,7 @@ dhcp6_cleanup (NMDevice *self, gboolean stop) } if (stop) - nm_dhcp_client_stop (priv->dhcp6_client); + nm_dhcp_client_stop (priv->dhcp6_client, release); g_object_unref (priv->dhcp6_client); priv->dhcp6_client = NULL; @@ -2779,8 +2804,8 @@ nm_device_deactivate_quickly (NMDevice *self) /* Clear any delayed transitions */ delayed_transitions_clear (self); - dhcp4_cleanup (self, TRUE); - dhcp6_cleanup (self, TRUE); + dhcp4_cleanup (self, TRUE, FALSE); + dhcp6_cleanup (self, TRUE, FALSE); addrconf6_cleanup (self); dnsmasq_cleanup (self); aipd_cleanup (self); @@ -3357,8 +3382,8 @@ dispose (GObject *object) delayed_transitions_clear (self); /* Clean up and stop DHCP */ - dhcp4_cleanup (self, take_down); - dhcp6_cleanup (self, take_down); + dhcp4_cleanup (self, take_down, FALSE); + dhcp6_cleanup (self, take_down, FALSE); addrconf6_cleanup (self); dnsmasq_cleanup (self); diff --git a/src/nm-device.h b/src/nm-device.h index db2b1b7db0..bd400fd6bf 100644 --- a/src/nm-device.h +++ b/src/nm-device.h @@ -185,6 +185,8 @@ void nm_device_set_dhcp_anycast_address (NMDevice *device, guint8 *addr); void nm_device_clear_autoconnect_inhibit (NMDevice *device); +gboolean nm_device_dhcp4_renew (NMDevice *device, gboolean release); + G_END_DECLS #endif /* NM_DEVICE_H */