summaryrefslogtreecommitdiff
Commit message (Collapse)AuthorAgeFilesLines
* cli/polkit: make parsing polkit-agent-helper-1 protocol more conformingth/cli-command-cleanupThomas Haller2020-04-093-140/+162
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | - in io_watch_have_data(), ensure that we handle incomplete lines that don't yet have a newline by waiting for more data. That means, if the current content of the in_buffer does not have a newline, we wait longer. - in io_watch_have_data(), implement (and ignore) certain commands instead of failing the request. - in io_watch_have_data(), no longer g_compress() the entire line. "polkitagenthelper-pam.c" never backslash escapes the command, it only escapes the arguments. Of course, there should be no difference in practice, except that we don't want to handle escape sequences in the commands. - in io_watch_have_data(), compare SUCCESS/FAILURE literally. "polkitagenthelper-pam.c" never appends any trailing garbage to these commands, and we shouldn't handle that (although "polkitagentsession.c" does). - when io_watch_have_data() completes with success, we cannot destroy AuthRequest right away. It probably still has data pending that we first need to write to the polkit helper. Wait longer, and let io_watch_can_write() complete the request. - ensure we always answer the GDBusMethodInvocation. Otherwise, it gets leaked. - use NMStrBuf instead of GString.
* cli/polkit: suppress stderr from polkit-agent-helper when prompting for ↵Thomas Haller2020-04-091-1/+1
| | | | | | | | | | | | | polkit authentication Otherwise, we get an additional error message form the helper: $ nmcli --ask device wifi rescan System policy prevents Wi-Fi scans (action_id: org.freedesktop.NetworkManager.wifi.scan) password (user): ••••••• polkit-agent-helper-1: pam_authenticate failed: Authentication failure Error: org.freedesktop.NetworkManager.wifi.scan request failed: not authorized.
* cli/polkit: rework parsing identities for polkit requestThomas Haller2020-04-091-64/+72
| | | | | The identities are in a nested dictionary of variants. We only want to pick the "unix-user" values that we can handle.
* cli/polkit: reject unknown D-Bus methodsThomas Haller2020-04-091-3/+25
|
* cli/polkit: rename NM_POLKIT_LISTENER_SIGNAL_REQUEST signal to "request-sync"Thomas Haller2020-04-093-7/+7
| | | | | | The response is blocking, which generally is rather ugly. Let's not fix that now, but at least rename the signal so that it clearly points this out.
* cli/polkit: avoid G_DECLARE_FINAL_TYPE() in nm-polkit-listener.hThomas Haller2020-04-092-11/+22
| | | | G_DECLARE_FINAL_TYPE() is glib 2.44, while we currently still only require glib 2.40.
* shared: fix returning EAGAIN from nm_utils_fd_read()Thomas Haller2020-04-091-8/+6
| | | | | | | We cannot just swallow EAGAIN and pretend that not bytes were read. read() returning zero means end of file. The caller needs to distinguish between end of file and EAGAIN.
* shared/strbuf: fix signedness of integer comparison in ↵Thomas Haller2020-04-091-1/+1
| | | | nm_str_buf_append_printf()
* shared/strbuf: rename private, mutable fields in NMStrBuf structureThomas Haller2020-04-092-63/+69
| | | | | | | | | | | | | NMStrBuf is not an opaque structure, so that we can allocate it on the stack or embed it in a struct. But most of the fields should not be touched outside of the implementation. Also, "len" and "allocated" fields may be accessed directly, but they should not be modified. Rename the fields to make that clearer.
* shared/strbuf: add nm_str_buf_is_initalized() helperThomas Haller2020-04-091-0/+11
|
* shared/strbuf: add nm_str_buf_erase() helperThomas Haller2020-04-092-0/+73
|
* shared/strbuf: add nm_str_buf_get_str_unsafe() helper function to give ↵Thomas Haller2020-04-091-0/+7
| | | | direct access to string buffer
* shared/strbuf: add nm_str_buf_set_size() helper functionThomas Haller2020-04-091-0/+49
|
* shared/strbuf: add nm_str_buf_ensure_trailing_c() helper functionThomas Haller2020-04-091-0/+10
|
* shared/strbuf: expose read only value for "allocated" buffer sizeThomas Haller2020-04-091-1/+4
| | | | | | | | | | | | | | We cannot actually mark the field as const, because then you could no longer initialize a variable that contains a NMStrBuf with designated initializers. We also want to keep the "_allocated" alias, for the only places that are allowed to mutate the field: inside "nm-str-buf.h". Add an alias for that field, that is allowed to be read, provided that you don't modify it! The alternative would be a nm_str_buf_get_allocated() accessor, but that seems unnecessarily verbose when you could just access the field.
* shared/strbuf: don't have const values in NMStrBufThomas Haller2020-04-091-1/+1
| | | | | | | | | | | | | Before, if a struct had a field of type NMStrBuf (which is sensible to do), then you could not longer initialize the entire struct with *ptr = (Type) { }; because NMStrBuf contained const fields. The user should never set these fields directly and use nm_str_buf_*() to modify them them. But no longer mark them as const, because that breaks valid use cases.
* shared/strbuf: allow forward declaring "struct _NMStrBuf"Thomas Haller2020-04-091-1/+1
|
* shared/strbuf: only clear the bytes that we actually wrote toThomas Haller2020-04-091-1/+1
| | | | | | | | | The allocated buffes are not known to be written. It is unnecessary to clear them. If the user writes sensitive data to those locations, without using the NMStrBuf API, then it is up to the user to bzero the memory accordingly.
* shared: add NM_UTILS_GET_NEXT_REALLOC_SIZE_1000 defineThomas Haller2020-04-092-0/+25
| | | | | | | | | | | | When we have a buffer that we want to grow exponentially with nm_utils_get_next_realloc_size(), then there are certain buffer sizes that are better suited. For example, if you have an empty NMStrBuf (len == 0), and you want to allocate roughly one kilobyte, then 1024 is a bad choice, because nm_utils_get_next_realloc_size() will give you 2024 bytes. NM_UTILS_GET_NEXT_REALLOC_SIZE_1000 might be better in this case.
* cli: remove redundant return value from NMCCommand funcsThomas Haller2020-04-096-313/+307
| | | | | | | | | | | | | | | Many func implementations are asynchronous, that means, they cannot return right away. Instead, they record the return value in nmc->result_value. The return value from the command functions was thus redundant. In the best case, the return value agrees with the cached result in nmc->result_value, in which it was unnecessary. In the worst case, they disagree, and overwrite each other. nmc->result_value is state. Tracking state is hard, and there should be fewer places where the state gets mutated. Also, the rules how that happened should be clearer. Drop the redundant, conflicting mechanism.
* cli: mark argv argument for command line parsing as constThomas Haller2020-04-0911-151/+171
| | | | | | | | | It's bad style to pass the argv argument around and mutate it. We shouldn't mutate it, and not assume that it stays around after the function returns to the caller (meaning, we should clone the array if we intend to use it later). Add const specifier.
* cli: merge implementations for do_networking_on_off()Thomas Haller2020-04-091-17/+7
|
* cli: pass cmd to NMCCommand.func()Thomas Haller2020-04-096-70/+70
| | | | | | | | | | | | | | It is useful from inside a function to know the command that it belongs to. Currently we have do_networking_on() and do_networking_off() as separate functions. However, these are basically the same with a minor difference. If the func callback could know the "cmd" that it was called for, these function can be combined. Of course, without passing the NMCCommand instance, you still can achieve the same results, especially as the NMCCommand instances are static and known at compile time: just have separate func implementations. But by passing the command to the function, they *can* be combined, which is a useful thing to do.
* cli: cleanup NMCCommand and declarations of func implementationsThomas Haller2020-04-0912-164/+108
| | | | | | | | | | | | | | - move the main func declarations to nmcli.h and give them a common prefix "nmc_command_func_" prefix. - remove some of the header files that are now empty. In fact, these headers did not really declare some well separated module. While we probably should structure the code in nmcli better with better layering, it was not and still is not. Having these dummy headers don't mean that the code is well structured and they serve little purpose. - move the static NMCommand lists variables into the function scope where they are used.
* shared/tests: avoid undefined behavior in ↵Thomas Haller2020-04-091-1/+1
| | | | test_nm_utils_get_next_realloc_size() test
* ovsdb: retry calls in case of communication error with serverBeniamino Galvani2020-04-091-26/+55
| | | | | | | | | | | | When the server is restarted the write to unix socket fails with EPIPE. In such case, don't fail all the calls in queue; instead, after a sync of the ovsdb state (through a monitor call), start processing the queue again, including the call that previously failed. Add a retry counter to avoid that calls are stuck in the queue forever in a hypothetical scenario in which the write always fails. https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/459
* device: fix assertion failure configuring bridge portsBeniamino Galvani2020-04-091-1/+4
| | | | Fixes: 177ee2d7bf99 ('device/bridge: code cleanup in commit_option()')
* clients/trivial: remove obsolete comment from test-client.py howtoThomas Haller2020-04-091-5/+0
| | | | | | This would only be necessary when editing the test themselves, to not only remove individual tests, but entire test runs. It's not necessary to describe that in the howto.
* device/bridge: code cleanup in commit_option()Thomas Haller2020-04-091-41/+40
|
* device/bridge: fix uninitialized variable in commit_option()Thomas Haller2020-04-091-0/+1
| | | | Fixes: 93e38cbe56f4 ('nm-setting-bridge: add 'group-address' bridge option')
* dns: fix crash in rebuild_domain_lists()Thomas Haller2020-04-081-2/+2
| | | | Fixes: 103943776c12 ('dns: cleanup rebuild_domain_lists() constructing domains list')
* clients: set ipv4.dns-priority to a exclusive value (-10) when importing ↵Thomas Haller2020-04-081-0/+8
| | | | WireGuard profiles
* dns: add FIXME comment about adding default "~" routing search domainThomas Haller2020-04-081-0/+5
|
* clients: set routing search domain with nameservers when importing WireGuard ↵Thomas Haller2020-04-083-0/+19
| | | | | | | | | | | | | | | | | | | profile When the users configure a DNS server on the interface, they likely want to use it, regardless whether there is a default route on the device. For that to work, add an explicit "~" search domain. Otherwise, by default NetworkManager only adds the special search domain only on devices that have a "best default route" (nm_ip_config_best_default_route_is). But that only considers a best default route in the main table, and WireGuard (with ipx-auto-default-route) adds the default route to a separate table. The heuristic to determine best devices works not well with policy routing, so explicitly add this search domain during import. https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/issues/405
* clients: use nm_utils_inet_ntop_dup() in nm_vpn_wireguard_import()Thomas Haller2020-04-081-3/+2
|
* clients/trivial: fix outdated code comment about Table=auto in ↵Thomas Haller2020-04-081-3/+4
| | | | nm_vpn_wireguard_import()
* dns: cleanup rebuild_domain_lists() constructing domains listThomas Haller2020-04-081-29/+49
|
* systemd: merge branch systemd into masterThomas Haller2020-04-0822-59/+360
|\
| * systemd: update code from upstream (2020-04-08)Thomas Haller2020-04-0820-59/+351
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | This is a direct dump from systemd git. ====== SYSTEMD_DIR=../systemd COMMIT=8ff8ce62845e708186077d11eba83adae7b02e61 ( cd "$SYSTEMD_DIR" git checkout "$COMMIT" git reset --hard git clean -fdx ) git ls-files -z :/src/systemd/src/ \ :/shared/systemd/src/ \ :/shared/nm-std-aux/unaligned.h | \ xargs -0 rm -f nm_copy_sd_shared() { mkdir -p "./shared/systemd/$(dirname "$1")" cp "$SYSTEMD_DIR/$1" "./shared/systemd/$1" } nm_copy_sd_core() { mkdir -p "./src/systemd/$(dirname "$1")" cp "$SYSTEMD_DIR/$1" "./src/systemd/$1" } nm_copy_sd_stdaux() { mkdir -p "./shared/nm-std-aux/" cp "$SYSTEMD_DIR/$1" "./shared/nm-std-aux/${1##*/}" } nm_copy_sd_core "src/libsystemd-network/arp-util.c" nm_copy_sd_core "src/libsystemd-network/arp-util.h" nm_copy_sd_core "src/libsystemd-network/dhcp-identifier.c" nm_copy_sd_core "src/libsystemd-network/dhcp-identifier.h" nm_copy_sd_core "src/libsystemd-network/dhcp-internal.h" nm_copy_sd_core "src/libsystemd-network/dhcp-lease-internal.h" nm_copy_sd_core "src/libsystemd-network/dhcp-network.c" nm_copy_sd_core "src/libsystemd-network/dhcp-option.c" nm_copy_sd_core "src/libsystemd-network/dhcp-packet.c" nm_copy_sd_core "src/libsystemd-network/dhcp-protocol.h" nm_copy_sd_core "src/libsystemd-network/dhcp6-internal.h" nm_copy_sd_core "src/libsystemd-network/dhcp6-lease-internal.h" nm_copy_sd_core "src/libsystemd-network/dhcp6-network.c" nm_copy_sd_core "src/libsystemd-network/dhcp6-option.c" nm_copy_sd_core "src/libsystemd-network/dhcp6-protocol.h" nm_copy_sd_core "src/libsystemd-network/lldp-internal.h" nm_copy_sd_core "src/libsystemd-network/lldp-neighbor.c" nm_copy_sd_core "src/libsystemd-network/lldp-neighbor.h" nm_copy_sd_core "src/libsystemd-network/lldp-network.c" nm_copy_sd_core "src/libsystemd-network/lldp-network.h" nm_copy_sd_core "src/libsystemd-network/network-internal.c" nm_copy_sd_core "src/libsystemd-network/network-internal.h" nm_copy_sd_core "src/libsystemd-network/sd-dhcp-client.c" nm_copy_sd_core "src/libsystemd-network/sd-dhcp-lease.c" nm_copy_sd_core "src/libsystemd-network/sd-dhcp6-client.c" nm_copy_sd_core "src/libsystemd-network/sd-dhcp6-lease.c" nm_copy_sd_core "src/libsystemd-network/sd-ipv4acd.c" nm_copy_sd_core "src/libsystemd-network/sd-ipv4ll.c" nm_copy_sd_core "src/libsystemd-network/sd-lldp.c" nm_copy_sd_core "src/libsystemd/sd-event/event-source.h" nm_copy_sd_core "src/libsystemd/sd-event/event-util.c" nm_copy_sd_core "src/libsystemd/sd-event/event-util.h" nm_copy_sd_core "src/libsystemd/sd-event/sd-event.c" nm_copy_sd_core "src/libsystemd/sd-id128/id128-util.c" nm_copy_sd_core "src/libsystemd/sd-id128/id128-util.h" nm_copy_sd_core "src/libsystemd/sd-id128/sd-id128.c" nm_copy_sd_core "src/systemd/_sd-common.h" nm_copy_sd_core "src/systemd/sd-dhcp-client.h" nm_copy_sd_core "src/systemd/sd-dhcp-lease.h" nm_copy_sd_core "src/systemd/sd-dhcp-option.h" nm_copy_sd_core "src/systemd/sd-dhcp6-client.h" nm_copy_sd_core "src/systemd/sd-dhcp6-lease.h" nm_copy_sd_core "src/systemd/sd-event.h" nm_copy_sd_core "src/systemd/sd-id128.h" nm_copy_sd_core "src/systemd/sd-ipv4acd.h" nm_copy_sd_core "src/systemd/sd-ipv4ll.h" nm_copy_sd_core "src/systemd/sd-lldp.h" nm_copy_sd_core "src/systemd/sd-ndisc.h" nm_copy_sd_shared "src/basic/alloc-util.c" nm_copy_sd_shared "src/basic/alloc-util.h" nm_copy_sd_shared "src/basic/async.h" nm_copy_sd_shared "src/basic/cgroup-util.h" nm_copy_sd_shared "src/basic/env-file.c" nm_copy_sd_shared "src/basic/env-file.h" nm_copy_sd_shared "src/basic/env-util.c" nm_copy_sd_shared "src/basic/env-util.h" nm_copy_sd_shared "src/basic/errno-util.h" nm_copy_sd_shared "src/basic/escape.c" nm_copy_sd_shared "src/basic/escape.h" nm_copy_sd_shared "src/basic/ether-addr-util.c" nm_copy_sd_shared "src/basic/ether-addr-util.h" nm_copy_sd_shared "src/basic/extract-word.c" nm_copy_sd_shared "src/basic/extract-word.h" nm_copy_sd_shared "src/basic/fd-util.c" nm_copy_sd_shared "src/basic/fd-util.h" nm_copy_sd_shared "src/basic/fileio.c" nm_copy_sd_shared "src/basic/fileio.h" nm_copy_sd_shared "src/basic/format-util.c" nm_copy_sd_shared "src/basic/format-util.h" nm_copy_sd_shared "src/basic/fs-util.c" nm_copy_sd_shared "src/basic/fs-util.h" nm_copy_sd_shared "src/basic/hash-funcs.c" nm_copy_sd_shared "src/basic/hash-funcs.h" nm_copy_sd_shared "src/basic/hashmap.c" nm_copy_sd_shared "src/basic/hashmap.h" nm_copy_sd_shared "src/basic/hexdecoct.c" nm_copy_sd_shared "src/basic/hexdecoct.h" nm_copy_sd_shared "src/basic/hostname-util.c" nm_copy_sd_shared "src/basic/hostname-util.h" nm_copy_sd_shared "src/basic/in-addr-util.c" nm_copy_sd_shared "src/basic/in-addr-util.h" nm_copy_sd_shared "src/basic/io-util.c" nm_copy_sd_shared "src/basic/io-util.h" nm_copy_sd_shared "src/basic/list.h" nm_copy_sd_shared "src/basic/log.h" nm_copy_sd_shared "src/basic/macro.h" nm_copy_sd_shared "src/basic/memory-util.c" nm_copy_sd_shared "src/basic/memory-util.h" nm_copy_sd_shared "src/basic/mempool.c" nm_copy_sd_shared "src/basic/mempool.h" nm_copy_sd_shared "src/basic/missing_fcntl.h" nm_copy_sd_shared "src/basic/missing_random.h" nm_copy_sd_shared "src/basic/missing_socket.h" nm_copy_sd_shared "src/basic/missing_stat.h" nm_copy_sd_shared "src/basic/missing_syscall.h" nm_copy_sd_shared "src/basic/missing_type.h" nm_copy_sd_shared "src/basic/parse-util.c" nm_copy_sd_shared "src/basic/parse-util.h" nm_copy_sd_shared "src/basic/path-util.c" nm_copy_sd_shared "src/basic/path-util.h" nm_copy_sd_shared "src/basic/prioq.c" nm_copy_sd_shared "src/basic/prioq.h" nm_copy_sd_shared "src/basic/process-util.c" nm_copy_sd_shared "src/basic/process-util.h" nm_copy_sd_shared "src/basic/random-util.c" nm_copy_sd_shared "src/basic/random-util.h" nm_copy_sd_shared "src/basic/set.h" nm_copy_sd_shared "src/basic/signal-util.c" nm_copy_sd_shared "src/basic/signal-util.h" nm_copy_sd_shared "src/basic/siphash24.h" nm_copy_sd_shared "src/basic/socket-util.c" nm_copy_sd_shared "src/basic/socket-util.h" nm_copy_sd_shared "src/basic/sort-util.h" nm_copy_sd_shared "src/basic/sparse-endian.h" nm_copy_sd_shared "src/basic/stat-util.c" nm_copy_sd_shared "src/basic/stat-util.h" nm_copy_sd_shared "src/basic/stdio-util.h" nm_copy_sd_shared "src/basic/string-table.c" nm_copy_sd_shared "src/basic/string-table.h" nm_copy_sd_shared "src/basic/string-util.c" nm_copy_sd_shared "src/basic/string-util.h" nm_copy_sd_shared "src/basic/strv.c" nm_copy_sd_shared "src/basic/strv.h" nm_copy_sd_shared "src/basic/strxcpyx.c" nm_copy_sd_shared "src/basic/strxcpyx.h" nm_copy_sd_shared "src/basic/time-util.c" nm_copy_sd_shared "src/basic/time-util.h" nm_copy_sd_shared "src/basic/tmpfile-util.c" nm_copy_sd_shared "src/basic/tmpfile-util.h" nm_copy_sd_shared "src/basic/umask-util.h" nm_copy_sd_shared "src/basic/user-util.h" nm_copy_sd_shared "src/basic/utf8.c" nm_copy_sd_shared "src/basic/utf8.h" nm_copy_sd_shared "src/basic/util.c" nm_copy_sd_shared "src/basic/util.h" nm_copy_sd_shared "src/shared/dns-domain.c" nm_copy_sd_shared "src/shared/dns-domain.h" nm_copy_sd_shared "src/shared/web-util.c" nm_copy_sd_shared "src/shared/web-util.h" nm_copy_sd_stdaux "src/basic/unaligned.h"
* | license: Add Frédéric to RELICENSE.mdFrédéric Danis2020-04-082-0/+2
| | | | | | | | | | | | | | | | | | | | | | | | I, Frédéric Danis, agree to relicense my contributions to NetworkManager as LGPL-2.1+ as proposed by Thomas Haller. Some of my work may be held under copyright by Sigfox or Collabora Ltd. I do not speak for those entities. Signed-off-by: Frédéric Danis <frederic.danis.oss@gmail.com> https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/462
* | po: update Ukrainian (uk) translationYuri Chornoivan2020-04-071-1062/+1042
| | | | | | | | https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/461
* | bridge: merge branch 'ac/bridge_options'Antonio Cardace2020-04-0612-147/+944
|\ \ | | | | | | | | | https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/449
| * | nm-setting-bridge: add 'multicast-querier' bridge optionac/bridge_optionsAntonio Cardace2020-04-068-0/+68
| | | | | | | | | | | | https://bugzilla.redhat.com/show_bug.cgi?id=1755768
| * | nm-setting-bridge: add 'multicast-query-use-ifaddr' bridge optionAntonio Cardace2020-04-068-98/+166
| | | | | | | | | | | | https://bugzilla.redhat.com/show_bug.cgi?id=1755768
| * | nm-setting-bridge: add 'multicast-router' bridge optionAntonio Cardace2020-04-069-0/+155
| | | | | | | | | | | | | | | | | | Also add related unit test. https://bugzilla.redhat.com/show_bug.cgi?id=1755768
| * | nm-setting-bridge: add 'vlan-stats-enabled' bridge optionAntonio Cardace2020-04-068-14/+80
| | | | | | | | | | | | https://bugzilla.redhat.com/show_bug.cgi?id=1755768
| * | nm-setting-bridge: add 'vlan-protocol' bridge optionAntonio Cardace2020-04-069-0/+125
| | | | | | | | | | | | | | | | | | Also add related unit test. https://bugzilla.redhat.com/show_bug.cgi?id=1755768
| * | nm-setting-bridge: add 'group-address' bridge optionAntonio Cardace2020-04-0612-65/+382
| | | | | | | | | | | | | | | | | | Also add related unit test. https://bugzilla.redhat.com/show_bug.cgi?id=1755768
| * | nm-setting-bridge: hide GObject structs from public API and embed private dataAntonio Cardace2020-04-062-18/+16
|/ / | | | | | | | | | | | | | | | | | | Hide the object and class structures from public API. This is an API and ABI break, but of something that is very likely unused. This is mainly done to embed the private structure in the object itself. This has benefits for performance and debugability.
* | libnm,cli: merge branch 'th/libnm-setting-vpn-cleanup'Thomas Haller2020-04-049-343/+1118
|\ \ | | | | | | | | | | | | | | | https://gitlab.freedesktop.org/NetworkManager/NetworkManager/issues/390 https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/453