diff options
Diffstat (limited to 'src/core/dhcp/nm-dhcp-client.c')
| -rw-r--r-- | src/core/dhcp/nm-dhcp-client.c | 229 |
1 files changed, 127 insertions, 102 deletions
diff --git a/src/core/dhcp/nm-dhcp-client.c b/src/core/dhcp/nm-dhcp-client.c index 805b42d2..600cb930 100644 --- a/src/core/dhcp/nm-dhcp-client.c +++ b/src/core/dhcp/nm-dhcp-client.c @@ -84,6 +84,7 @@ typedef struct _NMDhcpClientPrivate { * and is set from l3cd_next. */ const NML3ConfigData *l3cd_curr; + GSource *previous_lease_timeout_source; GSource *no_lease_timeout_source; GSource *watch_source; GBytes *effective_client_id; @@ -269,6 +270,12 @@ nm_dhcp_client_create_options_dict(NMDhcpClient *self, gboolean static_keys) return options; } +const NML3ConfigData * +nm_dhcp_client_get_lease(NMDhcpClient *self) +{ + return NM_DHCP_CLIENT_GET_PRIVATE(self)->l3cd_curr; +} + /*****************************************************************************/ gboolean @@ -301,11 +308,16 @@ nm_dhcp_client_set_effective_client_id(NMDhcpClient *self, GBytes *client_id) /*****************************************************************************/ static void -_emit_notify(NMDhcpClient *self, const NMDhcpClientNotifyData *notify_data) +_emit_notify_data(NMDhcpClient *self, const NMDhcpClientNotifyData *notify_data) { g_signal_emit(G_OBJECT(self), signals[SIGNAL_NOTIFY], 0, notify_data); } +#define _emit_notify(self, _notify_type, ...) \ + _emit_notify_data( \ + (self), \ + &((const NMDhcpClientNotifyData){.notify_type = (_notify_type), __VA_ARGS__})) + /*****************************************************************************/ static void @@ -392,12 +404,7 @@ _no_lease_timeout(gpointer 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, - })); - + _emit_notify(self, NM_DHCP_CLIENT_NOTIFY_TYPE_NO_LEASE_TIMEOUT); return G_SOURCE_CONTINUE; } @@ -473,7 +480,7 @@ _acd_complete_on_idle_cb(gpointer user_data) } #define _acd_reglist_data_get(priv, idx) \ - nm_g_array_index_p((priv)->v4.acd.reglist, AcdRegListData, (idx)) + (&nm_g_array_index((priv)->v4.acd.reglist, AcdRegListData, (idx))) static guint _acd_reglist_data_find(NMDhcpClientPrivate *priv, in_addr_t addr_needle) @@ -503,10 +510,10 @@ _acd_reglist_data_remove(NMDhcpClient *self, guint idx, gboolean do_log) reglist_data = _acd_reglist_data_get(priv, idx); if (do_log) { - char sbuf_addr[NM_UTILS_INET_ADDRSTRLEN]; + char sbuf_addr[NM_INET_ADDRSTRLEN]; _LOGD("acd: drop check for address %s (l3cd " NM_HASH_OBFUSCATE_PTR_FMT ")", - _nm_utils_inet4_ntop(reglist_data->addr, sbuf_addr), + nm_inet4_ntop(reglist_data->addr, sbuf_addr), NM_HASH_OBFUSCATE_PTR(reglist_data->l3cd)); } @@ -585,7 +592,7 @@ static void _acd_check_lease(NMDhcpClient *self, NMOptionBool *out_acd_state) { NMDhcpClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE(self); - char sbuf_addr[NM_UTILS_INET_ADDRSTRLEN]; + char sbuf_addr[NM_INET_ADDRSTRLEN]; in_addr_t addr; gboolean addr_changed = FALSE; guint idx; @@ -624,7 +631,7 @@ _acd_check_lease(NMDhcpClient *self, NMOptionBool *out_acd_state) _LOGD("acd: %s check for address %s (timeout %u msec, l3cd " NM_HASH_OBFUSCATE_PTR_FMT ")", addr_changed ? "add" : "update", - _nm_utils_inet4_ntop(addr, sbuf_addr), + nm_inet4_ntop(addr, sbuf_addr), priv->config.v4.acd_timeout_msec, NM_HASH_OBFUSCATE_PTR(priv->l3cd_next)); @@ -711,7 +718,7 @@ gboolean _nm_dhcp_client_accept_offer(NMDhcpClient *self, gconstpointer p_yiaddr) { NMDhcpClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE(self); - char sbuf_addr[NM_UTILS_INET_ADDRSTRLEN]; + char sbuf_addr[NM_INET_ADDRSTRLEN]; NMIPAddr yiaddr; const NML3AcdAddrInfo *acd_info; @@ -744,7 +751,7 @@ _nm_dhcp_client_accept_offer(NMDhcpClient *self, gconstpointer p_yiaddr) return TRUE; _LOGD("offered lease rejected: address %s failed ACD check", - _nm_utils_inet4_ntop(yiaddr.addr4, sbuf_addr)); + nm_inet4_ntop(yiaddr.addr4, sbuf_addr)); return FALSE; } @@ -863,6 +870,9 @@ _nm_dhcp_client_notify(NMDhcpClient *self, return; } + if (priv->l3cd_next) + nm_clear_g_source_inst(&priv->previous_lease_timeout_source); + nm_l3_config_data_reset(&priv->l3cd_curr, priv->l3cd_next); if (client_event_type == NM_DHCP_CLIENT_EVENT_TYPE_BOUND && priv->l3cd_curr @@ -883,18 +893,12 @@ _nm_dhcp_client_notify(NMDhcpClient *self, l3_cfg_notify_check_connected(self); - { - const NMDhcpClientNotifyData notify_data = { - .notify_type = NM_DHCP_CLIENT_NOTIFY_TYPE_LEASE_UPDATE, - .lease_update = - { - .l3cd = priv->l3cd_curr, - .accepted = !priv->l3cfg_notify.wait_dhcp_commit, - }, - }; - - _emit_notify(self, ¬ify_data); - } + _emit_notify(self, + NM_DHCP_CLIENT_NOTIFY_TYPE_LEASE_UPDATE, + .lease_update = { + .l3cd = priv->l3cd_curr, + .accepted = !priv->l3cfg_notify.wait_dhcp_commit, + }); } static void @@ -1010,12 +1014,10 @@ ipv6_lladdr_timeout(gpointer user_data) nm_clear_g_source_inst(&priv->v6.lladdr_timeout_source); - _emit_notify( - self, - &((NMDhcpClientNotifyData){ - .notify_type = NM_DHCP_CLIENT_NOTIFY_TYPE_IT_LOOKS_BAD, - .it_looks_bad.reason = "timeout reached while waiting for an IPv6 link-local address", - })); + _emit_notify(self, + NM_DHCP_CLIENT_NOTIFY_TYPE_IT_LOOKS_BAD, + .it_looks_bad.reason = + "timeout reached while waiting for an IPv6 link-local address"); return G_SOURCE_CONTINUE; } @@ -1027,12 +1029,9 @@ ipv6_dad_timeout(gpointer user_data) nm_clear_g_source_inst(&priv->v6.dad_timeout_source); - _emit_notify( - self, - &((NMDhcpClientNotifyData){ - .notify_type = NM_DHCP_CLIENT_NOTIFY_TYPE_IT_LOOKS_BAD, - .it_looks_bad.reason = "timeout reached while waiting for IPv6 DAD to complete", - })); + _emit_notify(self, + NM_DHCP_CLIENT_NOTIFY_TYPE_IT_LOOKS_BAD, + .it_looks_bad.reason = "timeout reached while waiting for IPv6 DAD to complete"); return G_SOURCE_CONTINUE; } @@ -1068,35 +1067,33 @@ ipv6_lladdr_find(NMDhcpClient *self) static void ipv6_tentative_addr_check(NMDhcpClient *self, GPtrArray **tentative, - GPtrArray **missing, + GPtrArray **dadfailed, const NMPlatformIP6Address **valid) { NMDhcpClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE(self); NMDedupMultiIter iter; const NMPlatformIP6Address *addr; - NML3Cfg *l3cfg = priv->config.l3cfg; + NML3Cfg *l3cfg = priv->config.l3cfg; + NMPlatform *platform = nm_l3cfg_get_platform(l3cfg); + int ifindex = nm_l3cfg_get_ifindex(l3cfg); /* For each address in the lease, check whether it's tentative - * in platform. */ + * or dad-failed in platform. */ nm_l3_config_data_iter_ip6_address_for_each (&iter, priv->l3cd_curr, &addr) { const NMPlatformIP6Address *pladdr; - NMPObject needle; - - nmp_object_stackinit_id_ip6_address(&needle, nm_l3cfg_get_ifindex(l3cfg), &addr->address); - pladdr = NMP_OBJECT_CAST_IP6_ADDRESS(nm_platform_lookup_obj(nm_l3cfg_get_platform(l3cfg), - NMP_CACHE_ID_TYPE_OBJECT_TYPE, - &needle)); - if (!pladdr) { - /* address removed: we assume that's because DAD failed */ - if (missing) { - if (!*missing) - *missing = g_ptr_array_new(); - g_ptr_array_add(*missing, (gpointer) addr); + + pladdr = nm_platform_ip6_address_get(platform, ifindex, &addr->address); + if ((pladdr && NM_FLAGS_HAS(pladdr->n_ifa_flags, IFA_F_DADFAILED)) + || (!pladdr && nm_platform_ip6_dadfailed_check(platform, ifindex, &addr->address))) { + if (dadfailed) { + if (!*dadfailed) + *dadfailed = g_ptr_array_new(); + g_ptr_array_add(*dadfailed, (gpointer) addr); } continue; } - if (NM_FLAGS_HAS(pladdr->n_ifa_flags, IFA_F_TENTATIVE) + if (pladdr && NM_FLAGS_HAS(pladdr->n_ifa_flags, IFA_F_TENTATIVE) && !NM_FLAGS_HAS(pladdr->n_ifa_flags, IFA_F_OPTIMISTIC)) { if (tentative) { if (!*tentative) @@ -1105,6 +1102,9 @@ ipv6_tentative_addr_check(NMDhcpClient *self, } } + /* Here the address is non-tentative or it was removed externally by the user. + * In both cases it has completed DAD. + */ NM_SET_OUT(valid, addr); } } @@ -1113,7 +1113,7 @@ static void l3_cfg_notify_cb(NML3Cfg *l3cfg, const NML3ConfigNotifyData *notify_data, NMDhcpClient *self) { NMDhcpClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE(self); - char sbuf_addr[NM_UTILS_INET_ADDRSTRLEN]; + char sbuf_addr[NM_INET_ADDRSTRLEN]; nm_assert(l3cfg == priv->config.l3cfg); @@ -1133,10 +1133,8 @@ l3_cfg_notify_cb(NML3Cfg *l3cfg, const NML3ConfigNotifyData *notify_data, NMDhcp if (!NM_DHCP_CLIENT_GET_CLASS(self)->ip6_start(self, &addr->address, &error)) { _emit_notify(self, - &((NMDhcpClientNotifyData){ - .notify_type = NM_DHCP_CLIENT_NOTIFY_TYPE_IT_LOOKS_BAD, - .it_looks_bad.reason = error->message, - })); + NM_DHCP_CLIENT_NOTIFY_TYPE_IT_LOOKS_BAD, + .it_looks_bad.reason = error->message); } } } @@ -1144,13 +1142,13 @@ l3_cfg_notify_cb(NML3Cfg *l3cfg, const NML3ConfigNotifyData *notify_data, NMDhcp if (notify_data->notify_type == NM_L3_CONFIG_NOTIFY_TYPE_PLATFORM_CHANGE_ON_IDLE && priv->l3cfg_notify.wait_ipv6_dad) { gs_unref_ptrarray GPtrArray *tentative = NULL; - gs_unref_ptrarray GPtrArray *missing = NULL; + gs_unref_ptrarray GPtrArray *dadfailed = NULL; const NMPlatformIP6Address *valid = NULL; char str[NM_UTILS_TO_STRING_BUFFER_SIZE]; guint i; gs_free_error GError *error = NULL; - ipv6_tentative_addr_check(self, &tentative, &missing, &valid); + ipv6_tentative_addr_check(self, &tentative, &dadfailed, &valid); if (tentative) { for (i = 0; i < tentative->len; i++) { _LOGD("still waiting DAD for address: %s", @@ -1163,10 +1161,10 @@ l3_cfg_notify_cb(NML3Cfg *l3cfg, const NML3ConfigNotifyData *notify_data, NMDhcp nm_clear_g_source_inst(&priv->v6.dad_timeout_source); l3_cfg_notify_check_connected(self); - if (missing) { - for (i = 0; i < missing->len; i++) { + if (dadfailed) { + for (i = 0; i < dadfailed->len; i++) { _LOGE("DAD failed for address: %s", - nm_platform_ip6_address_to_string(missing->pdata[i], str, sizeof(str))); + nm_platform_ip6_address_to_string(dadfailed->pdata[i], str, sizeof(str))); } } @@ -1176,22 +1174,19 @@ l3_cfg_notify_cb(NML3Cfg *l3cfg, const NML3ConfigNotifyData *notify_data, NMDhcp if (_dhcp_client_accept(self, priv->l3cd_curr, &error)) { _emit_notify(self, - &((NMDhcpClientNotifyData){ - .notify_type = NM_DHCP_CLIENT_NOTIFY_TYPE_LEASE_UPDATE, - .lease_update = { - .l3cd = priv->l3cd_curr, - .accepted = TRUE, - }})); + NM_DHCP_CLIENT_NOTIFY_TYPE_LEASE_UPDATE, + .lease_update = { + .l3cd = priv->l3cd_curr, + .accepted = TRUE, + }); } else { gs_free char *reason = g_strdup_printf("error accepting lease: %s", error->message); _LOGD("accept failed: %s", error->message); _emit_notify(self, - &((NMDhcpClientNotifyData){ - .notify_type = NM_DHCP_CLIENT_NOTIFY_TYPE_IT_LOOKS_BAD, - .it_looks_bad.reason = reason, - })); + NM_DHCP_CLIENT_NOTIFY_TYPE_IT_LOOKS_BAD, + .it_looks_bad.reason = reason); } } else { _LOGD("decline the lease"); @@ -1266,20 +1261,17 @@ l3_cfg_notify_cb(NML3Cfg *l3cfg, const NML3ConfigNotifyData *notify_data, NMDhcp _LOGD("accept failed: %s", error->message); _emit_notify(self, - &((NMDhcpClientNotifyData){ - .notify_type = NM_DHCP_CLIENT_NOTIFY_TYPE_IT_LOOKS_BAD, - .it_looks_bad.reason = reason, - })); + NM_DHCP_CLIENT_NOTIFY_TYPE_IT_LOOKS_BAD, + .it_looks_bad.reason = reason, ); goto wait_dhcp_commit_done; } - _emit_notify( - self, - &((NMDhcpClientNotifyData){.notify_type = NM_DHCP_CLIENT_NOTIFY_TYPE_LEASE_UPDATE, - .lease_update = { - .l3cd = priv->l3cd_curr, - .accepted = TRUE, - }})); + _emit_notify(self, + NM_DHCP_CLIENT_NOTIFY_TYPE_LEASE_UPDATE, + .lease_update = { + .l3cd = priv->l3cd_curr, + .accepted = TRUE, + }); } } wait_dhcp_commit_done: @@ -1318,7 +1310,7 @@ wait_dhcp_commit_done: if (acd_state != NM_OPTION_BOOL_DEFAULT) { _LOGD("acd: acd %s for %s", acd_state ? "ready" : "conflict", - _nm_utils_inet4_ntop(priv->v4.acd.addr, sbuf_addr)); + nm_inet4_ntop(priv->v4.acd.addr, sbuf_addr)); nm_l3cfg_commit_type_clear(priv->config.l3cfg, &priv->v4.acd.l3cfg_commit_handle); priv->v4.acd.state = acd_state; priv->v4.acd.done_source = nm_g_idle_add_source(_acd_complete_on_idle_cb, self); @@ -1327,6 +1319,19 @@ wait_dhcp_commit_done: } } +static gboolean +_previous_lease_timeout_cb(gpointer user_data) +{ + NMDhcpClient *self = user_data; + NMDhcpClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE(self); + + nm_clear_g_source_inst(&priv->previous_lease_timeout_source); + + _nm_dhcp_client_notify(self, NM_DHCP_CLIENT_EVENT_TYPE_TIMEOUT, NULL); + + return G_SOURCE_CONTINUE; +} + gboolean nm_dhcp_client_start(NMDhcpClient *self, GError **error) { @@ -1358,6 +1363,23 @@ nm_dhcp_client_start(NMDhcpClient *self, GError **error) _no_lease_timeout_schedule(self); + if (priv->config.previous_lease) { + /* We got passed a previous lease (during a reapply). For a few seconds, we + * will pretend that this is current lease. */ + priv->l3cd_curr = g_steal_pointer(&priv->config.previous_lease); + + /* Schedule a timeout for when we give up using this lease. Note + * that then we will emit a NM_DHCP_CLIENT_NOTIFY_TYPE_LEASE_UPDATE event + * and the lease is gone. Note that NMDevice ignores that and will + * keep using the lease. + * + * At the same time, we have _no_lease_timeout_schedule() ticking, when + * that expires, we will emit a NM_DHCP_CLIENT_NOTIFY_TYPE_NO_LEASE_TIMEOUT + * signal, which causes NMDevice to clear the lease. */ + priv->previous_lease_timeout_source = + nm_g_timeout_add_seconds_source(15, _previous_lease_timeout_cb, self); + } + if (IS_IPv4) return NM_DHCP_CLIENT_GET_CLASS(self)->ip4_start(self, error); @@ -1438,6 +1460,8 @@ nm_dhcp_client_stop(NMDhcpClient *self, gboolean release) if (priv->is_stopped) return; + nm_clear_g_source_inst(&priv->previous_lease_timeout_source); + priv->is_stopped = TRUE; if (priv->invocation) { @@ -1597,15 +1621,11 @@ maybe_add_option(NMDhcpClient *self, GHashTable *hash, const char *key, GVariant void nm_dhcp_client_emit_ipv6_prefix_delegated(NMDhcpClient *self, const NMPlatformIP6Address *prefix) { - const NMDhcpClientNotifyData notify_data = { - .notify_type = NM_DHCP_CLIENT_NOTIFY_TYPE_PREFIX_DELEGATED, - .prefix_delegated = - { - .prefix = prefix, - }, - }; - - _emit_notify(self, ¬ify_data); + _emit_notify(self, + NM_DHCP_CLIENT_NOTIFY_TYPE_PREFIX_DELEGATED, + .prefix_delegated = { + .prefix = prefix, + }); } gboolean @@ -1621,7 +1641,7 @@ nm_dhcp_client_handle_event(gpointer unused, nm_auto_unref_l3cd_init NML3ConfigData *l3cd = NULL; NMDhcpClientEventType client_event_type; NMPlatformIP6Address prefix = { - 0, + 0, }; g_return_val_if_fail(NM_IS_DHCP_CLIENT(self), FALSE); @@ -1751,14 +1771,14 @@ nm_dhcp_client_server_id_is_rejected(NMDhcpClient *self, gconstpointer addr) in_addr_t mask; int r_prefix; - if (!nm_utils_parse_inaddr_prefix_bin(AF_INET, - priv->config.reject_servers[i], - NULL, - &r_addr, - &r_prefix)) + if (!nm_inet_parse_with_prefix_bin(AF_INET, + priv->config.reject_servers[i], + NULL, + &r_addr, + &r_prefix)) nm_assert_not_reached(); - mask = _nm_utils_ip4_prefix_to_netmask(r_prefix < 0 ? 32 : r_prefix); + mask = nm_ip4_addr_netmask_from_prefix(r_prefix < 0 ? 32 : r_prefix); if ((addr4 & mask) == (r_addr & mask)) return TRUE; } @@ -1783,6 +1803,8 @@ config_init(NMDhcpClientConfig *config, const NMDhcpClientConfig *src) g_object_ref(config->l3cfg); + nm_l3_config_data_ref_and_seal(config->previous_lease); + nm_g_bytes_ref(config->hwaddr); nm_g_bytes_ref(config->bcast_hwaddr); nm_g_bytes_ref(config->vendor_class_identifier); @@ -1843,6 +1865,8 @@ config_clear(NMDhcpClientConfig *config) { g_object_unref(config->l3cfg); + nm_clear_l3cd(&config->previous_lease); + 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); @@ -1919,6 +1943,7 @@ dispose(GObject *object) watch_cleanup(self); + nm_clear_g_source_inst(&priv->previous_lease_timeout_source); nm_clear_g_source_inst(&priv->no_lease_timeout_source); if (!NM_IS_IPv4(priv->config.addr_family)) { |