diff options
Diffstat (limited to 'src/core/dhcp/nm-dhcp-client.c')
-rw-r--r-- | src/core/dhcp/nm-dhcp-client.c | 1087 |
1 files changed, 382 insertions, 705 deletions
diff --git a/src/core/dhcp/nm-dhcp-client.c b/src/core/dhcp/nm-dhcp-client.c index f88c79c0be..6f71a44501 100644 --- a/src/core/dhcp/nm-dhcp-client.c +++ b/src/core/dhcp/nm-dhcp-client.c @@ -20,9 +20,13 @@ #include "NetworkManagerUtils.h" #include "nm-utils.h" +#include "nm-l3cfg.h" +#include "nm-l3-config-data.h" #include "nm-dhcp-utils.h" #include "nm-dhcp-options.h" #include "libnm-platform/nm-platform.h" +#include "nm-hostname-manager.h" +#include "libnm-systemd-shared/nm-sd-utils-shared.h" #include "nm-dhcp-client-logging.h" @@ -32,53 +36,19 @@ enum { SIGNAL_NOTIFY, LAST_SIGNAL }; static guint signals[LAST_SIGNAL] = {0}; -NM_GOBJECT_PROPERTIES_DEFINE(NMDhcpClient, - PROP_ADDR_FAMILY, - PROP_ANYCAST_ADDRESS, - PROP_FLAGS, - PROP_HWADDR, - PROP_BROADCAST_HWADDR, - PROP_IFACE, - PROP_IFINDEX, - PROP_MULTI_IDX, - PROP_ROUTE_METRIC, - PROP_ROUTE_TABLE, - PROP_TIMEOUT, - PROP_UUID, - PROP_IAID, - PROP_IAID_EXPLICIT, - PROP_HOSTNAME, - PROP_HOSTNAME_FLAGS, - PROP_MUD_URL, - PROP_VENDOR_CLASS_IDENTIFIER, - PROP_REJECT_SERVERS, ); +NM_GOBJECT_PROPERTIES_DEFINE(NMDhcpClient, PROP_CONFIG, ); typedef struct _NMDhcpClientPrivate { - NMDedupMultiIndex * multi_idx; - char * iface; - GBytes * hwaddr; - GBytes * bcast_hwaddr; - char * uuid; - GBytes * client_id; - char * hostname; - const char ** reject_servers; - char * mud_url; - char * anycast_address; - GBytes * vendor_class_identifier; - pid_t pid; - guint timeout_id; - guint watch_id; - int addr_family; - int ifindex; - guint32 route_table; - guint32 route_metric; - guint32 timeout; - guint32 iaid; - NMDhcpState state; - NMDhcpHostnameFlags hostname_flags; - NMDhcpClientFlags client_flags; - bool iaid_explicit : 1; - bool is_stopped : 1; + NMDhcpClientConfig config; + const NML3ConfigData *l3cd; + GSource * no_lease_timeout_source; + pid_t pid; + guint timeout_id; + guint watch_id; + NMDhcpState state; + bool iaid_explicit : 1; + bool is_stopped : 1; + GBytes * effective_client_id; } NMDhcpClientPrivate; G_DEFINE_ABSTRACT_TYPE(NMDhcpClient, nm_dhcp_client, G_TYPE_OBJECT) @@ -98,25 +68,6 @@ _emit_notify(NMDhcpClient *self, const NMDhcpClientNotifyData *notify_data) g_signal_emit(G_OBJECT(self), signals[SIGNAL_NOTIFY], 0, notify_data); } -static void -_emit_notify_state_changed(NMDhcpClient *self, - NMDhcpState dhcp_state, - NMIPConfig * ip_config, - GHashTable * options) -{ - const NMDhcpClientNotifyData notify_data = { - .notify_type = NM_DHCP_CLIENT_NOTIFY_TYPE_STATE_CHANGED, - .state_changed = - { - .dhcp_state = dhcp_state, - .ip_config = ip_config, - .options = options, - }, - }; - - _emit_notify(self, ¬ify_data); -} - /*****************************************************************************/ pid_t @@ -127,149 +78,24 @@ nm_dhcp_client_get_pid(NMDhcpClient *self) return NM_DHCP_CLIENT_GET_PRIVATE(self)->pid; } -NMDedupMultiIndex * -nm_dhcp_client_get_multi_idx(NMDhcpClient *self) -{ - g_return_val_if_fail(NM_IS_DHCP_CLIENT(self), NULL); - - return NM_DHCP_CLIENT_GET_PRIVATE(self)->multi_idx; -} - -const char * -nm_dhcp_client_get_iface(NMDhcpClient *self) -{ - g_return_val_if_fail(NM_IS_DHCP_CLIENT(self), NULL); - - return NM_DHCP_CLIENT_GET_PRIVATE(self)->iface; -} - -int -nm_dhcp_client_get_ifindex(NMDhcpClient *self) -{ - g_return_val_if_fail(NM_IS_DHCP_CLIENT(self), -1); - - return NM_DHCP_CLIENT_GET_PRIVATE(self)->ifindex; -} - -int -nm_dhcp_client_get_addr_family(NMDhcpClient *self) -{ - g_return_val_if_fail(NM_IS_DHCP_CLIENT(self), AF_UNSPEC); - - return NM_DHCP_CLIENT_GET_PRIVATE(self)->addr_family; -} - -const char * -nm_dhcp_client_get_uuid(NMDhcpClient *self) -{ - g_return_val_if_fail(NM_IS_DHCP_CLIENT(self), NULL); - - return NM_DHCP_CLIENT_GET_PRIVATE(self)->uuid; -} - -GBytes * -nm_dhcp_client_get_hw_addr(NMDhcpClient *self) -{ - g_return_val_if_fail(NM_IS_DHCP_CLIENT(self), NULL); - - return NM_DHCP_CLIENT_GET_PRIVATE(self)->hwaddr; -} - -GBytes * -nm_dhcp_client_get_broadcast_hw_addr(NMDhcpClient *self) -{ - g_return_val_if_fail(NM_IS_DHCP_CLIENT(self), NULL); - - return NM_DHCP_CLIENT_GET_PRIVATE(self)->bcast_hwaddr; -} - -guint32 -nm_dhcp_client_get_route_table(NMDhcpClient *self) -{ - g_return_val_if_fail(NM_IS_DHCP_CLIENT(self), RT_TABLE_MAIN); - - return NM_DHCP_CLIENT_GET_PRIVATE(self)->route_table; -} - -void -nm_dhcp_client_set_route_table(NMDhcpClient *self, guint32 route_table) -{ - NMDhcpClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE(self); - - if (route_table != priv->route_table) { - priv->route_table = route_table; - _notify(self, PROP_ROUTE_TABLE); - } -} - -guint32 -nm_dhcp_client_get_route_metric(NMDhcpClient *self) -{ - g_return_val_if_fail(NM_IS_DHCP_CLIENT(self), G_MAXUINT32); - - return NM_DHCP_CLIENT_GET_PRIVATE(self)->route_metric; -} - -void -nm_dhcp_client_set_route_metric(NMDhcpClient *self, guint32 route_metric) -{ - NMDhcpClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE(self); - - if (route_metric != priv->route_metric) { - priv->route_metric = route_metric; - _notify(self, PROP_ROUTE_METRIC); - } -} - -guint32 -nm_dhcp_client_get_timeout(NMDhcpClient *self) -{ - g_return_val_if_fail(NM_IS_DHCP_CLIENT(self), 0); - - return NM_DHCP_CLIENT_GET_PRIVATE(self)->timeout; -} - -guint32 -nm_dhcp_client_get_iaid(NMDhcpClient *self) -{ - g_return_val_if_fail(NM_IS_DHCP_CLIENT(self), 0); - - return NM_DHCP_CLIENT_GET_PRIVATE(self)->iaid; -} - -gboolean -nm_dhcp_client_get_iaid_explicit(NMDhcpClient *self) -{ - g_return_val_if_fail(NM_IS_DHCP_CLIENT(self), FALSE); - - return NM_DHCP_CLIENT_GET_PRIVATE(self)->iaid_explicit; -} - -GBytes * -nm_dhcp_client_get_client_id(NMDhcpClient *self) -{ - g_return_val_if_fail(NM_IS_DHCP_CLIENT(self), NULL); - - return NM_DHCP_CLIENT_GET_PRIVATE(self)->client_id; -} - static void -_set_client_id(NMDhcpClient *self, GBytes *client_id, gboolean take) +_set_effective_client_id(NMDhcpClient *self, GBytes *client_id, gboolean take) { NMDhcpClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE(self); nm_assert(!client_id || g_bytes_get_size(client_id) >= 2); - if (priv->client_id == client_id - || (priv->client_id && client_id && g_bytes_equal(priv->client_id, client_id))) { + if (priv->effective_client_id == client_id + || (priv->effective_client_id && client_id + && g_bytes_equal(priv->effective_client_id, client_id))) { if (take && client_id) g_bytes_unref(client_id); return; } - if (priv->client_id) - g_bytes_unref(priv->client_id); - priv->client_id = client_id; + if (priv->effective_client_id) + g_bytes_unref(priv->effective_client_id); + priv->effective_client_id = client_id; if (!take && client_id) g_bytes_ref(client_id); @@ -277,94 +103,20 @@ _set_client_id(NMDhcpClient *self, GBytes *client_id, gboolean take) gs_free char *s = NULL; _LOGT("%s: set %s", - nm_dhcp_client_get_addr_family(self) == AF_INET6 ? "duid" : "client-id", - priv->client_id ? (s = nm_dhcp_utils_duid_to_string(priv->client_id)) : "default"); + priv->config.addr_family == AF_INET6 ? "duid" : "client-id", + priv->effective_client_id + ? (s = nm_dhcp_utils_duid_to_string(priv->effective_client_id)) + : "default"); } } void -nm_dhcp_client_set_client_id(NMDhcpClient *self, GBytes *client_id) +nm_dhcp_client_set_effective_client_id(NMDhcpClient *self, GBytes *client_id) { g_return_if_fail(NM_IS_DHCP_CLIENT(self)); g_return_if_fail(!client_id || g_bytes_get_size(client_id) >= 2); - _set_client_id(self, client_id, FALSE); -} - -void -nm_dhcp_client_set_client_id_bin(NMDhcpClient *self, - guint8 type, - const guint8 *client_id, - gsize len) -{ - guint8 *buf; - GBytes *b; - - g_return_if_fail(NM_IS_DHCP_CLIENT(self)); - g_return_if_fail(client_id); - g_return_if_fail(len > 0); - - buf = g_malloc(len + 1); - buf[0] = type; - memcpy(buf + 1, client_id, len); - b = g_bytes_new_take(buf, len + 1); - _set_client_id(self, b, TRUE); -} - -const char * -nm_dhcp_client_get_anycast_address(NMDhcpClient *self) -{ - g_return_val_if_fail(NM_IS_DHCP_CLIENT(self), NULL); - - return NM_DHCP_CLIENT_GET_PRIVATE(self)->anycast_address; -} - -const char * -nm_dhcp_client_get_hostname(NMDhcpClient *self) -{ - g_return_val_if_fail(NM_IS_DHCP_CLIENT(self), NULL); - - return NM_DHCP_CLIENT_GET_PRIVATE(self)->hostname; -} - -NMDhcpHostnameFlags -nm_dhcp_client_get_hostname_flags(NMDhcpClient *self) -{ - g_return_val_if_fail(NM_IS_DHCP_CLIENT(self), NM_DHCP_HOSTNAME_FLAG_NONE); - - return NM_DHCP_CLIENT_GET_PRIVATE(self)->hostname_flags; -} - -NMDhcpClientFlags -nm_dhcp_client_get_client_flags(NMDhcpClient *self) -{ - g_return_val_if_fail(NM_IS_DHCP_CLIENT(self), NM_DHCP_CLIENT_FLAGS_NONE); - - return NM_DHCP_CLIENT_GET_PRIVATE(self)->client_flags; -} - -const char * -nm_dhcp_client_get_mud_url(NMDhcpClient *self) -{ - g_return_val_if_fail(NM_IS_DHCP_CLIENT(self), NULL); - - return NM_DHCP_CLIENT_GET_PRIVATE(self)->mud_url; -} - -GBytes * -nm_dhcp_client_get_vendor_class_identifier(NMDhcpClient *self) -{ - g_return_val_if_fail(NM_IS_DHCP_CLIENT(self), NULL); - - return NM_DHCP_CLIENT_GET_PRIVATE(self)->vendor_class_identifier; -} - -const char *const * -nm_dhcp_client_get_reject_servers(NMDhcpClient *self) -{ - g_return_val_if_fail(NM_IS_DHCP_CLIENT(self), NULL); - - return (const char *const *) NM_DHCP_CLIENT_GET_PRIVATE(self)->reject_servers; + _set_effective_client_id(self, client_id, FALSE); } /*****************************************************************************/ @@ -457,78 +209,159 @@ stop(NMDhcpClient *self, gboolean release) if (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); + nm_dhcp_client_stop_pid(priv->pid, priv->config.iface); } priv->pid = -1; } -void -nm_dhcp_client_set_state(NMDhcpClient *self, - NMDhcpState new_state, - NMIPConfig * ip_config, - GHashTable * options) +static gboolean +_no_lease_timeout(gpointer user_data) { + NMDhcpClient * self = user_data; NMDhcpClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE(self); + nm_clear_g_source_inst(&priv->no_lease_timeout_source); + + _emit_notify(self, + &((NMDhcpClientNotifyData){ + .notify_type = NM_DHCP_CLIENT_NOTIFY_TYPE_NO_LEASE_TIMEOUT, + })); + return G_SOURCE_CONTINUE; +} + +const NMDhcpClientConfig * +nm_dhcp_client_get_config(NMDhcpClient *self) +{ + NMDhcpClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE(self); + + return &priv->config; +} + +void +nm_dhcp_client_set_state(NMDhcpClient *self, NMDhcpState new_state, const NML3ConfigData *l3cd) +{ + NMDhcpClientPrivate * priv = NM_DHCP_CLIENT_GET_PRIVATE(self); + GHashTable * options; + const int IS_IPv4 = NM_IS_IPv4(priv->config.addr_family); + nm_auto_unref_l3cd const NML3ConfigData *l3cd_merged = NULL; + + g_return_if_fail(NM_IS_DHCP_CLIENT(self)); + if (NM_IN_SET(new_state, NM_DHCP_STATE_BOUND, NM_DHCP_STATE_EXTENDED)) { - g_return_if_fail(NM_IS_IP_CONFIG_ADDR_FAMILY(ip_config, priv->addr_family)); - g_return_if_fail(options); - } else { - g_return_if_fail(!ip_config); - g_return_if_fail(!options); - } + g_return_if_fail(NM_IS_L3_CONFIG_DATA(l3cd)); + g_return_if_fail(nm_l3_config_data_get_dhcp_lease(l3cd, priv->config.addr_family)); + } else + g_return_if_fail(!l3cd); + + if (l3cd) + nm_l3_config_data_seal(l3cd); if (new_state >= NM_DHCP_STATE_BOUND) timeout_cleanup(self); if (new_state >= NM_DHCP_STATE_TIMEOUT) watch_cleanup(self); - /* The client may send same-state transitions for RENEW/REBIND events and - * the lease may have changed, so handle same-state transitions for the - * EXTENDED and BOUND states. Ignore same-state transitions for other - * events since the lease won't have changed and the state was already handled. - */ - if ((priv->state == new_state) - && !NM_IN_SET(new_state, NM_DHCP_STATE_BOUND, NM_DHCP_STATE_EXTENDED)) - return; + if (!IS_IPv4 && l3cd) { + if (nm_dhcp_utils_merge_new_dhcp6_lease(priv->l3cd, l3cd, &l3cd_merged)) { + l3cd = nm_l3_config_data_seal(l3cd_merged); + } + } - if (_LOGD_ENABLED()) { - gs_free const char **keys = NULL; - guint i, nkeys; + if (priv->l3cd == l3cd) + return; - keys = nm_strdict_get_keys(options, TRUE, &nkeys); - for (i = 0; i < nkeys; i++) { - _LOGD("option %-20s => '%s'", keys[i], (char *) g_hash_table_lookup(options, keys[i])); + if (l3cd) + nm_clear_g_source_inst(&priv->no_lease_timeout_source); + else { + /* FIXME(l3cfg:dhcp): we also need to start no_lease_timeout initially, if the + * instance starts without a previous_lease. */ + if (!priv->no_lease_timeout_source && priv->l3cd) { + if (priv->config.timeout == NM_DHCP_TIMEOUT_INFINITY) + priv->no_lease_timeout_source = g_source_ref(nm_g_source_sentinel_get(0)); + else { + priv->no_lease_timeout_source = + nm_g_timeout_add_source_seconds(priv->config.timeout, _no_lease_timeout, self); + } } } - if (_LOGT_ENABLED() && priv->addr_family == AF_INET6) { - gs_free char *event_id = NULL; + /* FIXME(l3cfg:dhcp): the API of NMDhcpClient is changing to expose a simpler API. + * The internals like NMDhcpState should not be exposed (or possibly dropped in large + * parts). */ + + nm_l3_config_data_reset(&priv->l3cd, l3cd); + + options = l3cd ? nm_dhcp_lease_get_options( + nm_l3_config_data_get_dhcp_lease(l3cd, priv->config.addr_family)) + : NULL; + + if (_LOGD_ENABLED()) { + if (options) { + gs_free const char **keys = NULL; + guint nkeys; + guint i; + + keys = nm_strdict_get_keys(options, TRUE, &nkeys); + for (i = 0; i < nkeys; i++) { + _LOGD("option %-20s => '%s'", + keys[i], + (char *) g_hash_table_lookup(options, keys[i])); + } + + if (priv->config.addr_family == AF_INET6) { + gs_free char *event_id = NULL; - event_id = nm_dhcp_utils_get_dhcp6_event_id(options); - if (event_id) - _LOGT("event-id: \"%s\"", event_id); + event_id = nm_dhcp_utils_get_dhcp6_event_id(options); + if (event_id) + _LOGT("event-id: \"%s\"", event_id); + } + } } if (_LOGI_ENABLED()) { const char *req_str = - NM_IS_IPv4(priv->addr_family) - ? nm_dhcp_option_request_string(AF_INET, NM_DHCP_OPTION_DHCP4_NM_IP_ADDRESS) - : nm_dhcp_option_request_string(AF_INET6, NM_DHCP_OPTION_DHCP6_NM_IP_ADDRESS); + IS_IPv4 ? nm_dhcp_option_request_string(AF_INET, NM_DHCP_OPTION_DHCP4_NM_IP_ADDRESS) + : nm_dhcp_option_request_string(AF_INET6, NM_DHCP_OPTION_DHCP6_NM_IP_ADDRESS); const char *addr = nm_g_hash_table_lookup(options, req_str); - _LOGI("state changed %s -> %s%s%s%s", - nm_dhcp_state_to_string(priv->state), - nm_dhcp_state_to_string(new_state), + _LOGI("state changed %s%s%s%s", + priv->l3cd ? "new lease" : "no lease", NM_PRINT_FMT_QUOTED(addr, ", address=", addr, "", "")); } - priv->state = new_state; + /* FIXME(l3cfg:dhcp:acd): NMDhcpClient must also do ACD. It needs acd_timeout_msec + * as a configuration parameter (in NMDhcpClientConfig). When ACD is enabled, + * when a new lease gets announced, it must first use NML3Cfg to run ACD on the + * interface (the previous lease -- if any -- will still be used at that point). + * If ACD fails, we call nm_dhcp_client_decline() and try to get a different + * lease. + * If ACD passes, we need to notify the new lease, and the user (NMDevice) may + * then configure the address. We need to watch the configured addresses (in NML3Cfg), + * and if the address appears there, we need to accept the lease. That is complicated + * but necessary, because we can only accept the lease after we configured the + * address. + * + * As a whole, ACD is transparent for the user (NMDevice). It's entirely managed + * by NMDhcpClient. Note that we do ACD through NML3Cfg, which centralizes IP handling + * for one interface, so for example if the same address happens to be configured + * as a static address (bypassing ACD), then NML3Cfg is aware of that and signals + * immediate success. */ - _emit_notify_state_changed(self, new_state, ip_config, options); + { + const NMDhcpClientNotifyData notify_data = { + .notify_type = NM_DHCP_CLIENT_NOTIFY_TYPE_LEASE_UPDATE, + .lease_update = + { + .l3cd = priv->l3cd, + }, + }; + + _emit_notify(self, ¬ify_data); + } } -static gboolean +/* FIXME(l3cfg:dhcp) */ +_nm_unused static gboolean transaction_timeout(gpointer user_data) { NMDhcpClient * self = NM_DHCP_CLIENT(user_data); @@ -536,7 +369,7 @@ transaction_timeout(gpointer user_data) priv->timeout_id = 0; _LOGW("request timed out"); - nm_dhcp_client_set_state(self, NM_DHCP_STATE_TIMEOUT, NULL, NULL); + nm_dhcp_client_set_state(self, NM_DHCP_STATE_TIMEOUT, NULL); return G_SOURCE_REMOVE; } @@ -554,7 +387,7 @@ daemon_watch_cb(GPid pid, int status, gpointer user_data) priv->pid = -1; - nm_dhcp_client_set_state(self, NM_DHCP_STATE_TERMINATED, NULL, NULL); + nm_dhcp_client_set_state(self, NM_DHCP_STATE_TERMINATED, NULL); } void @@ -566,10 +399,10 @@ nm_dhcp_client_start_timeout(NMDhcpClient *self) /* Set up a timeout on the transaction to kill it after the timeout */ - if (priv->timeout == NM_DHCP_TIMEOUT_INFINITY) - return; - - priv->timeout_id = g_timeout_add_seconds(priv->timeout, transaction_timeout, self); + /* FIXME(l3cfg:dhcp): no-lease-timeout is only for convenience for the user (NMDevice). + * Whatever the purpose of nm_dhcp_client_start_timeout() is, it is not the same timer. */ + return; + //priv->timeout_id = g_timeout_add_seconds(priv->no_lease_timeout, transaction_timeout, self); } void @@ -599,10 +432,7 @@ nm_dhcp_client_stop_watch_child(NMDhcpClient *self, pid_t pid) } gboolean -nm_dhcp_client_start_ip4(NMDhcpClient *self, - GBytes * client_id, - const char * last_ip4_address, - GError ** error) +nm_dhcp_client_start_ip4(NMDhcpClient *self, GError **error) { NMDhcpClientPrivate *priv; @@ -610,24 +440,37 @@ nm_dhcp_client_start_ip4(NMDhcpClient *self, priv = NM_DHCP_CLIENT_GET_PRIVATE(self); g_return_val_if_fail(priv->pid == -1, FALSE); - g_return_val_if_fail(priv->addr_family == AF_INET, FALSE); - g_return_val_if_fail(priv->uuid != NULL, FALSE); - - if (priv->timeout == NM_DHCP_TIMEOUT_INFINITY) + g_return_val_if_fail(priv->config.addr_family == AF_INET, FALSE); + g_return_val_if_fail(priv->config.uuid, FALSE); + + /* FIXME(l3cfg:dhcp:ipv6ll): for IPv6, NMDhcpClient needs to wait that + * a IPv6 LL address appears. The user (NMDevice) will start the generation + * of a LL address, but NMDhcpClient is already running and is just waiting. + * + * All the while, NM_DHCP_CLIENT_NO_LEASE_TIMEOUT is ticking. If the LL address + * does not appear in (e.g. 5 seconds), a NM_DHCP_CLIENT_NOTIFY_TYPE_IT_LOOKS_BAD signal + * can be emitted. */ + + if (priv->config.timeout == NM_DHCP_TIMEOUT_INFINITY) _LOGI("activation: beginning transaction (no timeout)"); else - _LOGI("activation: beginning transaction (timeout in %u seconds)", (guint) priv->timeout); + _LOGI("activation: beginning transaction (timeout in %u seconds)", + (guint) priv->config.timeout); - nm_dhcp_client_set_client_id(self, client_id); - - return NM_DHCP_CLIENT_GET_CLASS(self)->ip4_start(self, last_ip4_address, error); + return NM_DHCP_CLIENT_GET_CLASS(self)->ip4_start(self, error); } gboolean nm_dhcp_client_accept(NMDhcpClient *self, GError **error) { + NMDhcpClientPrivate *priv; + g_return_val_if_fail(NM_IS_DHCP_CLIENT(self), FALSE); + priv = NM_DHCP_CLIENT_GET_PRIVATE(self); + + g_return_val_if_fail(priv->l3cd, FALSE); + if (NM_DHCP_CLIENT_GET_CLASS(self)->accept) { return NM_DHCP_CLIENT_GET_CLASS(self)->accept(self, error); } @@ -652,8 +495,14 @@ nm_dhcp_client_can_accept(NMDhcpClient *self) gboolean nm_dhcp_client_decline(NMDhcpClient *self, const char *error_message, GError **error) { + NMDhcpClientPrivate *priv; + g_return_val_if_fail(NM_IS_DHCP_CLIENT(self), FALSE); + priv = NM_DHCP_CLIENT_GET_PRIVATE(self); + + g_return_val_if_fail(priv->l3cd, FALSE); + if (NM_DHCP_CLIENT_GET_CLASS(self)->decline) { return NM_DHCP_CLIENT_GET_CLASS(self)->decline(self, error_message, error); } @@ -668,42 +517,31 @@ get_duid(NMDhcpClient *self) } gboolean -nm_dhcp_client_start_ip6(NMDhcpClient * self, - GBytes * client_id, - gboolean enforce_duid, - const struct in6_addr * ll_addr, - NMSettingIP6ConfigPrivacy privacy, - guint needed_prefixes, - GError ** error) +nm_dhcp_client_start_ip6(NMDhcpClient *self, GError **error) { NMDhcpClientPrivate *priv; gs_unref_bytes GBytes *own_client_id = NULL; g_return_val_if_fail(NM_IS_DHCP_CLIENT(self), FALSE); - g_return_val_if_fail(client_id, FALSE); - priv = NM_DHCP_CLIENT_GET_PRIVATE(self); g_return_val_if_fail(priv->pid == -1, FALSE); - g_return_val_if_fail(priv->addr_family == AF_INET6, FALSE); - g_return_val_if_fail(priv->uuid != NULL, FALSE); - g_return_val_if_fail(!priv->client_id, FALSE); + g_return_val_if_fail(priv->config.addr_family == AF_INET6, FALSE); + g_return_val_if_fail(priv->config.uuid, FALSE); + g_return_val_if_fail(!priv->effective_client_id, FALSE); - if (!enforce_duid) + if (!priv->config.v6.enforce_duid) own_client_id = NM_DHCP_CLIENT_GET_CLASS(self)->get_duid(self); - _set_client_id(self, own_client_id ?: client_id, FALSE); + _set_effective_client_id(self, own_client_id ?: priv->config.client_id, FALSE); - if (priv->timeout == NM_DHCP_TIMEOUT_INFINITY) + if (priv->config.timeout == NM_DHCP_TIMEOUT_INFINITY) _LOGI("activation: beginning transaction (no timeout)"); else - _LOGI("activation: beginning transaction (timeout in %u seconds)", (guint) priv->timeout); + _LOGI("activation: beginning transaction (timeout in %u seconds)", + (guint) priv->config.timeout); - return NM_DHCP_CLIENT_GET_CLASS(self)->ip6_start(self, - ll_addr, - privacy, - needed_prefixes, - error); + return NM_DHCP_CLIENT_GET_CLASS(self)->ip6_start(self, error); } void @@ -789,7 +627,7 @@ nm_dhcp_client_stop(NMDhcpClient *self, gboolean release) _LOGI("canceled DHCP transaction"); nm_assert(priv->pid == -1); - nm_dhcp_client_set_state(self, NM_DHCP_STATE_TERMINATED, NULL, NULL); + nm_dhcp_client_set_state(self, NM_DHCP_STATE_TERMINATED, NULL); } /*****************************************************************************/ @@ -921,12 +759,10 @@ nm_dhcp_client_handle_event(gpointer unused, const char * reason, NMDhcpClient *self) { - NMDhcpClientPrivate *priv; - guint32 old_state; - guint32 new_state; - gs_unref_hashtable GHashTable *str_options = NULL; - gs_unref_object NMIPConfig *ip_config = NULL; - NMPlatformIP6Address prefix = { + NMDhcpClientPrivate * priv; + guint32 new_state; + nm_auto_unref_l3cd_init NML3ConfigData *l3cd = NULL; + NMPlatformIP6Address prefix = { 0, }; @@ -938,25 +774,26 @@ nm_dhcp_client_handle_event(gpointer unused, priv = NM_DHCP_CLIENT_GET_PRIVATE(self); - if (g_strcmp0(priv->iface, iface) != 0) + if (!nm_streq0(priv->config.iface, iface)) return FALSE; if (priv->pid != pid) return FALSE; - old_state = priv->state; - new_state = reason_to_state(self, priv->iface, reason); + new_state = reason_to_state(self, priv->config.iface, reason); + if (new_state == NM_DHCP_STATE_NOOP) + return TRUE; + _LOGD("DHCP state '%s' -> '%s' (reason: '%s')", - nm_dhcp_state_to_string(old_state), + nm_dhcp_state_to_string(priv->state), nm_dhcp_state_to_string(new_state), reason); - - if (new_state == NM_DHCP_STATE_NOOP) - return TRUE; + priv->state = new_state; if (NM_IN_SET(new_state, NM_DHCP_STATE_BOUND, NM_DHCP_STATE_EXTENDED)) { - GVariantIter iter; - const char * name; - GVariant * value; + gs_unref_hashtable GHashTable *str_options = NULL; + GVariantIter iter; + const char * name; + GVariant * value; /* Copy options */ str_options = g_hash_table_new_full(nm_str_hash, g_str_equal, g_free, g_free); @@ -968,25 +805,29 @@ nm_dhcp_client_handle_event(gpointer unused, /* Create the IP config */ if (g_hash_table_size(str_options) > 0) { - if (priv->addr_family == AF_INET) { - ip_config = NM_IP_CONFIG_CAST( - nm_dhcp_utils_ip4_config_from_options(nm_dhcp_client_get_multi_idx(self), - priv->ifindex, - priv->iface, - str_options, - priv->route_table, - priv->route_metric)); + if (priv->config.addr_family == AF_INET) { + l3cd = nm_dhcp_utils_ip4_config_from_options( + nm_l3cfg_get_multi_idx(priv->config.l3cfg), + nm_l3cfg_get_ifindex(priv->config.l3cfg), + priv->config.iface, + str_options); } else { - prefix = nm_dhcp_utils_ip6_prefix_from_options(str_options); - ip_config = NM_IP_CONFIG_CAST(nm_dhcp_utils_ip6_config_from_options( - nm_dhcp_client_get_multi_idx(self), - priv->ifindex, - priv->iface, + prefix = nm_dhcp_utils_ip6_prefix_from_options(str_options); + l3cd = nm_dhcp_utils_ip6_config_from_options( + nm_l3cfg_get_multi_idx(priv->config.l3cfg), + nm_l3cfg_get_ifindex(priv->config.l3cfg), + priv->config.iface, str_options, - NM_FLAGS_HAS(priv->client_flags, NM_DHCP_CLIENT_FLAGS_INFO_ONLY))); + priv->config.v6.info_only); } } else g_warn_if_reached(); + + if (l3cd) { + nm_l3_config_data_set_dhcp_lease_from_options(l3cd, + priv->config.addr_family, + g_steal_pointer(&str_options)); + } } if (!IN6_IS_ADDR_UNSPECIFIED(&prefix.address)) { @@ -994,17 +835,16 @@ nm_dhcp_client_handle_event(gpointer unused, * of the DHCP client instance. Instead, we just signal the prefix * to the device. */ nm_dhcp_client_emit_ipv6_prefix_delegated(self, &prefix); - } else { - /* Fail if no valid IP config was received */ - if (NM_IN_SET(new_state, NM_DHCP_STATE_BOUND, NM_DHCP_STATE_EXTENDED) && !ip_config) { - _LOGW("client bound but IP config not received"); - new_state = NM_DHCP_STATE_FAIL; - nm_clear_pointer(&str_options, g_hash_table_unref); - } + return TRUE; + } - nm_dhcp_client_set_state(self, new_state, ip_config, str_options); + /* Fail if no valid IP config was received */ + if (NM_IN_SET(new_state, NM_DHCP_STATE_BOUND, NM_DHCP_STATE_EXTENDED) && !l3cd) { + _LOGW("client bound but IP config not received"); + new_state = NM_DHCP_STATE_FAIL; } + nm_dhcp_client_set_state(self, new_state, l3cd); return TRUE; } @@ -1016,18 +856,18 @@ nm_dhcp_client_server_id_is_rejected(NMDhcpClient *self, gconstpointer addr) guint i; /* IPv6 not implemented yet */ - nm_assert(priv->addr_family == AF_INET); + nm_assert(priv->config.addr_family == AF_INET); - if (!priv->reject_servers || !priv->reject_servers[0]) + if (!priv->config.reject_servers || !priv->config.reject_servers[0]) return FALSE; - for (i = 0; priv->reject_servers[i]; i++) { + for (i = 0; priv->config.reject_servers[i]; i++) { in_addr_t r_addr; in_addr_t mask; int r_prefix; if (!nm_utils_parse_inaddr_prefix_bin(AF_INET, - priv->reject_servers[i], + priv->config.reject_servers[i], NULL, &r_addr, &r_prefix)) @@ -1040,146 +880,151 @@ nm_dhcp_client_server_id_is_rejected(NMDhcpClient *self, gconstpointer addr) return FALSE; } -/*****************************************************************************/ +static void +config_init(NMDhcpClientConfig *config, const NMDhcpClientConfig *src) +{ + *config = *src; + + g_object_ref(config->l3cfg); + + if (config->hwaddr) + g_bytes_ref(config->hwaddr); + if (config->bcast_hwaddr) + g_bytes_ref(config->bcast_hwaddr); + if (config->vendor_class_identifier) + g_bytes_ref(config->vendor_class_identifier); + if (config->client_id) + g_bytes_ref(config->client_id); + + config->iface = g_strdup(config->iface); + config->uuid = g_strdup(config->uuid); + config->anycast_address = g_strdup(config->anycast_address); + config->hostname = g_strdup(config->hostname); + config->mud_url = g_strdup(config->mud_url); + + config->reject_servers = (const char *const *) nm_strv_dup(config->reject_servers, -1, TRUE); + + if (config->addr_family == AF_INET) { + config->v4.last_address = g_strdup(config->v4.last_address); + } else if (config->addr_family == AF_INET6) { + config->v6.ll_addr = g_memdup(config->v6.ll_addr, sizeof(struct in6_addr)); + config->hwaddr = NULL; + config->bcast_hwaddr = NULL; + config->use_fqdn = TRUE; + } else { + nm_assert_not_reached(); + } + + if (!config->hostname && config->send_hostname) { + const char * hostname; + gs_free char *hostname_tmp = NULL; + + hostname = nm_hostname_manager_get_hostname(nm_hostname_manager_get()); + + if (nm_utils_is_specific_hostname(hostname)) { + if (config->addr_family == AF_INET) { + char *dot; + + hostname_tmp = g_strdup(hostname); + dot = strchr(hostname_tmp, '.'); + if (dot) + *dot = '\0'; + } + config->hostname = hostname_tmp ? g_steal_pointer(&hostname_tmp) : g_strdup(hostname); + } + } + + if (config->hostname) { + if ((config->use_fqdn && !nm_sd_dns_name_is_valid(config->hostname)) + || (!config->use_fqdn && !nm_sd_hostname_is_valid(config->hostname, FALSE))) { + nm_log_warn(LOGD_DHCP, + "dhcp%c: %s '%s' is invalid, will be ignored", + nm_utils_addr_family_to_char(config->addr_family), + config->use_fqdn ? "FQDN" : "hostname", + config->hostname); + nm_clear_g_free((gpointer *) &config->hostname); + } + } +} static void -get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) +config_clear(NMDhcpClientConfig *config) { - NMDhcpClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE(object); + g_object_unref(config->l3cfg); - switch (prop_id) { - case PROP_IFACE: - g_value_set_string(value, priv->iface); - break; - case PROP_IFINDEX: - g_value_set_int(value, priv->ifindex); - break; - case PROP_HWADDR: - g_value_set_boxed(value, priv->hwaddr); - break; - case PROP_BROADCAST_HWADDR: - g_value_set_boxed(value, priv->bcast_hwaddr); - break; - case PROP_ADDR_FAMILY: - g_value_set_int(value, priv->addr_family); - break; - case PROP_UUID: - g_value_set_string(value, priv->uuid); - break; - case PROP_IAID: - g_value_set_uint(value, priv->iaid); - break; - case PROP_IAID_EXPLICIT: - g_value_set_boolean(value, priv->iaid_explicit); - break; - case PROP_HOSTNAME: - g_value_set_string(value, priv->hostname); - break; - case PROP_ROUTE_METRIC: - g_value_set_uint(value, priv->route_metric); - break; - case PROP_ROUTE_TABLE: - g_value_set_uint(value, priv->route_table); - break; - case PROP_TIMEOUT: - g_value_set_uint(value, priv->timeout); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); - break; + nm_clear_pointer(&config->hwaddr, g_bytes_unref); + nm_clear_pointer(&config->bcast_hwaddr, g_bytes_unref); + nm_clear_pointer(&config->vendor_class_identifier, g_bytes_unref); + nm_clear_pointer(&config->client_id, g_bytes_unref); + + nm_clear_g_free((gpointer *) &config->iface); + nm_clear_g_free((gpointer *) &config->uuid); + nm_clear_g_free((gpointer *) &config->anycast_address); + nm_clear_g_free((gpointer *) &config->hostname); + nm_clear_g_free((gpointer *) &config->mud_url); + + nm_clear_pointer((gpointer *) &config->reject_servers, g_strfreev); + + if (config->addr_family == AF_INET) { + nm_clear_g_free((gpointer *) &config->v4.last_address); + } else if (config->addr_family == AF_INET6) { + nm_clear_g_free((gpointer *) &config->v6.ll_addr); + } else { + nm_assert_not_reached(); } } +int +nm_dhcp_client_get_addr_family(NMDhcpClient *self) +{ + NMDhcpClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE(self); + + return priv->config.addr_family; +} + +const char * +nm_dhcp_client_get_iface(NMDhcpClient *self) +{ + NMDhcpClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE(self); + + return priv->config.iface; +} + +NMDedupMultiIndex * +nm_dhcp_client_get_multi_idx(NMDhcpClient *self) +{ + NMDhcpClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE(self); + + return nm_l3cfg_get_multi_idx(priv->config.l3cfg); +} + +int +nm_dhcp_client_get_ifindex(NMDhcpClient *self) +{ + NMDhcpClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE(self); + + return nm_l3cfg_get_ifindex(priv->config.l3cfg); +} + +GBytes * +nm_dhcp_client_get_effective_client_id(NMDhcpClient *self) +{ + NMDhcpClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE(self); + + return priv->effective_client_id; +} + +/*****************************************************************************/ + static void set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { NMDhcpClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE(object); - guint flags; switch (prop_id) { - case PROP_FLAGS: - /* construct-only */ - flags = g_value_get_uint(value); - nm_assert(!NM_FLAGS_ANY(flags, ~((guint) NM_DHCP_CLIENT_FLAGS_ALL))); - priv->client_flags = flags; - break; - case PROP_MULTI_IDX: - /* construct-only */ - priv->multi_idx = g_value_get_pointer(value); - if (!priv->multi_idx) - g_return_if_reached(); - nm_dedup_multi_index_ref(priv->multi_idx); - break; - case PROP_IFACE: - /* construct-only */ - priv->iface = g_value_dup_string(value); - g_return_if_fail(priv->iface); - nm_assert(nm_utils_ifname_valid_kernel(priv->iface, NULL)); - break; - case PROP_IFINDEX: - /* construct-only */ - priv->ifindex = g_value_get_int(value); - g_return_if_fail(priv->ifindex > 0); - break; - case PROP_HWADDR: - /* construct-only */ - priv->hwaddr = g_value_dup_boxed(value); - break; - case PROP_ANYCAST_ADDRESS: - /* construct-only */ - priv->anycast_address = g_value_dup_string(value); - break; - case PROP_BROADCAST_HWADDR: - /* construct-only */ - priv->bcast_hwaddr = g_value_dup_boxed(value); - break; - case PROP_ADDR_FAMILY: - /* construct-only */ - priv->addr_family = g_value_get_int(value); - if (!NM_IN_SET(priv->addr_family, AF_INET, AF_INET6)) - g_return_if_reached(); - break; - case PROP_UUID: - /* construct-only */ - priv->uuid = g_value_dup_string(value); - break; - case PROP_IAID: - /* construct-only */ - priv->iaid = g_value_get_uint(value); - break; - case PROP_IAID_EXPLICIT: - /* construct-only */ - priv->iaid_explicit = g_value_get_boolean(value); - break; - case PROP_HOSTNAME: - /* construct-only */ - priv->hostname = g_value_dup_string(value); - break; - case PROP_HOSTNAME_FLAGS: - /* construct-only */ - priv->hostname_flags = g_value_get_uint(value); - break; - case PROP_MUD_URL: - /* construct-only */ - priv->mud_url = g_value_dup_string(value); - break; - case PROP_ROUTE_TABLE: - priv->route_table = g_value_get_uint(value); - break; - case PROP_ROUTE_METRIC: - priv->route_metric = g_value_get_uint(value); - break; - case PROP_TIMEOUT: - /* construct-only */ - priv->timeout = g_value_get_uint(value); - break; - case PROP_VENDOR_CLASS_IDENTIFIER: - /* construct-only */ - priv->vendor_class_identifier = g_value_dup_boxed(value); - break; - case PROP_REJECT_SERVERS: + case PROP_CONFIG: /* construct-only */ - priv->reject_servers = nm_strv_dup_packed(g_value_get_boxed(value), -1); + config_init(&priv->config, g_value_get_pointer(value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); @@ -1200,53 +1045,31 @@ nm_dhcp_client_init(NMDhcpClient *self) priv->pid = -1; } -#if NM_MORE_ASSERTS static void -constructed(GObject *object) +dispose(GObject *object) { NMDhcpClient * self = NM_DHCP_CLIENT(object); NMDhcpClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE(self); - /* certain flags only make sense with certain address family. Assert - * for that. */ - if (NM_IS_IPv4(priv->addr_family)) - nm_assert(!NM_FLAGS_ANY(priv->client_flags, NM_DHCP_CLIENT_FLAGS_INFO_ONLY)); - else { - nm_assert(NM_FLAGS_HAS(priv->client_flags, NM_DHCP_CLIENT_FLAGS_USE_FQDN)); - nm_assert(!NM_FLAGS_ANY(priv->client_flags, NM_DHCP_CLIENT_FLAGS_REQUEST_BROADCAST)); - } + nm_dhcp_client_stop(self, FALSE); - nm_assert(!priv->anycast_address || nm_utils_hwaddr_valid(priv->anycast_address, ETH_ALEN)); + watch_cleanup(self); + timeout_cleanup(self); + + nm_clear_g_source_inst(&priv->no_lease_timeout_source); - G_OBJECT_CLASS(nm_dhcp_client_parent_class)->constructed(object); + G_OBJECT_CLASS(nm_dhcp_client_parent_class)->dispose(object); } -#endif static void -dispose(GObject *object) +finalize(GObject *object) { NMDhcpClient * self = NM_DHCP_CLIENT(object); NMDhcpClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE(self); - nm_dhcp_client_stop(self, FALSE); - - watch_cleanup(self); - timeout_cleanup(self); - - nm_clear_g_free(&priv->iface); - nm_clear_g_free(&priv->hostname); - nm_clear_g_free(&priv->uuid); - nm_clear_g_free(&priv->anycast_address); - nm_clear_g_free(&priv->mud_url); - nm_clear_g_free(&priv->reject_servers); - nm_clear_pointer(&priv->client_id, g_bytes_unref); - nm_clear_pointer(&priv->hwaddr, g_bytes_unref); - nm_clear_pointer(&priv->bcast_hwaddr, g_bytes_unref); - nm_clear_pointer(&priv->vendor_class_identifier, g_bytes_unref); + config_clear(&priv->config); - G_OBJECT_CLASS(nm_dhcp_client_parent_class)->dispose(object); - - priv->multi_idx = nm_dedup_multi_index_unref(priv->multi_idx); + G_OBJECT_CLASS(nm_dhcp_client_parent_class)->finalize(object); } static void @@ -1256,165 +1079,19 @@ nm_dhcp_client_class_init(NMDhcpClientClass *client_class) g_type_class_add_private(client_class, sizeof(NMDhcpClientPrivate)); -#if NM_MORE_ASSERTS - object_class->constructed = constructed; -#endif object_class->dispose = dispose; - object_class->get_property = get_property; + object_class->finalize = finalize; object_class->set_property = set_property; client_class->stop = stop; client_class->get_duid = get_duid; - obj_properties[PROP_MULTI_IDX] = - g_param_spec_pointer(NM_DHCP_CLIENT_MULTI_IDX, + obj_properties[PROP_CONFIG] = + g_param_spec_pointer(NM_DHCP_CLIENT_CONFIG, "", "", G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); - obj_properties[PROP_IFACE] = - g_param_spec_string(NM_DHCP_CLIENT_INTERFACE, - "", - "", - NULL, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_IFINDEX] = - g_param_spec_int(NM_DHCP_CLIENT_IFINDEX, - "", - "", - -1, - G_MAXINT, - -1, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_HWADDR] = - g_param_spec_boxed(NM_DHCP_CLIENT_HWADDR, - "", - "", - G_TYPE_BYTES, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_BROADCAST_HWADDR] = - g_param_spec_boxed(NM_DHCP_CLIENT_BROADCAST_HWADDR, - "", - "", - G_TYPE_BYTES, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_ADDR_FAMILY] = - g_param_spec_int(NM_DHCP_CLIENT_ADDR_FAMILY, - "", - "", - 0, - G_MAXINT, - AF_UNSPEC, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_ANYCAST_ADDRESS] = - g_param_spec_string(NM_DHCP_CLIENT_ANYCAST_ADDRESS, - "", - "", - NULL, - G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_UUID] = - g_param_spec_string(NM_DHCP_CLIENT_UUID, - "", - "", - NULL, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_IAID] = - g_param_spec_uint(NM_DHCP_CLIENT_IAID, - "", - "", - 0, - G_MAXUINT32, - 0, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_IAID_EXPLICIT] = - g_param_spec_boolean(NM_DHCP_CLIENT_IAID_EXPLICIT, - "", - "", - FALSE, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_HOSTNAME] = - g_param_spec_string(NM_DHCP_CLIENT_HOSTNAME, - "", - "", - NULL, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_HOSTNAME_FLAGS] = - g_param_spec_uint(NM_DHCP_CLIENT_HOSTNAME_FLAGS, - "", - "", - 0, - G_MAXUINT32, - NM_DHCP_HOSTNAME_FLAG_NONE, - G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_MUD_URL] = - g_param_spec_string(NM_DHCP_CLIENT_MUD_URL, - "", - "", - NULL, - G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_ROUTE_TABLE] = - g_param_spec_uint(NM_DHCP_CLIENT_ROUTE_TABLE, - "", - "", - 0, - G_MAXUINT32, - RT_TABLE_MAIN, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_ROUTE_METRIC] = - g_param_spec_uint(NM_DHCP_CLIENT_ROUTE_METRIC, - "", - "", - 0, - G_MAXUINT32, - 0, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); - - G_STATIC_ASSERT_EXPR(G_MAXINT32 == NM_DHCP_TIMEOUT_INFINITY); - obj_properties[PROP_TIMEOUT] = - g_param_spec_uint(NM_DHCP_CLIENT_TIMEOUT, - "", - "", - 1, - G_MAXINT32, - NM_DHCP_TIMEOUT_DEFAULT, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_FLAGS] = - g_param_spec_uint(NM_DHCP_CLIENT_FLAGS, - "", - "", - 0, - G_MAXUINT32, - 0, - G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_VENDOR_CLASS_IDENTIFIER] = - g_param_spec_boxed(NM_DHCP_CLIENT_VENDOR_CLASS_IDENTIFIER, - "", - "", - G_TYPE_BYTES, - G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_REJECT_SERVERS] = - g_param_spec_boxed(NM_DHCP_CLIENT_REJECT_SERVERS, - "", - "", - G_TYPE_STRV, - G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); - g_object_class_install_properties(object_class, _PROPERTY_ENUMS_LAST, obj_properties); signals[SIGNAL_NOTIFY] = |