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 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); g_assert (priv->client6 == client); _LOGD ("client event %d", 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: case SD_DHCP6_CLIENT_EVENT_INFORMATION_REQUEST: bound6_handle (self); break; default: _LOGW ("unhandled event %d", event); break; } }
static void dhcp_event_cb (sd_dhcp_client *client, int event, gpointer user_data) { NMDhcpSystemd *self = NM_DHCP_SYSTEMD (user_data); NMDhcpSystemdPrivate *priv = NM_DHCP_SYSTEMD_GET_PRIVATE (self); g_assert (priv->client4 == client); _LOGD ("client event %d", event); switch (event) { case SD_DHCP_CLIENT_EVENT_EXPIRED: nm_dhcp_client_set_state (NM_DHCP_CLIENT (user_data), NM_DHCP_STATE_EXPIRE, NULL, NULL); break; case SD_DHCP_CLIENT_EVENT_STOP: nm_dhcp_client_set_state (NM_DHCP_CLIENT (user_data), NM_DHCP_STATE_FAIL, NULL, NULL); break; case SD_DHCP_CLIENT_EVENT_RENEW: case SD_DHCP_CLIENT_EVENT_IP_CHANGE: case SD_DHCP_CLIENT_EVENT_IP_ACQUIRE: bound4_handle (self); break; default: _LOGW ("unhandled DHCP event %d", event); break; } }
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 daemon_watch_cb (GPid pid, gint status, gpointer user_data) { NMDHCPClient *self = NM_DHCP_CLIENT (user_data); NMDHCPClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE (self); NMDHCPState new_state; if (priv->ipv6) { nm_log_info (LOGD_DHCP6, "(%s): DHCPv6 client pid %d exited with status %d", priv->iface, pid, WIFEXITED (status) ? WEXITSTATUS (status) : -1); } else { nm_log_info (LOGD_DHCP4, "(%s): DHCPv4 client pid %d exited with status %d", priv->iface, pid, WIFEXITED (status) ? WEXITSTATUS (status) : -1); } if (!WIFEXITED (status)) { new_state = DHC_ABEND; nm_log_warn (LOGD_DHCP, "DHCP client died abnormally"); } else new_state = DHC_END; watch_cleanup (self); timeout_cleanup (self); priv->dead = TRUE; dhcp_client_set_state (self, new_state, TRUE, FALSE); }
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 gboolean signal_remove (gpointer user_data) { NMDHCPClient *self = NM_DHCP_CLIENT (user_data); NM_DHCP_CLIENT_GET_PRIVATE (self)->remove_id = 0; g_signal_emit (G_OBJECT (self), signals[REMOVE], 0); return FALSE; }
static void _save_client_id (NMDhcpSystemd *self, uint8_t type, const uint8_t *client_id, size_t len) { gs_unref_bytes GBytes *b = NULL; gs_free char *buf = NULL; g_return_if_fail (self != NULL); g_return_if_fail (client_id != NULL); g_return_if_fail (len > 0); if (!nm_dhcp_client_get_client_id (NM_DHCP_CLIENT (self))) { buf = g_malloc (len + 1); buf[0] = type; memcpy (buf + 1, client_id, len); b = g_bytes_new (buf, len + 1); nm_dhcp_client_set_client_id (NM_DHCP_CLIENT (self), b); } }
static gboolean daemon_timeout (gpointer user_data) { NMDHCPClient *self = NM_DHCP_CLIENT (user_data); NMDHCPClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE (self); if (priv->ipv6) { nm_log_warn (LOGD_DHCP6, "(%s): DHCPv6 request timed out.", priv->iface); } else { nm_log_warn (LOGD_DHCP4, "(%s): DHCPv4 request timed out.", priv->iface); } g_signal_emit (G_OBJECT (self), signals[TIMEOUT], 0); return FALSE; }
static void dispose (GObject *object) { NMDhcpManagerPrivate *priv = NM_DHCP_MANAGER_GET_PRIVATE (object); GList *values, *iter; if (priv->clients) { values = g_hash_table_get_values (priv->clients); for (iter = values; iter; iter = g_list_next (iter)) remove_client (NM_DHCP_MANAGER (object), NM_DHCP_CLIENT (iter->data)); g_list_free (values); } G_OBJECT_CLASS (nm_dhcp_manager_parent_class)->dispose (object); }
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 dispose (GObject *object) { NMDHCPClient *self = NM_DHCP_CLIENT (object); NMDHCPClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE (self); /* Stopping the client is left up to the controlling device * explicitly since we may want to quit NetworkManager but not terminate * the DHCP client. */ if (priv->remove_id) g_source_remove (priv->remove_id); g_hash_table_destroy (priv->options); g_free (priv->iface); G_OBJECT_CLASS (nm_dhcp_client_parent_class)->dispose (object); }
static NMDHCPClient * get_client_for_pid (NMDHCPManager *manager, GPid pid) { 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); 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 (nm_dhcp_client_get_pid (candidate) == pid) return candidate; } return NULL; }
static NMDhcpClient * get_client_for_ifindex (NMDhcpManager *manager, int ifindex, gboolean ip6) { NMDhcpManagerPrivate *priv; GHashTableIter iter; gpointer value; g_return_val_if_fail (NM_IS_DHCP_MANAGER (manager), NULL); g_return_val_if_fail (ifindex > 0, 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 ( nm_dhcp_client_get_ifindex (candidate) == ifindex && nm_dhcp_client_get_ipv6 (candidate) == ip6) return candidate; } return NULL; }
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); } }