|
Packit Service |
a1bd4f |
/* SPDX-License-Identifier: LGPL-2.1+ */
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
#include "nm-default.h"
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
#include "nm-l3-ipv4ll.h"
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
#include <net/if.h>
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
#include "n-acd/src/n-acd.h"
|
|
Packit Service |
a1bd4f |
#include "nm-core-utils.h"
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
#define ADDR_IPV4LL_PREFIX_LEN 16
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
#define TIMED_OUT_TIME_FACTOR 5u
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
/*****************************************************************************/
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
typedef enum {
|
|
Packit Service |
a1bd4f |
TIMED_OUT_STATE_IS_NOT_TIMED_OUT,
|
|
Packit Service |
a1bd4f |
TIMED_OUT_STATE_IS_TIMED_OUT,
|
|
Packit Service |
a1bd4f |
TIMED_OUT_STATE_HAVE_TIMER_RUNNING,
|
|
Packit Service |
a1bd4f |
} TimedOutState;
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
struct _NML3IPv4LLRegistration {
|
|
Packit Service |
a1bd4f |
NML3IPv4LL *self;
|
|
Packit Service |
a1bd4f |
CList reg_lst;
|
|
Packit Service |
a1bd4f |
guint timeout_msec;
|
|
Packit Service |
a1bd4f |
};
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
G_STATIC_ASSERT(G_STRUCT_OFFSET(NML3IPv4LLRegistration, self) == 0);
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
struct _NML3IPv4LL {
|
|
Packit Service |
a1bd4f |
NML3Cfg * l3cfg;
|
|
Packit Service |
a1bd4f |
int ref_count;
|
|
Packit Service |
a1bd4f |
in_addr_t addr;
|
|
Packit Service |
a1bd4f |
guint reg_timeout_msec;
|
|
Packit Service |
a1bd4f |
CList reg_lst_head;
|
|
Packit Service |
a1bd4f |
NML3CfgCommitTypeHandle *l3cfg_commit_handle;
|
|
Packit Service |
a1bd4f |
GSource * state_change_on_idle_source;
|
|
Packit Service |
a1bd4f |
GSource * timed_out_source;
|
|
Packit Service |
a1bd4f |
const NML3ConfigData * l3cd;
|
|
Packit Service |
a1bd4f |
const NMPObject * plobj;
|
|
Packit Service |
a1bd4f |
struct {
|
|
Packit Service |
a1bd4f |
nm_le64_t value;
|
|
Packit Service |
a1bd4f |
nm_le64_t generation;
|
|
Packit Service |
a1bd4f |
} seed;
|
|
Packit Service |
a1bd4f |
gint64 timed_out_expiry_msec;
|
|
Packit Service |
a1bd4f |
gulong l3cfg_signal_notify_id;
|
|
Packit Service |
a1bd4f |
NML3IPv4LLState state;
|
|
Packit Service |
a1bd4f |
NMEtherAddr seed_mac;
|
|
Packit Service |
a1bd4f |
NMEtherAddr mac;
|
|
Packit Service |
a1bd4f |
bool seed_set : 1;
|
|
Packit Service |
a1bd4f |
bool mac_set : 1;
|
|
Packit Service |
a1bd4f |
bool notify_on_idle : 1;
|
|
Packit Service |
a1bd4f |
bool reg_changed : 1;
|
|
Packit Service |
a1bd4f |
bool l3cd_timeout_msec_changed : 1;
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
/* not yet used. */
|
|
Packit Service |
a1bd4f |
bool seed_reset_generation : 1;
|
|
Packit Service |
a1bd4f |
};
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
G_STATIC_ASSERT(G_STRUCT_OFFSET(NML3IPv4LL, ref_count) == sizeof(gpointer));
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
#define L3CD_TAG(self) (&(((const char *) self)[1]))
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
/*****************************************************************************/
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
#define _NMLOG_DOMAIN LOGD_IP4
|
|
Packit Service |
a1bd4f |
#define _NMLOG_PREFIX_NAME "ipv4ll"
|
|
Packit Service |
a1bd4f |
#define _NMLOG(level, ...) \
|
|
Packit Service |
a1bd4f |
G_STMT_START \
|
|
Packit Service |
a1bd4f |
{ \
|
|
Packit Service |
a1bd4f |
nm_log((level), \
|
|
Packit Service |
a1bd4f |
(_NMLOG_DOMAIN), \
|
|
Packit Service |
a1bd4f |
NULL, \
|
|
Packit Service |
a1bd4f |
NULL, \
|
|
Packit Service |
a1bd4f |
_NMLOG_PREFIX_NAME "[" NM_HASH_OBFUSCATE_PTR_FMT \
|
|
Packit Service |
a1bd4f |
",ifindex=%d]: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \
|
|
Packit Service |
a1bd4f |
NM_HASH_OBFUSCATE_PTR(self), \
|
|
Packit Service |
a1bd4f |
nm_l3cfg_get_ifindex((self)->l3cfg) _NM_UTILS_MACRO_REST(__VA_ARGS__)); \
|
|
Packit Service |
a1bd4f |
} \
|
|
Packit Service |
a1bd4f |
G_STMT_END
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
/*****************************************************************************/
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
static void _ipv4ll_state_change_on_idle(NML3IPv4LL *self);
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
static void _ipv4ll_state_change(NML3IPv4LL *self, gboolean is_on_idle_handler);
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
static void _ipv4ll_set_timed_out_update(NML3IPv4LL *self, TimedOutState new_state);
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
/*****************************************************************************/
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
NM_UTILS_ENUM2STR_DEFINE(nm_l3_ipv4ll_state_to_string,
|
|
Packit Service |
a1bd4f |
NML3IPv4LLState,
|
|
Packit Service |
a1bd4f |
NM_UTILS_ENUM2STR(NM_L3_IPV4LL_STATE_UNKNOWN, "unknown"),
|
|
Packit Service |
a1bd4f |
NM_UTILS_ENUM2STR(NM_L3_IPV4LL_STATE_DISABLED, "disabled"),
|
|
Packit Service |
a1bd4f |
NM_UTILS_ENUM2STR(NM_L3_IPV4LL_STATE_WAIT_FOR_LINK, "wait-for-link"),
|
|
Packit Service |
a1bd4f |
NM_UTILS_ENUM2STR(NM_L3_IPV4LL_STATE_EXTERNAL, "external"),
|
|
Packit Service |
a1bd4f |
NM_UTILS_ENUM2STR(NM_L3_IPV4LL_STATE_PROBING, "probing"),
|
|
Packit Service |
a1bd4f |
NM_UTILS_ENUM2STR(NM_L3_IPV4LL_STATE_DEFENDING, "defending"),
|
|
Packit Service |
a1bd4f |
NM_UTILS_ENUM2STR(NM_L3_IPV4LL_STATE_READY, "ready"), );
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
/*****************************************************************************/
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
#define _ASSERT(self) \
|
|
Packit Service |
a1bd4f |
G_STMT_START \
|
|
Packit Service |
a1bd4f |
{ \
|
|
Packit Service |
a1bd4f |
NML3IPv4LL *const _self = (self); \
|
|
Packit Service |
a1bd4f |
\
|
|
Packit Service |
a1bd4f |
nm_assert(NM_IS_L3_IPV4LL(_self)); \
|
|
Packit Service |
a1bd4f |
if (NM_MORE_ASSERTS > 5) { \
|
|
Packit Service |
a1bd4f |
nm_assert(_self->addr == 0u || nm_utils_ip4_address_is_link_local(_self->addr)); \
|
|
Packit Service |
a1bd4f |
nm_assert(!_self->l3cd || NM_IS_L3_CONFIG_DATA(_self->l3cd)); \
|
|
Packit Service |
a1bd4f |
} \
|
|
Packit Service |
a1bd4f |
} \
|
|
Packit Service |
a1bd4f |
G_STMT_END
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
/*****************************************************************************/
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
NML3Cfg *
|
|
Packit Service |
a1bd4f |
nm_l3_ipv4ll_get_l3cfg(NML3IPv4LL *self)
|
|
Packit Service |
a1bd4f |
{
|
|
Packit Service |
a1bd4f |
nm_assert(NM_IS_L3_IPV4LL(self));
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
return self->l3cfg;
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
int
|
|
Packit Service |
a1bd4f |
nm_l3_ipv4ll_get_ifindex(NML3IPv4LL *self)
|
|
Packit Service |
a1bd4f |
{
|
|
Packit Service |
a1bd4f |
nm_assert(NM_IS_L3_IPV4LL(self));
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
return nm_l3cfg_get_ifindex(self->l3cfg);
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
NMPlatform *
|
|
Packit Service |
a1bd4f |
nm_l3_ipv4ll_get_platform(NML3IPv4LL *self)
|
|
Packit Service |
a1bd4f |
{
|
|
Packit Service |
a1bd4f |
nm_assert(NM_IS_L3_IPV4LL(self));
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
return nm_l3cfg_get_platform(self->l3cfg);
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
/*****************************************************************************/
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
NML3IPv4LLState
|
|
Packit Service |
a1bd4f |
nm_l3_ipv4ll_get_state(NML3IPv4LL *self)
|
|
Packit Service |
a1bd4f |
{
|
|
Packit Service |
a1bd4f |
nm_assert(NM_IS_L3_IPV4LL(self));
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
return self->state;
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
static gboolean
|
|
Packit Service |
a1bd4f |
_ipv4ll_is_timed_out(NML3IPv4LL *self)
|
|
Packit Service |
a1bd4f |
{
|
|
Packit Service |
a1bd4f |
_ASSERT(self);
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
return self->timed_out_expiry_msec != 0 && !self->timed_out_source;
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
gboolean
|
|
Packit Service |
a1bd4f |
nm_l3_ipv4ll_is_timed_out(NML3IPv4LL *self)
|
|
Packit Service |
a1bd4f |
{
|
|
Packit Service |
a1bd4f |
nm_assert(NM_IS_L3_IPV4LL(self));
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
return _ipv4ll_is_timed_out(self);
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
in_addr_t
|
|
Packit Service |
a1bd4f |
nm_l3_ipv4ll_get_addr(NML3IPv4LL *self)
|
|
Packit Service |
a1bd4f |
{
|
|
Packit Service |
a1bd4f |
nm_assert(NM_IS_L3_IPV4LL(self));
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
return self->addr;
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
const NML3ConfigData *
|
|
Packit Service |
a1bd4f |
nm_l3_ipv4ll_get_l3cd(NML3IPv4LL *self)
|
|
Packit Service |
a1bd4f |
{
|
|
Packit Service |
a1bd4f |
nm_assert(NM_IS_L3_IPV4LL(self));
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
return self->l3cd;
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
static void
|
|
Packit Service |
a1bd4f |
_ipv4ll_emit_signal_notify(NML3IPv4LL *self)
|
|
Packit Service |
a1bd4f |
{
|
|
Packit Service |
a1bd4f |
NML3ConfigNotifyData notify_data;
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
self->notify_on_idle = FALSE;
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
notify_data.notify_type = NM_L3_CONFIG_NOTIFY_TYPE_IPV4LL_EVENT;
|
|
Packit Service |
a1bd4f |
notify_data.ipv4ll_event = (typeof(notify_data.ipv4ll_event)){
|
|
Packit Service |
a1bd4f |
.ipv4ll = self,
|
|
Packit Service |
a1bd4f |
};
|
|
Packit Service |
a1bd4f |
_nm_l3cfg_emit_signal_notify(self->l3cfg, ¬ify_data);
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
/*****************************************************************************/
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
static NML3IPv4LLRegistration *
|
|
Packit Service |
a1bd4f |
_registration_update(NML3IPv4LL * self,
|
|
Packit Service |
a1bd4f |
NML3IPv4LLRegistration *reg,
|
|
Packit Service |
a1bd4f |
gboolean add,
|
|
Packit Service |
a1bd4f |
guint timeout_msec)
|
|
Packit Service |
a1bd4f |
{
|
|
Packit Service |
a1bd4f |
nm_auto_unref_l3ipv4ll NML3IPv4LL *self_unref_on_exit = NULL;
|
|
Packit Service |
a1bd4f |
gboolean changed = FALSE;
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
if (reg) {
|
|
Packit Service |
a1bd4f |
nm_assert(!self);
|
|
Packit Service |
a1bd4f |
_ASSERT(reg->self);
|
|
Packit Service |
a1bd4f |
self = reg->self;
|
|
Packit Service |
a1bd4f |
nm_assert(c_list_contains(&self->reg_lst_head, ®->reg_lst));
|
|
Packit Service |
a1bd4f |
nm_assert(self == nm_l3_ipv4ll_register_get_instance(reg));
|
|
Packit Service |
a1bd4f |
} else {
|
|
Packit Service |
a1bd4f |
nm_assert(add);
|
|
Packit Service |
a1bd4f |
_ASSERT(self);
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
if (!add) {
|
|
Packit Service |
a1bd4f |
_LOGT("registration[" NM_HASH_OBFUSCATE_PTR_FMT "]: remove", NM_HASH_OBFUSCATE_PTR(reg));
|
|
Packit Service |
a1bd4f |
c_list_unlink_stale(®->reg_lst);
|
|
Packit Service |
a1bd4f |
if (c_list_is_empty(&self->reg_lst_head))
|
|
Packit Service |
a1bd4f |
self_unref_on_exit = self;
|
|
Packit Service |
a1bd4f |
nm_g_slice_free(reg);
|
|
Packit Service |
a1bd4f |
reg = NULL;
|
|
Packit Service |
a1bd4f |
goto out;
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
if (!reg) {
|
|
Packit Service |
a1bd4f |
reg = g_slice_new(NML3IPv4LLRegistration);
|
|
Packit Service |
a1bd4f |
*reg = (NML3IPv4LLRegistration){
|
|
Packit Service |
a1bd4f |
.self = self,
|
|
Packit Service |
a1bd4f |
.timeout_msec = timeout_msec,
|
|
Packit Service |
a1bd4f |
};
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
if (c_list_is_empty(&self->reg_lst_head))
|
|
Packit Service |
a1bd4f |
nm_l3_ipv4ll_ref(self);
|
|
Packit Service |
a1bd4f |
c_list_link_tail(&self->reg_lst_head, ®->reg_lst);
|
|
Packit Service |
a1bd4f |
changed = TRUE;
|
|
Packit Service |
a1bd4f |
_LOGT("registration[" NM_HASH_OBFUSCATE_PTR_FMT "]: add (timeout_msec=%u)",
|
|
Packit Service |
a1bd4f |
NM_HASH_OBFUSCATE_PTR(reg),
|
|
Packit Service |
a1bd4f |
timeout_msec);
|
|
Packit Service |
a1bd4f |
} else {
|
|
Packit Service |
a1bd4f |
if (reg->timeout_msec != timeout_msec) {
|
|
Packit Service |
a1bd4f |
reg->timeout_msec = timeout_msec;
|
|
Packit Service |
a1bd4f |
changed = TRUE;
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
if (changed) {
|
|
Packit Service |
a1bd4f |
_LOGT("registration[" NM_HASH_OBFUSCATE_PTR_FMT "]: update (timeout_msec=%u)",
|
|
Packit Service |
a1bd4f |
NM_HASH_OBFUSCATE_PTR(reg),
|
|
Packit Service |
a1bd4f |
timeout_msec);
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
out:
|
|
Packit Service |
a1bd4f |
if (changed) {
|
|
Packit Service |
a1bd4f |
self->reg_changed = TRUE;
|
|
Packit Service |
a1bd4f |
_ipv4ll_state_change(self, FALSE);
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
return reg;
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
NML3IPv4LLRegistration *
|
|
Packit Service |
a1bd4f |
nm_l3_ipv4ll_register_new(NML3IPv4LL *self, guint timeout_msec)
|
|
Packit Service |
a1bd4f |
{
|
|
Packit Service |
a1bd4f |
return _registration_update(self, NULL, TRUE, timeout_msec);
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
NML3IPv4LLRegistration *
|
|
Packit Service |
a1bd4f |
nm_l3_ipv4ll_register_update(NML3IPv4LLRegistration *reg, guint timeout_msec)
|
|
Packit Service |
a1bd4f |
{
|
|
Packit Service |
a1bd4f |
return _registration_update(NULL, reg, TRUE, timeout_msec);
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
NML3IPv4LLRegistration *
|
|
Packit Service |
a1bd4f |
nm_l3_ipv4ll_register_remove(NML3IPv4LLRegistration *reg)
|
|
Packit Service |
a1bd4f |
{
|
|
Packit Service |
a1bd4f |
return _registration_update(NULL, reg, FALSE, 0);
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
/*****************************************************************************/
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
static gboolean
|
|
Packit Service |
a1bd4f |
_ip4_address_is_link_local(const NMPlatformIP4Address *a)
|
|
Packit Service |
a1bd4f |
{
|
|
Packit Service |
a1bd4f |
nm_assert(a);
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
return nm_utils_ip4_address_is_link_local(a->address) && a->plen == ADDR_IPV4LL_PREFIX_LEN
|
|
Packit Service |
a1bd4f |
&& a->address == a->peer_address;
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
static gboolean
|
|
Packit Service |
a1bd4f |
_acd_info_is_good(const NML3AcdAddrInfo *acd_info)
|
|
Packit Service |
a1bd4f |
{
|
|
Packit Service |
a1bd4f |
if (!acd_info)
|
|
Packit Service |
a1bd4f |
return TRUE;
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
switch (acd_info->state) {
|
|
Packit Service |
a1bd4f |
case NM_L3_ACD_ADDR_STATE_INIT:
|
|
Packit Service |
a1bd4f |
case NM_L3_ACD_ADDR_STATE_PROBING:
|
|
Packit Service |
a1bd4f |
case NM_L3_ACD_ADDR_STATE_READY:
|
|
Packit Service |
a1bd4f |
case NM_L3_ACD_ADDR_STATE_DEFENDING:
|
|
Packit Service |
a1bd4f |
case NM_L3_ACD_ADDR_STATE_EXTERNAL_REMOVED:
|
|
Packit Service |
a1bd4f |
return TRUE;
|
|
Packit Service |
a1bd4f |
case NM_L3_ACD_ADDR_STATE_USED:
|
|
Packit Service |
a1bd4f |
case NM_L3_ACD_ADDR_STATE_CONFLICT:
|
|
Packit Service |
a1bd4f |
return FALSE;
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
nm_assert_not_reached();
|
|
Packit Service |
a1bd4f |
return FALSE;
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
/*****************************************************************************/
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
static NMPlatformIP4Address *
|
|
Packit Service |
a1bd4f |
_l3cd_config_plat_init_addr(NMPlatformIP4Address *a, int ifindex, in_addr_t addr)
|
|
Packit Service |
a1bd4f |
{
|
|
Packit Service |
a1bd4f |
nm_assert(nm_utils_ip4_address_is_link_local(addr));
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
*a = (NMPlatformIP4Address){
|
|
Packit Service |
a1bd4f |
.ifindex = ifindex,
|
|
Packit Service |
a1bd4f |
.address = addr,
|
|
Packit Service |
a1bd4f |
.peer_address = addr,
|
|
Packit Service |
a1bd4f |
.plen = ADDR_IPV4LL_PREFIX_LEN,
|
|
Packit Service |
a1bd4f |
.addr_source = NM_IP_CONFIG_SOURCE_IP4LL,
|
|
Packit Service |
a1bd4f |
};
|
|
Packit Service |
a1bd4f |
return a;
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
static NMPlatformIP4Route *
|
|
Packit Service |
a1bd4f |
_l3cd_config_plat_init_route(NMPlatformIP4Route *r, int ifindex)
|
|
Packit Service |
a1bd4f |
{
|
|
Packit Service |
a1bd4f |
*r = (NMPlatformIP4Route){
|
|
Packit Service |
a1bd4f |
.ifindex = ifindex,
|
|
Packit Service |
a1bd4f |
.network = htonl(0xE0000000u),
|
|
Packit Service |
a1bd4f |
.plen = 4,
|
|
Packit Service |
a1bd4f |
.rt_source = NM_IP_CONFIG_SOURCE_IP4LL,
|
|
Packit Service |
a1bd4f |
.table_any = TRUE,
|
|
Packit Service |
a1bd4f |
.metric_any = TRUE,
|
|
Packit Service |
a1bd4f |
};
|
|
Packit Service |
a1bd4f |
return r;
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
static const NML3ConfigData *
|
|
Packit Service |
a1bd4f |
_l3cd_config_create(int ifindex, in_addr_t addr, NMDedupMultiIndex *multi_idx)
|
|
Packit Service |
a1bd4f |
{
|
|
Packit Service |
a1bd4f |
nm_auto_unref_l3cd_init NML3ConfigData *l3cd = NULL;
|
|
Packit Service |
a1bd4f |
NMPlatformIP4Address a;
|
|
Packit Service |
a1bd4f |
NMPlatformIP4Route r;
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
nm_assert(nm_utils_ip4_address_is_link_local(addr));
|
|
Packit Service |
a1bd4f |
nm_assert(ifindex > 0);
|
|
Packit Service |
a1bd4f |
nm_assert(multi_idx);
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
l3cd = nm_l3_config_data_new(multi_idx, ifindex);
|
|
Packit Service |
a1bd4f |
nm_l3_config_data_set_source(l3cd, NM_IP_CONFIG_SOURCE_IP4LL);
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
nm_l3_config_data_add_address_4(l3cd, _l3cd_config_plat_init_addr(&a, ifindex, addr));
|
|
Packit Service |
a1bd4f |
nm_l3_config_data_add_route_4(l3cd, _l3cd_config_plat_init_route(&r, ifindex));
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
return nm_l3_config_data_seal(g_steal_pointer(&l3cd));
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
static in_addr_t
|
|
Packit Service |
a1bd4f |
_l3cd_config_get_addr(const NML3ConfigData *l3cd)
|
|
Packit Service |
a1bd4f |
{
|
|
Packit Service |
a1bd4f |
NMDedupMultiIter iter;
|
|
Packit Service |
a1bd4f |
const NMPlatformIP4Address *pladdr;
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
if (!l3cd)
|
|
Packit Service |
a1bd4f |
return 0u;
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
nm_l3_config_data_iter_ip4_address_for_each (&iter, l3cd, &pladdr) {
|
|
Packit Service |
a1bd4f |
const in_addr_t addr = pladdr->address;
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
nm_assert(_ip4_address_is_link_local(pladdr));
|
|
Packit Service |
a1bd4f |
#if NM_MORE_ASSERTS > 10
|
|
Packit Service |
a1bd4f |
{
|
|
Packit Service |
a1bd4f |
nm_auto_unref_l3cd const NML3ConfigData *l3cd2 = NULL;
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
l3cd2 = _l3cd_config_create(nm_l3_config_data_get_ifindex(l3cd),
|
|
Packit Service |
a1bd4f |
addr,
|
|
Packit Service |
a1bd4f |
nm_l3_config_data_get_multi_idx(l3cd));
|
|
Packit Service |
a1bd4f |
nm_assert(nm_l3_config_data_equal(l3cd2, l3cd));
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
#endif
|
|
Packit Service |
a1bd4f |
return addr;
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
return nm_assert_unreachable_val(0u);
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
/*****************************************************************************/
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
static void
|
|
Packit Service |
a1bd4f |
_ipv4ll_addrgen(NML3IPv4LL *self, gboolean generate_new_addr)
|
|
Packit Service |
a1bd4f |
{
|
|
Packit Service |
a1bd4f |
CSipHash state;
|
|
Packit Service |
a1bd4f |
char sbuf_addr[NM_UTILS_INET_ADDRSTRLEN];
|
|
Packit Service |
a1bd4f |
gboolean seed_changed = FALSE;
|
|
Packit Service |
a1bd4f |
in_addr_t addr_new;
|
|
Packit Service |
a1bd4f |
guint64 h;
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
_ASSERT(self);
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
/* MAC_HASH_KEY is the same as used by systemd. */
|
|
Packit Service |
a1bd4f |
#define MAC_HASH_KEY \
|
|
Packit Service |
a1bd4f |
((const guint8[16]){0xdf, \
|
|
Packit Service |
a1bd4f |
0x04, \
|
|
Packit Service |
a1bd4f |
0x22, \
|
|
Packit Service |
a1bd4f |
0x98, \
|
|
Packit Service |
a1bd4f |
0x3f, \
|
|
Packit Service |
a1bd4f |
0xad, \
|
|
Packit Service |
a1bd4f |
0x14, \
|
|
Packit Service |
a1bd4f |
0x52, \
|
|
Packit Service |
a1bd4f |
0xf9, \
|
|
Packit Service |
a1bd4f |
0x87, \
|
|
Packit Service |
a1bd4f |
0x2e, \
|
|
Packit Service |
a1bd4f |
0xd1, \
|
|
Packit Service |
a1bd4f |
0x9c, \
|
|
Packit Service |
a1bd4f |
0x70, \
|
|
Packit Service |
a1bd4f |
0xe2, \
|
|
Packit Service |
a1bd4f |
0xf2})
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
if (self->mac_set && (!self->seed_set || !nm_ether_addr_equal(&self->mac, &self->seed_mac))) {
|
|
Packit Service |
a1bd4f |
/* systemd's ipv4ll library by default only hashes the MAC address (as we do here).
|
|
Packit Service |
a1bd4f |
* This is also what previous versions of NetworkManager did (whenn using sd_ipv4ll).
|
|
Packit Service |
a1bd4f |
*
|
|
Packit Service |
a1bd4f |
* On the other hand, systemd-networkd uses net_get_name_persistent() of the device
|
|
Packit Service |
a1bd4f |
* mixed with /etc/machine-id.
|
|
Packit Service |
a1bd4f |
*
|
|
Packit Service |
a1bd4f |
* See also: https://tools.ietf.org/html/rfc3927#section-2.1
|
|
Packit Service |
a1bd4f |
*
|
|
Packit Service |
a1bd4f |
* FIXME(l3cfg): At this point, maybe we should also mix it with nm_utils_host_id_get().
|
|
Packit Service |
a1bd4f |
* This would get the behavior closer to what systemd-networkd does.
|
|
Packit Service |
a1bd4f |
* Don't do that for now, because it would be a change in behavior compared
|
|
Packit Service |
a1bd4f |
* to earlier versions of NetworkManager. */
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
c_siphash_init(&state, MAC_HASH_KEY);
|
|
Packit Service |
a1bd4f |
c_siphash_append(&state, self->mac.ether_addr_octet, ETH_ALEN);
|
|
Packit Service |
a1bd4f |
h = c_siphash_finalize(&state);
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
_LOGT("addr-gen: %sset seed (for " NM_ETHER_ADDR_FORMAT_STR ")",
|
|
Packit Service |
a1bd4f |
self->seed_set ? "re" : "",
|
|
Packit Service |
a1bd4f |
NM_ETHER_ADDR_FORMAT_VAL(&self->mac));
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
self->seed_set = TRUE;
|
|
Packit Service |
a1bd4f |
self->seed_mac = self->mac;
|
|
Packit Service |
a1bd4f |
self->seed.generation = htole64(0);
|
|
Packit Service |
a1bd4f |
self->seed.value = htole64(h);
|
|
Packit Service |
a1bd4f |
self->seed_reset_generation = FALSE;
|
|
Packit Service |
a1bd4f |
self->addr = 0u;
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
seed_changed = TRUE;
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
if (!self->seed_set) {
|
|
Packit Service |
a1bd4f |
/* we have no seed set (and consequently no MAC address set either).
|
|
Packit Service |
a1bd4f |
* We cannot generate an address. */
|
|
Packit Service |
a1bd4f |
nm_assert(self->addr == 0u);
|
|
Packit Service |
a1bd4f |
return;
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
nm_assert(seed_changed || self->seed.generation != htole64(0u));
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
if (self->seed_reset_generation) {
|
|
Packit Service |
a1bd4f |
_LOGT("addr-gen: reset seed (generation only)");
|
|
Packit Service |
a1bd4f |
self->seed.generation = htole64(0);
|
|
Packit Service |
a1bd4f |
self->addr = 0u;
|
|
Packit Service |
a1bd4f |
seed_changed = TRUE;
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
if (!seed_changed && !generate_new_addr) {
|
|
Packit Service |
a1bd4f |
/* neither did the caller request a new address, nor was the seed changed. The current
|
|
Packit Service |
a1bd4f |
* address is still to be used. */
|
|
Packit Service |
a1bd4f |
nm_assert(nm_utils_ip4_address_is_link_local(self->addr));
|
|
Packit Service |
a1bd4f |
return;
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
gen_addr:
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
#define PICK_HASH_KEY \
|
|
Packit Service |
a1bd4f |
((const guint8[16]){0x15, \
|
|
Packit Service |
a1bd4f |
0xac, \
|
|
Packit Service |
a1bd4f |
0x82, \
|
|
Packit Service |
a1bd4f |
0xa6, \
|
|
Packit Service |
a1bd4f |
0xd6, \
|
|
Packit Service |
a1bd4f |
0x3f, \
|
|
Packit Service |
a1bd4f |
0x49, \
|
|
Packit Service |
a1bd4f |
0x78, \
|
|
Packit Service |
a1bd4f |
0x98, \
|
|
Packit Service |
a1bd4f |
0x77, \
|
|
Packit Service |
a1bd4f |
0x5d, \
|
|
Packit Service |
a1bd4f |
0x0c, \
|
|
Packit Service |
a1bd4f |
0x69, \
|
|
Packit Service |
a1bd4f |
0x02, \
|
|
Packit Service |
a1bd4f |
0x94, \
|
|
Packit Service |
a1bd4f |
0x0b})
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
h = c_siphash_hash(PICK_HASH_KEY, (const guint8 *) &self->seed, sizeof(self->seed));
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
self->seed.generation = htole64(le64toh(self->seed.generation) + 1u);
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
addr_new = htonl(h & UINT32_C(0x0000FFFF)) | NM_IPV4LL_NETWORK;
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
if (self->addr == addr_new || NM_IN_SET(ntohl(addr_new) & 0x0000FF00u, 0x0000u, 0xFF00u))
|
|
Packit Service |
a1bd4f |
goto gen_addr;
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
nm_assert(nm_utils_ip4_address_is_link_local(addr_new));
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
_LOGT("addr-gen: set address %s", _nm_utils_inet4_ntop(addr_new, sbuf_addr));
|
|
Packit Service |
a1bd4f |
self->addr = addr_new;
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
/*****************************************************************************/
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
static void
|
|
Packit Service |
a1bd4f |
_ipv4ll_update_link(NML3IPv4LL *self, const NMPObject *plobj)
|
|
Packit Service |
a1bd4f |
{
|
|
Packit Service |
a1bd4f |
char sbuf[ETH_ALEN * 3];
|
|
Packit Service |
a1bd4f |
nm_auto_nmpobj const NMPObject *pllink_old = NULL;
|
|
Packit Service |
a1bd4f |
const NMEtherAddr * mac_new;
|
|
Packit Service |
a1bd4f |
gboolean changed;
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
if (self->plobj == plobj)
|
|
Packit Service |
a1bd4f |
return;
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
pllink_old = g_steal_pointer(&self->plobj);
|
|
Packit Service |
a1bd4f |
self->plobj = nmp_object_ref(plobj);
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
mac_new = NULL;
|
|
Packit Service |
a1bd4f |
if (plobj) {
|
|
Packit Service |
a1bd4f |
const NMPlatformLink *pllink = NMP_OBJECT_CAST_LINK(plobj);
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
if (pllink->l_address.len == ETH_ALEN)
|
|
Packit Service |
a1bd4f |
mac_new = &pllink->l_address.ether_addr;
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
changed = FALSE;
|
|
Packit Service |
a1bd4f |
if (!mac_new) {
|
|
Packit Service |
a1bd4f |
if (self->mac_set) {
|
|
Packit Service |
a1bd4f |
changed = TRUE;
|
|
Packit Service |
a1bd4f |
self->mac_set = FALSE;
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
} else {
|
|
Packit Service |
a1bd4f |
if (!self->mac_set || !nm_ether_addr_equal(mac_new, &self->mac)) {
|
|
Packit Service |
a1bd4f |
changed = TRUE;
|
|
Packit Service |
a1bd4f |
self->mac_set = TRUE;
|
|
Packit Service |
a1bd4f |
self->mac = *mac_new;
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
if (changed) {
|
|
Packit Service |
a1bd4f |
_LOGT("mac changed: %s",
|
|
Packit Service |
a1bd4f |
self->mac_set ? _nm_utils_hwaddr_ntoa(&self->mac, ETH_ALEN, TRUE, sbuf, sizeof(sbuf))
|
|
Packit Service |
a1bd4f |
: "unset");
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
/*****************************************************************************/
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
static void
|
|
Packit Service |
a1bd4f |
_l3cd_config_add(NML3IPv4LL *self)
|
|
Packit Service |
a1bd4f |
{
|
|
Packit Service |
a1bd4f |
nm_auto_unref_l3cd const NML3ConfigData *l3cd = NULL;
|
|
Packit Service |
a1bd4f |
char sbuf_addr[NM_UTILS_INET_ADDRSTRLEN];
|
|
Packit Service |
a1bd4f |
gboolean changed;
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
_ASSERT(self);
|
|
Packit Service |
a1bd4f |
nm_assert(self->addr != 0u);
|
|
Packit Service |
a1bd4f |
nm_assert(self->reg_timeout_msec > 0u);
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
if (_l3cd_config_get_addr(self->l3cd) != self->addr) {
|
|
Packit Service |
a1bd4f |
l3cd = _l3cd_config_create(nm_l3_ipv4ll_get_ifindex(self),
|
|
Packit Service |
a1bd4f |
self->addr,
|
|
Packit Service |
a1bd4f |
nm_l3cfg_get_multi_idx(self->l3cfg));
|
|
Packit Service |
a1bd4f |
nm_assert(!nm_l3_config_data_equal(l3cd, self->l3cd));
|
|
Packit Service |
a1bd4f |
changed = TRUE;
|
|
Packit Service |
a1bd4f |
} else
|
|
Packit Service |
a1bd4f |
changed = FALSE;
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
if (!changed && !self->l3cd_timeout_msec_changed)
|
|
Packit Service |
a1bd4f |
return;
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
self->l3cd_timeout_msec_changed = FALSE;
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
_LOGT("add l3cd config with %s (acd-timeout %u msec%s)",
|
|
Packit Service |
a1bd4f |
_nm_utils_inet4_ntop(self->addr, sbuf_addr),
|
|
Packit Service |
a1bd4f |
self->reg_timeout_msec,
|
|
Packit Service |
a1bd4f |
changed ? "" : " changed");
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
if (changed) {
|
|
Packit Service |
a1bd4f |
NM_SWAP(&l3cd, &self->l3cd);
|
|
Packit Service |
a1bd4f |
self->notify_on_idle = TRUE;
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
if (!nm_l3cfg_add_config(self->l3cfg,
|
|
Packit Service |
a1bd4f |
L3CD_TAG(self),
|
|
Packit Service |
a1bd4f |
TRUE,
|
|
Packit Service |
a1bd4f |
self->l3cd,
|
|
Packit Service |
a1bd4f |
NM_L3CFG_CONFIG_PRIORITY_IPV4LL,
|
|
Packit Service |
a1bd4f |
0,
|
|
Packit Service |
a1bd4f |
0,
|
|
Packit Service |
a1bd4f |
NM_PLATFORM_ROUTE_METRIC_DEFAULT_IP4,
|
|
Packit Service |
a1bd4f |
NM_PLATFORM_ROUTE_METRIC_DEFAULT_IP6,
|
|
Packit Service |
a1bd4f |
0,
|
|
Packit Service |
a1bd4f |
0,
|
|
Packit Service |
a1bd4f |
NM_L3_ACD_DEFEND_TYPE_ONCE,
|
|
Packit Service |
a1bd4f |
self->reg_timeout_msec,
|
|
Packit Service |
a1bd4f |
NM_L3_CONFIG_MERGE_FLAGS_ONLY_FOR_ACD))
|
|
Packit Service |
a1bd4f |
nm_assert_not_reached();
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
self->l3cfg_commit_handle = nm_l3cfg_commit_type_register(self->l3cfg,
|
|
Packit Service |
a1bd4f |
NM_L3_CFG_COMMIT_TYPE_ASSUME,
|
|
Packit Service |
a1bd4f |
self->l3cfg_commit_handle);
|
|
Packit Service |
a1bd4f |
nm_l3cfg_commit_on_idle_schedule(self->l3cfg);
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
static gboolean
|
|
Packit Service |
a1bd4f |
_l3cd_config_remove(NML3IPv4LL *self)
|
|
Packit Service |
a1bd4f |
{
|
|
Packit Service |
a1bd4f |
nm_auto_unref_l3cd const NML3ConfigData *l3cd = NULL;
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
nm_assert(NM_IS_L3_IPV4LL(self));
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
if (!self->l3cd)
|
|
Packit Service |
a1bd4f |
return FALSE;
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
_LOGT("remove l3cd config");
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
self->notify_on_idle = TRUE;
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
l3cd = g_steal_pointer(&self->l3cd);
|
|
Packit Service |
a1bd4f |
if (!nm_l3cfg_remove_config(self->l3cfg, L3CD_TAG(self), l3cd))
|
|
Packit Service |
a1bd4f |
nm_assert_not_reached();
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
nm_l3cfg_commit_type_unregister(self->l3cfg, g_steal_pointer(&self->l3cfg_commit_handle));
|
|
Packit Service |
a1bd4f |
nm_l3cfg_commit_on_idle_schedule(self->l3cfg);
|
|
Packit Service |
a1bd4f |
return TRUE;
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
/*****************************************************************************/
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
static const NMPlatformIP4Address *
|
|
Packit Service |
a1bd4f |
_ipv4ll_platform_ip4_address_lookup(NML3IPv4LL *self, in_addr_t addr)
|
|
Packit Service |
a1bd4f |
{
|
|
Packit Service |
a1bd4f |
const NMPlatformIP4Address *pladdr;
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
if (addr == 0u)
|
|
Packit Service |
a1bd4f |
return NULL;
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
nm_assert(nm_utils_ip4_address_is_link_local(addr));
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
pladdr = nm_platform_ip4_address_get(nm_l3_ipv4ll_get_platform(self),
|
|
Packit Service |
a1bd4f |
nm_l3_ipv4ll_get_ifindex(self),
|
|
Packit Service |
a1bd4f |
addr,
|
|
Packit Service |
a1bd4f |
ADDR_IPV4LL_PREFIX_LEN,
|
|
Packit Service |
a1bd4f |
addr);
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
nm_assert(!pladdr || pladdr->address == addr);
|
|
Packit Service |
a1bd4f |
nm_assert(!pladdr || _ip4_address_is_link_local(pladdr));
|
|
Packit Service |
a1bd4f |
return pladdr;
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
static const NML3AcdAddrInfo *
|
|
Packit Service |
a1bd4f |
_ipv4ll_l3cfg_get_acd_addr_info(NML3IPv4LL *self, in_addr_t addr)
|
|
Packit Service |
a1bd4f |
{
|
|
Packit Service |
a1bd4f |
if (addr == 0u)
|
|
Packit Service |
a1bd4f |
return NULL;
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
nm_assert(nm_utils_ip4_address_is_link_local(addr));
|
|
Packit Service |
a1bd4f |
return nm_l3cfg_get_acd_addr_info(self->l3cfg, addr);
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
static const NMPlatformIP4Address *
|
|
Packit Service |
a1bd4f |
_ipv4ll_platform_find_addr(NML3IPv4LL *self, const NML3AcdAddrInfo **out_acd_info)
|
|
Packit Service |
a1bd4f |
{
|
|
Packit Service |
a1bd4f |
const NMPlatformIP4Address *addr_without_acd_info = NULL;
|
|
Packit Service |
a1bd4f |
NMDedupMultiIter iter;
|
|
Packit Service |
a1bd4f |
NMPLookup lookup;
|
|
Packit Service |
a1bd4f |
const NMPObject * obj;
|
|
Packit Service |
a1bd4f |
const NML3AcdAddrInfo * acd_info;
|
|
Packit Service |
a1bd4f |
const NMPlatformIP4Address *addr;
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
nmp_lookup_init_object(&lookup, NMP_OBJECT_TYPE_IP4_ADDRESS, nm_l3_ipv4ll_get_ifindex(self));
|
|
Packit Service |
a1bd4f |
nm_platform_iter_obj_for_each (&iter, nm_l3_ipv4ll_get_platform(self), &lookup, &obj) {
|
|
Packit Service |
a1bd4f |
addr = NMP_OBJECT_CAST_IP4_ADDRESS(obj);
|
|
Packit Service |
a1bd4f |
if (!_ip4_address_is_link_local(addr))
|
|
Packit Service |
a1bd4f |
continue;
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
acd_info = _ipv4ll_l3cfg_get_acd_addr_info(self, addr->address);
|
|
Packit Service |
a1bd4f |
if (!_acd_info_is_good(acd_info))
|
|
Packit Service |
a1bd4f |
continue;
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
if (acd_info) {
|
|
Packit Service |
a1bd4f |
/* We have a good acd_info. We won't find a better one. Return it. */
|
|
Packit Service |
a1bd4f |
NM_SET_OUT(out_acd_info, acd_info);
|
|
Packit Service |
a1bd4f |
return addr;
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
if (!addr_without_acd_info) {
|
|
Packit Service |
a1bd4f |
/* remember a potential candidate address that has no acd_info. */
|
|
Packit Service |
a1bd4f |
addr_without_acd_info = addr;
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
if (addr_without_acd_info) {
|
|
Packit Service |
a1bd4f |
NM_SET_OUT(out_acd_info, NULL);
|
|
Packit Service |
a1bd4f |
return addr_without_acd_info;
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
return NULL;
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
/*****************************************************************************/
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
static gboolean
|
|
Packit Service |
a1bd4f |
_ipv4ll_set_timed_out_timeout_cb(gpointer user_data)
|
|
Packit Service |
a1bd4f |
{
|
|
Packit Service |
a1bd4f |
NML3IPv4LL *self = user_data;
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
_ipv4ll_set_timed_out_update(self, TIMED_OUT_STATE_IS_TIMED_OUT);
|
|
Packit Service |
a1bd4f |
if (self->notify_on_idle)
|
|
Packit Service |
a1bd4f |
_ipv4ll_emit_signal_notify(self);
|
|
Packit Service |
a1bd4f |
return G_SOURCE_REMOVE;
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
static void
|
|
Packit Service |
a1bd4f |
_ipv4ll_set_timed_out_update(NML3IPv4LL *self, TimedOutState new_state)
|
|
Packit Service |
a1bd4f |
{
|
|
Packit Service |
a1bd4f |
gboolean before;
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
before = _ipv4ll_is_timed_out(self);
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
switch (new_state) {
|
|
Packit Service |
a1bd4f |
case TIMED_OUT_STATE_IS_TIMED_OUT:
|
|
Packit Service |
a1bd4f |
if (self->timed_out_expiry_msec == 0) {
|
|
Packit Service |
a1bd4f |
nm_assert(!self->timed_out_source);
|
|
Packit Service |
a1bd4f |
self->timed_out_expiry_msec = 1;
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
nm_clear_g_source_inst(&self->timed_out_source);
|
|
Packit Service |
a1bd4f |
break;
|
|
Packit Service |
a1bd4f |
case TIMED_OUT_STATE_IS_NOT_TIMED_OUT:
|
|
Packit Service |
a1bd4f |
self->timed_out_expiry_msec = 0;
|
|
Packit Service |
a1bd4f |
nm_clear_g_source_inst(&self->timed_out_source);
|
|
Packit Service |
a1bd4f |
break;
|
|
Packit Service |
a1bd4f |
case TIMED_OUT_STATE_HAVE_TIMER_RUNNING:
|
|
Packit Service |
a1bd4f |
{
|
|
Packit Service |
a1bd4f |
gint64 now_msec = nm_utils_get_monotonic_timestamp_msec();
|
|
Packit Service |
a1bd4f |
guint timeout_msec;
|
|
Packit Service |
a1bd4f |
gint64 expiry_msec;
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
nm_assert(self->reg_timeout_msec > 0u);
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
timeout_msec = nm_mult_clamped_u(TIMED_OUT_TIME_FACTOR, self->reg_timeout_msec);
|
|
Packit Service |
a1bd4f |
expiry_msec = now_msec + timeout_msec;
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
if (self->timed_out_expiry_msec == 0 || self->timed_out_expiry_msec < expiry_msec) {
|
|
Packit Service |
a1bd4f |
self->timed_out_expiry_msec = expiry_msec;
|
|
Packit Service |
a1bd4f |
nm_clear_g_source_inst(&self->timed_out_source);
|
|
Packit Service |
a1bd4f |
self->timed_out_source = nm_g_timeout_source_new(timeout_msec,
|
|
Packit Service |
a1bd4f |
G_PRIORITY_DEFAULT,
|
|
Packit Service |
a1bd4f |
_ipv4ll_set_timed_out_timeout_cb,
|
|
Packit Service |
a1bd4f |
self,
|
|
Packit Service |
a1bd4f |
NULL);
|
|
Packit Service |
a1bd4f |
g_source_attach(self->timed_out_source, NULL);
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
break;
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
if (before != _ipv4ll_is_timed_out(self)) {
|
|
Packit Service |
a1bd4f |
self->notify_on_idle = TRUE;
|
|
Packit Service |
a1bd4f |
_LOGT("state: set timed-out-is-bad=%d", (!before));
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
static gboolean
|
|
Packit Service |
a1bd4f |
_ipv4ll_set_state(NML3IPv4LL *self, NML3IPv4LLState state)
|
|
Packit Service |
a1bd4f |
{
|
|
Packit Service |
a1bd4f |
char sbuf_addr[NM_UTILS_INET_ADDRSTRLEN];
|
|
Packit Service |
a1bd4f |
char sbuf100[100];
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
if (self->state == state)
|
|
Packit Service |
a1bd4f |
return FALSE;
|
|
Packit Service |
a1bd4f |
self->state = state;
|
|
Packit Service |
a1bd4f |
self->notify_on_idle = TRUE;
|
|
Packit Service |
a1bd4f |
_LOGT("state: set state %s (addr=%s)",
|
|
Packit Service |
a1bd4f |
nm_l3_ipv4ll_state_to_string(state, sbuf100, sizeof(sbuf100)),
|
|
Packit Service |
a1bd4f |
_nm_utils_inet4_ntop(self->addr, sbuf_addr));
|
|
Packit Service |
a1bd4f |
return TRUE;
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
static void
|
|
Packit Service |
a1bd4f |
_ipv4ll_state_change(NML3IPv4LL *self, gboolean is_on_idle_handler)
|
|
Packit Service |
a1bd4f |
{
|
|
Packit Service |
a1bd4f |
nm_auto_unref_l3ipv4ll NML3IPv4LL *self_keep_alive = NULL;
|
|
Packit Service |
a1bd4f |
const NMPlatformIP4Address * pladdr;
|
|
Packit Service |
a1bd4f |
const NML3AcdAddrInfo * acd_info;
|
|
Packit Service |
a1bd4f |
gboolean generate_new_addr;
|
|
Packit Service |
a1bd4f |
NML3IPv4LLState new_state;
|
|
Packit Service |
a1bd4f |
in_addr_t addr0;
|
|
Packit Service |
a1bd4f |
NML3IPv4LLRegistration * reg;
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
_ASSERT(self);
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
self_keep_alive = nm_l3_ipv4ll_ref(self);
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
nm_clear_g_source_inst(&self->state_change_on_idle_source);
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
addr0 = self->addr;
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
if (self->reg_changed) {
|
|
Packit Service |
a1bd4f |
guint timeout_msec = self->reg_timeout_msec;
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
self->reg_changed = FALSE;
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
if (c_list_is_empty(&self->reg_lst_head))
|
|
Packit Service |
a1bd4f |
timeout_msec = 0;
|
|
Packit Service |
a1bd4f |
else {
|
|
Packit Service |
a1bd4f |
timeout_msec = G_MAXUINT;
|
|
Packit Service |
a1bd4f |
c_list_for_each_entry (reg, &self->reg_lst_head, reg_lst) {
|
|
Packit Service |
a1bd4f |
if (reg->timeout_msec < timeout_msec)
|
|
Packit Service |
a1bd4f |
timeout_msec = reg->timeout_msec;
|
|
Packit Service |
a1bd4f |
if (reg->timeout_msec == 0)
|
|
Packit Service |
a1bd4f |
break;
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
if (self->reg_timeout_msec != timeout_msec) {
|
|
Packit Service |
a1bd4f |
self->reg_timeout_msec = timeout_msec;
|
|
Packit Service |
a1bd4f |
self->l3cd_timeout_msec_changed = TRUE;
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
if (self->reg_timeout_msec == 0) {
|
|
Packit Service |
a1bd4f |
_ipv4ll_set_timed_out_update(self, TIMED_OUT_STATE_IS_NOT_TIMED_OUT);
|
|
Packit Service |
a1bd4f |
if (_ipv4ll_set_state(self, NM_L3_IPV4LL_STATE_DISABLED))
|
|
Packit Service |
a1bd4f |
_l3cd_config_remove(self);
|
|
Packit Service |
a1bd4f |
goto out_notify;
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
if (!self->mac_set) {
|
|
Packit Service |
a1bd4f |
_ipv4ll_set_timed_out_update(self, TIMED_OUT_STATE_HAVE_TIMER_RUNNING);
|
|
Packit Service |
a1bd4f |
if (_ipv4ll_set_state(self, NM_L3_IPV4LL_STATE_WAIT_FOR_LINK))
|
|
Packit Service |
a1bd4f |
_l3cd_config_remove(self);
|
|
Packit Service |
a1bd4f |
else
|
|
Packit Service |
a1bd4f |
nm_assert(!self->l3cd);
|
|
Packit Service |
a1bd4f |
goto out_notify;
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
if (self->state <= NM_L3_IPV4LL_STATE_EXTERNAL) {
|
|
Packit Service |
a1bd4f |
pladdr = _ipv4ll_platform_ip4_address_lookup(self, self->addr);
|
|
Packit Service |
a1bd4f |
if (pladdr) {
|
|
Packit Service |
a1bd4f |
if (!_acd_info_is_good(_ipv4ll_l3cfg_get_acd_addr_info(self, self->addr)))
|
|
Packit Service |
a1bd4f |
pladdr = NULL;
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
if (!pladdr)
|
|
Packit Service |
a1bd4f |
pladdr = _ipv4ll_platform_find_addr(self, NULL);
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
if (pladdr) {
|
|
Packit Service |
a1bd4f |
/* we have an externally configured address. Check whether we can use it. */
|
|
Packit Service |
a1bd4f |
self->addr = pladdr->address;
|
|
Packit Service |
a1bd4f |
self->notify_on_idle = TRUE;
|
|
Packit Service |
a1bd4f |
_ipv4ll_set_state(self, NM_L3_IPV4LL_STATE_EXTERNAL);
|
|
Packit Service |
a1bd4f |
_l3cd_config_add(self);
|
|
Packit Service |
a1bd4f |
_ipv4ll_set_timed_out_update(self, TIMED_OUT_STATE_IS_NOT_TIMED_OUT);
|
|
Packit Service |
a1bd4f |
goto out_notify;
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
generate_new_addr = FALSE;
|
|
Packit Service |
a1bd4f |
while (TRUE) {
|
|
Packit Service |
a1bd4f |
_ipv4ll_addrgen(self, generate_new_addr);
|
|
Packit Service |
a1bd4f |
acd_info = _ipv4ll_l3cfg_get_acd_addr_info(self, self->addr);
|
|
Packit Service |
a1bd4f |
if (_acd_info_is_good(acd_info))
|
|
Packit Service |
a1bd4f |
break;
|
|
Packit Service |
a1bd4f |
generate_new_addr = TRUE;
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
nm_assert(_acd_info_is_good(acd_info));
|
|
Packit Service |
a1bd4f |
switch (acd_info ? acd_info->state : NM_L3_ACD_ADDR_STATE_INIT) {
|
|
Packit Service |
a1bd4f |
case NM_L3_ACD_ADDR_STATE_INIT:
|
|
Packit Service |
a1bd4f |
case NM_L3_ACD_ADDR_STATE_PROBING:
|
|
Packit Service |
a1bd4f |
new_state = NM_L3_IPV4LL_STATE_PROBING;
|
|
Packit Service |
a1bd4f |
_ipv4ll_set_timed_out_update(self, TIMED_OUT_STATE_HAVE_TIMER_RUNNING);
|
|
Packit Service |
a1bd4f |
goto out_is_good_1;
|
|
Packit Service |
a1bd4f |
case NM_L3_ACD_ADDR_STATE_READY:
|
|
Packit Service |
a1bd4f |
new_state = NM_L3_IPV4LL_STATE_READY;
|
|
Packit Service |
a1bd4f |
_ipv4ll_set_timed_out_update(self, TIMED_OUT_STATE_HAVE_TIMER_RUNNING);
|
|
Packit Service |
a1bd4f |
goto out_is_good_1;
|
|
Packit Service |
a1bd4f |
case NM_L3_ACD_ADDR_STATE_DEFENDING:
|
|
Packit Service |
a1bd4f |
new_state = NM_L3_IPV4LL_STATE_DEFENDING;
|
|
Packit Service |
a1bd4f |
_ipv4ll_set_timed_out_update(self, TIMED_OUT_STATE_IS_NOT_TIMED_OUT);
|
|
Packit Service |
a1bd4f |
goto out_is_good_1;
|
|
Packit Service |
a1bd4f |
case NM_L3_ACD_ADDR_STATE_EXTERNAL_REMOVED:
|
|
Packit Service |
a1bd4f |
case NM_L3_ACD_ADDR_STATE_USED:
|
|
Packit Service |
a1bd4f |
case NM_L3_ACD_ADDR_STATE_CONFLICT:
|
|
Packit Service |
a1bd4f |
nm_assert_not_reached();
|
|
Packit Service |
a1bd4f |
goto out_notify;
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
nm_assert_not_reached();
|
|
Packit Service |
a1bd4f |
goto out_notify;
|
|
Packit Service |
a1bd4f |
out_is_good_1:
|
|
Packit Service |
a1bd4f |
_ipv4ll_set_state(self, new_state);
|
|
Packit Service |
a1bd4f |
_l3cd_config_add(self);
|
|
Packit Service |
a1bd4f |
if (self->addr != addr0)
|
|
Packit Service |
a1bd4f |
self->notify_on_idle = TRUE;
|
|
Packit Service |
a1bd4f |
goto out_notify;
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
out_notify:
|
|
Packit Service |
a1bd4f |
if (self->notify_on_idle) {
|
|
Packit Service |
a1bd4f |
if (is_on_idle_handler)
|
|
Packit Service |
a1bd4f |
_ipv4ll_emit_signal_notify(self);
|
|
Packit Service |
a1bd4f |
else
|
|
Packit Service |
a1bd4f |
_ipv4ll_state_change_on_idle(self);
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
static gboolean
|
|
Packit Service |
a1bd4f |
_ipv4ll_state_change_on_idle_cb(gpointer user_data)
|
|
Packit Service |
a1bd4f |
{
|
|
Packit Service |
a1bd4f |
NML3IPv4LL *self = user_data;
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
_ipv4ll_state_change(self, TRUE);
|
|
Packit Service |
a1bd4f |
return G_SOURCE_REMOVE;
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
static void
|
|
Packit Service |
a1bd4f |
_ipv4ll_state_change_on_idle(NML3IPv4LL *self)
|
|
Packit Service |
a1bd4f |
{
|
|
Packit Service |
a1bd4f |
nm_assert(NM_IS_L3_IPV4LL(self));
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
if (!self->state_change_on_idle_source) {
|
|
Packit Service |
a1bd4f |
self->state_change_on_idle_source =
|
|
Packit Service |
a1bd4f |
nm_g_idle_source_new(G_PRIORITY_DEFAULT, _ipv4ll_state_change_on_idle_cb, self, NULL);
|
|
Packit Service |
a1bd4f |
g_source_attach(self->state_change_on_idle_source, NULL);
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
/*****************************************************************************/
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
static void
|
|
Packit Service |
a1bd4f |
_l3cfg_notify_cb(NML3Cfg *l3cfg, const NML3ConfigNotifyData *notify_data, NML3IPv4LL *self)
|
|
Packit Service |
a1bd4f |
{
|
|
Packit Service |
a1bd4f |
if (notify_data->notify_type == NM_L3_CONFIG_NOTIFY_TYPE_PLATFORM_CHANGE_ON_IDLE) {
|
|
Packit Service |
a1bd4f |
/* NMl3Cfg only reloads the platform link during the idle handler. Pick it up now. */
|
|
Packit Service |
a1bd4f |
_ipv4ll_update_link(self, nm_l3cfg_get_plobj(l3cfg, FALSE));
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
/* theoretically, this even is already on an idle handler. However, we share
|
|
Packit Service |
a1bd4f |
* the call with other signal handlers, so at this point we don't want to
|
|
Packit Service |
a1bd4f |
* emit additional signals. Thus pass %FALSE to _ipv4ll_state_change(). */
|
|
Packit Service |
a1bd4f |
_ipv4ll_state_change(self, FALSE);
|
|
Packit Service |
a1bd4f |
return;
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
if (notify_data->notify_type == NM_L3_CONFIG_NOTIFY_TYPE_ACD_EVENT) {
|
|
Packit Service |
a1bd4f |
if (self->l3cd
|
|
Packit Service |
a1bd4f |
&& nm_l3_acd_addr_info_find_track_info(¬ify_data->acd_event.info,
|
|
Packit Service |
a1bd4f |
L3CD_TAG(self),
|
|
Packit Service |
a1bd4f |
self->l3cd,
|
|
Packit Service |
a1bd4f |
NULL)) {
|
|
Packit Service |
a1bd4f |
_ipv4ll_state_change(self, FALSE);
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
return;
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
/*****************************************************************************/
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
NML3IPv4LL *
|
|
Packit Service |
a1bd4f |
nm_l3_ipv4ll_new(NML3Cfg *l3cfg)
|
|
Packit Service |
a1bd4f |
{
|
|
Packit Service |
a1bd4f |
NML3IPv4LL *self;
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
g_return_val_if_fail(NM_IS_L3CFG(l3cfg), NULL);
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
self = g_slice_new(NML3IPv4LL);
|
|
Packit Service |
a1bd4f |
*self = (NML3IPv4LL){
|
|
Packit Service |
a1bd4f |
.l3cfg = g_object_ref(l3cfg),
|
|
Packit Service |
a1bd4f |
.ref_count = 1,
|
|
Packit Service |
a1bd4f |
.reg_lst_head = C_LIST_INIT(self->reg_lst_head),
|
|
Packit Service |
a1bd4f |
.l3cfg_commit_handle = NULL,
|
|
Packit Service |
a1bd4f |
.state_change_on_idle_source = NULL,
|
|
Packit Service |
a1bd4f |
.l3cd = NULL,
|
|
Packit Service |
a1bd4f |
.plobj = NULL,
|
|
Packit Service |
a1bd4f |
.addr = 0u,
|
|
Packit Service |
a1bd4f |
.state = NM_L3_IPV4LL_STATE_DISABLED,
|
|
Packit Service |
a1bd4f |
.reg_timeout_msec = 0,
|
|
Packit Service |
a1bd4f |
.notify_on_idle = TRUE,
|
|
Packit Service |
a1bd4f |
.l3cfg_signal_notify_id =
|
|
Packit Service |
a1bd4f |
g_signal_connect(l3cfg, NM_L3CFG_SIGNAL_NOTIFY, G_CALLBACK(_l3cfg_notify_cb), self),
|
|
Packit Service |
a1bd4f |
.seed_set = FALSE,
|
|
Packit Service |
a1bd4f |
.seed_reset_generation = FALSE,
|
|
Packit Service |
a1bd4f |
};
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
_LOGT("created: l3cfg=" NM_HASH_OBFUSCATE_PTR_FMT, NM_HASH_OBFUSCATE_PTR(l3cfg));
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
_ipv4ll_update_link(self, nm_l3cfg_get_plobj(l3cfg, FALSE));
|
|
Packit Service |
a1bd4f |
_ipv4ll_state_change(self, FALSE);
|
|
Packit Service |
a1bd4f |
return self;
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
NML3IPv4LL *
|
|
Packit Service |
a1bd4f |
nm_l3_ipv4ll_ref(NML3IPv4LL *self)
|
|
Packit Service |
a1bd4f |
{
|
|
Packit Service |
a1bd4f |
if (!self)
|
|
Packit Service |
a1bd4f |
return NULL;
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
_ASSERT(self);
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
nm_assert(self->ref_count < G_MAXINT);
|
|
Packit Service |
a1bd4f |
self->ref_count++;
|
|
Packit Service |
a1bd4f |
return self;
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
void
|
|
Packit Service |
a1bd4f |
nm_l3_ipv4ll_unref(NML3IPv4LL *self)
|
|
Packit Service |
a1bd4f |
{
|
|
Packit Service |
a1bd4f |
if (!self)
|
|
Packit Service |
a1bd4f |
return;
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
_ASSERT(self);
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
if (--self->ref_count > 0)
|
|
Packit Service |
a1bd4f |
return;
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
if (nm_l3cfg_get_ipv4ll(self->l3cfg) == self)
|
|
Packit Service |
a1bd4f |
_nm_l3cfg_unregister_ipv4ll(self->l3cfg);
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
_LOGT("finalize");
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
nm_assert(c_list_is_empty(&self->reg_lst_head));
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
if (self->l3cd) {
|
|
Packit Service |
a1bd4f |
nm_auto_unref_l3cd const NML3ConfigData *l3cd = NULL;
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
l3cd = g_steal_pointer(&self->l3cd);
|
|
Packit Service |
a1bd4f |
if (!nm_l3cfg_remove_config(self->l3cfg, L3CD_TAG(self), l3cd))
|
|
Packit Service |
a1bd4f |
nm_assert_not_reached();
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
nm_l3cfg_commit_type_unregister(self->l3cfg, g_steal_pointer(&self->l3cfg_commit_handle));
|
|
Packit Service |
a1bd4f |
nm_l3cfg_commit_on_idle_schedule(self->l3cfg);
|
|
Packit Service |
a1bd4f |
} else
|
|
Packit Service |
a1bd4f |
nm_assert(!self->l3cfg_commit_handle);
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
nm_clear_g_source_inst(&self->state_change_on_idle_source);
|
|
Packit Service |
a1bd4f |
nm_clear_g_source_inst(&self->timed_out_source);
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
nm_clear_g_signal_handler(self->l3cfg, &self->l3cfg_signal_notify_id);
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
g_clear_object(&self->l3cfg);
|
|
Packit Service |
a1bd4f |
nmp_object_unref(self->plobj);
|
|
Packit Service |
a1bd4f |
nm_g_slice_free(self);
|
|
Packit Service |
a1bd4f |
}
|