about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorMichael Biebl <biebl@debian.org>2023-10-04 11:44:49 +0200
committerMichael Biebl <biebl@debian.org>2023-10-04 11:44:49 +0200
commitd4d8b2b91f7ba000d97a8b2aab48c85000c11314 (patch)
tree4bae747b430c9dae89c22cbf298cbf6c862a52b8 /src
parent05e4a733f2141995181a551854d5df929f084adf (diff)
New upstream version 1.44.2 upstream/1.44.2
Diffstat (limited to 'src')
-rw-r--r--src/core/devices/nm-device.c16
-rw-r--r--src/core/devices/wwan/nm-device-modem.c15
-rw-r--r--src/core/devices/wwan/nm-modem-ofono.c7
-rw-r--r--src/core/main-utils.c15
-rw-r--r--src/core/nm-checkpoint.c23
-rw-r--r--src/core/nm-l3cfg.c27
-rw-r--r--src/core/nm-l3cfg.h1
-rw-r--r--src/core/nm-manager.c15
-rw-r--r--src/libnm-core-impl/nm-setting-ip-tunnel.c36
-rw-r--r--src/libnm-core-public/nm-version-macros.h2
-rw-r--r--src/libnmc-base/nm-client-utils.c3
-rw-r--r--src/libnmc-setting/settings-docs.h6
-rw-r--r--src/libnmc-setting/settings-docs.h.in6
-rw-r--r--src/nmcli/gen-metadata-nm-settings-nmcli.xml.in6
-rw-r--r--src/nmcli/nmcli.c6
15 files changed, 130 insertions, 54 deletions
diff --git a/src/core/devices/nm-device.c b/src/core/devices/nm-device.c
index 2038e2f2..d1212560 100644
--- a/src/core/devices/nm-device.c
+++ b/src/core/devices/nm-device.c
@@ -4247,6 +4247,20 @@ _dev_l3_cfg_notify_cb(NML3Cfg *l3cfg, const NML3ConfigNotifyData *notify_data, N
     case NM_L3_CONFIG_NOTIFY_TYPE_ACD_EVENT:
     {
         const NML3AcdAddrInfo *addr_info = &notify_data->acd_event.info;
+        char                   buf_addr[NM_INET_ADDRSTRLEN];
+
+        if (addr_info->state == NM_L3_ACD_ADDR_STATE_USED) {
+            _LOGI(LOGD_DEVICE,
+                  "IP address %s cannot be configured because it is already in use in the "
+                  "network by host %s",
+                  nm_inet4_ntop(addr_info->addr, buf_addr),
+                  nm_ether_addr_to_string_a(&addr_info->last_conflict_addr));
+        } else if (addr_info->state == NM_L3_ACD_ADDR_STATE_CONFLICT) {
+            _LOGI(LOGD_DEVICE,
+                  "conflict detected for IP address %s with host %s",
+                  nm_inet4_ntop(addr_info->addr, buf_addr),
+                  nm_ether_addr_to_string_a(&addr_info->last_conflict_addr));
+        }
 
         if (addr_info->state > NM_L3_ACD_ADDR_STATE_PROBING)
             _dev_ipmanual_check_ready(self);
@@ -8740,7 +8754,7 @@ _get_maybe_ipv6_disabled(NMDevice *self)
         return FALSE;
 
     path = nm_sprintf_bufa(128, "/proc/sys/net/ipv6/conf/%s/disable_ipv6", ifname);
-    return (nm_platform_sysctl_get_int32(platform, NMP_SYSCTL_PATHID_ABSOLUTE(path), 0) == 0);
+    return (nm_platform_sysctl_get_int32(platform, NMP_SYSCTL_PATHID_ABSOLUTE(path), 1) != 0);
 }
 
 /*
diff --git a/src/core/devices/wwan/nm-device-modem.c b/src/core/devices/wwan/nm-device-modem.c
index a1050c3f..929bda15 100644
--- a/src/core/devices/wwan/nm-device-modem.c
+++ b/src/core/devices/wwan/nm-device-modem.c
@@ -70,14 +70,17 @@ ppp_failed(NMModem *modem, guint i_reason, gpointer user_data)
 static void
 modem_prepare_result(NMModem *modem, gboolean success, guint i_reason, gpointer user_data)
 {
-    NMDeviceModem        *self   = NM_DEVICE_MODEM(user_data);
-    NMDeviceModemPrivate *priv   = NM_DEVICE_MODEM_GET_PRIVATE(self);
-    NMDevice             *device = NM_DEVICE(self);
-    NMDeviceStateReason   reason = i_reason;
+    NMDeviceModem        *self         = NM_DEVICE_MODEM(user_data);
+    NMDeviceModemPrivate *priv         = NM_DEVICE_MODEM_GET_PRIVATE(self);
+    NMDevice             *device       = NM_DEVICE(self);
+    NMDeviceStateReason   reason       = i_reason;
+    NMDeviceState         device_state = nm_device_get_state(device);
 
-    if (nm_device_get_state(device) != NM_DEVICE_STATE_PREPARE
+    if (device_state != NM_DEVICE_STATE_PREPARE
         || priv->stage1_state != NM_DEVICE_STAGE_STATE_PENDING) {
-        nm_assert_not_reached();
+        _LOGD(LOGD_MB,
+              "device no longer in prepare state when modem prepare finished ('%s')",
+              nm_device_state_to_string(device_state));
         success = FALSE;
     }
 
diff --git a/src/core/devices/wwan/nm-modem-ofono.c b/src/core/devices/wwan/nm-modem-ofono.c
index de105bbd..3e0bbd48 100644
--- a/src/core/devices/wwan/nm-modem-ofono.c
+++ b/src/core/devices/wwan/nm-modem-ofono.c
@@ -1276,8 +1276,11 @@ handle_settings(NMModemOfono *self, GVariant *v_dict)
     nm_l3_config_data_add_address_4(priv->l3cd_4, &address);
 
     if (!g_variant_lookup(v_dict, "Gateway", "&s", &s) || !s) {
-        _LOGW("Settings 'Gateway' missing");
-        goto out;
+        /* It is normal for point-to-point connections to not have a gateway IP
+         * specified. Use 0.0.0.0 in that case.
+         */
+        _LOGD("Settings 'Gateway' missing. Setting it to 0.0.0.0");
+        s = "0.0.0.0";
     }
     if (!nm_inet_parse_bin(AF_INET, s, NULL, &gateway_network)) {
         _LOGW("invalid 'Gateway': %s", s);
diff --git a/src/core/main-utils.c b/src/core/main-utils.c
index c6fa05c0..9360d688 100644
--- a/src/core/main-utils.c
+++ b/src/core/main-utils.c
@@ -158,7 +158,8 @@ nm_main_utils_ensure_not_running_pidfile(const char *pidfile)
     gs_free char *contents     = NULL;
     gs_free char *proc_cmdline = NULL;
     gsize         len          = 0;
-    long          pid;
+    pid_t         pid;
+    gint64        pid64;
     const char   *process_name;
     const char   *prgname = g_get_prgname();
 
@@ -173,12 +174,13 @@ nm_main_utils_ensure_not_running_pidfile(const char *pidfile)
         return;
 
     errno = 0;
-    pid   = strtol(contents, NULL, 10);
-    if (pid <= 0 || pid > 65536 || errno)
+    pid64 = _nm_utils_ascii_str_to_int64(contents, 10, 0, G_MAXINT64, -1);
+    pid   = (pid_t) pid64;
+    if (pid <= 0 || (gint64) pid != pid64)
         return;
 
     nm_clear_g_free(&contents);
-    proc_cmdline = g_strdup_printf("/proc/%ld/cmdline", pid);
+    proc_cmdline = g_strdup_printf("/proc/%" G_GINT64_FORMAT "/cmdline", (gint64) pid);
     if (!g_file_get_contents(proc_cmdline, &contents, &len, NULL))
         return;
 
@@ -190,7 +192,10 @@ nm_main_utils_ensure_not_running_pidfile(const char *pidfile)
     if (strcmp(process_name, prgname) == 0) {
         /* Check that the process exists */
         if (kill(pid, 0) == 0) {
-            fprintf(stderr, _("%s is already running (pid %ld)\n"), prgname, pid);
+            fprintf(stderr,
+                    _("%s is already running (pid %" G_GINT64_FORMAT ")\n"),
+                    prgname,
+                    (gint64) pid);
             exit(1);
         }
     }
diff --git a/src/core/nm-checkpoint.c b/src/core/nm-checkpoint.c
index 5c4d4e53..74adf484 100644
--- a/src/core/nm-checkpoint.c
+++ b/src/core/nm-checkpoint.c
@@ -460,24 +460,27 @@ next_dev:
         NMDeviceState state;
 
         nm_manager_for_each_device (priv->manager, device, tmp_lst) {
-            gboolean found = FALSE;
-
             if (g_hash_table_contains(priv->devices, device))
                 continue;
 
             /* Also ignore devices that were in the checkpoint initially and
              * were moved to 'removed_devices' because they got removed from
              * the system. */
-            for (i = 0; i < priv->removed_devices->len; i++) {
-                dev_checkpoint = priv->removed_devices->pdata[i];
-                if (dev_checkpoint->dev_type == nm_device_get_device_type(device)
-                    && nm_streq0(dev_checkpoint->original_dev_name, nm_device_get_iface(device))) {
-                    found = TRUE;
-                    break;
+            if (priv->removed_devices) {
+                gboolean found = FALSE;
+
+                for (i = 0; i < priv->removed_devices->len; i++) {
+                    dev_checkpoint = priv->removed_devices->pdata[i];
+                    if (dev_checkpoint->dev_type == nm_device_get_device_type(device)
+                        && nm_streq0(dev_checkpoint->original_dev_name,
+                                     nm_device_get_iface(device))) {
+                        found = TRUE;
+                        break;
+                    }
                 }
+                if (found)
+                    continue;
             }
-            if (found)
-                continue;
 
             state = nm_device_get_state(device);
             if (state > NM_DEVICE_STATE_DISCONNECTED && state < NM_DEVICE_STATE_DEACTIVATING) {
diff --git a/src/core/nm-l3cfg.c b/src/core/nm-l3cfg.c
index 3c2d3ec8..ce9d5849 100644
--- a/src/core/nm-l3cfg.c
+++ b/src/core/nm-l3cfg.c
@@ -101,8 +101,6 @@ typedef struct {
      * timestamp when we start probing. */
     guint32 probing_timeout_msec;
 
-    NMEtherAddr last_conflict_addr;
-
     NML3AcdDefendType acd_defend_type_desired : 3;
     NML3AcdDefendType acd_defend_type_current : 3;
     bool              acd_defend_type_is_active : 1;
@@ -168,7 +166,6 @@ typedef struct {
     /* This flag is only used temporarily to do a bulk update and
      * clear all the ones that are no longer in used. */
     bool os_dirty : 1;
-    bool os_tna_dirty : 1;
 } ObjStateData;
 
 G_STATIC_ASSERT(G_STRUCT_OFFSET(ObjStateData, obj) == 0);
@@ -2663,8 +2660,8 @@ handle_init:
         nm_assert(acd_data->info.state == NM_L3_ACD_ADDR_STATE_PROBING);
         nm_assert(acd_data->nacd_probe);
 
-        acd_data->nacd_probe         = n_acd_probe_free(acd_data->nacd_probe);
-        acd_data->last_conflict_addr = *sender_addr;
+        acd_data->nacd_probe              = n_acd_probe_free(acd_data->nacd_probe);
+        acd_data->info.last_conflict_addr = *sender_addr;
         _l3_acd_data_state_set_full(self,
                                     acd_data,
                                     NM_L3_ACD_ADDR_STATE_USED,
@@ -2676,7 +2673,7 @@ handle_init:
             _l3_acd_data_timeout_schedule(acd_data, ACD_WAIT_TIME_PROBING_FULL_RESTART_MSEC);
 
         if (!_l3_acd_data_defendconflict_warning_ratelimited(acd_data, p_now_msec)) {
-            _LOGI("IPv4 address %s is used on network connected to interface %d%s%s%s from "
+            _LOGD("IPv4 address %s is used on network connected to interface %d%s%s%s from "
                   "host %s",
                   nm_inet4_ntop(acd_data->info.addr, sbuf_addr),
                   self->priv.ifindex,
@@ -2707,7 +2704,7 @@ handle_init:
                   nm_ether_addr_to_string_a(sender_addr));
 
         if (!_l3_acd_data_defendconflict_warning_ratelimited(acd_data, p_now_msec)) {
-            _LOGW("IPv4 address collision detection sees conflict on interface %d%s%s%s for "
+            _LOGD("IPv4 address collision detection sees conflict on interface %d%s%s%s for "
                   "address %s from host %s",
                   self->priv.ifindex,
                   NM_PRINT_FMT_QUOTED(self->priv.plobj_next,
@@ -2719,8 +2716,8 @@ handle_init:
                   nm_ether_addr_to_string_a(sender_addr));
         }
 
-        acd_data->nacd_probe         = n_acd_probe_free(acd_data->nacd_probe);
-        acd_data->last_conflict_addr = *sender_addr;
+        acd_data->nacd_probe              = n_acd_probe_free(acd_data->nacd_probe);
+        acd_data->info.last_conflict_addr = *sender_addr;
         _l3_acd_data_state_set(self, acd_data, NM_L3_ACD_ADDR_STATE_CONFLICT, TRUE);
         if (!acd_data->acd_data_timeout_source)
             _l3_acd_data_timeout_schedule(acd_data, ACD_WAIT_TIME_CONFLICT_RESTART_MSEC);
@@ -4035,7 +4032,7 @@ again:
                         &obj_state->os_failedobj_prioq_idx);
         _LOGW(
             "missing IPv%c route: %s",
-            nm_utils_addr_family_to_char(NMP_OBJECT_GET_TYPE(obj_state->obj)),
+            nm_utils_addr_family_to_char(NMP_OBJECT_GET_ADDR_FAMILY(obj_state->obj)),
             nmp_object_to_string(obj_state->obj, NMP_OBJECT_TO_STRING_PUBLIC, sbuf, sizeof(sbuf)));
         goto again;
     }
@@ -4076,7 +4073,7 @@ _failedobj_handle_routes(NML3Cfg *self, int addr_family, GPtrArray *routes_faile
         gboolean                  just_failed          = FALSE;
         gboolean                  arm_timer            = FALSE;
         int                       grace_timeout_msec;
-        gint64                    grace_expiry_mesc;
+        gint64                    grace_expiry_msec;
 
         nm_assert(NMP_OBJECT_GET_TYPE(o) == NMP_OBJECT_TYPE_IP_ROUTE(NM_IS_IPv4(addr_family)));
 
@@ -4108,11 +4105,11 @@ _failedobj_handle_routes(NML3Cfg *self, int addr_family, GPtrArray *routes_faile
             grace_timeout_msec = 0;
         }
 
-        grace_expiry_mesc = now_msec + grace_timeout_msec;
+        grace_expiry_msec = now_msec + grace_timeout_msec;
 
         if (obj_state->os_failedobj_expiry_msec == 0) {
             /* This is a new failure that we didn't see before... */
-            obj_state->os_failedobj_expiry_msec = grace_expiry_mesc;
+            obj_state->os_failedobj_expiry_msec = grace_expiry_msec;
             if (grace_timeout_msec == 0)
                 just_failed = TRUE;
             else {
@@ -4120,9 +4117,9 @@ _failedobj_handle_routes(NML3Cfg *self, int addr_family, GPtrArray *routes_faile
                 just_started_to_fail = TRUE;
             }
         } else {
-            if (obj_state->os_failedobj_expiry_msec > grace_expiry_mesc) {
+            if (obj_state->os_failedobj_expiry_msec > grace_expiry_msec) {
                 /* Shorten the grace timeout. We anyway rearm below... */
-                obj_state->os_failedobj_expiry_msec = grace_expiry_mesc;
+                obj_state->os_failedobj_expiry_msec = grace_expiry_msec;
             }
             if (obj_state->os_failedobj_expiry_msec <= now_msec) {
                 /* The grace period is (already) expired. */
diff --git a/src/core/nm-l3cfg.h b/src/core/nm-l3cfg.h
index 5ee201e7..9b8ec67f 100644
--- a/src/core/nm-l3cfg.h
+++ b/src/core/nm-l3cfg.h
@@ -92,6 +92,7 @@ typedef struct {
     NML3AcdAddrState            state;
     NML3Cfg                    *l3cfg;
     const NML3AcdAddrTrackInfo *track_infos;
+    NMEtherAddr                 last_conflict_addr;
 } NML3AcdAddrInfo;
 
 static inline const NML3AcdAddrTrackInfo *
diff --git a/src/core/nm-manager.c b/src/core/nm-manager.c
index 9c721220..937acbba 100644
--- a/src/core/nm-manager.c
+++ b/src/core/nm-manager.c
@@ -3222,6 +3222,13 @@ device_auth_done_cb(NMAuthChain *chain, GDBusMethodInvocation *context, gpointer
         nm_assert(error || (result == NM_AUTH_CALL_RESULT_YES));
     }
 
+    if (!error && !nm_dbus_object_is_exported(NM_DBUS_OBJECT(device))) {
+        g_set_error(&error,
+                    NM_MANAGER_ERROR,
+                    NM_MANAGER_ERROR_UNKNOWN_DEVICE,
+                    "device no longer exists");
+    }
+
     callback(device, context, subject, error, nm_auth_chain_get_data(chain, "user-data"));
 }
 
@@ -3287,6 +3294,14 @@ nm_manager_device_auth_request(NMManager                     *self,
                                                 &error))
         goto fail_on_idle;
 
+    if (!nm_dbus_object_is_exported(NM_DBUS_OBJECT(device))) {
+        g_set_error(&error,
+                    NM_MANAGER_ERROR,
+                    NM_MANAGER_ERROR_UNKNOWN_DEVICE,
+                    "device no longer exists");
+        goto fail_on_idle;
+    }
+
     chain = nm_auth_chain_new_subject(subject, context, device_auth_done_cb, self);
     if (cancellable)
         nm_auth_chain_set_cancellable(chain, cancellable);
diff --git a/src/libnm-core-impl/nm-setting-ip-tunnel.c b/src/libnm-core-impl/nm-setting-ip-tunnel.c
index d28eb73f..2deebf42 100644
--- a/src/libnm-core-impl/nm-setting-ip-tunnel.c
+++ b/src/libnm-core-impl/nm-setting-ip-tunnel.c
@@ -593,11 +593,22 @@ nm_setting_ip_tunnel_class_init(NMSettingIPTunnelClass *klass)
     /**
      * NMSettingIPTunnel:mode:
      *
-     * The tunneling mode, for example %NM_IP_TUNNEL_MODE_IPIP or
-     * %NM_IP_TUNNEL_MODE_GRE.
+     * The tunneling mode. Valid values: %NM_IP_TUNNEL_MODE_IPIP,
+     * %NM_IP_TUNNEL_MODE_GRE, %NM_IP_TUNNEL_MODE_SIT, %NM_IP_TUNNEL_MODE_ISATAP,
+     * %NM_IP_TUNNEL_MODE_VTI, %NM_IP_TUNNEL_MODE_IP6IP6, %NM_IP_TUNNEL_MODE_IPIP6,
+     * %NM_IP_TUNNEL_MODE_IP6GRE, %NM_IP_TUNNEL_MODE_VTI6, %NM_IP_TUNNEL_MODE_GRETAP
+     * and %NM_IP_TUNNEL_MODE_IP6GRETAP
      *
      * Since: 1.2
      **/
+    /* ---nmcli---
+     * property: mode
+     * description:
+     *   The tunneling mode. Valid values: ipip (1), gre (2), sit (3), isatap (4),
+     *   vti (5), ip6ip6 (6), ipip6 (7), ip6gre (8), vti6 (9), gretap (10) and
+     *   ip6gretap (11)
+     * ---end---
+     */
     _nm_setting_property_define_direct_uint32(properties_override,
                                               obj_properties,
                                               NM_SETTING_IP_TUNNEL_MODE,
@@ -731,10 +742,19 @@ nm_setting_ip_tunnel_class_init(NMSettingIPTunnelClass *klass)
      * NMSettingIPTunnel:encapsulation-limit:
      *
      * How many additional levels of encapsulation are permitted to be prepended
-     * to packets. This property applies only to IPv6 tunnels. To disable this option, add %NM_IP_TUNNEL_FLAG_IP6_IGN_ENCAP_LIMIT to ip-tunnel flags.
+     * to packets. This property applies only to IPv6 tunnels. To disable this option,
+     * add %NM_IP_TUNNEL_FLAG_IP6_IGN_ENCAP_LIMIT to ip-tunnel flags.
      *
      * Since: 1.2
      **/
+    /* ---nmcli---
+     * property: encapsulation-limit
+     * description:
+     *   How many additional levels of encapsulation are permitted to be prepended
+     *   to packets. This property applies only to IPv6 tunnels. To disable this
+     *   option, add 0x1 (ip6-ign-encap-limit) to ip-tunnel flags.
+     * ---end---
+     */
     _nm_setting_property_define_direct_uint32(properties_override,
                                               obj_properties,
                                               NM_SETTING_IP_TUNNEL_ENCAPSULATION_LIMIT,
@@ -814,6 +834,16 @@ nm_setting_ip_tunnel_class_init(NMSettingIPTunnelClass *klass)
      *
      * Since: 1.12
      **/
+    /* ---nmcli---
+     * property: flags
+     * description:
+     *   Tunnel flags. Currently, the following values are supported:
+     *   0x1 (ip6-ign-encap-limit), 0x2 (ip6-use-orig-tclass),
+     *   0x4 (ip6-use-orig-flowlabel), 0x8 (ip6-mip6-dev), 0x10 (ip6-rcv-dscp-copy)
+     *   and 0x20 (ip6-use-orig-fwmark).
+     *   They are valid only for IPv6 tunnels.
+     * ---end---
+     */
     _nm_setting_property_define_direct_uint32(properties_override,
                                               obj_properties,
                                               NM_SETTING_IP_TUNNEL_FLAGS,
diff --git a/src/libnm-core-public/nm-version-macros.h b/src/libnm-core-public/nm-version-macros.h
index 9b5233e4..14948f2b 100644
--- a/src/libnm-core-public/nm-version-macros.h
+++ b/src/libnm-core-public/nm-version-macros.h
@@ -30,7 +30,7 @@
  * Evaluates to the micro version number of NetworkManager which this source
  * compiled against.
  */
-#define NM_MICRO_VERSION (0)
+#define NM_MICRO_VERSION (2)
 
 /**
  * NM_CHECK_VERSION:
diff --git a/src/libnmc-base/nm-client-utils.c b/src/libnmc-base/nm-client-utils.c
index 4ce1ac6c..b052a307 100644
--- a/src/libnmc-base/nm-client-utils.c
+++ b/src/libnmc-base/nm-client-utils.c
@@ -712,6 +712,9 @@ nmc_print_qrcode(const char *str)
                 bool bottom = qrcodegen_getModule(qrcode, x, y + 1);
                 if (top) {
                     g_print(bottom ? " " : "\u2584");
+                } else if (y > size) {
+                    /* Print the last line (the bottom QR border) in light gray, no bg color */
+                    g_print("\033[0;37m\u2580");
                 } else {
                     g_print(bottom ? "\u2580" : "\u2588");
                 }
diff --git a/src/libnmc-setting/settings-docs.h b/src/libnmc-setting/settings-docs.h
index f06c981a..bdda8e50 100644
--- a/src/libnmc-setting/settings-docs.h
+++ b/src/libnmc-setting/settings-docs.h
@@ -219,13 +219,13 @@
 #define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_ROUTES N_("Array of IP routes.")
 #define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_ROUTING_RULES N_("A comma separated list of routing rules for policy routing.")
 #define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_TOKEN N_("Configure the token for draft-chown-6man-tokenised-ipv6-identifiers-02 IPv6 tokenized interface identifiers. Useful with eui64 addr-gen-mode. When set, the token is used as IPv6 interface identifier instead of the hardware address. This only applies to addresses from stateless autoconfiguration, not to IPv6 link local addresses.")
-#define DESCRIBE_DOC_NM_SETTING_IP_TUNNEL_ENCAPSULATION_LIMIT N_("How many additional levels of encapsulation are permitted to be prepended to packets. This property applies only to IPv6 tunnels. To disable this option, add NM_IP_TUNNEL_FLAG_IP6_IGN_ENCAP_LIMIT (0x1) to ip-tunnel flags.")
-#define DESCRIBE_DOC_NM_SETTING_IP_TUNNEL_FLAGS N_("Tunnel flags. Currently, the following values are supported: NM_IP_TUNNEL_FLAG_IP6_IGN_ENCAP_LIMIT (0x1), NM_IP_TUNNEL_FLAG_IP6_USE_ORIG_TCLASS (0x2), NM_IP_TUNNEL_FLAG_IP6_USE_ORIG_FLOWLABEL (0x4), NM_IP_TUNNEL_FLAG_IP6_MIP6_DEV (0x8), NM_IP_TUNNEL_FLAG_IP6_RCV_DSCP_COPY (0x10), NM_IP_TUNNEL_FLAG_IP6_USE_ORIG_FWMARK (0x20). They are valid only for IPv6 tunnels.")
+#define DESCRIBE_DOC_NM_SETTING_IP_TUNNEL_ENCAPSULATION_LIMIT N_("How many additional levels of encapsulation are permitted to be prepended to packets. This property applies only to IPv6 tunnels. To disable this option, add 0x1 (ip6-ign-encap-limit) to ip-tunnel flags.")
+#define DESCRIBE_DOC_NM_SETTING_IP_TUNNEL_FLAGS N_("Tunnel flags. Currently, the following values are supported: 0x1 (ip6-ign-encap-limit), 0x2 (ip6-use-orig-tclass), 0x4 (ip6-use-orig-flowlabel), 0x8 (ip6-mip6-dev), 0x10 (ip6-rcv-dscp-copy) and 0x20 (ip6-use-orig-fwmark). They are valid only for IPv6 tunnels.")
 #define DESCRIBE_DOC_NM_SETTING_IP_TUNNEL_FLOW_LABEL N_("The flow label to assign to tunnel packets. This property applies only to IPv6 tunnels.")
 #define DESCRIBE_DOC_NM_SETTING_IP_TUNNEL_FWMARK N_("The fwmark value to assign to tunnel packets. This property can be set to a non zero value only on VTI and VTI6 tunnels.")
 #define DESCRIBE_DOC_NM_SETTING_IP_TUNNEL_INPUT_KEY N_("The key used for tunnel input packets; the property is valid only for certain tunnel modes (GRE, IP6GRE). If empty, no key is used.")
 #define DESCRIBE_DOC_NM_SETTING_IP_TUNNEL_LOCAL N_("The local endpoint of the tunnel; the value can be empty, otherwise it must contain an IPv4 or IPv6 address.")
-#define DESCRIBE_DOC_NM_SETTING_IP_TUNNEL_MODE N_("The tunneling mode, for example NM_IP_TUNNEL_MODE_IPIP (1) or NM_IP_TUNNEL_MODE_GRE (2).")
+#define DESCRIBE_DOC_NM_SETTING_IP_TUNNEL_MODE N_("The tunneling mode. Valid values: ipip (1), gre (2), sit (3), isatap (4), vti (5), ip6ip6 (6), ipip6 (7), ip6gre (8), vti6 (9), gretap (10) and ip6gretap (11)")
 #define DESCRIBE_DOC_NM_SETTING_IP_TUNNEL_MTU N_("If non-zero, only transmit packets of the specified size or smaller, breaking larger packets up into multiple fragments.")
 #define DESCRIBE_DOC_NM_SETTING_IP_TUNNEL_OUTPUT_KEY N_("The key used for tunnel output packets; the property is valid only for certain tunnel modes (GRE, IP6GRE). If empty, no key is used.")
 #define DESCRIBE_DOC_NM_SETTING_IP_TUNNEL_PARENT N_("If given, specifies the parent interface name or parent connection UUID the new device will be bound to so that tunneled packets will only be routed via that interface.")
diff --git a/src/libnmc-setting/settings-docs.h.in b/src/libnmc-setting/settings-docs.h.in
index f06c981a..bdda8e50 100644
--- a/src/libnmc-setting/settings-docs.h.in
+++ b/src/libnmc-setting/settings-docs.h.in
@@ -219,13 +219,13 @@
 #define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_ROUTES N_("Array of IP routes.")
 #define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_ROUTING_RULES N_("A comma separated list of routing rules for policy routing.")
 #define DESCRIBE_DOC_NM_SETTING_IP6_CONFIG_TOKEN N_("Configure the token for draft-chown-6man-tokenised-ipv6-identifiers-02 IPv6 tokenized interface identifiers. Useful with eui64 addr-gen-mode. When set, the token is used as IPv6 interface identifier instead of the hardware address. This only applies to addresses from stateless autoconfiguration, not to IPv6 link local addresses.")
-#define DESCRIBE_DOC_NM_SETTING_IP_TUNNEL_ENCAPSULATION_LIMIT N_("How many additional levels of encapsulation are permitted to be prepended to packets. This property applies only to IPv6 tunnels. To disable this option, add NM_IP_TUNNEL_FLAG_IP6_IGN_ENCAP_LIMIT (0x1) to ip-tunnel flags.")
-#define DESCRIBE_DOC_NM_SETTING_IP_TUNNEL_FLAGS N_("Tunnel flags. Currently, the following values are supported: NM_IP_TUNNEL_FLAG_IP6_IGN_ENCAP_LIMIT (0x1), NM_IP_TUNNEL_FLAG_IP6_USE_ORIG_TCLASS (0x2), NM_IP_TUNNEL_FLAG_IP6_USE_ORIG_FLOWLABEL (0x4), NM_IP_TUNNEL_FLAG_IP6_MIP6_DEV (0x8), NM_IP_TUNNEL_FLAG_IP6_RCV_DSCP_COPY (0x10), NM_IP_TUNNEL_FLAG_IP6_USE_ORIG_FWMARK (0x20). They are valid only for IPv6 tunnels.")
+#define DESCRIBE_DOC_NM_SETTING_IP_TUNNEL_ENCAPSULATION_LIMIT N_("How many additional levels of encapsulation are permitted to be prepended to packets. This property applies only to IPv6 tunnels. To disable this option, add 0x1 (ip6-ign-encap-limit) to ip-tunnel flags.")
+#define DESCRIBE_DOC_NM_SETTING_IP_TUNNEL_FLAGS N_("Tunnel flags. Currently, the following values are supported: 0x1 (ip6-ign-encap-limit), 0x2 (ip6-use-orig-tclass), 0x4 (ip6-use-orig-flowlabel), 0x8 (ip6-mip6-dev), 0x10 (ip6-rcv-dscp-copy) and 0x20 (ip6-use-orig-fwmark). They are valid only for IPv6 tunnels.")
 #define DESCRIBE_DOC_NM_SETTING_IP_TUNNEL_FLOW_LABEL N_("The flow label to assign to tunnel packets. This property applies only to IPv6 tunnels.")
 #define DESCRIBE_DOC_NM_SETTING_IP_TUNNEL_FWMARK N_("The fwmark value to assign to tunnel packets. This property can be set to a non zero value only on VTI and VTI6 tunnels.")
 #define DESCRIBE_DOC_NM_SETTING_IP_TUNNEL_INPUT_KEY N_("The key used for tunnel input packets; the property is valid only for certain tunnel modes (GRE, IP6GRE). If empty, no key is used.")
 #define DESCRIBE_DOC_NM_SETTING_IP_TUNNEL_LOCAL N_("The local endpoint of the tunnel; the value can be empty, otherwise it must contain an IPv4 or IPv6 address.")
-#define DESCRIBE_DOC_NM_SETTING_IP_TUNNEL_MODE N_("The tunneling mode, for example NM_IP_TUNNEL_MODE_IPIP (1) or NM_IP_TUNNEL_MODE_GRE (2).")
+#define DESCRIBE_DOC_NM_SETTING_IP_TUNNEL_MODE N_("The tunneling mode. Valid values: ipip (1), gre (2), sit (3), isatap (4), vti (5), ip6ip6 (6), ipip6 (7), ip6gre (8), vti6 (9), gretap (10) and ip6gretap (11)")
 #define DESCRIBE_DOC_NM_SETTING_IP_TUNNEL_MTU N_("If non-zero, only transmit packets of the specified size or smaller, breaking larger packets up into multiple fragments.")
 #define DESCRIBE_DOC_NM_SETTING_IP_TUNNEL_OUTPUT_KEY N_("The key used for tunnel output packets; the property is valid only for certain tunnel modes (GRE, IP6GRE). If empty, no key is used.")
 #define DESCRIBE_DOC_NM_SETTING_IP_TUNNEL_PARENT N_("If given, specifies the parent interface name or parent connection UUID the new device will be bound to so that tunneled packets will only be routed via that interface.")
diff --git a/src/nmcli/gen-metadata-nm-settings-nmcli.xml.in b/src/nmcli/gen-metadata-nm-settings-nmcli.xml.in
index ef0973ca..1e0797ab 100644
--- a/src/nmcli/gen-metadata-nm-settings-nmcli.xml.in
+++ b/src/nmcli/gen-metadata-nm-settings-nmcli.xml.in
@@ -620,7 +620,7 @@
     <setting name="ip-tunnel" >
         <property name="mode"
                   alias="mode"
-                  nmcli-description="The tunneling mode, for example NM_IP_TUNNEL_MODE_IPIP (1) or NM_IP_TUNNEL_MODE_GRE (2)." />
+                  nmcli-description="The tunneling mode. Valid values: ipip (1), gre (2), sit (3), isatap (4), vti (5), ip6ip6 (6), ipip6 (7), ip6gre (8), vti6 (9), gretap (10) and ip6gretap (11)" />
         <property name="parent"
                   alias="dev"
                   nmcli-description="If given, specifies the parent interface name or parent connection UUID the new device will be bound to so that tunneled packets will only be routed via that interface." />
@@ -641,7 +641,7 @@
         <property name="output-key"
                   nmcli-description="The key used for tunnel output packets; the property is valid only for certain tunnel modes (GRE, IP6GRE). If empty, no key is used." />
         <property name="encapsulation-limit"
-                  nmcli-description="How many additional levels of encapsulation are permitted to be prepended to packets. This property applies only to IPv6 tunnels. To disable this option, add NM_IP_TUNNEL_FLAG_IP6_IGN_ENCAP_LIMIT (0x1) to ip-tunnel flags." />
+                  nmcli-description="How many additional levels of encapsulation are permitted to be prepended to packets. This property applies only to IPv6 tunnels. To disable this option, add 0x1 (ip6-ign-encap-limit) to ip-tunnel flags." />
         <property name="flow-label"
                   nmcli-description="The flow label to assign to tunnel packets. This property applies only to IPv6 tunnels." />
         <property name="fwmark"
@@ -649,7 +649,7 @@
         <property name="mtu"
                   nmcli-description="If non-zero, only transmit packets of the specified size or smaller, breaking larger packets up into multiple fragments." />
         <property name="flags"
-                  nmcli-description="Tunnel flags. Currently, the following values are supported: NM_IP_TUNNEL_FLAG_IP6_IGN_ENCAP_LIMIT (0x1), NM_IP_TUNNEL_FLAG_IP6_USE_ORIG_TCLASS (0x2), NM_IP_TUNNEL_FLAG_IP6_USE_ORIG_FLOWLABEL (0x4), NM_IP_TUNNEL_FLAG_IP6_MIP6_DEV (0x8), NM_IP_TUNNEL_FLAG_IP6_RCV_DSCP_COPY (0x10), NM_IP_TUNNEL_FLAG_IP6_USE_ORIG_FWMARK (0x20). They are valid only for IPv6 tunnels." />
+                  nmcli-description="Tunnel flags. Currently, the following values are supported: 0x1 (ip6-ign-encap-limit), 0x2 (ip6-use-orig-tclass), 0x4 (ip6-use-orig-flowlabel), 0x8 (ip6-mip6-dev), 0x10 (ip6-rcv-dscp-copy) and 0x20 (ip6-use-orig-fwmark). They are valid only for IPv6 tunnels." />
     </setting>
     <setting name="ipv4" >
         <property name="method"
diff --git a/src/nmcli/nmcli.c b/src/nmcli/nmcli.c
index 792edf6e..6de42faa 100644
--- a/src/nmcli/nmcli.c
+++ b/src/nmcli/nmcli.c
@@ -481,7 +481,7 @@ check_colors(NmcColorOption color_option, char **out_palette_str)
         return FALSE;
     }
 
-    if (color_option == NMC_USE_COLOR_AUTO && g_getenv("NO_COLOR")) {
+    if (color_option == NMC_USE_COLOR_AUTO && nm_str_not_empty(g_getenv("NO_COLOR"))) {
         /* https://no-color.org/ */
         return FALSE;
     }
@@ -489,7 +489,9 @@ check_colors(NmcColorOption color_option, char **out_palette_str)
     term = g_getenv("TERM");
 
     if (color_option == NMC_USE_COLOR_AUTO) {
-        if (nm_streq0(term, "dumb") || !isatty(STDOUT_FILENO))
+        if (nm_str_not_empty(g_getenv("CLICOLOR_FORCE"))) {
+            color_option = NMC_USE_COLOR_YES;
+        } else if (nm_streq0(term, "dumb") || !isatty(STDOUT_FILENO))
             return FALSE;
     }