void nm_dhcp_client_stop (NMDHCPClient *self, gboolean release) { NMDHCPClientPrivate *priv; g_return_if_fail (self != NULL); g_return_if_fail (NM_IS_DHCP_CLIENT (self)); priv = NM_DHCP_CLIENT_GET_PRIVATE (self); /* Kill the DHCP client */ if (!priv->dead) { 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", priv->iface, priv->pid); } /* And clean stuff up */ priv->pid = -1; dhcp_client_set_state (self, DHC_END, FALSE, TRUE); g_hash_table_remove_all (priv->options); timeout_cleanup (self); watch_cleanup (self); }
static void set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { NMDHCPClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE (object); switch (prop_id) { case PROP_IFACE: /* construct-only */ priv->iface = g_strdup (g_value_get_string (value)); break; case PROP_IPV6: /* construct-only */ priv->ipv6 = g_value_get_boolean (value); break; case PROP_UUID: /* construct-only */ priv->uuid = g_value_dup_string (value); break; case PROP_TIMEOUT: priv->timeout = g_value_get_uint (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } }
gboolean nm_dhcp_client_start_ip6 (NMDHCPClient *self, NMSettingIP6Config *s_ip6, guint8 *dhcp_anycast_addr, const char *hostname, gboolean info_only) { NMDHCPClientPrivate *priv; g_return_val_if_fail (self != NULL, FALSE); g_return_val_if_fail (NM_IS_DHCP_CLIENT (self), FALSE); priv = NM_DHCP_CLIENT_GET_PRIVATE (self); g_return_val_if_fail (priv->pid == -1, FALSE); g_return_val_if_fail (priv->ipv6 == TRUE, FALSE); g_return_val_if_fail (priv->uuid != NULL, FALSE); priv->info_only = info_only; nm_log_info (LOGD_DHCP, "Activation (%s) Beginning DHCPv6 transaction (timeout in %d seconds)", priv->iface, priv->timeout); priv->pid = NM_DHCP_CLIENT_GET_CLASS (self)->ip6_start (self, s_ip6, dhcp_anycast_addr, hostname, info_only); if (priv->pid > 0) start_monitor (self); return priv->pid ? TRUE : FALSE; }
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 void get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { NMDHCPClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE (object); switch (prop_id) { case PROP_IFACE: g_value_set_string (value, priv->iface); break; case PROP_HWADDR: g_value_set_boxed (value, priv->hwaddr); break; case PROP_IPV6: g_value_set_boolean (value, priv->ipv6); break; case PROP_UUID: g_value_set_string (value, priv->uuid); break; case PROP_TIMEOUT: g_value_set_uint (value, priv->timeout); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } }
static void nm_dhcp_client_init (NMDHCPClient *self) { NMDHCPClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE (self); priv->options = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); priv->pid = -1; }
GPid nm_dhcp_client_get_pid (NMDHCPClient *self) { g_return_val_if_fail (self != NULL, -1); g_return_val_if_fail (NM_IS_DHCP_CLIENT (self), -1); return NM_DHCP_CLIENT_GET_PRIVATE (self)->pid; }
const char * nm_dhcp_client_get_iface (NMDHCPClient *self) { g_return_val_if_fail (self != NULL, NULL); g_return_val_if_fail (NM_IS_DHCP_CLIENT (self), NULL); return NM_DHCP_CLIENT_GET_PRIVATE (self)->iface; }
gboolean nm_dhcp_client_get_ipv6 (NMDHCPClient *self) { g_return_val_if_fail (self != NULL, FALSE); g_return_val_if_fail (NM_IS_DHCP_CLIENT (self), FALSE); return NM_DHCP_CLIENT_GET_PRIVATE (self)->ipv6; }
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; }
void nm_dhcp_client_new_options (NMDHCPClient *self, GHashTable *options, const char *reason) { NMDHCPClientPrivate *priv; guint32 old_state; guint32 new_state; g_return_if_fail (self != NULL); g_return_if_fail (NM_IS_DHCP_CLIENT (self)); g_return_if_fail (options != NULL); g_return_if_fail (reason != NULL); priv = NM_DHCP_CLIENT_GET_PRIVATE (self); old_state = priv->state; new_state = string_to_state (reason); /* Clear old and save new DHCP options */ g_hash_table_remove_all (priv->options); g_hash_table_foreach (options, copy_option, priv->options); if (old_state == new_state) { /* dhclient will stay in the same state (or, really, provide the same * reason) for operations like RENEW and REBIND. We need to ensure * that triggers various DHCP lease change code, so we need to pass * along same-state transitions for these states. */ if ( new_state != DHC_BOUND4 && new_state != DHC_RENEW4 && new_state != DHC_REBIND4 && new_state != DHC_BOUND6 && new_state != DHC_RENEW6 && new_state != DHC_REBIND6) return; } /* Handle changed device state */ if (state_is_bound (new_state)) { /* Cancel the timeout if the DHCP client is now bound */ timeout_cleanup (self); } if (priv->ipv6) { nm_log_info (LOGD_DHCP6, "(%s): DHCPv6 state changed %s -> %s", priv->iface, state_to_string (old_state), state_to_string (new_state)); } else { nm_log_info (LOGD_DHCP4, "(%s): DHCPv4 state changed %s -> %s", priv->iface, state_to_string (old_state), state_to_string (new_state)); } dhcp_client_set_state (self, new_state, TRUE, FALSE); }
static void watch_cleanup (NMDHCPClient *self) { NMDHCPClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE (self); if (priv->watch_id) { g_source_remove (priv->watch_id); priv->watch_id = 0; } }
gboolean nm_dhcp_client_foreach_option (NMDHCPClient *self, GHFunc func, gpointer user_data) { NMDHCPClientPrivate *priv; GHashTableIter iter; gpointer iterkey, itervalue; g_return_val_if_fail (self != NULL, FALSE); g_return_val_if_fail (NM_IS_DHCP_CLIENT (self), FALSE); g_return_val_if_fail (func != NULL, FALSE); priv = NM_DHCP_CLIENT_GET_PRIVATE (self); if (!state_is_bound (priv->state)) { if (priv->ipv6) { nm_log_warn (LOGD_DHCP6, "(%s): DHCPv6 client didn't bind to a lease.", priv->iface); } else { nm_log_warn (LOGD_DHCP4, "(%s): DHCPv4 client didn't bind to a lease.", priv->iface); } } g_hash_table_iter_init (&iter, priv->options); while (g_hash_table_iter_next (&iter, &iterkey, &itervalue)) { const char *key = iterkey, *value = itervalue; const char **p; static const char *filter_options[] = { "interface", "pid", "reason", "dhcp_message_type", NULL }; gboolean ignore = FALSE; /* Filter out stuff that's not actually new DHCP options */ for (p = filter_options; *p; p++) { if (!strcmp (*p, key) || !strncmp (key, OLD_TAG, strlen (OLD_TAG))) { ignore = TRUE; break; } } if (!ignore) { const char *tmp_key = key; /* Remove the "new_" prefix that dhclient passes back */ if (!strncmp (key, NEW_TAG, strlen (NEW_TAG))) tmp_key = key + strlen (NEW_TAG); func ((gpointer) tmp_key, (gpointer) value, user_data); } } return TRUE; }
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 start_monitor (NMDHCPClient *self) { NMDHCPClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE (self); g_return_if_fail (priv->pid > 0); /* Set up a timeout on the transaction to kill it after the timeout */ priv->timeout_id = g_timeout_add_seconds (priv->timeout, daemon_timeout, self); priv->watch_id = g_child_watch_add (priv->pid, (GChildWatchFunc) daemon_watch_cb, self); }
gboolean nm_dhcp_client_start_ip6 (NMDHCPClient *self, NMSettingIP6Config *s_ip6, guint8 *dhcp_anycast_addr, const char *hostname, gboolean info_only) { NMDHCPClientPrivate *priv; char *escaped; g_return_val_if_fail (self != NULL, FALSE); g_return_val_if_fail (NM_IS_DHCP_CLIENT (self), FALSE); priv = NM_DHCP_CLIENT_GET_PRIVATE (self); g_return_val_if_fail (priv->pid == -1, FALSE); g_return_val_if_fail (priv->ipv6 == TRUE, FALSE); g_return_val_if_fail (priv->uuid != NULL, FALSE); /* If we don't have one yet, read the default DUID for this DHCPv6 client * from the client-specific persistent configuration. */ if (!priv->duid) priv->duid = NM_DHCP_CLIENT_GET_CLASS (self)->get_duid (self); if (nm_logging_level_enabled (LOGL_DEBUG)) { escaped = escape_duid (priv->duid); nm_log_dbg (LOGD_DHCP, "(%s): DHCPv6 DUID is '%s'", priv->iface, escaped); g_free (escaped); } priv->info_only = info_only; nm_log_info (LOGD_DHCP, "Activation (%s) Beginning DHCPv6 transaction (timeout in %d seconds)", priv->iface, priv->timeout); priv->pid = NM_DHCP_CLIENT_GET_CLASS (self)->ip6_start (self, s_ip6, dhcp_anycast_addr, hostname, info_only, priv->duid); if (priv->pid > 0) start_monitor (self); return priv->pid ? TRUE : FALSE; }
void nm_dhcp_client_new_options (NMDHCPClient *self, GHashTable *options, const char *reason) { NMDHCPClientPrivate *priv; guint32 old_state; guint32 new_state; g_return_if_fail (self != NULL); g_return_if_fail (NM_IS_DHCP_CLIENT (self)); g_return_if_fail (options != NULL); g_return_if_fail (reason != NULL); priv = NM_DHCP_CLIENT_GET_PRIVATE (self); old_state = priv->state; new_state = string_to_state (reason); /* Clear old and save new DHCP options */ g_hash_table_remove_all (priv->options); g_hash_table_foreach (options, copy_option, priv->options); if (old_state == new_state) return; /* Handle changed device state */ if (state_is_bound (new_state)) { /* Cancel the timeout if the DHCP client is now bound */ timeout_cleanup (self); } if (priv->ipv6) { nm_log_info (LOGD_DHCP6, "(%s): DHCPv6 state changed %s -> %s", priv->iface, state_to_string (old_state), state_to_string (new_state)); } else { nm_log_info (LOGD_DHCP4, "(%s): DHCPv4 state changed %s -> %s", priv->iface, state_to_string (old_state), state_to_string (new_state)); } dhcp_client_set_state (self, new_state, TRUE, FALSE); }
static void stop (NMDHCPClient *self, gboolean release) { NMDHCPClientPrivate *priv; g_return_if_fail (self != NULL); g_return_if_fail (NM_IS_DHCP_CLIENT (self)); priv = NM_DHCP_CLIENT_GET_PRIVATE (self); g_return_if_fail (priv->pid > 0); /* Clean up the watch handler since we're explicitly killing the daemon */ watch_cleanup (self); nm_dhcp_client_stop_pid (priv->pid, priv->iface, 0); priv->info_only = FALSE; }
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); }
NMIP6Config * nm_dhcp_client_get_ip6_config (NMDHCPClient *self, gboolean test) { NMDHCPClientPrivate *priv; g_return_val_if_fail (self != NULL, NULL); g_return_val_if_fail (NM_IS_DHCP_CLIENT (self), NULL); priv = NM_DHCP_CLIENT_GET_PRIVATE (self); if (test && !state_is_bound (priv->state)) { nm_log_warn (LOGD_DHCP6, "(%s): DHCPv6 client didn't bind to a lease.", priv->iface); return NULL; } if (!g_hash_table_size (priv->options)) { /* We never got a response from the DHCP client */ return NULL; } return ip6_options_to_config (self); }
static void dhcp_client_set_state (NMDHCPClient *self, NMDHCPState state, gboolean emit_state, gboolean remove_now) { NMDHCPClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE (self); priv->state = state; if (emit_state) g_signal_emit (G_OBJECT (self), signals[STATE_CHANGED], 0, priv->state); if (state == DHC_END || state == DHC_ABEND) { /* Start the remove signal timer */ if (remove_now) { g_signal_emit (G_OBJECT (self), signals[REMOVE], 0); } else { if (!priv->remove_id) priv->remove_id = g_timeout_add_seconds (5, signal_remove, self); } } }
/* Given a table of DHCP options from the client, convert into an IP4Config */ static NMIP4Config * ip4_options_to_config (NMDHCPClient *self) { NMDHCPClientPrivate *priv; NMIP4Config *ip4_config = NULL; struct in_addr tmp_addr; NMIP4Address *addr = NULL; char *str = NULL; guint32 gwaddr = 0, prefix = 0; g_return_val_if_fail (self != NULL, NULL); g_return_val_if_fail (NM_IS_DHCP_CLIENT (self), NULL); priv = NM_DHCP_CLIENT_GET_PRIVATE (self); g_return_val_if_fail (priv->options != NULL, NULL); ip4_config = nm_ip4_config_new (); if (!ip4_config) { nm_log_warn (LOGD_DHCP4, "(%s): couldn't allocate memory for an IP4Config!", priv->iface); return NULL; } addr = nm_ip4_address_new (); if (!addr) { nm_log_warn (LOGD_DHCP4, "(%s): couldn't allocate memory for an IP4 Address!", priv->iface); goto error; } str = g_hash_table_lookup (priv->options, "new_ip_address"); if (str && (inet_pton (AF_INET, str, &tmp_addr) > 0)) { nm_ip4_address_set_address (addr, tmp_addr.s_addr); nm_log_info (LOGD_DHCP4, " address %s", str); } else goto error; str = g_hash_table_lookup (priv->options, "new_subnet_mask"); if (str && (inet_pton (AF_INET, str, &tmp_addr) > 0)) { prefix = nm_utils_ip4_netmask_to_prefix (tmp_addr.s_addr); nm_log_info (LOGD_DHCP4, " prefix %d (%s)", prefix, str); } else { /* Get default netmask for the IP according to appropriate class. */ prefix = nm_utils_ip4_get_default_prefix (nm_ip4_address_get_address (addr)); nm_log_info (LOGD_DHCP4, " prefix %d (default)", prefix); } nm_ip4_address_set_prefix (addr, prefix); /* Routes: if the server returns classless static routes, we MUST ignore * the 'static_routes' option. */ if (!ip4_process_classless_routes (priv->options, ip4_config, &gwaddr)) process_classful_routes (priv->options, ip4_config); if (gwaddr) { char buf[INET_ADDRSTRLEN + 1]; inet_ntop (AF_INET, &gwaddr, buf, sizeof (buf)); nm_log_info (LOGD_DHCP4, " gateway %s", buf); nm_ip4_address_set_gateway (addr, gwaddr); } else { /* If the gateway wasn't provided as a classless static route with a * subnet length of 0, try to find it using the old-style 'routers' option. */ str = g_hash_table_lookup (priv->options, "new_routers"); if (str) { char **routers = g_strsplit (str, " ", 0); char **s; for (s = routers; *s; s++) { /* FIXME: how to handle multiple routers? */ if (inet_pton (AF_INET, *s, &tmp_addr) > 0) { nm_ip4_address_set_gateway (addr, tmp_addr.s_addr); nm_log_info (LOGD_DHCP4, " gateway %s", *s); break; } else nm_log_warn (LOGD_DHCP4, "ignoring invalid gateway '%s'", *s); } g_strfreev (routers); } } nm_ip4_config_take_address (ip4_config, addr); addr = NULL; str = g_hash_table_lookup (priv->options, "new_host_name"); if (str) nm_log_info (LOGD_DHCP4, " hostname '%s'", str); str = g_hash_table_lookup (priv->options, "new_domain_name_servers"); if (str) { char **searches = g_strsplit (str, " ", 0); char **s; for (s = searches; *s; s++) { if (inet_pton (AF_INET, *s, &tmp_addr) > 0) { nm_ip4_config_add_nameserver (ip4_config, tmp_addr.s_addr); nm_log_info (LOGD_DHCP4, " nameserver '%s'", *s); } else nm_log_warn (LOGD_DHCP4, "ignoring invalid nameserver '%s'", *s); } g_strfreev (searches); } str = g_hash_table_lookup (priv->options, "new_domain_name"); if (str) { char **domains = g_strsplit (str, " ", 0); char **s; for (s = domains; *s; s++) { nm_log_info (LOGD_DHCP4, " domain name '%s'", *s); nm_ip4_config_add_domain (ip4_config, *s); } g_strfreev (domains); } str = g_hash_table_lookup (priv->options, "new_domain_search"); if (str) process_domain_search (str, ip4_add_domain_search, ip4_config); str = g_hash_table_lookup (priv->options, "new_netbios_name_servers"); if (str) { char **searches = g_strsplit (str, " ", 0); char **s; for (s = searches; *s; s++) { if (inet_pton (AF_INET, *s, &tmp_addr) > 0) { nm_ip4_config_add_wins (ip4_config, tmp_addr.s_addr); nm_log_info (LOGD_DHCP4, " wins '%s'", *s); } else nm_log_warn (LOGD_DHCP4, "ignoring invalid WINS server '%s'", *s); } g_strfreev (searches); } str = g_hash_table_lookup (priv->options, "new_interface_mtu"); if (str) { int int_mtu; errno = 0; int_mtu = strtol (str, NULL, 10); if ((errno == EINVAL) || (errno == ERANGE)) goto error; if (int_mtu > 576) nm_ip4_config_set_mtu (ip4_config, int_mtu); } str = g_hash_table_lookup (priv->options, "new_nis_domain"); if (str) { nm_log_info (LOGD_DHCP4, " NIS domain '%s'", str); nm_ip4_config_set_nis_domain (ip4_config, str); } str = g_hash_table_lookup (priv->options, "new_nis_servers"); if (str) { char **searches = g_strsplit (str, " ", 0); char **s; for (s = searches; *s; s++) { if (inet_pton (AF_INET, *s, &tmp_addr) > 0) { nm_ip4_config_add_nis_server (ip4_config, tmp_addr.s_addr); nm_log_info (LOGD_DHCP4, " nis '%s'", *s); } else nm_log_warn (LOGD_DHCP4, "ignoring invalid NIS server '%s'", *s); } g_strfreev (searches); } return ip4_config; error: if (addr) nm_ip4_address_unref (addr); g_object_unref (ip4_config); return NULL; }
/* Given a table of DHCP options from the client, convert into an IP6Config */ static NMIP6Config * ip6_options_to_config (NMDHCPClient *self) { NMDHCPClientPrivate *priv; NMIP6Config *ip6_config = NULL; struct in6_addr tmp_addr; NMIP6Address *addr = NULL; char *str = NULL; GHashTableIter iter; gpointer key, value; g_return_val_if_fail (self != NULL, NULL); g_return_val_if_fail (NM_IS_DHCP_CLIENT (self), NULL); priv = NM_DHCP_CLIENT_GET_PRIVATE (self); g_return_val_if_fail (priv->options != NULL, NULL); g_hash_table_iter_init (&iter, priv->options); while (g_hash_table_iter_next (&iter, &key, &value)) { nm_log_dbg (LOGD_DHCP6, "(%s): option '%s'=>'%s'", priv->iface, (const char *) key, (const char *) value); } ip6_config = nm_ip6_config_new (); if (!ip6_config) { nm_log_warn (LOGD_DHCP6, "(%s): couldn't allocate memory for an IP6Config!", priv->iface); return NULL; } addr = nm_ip6_address_new (); if (!addr) { nm_log_warn (LOGD_DHCP6, "(%s): couldn't allocate memory for an IP6 Address!", priv->iface); goto error; } str = g_hash_table_lookup (priv->options, "new_ip6_address"); if (str) { if (!inet_pton (AF_INET6, str, &tmp_addr)) { nm_log_warn (LOGD_DHCP6, "(%s): DHCP returned invalid address '%s'", priv->iface); goto error; } nm_ip6_address_set_address (addr, &tmp_addr); nm_log_info (LOGD_DHCP6, " address %s", str); } else { /* No address in managed mode is a hard error */ if (priv->info_only == FALSE) goto error; /* But "info-only" setups don't necessarily need an address */ nm_ip6_address_unref (addr); addr = NULL; } /* Only care about prefix if we got an address */ if (addr) { str = g_hash_table_lookup (priv->options, "new_ip6_prefixlen"); if (str) { long unsigned int prefix; errno = 0; prefix = strtoul (str, NULL, 10); if (errno != 0 || prefix > 128) goto error; nm_ip6_address_set_prefix (addr, (guint32) prefix); nm_log_info (LOGD_DHCP6, " prefix %lu", prefix); } nm_ip6_config_take_address (ip6_config, addr); addr = NULL; } str = g_hash_table_lookup (priv->options, "new_host_name"); if (str) nm_log_info (LOGD_DHCP6, " hostname '%s'", str); str = g_hash_table_lookup (priv->options, "new_dhcp6_name_servers"); if (str) { char **searches = g_strsplit (str, " ", 0); char **s; for (s = searches; *s; s++) { if (inet_pton (AF_INET6, *s, &tmp_addr) > 0) { nm_ip6_config_add_nameserver (ip6_config, &tmp_addr); nm_log_info (LOGD_DHCP6, " nameserver '%s'", *s); } else nm_log_warn (LOGD_DHCP6, "ignoring invalid nameserver '%s'", *s); } g_strfreev (searches); } str = g_hash_table_lookup (priv->options, "new_dhcp6_domain_search"); if (str) process_domain_search (str, ip6_add_domain_search, ip6_config); return ip6_config; error: if (addr) nm_ip6_address_unref (addr); g_object_unref (ip6_config); return NULL; }
/* Given a table of DHCP options from the client, convert into an IP6Config */ static NMIP6Config * ip6_options_to_config (NMDHCPClient *self) { NMDHCPClientPrivate *priv; NMIP6Config *ip6_config = NULL; struct in6_addr tmp_addr; NMIP6Address *addr = NULL; char *str = NULL; GHashTableIter iter; gpointer key, value; g_return_val_if_fail (self != NULL, NULL); g_return_val_if_fail (NM_IS_DHCP_CLIENT (self), NULL); priv = NM_DHCP_CLIENT_GET_PRIVATE (self); g_return_val_if_fail (priv->options != NULL, NULL); g_hash_table_iter_init (&iter, priv->options); while (g_hash_table_iter_next (&iter, &key, &value)) { nm_log_dbg (LOGD_DHCP6, "(%s): option '%s'=>'%s'", priv->iface, (const char *) key, (const char *) value); } ip6_config = nm_ip6_config_new (); if (!ip6_config) { nm_log_warn (LOGD_DHCP6, "(%s): couldn't allocate memory for an IP6Config!", priv->iface); return NULL; } str = g_hash_table_lookup (priv->options, "new_ip6_address"); if (str) { if (!inet_pton (AF_INET6, str, &tmp_addr)) { nm_log_warn (LOGD_DHCP6, "(%s): DHCP returned invalid address '%s'", priv->iface, str); goto error; } addr = nm_ip6_address_new (); g_assert (addr); nm_ip6_address_set_address (addr, &tmp_addr); /* DHCPv6 IA_NA assignments are single address only */ nm_ip6_address_set_prefix (addr, 128); nm_log_info (LOGD_DHCP6, " address %s/128", str); nm_ip6_config_take_address (ip6_config, addr); } else if (priv->info_only == FALSE) { /* No address in Managed mode is a hard error */ goto error; } str = g_hash_table_lookup (priv->options, "new_host_name"); if (str) nm_log_info (LOGD_DHCP6, " hostname '%s'", str); str = g_hash_table_lookup (priv->options, "new_dhcp6_name_servers"); if (str) { char **searches = g_strsplit (str, " ", 0); char **s; for (s = searches; *s; s++) { if (inet_pton (AF_INET6, *s, &tmp_addr) > 0) { nm_ip6_config_add_nameserver (ip6_config, &tmp_addr); nm_log_info (LOGD_DHCP6, " nameserver '%s'", *s); } else nm_log_warn (LOGD_DHCP6, "ignoring invalid nameserver '%s'", *s); } g_strfreev (searches); } str = g_hash_table_lookup (priv->options, "new_dhcp6_domain_search"); if (str) process_domain_search (str, ip6_add_domain_search, ip6_config); return ip6_config; error: g_object_unref (ip6_config); return NULL; }