mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git
synced 2026-01-08 01:20:16 +01:00
dhcp: merge branch 'th/dhcp-acd'
https://bugzilla.redhat.com/show_bug.cgi?id=1713380 https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/1230
This commit is contained in:
commit
3079628263
16 changed files with 1193 additions and 442 deletions
|
|
@ -9,14 +9,17 @@ set -e
|
|||
# - build: build a new image, named "$CONTAINER_NAME_REPOSITORY:$CONTAINER_NAME_TAG" ("nm:nm")
|
||||
# - run: start the container and tag it "$CONTAINER_NAME_NAME" ("nm")
|
||||
# - exec: run bash inside the container
|
||||
# - journal|j: print the journal from inside the container
|
||||
# - stop: stop the container
|
||||
# - clean: delete the container and the image.
|
||||
#
|
||||
# Options:
|
||||
# --no-cleanup: don't delete the CONTAINERFILE and other artifacts
|
||||
# --stop: only has effect with "run". It will stop the container afterwards.
|
||||
# -- [COMMAND]: with command "exec", provide a command to run in the container.
|
||||
# Defaults to "bash".
|
||||
# -- [EXTRA_ARGS]:
|
||||
# - with command "exec", provide a command and arguments to run in the container.
|
||||
# Defaults to "bash".
|
||||
# - with command "journal", additional arguments that are passed to journalctl.
|
||||
#
|
||||
# It bind mounts the current working directory inside the container.
|
||||
# You can run `make install` and run tests.
|
||||
|
|
@ -32,11 +35,13 @@ CONTAINER_NAME_REPOSITORY=${CONTAINER_NAME_REPOSITORY:-nm}
|
|||
CONTAINER_NAME_TAG=${CONTAINER_NAME_TAG:-nm}
|
||||
CONTAINER_NAME_NAME=${CONTAINER_NAME_NAME:-nm}
|
||||
|
||||
EXEC_ENV=()
|
||||
|
||||
###############################################################################
|
||||
|
||||
usage() {
|
||||
cat <<EOF
|
||||
$0: build|run|exec|stop|clean [--no-cleanup] [--stop]
|
||||
$0: build|run|exec|stop|clean|journal [--no-cleanup] [--stop] [-- EXTRA_ARGS]
|
||||
EOF
|
||||
echo
|
||||
awk '/^####*$/{ if(on) exit; on=1} { if (on) { if (on==2) print(substr($0,3)); on=2; } }' "$BASH_SOURCE"
|
||||
|
|
@ -167,6 +172,12 @@ alias n="ninja -C build"
|
|||
|
||||
alias l='ls -l --color=auto'
|
||||
|
||||
ulimit -c unlimited
|
||||
|
||||
export G_DEBUG=fatal-warnings
|
||||
|
||||
unset DEBUGINFOD_URLS
|
||||
|
||||
Clean() {
|
||||
systemctl stop NetworkManager
|
||||
rm -i -rf /run/NetworkManager
|
||||
|
|
@ -233,8 +244,8 @@ nmcli connection add type pppoe con-name ppp-net1 ifname ppp-net1 pppoe.parent n
|
|||
for i in {1..9}; do nm-env-prepare.sh --prefix eth -i \$i; done
|
||||
systemctl status NetworkManager
|
||||
systemctl stop NetworkManager
|
||||
systemctl stop NetworkManager; /opt/test/sbin/NetworkManager --debug 2>&1 | tee -a /tmp/nm-log.txt
|
||||
systemctl stop NetworkManager; gdb -ex run --args /opt/test/sbin/NetworkManager --debug
|
||||
systemctl stop NetworkManager; /opt/test/sbin/NetworkManager --debug 2>&1 | tee -a ./nm-log.txt
|
||||
EOF
|
||||
|
||||
cat <<EOF | tmp_file "$BASEDIR/data-gdbinit"
|
||||
|
|
@ -265,6 +276,7 @@ RUN dnf install -y \\
|
|||
bash-completion \\
|
||||
bind-utils \\
|
||||
bluez-libs-devel \\
|
||||
clang-tools-extra \\
|
||||
cscope \\
|
||||
dbus-devel \\
|
||||
dbus-x11 \\
|
||||
|
|
@ -304,6 +316,7 @@ RUN dnf install -y \\
|
|||
ppp-devel \\
|
||||
procps \\
|
||||
python3-behave \\
|
||||
python3-black \\
|
||||
python3-dbus \\
|
||||
python3-devel \\
|
||||
python3-gobject \\
|
||||
|
|
@ -336,6 +349,7 @@ COPY data-nm-env-prepare.sh "/usr/bin/nm-env-prepare.sh"
|
|||
COPY data-motd /etc/motd
|
||||
COPY data-bashrc.my /etc/bashrc.my
|
||||
COPY data-90-my.conf /etc/NetworkManager/conf.d/90-my.conf
|
||||
RUN echo -n "" > /etc/NetworkManager/conf.d/95-user.conf
|
||||
COPY data-bash_history /root/.bash_history
|
||||
COPY data-gdbinit /root/.gdbinit
|
||||
COPY data-gdb_history /root/.gdb_history
|
||||
|
|
@ -421,18 +435,29 @@ do_run() {
|
|||
do_exec() {
|
||||
do_run
|
||||
|
||||
local e
|
||||
local EXTRA_ARGS=("$@")
|
||||
if [ "${#EXTRA_ARGS[@]}" = 0 ]; then
|
||||
EXTRA_ARGS=('bash')
|
||||
fi
|
||||
|
||||
podman exec --workdir "$BASEDIR_NM" -it "$CONTAINER_NAME_NAME" "${EXTRA_ARGS[@]}"
|
||||
local ENV=()
|
||||
for e in "${EXEC_ENV[@]}" ; do
|
||||
ENV+=(-e "$e")
|
||||
done
|
||||
|
||||
podman exec "${ENV[@]}" --workdir "$BASEDIR_NM" -it "$CONTAINER_NAME_NAME" "${EXTRA_ARGS[@]}"
|
||||
|
||||
if [ "$DO_STOP" = 1 ]; then
|
||||
do_stop
|
||||
fi
|
||||
}
|
||||
|
||||
do_journal() {
|
||||
EXEC_ENV+=( "SYSTEMD_COLORS=0" )
|
||||
do_exec "journalctl" --no-pager "$@"
|
||||
}
|
||||
|
||||
do_stop() {
|
||||
container_is_running "$CONTAINER_NAME_NAME" || return 0
|
||||
podman stop "$CONTAINER_NAME_NAME"
|
||||
|
|
@ -453,7 +478,10 @@ for (( i=1 ; i<="$#" ; )) ; do
|
|||
--stop)
|
||||
DO_STOP=1
|
||||
;;
|
||||
build|run|exec|stop|clean)
|
||||
j)
|
||||
CMD=journal
|
||||
;;
|
||||
build|run|exec|stop|clean|journal)
|
||||
CMD=$c
|
||||
;;
|
||||
--)
|
||||
|
|
@ -465,8 +493,13 @@ for (( i=1 ; i<="$#" ; )) ; do
|
|||
exit 0
|
||||
;;
|
||||
*)
|
||||
usage
|
||||
die "invalid argument: $c"
|
||||
if [ "$CMD" = "journal" ]; then
|
||||
EXTRA_ARGS=( "${@:$((i-1))}" )
|
||||
break;
|
||||
else
|
||||
usage
|
||||
die "invalid argument: $c"
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
|
@ -475,7 +508,7 @@ done
|
|||
|
||||
test "$UID" != 0 || die "cannot run as root"
|
||||
|
||||
if test $CMD != exec && test "${#EXTRA_ARGS[@]}" != 0 ; then
|
||||
if test "$CMD" != exec -a "$CMD" != journal -a "${#EXTRA_ARGS[@]}" != 0 ; then
|
||||
die "Extra arguments are only allowed with exec command"
|
||||
fi
|
||||
|
||||
|
|
|
|||
|
|
@ -10296,7 +10296,11 @@ _dev_ipdhcpx_start(NMDevice *self, int addr_family)
|
|||
.vendor_class_identifier = vendor_class_identifier,
|
||||
.use_fqdn = hostname_is_fqdn,
|
||||
.reject_servers = reject_servers,
|
||||
.v4.request_broadcast = request_broadcast,
|
||||
.v4 =
|
||||
{
|
||||
.request_broadcast = request_broadcast,
|
||||
.acd_timeout_msec = _prop_get_ipv4_dad_timeout(self),
|
||||
},
|
||||
};
|
||||
|
||||
priv->ipdhcp_data_4.client =
|
||||
|
|
@ -10311,22 +10315,25 @@ _dev_ipdhcpx_start(NMDevice *self, int addr_family)
|
|||
duid = _prop_get_ipv6_dhcp_duid(self, connection, hwaddr, &enforce_duid);
|
||||
|
||||
config = (NMDhcpClientConfig){
|
||||
.addr_family = AF_INET6,
|
||||
.l3cfg = nm_device_get_l3cfg(self),
|
||||
.iface = nm_device_get_ip_iface(self),
|
||||
.uuid = nm_connection_get_uuid(connection),
|
||||
.send_hostname = nm_setting_ip_config_get_dhcp_send_hostname(s_ip),
|
||||
.hostname = nm_setting_ip_config_get_dhcp_hostname(s_ip),
|
||||
.hostname_flags = _prop_get_ipvx_dhcp_hostname_flags(self, AF_INET6),
|
||||
.client_id = duid,
|
||||
.mud_url = _prop_get_connection_mud_url(self, s_con),
|
||||
.timeout = no_lease_timeout_sec,
|
||||
.anycast_address = _device_get_dhcp_anycast_address(self),
|
||||
.v6.enforce_duid = enforce_duid,
|
||||
.v6.iaid = iaid,
|
||||
.v6.iaid_explicit = iaid_explicit,
|
||||
.v6.info_only = (priv->ipdhcp_data_6.v6.mode == NM_NDISC_DHCP_LEVEL_OTHERCONF),
|
||||
.v6.needed_prefixes = priv->ipdhcp_data_6.v6.needed_prefixes,
|
||||
.addr_family = AF_INET6,
|
||||
.l3cfg = nm_device_get_l3cfg(self),
|
||||
.iface = nm_device_get_ip_iface(self),
|
||||
.uuid = nm_connection_get_uuid(connection),
|
||||
.send_hostname = nm_setting_ip_config_get_dhcp_send_hostname(s_ip),
|
||||
.hostname = nm_setting_ip_config_get_dhcp_hostname(s_ip),
|
||||
.hostname_flags = _prop_get_ipvx_dhcp_hostname_flags(self, AF_INET6),
|
||||
.client_id = duid,
|
||||
.mud_url = _prop_get_connection_mud_url(self, s_con),
|
||||
.timeout = no_lease_timeout_sec,
|
||||
.anycast_address = _device_get_dhcp_anycast_address(self),
|
||||
.v6 =
|
||||
{
|
||||
.enforce_duid = enforce_duid,
|
||||
.iaid = iaid,
|
||||
.iaid_explicit = iaid_explicit,
|
||||
.info_only = (priv->ipdhcp_data_6.v6.mode == NM_NDISC_DHCP_LEVEL_OTHERCONF),
|
||||
.needed_prefixes = priv->ipdhcp_data_6.v6.needed_prefixes,
|
||||
},
|
||||
};
|
||||
|
||||
priv->ipdhcp_data_6.client =
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -84,15 +84,6 @@ typedef struct {
|
|||
|
||||
const char *nm_dhcp_client_event_type_to_string(NMDhcpClientEventType client_event_type);
|
||||
|
||||
/* FIXME(l3cfg:dhcp:config): nm_dhcp_manager_start_ip[46]() has a gazillion of parameters,
|
||||
* those get passed on as CONSTRUCT_ONLY properties to the NMDhcpClient. Drop
|
||||
* all these parameters, and let the caller provide one NMDhcpClientConfig
|
||||
* instance. There will be only one GObject property (NM_DHCP_CLIENT_CONFIG),
|
||||
* which is CONSTRUCT_ONLY and takes a (mandatory) G_TYPE_POINTER for the
|
||||
* configuration.
|
||||
*
|
||||
* Since NMDhcpClientConfig has an addr_family, we also don't need separate
|
||||
* nm_dhcp_manager_start_ip[46]() methods. */
|
||||
typedef struct {
|
||||
int addr_family;
|
||||
|
||||
|
|
@ -156,12 +147,17 @@ typedef struct {
|
|||
|
||||
union {
|
||||
struct {
|
||||
/* The address from the previous lease */
|
||||
const char *last_address;
|
||||
|
||||
/* Whether to do ACD for the DHCPv4 address. With timeout zero, ACD
|
||||
* is disabled. */
|
||||
guint acd_timeout_msec;
|
||||
|
||||
/* Set BOOTP broadcast flag in request packets, so that servers
|
||||
* will always broadcast replies. */
|
||||
bool request_broadcast : 1;
|
||||
|
||||
/* The address from the previous lease */
|
||||
const char *last_address;
|
||||
} v4;
|
||||
struct {
|
||||
/* If set, the DUID from the connection is used; otherwise
|
||||
|
|
@ -208,9 +204,12 @@ typedef struct {
|
|||
|
||||
gboolean (*ip4_start)(NMDhcpClient *self, GError **error);
|
||||
|
||||
gboolean (*accept)(NMDhcpClient *self, GError **error);
|
||||
gboolean (*accept)(NMDhcpClient *self, const NML3ConfigData *l3cd, GError **error);
|
||||
|
||||
gboolean (*decline)(NMDhcpClient *self, const char *error_message, GError **error);
|
||||
gboolean (*decline)(NMDhcpClient *self,
|
||||
const NML3ConfigData *l3cd,
|
||||
const char *error_message,
|
||||
GError **error);
|
||||
|
||||
gboolean (*ip6_start)(NMDhcpClient *self, const struct in6_addr *ll_addr, GError **error);
|
||||
|
||||
|
|
@ -249,11 +248,6 @@ nm_dhcp_client_get_lease(NMDhcpClient *self)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
gboolean nm_dhcp_client_accept(NMDhcpClient *self, GError **error);
|
||||
gboolean nm_dhcp_client_can_accept(NMDhcpClient *self);
|
||||
|
||||
gboolean nm_dhcp_client_decline(NMDhcpClient *self, const char *error_message, GError **error);
|
||||
|
||||
void nm_dhcp_client_stop(NMDhcpClient *self, gboolean release);
|
||||
|
||||
/* Backend helpers for subclasses */
|
||||
|
|
@ -271,12 +265,15 @@ void _nm_dhcp_client_notify(NMDhcpClient *self,
|
|||
NMDhcpClientEventType client_event_type,
|
||||
const NML3ConfigData *l3cd);
|
||||
|
||||
gboolean nm_dhcp_client_handle_event(gpointer unused,
|
||||
const char *iface,
|
||||
int pid,
|
||||
GVariant *options,
|
||||
const char *reason,
|
||||
NMDhcpClient *self);
|
||||
gboolean _nm_dhcp_client_accept_offer(NMDhcpClient *self, gconstpointer p_yiaddr);
|
||||
|
||||
gboolean nm_dhcp_client_handle_event(gpointer unused,
|
||||
const char *iface,
|
||||
int pid,
|
||||
GVariant *options,
|
||||
const char *reason,
|
||||
GDBusMethodInvocation *invocation,
|
||||
NMDhcpClient *self);
|
||||
|
||||
void nm_dhcp_client_emit_ipv6_prefix_delegated(NMDhcpClient *self,
|
||||
const NMPlatformIP6Address *prefix);
|
||||
|
|
|
|||
|
|
@ -100,32 +100,20 @@ next:;
|
|||
return g_variant_ref_sink(g_variant_new("(a{sv})", &builder));
|
||||
}
|
||||
|
||||
static void
|
||||
kill_pid(void)
|
||||
{
|
||||
const char *pid_str;
|
||||
pid_t pid = 0;
|
||||
|
||||
pid_str = getenv("pid");
|
||||
if (pid_str)
|
||||
pid = strtol(pid_str, NULL, 10);
|
||||
if (pid) {
|
||||
_LOGI("a fatal error occurred, kill dhclient instance with pid %d", pid);
|
||||
kill(pid, SIGTERM);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
gs_unref_object GDBusConnection *connection = NULL;
|
||||
gs_free_error GError *error = NULL;
|
||||
gs_unref_variant GVariant *parameters = NULL;
|
||||
gs_unref_variant GVariant *result = NULL;
|
||||
gboolean success = FALSE;
|
||||
gs_unref_object GDBusConnection *connection = NULL;
|
||||
gs_free_error GError *error = NULL;
|
||||
gs_free_error GError *error_flush = NULL;
|
||||
gs_unref_variant GVariant *parameters = NULL;
|
||||
gs_unref_variant GVariant *result = NULL;
|
||||
gs_free char *s_err = NULL;
|
||||
gboolean success;
|
||||
guint try_count;
|
||||
gint64 time_start;
|
||||
gint64 time_end;
|
||||
gint64 remaining_time;
|
||||
|
||||
/* Connecting to the unix socket can fail with EAGAIN if there are too
|
||||
* many pending connections and the server can't accept them in time
|
||||
|
|
@ -136,6 +124,8 @@ main(int argc, char *argv[])
|
|||
time_end = time_start + (5000 * 1000L);
|
||||
try_count = 0;
|
||||
|
||||
_LOGi("nm-dhcp-helper: event called");
|
||||
|
||||
do_connect:
|
||||
try_count++;
|
||||
connection =
|
||||
|
|
@ -146,16 +136,16 @@ do_connect:
|
|||
&error);
|
||||
if (!connection) {
|
||||
if (g_error_matches(error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK)) {
|
||||
gint64 time_remaining = time_end - g_get_monotonic_time();
|
||||
gint64 interval;
|
||||
remaining_time = time_end - g_get_monotonic_time();
|
||||
if (remaining_time > 0) {
|
||||
gint64 interval;
|
||||
|
||||
if (time_remaining > 0) {
|
||||
_LOGi("failure to connect: %s (retry %u, waited %lld ms)",
|
||||
error->message,
|
||||
try_count,
|
||||
(long long) (time_end - time_remaining - time_start) / 1000);
|
||||
(long long) (time_end - remaining_time - time_start) / 1000);
|
||||
interval = NM_CLAMP((gint64) (100L * (1L << NM_MIN(try_count, 31))), 5000, 100000);
|
||||
g_usleep(NM_MIN(interval, time_remaining));
|
||||
g_usleep(NM_MIN(interval, remaining_time));
|
||||
g_clear_error(&error);
|
||||
goto do_connect;
|
||||
}
|
||||
|
|
@ -163,6 +153,7 @@ do_connect:
|
|||
|
||||
g_dbus_error_strip_remote_error(error);
|
||||
_LOGE("could not connect to NetworkManager D-Bus socket: %s", error->message);
|
||||
success = FALSE;
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
|
@ -180,63 +171,78 @@ do_notify:
|
|||
parameters,
|
||||
NULL,
|
||||
G_DBUS_CALL_FLAGS_NONE,
|
||||
1000,
|
||||
60000,
|
||||
NULL,
|
||||
&error);
|
||||
|
||||
if (!result) {
|
||||
gs_free char *s_err = NULL;
|
||||
|
||||
s_err = g_dbus_error_get_remote_error(error);
|
||||
if (NM_IN_STRSET(s_err, "org.freedesktop.DBus.Error.UnknownMethod")) {
|
||||
gint64 remaining_time = time_end - g_get_monotonic_time();
|
||||
gint64 interval;
|
||||
|
||||
/* I am not sure that a race can actually happen, as we register the object
|
||||
* on the server side during GDBusServer:new-connection signal.
|
||||
*
|
||||
* However, there was also a race for subscribing to an event, so let's just
|
||||
* do some retry. */
|
||||
if (remaining_time > 0) {
|
||||
_LOGi("failure to call notify: %s (retry %u)", error->message, try_count);
|
||||
interval = NM_CLAMP((gint64) (100L * (1L << NM_MIN(try_count, 31))), 5000, 25000);
|
||||
g_usleep(NM_MIN(interval, remaining_time));
|
||||
g_clear_error(&error);
|
||||
goto do_notify;
|
||||
}
|
||||
}
|
||||
_LOGW("failure to call notify: %s (try signal via Event)", error->message);
|
||||
g_clear_error(&error);
|
||||
|
||||
/* for backward compatibility, try to emit the signal. There is no stable
|
||||
* API between the dhcp-helper and NetworkManager. However, while upgrading
|
||||
* the NetworkManager package, a newer helper might want to notify an
|
||||
* older server, which still uses the "Event". */
|
||||
if (!g_dbus_connection_emit_signal(connection,
|
||||
NULL,
|
||||
"/",
|
||||
NM_DHCP_CLIENT_DBUS_IFACE,
|
||||
"Event",
|
||||
parameters,
|
||||
&error)) {
|
||||
g_dbus_error_strip_remote_error(error);
|
||||
_LOGE("could not send DHCP Event signal: %s", error->message);
|
||||
goto out;
|
||||
}
|
||||
/* We were able to send the asynchronous Event. Consider that a success. */
|
||||
success = TRUE;
|
||||
} else
|
||||
if (result) {
|
||||
success = TRUE;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!g_dbus_connection_flush_sync(connection, NULL, &error)) {
|
||||
g_dbus_error_strip_remote_error(error);
|
||||
_LOGE("could not flush D-Bus connection: %s", error->message);
|
||||
s_err = g_dbus_error_get_remote_error(error);
|
||||
|
||||
if (NM_IN_STRSET(s_err, "org.freedesktop.NetworkManager.Device.Failed")) {
|
||||
_LOGi("notify failed with reason: %s", error->message);
|
||||
success = FALSE;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!NM_IN_STRSET(s_err, "org.freedesktop.DBus.Error.UnknownMethod")) {
|
||||
/* Some unexpected error. We treat that as a failure. In particular,
|
||||
* the daemon will fail the request if ACD fails. This causes nm-dhcp-helper
|
||||
* to fail, which in turn causes dhclient to send a DECLINE. */
|
||||
_LOGW("failure to call notify: %s (try signal via Event)", error->message);
|
||||
success = FALSE;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* I am not sure that a race can actually happen, as we register the object
|
||||
* on the server side during GDBusServer:new-connection signal.
|
||||
*
|
||||
* However, there was also a race for subscribing to an event, so let's just
|
||||
* do some retry. */
|
||||
remaining_time = time_end - g_get_monotonic_time();
|
||||
if (remaining_time > 0) {
|
||||
gint64 interval;
|
||||
|
||||
_LOGi("failure to call notify: %s (retry %u)", error->message, try_count);
|
||||
interval = NM_CLAMP((gint64) (100L * (1L << NM_MIN(try_count, 31))), 5000, 25000);
|
||||
g_usleep(NM_MIN(interval, remaining_time));
|
||||
g_clear_error(&error);
|
||||
goto do_notify;
|
||||
}
|
||||
|
||||
/* for backward compatibility, try to emit the signal. There is no stable
|
||||
* API between the dhcp-helper and NetworkManager. However, while upgrading
|
||||
* the NetworkManager package, a newer helper might want to notify an
|
||||
* older server, which still uses the "Event". */
|
||||
|
||||
_LOGW("failure to call notify: %s (try signal via Event)", error->message);
|
||||
g_clear_error(&error);
|
||||
|
||||
if (g_dbus_connection_emit_signal(connection,
|
||||
NULL,
|
||||
"/",
|
||||
NM_DHCP_CLIENT_DBUS_IFACE,
|
||||
"Event",
|
||||
parameters,
|
||||
&error)) {
|
||||
/* We were able to send the asynchronous Event. Consider that a success. */
|
||||
success = TRUE;
|
||||
goto out;
|
||||
}
|
||||
|
||||
g_dbus_error_strip_remote_error(error);
|
||||
_LOGE("could not send DHCP Event signal: %s", error->message);
|
||||
success = FALSE;
|
||||
|
||||
out:
|
||||
if (!success)
|
||||
kill_pid();
|
||||
if (!g_dbus_connection_flush_sync(connection, NULL, &error_flush)) {
|
||||
_LOGE("could not flush D-Bus connection: %s", error_flush->message);
|
||||
/* if we considered this a success so far, don't fail because of this. */
|
||||
}
|
||||
|
||||
_LOGi("success: %s", success ? "YES" : "NO");
|
||||
return success ? EXIT_SUCCESS : EXIT_FAILURE;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -128,7 +128,7 @@ get_option(GVariant *options, const char *key)
|
|||
}
|
||||
|
||||
static void
|
||||
_method_call_handle(NMDhcpListener *self, GVariant *parameters)
|
||||
_method_call_handle(NMDhcpListener *self, GDBusMethodInvocation *invocation, GVariant *parameters)
|
||||
{
|
||||
gs_free char *iface = NULL;
|
||||
gs_free char *pid_str = NULL;
|
||||
|
|
@ -142,23 +142,23 @@ _method_call_handle(NMDhcpListener *self, GVariant *parameters)
|
|||
iface = get_option(options, "interface");
|
||||
if (iface == NULL) {
|
||||
_LOGW("dhcp-event: didn't have associated interface.");
|
||||
return;
|
||||
goto out;
|
||||
}
|
||||
|
||||
pid_str = get_option(options, "pid");
|
||||
pid = _nm_utils_ascii_str_to_int64(pid_str, 10, 0, G_MAXINT32, -1);
|
||||
if (pid == -1) {
|
||||
_LOGW("dhcp-event: couldn't convert PID '%s' to an integer", pid_str ?: "(null)");
|
||||
return;
|
||||
goto out;
|
||||
}
|
||||
|
||||
reason = get_option(options, "reason");
|
||||
if (reason == NULL) {
|
||||
_LOGW("dhcp-event: (pid %d) DHCP event didn't have a reason", pid);
|
||||
return;
|
||||
goto out;
|
||||
}
|
||||
|
||||
g_signal_emit(self, signals[EVENT], 0, iface, pid, options, reason, &handled);
|
||||
g_signal_emit(self, signals[EVENT], 0, iface, pid, options, reason, invocation, &handled);
|
||||
if (!handled) {
|
||||
if (g_ascii_strcasecmp(reason, "RELEASE") == 0) {
|
||||
/* Ignore event when the dhcp client gets killed and we receive its last message */
|
||||
|
|
@ -166,6 +166,10 @@ _method_call_handle(NMDhcpListener *self, GVariant *parameters)
|
|||
} else
|
||||
_LOGW("dhcp-event: (pid %d) unhandled DHCP event for interface %s", pid, iface);
|
||||
}
|
||||
|
||||
out:
|
||||
if (!handled)
|
||||
g_dbus_method_invocation_return_value(invocation, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -190,8 +194,7 @@ _method_call(GDBusConnection *connection,
|
|||
return;
|
||||
}
|
||||
|
||||
_method_call_handle(self, parameters);
|
||||
g_dbus_method_invocation_return_value(invocation, NULL);
|
||||
_method_call_handle(self, invocation, parameters);
|
||||
}
|
||||
|
||||
static GDBusInterfaceInfo *const interface_info = NM_DEFINE_GDBUS_INTERFACE_INFO(
|
||||
|
|
@ -311,9 +314,10 @@ nm_dhcp_listener_class_init(NMDhcpListenerClass *listener_class)
|
|||
NULL,
|
||||
NULL,
|
||||
G_TYPE_BOOLEAN, /* listeners return TRUE if handled */
|
||||
4,
|
||||
5,
|
||||
G_TYPE_STRING, /* iface */
|
||||
G_TYPE_INT, /* pid */
|
||||
G_TYPE_VARIANT, /* options */
|
||||
G_TYPE_STRING); /* reason */
|
||||
G_TYPE_STRING, /* reason */
|
||||
G_TYPE_DBUS_METHOD_INVOCATION /* invocation*/);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -42,6 +42,30 @@ G_DEFINE_TYPE(NMDhcpManager, nm_dhcp_manager, G_TYPE_OBJECT)
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
#undef _NMLOG_ENABLED
|
||||
#define _NMLOG_ENABLED(level, addr_family) nm_logging_enabled((level), _LOGD_DHCP(addr_family))
|
||||
|
||||
#define _NMLOG(level, addr_family, ...) \
|
||||
G_STMT_START \
|
||||
{ \
|
||||
const int _addr_family = (addr_family); \
|
||||
const NMLogLevel _log_level = (level); \
|
||||
const NMLogDomain _log_domain = LOGD_DHCP_af(_addr_family); \
|
||||
\
|
||||
if (nm_logging_enabled(_log_level, _log_domain)) { \
|
||||
_nm_log(_log_level, \
|
||||
_log_domain, \
|
||||
0, \
|
||||
NULL, \
|
||||
NULL, \
|
||||
"dhcp%s: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \
|
||||
nm_utils_addr_family_to_str(_addr_family) _NM_UTILS_MACRO_REST(__VA_ARGS__)); \
|
||||
} \
|
||||
} \
|
||||
G_STMT_END
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/* default to installed helper, but can be modified for testing */
|
||||
const char *nm_dhcp_helper_path = LIBEXECDIR "/nm-dhcp-helper";
|
||||
|
||||
|
|
@ -167,11 +191,10 @@ nm_dhcp_manager_start_client(NMDhcpManager *self, NMDhcpClientConfig *config, GE
|
|||
|
||||
gtype = _client_factory_get_gtype(priv->client_factory, config->addr_family);
|
||||
|
||||
nm_log_trace(LOGD_DHCP,
|
||||
"dhcp%c: creating IPv%c DHCP client of type %s",
|
||||
nm_utils_addr_family_to_char(config->addr_family),
|
||||
nm_utils_addr_family_to_char(config->addr_family),
|
||||
g_type_name(gtype));
|
||||
_LOGT(config->addr_family,
|
||||
"creating IPv%c DHCP client of type %s",
|
||||
nm_utils_addr_family_to_char(config->addr_family),
|
||||
g_type_name(gtype));
|
||||
|
||||
client = g_object_new(gtype, NM_DHCP_CLIENT_CONFIG, config, NULL);
|
||||
|
||||
|
|
@ -244,11 +267,11 @@ nm_dhcp_manager_init(NMDhcpManager *self)
|
|||
if (!f)
|
||||
continue;
|
||||
|
||||
nm_log_dbg(LOGD_DHCP,
|
||||
"dhcp-init: enabled DHCP client '%s'%s%s",
|
||||
f->name,
|
||||
_client_factory_available(f) ? "" : " (not available)",
|
||||
f->undocumented ? " (undocumented internal plugin)" : "");
|
||||
_LOGD(AF_UNSPEC,
|
||||
"init: enabled DHCP client '%s'%s%s",
|
||||
f->name,
|
||||
_client_factory_available(f) ? "" : " (not available)",
|
||||
f->undocumented ? " (undocumented internal plugin)" : "");
|
||||
}
|
||||
|
||||
/* Client-specific setup */
|
||||
|
|
@ -261,20 +284,20 @@ nm_dhcp_manager_init(NMDhcpManager *self)
|
|||
if (client) {
|
||||
client_factory = _client_factory_available(_client_factory_find_by_name(client));
|
||||
if (!client_factory)
|
||||
nm_log_warn(LOGD_DHCP, "dhcp-init: DHCP client '%s' not available", client);
|
||||
_LOGW(AF_UNSPEC, "init: DHCP client '%s' not available", client);
|
||||
}
|
||||
if (!client_factory) {
|
||||
client_factory = _client_factory_find_by_name("" NM_CONFIG_DEFAULT_MAIN_DHCP);
|
||||
if (!client_factory)
|
||||
nm_log_err(LOGD_DHCP,
|
||||
"dhcp-init: default DHCP client '%s' is not installed",
|
||||
NM_CONFIG_DEFAULT_MAIN_DHCP);
|
||||
_LOGE(AF_UNSPEC,
|
||||
"init: default DHCP client '%s' is not installed",
|
||||
NM_CONFIG_DEFAULT_MAIN_DHCP);
|
||||
else {
|
||||
client_factory = _client_factory_available(client_factory);
|
||||
if (!client_factory)
|
||||
nm_log_info(LOGD_DHCP,
|
||||
"dhcp-init: default DHCP client '%s' is not available",
|
||||
NM_CONFIG_DEFAULT_MAIN_DHCP);
|
||||
_LOGI(AF_UNSPEC,
|
||||
"init: default DHCP client '%s' is not available",
|
||||
NM_CONFIG_DEFAULT_MAIN_DHCP);
|
||||
}
|
||||
}
|
||||
if (!client_factory) {
|
||||
|
|
@ -287,7 +310,7 @@ nm_dhcp_manager_init(NMDhcpManager *self)
|
|||
|
||||
g_return_if_fail(client_factory);
|
||||
|
||||
nm_log_info(LOGD_DHCP, "dhcp-init: Using DHCP client '%s'", client_factory->name);
|
||||
_LOGI(AF_UNSPEC, "init: Using DHCP client '%s'", client_factory->name);
|
||||
|
||||
/* NOTE: currently the DHCP plugin is chosen once at start. It's not
|
||||
* possible to reload that configuration. If that ever becomes possible,
|
||||
|
|
|
|||
|
|
@ -52,9 +52,16 @@ typedef struct _NMDhcpNettoolsClass NMDhcpNettoolsClass;
|
|||
typedef struct {
|
||||
NDhcp4Client *client;
|
||||
NDhcp4ClientProbe *probe;
|
||||
NDhcp4ClientLease *lease;
|
||||
GSource *event_source;
|
||||
char *lease_file;
|
||||
|
||||
struct {
|
||||
NDhcp4ClientLease *lease;
|
||||
const NML3ConfigData *lease_l3cd;
|
||||
} granted;
|
||||
|
||||
GSource *pop_all_events_on_idle_source;
|
||||
|
||||
GSource *event_source;
|
||||
char *lease_file;
|
||||
} NMDhcpNettoolsPrivate;
|
||||
|
||||
struct _NMDhcpNettools {
|
||||
|
|
@ -73,6 +80,10 @@ G_DEFINE_TYPE(NMDhcpNettools, nm_dhcp_nettools, NM_TYPE_DHCP_CLIENT)
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
static void dhcp4_event_pop_all_events_on_idle(NMDhcpNettools *self);
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
static void
|
||||
set_error_nettools(GError **error, int r, const char *message)
|
||||
{
|
||||
|
|
@ -864,15 +875,19 @@ lease_save(NMDhcpNettools *self, NDhcp4ClientLease *lease, const char *lease_fil
|
|||
}
|
||||
|
||||
static void
|
||||
bound4_handle(NMDhcpNettools *self, NDhcp4ClientLease *lease, gboolean extended)
|
||||
bound4_handle(NMDhcpNettools *self, guint event, NDhcp4ClientLease *lease)
|
||||
{
|
||||
NMDhcpNettoolsPrivate *priv = NM_DHCP_NETTOOLS_GET_PRIVATE(self);
|
||||
NMDhcpClient *client = NM_DHCP_CLIENT(self);
|
||||
const NMDhcpClientConfig *client_config;
|
||||
nm_auto_unref_l3cd_init NML3ConfigData *l3cd = NULL;
|
||||
GError *error = NULL;
|
||||
gs_free_error GError *error = NULL;
|
||||
|
||||
nm_assert(NM_IN_SET(event, N_DHCP4_CLIENT_EVENT_GRANTED, N_DHCP4_CLIENT_EVENT_EXTENDED));
|
||||
nm_assert(lease);
|
||||
|
||||
_LOGT("lease available (%s)", (event == N_DHCP4_CLIENT_EVENT_GRANTED) ? "granted" : "extended");
|
||||
|
||||
_LOGT("lease available (%s)", extended ? "extended" : "new");
|
||||
client_config = nm_dhcp_client_get_config(client);
|
||||
l3cd = lease_to_ip4_config(nm_dhcp_client_get_multi_idx(client),
|
||||
client_config->iface,
|
||||
|
|
@ -881,36 +896,65 @@ bound4_handle(NMDhcpNettools *self, NDhcp4ClientLease *lease, gboolean extended)
|
|||
&error);
|
||||
if (!l3cd) {
|
||||
_LOGW("failure to parse lease: %s", error->message);
|
||||
g_clear_error(&error);
|
||||
|
||||
if (event == N_DHCP4_CLIENT_EVENT_GRANTED) {
|
||||
n_dhcp4_client_lease_decline(lease, "invalid lease");
|
||||
dhcp4_event_pop_all_events_on_idle(self);
|
||||
}
|
||||
|
||||
_nm_dhcp_client_notify(NM_DHCP_CLIENT(self), NM_DHCP_CLIENT_EVENT_TYPE_FAIL, NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
lease_save(self, lease, priv->lease_file);
|
||||
if (event == N_DHCP4_CLIENT_EVENT_GRANTED) {
|
||||
priv->granted.lease = n_dhcp4_client_lease_ref(lease);
|
||||
priv->granted.lease_l3cd = nm_l3_config_data_ref(l3cd);
|
||||
} else
|
||||
lease_save(self, lease, priv->lease_file);
|
||||
|
||||
_nm_dhcp_client_notify(NM_DHCP_CLIENT(self),
|
||||
extended ? NM_DHCP_CLIENT_EVENT_TYPE_EXTENDED
|
||||
: NM_DHCP_CLIENT_EVENT_TYPE_BOUND,
|
||||
event == N_DHCP4_CLIENT_EVENT_GRANTED
|
||||
? NM_DHCP_CLIENT_EVENT_TYPE_BOUND
|
||||
: NM_DHCP_CLIENT_EVENT_TYPE_EXTENDED,
|
||||
l3cd);
|
||||
}
|
||||
|
||||
static void
|
||||
dhcp4_event_handle(NMDhcpNettools *self, NDhcp4ClientEvent *event)
|
||||
{
|
||||
NMDhcpNettoolsPrivate *priv = NM_DHCP_NETTOOLS_GET_PRIVATE(self);
|
||||
const NMDhcpClientConfig *client_config;
|
||||
struct in_addr server_id;
|
||||
char addr_str[INET_ADDRSTRLEN];
|
||||
int r;
|
||||
NMDhcpNettoolsPrivate *priv = NM_DHCP_NETTOOLS_GET_PRIVATE(self);
|
||||
struct in_addr server_id;
|
||||
struct in_addr yiaddr;
|
||||
char addr_str[INET_ADDRSTRLEN];
|
||||
char addr_str2[INET_ADDRSTRLEN];
|
||||
int r;
|
||||
|
||||
_LOGT("client event %d", event->event);
|
||||
client_config = nm_dhcp_client_get_config(NM_DHCP_CLIENT(self));
|
||||
if (event->event == N_DHCP4_CLIENT_EVENT_LOG) {
|
||||
_NMLOG(nm_log_level_from_syslog(event->log.level), "event: %s", event->log.message);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!NM_IN_SET(event->event, N_DHCP4_CLIENT_EVENT_LOG)) {
|
||||
/* In almost all events (even those that we don't expect below), we clear
|
||||
* the currently granted lease. That is, because in GRANTED state we
|
||||
* expect to follow up with accept/decline, and that only works while
|
||||
* we are still in the same state. Transitioning away to another state
|
||||
* (on most events) will invalidate that. */
|
||||
nm_clear_pointer(&priv->granted.lease, n_dhcp4_client_lease_unref);
|
||||
nm_clear_l3cd(&priv->granted.lease_l3cd);
|
||||
}
|
||||
|
||||
switch (event->event) {
|
||||
case N_DHCP4_CLIENT_EVENT_OFFER:
|
||||
r = n_dhcp4_client_lease_get_server_identifier(event->offer.lease, &server_id);
|
||||
if (r) {
|
||||
_LOGW("selecting lease failed: %d", r);
|
||||
_LOGW("selecting lease failed: could not get DHCP server identifier (%d)", r);
|
||||
return;
|
||||
}
|
||||
|
||||
n_dhcp4_client_lease_get_yiaddr(event->offer.lease, &yiaddr);
|
||||
if (yiaddr.s_addr == INADDR_ANY) {
|
||||
_LOGD("selecting lease failed: no yiaddr address");
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -920,47 +964,102 @@ dhcp4_event_handle(NMDhcpNettools *self, NDhcp4ClientEvent *event)
|
|||
return;
|
||||
}
|
||||
|
||||
if (!_nm_dhcp_client_accept_offer(NM_DHCP_CLIENT(self), &yiaddr.s_addr)) {
|
||||
/* We don't log about this, the parent class is expected to notify about the reasons. */
|
||||
return;
|
||||
}
|
||||
|
||||
_LOGT("selecting offered lease from %s for %s",
|
||||
_nm_utils_inet4_ntop(server_id.s_addr, addr_str),
|
||||
_nm_utils_inet4_ntop(yiaddr.s_addr, addr_str2));
|
||||
|
||||
r = n_dhcp4_client_lease_select(event->offer.lease);
|
||||
|
||||
dhcp4_event_pop_all_events_on_idle(self);
|
||||
|
||||
if (r) {
|
||||
_LOGW("selecting lease failed: %d", r);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
return;
|
||||
case N_DHCP4_CLIENT_EVENT_RETRACTED:
|
||||
case N_DHCP4_CLIENT_EVENT_EXPIRED:
|
||||
_nm_dhcp_client_notify(NM_DHCP_CLIENT(self), NM_DHCP_CLIENT_EVENT_TYPE_EXPIRE, NULL);
|
||||
break;
|
||||
return;
|
||||
case N_DHCP4_CLIENT_EVENT_CANCELLED:
|
||||
_nm_dhcp_client_notify(NM_DHCP_CLIENT(self), NM_DHCP_CLIENT_EVENT_TYPE_FAIL, NULL);
|
||||
break;
|
||||
return;
|
||||
case N_DHCP4_CLIENT_EVENT_GRANTED:
|
||||
priv->lease = n_dhcp4_client_lease_ref(event->granted.lease);
|
||||
bound4_handle(self, event->granted.lease, FALSE);
|
||||
break;
|
||||
bound4_handle(self, event->event, event->granted.lease);
|
||||
return;
|
||||
case N_DHCP4_CLIENT_EVENT_EXTENDED:
|
||||
bound4_handle(self, event->extended.lease, TRUE);
|
||||
break;
|
||||
bound4_handle(self, event->event, event->extended.lease);
|
||||
return;
|
||||
case N_DHCP4_CLIENT_EVENT_DOWN:
|
||||
/* ignore down events, they are purely informational */
|
||||
break;
|
||||
case N_DHCP4_CLIENT_EVENT_LOG:
|
||||
{
|
||||
NMLogLevel nm_level;
|
||||
|
||||
nm_level = nm_log_level_from_syslog(event->log.level);
|
||||
if (nm_logging_enabled(nm_level, LOGD_DHCP4)) {
|
||||
nm_log(nm_level,
|
||||
LOGD_DHCP4,
|
||||
NULL,
|
||||
NULL,
|
||||
"dhcp4 (%s): %s",
|
||||
client_config->iface,
|
||||
event->log.message);
|
||||
}
|
||||
} break;
|
||||
_LOGT("event: down (ignore)");
|
||||
return;
|
||||
default:
|
||||
_LOGW("unhandled DHCP event %d", event->event);
|
||||
break;
|
||||
_LOGE("unhandled DHCP event %d", event->event);
|
||||
nm_assert(event->event != N_DHCP4_CLIENT_EVENT_LOG);
|
||||
nm_assert_not_reached();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
dhcp4_event_pop_all_events(NMDhcpNettools *self)
|
||||
{
|
||||
NMDhcpNettoolsPrivate *priv = NM_DHCP_NETTOOLS_GET_PRIVATE(self);
|
||||
NDhcp4ClientEvent *event;
|
||||
|
||||
while (!n_dhcp4_client_pop_event(priv->client, &event) && event)
|
||||
dhcp4_event_handle(self, event);
|
||||
|
||||
nm_clear_g_source_inst(&priv->pop_all_events_on_idle_source);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
dhcp4_event_pop_all_events_on_idle_cb(gpointer user_data)
|
||||
{
|
||||
NMDhcpNettools *self = user_data;
|
||||
NMDhcpNettoolsPrivate *priv = NM_DHCP_NETTOOLS_GET_PRIVATE(self);
|
||||
|
||||
nm_clear_g_source_inst(&priv->pop_all_events_on_idle_source);
|
||||
dhcp4_event_pop_all_events(self);
|
||||
return G_SOURCE_CONTINUE;
|
||||
}
|
||||
|
||||
static void
|
||||
dhcp4_event_pop_all_events_on_idle(NMDhcpNettools *self)
|
||||
{
|
||||
NMDhcpNettoolsPrivate *priv = NM_DHCP_NETTOOLS_GET_PRIVATE(self);
|
||||
|
||||
/* For the most part, NDhcp4Client gets driven from internal, that is
|
||||
* by having events ready on the socket or the timerfd. For those
|
||||
* events, we will poll on the (epoll) FD, then let it be processed
|
||||
* by n_dhcp4_client_dispatch(), and pop the queued events.
|
||||
*
|
||||
* But certain commands (n_dhcp4_client_lease_select(), n_dhcp4_client_lease_accept(),
|
||||
* n_dhcp4_client_lease_decline()) are initiated by the user. And they tend
|
||||
* to log events. Logging is done by queuing a message, but that won't be processed,
|
||||
* unless we pop the event.
|
||||
*
|
||||
* To ensure that those logging events get popped, schedule an idle handler to do that.
|
||||
*
|
||||
* Yes, this means, that the messages only get logged later, when the idle handler
|
||||
* runs. The alternative seems even more problematic, because we don't know
|
||||
* the current call-state, and it seems dangerous to pop unexpected events.
|
||||
* E.g. we call n_dhcp4_client_lease_select() from inside the event-handler,
|
||||
* it seems wrong to call dhcp4_event_pop_all_events() in that context again.
|
||||
*
|
||||
* See-also: https://github.com/nettools/n-dhcp4/issues/34
|
||||
*/
|
||||
|
||||
if (!priv->pop_all_events_on_idle_source) {
|
||||
priv->pop_all_events_on_idle_source =
|
||||
nm_g_idle_add_source(dhcp4_event_pop_all_events_on_idle_cb, self);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -969,7 +1068,6 @@ dhcp4_event_cb(int fd, GIOCondition condition, gpointer user_data)
|
|||
{
|
||||
NMDhcpNettools *self = user_data;
|
||||
NMDhcpNettoolsPrivate *priv = NM_DHCP_NETTOOLS_GET_PRIVATE(self);
|
||||
NDhcp4ClientEvent *event;
|
||||
int r;
|
||||
|
||||
r = n_dhcp4_client_dispatch(priv->client);
|
||||
|
|
@ -990,8 +1088,7 @@ dhcp4_event_cb(int fd, GIOCondition condition, gpointer user_data)
|
|||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
while (!n_dhcp4_client_pop_event(priv->client, &event) && event)
|
||||
dhcp4_event_handle(self, event);
|
||||
dhcp4_event_pop_all_events(self);
|
||||
|
||||
return G_SOURCE_CONTINUE;
|
||||
}
|
||||
|
|
@ -1098,46 +1195,69 @@ nettools_create(NMDhcpNettools *self, GError **error)
|
|||
}
|
||||
|
||||
static gboolean
|
||||
_accept(NMDhcpClient *client, GError **error)
|
||||
_accept(NMDhcpClient *client, const NML3ConfigData *l3cd, GError **error)
|
||||
{
|
||||
NMDhcpNettools *self = NM_DHCP_NETTOOLS(client);
|
||||
NMDhcpNettoolsPrivate *priv = NM_DHCP_NETTOOLS_GET_PRIVATE(self);
|
||||
int r;
|
||||
|
||||
g_return_val_if_fail(priv->lease, FALSE);
|
||||
|
||||
_LOGT("accept");
|
||||
|
||||
r = n_dhcp4_client_lease_accept(priv->lease);
|
||||
g_return_val_if_fail(l3cd, FALSE);
|
||||
|
||||
if (priv->granted.lease_l3cd != l3cd) {
|
||||
nm_utils_error_set(error, NM_UTILS_ERROR_UNKNOWN, "calling accept in unexpected state");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
nm_assert(priv->granted.lease);
|
||||
|
||||
r = n_dhcp4_client_lease_accept(priv->granted.lease);
|
||||
|
||||
dhcp4_event_pop_all_events_on_idle(self);
|
||||
|
||||
nm_clear_pointer(&priv->granted.lease, n_dhcp4_client_lease_unref);
|
||||
nm_clear_l3cd(&priv->granted.lease_l3cd);
|
||||
|
||||
if (r) {
|
||||
set_error_nettools(error, r, "failed to accept lease");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
priv->lease = n_dhcp4_client_lease_unref(priv->lease);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
decline(NMDhcpClient *client, const char *error_message, GError **error)
|
||||
decline(NMDhcpClient *client, const NML3ConfigData *l3cd, const char *error_message, GError **error)
|
||||
{
|
||||
NMDhcpNettools *self = NM_DHCP_NETTOOLS(client);
|
||||
NMDhcpNettoolsPrivate *priv = NM_DHCP_NETTOOLS_GET_PRIVATE(self);
|
||||
int r;
|
||||
nm_auto(n_dhcp4_client_lease_unrefp) NDhcp4ClientLease *lease = NULL;
|
||||
|
||||
g_return_val_if_fail(priv->lease, FALSE);
|
||||
_LOGT("decline (%s)", error_message);
|
||||
|
||||
_LOGT("dhcp4-client: decline (%s)", error_message);
|
||||
g_return_val_if_fail(l3cd, FALSE);
|
||||
|
||||
if (priv->granted.lease_l3cd != l3cd) {
|
||||
nm_utils_error_set(error, NM_UTILS_ERROR_UNKNOWN, "calling decline in unexpected state");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
nm_assert(priv->granted.lease);
|
||||
|
||||
lease = g_steal_pointer(&priv->granted.lease);
|
||||
nm_clear_l3cd(&priv->granted.lease_l3cd);
|
||||
|
||||
r = n_dhcp4_client_lease_decline(lease, error_message);
|
||||
|
||||
dhcp4_event_pop_all_events_on_idle(self);
|
||||
|
||||
r = n_dhcp4_client_lease_decline(priv->lease, error_message);
|
||||
if (r) {
|
||||
set_error_nettools(error, r, "failed to decline lease");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
priv->lease = n_dhcp4_client_lease_unref(priv->lease);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
|
@ -1348,7 +1468,9 @@ dispose(GObject *object)
|
|||
|
||||
nm_clear_g_free(&priv->lease_file);
|
||||
nm_clear_g_source_inst(&priv->event_source);
|
||||
nm_clear_pointer(&priv->lease, n_dhcp4_client_lease_unref);
|
||||
nm_clear_g_source_inst(&priv->pop_all_events_on_idle_source);
|
||||
nm_clear_pointer(&priv->granted.lease, n_dhcp4_client_lease_unref);
|
||||
nm_clear_l3cd(&priv->granted.lease_l3cd);
|
||||
nm_clear_pointer(&priv->probe, n_dhcp4_client_probe_free);
|
||||
nm_clear_pointer(&priv->client, n_dhcp4_client_unref);
|
||||
|
||||
|
|
|
|||
|
|
@ -416,6 +416,8 @@ nm_dhcp_utils_ip4_config_from_options(NMDedupMultiIndex *multi_idx,
|
|||
str = g_hash_table_lookup(options, "ip_address");
|
||||
if (!str || !nm_utils_parse_inaddr_bin(AF_INET, str, NULL, &addr))
|
||||
return NULL;
|
||||
if (addr == INADDR_ANY)
|
||||
return NULL;
|
||||
|
||||
_LOG2I(LOGD_DHCP4, iface, " address %s", str);
|
||||
|
||||
|
|
@ -428,6 +430,7 @@ nm_dhcp_utils_ip4_config_from_options(NMDedupMultiIndex *multi_idx,
|
|||
plen = _nm_utils_ip4_get_default_prefix(addr);
|
||||
_LOG2I(LOGD_DHCP4, iface, " plen %d (default)", plen);
|
||||
}
|
||||
|
||||
nm_platform_ip4_address_set_addr(&address, addr, plen);
|
||||
|
||||
/* Routes: if the server returns classless static routes, we MUST ignore
|
||||
|
|
|
|||
|
|
@ -37,7 +37,6 @@ G_STATIC_ASSERT(NM_ACD_TIMEOUT_RFC5227_MSEC == N_ACD_TIMEOUT_RFC5227);
|
|||
#define ACD_ENSURE_RATELIMIT_MSEC ((guint32) 4000u)
|
||||
#define ACD_WAIT_PROBING_EXTRA_TIME_MSEC ((guint32) (1000u + ACD_ENSURE_RATELIMIT_MSEC))
|
||||
#define ACD_WAIT_PROBING_EXTRA_TIME2_MSEC ((guint32) 1000u)
|
||||
#define ACD_MAX_TIMEOUT_MSEC ((guint32) 30000u)
|
||||
#define ACD_WAIT_TIME_PROBING_FULL_RESTART_MSEC ((guint32) 30000u)
|
||||
#define ACD_WAIT_TIME_CONFLICT_RESTART_MSEC ((guint32) 120000u)
|
||||
#define ACD_WAIT_TIME_ANNOUNCE_RESTART_MSEC ((guint32) 30000u)
|
||||
|
|
@ -1866,10 +1865,10 @@ _l3_acd_data_add(NML3Cfg *self,
|
|||
|
||||
acd_data = _l3_acd_data_find(self, addr);
|
||||
|
||||
if (acd_timeout_msec > ACD_MAX_TIMEOUT_MSEC) {
|
||||
if (acd_timeout_msec > NM_ACD_TIMEOUT_MAX_MSEC) {
|
||||
/* we limit the maximum timeout. Otherwise we have to handle integer overflow
|
||||
* when adding timeouts. */
|
||||
acd_timeout_msec = ACD_MAX_TIMEOUT_MSEC;
|
||||
acd_timeout_msec = NM_ACD_TIMEOUT_MAX_MSEC;
|
||||
}
|
||||
|
||||
if (!acd_data) {
|
||||
|
|
@ -3229,8 +3228,8 @@ nm_l3cfg_add_config(NML3Cfg *self,
|
|||
nm_assert(l3cd);
|
||||
nm_assert(nm_l3_config_data_get_ifindex(l3cd) == self->priv.ifindex);
|
||||
|
||||
if (acd_timeout_msec > ACD_MAX_TIMEOUT_MSEC)
|
||||
acd_timeout_msec = ACD_MAX_TIMEOUT_MSEC;
|
||||
if (acd_timeout_msec > NM_ACD_TIMEOUT_MAX_MSEC)
|
||||
acd_timeout_msec = NM_ACD_TIMEOUT_MAX_MSEC;
|
||||
|
||||
nm_assert(NM_IN_SET(acd_defend_type,
|
||||
NM_L3_ACD_DEFEND_TYPE_NEVER,
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
#define NM_L3CFG_CONFIG_PRIORITY_IPV6LL 1
|
||||
#define NM_L3CFG_CONFIG_PRIORITY_VPN 9
|
||||
#define NM_ACD_TIMEOUT_RFC5227_MSEC 9000u
|
||||
#define NM_ACD_TIMEOUT_MAX_MSEC 30000u
|
||||
|
||||
#define NM_TYPE_L3CFG (nm_l3cfg_get_type())
|
||||
#define NM_L3CFG(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_L3CFG, NML3Cfg))
|
||||
|
|
|
|||
|
|
@ -59,7 +59,16 @@ typedef enum {
|
|||
LOGD_IP = LOGD_IP4 | LOGD_IP6,
|
||||
|
||||
#define LOGD_DHCPX(is_ipv4) ((is_ipv4) ? LOGD_DHCP4 : LOGD_DHCP6)
|
||||
#define LOGD_IPX(is_ipv4) ((is_ipv4) ? LOGD_IP4 : LOGD_IP6)
|
||||
|
||||
#define LOGD_DHCP_af(addr_family) \
|
||||
({ \
|
||||
const int _addr_family_1 = (addr_family); \
|
||||
\
|
||||
(_addr_family_1 == AF_UNSPEC ? LOGD_DHCP \
|
||||
: (NM_IS_IPv4(_addr_family_1) ? LOGD_DHCP4 : LOGD_DHCP6)); \
|
||||
})
|
||||
|
||||
#define LOGD_IPX(is_ipv4) ((is_ipv4) ? LOGD_IP4 : LOGD_IP6)
|
||||
|
||||
} NMLogDomain;
|
||||
|
||||
|
|
|
|||
|
|
@ -2194,38 +2194,57 @@ nm_g_array_unref(GArray *arr)
|
|||
g_array_unref(arr);
|
||||
}
|
||||
|
||||
#define nm_g_array_first(arr, type) \
|
||||
({ \
|
||||
GArray *const _arr = (arr); \
|
||||
guint _len; \
|
||||
\
|
||||
nm_assert(_arr); \
|
||||
_len = _arr->len; \
|
||||
nm_assert(_len > 0); \
|
||||
&g_array_index(arr, type, 0); \
|
||||
#define nm_g_array_first(arr, Type) \
|
||||
({ \
|
||||
GArray *const _arr = (arr); \
|
||||
\
|
||||
nm_assert(_arr); \
|
||||
nm_assert(sizeof(Type) == g_array_get_element_size(_arr)); \
|
||||
nm_assert(_arr->len > 0); \
|
||||
\
|
||||
&g_array_index(arr, Type, 0); \
|
||||
})
|
||||
|
||||
#define nm_g_array_last(arr, type) \
|
||||
({ \
|
||||
GArray *const _arr = (arr); \
|
||||
guint _len; \
|
||||
\
|
||||
nm_assert(_arr); \
|
||||
_len = _arr->len; \
|
||||
nm_assert(_len > 0); \
|
||||
&g_array_index(arr, type, _len - 1u); \
|
||||
#define nm_g_array_last(arr, Type) \
|
||||
({ \
|
||||
GArray *const _arr = (arr); \
|
||||
\
|
||||
nm_assert(_arr); \
|
||||
nm_assert(sizeof(Type) == g_array_get_element_size(_arr)); \
|
||||
nm_assert(_arr->len > 0); \
|
||||
\
|
||||
&g_array_index(arr, Type, _arr->len - 1u); \
|
||||
})
|
||||
|
||||
#define nm_g_array_append_new(arr, type) \
|
||||
({ \
|
||||
GArray *const _arr = (arr); \
|
||||
guint _len; \
|
||||
\
|
||||
nm_assert(_arr); \
|
||||
_len = _arr->len; \
|
||||
nm_assert(_len < G_MAXUINT); \
|
||||
g_array_set_size(_arr, _len + 1u); \
|
||||
&g_array_index(arr, type, _len); \
|
||||
/* Similar to g_array_index(). The differences are
|
||||
* - this does nm_assert() checks that the arguments are valid.
|
||||
* - returns a pointer to the element. */
|
||||
#define nm_g_array_index_p(arr, Type, idx) \
|
||||
({ \
|
||||
GArray *const _arr = (arr); \
|
||||
const guint _idx = (idx); \
|
||||
\
|
||||
nm_assert(_arr); \
|
||||
nm_assert(sizeof(Type) == g_array_get_element_size(_arr)); \
|
||||
nm_assert(_idx < _arr->len); \
|
||||
\
|
||||
&g_array_index(_arr, Type, _idx); \
|
||||
})
|
||||
|
||||
#define nm_g_array_append_new(arr, Type) \
|
||||
({ \
|
||||
GArray *const _arr = (arr); \
|
||||
guint _len; \
|
||||
\
|
||||
nm_assert(_arr); \
|
||||
nm_assert(sizeof(Type) == g_array_get_element_size(_arr)); \
|
||||
\
|
||||
_len = _arr->len; \
|
||||
\
|
||||
nm_assert(_len < G_MAXUINT); \
|
||||
\
|
||||
g_array_set_size(_arr, _len + 1u); \
|
||||
&g_array_index(arr, Type, _len); \
|
||||
})
|
||||
|
||||
/*****************************************************************************/
|
||||
|
|
@ -3102,10 +3121,14 @@ gboolean nm_utils_ifname_valid(const char *name, NMUtilsIfaceType type, GError *
|
|||
static inline GArray *
|
||||
nm_strvarray_ensure(GArray **p)
|
||||
{
|
||||
nm_assert(p);
|
||||
|
||||
if (!*p) {
|
||||
*p = g_array_new(TRUE, FALSE, sizeof(char *));
|
||||
g_array_set_clear_func(*p, nm_indirect_g_free);
|
||||
}
|
||||
} else
|
||||
nm_assert(g_array_get_element_size(*p) == sizeof(char *));
|
||||
|
||||
return *p;
|
||||
}
|
||||
|
||||
|
|
@ -3114,6 +3137,9 @@ nm_strvarray_add(GArray *array, const char *str)
|
|||
{
|
||||
char *s;
|
||||
|
||||
nm_assert(array);
|
||||
nm_assert(g_array_get_element_size(array) == sizeof(char *));
|
||||
|
||||
s = g_strdup(str);
|
||||
g_array_append_val(array, s);
|
||||
}
|
||||
|
|
@ -3121,15 +3147,14 @@ nm_strvarray_add(GArray *array, const char *str)
|
|||
static inline const char *
|
||||
nm_strvarray_get_idx(GArray *array, guint idx)
|
||||
{
|
||||
nm_assert(array);
|
||||
nm_assert(idx < array->len);
|
||||
|
||||
return g_array_index(array, const char *, idx);
|
||||
return *nm_g_array_index_p(array, const char *, idx);
|
||||
}
|
||||
|
||||
static inline const char *const *
|
||||
nm_strvarray_get_strv_non_empty(GArray *arr, guint *length)
|
||||
{
|
||||
nm_assert(!arr || g_array_get_element_size(arr) == sizeof(char *));
|
||||
|
||||
if (!arr || arr->len == 0) {
|
||||
NM_SET_OUT(length, 0);
|
||||
return NULL;
|
||||
|
|
@ -3144,6 +3169,8 @@ nm_strvarray_get_strv_non_empty_dup(GArray *arr, guint *length)
|
|||
{
|
||||
const char *const *strv;
|
||||
|
||||
nm_assert(!arr || g_array_get_element_size(arr) == sizeof(char *));
|
||||
|
||||
if (!arr || arr->len == 0) {
|
||||
NM_SET_OUT(length, 0);
|
||||
return NULL;
|
||||
|
|
@ -3162,6 +3189,8 @@ nm_strvarray_get_strv(GArray **arr, guint *length)
|
|||
return (const char *const *) arr;
|
||||
}
|
||||
|
||||
nm_assert(g_array_get_element_size(*arr) == sizeof(char *));
|
||||
|
||||
NM_SET_OUT(length, (*arr)->len);
|
||||
return &g_array_index(*arr, const char *, 0);
|
||||
}
|
||||
|
|
@ -3173,6 +3202,8 @@ nm_strvarray_set_strv(GArray **array, const char *const *strv)
|
|||
|
||||
array_old = g_steal_pointer(array);
|
||||
|
||||
nm_assert(!array_old || g_array_get_element_size(array_old) == sizeof(char *));
|
||||
|
||||
if (!strv || !strv[0])
|
||||
return;
|
||||
|
||||
|
|
@ -3189,6 +3220,7 @@ nm_strvarray_find_first(GArray *strv, const char *needle)
|
|||
nm_assert(needle);
|
||||
|
||||
if (strv) {
|
||||
nm_assert(g_array_get_element_size(strv) == sizeof(char *));
|
||||
for (i = 0; i < strv->len; i++) {
|
||||
if (nm_streq(needle, g_array_index(strv, const char *, i)))
|
||||
return i;
|
||||
|
|
|
|||
|
|
@ -351,32 +351,15 @@ _c_public_ int n_dhcp4_client_lease_query(NDhcp4ClientLease *lease, uint8_t opti
|
|||
* selected none of the others can be.
|
||||
*
|
||||
* Return: 0 on success, or a negative error code on failure.
|
||||
* Returns -ENOTRECOVERABLE when called in an unexpected state.
|
||||
*/
|
||||
_c_public_ int n_dhcp4_client_lease_select(NDhcp4ClientLease *lease) {
|
||||
NDhcp4ClientLease *l, *t_l;
|
||||
NDhcp4ClientProbe *probe;
|
||||
int r;
|
||||
|
||||
/* XXX error handling, this must be an OFFER */
|
||||
|
||||
if (!lease->probe)
|
||||
return -ENOTRECOVERABLE;
|
||||
if (lease->probe->current_lease)
|
||||
return -ENOTRECOVERABLE;
|
||||
|
||||
r = n_dhcp4_client_probe_transition_select(lease->probe, lease->message, n_dhcp4_gettime(CLOCK_BOOTTIME));
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
/*
|
||||
* Only one of the offered leases can be selected, so flush the list.
|
||||
* All offered lease, including this one are now dead.
|
||||
*/
|
||||
probe = lease->probe;
|
||||
c_list_for_each_entry_safe(l, t_l, &probe->lease_list, probe_link)
|
||||
n_dhcp4_client_lease_unlink(l);
|
||||
|
||||
return 0;
|
||||
return n_dhcp4_client_probe_transition_select(lease->probe, lease->message, n_dhcp4_gettime(CLOCK_BOOTTIME));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -390,24 +373,15 @@ _c_public_ int n_dhcp4_client_lease_select(NDhcp4ClientLease *lease) {
|
|||
* can be accepted.
|
||||
*
|
||||
* Return: 0 on success, or a negative error code on failure.
|
||||
* Returns -ENOTRECOVERABLE when called in an unexpected state.
|
||||
*/
|
||||
_c_public_ int n_dhcp4_client_lease_accept(NDhcp4ClientLease *lease) {
|
||||
int r;
|
||||
|
||||
/* XXX error handling, this must be an ACK */
|
||||
|
||||
if (!lease->probe)
|
||||
return -ENOTRECOVERABLE;
|
||||
if (lease->probe->current_lease != lease)
|
||||
return -ENOTRECOVERABLE;
|
||||
|
||||
r = n_dhcp4_client_probe_transition_accept(lease->probe, lease->message);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
n_dhcp4_client_lease_unlink(lease);
|
||||
|
||||
return 0;
|
||||
return n_dhcp4_client_probe_transition_accept(lease->probe, lease->message);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -421,23 +395,13 @@ _c_public_ int n_dhcp4_client_lease_accept(NDhcp4ClientLease *lease) {
|
|||
* decline.
|
||||
*
|
||||
* Return: 0 on success, or a negative error code on failure.
|
||||
* Returns -ENOTRECOVERABLE when called in an unexpected state.
|
||||
*/
|
||||
_c_public_ int n_dhcp4_client_lease_decline(NDhcp4ClientLease *lease, const char *error) {
|
||||
int r;
|
||||
|
||||
/* XXX: error handling, this must be an ACK */
|
||||
|
||||
if (!lease->probe)
|
||||
return -ENOTRECOVERABLE;
|
||||
if (lease->probe->current_lease != lease)
|
||||
return -ENOTRECOVERABLE;
|
||||
|
||||
r = n_dhcp4_client_probe_transition_decline(lease->probe, lease->message, error, n_dhcp4_gettime(CLOCK_BOOTTIME));
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
lease->probe->current_lease = n_dhcp4_client_lease_unref(lease->probe->current_lease);
|
||||
n_dhcp4_client_lease_unlink(lease);
|
||||
|
||||
return 0;
|
||||
return n_dhcp4_client_probe_transition_decline(lease->probe, lease->message, error, n_dhcp4_gettime(CLOCK_BOOTTIME));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1024,6 +1024,7 @@ static int n_dhcp4_client_probe_transition_nak(NDhcp4ClientProbe *probe) {
|
|||
|
||||
int n_dhcp4_client_probe_transition_select(NDhcp4ClientProbe *probe, NDhcp4Incoming *offer, uint64_t ns_now) {
|
||||
_c_cleanup_(n_dhcp4_outgoing_freep) NDhcp4Outgoing *request = NULL;
|
||||
NDhcp4ClientLease *l, *t_l;
|
||||
int r;
|
||||
|
||||
switch (probe->state) {
|
||||
|
|
@ -1042,11 +1043,16 @@ int n_dhcp4_client_probe_transition_select(NDhcp4ClientProbe *probe, NDhcp4Incom
|
|||
else
|
||||
request = NULL; /* consumed */
|
||||
|
||||
/* XXX: ignore other offers */
|
||||
|
||||
probe->state = N_DHCP4_CLIENT_PROBE_STATE_REQUESTING;
|
||||
|
||||
break;
|
||||
/*
|
||||
* Only one of the offered leases can be selected, so flush the list.
|
||||
* All offered lease, including this one are now dead.
|
||||
*/
|
||||
c_list_for_each_entry_safe(l, t_l, &probe->lease_list, probe_link)
|
||||
n_dhcp4_client_lease_unlink(l);
|
||||
|
||||
return 0;
|
||||
case N_DHCP4_CLIENT_PROBE_STATE_INIT:
|
||||
case N_DHCP4_CLIENT_PROBE_STATE_INIT_REBOOT:
|
||||
case N_DHCP4_CLIENT_PROBE_STATE_REBOOTING:
|
||||
|
|
@ -1057,11 +1063,9 @@ int n_dhcp4_client_probe_transition_select(NDhcp4ClientProbe *probe, NDhcp4Incom
|
|||
case N_DHCP4_CLIENT_PROBE_STATE_REBINDING:
|
||||
case N_DHCP4_CLIENT_PROBE_STATE_EXPIRED:
|
||||
default:
|
||||
/* ignore */
|
||||
break;
|
||||
/* user called in invalid state. Return error. */
|
||||
return -ENOTRECOVERABLE;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -1085,10 +1089,11 @@ int n_dhcp4_client_probe_transition_accept(NDhcp4ClientProbe *probe, NDhcp4Incom
|
|||
return r;
|
||||
|
||||
probe->state = N_DHCP4_CLIENT_PROBE_STATE_BOUND;
|
||||
|
||||
probe->ns_decline_restart_delay = 0;
|
||||
n_dhcp4_client_lease_unlink(probe->current_lease);
|
||||
n_dhcp4_client_arm_timer(probe->client);
|
||||
|
||||
break;
|
||||
return 0;
|
||||
|
||||
case N_DHCP4_CLIENT_PROBE_STATE_INIT:
|
||||
case N_DHCP4_CLIENT_PROBE_STATE_INIT_REBOOT:
|
||||
|
|
@ -1100,11 +1105,9 @@ int n_dhcp4_client_probe_transition_accept(NDhcp4ClientProbe *probe, NDhcp4Incom
|
|||
case N_DHCP4_CLIENT_PROBE_STATE_REBINDING:
|
||||
case N_DHCP4_CLIENT_PROBE_STATE_EXPIRED:
|
||||
default:
|
||||
/* ignore */
|
||||
break;
|
||||
/* user called in invalid state. Return error. */
|
||||
return -ENOTRECOVERABLE;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -1126,9 +1129,22 @@ int n_dhcp4_client_probe_transition_decline(NDhcp4ClientProbe *probe, NDhcp4Inco
|
|||
else
|
||||
request = NULL; /* consumed */
|
||||
|
||||
/* XXX: what state to transition to? */
|
||||
n_dhcp4_client_lease_unlink(probe->current_lease);
|
||||
probe->current_lease = n_dhcp4_client_lease_unref(probe->current_lease);
|
||||
|
||||
break;
|
||||
probe->state = N_DHCP4_CLIENT_PROBE_STATE_INIT;
|
||||
|
||||
/* RFC2131, 3.1, 5.) The client SHOULD wait a minimum of ten seconds before restarting
|
||||
* the configuration process to avoid excessive network traffic in case of looping.
|
||||
*
|
||||
* Let's go beyond that, and use an exponential backoff. */
|
||||
probe->ns_decline_restart_delay = C_CLAMP(probe->ns_decline_restart_delay * 2u,
|
||||
UINT64_C(10) * UINT64_C(1000000000),
|
||||
UINT64_C(300) * UINT64_C(1000000000));
|
||||
probe->ns_deferred = n_dhcp4_gettime(CLOCK_BOOTTIME) + probe->ns_decline_restart_delay;
|
||||
|
||||
n_dhcp4_client_arm_timer(probe->client);
|
||||
return 0;
|
||||
|
||||
case N_DHCP4_CLIENT_PROBE_STATE_INIT:
|
||||
case N_DHCP4_CLIENT_PROBE_STATE_INIT_REBOOT:
|
||||
|
|
@ -1140,11 +1156,9 @@ int n_dhcp4_client_probe_transition_decline(NDhcp4ClientProbe *probe, NDhcp4Inco
|
|||
case N_DHCP4_CLIENT_PROBE_STATE_REBINDING:
|
||||
case N_DHCP4_CLIENT_PROBE_STATE_EXPIRED:
|
||||
default:
|
||||
/* ignore */
|
||||
break;
|
||||
/* user called in invalid state. Return error. */
|
||||
return -ENOTRECOVERABLE;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -378,6 +378,7 @@ struct NDhcp4ClientProbe {
|
|||
uint64_t ns_deferred; /* timeout for deferred action */
|
||||
uint64_t ns_reinit;
|
||||
uint64_t ns_nak_restart_delay; /* restart delay after a nak */
|
||||
uint64_t ns_decline_restart_delay; /* restart delay after a decline */
|
||||
NDhcp4ClientLease *current_lease; /* current lease */
|
||||
|
||||
NDhcp4CConnection connection; /* client connection wrapper */
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue