static void nm_dhcp_manager_handle_event (DBusGProxy *proxy, GHashTable *options, gpointer user_data) { NMDHCPManager *manager; NMDHCPManagerPrivate *priv; NMDHCPClient *client; char *iface = NULL; char *pid_str = NULL; char *reason = NULL; unsigned long temp; manager = NM_DHCP_MANAGER (user_data); priv = NM_DHCP_MANAGER_GET_PRIVATE (manager); iface = get_option (options, "interface"); if (iface == NULL) { nm_log_warn (LOGD_DHCP, "DHCP event didn't have associated interface."); goto out; } pid_str = get_option (options, "pid"); if (pid_str == NULL) { nm_log_warn (LOGD_DHCP, "DHCP event didn't have associated PID."); goto out; } temp = strtoul (pid_str, NULL, 10); if ((temp == ULONG_MAX) && (errno == ERANGE)) { nm_log_warn (LOGD_DHCP, "couldn't convert PID"); goto out; } client = get_client_for_pid (manager, (GPid) temp); if (client == NULL) { nm_log_warn (LOGD_DHCP, "(pid %d) unhandled DHCP event for interface %s", temp, iface); goto out; } if (strcmp (iface, nm_dhcp_client_get_iface (client))) { nm_log_warn (LOGD_DHCP, "(pid %d) received DHCP event from unexpected interface '%s' (expected '%s')", temp, iface, nm_dhcp_client_get_iface (client)); goto out; } reason = get_option (options, "reason"); if (reason == NULL) { nm_log_warn (LOGD_DHCP, "(pid %d) DHCP event didn't have a reason", temp); goto out; } nm_dhcp_client_new_options (client, options, reason); out: g_free (iface); g_free (pid_str); g_free (reason); }
static void dhcp6_event_cb (sd_dhcp6_client *client, int event, gpointer user_data) { NMDhcpSystemd *self = NM_DHCP_SYSTEMD (user_data); NMDhcpSystemdPrivate *priv = NM_DHCP_SYSTEMD_GET_PRIVATE (self); const char *iface = nm_dhcp_client_get_iface (NM_DHCP_CLIENT (self)); g_assert (priv->client6 == client); nm_log_dbg (LOGD_DHCP6, "(%s): DHCPv6 client event %d", iface, event); switch (event) { case SD_DHCP6_CLIENT_EVENT_RETRANS_MAX: nm_dhcp_client_set_state (NM_DHCP_CLIENT (user_data), NM_DHCP_STATE_TIMEOUT, NULL, NULL); break; case SD_DHCP6_CLIENT_EVENT_RESEND_EXPIRE: case SD_DHCP6_CLIENT_EVENT_STOP: nm_dhcp_client_set_state (NM_DHCP_CLIENT (user_data), NM_DHCP_STATE_FAIL, NULL, NULL); break; case SD_DHCP6_CLIENT_EVENT_IP_ACQUIRE: bound6_handle (self); break; default: nm_log_warn (LOGD_DHCP6, "(%s): unhandled DHCPv6 event %d", iface, event); break; } }
static NMDHCPClient * get_client_for_iface (NMDHCPManager *manager, const char *iface, gboolean ip6) { NMDHCPManagerPrivate *priv; GHashTableIter iter; gpointer value; g_return_val_if_fail (manager != NULL, NULL); g_return_val_if_fail (NM_IS_DHCP_MANAGER (manager), NULL); g_return_val_if_fail (iface, NULL); priv = NM_DHCP_MANAGER_GET_PRIVATE (manager); g_hash_table_iter_init (&iter, priv->clients); while (g_hash_table_iter_next (&iter, NULL, &value)) { NMDHCPClient *candidate = NM_DHCP_CLIENT (value); if ( !strcmp (iface, nm_dhcp_client_get_iface (candidate)) && (nm_dhcp_client_get_ipv6 (candidate) == ip6)) return candidate; } return NULL; }
static void bound6_handle (NMDhcpSystemd *self) { /* not yet supported... */ nm_log_warn (LOGD_DHCP6, "(%s): internal DHCP does not yet support DHCPv6", nm_dhcp_client_get_iface (NM_DHCP_CLIENT (self))); nm_dhcp_client_set_state (NM_DHCP_CLIENT (self), NM_DHCP_STATE_FAIL, NULL, NULL); }
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 void stop (NMDhcpClient *client, gboolean release, const GByteArray *duid) { NMDhcpSystemdPrivate *priv = NM_DHCP_SYSTEMD_GET_PRIVATE (client); int r = 0; if (priv->client4) r = sd_dhcp_client_stop (priv->client4); else if (priv->client6) r = sd_dhcp6_client_stop (priv->client6); if (r) { nm_log_warn (priv->client6 ? LOGD_DHCP6 : LOGD_DHCP4, "(%s): failed to stop DHCP client (%d)", nm_dhcp_client_get_iface (client), r); } }
static gboolean ip6_start (NMDhcpClient *client, const char *dhcp_anycast_addr, const struct in6_addr *ll_addr, gboolean info_only, NMSettingIP6ConfigPrivacy privacy, const GByteArray *duid) { 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; int r, i; g_assert (priv->client4 == NULL); g_assert (priv->client6 == NULL); g_return_val_if_fail (duid != NULL, FALSE); g_free (priv->lease_file); priv->lease_file = get_leasefile_path (iface, nm_dhcp_client_get_uuid (client), TRUE); priv->info_only = info_only; r = sd_dhcp6_client_new (&priv->client6); if (r < 0) { _LOGW ("failed to create client (%d)", r); return FALSE; } _LOGT ("dhcp-client6: set %p", priv->client4); if (info_only) sd_dhcp6_client_set_information_request (priv->client6, 1); /* NM stores the entire DUID which includes the uint16 "type", while systemd * wants the type passed separately from the following data. */ r = sd_dhcp6_client_set_duid (priv->client6, ntohs (((const guint16 *) duid->data)[0]), duid->data + 2, duid->len - 2); if (r < 0) { _LOGW ("failed to set DUID (%d)", r); return FALSE; } r = sd_dhcp6_client_attach_event (priv->client6, NULL, 0); if (r < 0) { _LOGW ("failed to attach event (%d)", r); goto error; } hwaddr = nm_dhcp_client_get_hw_addr (client); if (hwaddr) { r = sd_dhcp6_client_set_mac (priv->client6, hwaddr->data, hwaddr->len, get_arp_type (hwaddr)); if (r < 0) { _LOGW ("failed to set MAC address (%d)", r); goto error; } } r = sd_dhcp6_client_set_index (priv->client6, nm_dhcp_client_get_ifindex (client)); if (r < 0) { _LOGW ("failed to set ifindex (%d)", r); goto error; } r = sd_dhcp6_client_set_callback (priv->client6, dhcp6_event_cb, client); if (r < 0) { _LOGW ("failed to set callback (%d)", r); goto error; } /* Add requested options */ for (i = 0; dhcp6_requests[i].name; i++) { if (dhcp6_requests[i].include) sd_dhcp6_client_set_request_option (priv->client6, dhcp6_requests[i].num); } r = sd_dhcp6_client_set_local_address (priv->client6, ll_addr); if (r < 0) { _LOGW ("failed to set local address (%d)", r); goto error; } r = sd_dhcp6_client_start (priv->client6); if (r < 0) { _LOGW ("failed to start client (%d)", r); goto error; } return TRUE; error: sd_dhcp6_client_unref (priv->client6); priv->client6 = NULL; return FALSE; }
static NMIP6Config * lease_to_ip6_config (const char *iface, int ifindex, sd_dhcp6_lease *lease, GHashTable *options, gboolean log_lease, gboolean info_only, GError **error) { struct in6_addr tmp_addr, *dns; uint32_t lft_pref, lft_valid; NMIP6Config *ip6_config; const char *addr_str; char **domains; GString *str; int num, i; gint32 ts; g_return_val_if_fail (lease, NULL); ip6_config = nm_ip6_config_new (ifindex); ts = nm_utils_get_monotonic_timestamp_s (); str = g_string_sized_new (30); /* Addresses */ sd_dhcp6_lease_reset_address_iter (lease); while (sd_dhcp6_lease_get_address (lease, &tmp_addr, &lft_pref, &lft_valid) >= 0) { NMPlatformIP6Address address = { .plen = 128, .address = tmp_addr, .timestamp = ts, .lifetime = lft_valid, .preferred = lft_pref, .addr_source = NM_IP_CONFIG_SOURCE_DHCP, }; nm_ip6_config_add_address (ip6_config, &address); addr_str = nm_utils_inet6_ntop (&tmp_addr, NULL); g_string_append_printf (str, "%s%s", str->len ? " " : "", addr_str); LOG_LEASE (LOGD_DHCP6, " address %s", nm_platform_ip6_address_to_string (&address, NULL, 0)); }; if (str->len) { add_option (options, dhcp6_requests, DHCP6_OPTION_IP_ADDRESS, str->str); g_string_set_size (str , 0); } if (!info_only && nm_ip6_config_get_num_addresses (ip6_config) == 0) { g_string_free (str, TRUE); g_object_unref (ip6_config); g_set_error_literal (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_FAILED, "no address received in managed mode"); return NULL; } /* DNS servers */ num = sd_dhcp6_lease_get_dns (lease, &dns); if (num > 0) { for (i = 0; i < num; i++) { nm_ip6_config_add_nameserver (ip6_config, &dns[i]); addr_str = nm_utils_inet6_ntop (&dns[i], NULL); g_string_append_printf (str, "%s%s", str->len ? " " : "", addr_str); LOG_LEASE (LOGD_DHCP6, " nameserver %s", addr_str); } add_option (options, dhcp6_requests, SD_DHCP6_OPTION_DNS_SERVERS, str->str); g_string_set_size (str, 0); } /* Search domains */ num = sd_dhcp6_lease_get_domains (lease, &domains); if (num > 0) { for (i = 0; i < num; i++) { nm_ip6_config_add_search (ip6_config, domains[i]); g_string_append_printf (str, "%s%s", str->len ? " " : "", domains[i]); LOG_LEASE (LOGD_DHCP6, " domain name '%s'", domains[i]); } add_option (options, dhcp6_requests, SD_DHCP6_OPTION_DOMAIN_LIST, str->str); g_string_set_size (str, 0); } g_string_free (str, TRUE); return ip6_config; } static void bound6_handle (NMDhcpSystemd *self) { NMDhcpSystemdPrivate *priv = NM_DHCP_SYSTEMD_GET_PRIVATE (self); const char *iface = nm_dhcp_client_get_iface (NM_DHCP_CLIENT (self)); gs_unref_object NMIP6Config *ip6_config = NULL; gs_unref_hashtable GHashTable *options = NULL; gs_free_error GError *error = NULL; sd_dhcp6_lease *lease; int r; r = sd_dhcp6_client_get_lease (priv->client6, &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); ip6_config = lease_to_ip6_config (iface, nm_dhcp_client_get_ifindex (NM_DHCP_CLIENT (self)), lease, options, TRUE, priv->info_only, &error); if (ip6_config) { nm_dhcp_client_set_state (NM_DHCP_CLIENT (self), NM_DHCP_STATE_BOUND, G_OBJECT (ip6_config), options); } else { _LOGW ("%s", error->message); nm_dhcp_client_set_state (NM_DHCP_CLIENT (self), NM_DHCP_STATE_FAIL, NULL, NULL); } }
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_client_id, const char *dhcp_anycast_addr, const char *hostname) { NMDhcpDhcpcdPrivate *priv = NM_DHCP_DHCPCD_GET_PRIVATE (client); GPtrArray *argv = NULL; pid_t pid = -1; GError *error = NULL; char *pid_contents = NULL, *binary_name, *cmd_str; const char *iface; g_return_val_if_fail (priv->pid_file == NULL, FALSE); iface = nm_dhcp_client_get_iface (client); /* dhcpcd does not allow custom pidfiles; the pidfile is always * RUNDIR "dhcpcd-<ifname>.pid". */ priv->pid_file = g_strdup_printf (RUNDIR "/dhcpcd-%s.pid", iface); if (!g_file_test (priv->path, G_FILE_TEST_EXISTS)) { nm_log_warn (LOGD_DHCP4, "%s does not exist.", priv->path); return FALSE; } /* Kill any existing dhcpcd from the pidfile */ binary_name = g_path_get_basename (priv->path); nm_dhcp_client_stop_existing (priv->pid_file, binary_name); g_free (binary_name); argv = g_ptr_array_new (); g_ptr_array_add (argv, (gpointer) priv->path); g_ptr_array_add (argv, (gpointer) "-B"); /* Don't background on lease (disable fork()) */ g_ptr_array_add (argv, (gpointer) "-K"); /* Disable built-in carrier detection */ g_ptr_array_add (argv, (gpointer) "-L"); /* Disable built-in IPv4LL since we use avahi-autoipd */ /* --noarp. Don't request or claim the address by ARP; this also disables IPv4LL. */ g_ptr_array_add (argv, (gpointer) "-A"); g_ptr_array_add (argv, (gpointer) "-G"); /* Let NM handle routing */ g_ptr_array_add (argv, (gpointer) "-c"); /* Set script file */ g_ptr_array_add (argv, (gpointer) nm_dhcp_helper_path); #ifdef DHCPCD_SUPPORTS_IPV6 /* IPv4-only for now. NetworkManager knows better than dhcpcd when to * run IPv6, and dhcpcd's automatic Router Solicitations cause problems * with devices that don't expect them. */ g_ptr_array_add (argv, (gpointer) "-4"); #endif if (hostname && strlen (hostname)) { g_ptr_array_add (argv, (gpointer) "-h"); /* Send hostname to DHCP server */ g_ptr_array_add (argv, (gpointer) hostname ); } g_ptr_array_add (argv, (gpointer) iface); g_ptr_array_add (argv, NULL); cmd_str = g_strjoinv (" ", (gchar **) argv->pdata); nm_log_dbg (LOGD_DHCP4, "running: %s", cmd_str); g_free (cmd_str); if (g_spawn_async (NULL, (char **) argv->pdata, NULL, G_SPAWN_DO_NOT_REAP_CHILD, &dhcpcd_child_setup, NULL, &pid, &error)) { g_assert (pid > 0); nm_log_info (LOGD_DHCP4, "dhcpcd started with pid %d", pid); nm_dhcp_client_watch_child (client, pid); } else { nm_log_warn (LOGD_DHCP4, "dhcpcd failed to start. error: '%s'", error->message); g_error_free (error); } g_free (pid_contents); g_ptr_array_free (argv, TRUE); return pid > 0 ? TRUE : FALSE; }
static GPid ip4_start (NMDHCPClient *client, NMSettingIP4Config *s_ip4, guint8 *dhcp_anycast_addr, const char *hostname) { NMDHCPDhcpcdPrivate *priv = NM_DHCP_DHCPCD_GET_PRIVATE (client); GPtrArray *argv = NULL; GPid pid = -1; GError *error = NULL; char *pid_contents = NULL, *binary_name, *cmd_str; const char *iface, *uuid; g_return_val_if_fail (priv->pid_file == NULL, -1); iface = nm_dhcp_client_get_iface (client); uuid = nm_dhcp_client_get_uuid (client); priv->pid_file = g_strdup_printf (NMSTATEDIR "/dhcpcd-%s.pid", iface); if (!g_file_test (priv->path, G_FILE_TEST_EXISTS)) { nm_log_warn (LOGD_DHCP4, "%s does not exist.", priv->path); return -1; } /* Kill any existing dhcpcd from the pidfile */ binary_name = g_path_get_basename (priv->path); nm_dhcp_client_stop_existing (priv->pid_file, binary_name); g_free (binary_name); argv = g_ptr_array_new (); g_ptr_array_add (argv, (gpointer) priv->path); g_ptr_array_add (argv, (gpointer) "-B"); /* Don't background on lease (disable fork()) */ g_ptr_array_add (argv, (gpointer) "-K"); /* Disable built-in carrier detection */ g_ptr_array_add (argv, (gpointer) "-L"); /* Disable built-in IPv4LL since we use avahi-autoipd */ g_ptr_array_add (argv, (gpointer) "-G"); /* Let NM handle routing */ g_ptr_array_add (argv, (gpointer) "-c"); /* Set script file */ g_ptr_array_add (argv, (gpointer) nm_dhcp_helper_path); if (hostname && strlen (hostname)) { g_ptr_array_add (argv, (gpointer) "-h"); /* Send hostname to DHCP server */ g_ptr_array_add (argv, (gpointer) hostname ); } g_ptr_array_add (argv, (gpointer) iface); g_ptr_array_add (argv, NULL); cmd_str = g_strjoinv (" ", (gchar **) argv->pdata); nm_log_dbg (LOGD_DHCP4, "running: %s", cmd_str); g_free (cmd_str); if (!g_spawn_async (NULL, (char **) argv->pdata, NULL, G_SPAWN_DO_NOT_REAP_CHILD, &dhcpcd_child_setup, NULL, &pid, &error)) { nm_log_warn (LOGD_DHCP4, "dhcpcd failed to start. error: '%s'", error->message); g_error_free (error); pid = -1; } else nm_log_info (LOGD_DHCP4, "dhcpcd started with pid %d", pid); g_free (pid_contents); g_ptr_array_free (argv, TRUE); return pid; }
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; }