mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git
synced 2026-03-11 23:30:44 +01:00
tmp
This commit is contained in:
commit
1470441226
125 changed files with 25683 additions and 16757 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -81,7 +81,6 @@ test-*.trs
|
|||
/data/org.freedesktop.NetworkManager.service
|
||||
/data/server.conf
|
||||
/data/org.freedesktop.NetworkManager.policy
|
||||
/data/org.freedesktop.NetworkManager.policy.in
|
||||
/data/nm-sudo.service
|
||||
/data/nm-priv-helper.service
|
||||
/data/NetworkManager-config-initrd.service
|
||||
|
|
|
|||
|
|
@ -60,11 +60,11 @@ variables:
|
|||
#
|
||||
# This is done by running `ci-fairy generate-template` and possibly bumping
|
||||
# ".default_tag".
|
||||
ALPINE_TAG: 'tag-0c3a6f855fb8'
|
||||
CENTOS_TAG: 'tag-c1c23df75dda'
|
||||
DEBIAN_TAG: 'tag-d4bf5db9e214'
|
||||
FEDORA_TAG: 'tag-c1c23df75dda'
|
||||
UBUNTU_TAG: 'tag-d4bf5db9e214'
|
||||
ALPINE_TAG: 'tag-8e4bbc59695b'
|
||||
CENTOS_TAG: 'tag-caf6673db1a7'
|
||||
DEBIAN_TAG: 'tag-e394e8e726e1'
|
||||
FEDORA_TAG: 'tag-caf6673db1a7'
|
||||
UBUNTU_TAG: 'tag-e394e8e726e1'
|
||||
|
||||
ALPINE_EXEC: 'bash .gitlab-ci/alpine-install.sh'
|
||||
CENTOS_EXEC: 'bash .gitlab-ci/fedora-install.sh'
|
||||
|
|
|
|||
55
NEWS
55
NEWS
|
|
@ -1,12 +1,58 @@
|
|||
=============================================
|
||||
NetworkManager-1.56
|
||||
Overview of changes since NetworkManager-1.54
|
||||
NetworkManager-1.58
|
||||
Overview of changes since NetworkManager-1.56
|
||||
=============================================
|
||||
|
||||
This is a snapshot of NetworkManager development. The API is
|
||||
subject to change and not guaranteed to be compatible with
|
||||
the later release.
|
||||
USE AT YOUR OWN RISK. NOT RECOMMENDED FOR PRODUCTION USE!
|
||||
|
||||
* Unify the versioning to use everywhere the scheme with the -rcX or -dev
|
||||
suffixes when appropriate. This affects, for example, the URL and filename
|
||||
of the release tarball and the version reported by nmcli and the daemon.
|
||||
As an exception, the C API will continue to use the 90+ scheme for RC versions.
|
||||
* Restrict the connectivity check to use the DNS servers defined on the
|
||||
same link. If the link has no DNS servers, the connectivity check will
|
||||
use any servers available in the system.
|
||||
* Install the systemd units in the initramfs using a systemd generator.
|
||||
* A new "check-connectivity" configuration option is available to disable the
|
||||
connectivity check for selected interfaces.
|
||||
* Remove the modify_system build option that allowed setting up the
|
||||
polkit permissions to allow non-admin users to create system-wide
|
||||
connection. That configuration is discouraged because it can be used
|
||||
to bypass filesystem permissions.
|
||||
* For private connections (the ones that specify a user in the
|
||||
"connection.permissions" property), verify that the user can access
|
||||
the 802.1X certificates and keys set in the connection.
|
||||
* Introduce a libnm function that can be used by VPN plugins to check
|
||||
user permissions on certificate and keys.
|
||||
* The support for Wireless Extensions is deprecated and will be
|
||||
removed in a future release. Wireless Extensions are now disabled by
|
||||
default.
|
||||
* Use an internal implementation of the ping functionality when the
|
||||
"connection.gateway-ping-timeout" or "connection.ip-ping-addresses"
|
||||
properties are set, instead of relying on the "ping" tool.
|
||||
* The powersave property now functions with the iwd backend.
|
||||
* The "band" property of Wi-fi connections now accepts the "6GHz"
|
||||
value.
|
||||
* Show the Wi-Fi band of APs in the scan results from nmcli.
|
||||
* New <Select...> button in nmtui that allows users to chose from list of
|
||||
available devices when creating connection profiles for physical interfaces
|
||||
(Ethernet, Wi-Fi, etc.).
|
||||
* Add support for CLAT (464XLAT) using a BPF program.
|
||||
* Change the default value of the ipv4.dhcp-ipv6-only-preferred property
|
||||
to a new value "auto" which automatically enables the option when CLAT
|
||||
is enabled ("yes" or "auto") in the connection profile.
|
||||
* WIFI connections using wpa-psk respect the setting connection.auth-retry
|
||||
and only prompt for new secrets during the last authentication attempt before
|
||||
failing.
|
||||
|
||||
=============================================
|
||||
NetworkManager-1.56
|
||||
Overview of changes since NetworkManager-1.54
|
||||
=============================================
|
||||
|
||||
* nmcli now supports viewing and managing WireGuard peers.
|
||||
* Support reapplying the "sriov.vfs" property as long as
|
||||
"sriov.total-vfs" is not changed.
|
||||
|
|
@ -35,11 +81,6 @@ Overview of changes since NetworkManager-1.54
|
|||
for eBPF is now detected at run time.
|
||||
* Add new MPTCP 'laminar' endpoint type, and set it by default alongside
|
||||
the 'subflow' one.
|
||||
* For private connections (the ones that specify a user in the
|
||||
"connection.permissions" property), verify that the user can access
|
||||
the 802.1X certificates and keys set in the connection.
|
||||
* Introduce a libnm function that can be used by VPN plugins to check
|
||||
user permissions on certificate and keys.
|
||||
|
||||
=============================================
|
||||
NetworkManager-1.54
|
||||
|
|
|
|||
|
|
@ -294,3 +294,6 @@
|
|||
|
||||
/* Define to 1 if dlvsym() is available */
|
||||
#mesondefine HAVE_DLVSYM
|
||||
|
||||
/* Define to 1 if you want CLAT support. */
|
||||
#mesondefine HAVE_CLAT
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ apk add \
|
|||
'alpine-sdk' \
|
||||
'autoconf' \
|
||||
'bash' \
|
||||
'bpftool' \
|
||||
'clang' \
|
||||
'curl-dev' \
|
||||
'dbus' \
|
||||
|
|
@ -23,6 +24,7 @@ apk add \
|
|||
'iproute2' \
|
||||
'iptables' \
|
||||
'jansson-dev' \
|
||||
'libbpf-dev' \
|
||||
'libgudev-dev' \
|
||||
'libndp-dev' \
|
||||
'libnvme-dev' \
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ install_ignore_missing() {
|
|||
|
||||
install \
|
||||
\
|
||||
bpftool \
|
||||
clang \
|
||||
dbus \
|
||||
dbus-x11 \
|
||||
|
|
@ -43,6 +44,7 @@ install \
|
|||
iproute2 \
|
||||
iptables \
|
||||
libaudit-dev \
|
||||
libbpf-dev \
|
||||
libcurl4-gnutls-dev \
|
||||
libdbus-1-dev \
|
||||
libgirepository1.0-dev \
|
||||
|
|
|
|||
|
|
@ -49,6 +49,7 @@ install \
|
|||
ModemManager-glib-devel \
|
||||
audit-libs-devel \
|
||||
bluez-libs-devel \
|
||||
bpftool \
|
||||
clang \
|
||||
dbus-devel \
|
||||
dbus-x11 \
|
||||
|
|
@ -64,6 +65,7 @@ install \
|
|||
iptables \
|
||||
jansson-devel \
|
||||
jq \
|
||||
libbpf-devel \
|
||||
libcurl-devel \
|
||||
libndp-devel \
|
||||
libnvme-devel \
|
||||
|
|
|
|||
|
|
@ -100,7 +100,17 @@ Release: __RELEASE_VERSION__%{?dist}
|
|||
%else
|
||||
%bcond_without iwd
|
||||
%endif
|
||||
|
||||
%if 0%{?fedora} <= 43 || 0%{?rhel} <= 10
|
||||
%bcond_without polkit_noauth_group
|
||||
%else
|
||||
%bcond_with polkit_noauth_group
|
||||
%endif
|
||||
%ifarch %{ix86}
|
||||
# there is no bpftool in i686
|
||||
%bcond_with clat
|
||||
%else
|
||||
%bcond_without clat
|
||||
%endif
|
||||
###############################################################################
|
||||
|
||||
%global dbus_version 1.9.18
|
||||
|
|
@ -178,7 +188,9 @@ Requires: dbus >= %{dbus_version}
|
|||
Requires: glib2 >= %{glib2_version}
|
||||
Requires: %{name}-libnm%{?_isa} = %{epoch}:%{version}-%{release}
|
||||
|
||||
Recommends: iputils
|
||||
%if %{with clat}
|
||||
Requires: libbpf
|
||||
%endif
|
||||
|
||||
%if 0%{?rhel} == 8
|
||||
# Older libndp versions use select() (rh#1933041). On well known distros,
|
||||
|
|
@ -227,6 +239,7 @@ Conflicts: NetworkManager-dispatcher-routing-rules <= 1:1.47.5-3
|
|||
%endif
|
||||
|
||||
BuildRequires: gcc
|
||||
BuildRequires: clang
|
||||
BuildRequires: pkgconfig
|
||||
BuildRequires: meson
|
||||
BuildRequires: gettext-devel >= 0.19.8
|
||||
|
|
@ -281,6 +294,10 @@ BuildRequires: firewalld-filesystem
|
|||
BuildRequires: iproute
|
||||
BuildRequires: iproute-tc
|
||||
BuildRequires: libnvme-devel >= 1.5
|
||||
%if %{with clat}
|
||||
BuildRequires: libbpf-devel
|
||||
BuildRequires: bpftool
|
||||
%endif
|
||||
|
||||
Provides: %{name}-dispatcher%{?_isa} = %{epoch}:%{version}-%{release}
|
||||
|
||||
|
|
@ -600,19 +617,20 @@ Preferably use nmcli instead.
|
|||
%endif
|
||||
%if %{with wifi}
|
||||
-Dwifi=true \
|
||||
%if 0%{?fedora}
|
||||
-Dwext=true \
|
||||
%else
|
||||
-Dwext=false \
|
||||
%endif
|
||||
%else
|
||||
-Dwifi=false \
|
||||
%endif
|
||||
-Dwext=false \
|
||||
%if %{with iwd}
|
||||
-Diwd=true \
|
||||
%else
|
||||
-Diwd=false \
|
||||
%endif
|
||||
%if %{with clat}
|
||||
-Dclat=true \
|
||||
%else
|
||||
-Dclat=false \
|
||||
%endif
|
||||
%if %{with bluetooth}
|
||||
-Dbluez5_dun=true \
|
||||
%else
|
||||
|
|
@ -649,7 +667,9 @@ Preferably use nmcli instead.
|
|||
-Dselinux=true \
|
||||
-Dpolkit=true \
|
||||
-Dconfig_auth_polkit_default=true \
|
||||
-Dmodify_system=true \
|
||||
%if %{with polkit_noauth_group}
|
||||
-Dpolkit_noauth_group=wheel \
|
||||
%endif
|
||||
-Dconcheck=true \
|
||||
%if 0%{?fedora}
|
||||
-Dlibpsl=true \
|
||||
|
|
@ -659,6 +679,7 @@ Preferably use nmcli instead.
|
|||
-Dsession_tracking=systemd \
|
||||
-Dsuspend_resume=systemd \
|
||||
-Dsystemdsystemunitdir=%{_unitdir} \
|
||||
-Dsystemdsystemgeneratordir=%{_systemdgeneratordir} \
|
||||
-Dsystem_ca_path=/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem \
|
||||
-Ddbus_conf_dir=%{dbus_sys_dir} \
|
||||
-Dtests=yes \
|
||||
|
|
@ -731,6 +752,7 @@ rm -f %{buildroot}%{_libdir}/pppd/%{ppp_version}/*.la
|
|||
rm -f %{buildroot}%{nmplugindir}/*.la
|
||||
|
||||
# Don't use the *-initrd.service files yet, wait dracut to support them
|
||||
rm -f %{buildroot}%{_systemdgeneratordir}/nm-initrd-generator.sh
|
||||
rm -f %{buildroot}%{_unitdir}/NetworkManager-config-initrd.service
|
||||
rm -f %{buildroot}%{_unitdir}/NetworkManager-initrd.service
|
||||
rm -f %{buildroot}%{_unitdir}/NetworkManager-wait-online-initrd.service
|
||||
|
|
@ -896,6 +918,9 @@ fi
|
|||
%{_datadir}/dbus-1/system-services/org.freedesktop.nm_dispatcher.service
|
||||
%{_datadir}/dbus-1/system-services/org.freedesktop.nm_priv_helper.service
|
||||
%{_datadir}/polkit-1/actions/*.policy
|
||||
%if %{with polkit_noauth_group}
|
||||
%{_datadir}/polkit-1/rules.d/org.freedesktop.NetworkManager.rules
|
||||
%endif
|
||||
%{_prefix}/lib/udev/rules.d/*.rules
|
||||
%{_prefix}/lib/firewalld/zones/nm-shared.xml
|
||||
# systemd stuff
|
||||
|
|
|
|||
|
|
@ -173,6 +173,7 @@ P_WIFI="${WIFI-1}"
|
|||
P_WWAN="${WWAN-1}"
|
||||
P_TEAM="${TEAM-1}"
|
||||
P_BLUETOOTH="${BLUETOOTH-1}"
|
||||
P_IFCFG_RH="${IFCFG_RH-0}"
|
||||
P_NMTUI="${NMTUI-1}"
|
||||
P_NM_CLOUD_SETUP="${NM_CLOUD_SETUP-1}"
|
||||
P_OVS="${OVS-1}"
|
||||
|
|
@ -202,7 +203,7 @@ if [ -z "$P_FEDORA" -a -z "$P_RHEL" ] ; then
|
|||
P_FEDORA="$x"
|
||||
P_RHEL=0
|
||||
else
|
||||
x="$(grep -q "ID=fedora" /etc/os-release && sed -n 's/VERSION_ID=//p' /etc/os-release)"
|
||||
x="$(grep -q 'ID="rhel"' /etc/os-release && sed -n 's/^VERSION_ID="*\([0-9]*\).*/\1/p' /etc/os-release)"
|
||||
if test "$x" -gt 0 ; then
|
||||
P_FEDORA=0
|
||||
P_RHEL="$x"
|
||||
|
|
@ -293,6 +294,14 @@ if [ -z "$P_MODEM_MANAGER_1" ] ; then
|
|||
fi
|
||||
fi
|
||||
|
||||
if [ -z "$TEAM" ] && [ "${P_RHEL-0}" -ge 10 ] ; then
|
||||
P_TEAM=0
|
||||
fi
|
||||
|
||||
if [ -z "$IFCFG_RH" ] && [ -n "$P_RHEL" ] && [ "$P_RHEL" -le 9 ] ; then
|
||||
P_IFCFG_RH=1
|
||||
fi
|
||||
|
||||
if bool "$P_DEBUG" ; then
|
||||
P_CFLAGS="-g -Og -fexceptions${P_CFLAGS:+ }$P_CFLAGS"
|
||||
else
|
||||
|
|
@ -378,7 +387,7 @@ meson setup\
|
|||
-Db_lto="$(bool_true "$P_LTO")" \
|
||||
-Dlibaudit=yes-disabled-by-default \
|
||||
-Dmodem_manager="$(bool_true "$P_MODEM_MANAGER_1")" \
|
||||
$(args_enable "$P_WIFI" -Dwifi=true -Dwext="$(bool_true "$P_FEDORA")") \
|
||||
$(args_enable "$P_WIFI" -Dwifi=true -Dwext=false) \
|
||||
$(args_enable "$(bool_not_true "$P_WIFI")" -Dwifi=false ) \
|
||||
-Diwd="$(bool_true "$P_IWD")" \
|
||||
-Dbluez5_dun="$(bool_true "$P_BLUETOOTH")" \
|
||||
|
|
@ -392,17 +401,17 @@ meson setup\
|
|||
-Dselinux=true \
|
||||
-Dpolkit=true \
|
||||
-Dconfig_auth_polkit_default=true \
|
||||
-Dmodify_system=true \
|
||||
-Dconcheck=true \
|
||||
-Dlibpsl="$(bool_true "$P_FEDORA")" \
|
||||
-Dsession_tracking=systemd \
|
||||
-Dsuspend_resume=systemd \
|
||||
-Dsystemdsystemunitdir=/usr/lib/systemd/system \
|
||||
-Dsystemdsystemgeneratordir=/usr/lib/systemd/system-generators \
|
||||
-Dsystem_ca_path=/etc/pki/tls/cert.pem \
|
||||
-Ddbus_conf_dir="$P_DBUS_SYS_DIR" \
|
||||
-Dtests=yes \
|
||||
-Dvalgrind=no \
|
||||
-Difcfg_rh=true \
|
||||
-Difcfg_rh="$(bool_true "$P_IFCFG_RH")" \
|
||||
-Difupdown=false \
|
||||
$(args_enable "$P_PPP" -Dppp=true -Dpppd="$D_SBINDIR/pppd" -Dpppd_plugin_dir="$D_LIBDIR/pppd/$P_PPP_VERSION") \
|
||||
$(args_enable "$(bool_not_true "$P_PPP")" -Dppp=false ) \
|
||||
|
|
|
|||
|
|
@ -169,6 +169,7 @@ meson setup build \
|
|||
-D ld_gc=false \
|
||||
-D session_tracking=no \
|
||||
-D systemdsystemunitdir=no \
|
||||
-D systemdsystemgeneratordir=no \
|
||||
-D systemd_journal=false \
|
||||
-D selinux=false \
|
||||
-D libaudit=no \
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
[Unit]
|
||||
Description=NetworkManager Configuration (initrd)
|
||||
AssertPathExists=/etc/initrd-release
|
||||
DefaultDependencies=no
|
||||
Wants=systemd-journald.socket
|
||||
After=systemd-journald.socket
|
||||
Before=systemd-udevd.service systemd-udev-trigger.service
|
||||
ConditionPathExists=/etc/initrd-release
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
|
|
@ -22,6 +22,3 @@ ExecStartPost=/bin/sh -c ' \
|
|||
fi \
|
||||
'
|
||||
RemainAfterExit=yes
|
||||
|
||||
[Install]
|
||||
WantedBy=initrd.target
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
[Unit]
|
||||
Description=NetworkManager (initrd)
|
||||
AssertPathExists=/etc/initrd-release
|
||||
DefaultDependencies=no
|
||||
Wants=systemd-udev-trigger.service network.target
|
||||
After=systemd-udev-trigger.service network-pre.target dbus.service NetworkManager-config-initrd.service
|
||||
Before=network.target
|
||||
BindsTo=dbus.service
|
||||
ConditionPathExists=/etc/initrd-release
|
||||
ConditionPathExists=/run/NetworkManager/initrd/neednet
|
||||
ConditionPathExistsGlob=|/usr/lib/NetworkManager/system-connections/*
|
||||
ConditionPathExistsGlob=|/run/NetworkManager/system-connections/*
|
||||
|
|
@ -22,11 +22,3 @@ Environment=NM_CONFIG_ENABLE_TAG=initrd
|
|||
Restart=on-failure
|
||||
ProtectSystem=true
|
||||
ProtectHome=read-only
|
||||
|
||||
[Install]
|
||||
WantedBy=initrd.target
|
||||
# We want to enable NetworkManager-wait-online-initrd.service whenever this
|
||||
# service is enabled. NetworkManager-wait-online-initrd.service has
|
||||
# WantedBy=network-online.target, so enabling it only has an effect if
|
||||
# network-online.target itself is enabled or pulled in by some other unit.
|
||||
Also=NetworkManager-config-initrd.service NetworkManager-wait-online-initrd.service
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
[Unit]
|
||||
Description=NetworkManager Wait Online (initrd)
|
||||
AssertPathExists=/etc/initrd-release
|
||||
DefaultDependencies=no
|
||||
Requires=NetworkManager-initrd.service
|
||||
After=NetworkManager-initrd.service
|
||||
Before=network-online.target
|
||||
ConditionPathExists=/etc/initrd-release
|
||||
ConditionPathExists=/run/NetworkManager/initrd/neednet
|
||||
|
||||
[Service]
|
||||
|
|
@ -21,6 +21,3 @@ Type=oneshot
|
|||
ExecStart=@bindir@/nm-online -s -q
|
||||
RemainAfterExit=yes
|
||||
Environment=NM_ONLINE_TIMEOUT=3600
|
||||
|
||||
[Install]
|
||||
WantedBy=initrd.target network-online.target
|
||||
|
|
|
|||
|
|
@ -55,21 +55,22 @@ if install_udevdir
|
|||
endif
|
||||
|
||||
if enable_polkit
|
||||
policy = 'org.freedesktop.NetworkManager.policy'
|
||||
|
||||
policy_in = configure_file(
|
||||
input: policy + '.in.in',
|
||||
output: '@BASENAME@',
|
||||
configuration: data_conf,
|
||||
)
|
||||
|
||||
i18n.merge_file(
|
||||
input: policy_in,
|
||||
input: 'org.freedesktop.NetworkManager.policy.in',
|
||||
output: '@BASENAME@',
|
||||
po_dir: po_dir,
|
||||
install: true,
|
||||
install_dir: polkit_gobject_policydir,
|
||||
install_dir: polkit_policydir,
|
||||
)
|
||||
|
||||
if polkit_noauth_group != ''
|
||||
configure_file(
|
||||
input: 'org.freedesktop.NetworkManager.rules.in',
|
||||
output: '@BASENAME@',
|
||||
install_dir: polkit_rulesdir,
|
||||
configuration: {'NM_POLKIT_NOAUTH_GROUP': polkit_noauth_group},
|
||||
)
|
||||
endif
|
||||
endif
|
||||
|
||||
if enable_firewalld_zone
|
||||
|
|
|
|||
|
|
@ -117,8 +117,8 @@
|
|||
<message>System policy prevents modification of network settings for all users</message>
|
||||
<defaults>
|
||||
<allow_any>auth_admin_keep</allow_any>
|
||||
<allow_inactive>@NM_MODIFY_SYSTEM_POLICY@</allow_inactive>
|
||||
<allow_active>@NM_MODIFY_SYSTEM_POLICY@</allow_active>
|
||||
<allow_inactive>auth_admin_keep</allow_inactive>
|
||||
<allow_active>auth_admin_keep</allow_active>
|
||||
</defaults>
|
||||
</action>
|
||||
|
||||
17
data/org.freedesktop.NetworkManager.rules.in
Normal file
17
data/org.freedesktop.NetworkManager.rules.in
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
// NetworkManager authorizations/policy for the @NM_POLKIT_NOAUTH_GROUP@ group.
|
||||
//
|
||||
// DO NOT EDIT THIS FILE, it will be overwritten on update.
|
||||
//
|
||||
// Allow users in the @NM_POLKIT_NOAUTH_GROUP@ group to create system-wide connections without being
|
||||
// prompted for a password if they are in a local console.
|
||||
// This is optional and is only recommended to maintain backwards compatibility
|
||||
// in systems where it was already working in this way. It is discouraged
|
||||
// otherwise.
|
||||
|
||||
polkit.addRule(function(action, subject) {
|
||||
if (action.id == "org.freedesktop.NetworkManager.settings.modify.system" &&
|
||||
subject.isInGroup("@NM_POLKIT_NOAUTH_GROUP@") &&
|
||||
subject.local) {
|
||||
return polkit.Result.YES;
|
||||
}
|
||||
});
|
||||
|
|
@ -83,6 +83,11 @@
|
|||
note that your distribution or other packages may drop configuration snippets for NetworkManager, such
|
||||
that they are part of the factory default.
|
||||
</para>
|
||||
<para>
|
||||
The options that are indicated as boolean can be set to one of these values:
|
||||
<literal>yes</literal>, <literal>true</literal>, <literal>on</literal>, <literal>1</literal>,
|
||||
<literal>no</literal>, <literal>false</literal>, <literal>off</literal>, <literal>0</literal>.
|
||||
</para>
|
||||
|
||||
</refsect1>
|
||||
|
||||
|
|
@ -949,6 +954,10 @@ ipv6.ip6-privacy=0
|
|||
<term><varname>ipv4.forwarding</varname></term>
|
||||
<listitem><para>Whether to configure IPv4 sysctl interface-specific forwarding. When enabled, the interface will act as a router to forward the IPv4 packet from one interface to another. If left unspecified, "auto" is used, so NetworkManager sets the IPv4 forwarding if any shared connection is active, or it will use the kernel default value otherwise. The "ipv4.forwarding" property is ignored when "ipv4.method" is set to "shared", because forwarding is always enabled in this case. The accepted values are: 0: disabled, 1: enabled, 2: auto, 3: ignored (leave the forwarding unchanged).</para></listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><varname>ipv4.clat</varname></term>
|
||||
<listitem><para>If left unspecified, defaults to "no".</para></listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><varname>ipv4.routed-dns</varname></term>
|
||||
</varlistentry>
|
||||
|
|
@ -967,7 +976,7 @@ ipv6.ip6-privacy=0
|
|||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><varname>ipv4.dhcp-ipv6-only-preferred</varname></term>
|
||||
<listitem><para>If left unspecified, the "IPv6-only preferred" DHCPv4 option is disabled.</para></listitem>
|
||||
<listitem><para>If left unspecified, it defaults to "auto".</para></listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><varname>ipv4.dhcp-hostname-flags</varname></term>
|
||||
|
|
@ -1249,12 +1258,13 @@ managed=1
|
|||
<term><varname>managed</varname></term>
|
||||
<listitem>
|
||||
<para>
|
||||
Whether the device is managed or not. A device can be
|
||||
marked as managed via udev rules (ENV{NM_UNMANAGED}),
|
||||
or via setting plugins (keyfile.unmanaged-devices).
|
||||
This is yet another way. Note that this configuration
|
||||
can be overruled at runtime via D-Bus. Also, it has
|
||||
higher priority then udev rules.
|
||||
A boolean value specifying whether the device is
|
||||
managed or not. A device can be marked as managed via
|
||||
udev rules (ENV{NM_UNMANAGED}), or via setting plugins
|
||||
(keyfile.unmanaged-devices). This is yet another
|
||||
way. Note that this configuration can be overruled at
|
||||
runtime via D-Bus. Also, it has higher priority than
|
||||
udev rules.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
|
@ -1323,9 +1333,27 @@ managed=1
|
|||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry id="keep-configuration">
|
||||
<term><varname>keep-configuration</varname></term>
|
||||
<varlistentry id="check-connectivity">
|
||||
<term><varname>check-connectivity</varname></term>
|
||||
<listitem>
|
||||
<para>
|
||||
A boolean value specifying whether NetworkManager will perform a connectivity check
|
||||
for this device. Defaults to <literal>yes</literal>.
|
||||
</para>
|
||||
<para>
|
||||
This setting does nothing if the connectivity check has been
|
||||
disabled globally using the
|
||||
<literal>connectivity.enabled</literal> setting.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry id="keep-configuration">
|
||||
<term><varname>keep-configuration</varname></term>
|
||||
<listitem>
|
||||
<para>
|
||||
A boolean value indicating whether the existing device
|
||||
configuration is kept at startup.
|
||||
</para>
|
||||
<para>
|
||||
On startup, NetworkManager tries to not interfere with
|
||||
interfaces that are already configured. It does so by
|
||||
|
|
@ -1422,16 +1450,16 @@ managed=1
|
|||
<term><varname>wifi.iwd.autoconnect</varname></term>
|
||||
<listitem>
|
||||
<para>
|
||||
If <literal>wifi.backend</literal> is <literal>iwd</literal>, setting this to
|
||||
<literal>false</literal> forces IWD's autoconnect mechanism to be disabled for
|
||||
this device and connections will only be initiated by NetworkManager whether
|
||||
commanded by a client or automatically. Leaving it <literal>true</literal> (default)
|
||||
stops NetworkManager from automatically initiating connections and allows
|
||||
IWD to use its network ranking and scanning logic to decide the best networks
|
||||
to autoconnect to next. Connections' <literal>autoconnect-priority</literal>,
|
||||
<literal>autoconnect-retries</literal> settings will be ignored. Other settings
|
||||
like <literal>permissions</literal> or <literal>multi-connect</literal> may interfere
|
||||
with IWD connection attempts.
|
||||
A boolean value. If <literal>wifi.backend</literal> is <literal>iwd</literal>,
|
||||
setting this to <literal>false</literal> forces IWD's autoconnect mechanism to be
|
||||
disabled for this device and connections will only be initiated by NetworkManager
|
||||
whether commanded by a client or automatically. Leaving it <literal>true</literal>
|
||||
(default) stops NetworkManager from automatically initiating connections and allows
|
||||
IWD to use its network ranking and scanning logic to decide the best networks to
|
||||
autoconnect to next. Connections' <literal>autoconnect-priority</literal>,
|
||||
<literal>autoconnect-retries</literal> settings will be ignored. Other settings like
|
||||
<literal>permissions</literal> or <literal>multi-connect</literal> may interfere with
|
||||
IWD connection attempts.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
|
@ -1490,7 +1518,7 @@ managed=1
|
|||
<variablelist>
|
||||
<varlistentry>
|
||||
<term><varname>enabled</varname></term>
|
||||
<listitem><para>Whether connectivity check is enabled.
|
||||
<listitem><para>A boolean indicating whether connectivity check is enabled.
|
||||
Note that to enable connectivity check, a valid uri must
|
||||
also be configured. The value defaults to true, but since
|
||||
the uri is unset by default, connectivity check may be disabled.
|
||||
|
|
|
|||
|
|
@ -1718,6 +1718,7 @@
|
|||
<group choice='req'>
|
||||
<arg choice='plain'>a</arg>
|
||||
<arg choice='plain'>bg</arg>
|
||||
<arg choice='plain'>6GHz</arg>
|
||||
</group>
|
||||
</arg>
|
||||
<arg><option>channel</option> <replaceable>channel</replaceable></arg>
|
||||
|
|
|
|||
50
meson.build
50
meson.build
|
|
@ -5,7 +5,7 @@ project(
|
|||
# NOTE: When incrementing version also add corresponding
|
||||
# NM_VERSION_x_y_z macros in
|
||||
# "src/libnm-core-public/nm-version-macros.h.in"
|
||||
version: '1.56.0',
|
||||
version: '1.57.2-dev',
|
||||
license: 'GPL2+',
|
||||
default_options: [
|
||||
'buildtype=debugoptimized',
|
||||
|
|
@ -358,7 +358,11 @@ enable_iwd = get_option('iwd')
|
|||
assert((not enable_iwd) or enable_wifi, 'Enabling iwd support requires Wi-Fi support as well')
|
||||
config_h.set10('WITH_IWD', enable_iwd)
|
||||
|
||||
enable_wext = get_option('wext')
|
||||
wext = get_option('wext')
|
||||
if wext == 'true'
|
||||
error('Wireless Extensions support is deprecated and will be removed in the future. Use -Dwext=force to keep using it')
|
||||
endif
|
||||
enable_wext = (wext == 'force')
|
||||
config_h.set10('HAVE_WEXT', enable_wext)
|
||||
|
||||
# Checks for libdl - on certain platforms its part of libc
|
||||
|
|
@ -408,6 +412,14 @@ if install_systemdunitdir and systemd_systemdsystemunitdir == ''
|
|||
systemd_systemdsystemunitdir = systemd_dep.get_variable(pkgconfig: 'systemdsystemunitdir', pkgconfig_define: ['rootprefix', nm_prefix])
|
||||
endif
|
||||
|
||||
systemd_systemdsystemgeneratordir = get_option('systemdsystemgeneratordir')
|
||||
install_systemdgeneratordir = (systemd_systemdsystemgeneratordir != 'no')
|
||||
|
||||
if install_systemdgeneratordir and systemd_systemdsystemgeneratordir == ''
|
||||
assert(systemd_dep.found(), 'systemd required but not found, please provide a valid systemd user generator dir or disable it')
|
||||
systemd_systemdsystemgeneratordir = systemd_dep.get_variable(pkgconfig: 'systemdsystemgeneratordir', pkgconfig_define: ['rootprefix', nm_prefix])
|
||||
endif
|
||||
|
||||
enable_systemd_journal = get_option('systemd_journal')
|
||||
if enable_systemd_journal
|
||||
assert(libsystemd_dep.found(), 'Missing systemd-journald support')
|
||||
|
|
@ -502,6 +514,16 @@ if enable_selinux
|
|||
endif
|
||||
config_h.set10('HAVE_SELINUX', enable_selinux)
|
||||
|
||||
# CLAT support
|
||||
enable_clat = get_option('clat')
|
||||
if enable_clat
|
||||
libbpf = dependency('libbpf', version: '>= 0.1.0', required: false)
|
||||
assert(libbpf.found(), 'You must have libbpf installed to build. Use -Dclat=false to disable use of it')
|
||||
libndp_dep = dependency('libndp', version: '>= 1.9', required: false)
|
||||
assert(libndp_dep.found(), 'You must have libndp >= 1.9 installed to build with CLAT support. Use -Dclat=false to disable it')
|
||||
endif
|
||||
config_h.set10('HAVE_CLAT', enable_clat)
|
||||
|
||||
# libaudit support
|
||||
libaudit = get_option('libaudit')
|
||||
enable_libaudit = libaudit.contains('yes')
|
||||
|
|
@ -526,7 +548,8 @@ config_h.set10('WITH_TEAMDCTL', enable_teamdctl)
|
|||
enable_polkit = get_option('polkit')
|
||||
if enable_polkit
|
||||
# FIXME: policydir should be relative to `datadir`, not `prefix`. Fixed in https://gitlab.freedesktop.org/polkit/polkit/merge_requests/2
|
||||
polkit_gobject_policydir = dependency('polkit-gobject-1').get_variable(pkgconfig: 'policydir', pkgconfig_define: ['prefix', nm_prefix])
|
||||
polkit_policydir = dependency('polkit-gobject-1').get_variable(pkgconfig: 'policydir', pkgconfig_define: ['prefix', nm_prefix])
|
||||
polkit_rulesdir = join_paths(fs.parent(polkit_policydir), 'rules.d')
|
||||
endif
|
||||
|
||||
config_auth_polkit_default = get_option('config_auth_polkit_default')
|
||||
|
|
@ -536,6 +559,12 @@ endif
|
|||
config_h.set_quoted('NM_CONFIG_DEFAULT_MAIN_AUTH_POLKIT', config_auth_polkit_default)
|
||||
|
||||
enable_modify_system = get_option('modify_system')
|
||||
if enable_modify_system
|
||||
# FIXME: remove this after everyone has stopped using modify_system
|
||||
error('modify_system=true is no longer allowed due to security reasons')
|
||||
endif
|
||||
|
||||
polkit_noauth_group = get_option('polkit_noauth_group')
|
||||
|
||||
polkit_agent_helper_1_path = get_option('polkit_agent_helper_1')
|
||||
foreach p : [ '/usr/libexec/polkit-agent-helper-1',
|
||||
|
|
@ -968,7 +997,6 @@ data_conf.set('NM_DHCP_CLIENTS_ENABLED', ', '.join(config_dhcp_c
|
|||
data_conf.set('NM_MAJOR_VERSION', nm_major_version)
|
||||
data_conf.set('NM_MICRO_VERSION', nm_micro_version)
|
||||
data_conf.set('NM_MINOR_VERSION', nm_minor_version)
|
||||
data_conf.set('NM_MODIFY_SYSTEM_POLICY', (enable_modify_system ? 'yes' : 'auth_admin_keep'))
|
||||
data_conf.set('NM_VERSION', nm_version)
|
||||
data_conf.set('VERSION', nm_version)
|
||||
data_conf.set('bindir', nm_bindir)
|
||||
|
|
@ -1084,6 +1112,7 @@ output = '\nSystem paths:\n'
|
|||
output += ' prefix: ' + nm_prefix + '\n'
|
||||
output += ' exec_prefix: ' + nm_prefix + '\n'
|
||||
output += ' systemdunitdir: ' + systemd_systemdsystemunitdir + '\n'
|
||||
output += ' systemdgeneratordir: ' + systemd_systemdsystemgeneratordir + '\n'
|
||||
output += ' udev_dir: ' + udev_udevdir + '\n'
|
||||
output += ' nmbinary: ' + nm_pkgsbindir + '\n'
|
||||
output += ' nmconfdir: ' + nm_pkgconfdir + '\n'
|
||||
|
|
@ -1098,17 +1127,7 @@ output += ' dbus_conf_dir: ' + dbus_conf_dir + '\n'
|
|||
output += '\nPlatform:\n'
|
||||
output += ' session tracking: ' + ','.join(session_trackers) + '\n'
|
||||
output += ' suspend/resume: ' + suspend_resume + '\n'
|
||||
output += ' policykit: ' + enable_polkit.to_string() + ' (default: ' + config_auth_polkit_default + ')'
|
||||
if enable_polkit
|
||||
output += ' ('
|
||||
if enable_modify_system
|
||||
output += 'permissive'
|
||||
else
|
||||
output += 'restrictive'
|
||||
endif
|
||||
output += ' modify.system)'
|
||||
endif
|
||||
output += '\n'
|
||||
output += ' policykit: ' + enable_polkit.to_string() + ' (default: ' + config_auth_polkit_default + ', noauth_group: "' + polkit_noauth_group + '")\n'
|
||||
output += ' polkit-agent-helper-1: ' + polkit_agent_helper_1_path + '\n'
|
||||
output += ' selinux: ' + enable_selinux.to_string() + '\n'
|
||||
output += ' systemd-journald: ' + enable_systemd_journal.to_string() + ' (default: logging.backend=' + config_logging_backend_default + ')\n'
|
||||
|
|
@ -1136,6 +1155,7 @@ output += ' ofono: ' + enable_ofono.to_string() + '\n'
|
|||
output += ' concheck: ' + enable_concheck.to_string() + '\n'
|
||||
output += ' libteamdctl: ' + enable_teamdctl.to_string() + '\n'
|
||||
output += ' ovs: ' + enable_ovs.to_string() + '\n'
|
||||
output += ' clat: ' + enable_clat.to_string() + '\n'
|
||||
output += ' nmcli: ' + enable_nmcli.to_string() + '\n'
|
||||
output += ' nmtui: ' + enable_nmtui.to_string() + '\n'
|
||||
output += ' nm-cloud-setup: ' + enable_nm_cloud_setup.to_string() + '\n'
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
# system paths
|
||||
option('systemdsystemunitdir', type: 'string', value: '', description: 'Directory for systemd service files')
|
||||
option('systemdsystemgeneratordir', type: 'string', value: '', description: 'Directory for systemd generator files')
|
||||
option('system_ca_path', type: 'string', value: '/etc/ssl/certs', description: 'path to system CA certificates')
|
||||
option('udev_dir', type: 'string', value: '', description: 'Absolute path of the udev base directory. Set to \'no\' not to install the udev rule')
|
||||
option('dbus_conf_dir', type: 'string', value: '', description: 'where D-Bus system.d directory is')
|
||||
|
|
@ -18,7 +19,8 @@ option('session_tracking', type: 'combo', choices: ['systemd', 'elogind', 'no'],
|
|||
option('suspend_resume', type: 'combo', choices: ['systemd', 'elogind', 'consolekit', 'auto'], value: 'auto', description: 'Build NetworkManager with specific suspend/resume support')
|
||||
option('polkit', type: 'boolean', value: true, description: 'User auth-polkit configuration option.')
|
||||
option('config_auth_polkit_default', type: 'combo', choices: ['default', 'true', 'false', 'root-only'], value: 'default', description: 'Default value for configuration main.auth-polkit.')
|
||||
option('modify_system', type: 'boolean', value: false, description: 'Allow users to modify system connections')
|
||||
option('modify_system', type: 'boolean', value: false, description: 'Allow users to modify system connections (option no longer supported, don\'t use)')
|
||||
option('polkit_noauth_group', type: 'string', value: '', description: 'Allow users of the selected group, typically sudo or wheel, to modify system connections without introducing a password (discouraged)')
|
||||
option('polkit_agent_helper_1', type: 'string', value: '', description: 'Path name to the polkit-agent-helper-1 binary from polkit')
|
||||
option('selinux', type: 'boolean', value: true, description: 'Build with SELinux')
|
||||
option('systemd_journal', type: 'boolean', value: true, description: 'Use systemd journal for logging')
|
||||
|
|
@ -28,7 +30,7 @@ option('hostname_persist', type: 'combo', choices: ['default', 'suse', 'gentoo',
|
|||
option('libaudit', type: 'combo', choices: ['yes', 'yes-disabled-by-default', 'no'], value: 'yes', description: 'Build with audit daemon support. yes-disabled-by-default enables support, but disables it unless explicitly configured via NetworkManager.conf')
|
||||
|
||||
# features
|
||||
option('wext', type: 'boolean', value: true, description: 'Enable or disable Linux Wireless Extensions')
|
||||
option('wext', type: 'combo', choices: ['true', 'false', 'force' ], value: 'false', description: 'Enable or disable Linux Wireless Extensions (deprecated). wext support will be removed in a future release, don\'t rely on this.')
|
||||
option('wifi', type: 'boolean', value: true, description: 'enable Wi-Fi support')
|
||||
option('iwd', type: 'boolean', value: false, description: 'enable iwd support (experimental)')
|
||||
option('ppp', type: 'boolean', value: true, description: 'enable PPP/PPPoE support')
|
||||
|
|
@ -46,6 +48,9 @@ option('nm_cloud_setup', type: 'boolean', value: true, description: 'Build nm-cl
|
|||
option('bluez5_dun', type: 'boolean', value: false, description: 'enable Bluez5 DUN support')
|
||||
option('ebpf', type: 'combo', choices: ['auto', 'true', 'false'], description: 'Enable eBPF support (deprecated)')
|
||||
option('nbft', type: 'boolean', value: true, description: 'Enable NBFT support in the initrd generator')
|
||||
option('clat', type: 'boolean', value: true, description: 'Build with CLAT support')
|
||||
option('bpf-compiler', type : 'combo', choices : ['auto', 'clang', 'gcc'],
|
||||
description : 'compiler used to build BPF programs')
|
||||
|
||||
# configuration plugins
|
||||
option('config_plugins_default', type: 'string', value: '', description: 'Default configuration option for main.plugins setting, used as fallback if the configuration option is unset')
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
# List of source files containing translatable strings.
|
||||
# Please keep this file sorted alphabetically.
|
||||
data/org.freedesktop.NetworkManager.policy.in.in
|
||||
data/org.freedesktop.NetworkManager.policy.in
|
||||
src/core/NetworkManagerUtils.c
|
||||
src/core/devices/adsl/nm-device-adsl.c
|
||||
src/core/devices/bluetooth/nm-bluez-manager.c
|
||||
|
|
|
|||
9522
po/pt_BR.po
9522
po/pt_BR.po
File diff suppressed because it is too large
Load diff
1203
src/core/bpf/clat.bpf.c
Normal file
1203
src/core/bpf/clat.bpf.c
Normal file
File diff suppressed because it is too large
Load diff
30
src/core/bpf/clat.h
Normal file
30
src/core/bpf/clat.h
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef __NAT64_H__
|
||||
#define __NAT64_H__
|
||||
|
||||
#include <linux/in6.h>
|
||||
|
||||
struct clat_config {
|
||||
struct in6_addr local_v6;
|
||||
struct in6_addr pref64;
|
||||
struct in_addr local_v4;
|
||||
unsigned pref64_len;
|
||||
};
|
||||
|
||||
struct clat_stats {
|
||||
/* egress: v4 to v6 */
|
||||
__u64 egress_tcp;
|
||||
__u64 egress_udp;
|
||||
__u64 egress_icmp;
|
||||
__u64 egress_other;
|
||||
__u64 egress_dropped;
|
||||
/* ingress: v6 to v4 */
|
||||
__u64 ingress_tcp;
|
||||
__u64 ingress_udp;
|
||||
__u64 ingress_icmp;
|
||||
__u64 ingress_other;
|
||||
__u64 ingress_fragment;
|
||||
__u64 ingress_dropped;
|
||||
};
|
||||
|
||||
#endif
|
||||
239
src/core/bpf/meson.build
Normal file
239
src/core/bpf/meson.build
Normal file
|
|
@ -0,0 +1,239 @@
|
|||
# SPDX-License-Identifier: LGPL-2.1+
|
||||
|
||||
# Ripped from systemd: https://github.com/systemd/systemd/pull/20429
|
||||
|
||||
if not enable_clat
|
||||
subdir_done()
|
||||
endif
|
||||
|
||||
bpf_compiler = get_option('bpf-compiler')
|
||||
clang_found = false
|
||||
clang_supports_bpf = false
|
||||
bpf_gcc_found = false
|
||||
bpftool_strip = false
|
||||
|
||||
if bpf_compiler == 'clang' or bpf_compiler == 'auto'
|
||||
# Support 'versioned' clang/llvm-strip binaries, as seen on Debian/Ubuntu
|
||||
# (like clang-10/llvm-strip-10)
|
||||
if meson.is_cross_build() or cc.get_id() != 'clang' or cc.cmd_array()[0].contains('afl-clang') or cc.cmd_array()[0].contains('hfuzz-clang')
|
||||
r = find_program('clang',
|
||||
version : '>= 10.0.0')
|
||||
clang_found = r.found()
|
||||
if clang_found
|
||||
if meson.version().version_compare('>= 0.55')
|
||||
clang = r.full_path()
|
||||
else
|
||||
clang = r.path()
|
||||
endif
|
||||
endif
|
||||
else
|
||||
clang_found = true
|
||||
clang = cc.cmd_array()
|
||||
endif
|
||||
|
||||
if clang_found
|
||||
# Check if 'clang -target bpf' is supported.
|
||||
clang_supports_bpf = run_command(clang, '-target', 'bpf', '--print-supported-cpus', check : false).returncode() == 0
|
||||
endif
|
||||
elif bpf_compiler == 'gcc' or bpf_compiler == 'auto'
|
||||
bpf_gcc = find_program('bpf-gcc',
|
||||
'bpf-none-gcc',
|
||||
'bpf-unknown-none-gcc',
|
||||
version : '>= 13.1.0')
|
||||
bpf_gcc_found = bpf_gcc.found()
|
||||
endif
|
||||
|
||||
if bpf_compiler == 'auto'
|
||||
if clang_supports_bpf and bpf_gcc_found
|
||||
# Both supported, prefer the one matching our compiler:
|
||||
if cc.get_id() == 'gcc'
|
||||
bpf_compiler = 'gcc'
|
||||
else
|
||||
# Default to clang if we don't know this compiler
|
||||
bpf_compiler = 'clang'
|
||||
endif
|
||||
elif clang_supports_bpf
|
||||
bpf_compiler = 'clang'
|
||||
elif bpf_gcc_found
|
||||
bpf_compiler = 'clang'
|
||||
endif
|
||||
endif
|
||||
|
||||
if clang_supports_bpf or bpf_gcc_found
|
||||
# Debian installs this in /usr/sbin/ which is not in $PATH.
|
||||
# We check for 'bpftool' first, honouring $PATH, and in /usr/sbin/ for Debian.
|
||||
# We use 'bpftool gen object' subcommand for bpftool strip, it was added by d80b2fcbe0a023619e0fc73112f2a02c2662f6ab (v5.13).
|
||||
bpftool = find_program('bpftool',
|
||||
'/usr/sbin/bpftool',
|
||||
required : bpf_compiler == 'gcc',
|
||||
version : bpf_compiler == 'gcc' ? '>= 7.0.0' : '>= 5.13.0')
|
||||
|
||||
if bpftool.found()
|
||||
bpftool_strip = true
|
||||
elif bpf_compiler == 'clang'
|
||||
# We require the 'bpftool gen skeleton' subcommand, it was added by 985ead416df39d6fe8e89580cc1db6aa273e0175 (v5.6).
|
||||
bpftool = find_program('bpftool',
|
||||
'/usr/sbin/bpftool',
|
||||
required : true,
|
||||
version : '>= 5.6.0')
|
||||
endif
|
||||
|
||||
# We use `llvm-strip` as a fallback if `bpftool gen object` strip support is not available.
|
||||
if not bpftool_strip and bpftool.found() and clang_supports_bpf
|
||||
if not meson.is_cross_build()
|
||||
llvm_strip_bin = run_command(clang, '--print-prog-name', 'llvm-strip',
|
||||
check : true).stdout().strip()
|
||||
else
|
||||
llvm_strip_bin = 'llvm-strip'
|
||||
endif
|
||||
llvm_strip = find_program(llvm_strip_bin,
|
||||
required : true,
|
||||
version : '>= 10.0.0')
|
||||
endif
|
||||
else
|
||||
error('clat support was enabled but couldn\'t find a suitable BPF compiler!')
|
||||
endif
|
||||
|
||||
bpf_clang_flags = [
|
||||
'-std=gnu17',
|
||||
'-Wunused',
|
||||
'-Wimplicit-fallthrough',
|
||||
'-Wno-compare-distinct-pointer-types',
|
||||
'-fno-stack-protector',
|
||||
'-O2',
|
||||
'-target',
|
||||
'bpf',
|
||||
'-g',
|
||||
'-c',
|
||||
]
|
||||
|
||||
bpf_gcc_flags = [
|
||||
'-std=gnu17',
|
||||
'-Wunused',
|
||||
'-Wimplicit-fallthrough',
|
||||
'-fno-stack-protector',
|
||||
'-fno-ssa-phiopt',
|
||||
'-O2',
|
||||
'-mcpu=v3',
|
||||
'-mco-re',
|
||||
'-gbtf',
|
||||
'-c',
|
||||
]
|
||||
|
||||
clang_arch_flag = '-D__@0@__'.format(host_machine.cpu_family())
|
||||
|
||||
libbpf_include_dir = dependency('libbpf').get_variable(pkgconfig : 'includedir')
|
||||
|
||||
# Generate defines that are appropriate to tell the compiler what architecture
|
||||
# we're compiling for. By default we just map meson's cpu_family to __<cpu_family>__.
|
||||
# This dictionary contains the exceptions where this doesn't work.
|
||||
#
|
||||
# C.f. https://mesonbuild.com/Reference-tables.html#cpu-families
|
||||
# and src/basic/missing_syscall_def.h.
|
||||
cpu_arch_defines = {
|
||||
'ppc' : ['-D__powerpc__', '-D__TARGET_ARCH_powerpc'],
|
||||
'ppc64' : ['-D__powerpc64__', '-D__TARGET_ARCH_powerpc', '-D_CALL_ELF=2'],
|
||||
'riscv32' : ['-D__riscv', '-D__riscv_xlen=32', '-D__TARGET_ARCH_riscv'],
|
||||
'riscv64' : ['-D__riscv', '-D__riscv_xlen=64', '-D__TARGET_ARCH_riscv'],
|
||||
'x86' : ['-D__i386__', '-D__TARGET_ARCH_x86'],
|
||||
's390x' : ['-D__s390__', '-D__s390x__', '-D__TARGET_ARCH_s390'],
|
||||
|
||||
# For arm, assume hardware fp is available.
|
||||
'arm' : ['-D__arm__', '-D__ARM_PCS_VFP', '-D__TARGET_ARCH_arm'],
|
||||
'loongarch64' : ['-D__loongarch__', '-D__loongarch_grlen=64', '-D__TARGET_ARCH_loongarch']
|
||||
}
|
||||
|
||||
bpf_arch_flags = cpu_arch_defines.get(host_machine.cpu_family(),
|
||||
['-D__@0@__'.format(host_machine.cpu_family())])
|
||||
if bpf_compiler == 'gcc'
|
||||
bpf_arch_flags += ['-m' + host_machine.endian() + '-endian']
|
||||
endif
|
||||
|
||||
bpf_o_unstripped_cmd = []
|
||||
if bpf_compiler == 'clang'
|
||||
bpf_o_unstripped_cmd += [
|
||||
clang,
|
||||
bpf_clang_flags,
|
||||
bpf_arch_flags,
|
||||
]
|
||||
elif bpf_compiler == 'gcc'
|
||||
bpf_o_unstripped_cmd += [
|
||||
bpf_gcc,
|
||||
bpf_gcc_flags,
|
||||
bpf_arch_flags,
|
||||
]
|
||||
endif
|
||||
|
||||
bpf_o_unstripped_cmd += ['-I.']
|
||||
|
||||
if cc.get_id() == 'gcc' or meson.is_cross_build()
|
||||
if cc.get_id() != 'gcc'
|
||||
warning('Cross compiler is not gcc. Guessing the target triplet for bpf likely fails.')
|
||||
endif
|
||||
target_triplet_cmd = run_command(cc.cmd_array(), '-print-multiarch', check: false)
|
||||
else
|
||||
# clang does not support -print-multiarch (D133170) and its -dump-machine
|
||||
# does not match multiarch. Query gcc instead.
|
||||
target_triplet_cmd = run_command('gcc', '-print-multiarch', check: false)
|
||||
endif
|
||||
|
||||
if target_triplet_cmd.returncode() == 0
|
||||
target_triplet = target_triplet_cmd.stdout().strip()
|
||||
bpf_o_unstripped_cmd += [
|
||||
'-isystem',
|
||||
'/usr/include/@0@'.format(target_triplet)
|
||||
]
|
||||
endif
|
||||
|
||||
bpf_o_unstripped_cmd += [
|
||||
'-idirafter',
|
||||
libbpf_include_dir,
|
||||
'@INPUT@',
|
||||
'-o',
|
||||
'@OUTPUT@'
|
||||
]
|
||||
|
||||
if bpftool_strip
|
||||
bpf_o_cmd = [
|
||||
bpftool,
|
||||
'gen',
|
||||
'object',
|
||||
'@OUTPUT@',
|
||||
'@INPUT@'
|
||||
]
|
||||
elif bpf_compiler == 'clang'
|
||||
bpf_o_cmd = [
|
||||
llvm_strip,
|
||||
'-g',
|
||||
'@INPUT@',
|
||||
'-o',
|
||||
'@OUTPUT@'
|
||||
]
|
||||
endif
|
||||
|
||||
skel_h_cmd = [
|
||||
bpftool,
|
||||
'g',
|
||||
's',
|
||||
'@INPUT@'
|
||||
]
|
||||
|
||||
clat_bpf_o_unstripped = custom_target(
|
||||
'clat.bpf.unstripped.o',
|
||||
input : 'clat.bpf.c',
|
||||
output : 'clat.bpf.unstripped.o',
|
||||
command : bpf_o_unstripped_cmd)
|
||||
|
||||
clat_bpf_o = custom_target(
|
||||
'clat.bpf.o',
|
||||
input : clat_bpf_o_unstripped,
|
||||
output : 'clat.bpf.o',
|
||||
command : bpf_o_cmd)
|
||||
|
||||
clat_skel_h = custom_target(
|
||||
'clat.skel.h',
|
||||
input : clat_bpf_o,
|
||||
output : 'clat.skel.h',
|
||||
command : skel_h_cmd,
|
||||
capture : true)
|
||||
|
||||
|
|
@ -805,7 +805,7 @@ typedef struct _NMDevicePrivate {
|
|||
|
||||
GVariant *ports_variant; /* Array of port devices D-Bus path */
|
||||
char *prop_ip_iface; /* IP interface D-Bus property */
|
||||
GList *ping_operations;
|
||||
CList ping_ops_lst_head;
|
||||
GSource *ping_timeout;
|
||||
} NMDevicePrivate;
|
||||
|
||||
|
|
@ -850,7 +850,6 @@ static const char *_activation_func_to_string(ActivationHandleFunc func);
|
|||
static void
|
||||
_set_state_full(NMDevice *self, NMDeviceState state, NMDeviceStateReason reason, gboolean quitting);
|
||||
static void queued_state_clear(NMDevice *device);
|
||||
static void ip_check_ping_watch_cb(GPid pid, int status, gpointer user_data);
|
||||
static void nm_device_start_ip_check(NMDevice *self);
|
||||
static void realize_start_setup(NMDevice *self,
|
||||
const NMPlatformLink *plink,
|
||||
|
|
@ -907,10 +906,11 @@ static void concheck_update_state(NMDevice *self,
|
|||
static void sriov_op_cb(GError *error, gpointer user_data);
|
||||
|
||||
static void device_ifindex_changed_cb(NMManager *manager, NMDevice *device_changed, NMDevice *self);
|
||||
static gboolean device_link_changed(gpointer user_data);
|
||||
static gboolean _get_maybe_ipv6_disabled(NMDevice *self);
|
||||
static void deactivate_ready(NMDevice *self, NMDeviceStateReason reason);
|
||||
static void carrier_disconnected_action_cancel(NMDevice *self);
|
||||
static gboolean device_link_changed(gpointer user_data);
|
||||
static gboolean _get_maybe_ipv6_disabled(NMDevice *self);
|
||||
static void deactivate_ready(NMDevice *self, NMDeviceStateReason reason);
|
||||
static void carrier_disconnected_action_cancel(NMDevice *self);
|
||||
static const char *nm_device_get_effective_ip_config_method(NMDevice *self, int addr_family);
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
|
|
@ -1524,6 +1524,50 @@ _prop_get_connection_dnssec(NMDevice *self, NMConnection *connection)
|
|||
NM_SETTING_CONNECTION_DNSSEC_DEFAULT);
|
||||
}
|
||||
|
||||
static NMSettingIp4ConfigClat
|
||||
_prop_get_ipv4_clat(NMDevice *self, gboolean do_log)
|
||||
{
|
||||
NMSettingIP4Config *s_ip4 = NULL;
|
||||
NMSettingIp4ConfigClat clat;
|
||||
const char *method;
|
||||
|
||||
s_ip4 = nm_device_get_applied_setting(self, NM_TYPE_SETTING_IP4_CONFIG);
|
||||
if (!s_ip4)
|
||||
return NM_SETTING_IP4_CONFIG_CLAT_NO;
|
||||
|
||||
method = nm_device_get_effective_ip_config_method(self, AF_INET);
|
||||
if (nm_streq(method, NM_SETTING_IP4_CONFIG_METHOD_DISABLED))
|
||||
return NM_SETTING_IP4_CONFIG_CLAT_NO;
|
||||
|
||||
clat = nm_setting_ip4_config_get_clat(s_ip4);
|
||||
if (clat == NM_SETTING_IP4_CONFIG_CLAT_DEFAULT) {
|
||||
clat = nm_config_data_get_connection_default_int64(NM_CONFIG_GET_DATA,
|
||||
NM_CON_DEFAULT("ipv4.clat"),
|
||||
self,
|
||||
NM_SETTING_IP4_CONFIG_CLAT_NO,
|
||||
NM_SETTING_IP4_CONFIG_CLAT_FORCE,
|
||||
NM_SETTING_IP4_CONFIG_CLAT_NO);
|
||||
}
|
||||
|
||||
if (clat == NM_SETTING_IP4_CONFIG_CLAT_AUTO
|
||||
&& !nm_streq(method, NM_SETTING_IP4_CONFIG_METHOD_AUTO)) {
|
||||
/* clat=auto enables CLAT only with method=auto */
|
||||
clat = NM_SETTING_IP4_CONFIG_CLAT_NO;
|
||||
}
|
||||
|
||||
if (!HAVE_CLAT
|
||||
&& NM_IN_SET(clat, NM_SETTING_IP4_CONFIG_CLAT_AUTO, NM_SETTING_IP4_CONFIG_CLAT_FORCE)) {
|
||||
if (do_log) {
|
||||
_NMLOG(clat == NM_SETTING_IP4_CONFIG_CLAT_FORCE ? LOGL_WARN : LOGL_TRACE,
|
||||
LOGD_DEVICE,
|
||||
"CLAT will not work because it is disabled at build time");
|
||||
}
|
||||
clat = NM_SETTING_IP4_CONFIG_CLAT_NO;
|
||||
}
|
||||
|
||||
return clat;
|
||||
}
|
||||
|
||||
static NMMptcpFlags
|
||||
_prop_get_connection_mptcp_flags(NMDevice *self, NMConnection *connection)
|
||||
{
|
||||
|
|
@ -1922,26 +1966,43 @@ _prop_get_ipvx_may_fail_cached(NMDevice *self, int addr_family, NMTernary *cache
|
|||
}
|
||||
|
||||
static gboolean
|
||||
_prop_get_ipv4_dhcp_ipv6_only_preferred(NMDevice *self)
|
||||
_prop_get_ipv4_dhcp_ipv6_only_preferred(NMDevice *self, gboolean *out_is_auto)
|
||||
{
|
||||
NMSettingIP4Config *s_ip4;
|
||||
NMSettingIP4DhcpIpv6OnlyPreferred ipv6_only;
|
||||
|
||||
NM_SET_OUT(out_is_auto, FALSE);
|
||||
|
||||
s_ip4 = nm_device_get_applied_setting(self, NM_TYPE_SETTING_IP4_CONFIG);
|
||||
if (!s_ip4)
|
||||
return FALSE;
|
||||
|
||||
ipv6_only = nm_setting_ip4_config_get_dhcp_ipv6_only_preferred(s_ip4);
|
||||
if (ipv6_only != NM_SETTING_IP4_DHCP_IPV6_ONLY_PREFERRED_DEFAULT)
|
||||
return ipv6_only;
|
||||
if (ipv6_only == NM_SETTING_IP4_DHCP_IPV6_ONLY_PREFERRED_DEFAULT) {
|
||||
ipv6_only = nm_config_data_get_connection_default_int64(
|
||||
NM_CONFIG_GET_DATA,
|
||||
NM_CON_DEFAULT("ipv4.dhcp-ipv6-only-preferred"),
|
||||
self,
|
||||
NM_SETTING_IP4_DHCP_IPV6_ONLY_PREFERRED_NO,
|
||||
NM_SETTING_IP4_DHCP_IPV6_ONLY_PREFERRED_AUTO,
|
||||
NM_SETTING_IP4_DHCP_IPV6_ONLY_PREFERRED_AUTO);
|
||||
}
|
||||
|
||||
return nm_config_data_get_connection_default_int64(
|
||||
NM_CONFIG_GET_DATA,
|
||||
NM_CON_DEFAULT("ipv4.dhcp-ipv6-only-preferred"),
|
||||
self,
|
||||
NM_SETTING_IP4_DHCP_IPV6_ONLY_PREFERRED_NO,
|
||||
NM_SETTING_IP4_DHCP_IPV6_ONLY_PREFERRED_YES,
|
||||
NM_SETTING_IP4_DHCP_IPV6_ONLY_PREFERRED_NO);
|
||||
if (NM_IN_SET(ipv6_only,
|
||||
NM_SETTING_IP4_DHCP_IPV6_ONLY_PREFERRED_YES,
|
||||
NM_SETTING_IP4_DHCP_IPV6_ONLY_PREFERRED_NO))
|
||||
return ipv6_only == NM_SETTING_IP4_DHCP_IPV6_ONLY_PREFERRED_YES;
|
||||
|
||||
/* auto */
|
||||
NM_SET_OUT(out_is_auto, TRUE);
|
||||
|
||||
if (nm_streq0(nm_device_get_effective_ip_config_method(self, AF_INET6),
|
||||
NM_SETTING_IP6_CONFIG_METHOD_AUTO)
|
||||
&& _prop_get_ipv4_clat(self, FALSE) != NM_SETTING_IP4_CONFIG_CLAT_NO) {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -3642,6 +3703,7 @@ nm_device_create_l3_config_data_from_connection(NMDevice *self, NMConnection *co
|
|||
nm_l3_config_data_set_dnssec(l3cd, _prop_get_connection_dnssec(self, connection));
|
||||
nm_l3_config_data_set_ip6_privacy(l3cd, _prop_get_ipv6_ip6_privacy(self, connection));
|
||||
nm_l3_config_data_set_mptcp_flags(l3cd, _prop_get_connection_mptcp_flags(self, connection));
|
||||
|
||||
return l3cd;
|
||||
}
|
||||
|
||||
|
|
@ -4924,7 +4986,7 @@ _dev_l3_cfg_notify_cb(NML3Cfg *l3cfg, const NML3ConfigNotifyData *notify_data, N
|
|||
if (state >= NM_DEVICE_STATE_IP_CONFIG && state < NM_DEVICE_STATE_DEACTIVATING) {
|
||||
/* FIXME(l3cfg): MTU handling should be moved to l3cfg. */
|
||||
if (l3cd)
|
||||
priv->ip6_mtu = nm_l3_config_data_get_ip6_mtu(l3cd);
|
||||
priv->ip6_mtu = nm_l3_config_data_get_ip6_mtu_ra(l3cd);
|
||||
_commit_mtu(self);
|
||||
}
|
||||
_dev_ipll4_check_fallback(self, l3cd);
|
||||
|
|
@ -6344,6 +6406,14 @@ concheck_is_possible(NMDevice *self)
|
|||
if (priv->state == NM_DEVICE_STATE_UNKNOWN)
|
||||
return FALSE;
|
||||
|
||||
if (!nm_config_data_get_device_config_boolean_by_device(
|
||||
NM_CONFIG_GET_DATA,
|
||||
NM_CONFIG_KEYFILE_KEY_DEVICE_CHECK_CONNECTIVITY,
|
||||
self,
|
||||
TRUE,
|
||||
TRUE))
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
|
@ -6364,8 +6434,10 @@ concheck_periodic_schedule_do(NMDevice *self, int addr_family, gint64 now_ns)
|
|||
goto out;
|
||||
}
|
||||
|
||||
if (!concheck_is_possible(self))
|
||||
if (!concheck_is_possible(self)) {
|
||||
concheck_update_state(self, addr_family, NM_CONNECTIVITY_UNKNOWN, FALSE);
|
||||
goto out;
|
||||
}
|
||||
|
||||
nm_assert(now_ns > 0);
|
||||
nm_assert(priv->concheck_x[IS_IPv4].p_cur_interval > 0);
|
||||
|
|
@ -6588,7 +6660,11 @@ concheck_update_interval(NMDevice *self, int addr_family, gboolean check_now)
|
|||
concheck_periodic_schedule_do(self, addr_family, 0);
|
||||
|
||||
/* also update the fake connectivity state. */
|
||||
concheck_update_state(self, addr_family, NM_CONNECTIVITY_FAKE, TRUE);
|
||||
if (concheck_is_possible(self))
|
||||
concheck_update_state(self, addr_family, NM_CONNECTIVITY_FAKE, TRUE);
|
||||
else
|
||||
concheck_update_state(self, addr_family, NM_CONNECTIVITY_UNKNOWN, FALSE);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -6617,6 +6693,7 @@ concheck_update_state(NMDevice *self,
|
|||
/* @state is a result of the connectivity check. We only expect a precise
|
||||
* number of possible values. */
|
||||
nm_assert(NM_IN_SET(state,
|
||||
NM_CONNECTIVITY_UNKNOWN,
|
||||
NM_CONNECTIVITY_LIMITED,
|
||||
NM_CONNECTIVITY_PORTAL,
|
||||
NM_CONNECTIVITY_FULL,
|
||||
|
|
@ -6940,8 +7017,11 @@ nm_device_check_connectivity(NMDevice *self,
|
|||
NMDeviceConnectivityCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
if (!concheck_is_possible(self))
|
||||
if (!concheck_is_possible(self)) {
|
||||
concheck_update_state(self, AF_INET, NM_CONNECTIVITY_UNKNOWN, FALSE);
|
||||
concheck_update_state(self, AF_INET6, NM_CONNECTIVITY_UNKNOWN, FALSE);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
concheck_periodic_schedule_set(self, addr_family, CONCHECK_SCHEDULE_CHECK_EXTERNAL);
|
||||
return concheck_start(self, addr_family, callback, user_data, FALSE);
|
||||
|
|
@ -8329,6 +8409,17 @@ config_changed(NMConfig *config,
|
|||
&& !nm_device_get_applied_setting(self, NM_TYPE_SETTING_SRIOV))
|
||||
device_init_static_sriov_num_vfs(self);
|
||||
}
|
||||
|
||||
if (NM_FLAGS_HAS(changes, NM_CONFIG_CHANGE_VALUES) && concheck_is_possible(self)) {
|
||||
/* restart (periodic) connectivity checks if they were previously disabled */
|
||||
if (!nm_config_data_get_device_config_boolean_by_device(
|
||||
old_data,
|
||||
NM_CONFIG_KEYFILE_KEY_DEVICE_CHECK_CONNECTIVITY,
|
||||
self,
|
||||
TRUE,
|
||||
TRUE))
|
||||
nm_device_check_connectivity_update_interval(self);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -11439,6 +11530,8 @@ _dev_ipmanual_start(NMDevice *self)
|
|||
if (_prop_get_ipvx_routed_dns(self, AF_INET6) == NM_SETTING_IP_CONFIG_ROUTED_DNS_YES) {
|
||||
nm_l3_config_data_set_routed_dns(l3cd, AF_INET6, TRUE);
|
||||
}
|
||||
|
||||
nm_l3_config_data_set_clat_config(l3cd, _prop_get_ipv4_clat(self, TRUE));
|
||||
}
|
||||
|
||||
if (!l3cd) {
|
||||
|
|
@ -11747,8 +11840,9 @@ _dev_ipdhcpx_start(NMDevice *self, int addr_family)
|
|||
gboolean hostname_is_fqdn;
|
||||
gboolean send_client_id;
|
||||
guint8 dscp;
|
||||
gboolean dscp_explicit = FALSE;
|
||||
gboolean ipv6_only_pref = FALSE;
|
||||
gboolean dscp_explicit = FALSE;
|
||||
gboolean ipv6_only_pref = FALSE;
|
||||
gboolean ipv6_only_pref_auto = FALSE;
|
||||
|
||||
client_id = _prop_get_ipv4_dhcp_client_id(self, connection, hwaddr, &send_client_id);
|
||||
dscp = _prop_get_ipv4_dhcp_dscp(self, &dscp_explicit);
|
||||
|
|
@ -11767,13 +11861,15 @@ _dev_ipdhcpx_start(NMDevice *self, int addr_family)
|
|||
hostname = nm_setting_ip_config_get_dhcp_hostname(s_ip);
|
||||
}
|
||||
|
||||
if (_prop_get_ipv4_dhcp_ipv6_only_preferred(self)) {
|
||||
if (_prop_get_ipv4_dhcp_ipv6_only_preferred(self, &ipv6_only_pref_auto)) {
|
||||
if (nm_streq0(priv->ipv6_method, NM_SETTING_IP6_CONFIG_METHOD_DISABLED)) {
|
||||
_LOGI_ipdhcp(
|
||||
addr_family,
|
||||
"not requesting the \"IPv6-only preferred\" option because IPv6 is disabled");
|
||||
} else {
|
||||
_LOGD_ipdhcp(addr_family, "requesting the \"IPv6-only preferred\" option");
|
||||
_LOGD_ipdhcp(addr_family,
|
||||
"requesting the \"IPv6-only preferred\" option (%s enabled)",
|
||||
ipv6_only_pref_auto ? "automatically" : "explicitly");
|
||||
ipv6_only_pref = TRUE;
|
||||
}
|
||||
}
|
||||
|
|
@ -15352,36 +15448,16 @@ _dispatcher_complete_proceed_state(NMDispatcherCallId *call_id, gpointer user_da
|
|||
/*****************************************************************************/
|
||||
|
||||
typedef struct {
|
||||
NMLogDomain log_domain;
|
||||
NMDevice *device;
|
||||
gboolean ping_addresses_require_all;
|
||||
GSource *watch;
|
||||
GPid pid;
|
||||
char *binary;
|
||||
char *address;
|
||||
guint deadline;
|
||||
char *addr_str;
|
||||
NMIPAddrTyped addr_bin;
|
||||
|
||||
NMLogDomain log_domain;
|
||||
NMDevice *device;
|
||||
GCancellable *cancellable;
|
||||
gboolean require_all;
|
||||
CList ping_ops_lst;
|
||||
} PingOperation;
|
||||
|
||||
static PingOperation *
|
||||
ping_operation_new(NMDevice *self,
|
||||
NMLogDomain log_domain,
|
||||
const char *address,
|
||||
const char *ping_binary,
|
||||
guint ping_timeout,
|
||||
gboolean ip_ping_addresses_require_all)
|
||||
{
|
||||
PingOperation *ping_op = g_new0(PingOperation, 1);
|
||||
|
||||
ping_op->device = self;
|
||||
ping_op->log_domain = log_domain;
|
||||
ping_op->address = g_strdup(address);
|
||||
ping_op->binary = g_strdup(ping_binary);
|
||||
ping_op->deadline = ping_timeout + 10;
|
||||
ping_op->ping_addresses_require_all = ip_ping_addresses_require_all;
|
||||
|
||||
return ping_op;
|
||||
}
|
||||
|
||||
static void
|
||||
ip_check_pre_up(NMDevice *self)
|
||||
{
|
||||
|
|
@ -15404,188 +15480,154 @@ ip_check_pre_up(NMDevice *self)
|
|||
}
|
||||
|
||||
static void
|
||||
cleanup_ping_operation(PingOperation *ping_op)
|
||||
ping_op_cleanup(PingOperation *ping_op)
|
||||
{
|
||||
if (ping_op->watch) {
|
||||
nm_clear_g_source_inst(&ping_op->watch);
|
||||
}
|
||||
|
||||
if (ping_op->pid) {
|
||||
nm_utils_kill_child_async(ping_op->pid,
|
||||
SIGTERM,
|
||||
ping_op->log_domain,
|
||||
"ping",
|
||||
1000,
|
||||
NULL,
|
||||
NULL);
|
||||
ping_op->pid = 0;
|
||||
}
|
||||
|
||||
nm_clear_g_free(&ping_op->binary);
|
||||
nm_clear_g_free(&ping_op->address);
|
||||
nm_clear_g_cancellable(&ping_op->cancellable);
|
||||
nm_clear_g_free(&ping_op->addr_str);
|
||||
c_list_unlink_stale(&ping_op->ping_ops_lst);
|
||||
|
||||
g_free(ping_op);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
spawn_ping_for_operation(NMDevice *self, PingOperation *ping_op)
|
||||
static void
|
||||
ping_cleanup(NMDevice *self)
|
||||
{
|
||||
gs_free char *str_timeout = NULL;
|
||||
gs_free char *tmp_str = NULL;
|
||||
const char *args[] = {ping_op->binary,
|
||||
"-I",
|
||||
nm_device_get_ip_iface(self),
|
||||
"-c",
|
||||
"1",
|
||||
"-w",
|
||||
NULL,
|
||||
ping_op->address,
|
||||
NULL};
|
||||
gs_free_error GError *error = NULL;
|
||||
gboolean ret;
|
||||
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self);
|
||||
PingOperation *ping_op;
|
||||
|
||||
args[6] = str_timeout = g_strdup_printf("%u", ping_op->deadline);
|
||||
|
||||
tmp_str = g_strjoinv(" ", (char **) args);
|
||||
_LOGD(ping_op->log_domain, "ping: running '%s'", tmp_str);
|
||||
|
||||
ret = g_spawn_async("/",
|
||||
(char **) args,
|
||||
NULL,
|
||||
G_SPAWN_DO_NOT_REAP_CHILD,
|
||||
NULL,
|
||||
NULL,
|
||||
&ping_op->pid,
|
||||
&error);
|
||||
|
||||
if (ret) {
|
||||
ping_op->watch = nm_g_child_watch_add_source(ping_op->pid, ip_check_ping_watch_cb, ping_op);
|
||||
} else {
|
||||
_LOGD(ping_op->log_domain, "ping: could not spawn %s: %s", ping_op->binary, error->message);
|
||||
while ((ping_op = c_list_first_entry(&priv->ping_ops_lst_head, PingOperation, ping_ops_lst))) {
|
||||
ping_op_cleanup(ping_op);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
respawn_ping_cb(gpointer user_data)
|
||||
{
|
||||
PingOperation *ping_op = (PingOperation *) user_data;
|
||||
NMDevice *self = ping_op->device;
|
||||
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self);
|
||||
|
||||
nm_clear_g_source_inst(&ping_op->watch);
|
||||
|
||||
if (!spawn_ping_for_operation(self, ping_op)) {
|
||||
priv->ping_operations = g_list_remove(priv->ping_operations, ping_op);
|
||||
cleanup_ping_operation(ping_op);
|
||||
|
||||
if (g_list_length(priv->ping_operations) == 0) {
|
||||
ip_check_pre_up(self);
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
nm_clear_g_source_inst(&priv->ping_timeout);
|
||||
}
|
||||
|
||||
static void
|
||||
ip_check_ping_watch_cb(GPid pid, int status, gpointer user_data)
|
||||
ping_host_cb(GObject *source, GAsyncResult *result, gpointer user_data)
|
||||
{
|
||||
PingOperation *ping_op = (PingOperation *) user_data;
|
||||
NMDevice *self = ping_op->device;
|
||||
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self);
|
||||
gboolean success = FALSE;
|
||||
NMDevice *self;
|
||||
NMDevicePrivate *priv;
|
||||
PingOperation *ping_op = user_data;
|
||||
gs_free_error GError *error = NULL;
|
||||
gboolean success;
|
||||
NMLogDomain log_domain;
|
||||
gs_free char *addr_str = NULL;
|
||||
|
||||
if (!ping_op->watch)
|
||||
success = nm_utils_ping_host_finish(result, &error);
|
||||
if (nm_utils_error_is_cancelled(error))
|
||||
return;
|
||||
|
||||
nm_clear_g_source_inst(&ping_op->watch);
|
||||
ping_op->pid = 0;
|
||||
self = NM_DEVICE(ping_op->device);
|
||||
priv = NM_DEVICE_GET_PRIVATE(self);
|
||||
log_domain = ping_op->log_domain;
|
||||
addr_str = g_steal_pointer(&ping_op->addr_str);
|
||||
|
||||
if (WIFEXITED(status)) {
|
||||
if (WEXITSTATUS(status) == 0) {
|
||||
_LOGD(ping_op->log_domain, "ping: ping succeeded on %s", ping_op->address);
|
||||
success = TRUE;
|
||||
} else {
|
||||
_LOGD(ping_op->log_domain,
|
||||
"ping: ping failed with error code %d on %s",
|
||||
WEXITSTATUS(status),
|
||||
ping_op->address);
|
||||
}
|
||||
} else {
|
||||
_LOGD(ping_op->log_domain,
|
||||
"ping: stopped unexpectedly with status %d on %s",
|
||||
status,
|
||||
ping_op->address);
|
||||
if (!success) {
|
||||
/* it should never fail because we set an infinite timeout */
|
||||
nm_assert_not_reached();
|
||||
return;
|
||||
}
|
||||
|
||||
if (success) {
|
||||
if (ping_op->ping_addresses_require_all) {
|
||||
priv->ping_operations = g_list_remove(priv->ping_operations, ping_op);
|
||||
if (g_list_length(priv->ping_operations) == 0) {
|
||||
_LOGD(ping_op->log_domain,
|
||||
"ping: ip-ping-addresses requires all, all ping checks on ip-ping-addresses "
|
||||
"succeeded");
|
||||
if (priv->ping_timeout)
|
||||
nm_clear_g_source_inst(&priv->ping_timeout);
|
||||
ip_check_pre_up(self);
|
||||
}
|
||||
cleanup_ping_operation(ping_op);
|
||||
} else {
|
||||
nm_assert(priv->ping_operations);
|
||||
|
||||
g_list_free_full(priv->ping_operations, (GDestroyNotify) cleanup_ping_operation);
|
||||
priv->ping_operations = NULL;
|
||||
|
||||
if (priv->ping_timeout)
|
||||
nm_clear_g_source_inst(&priv->ping_timeout);
|
||||
|
||||
_LOGD(ping_op->log_domain,
|
||||
"ping: ip-ping-addresses requires any, one ping check on ip-ping-addresses "
|
||||
"succeeded");
|
||||
ip_check_pre_up(self);
|
||||
if (ping_op->require_all) {
|
||||
ping_op_cleanup(ping_op);
|
||||
if (!c_list_is_empty(&priv->ping_ops_lst_head)) {
|
||||
_LOGD(log_domain,
|
||||
"ping: check on address %s succeeded, waiting for other addresses",
|
||||
addr_str);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
/* If ping exited with an error it may have returned early,
|
||||
* wait 1 second and restart it */
|
||||
ping_op->watch = nm_g_timeout_add_seconds_source(1, respawn_ping_cb, ping_op);
|
||||
}
|
||||
|
||||
_LOGD(log_domain, "ping: check on address %s succeeded, continuing the activation", addr_str);
|
||||
|
||||
ping_cleanup(self);
|
||||
ip_check_pre_up(self);
|
||||
}
|
||||
|
||||
static void
|
||||
ping_operation_start(NMDevice *self,
|
||||
const char *addr_str,
|
||||
NMIPAddrTyped *addr_bin,
|
||||
gboolean require_all)
|
||||
{
|
||||
PingOperation *ping_op;
|
||||
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self);
|
||||
NMIPAddrTyped addr_bin_local;
|
||||
char buf[NM_INET_ADDRSTRLEN];
|
||||
int addr_family;
|
||||
int ret;
|
||||
|
||||
/* Exactly one of the two must be set */
|
||||
nm_assert(!!addr_str ^ !!addr_bin);
|
||||
|
||||
/* Derive the string address from the binary and vice versa */
|
||||
if (addr_str) {
|
||||
ret = nm_inet_parse_bin_full(AF_UNSPEC,
|
||||
FALSE,
|
||||
addr_str,
|
||||
&addr_family,
|
||||
&addr_bin_local.addr.addr_ptr);
|
||||
nm_assert(ret);
|
||||
addr_bin_local.addr_family = addr_family;
|
||||
addr_bin = &addr_bin_local;
|
||||
} else {
|
||||
nm_inet_ntop(addr_bin->addr_family, addr_bin->addr.addr_ptr, buf);
|
||||
addr_str = buf;
|
||||
}
|
||||
|
||||
/* When pinging the gateway, the caller must ensure that the IP configuration is ready.
|
||||
* For the ip-ping-addresses property, a valid connection always has may-fail=no for
|
||||
* the families of all the target addresses. Thus, at this point the IP configuration
|
||||
* must also be ready. */
|
||||
nm_assert(priv->ip_data_x[NM_IS_IPv4(addr_bin->addr_family)].state == NM_DEVICE_IP_STATE_READY);
|
||||
|
||||
ping_op = g_new(PingOperation, 1);
|
||||
*ping_op = (PingOperation) {
|
||||
.device = self,
|
||||
.cancellable = g_cancellable_new(),
|
||||
.require_all = require_all,
|
||||
.addr_bin = *addr_bin,
|
||||
.addr_str = g_strdup(addr_str),
|
||||
.log_domain = (addr_bin->addr_family == AF_INET) ? LOGD_IP4 : LOGD_IP6,
|
||||
};
|
||||
|
||||
/* Start the asynchronous ping operation */
|
||||
nm_utils_ping_host(ping_op->addr_bin,
|
||||
nm_device_get_ip_ifindex(self),
|
||||
0, /* try forever */
|
||||
ping_op->cancellable,
|
||||
ping_host_cb,
|
||||
ping_op);
|
||||
|
||||
c_list_link_tail(&priv->ping_ops_lst_head, &ping_op->ping_ops_lst);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
ip_check_ping_timeout_cb(gpointer user_data)
|
||||
{
|
||||
NMDevice *self = NM_DEVICE(user_data);
|
||||
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self);
|
||||
NMDevice *self = NM_DEVICE(user_data);
|
||||
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self);
|
||||
PingOperation *ping_op;
|
||||
nm_auto_free_gstring GString *str = NULL;
|
||||
|
||||
_LOGW(LOGD_DEVICE, "ping timeout: unreachable gateway or ip-ping-addresses");
|
||||
|
||||
if (priv->ping_operations) {
|
||||
g_list_free_full(priv->ping_operations, (GDestroyNotify) cleanup_ping_operation);
|
||||
priv->ping_operations = NULL;
|
||||
if (_LOGW_ENABLED(LOGD_DEVICE)) {
|
||||
str = g_string_new("");
|
||||
c_list_for_each_entry (ping_op, &priv->ping_ops_lst_head, ping_ops_lst) {
|
||||
if (str->len != 0)
|
||||
g_string_append(str, ", ");
|
||||
g_string_append(str, ping_op->addr_str);
|
||||
}
|
||||
_LOGW(LOGD_DEVICE,
|
||||
"ping: the following addresses were not reachable within the timeout: %s",
|
||||
str->str);
|
||||
}
|
||||
|
||||
if (priv->ping_timeout)
|
||||
nm_clear_g_source_inst(&priv->ping_timeout);
|
||||
ping_cleanup(self);
|
||||
ip_check_pre_up(self);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
start_ping(NMDevice *self, PingOperation *ping_op)
|
||||
{
|
||||
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self);
|
||||
|
||||
if (spawn_ping_for_operation(self, ping_op)) {
|
||||
priv->ping_operations = g_list_append(priv->ping_operations, ping_op);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
cleanup_ping_operation(ping_op);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
nm_device_start_ip_check(NMDevice *self)
|
||||
{
|
||||
|
|
@ -15594,17 +15636,13 @@ nm_device_start_ip_check(NMDevice *self)
|
|||
NMSettingConnection *s_con;
|
||||
guint gw_ping_timeout = 0;
|
||||
guint ip_ping_timeout = 0;
|
||||
const char *ping_binary = NULL;
|
||||
char buf[NM_INET_ADDRSTRLEN];
|
||||
NMLogDomain log_domain = LOGD_IP4;
|
||||
gboolean ip_ping_addresses_require_all;
|
||||
gboolean ping_started = FALSE;
|
||||
gboolean require_all;
|
||||
NMIPAddrTyped addr_bin = {};
|
||||
|
||||
/* Shouldn't be any active ping here, since IP_CHECK happens after the
|
||||
* first IP method completes. Any subsequently completing IP method doesn't
|
||||
* get checked.
|
||||
*/
|
||||
g_return_if_fail(priv->ping_operations == NULL);
|
||||
* get checked. */
|
||||
g_return_if_fail(c_list_is_empty(&priv->ping_ops_lst_head));
|
||||
g_return_if_fail(priv->ip_data_4.state == NM_DEVICE_IP_STATE_READY
|
||||
|| priv->ip_data_6.state == NM_DEVICE_IP_STATE_READY);
|
||||
|
||||
|
|
@ -15613,100 +15651,71 @@ nm_device_start_ip_check(NMDevice *self)
|
|||
|
||||
s_con = nm_connection_get_setting_connection(connection);
|
||||
g_assert(s_con);
|
||||
gw_ping_timeout = nm_setting_connection_get_gateway_ping_timeout(s_con);
|
||||
ip_ping_addresses_require_all = _prop_get_connection_ip_ping_addresses_require_all(self, s_con);
|
||||
ip_ping_timeout = nm_setting_connection_get_ip_ping_timeout(s_con);
|
||||
gw_ping_timeout = nm_setting_connection_get_gateway_ping_timeout(s_con);
|
||||
ip_ping_timeout = nm_setting_connection_get_ip_ping_timeout(s_con);
|
||||
require_all = _prop_get_connection_ip_ping_addresses_require_all(self, s_con);
|
||||
|
||||
buf[0] = '\0';
|
||||
if (gw_ping_timeout != 0 && ip_ping_timeout == 0) {
|
||||
/* the timeouts are mutually exclusive */
|
||||
nm_assert(gw_ping_timeout == 0 || ip_ping_timeout == 0);
|
||||
|
||||
if (gw_ping_timeout > 0) {
|
||||
const NMPObject *gw;
|
||||
const NML3ConfigData *l3cd;
|
||||
|
||||
_LOGD(LOGD_DEVICE, "starting ping gateway...");
|
||||
|
||||
l3cd = priv->l3cfg ? nm_l3cfg_get_combined_l3cd(priv->l3cfg, TRUE) : NULL;
|
||||
if (!l3cd) {
|
||||
/* pass */
|
||||
} else if (priv->ip_data_4.state == NM_DEVICE_IP_STATE_READY) {
|
||||
gw = nm_l3_config_data_get_best_default_route(l3cd, AF_INET);
|
||||
if (gw) {
|
||||
nm_inet4_ntop(NMP_OBJECT_CAST_IP4_ROUTE(gw)->gateway, buf);
|
||||
ping_binary = nm_utils_find_helper("ping", "/usr/bin/ping", NULL);
|
||||
log_domain = LOGD_IP4;
|
||||
addr_bin.addr_family = AF_INET;
|
||||
addr_bin.addr.addr4 = NMP_OBJECT_CAST_IP4_ROUTE(gw)->gateway;
|
||||
}
|
||||
} else if (priv->ip_data_6.state == NM_DEVICE_IP_STATE_READY) {
|
||||
gw = nm_l3_config_data_get_best_default_route(l3cd, AF_INET6);
|
||||
if (gw) {
|
||||
nm_inet6_ntop(&NMP_OBJECT_CAST_IP6_ROUTE(gw)->gateway, buf);
|
||||
ping_binary = nm_utils_find_helper("ping6", "/usr/bin/ping6", NULL);
|
||||
log_domain = LOGD_IP6;
|
||||
addr_bin.addr_family = AF_INET6;
|
||||
addr_bin.addr.addr6 = NMP_OBJECT_CAST_IP6_ROUTE(gw)->gateway;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (buf[0]) {
|
||||
PingOperation *ping_op = ping_operation_new(self,
|
||||
log_domain,
|
||||
buf,
|
||||
ping_binary,
|
||||
gw_ping_timeout,
|
||||
ip_ping_addresses_require_all);
|
||||
|
||||
if (start_ping(self, ping_op))
|
||||
ping_started = TRUE;
|
||||
}
|
||||
|
||||
if (gw_ping_timeout == 0 && ip_ping_timeout != 0) {
|
||||
if (addr_bin.addr_family != AF_UNSPEC) {
|
||||
_LOGD(LOGD_DEVICE,
|
||||
"starting ping on the IPv%c gateway with a %u seconds timeout",
|
||||
nm_utils_addr_family_to_char(addr_bin.addr_family),
|
||||
gw_ping_timeout);
|
||||
ping_operation_start(self, NULL, &addr_bin, require_all);
|
||||
}
|
||||
} else if (ip_ping_timeout > 0) {
|
||||
const NML3ConfigData *l3cd;
|
||||
GArray *ip_ping_addresses;
|
||||
const char *const *strv;
|
||||
guint i;
|
||||
GArray *ip_ping_addresses = _nm_setting_connection_get_ip_ping_addresses(s_con);
|
||||
const char *const *strv = nm_strvarray_get_strv_notempty(ip_ping_addresses, NULL);
|
||||
|
||||
_LOGD(LOGD_DEVICE, "starting ping ip addresses...");
|
||||
ip_ping_addresses = _nm_setting_connection_get_ip_ping_addresses(s_con);
|
||||
strv = nm_strvarray_get_strv_notnull(ip_ping_addresses, NULL);
|
||||
|
||||
_LOGD(LOGD_DEVICE,
|
||||
"starting ping on the ip-ping-addresses with a %u seconds timeout",
|
||||
ip_ping_timeout);
|
||||
|
||||
l3cd = priv->l3cfg ? nm_l3cfg_get_combined_l3cd(priv->l3cfg, TRUE) : NULL;
|
||||
|
||||
if (l3cd) {
|
||||
for (i = 0; strv[i]; i++) {
|
||||
const char *s = strv[i];
|
||||
struct in_addr ipv4_addr;
|
||||
struct in6_addr ipv6_addr;
|
||||
|
||||
if (priv->ip_data_4.state == NM_DEVICE_IP_STATE_READY
|
||||
&& inet_pton(AF_INET, (const char *) s, &ipv4_addr)) {
|
||||
ping_binary = nm_utils_find_helper("ping", "/usr/bin/ping", NULL);
|
||||
log_domain = LOGD_IP4;
|
||||
} else if (priv->ip_data_6.state == NM_DEVICE_IP_STATE_READY
|
||||
&& inet_pton(AF_INET6, (const char *) s, &ipv6_addr)) {
|
||||
ping_binary = nm_utils_find_helper("ping6", "/usr/bin/ping6", NULL);
|
||||
log_domain = LOGD_IP6;
|
||||
} else
|
||||
continue;
|
||||
|
||||
if (s[0]) {
|
||||
PingOperation *ping_op = ping_operation_new(self,
|
||||
log_domain,
|
||||
s,
|
||||
ping_binary,
|
||||
ip_ping_timeout,
|
||||
ip_ping_addresses_require_all);
|
||||
|
||||
if (start_ping(self, ping_op))
|
||||
ping_started = TRUE;
|
||||
}
|
||||
ping_operation_start(self, strv[i], NULL, require_all);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ping_started) {
|
||||
if (c_list_is_empty(&priv->ping_ops_lst_head)) {
|
||||
/* No ping operation in progress, advance to pre-up */
|
||||
ip_check_pre_up(self);
|
||||
} else {
|
||||
priv->ping_timeout =
|
||||
nm_g_timeout_add_seconds_source(gw_ping_timeout ? gw_ping_timeout : ip_ping_timeout,
|
||||
nm_g_timeout_add_seconds_source(ip_ping_timeout > 0 ? ip_ping_timeout : gw_ping_timeout,
|
||||
ip_check_ping_timeout_cb,
|
||||
self);
|
||||
}
|
||||
/* If no ping was started, just advance to pre_up. */
|
||||
else
|
||||
ip_check_pre_up(self);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
|
@ -17165,17 +17174,11 @@ _cancel_activation(NMDevice *self)
|
|||
|
||||
_dispatcher_cleanup(self);
|
||||
|
||||
if (priv->ping_operations) {
|
||||
g_list_free_full(priv->ping_operations, (GDestroyNotify) cleanup_ping_operation);
|
||||
priv->ping_operations = NULL;
|
||||
}
|
||||
|
||||
if (priv->ping_timeout)
|
||||
nm_clear_g_source_inst(&priv->ping_timeout);
|
||||
|
||||
_dev_ip_state_cleanup(self, AF_INET, FALSE);
|
||||
_dev_ip_state_cleanup(self, AF_INET6, FALSE);
|
||||
|
||||
ping_cleanup(self);
|
||||
|
||||
/* Break the activation chain */
|
||||
activation_source_clear(self);
|
||||
}
|
||||
|
|
@ -17931,13 +17934,8 @@ _set_state_full(NMDevice *self, NMDeviceState state, NMDeviceStateReason reason,
|
|||
break;
|
||||
}
|
||||
case NM_DEVICE_STATE_SECONDARIES:
|
||||
if (priv->ping_operations) {
|
||||
g_list_free_full(priv->ping_operations, (GDestroyNotify) cleanup_ping_operation);
|
||||
priv->ping_operations = NULL;
|
||||
}
|
||||
if (priv->ping_timeout)
|
||||
nm_clear_g_source_inst(&priv->ping_timeout);
|
||||
_LOGD(LOGD_DEVICE, "device entered SECONDARIES state");
|
||||
ping_cleanup(self);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
|
@ -18917,14 +18915,14 @@ nm_device_get_supplicant_timeout(NMDevice *self)
|
|||
SUPPLICANT_DEFAULT_TIMEOUT);
|
||||
}
|
||||
|
||||
gboolean
|
||||
nm_device_auth_retries_try_next(NMDevice *self)
|
||||
static int
|
||||
_device_get_auth_retries(NMDevice *self)
|
||||
{
|
||||
NMDevicePrivate *priv;
|
||||
NMSettingConnection *s_con;
|
||||
int auth_retries;
|
||||
|
||||
g_return_val_if_fail(NM_IS_DEVICE(self), FALSE);
|
||||
g_return_val_if_fail(NM_IS_DEVICE(self), 0);
|
||||
|
||||
priv = NM_DEVICE_GET_PRIVATE(self);
|
||||
auth_retries = priv->auth_retries;
|
||||
|
|
@ -18956,13 +18954,47 @@ nm_device_auth_retries_try_next(NMDevice *self)
|
|||
priv->auth_retries = auth_retries;
|
||||
}
|
||||
|
||||
return auth_retries;
|
||||
}
|
||||
|
||||
gboolean
|
||||
nm_device_auth_retries_has_next(NMDevice *self)
|
||||
{
|
||||
int auth_retries;
|
||||
|
||||
g_return_val_if_fail(NM_IS_DEVICE(self), FALSE);
|
||||
|
||||
auth_retries = _device_get_auth_retries(self);
|
||||
|
||||
if (auth_retries == NM_DEVICE_AUTH_RETRIES_INFINITY)
|
||||
return TRUE;
|
||||
|
||||
if (auth_retries > 0)
|
||||
return TRUE;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
nm_device_auth_retries_try_next(NMDevice *self)
|
||||
{
|
||||
NMDevicePrivate *priv;
|
||||
int auth_retries;
|
||||
|
||||
g_return_val_if_fail(NM_IS_DEVICE(self), FALSE);
|
||||
|
||||
priv = NM_DEVICE_GET_PRIVATE(self);
|
||||
auth_retries = _device_get_auth_retries(self);
|
||||
|
||||
if (auth_retries == NM_DEVICE_AUTH_RETRIES_INFINITY)
|
||||
return TRUE;
|
||||
if (auth_retries <= 0) {
|
||||
nm_assert(auth_retries == 0);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
priv->auth_retries--;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
|
@ -19602,6 +19634,8 @@ nm_device_init(NMDevice *self)
|
|||
priv->available_connections = g_hash_table_new_full(nm_direct_hash, NULL, g_object_unref, NULL);
|
||||
priv->ip6_saved_properties = g_hash_table_new_full(nm_str_hash, g_str_equal, NULL, g_free);
|
||||
|
||||
c_list_init(&priv->ping_ops_lst_head);
|
||||
|
||||
priv->managed_type_ = NM_DEVICE_MANAGED_TYPE_EXTERNAL;
|
||||
/* If networking is already disabled at boot, we want to manage all devices
|
||||
* after re-enabling networking; hence, the initial state is MANAGED. */
|
||||
|
|
|
|||
|
|
@ -791,6 +791,7 @@ void nm_device_update_permanent_hw_address(NMDevice *self, gboolean force_fr
|
|||
void nm_device_update_dynamic_ip_setup(NMDevice *self, const char *reason);
|
||||
guint nm_device_get_supplicant_timeout(NMDevice *self);
|
||||
|
||||
gboolean nm_device_auth_retries_has_next(NMDevice *self);
|
||||
gboolean nm_device_auth_retries_try_next(NMDevice *self);
|
||||
|
||||
gboolean nm_device_hw_addr_get_cloned(NMDevice *self,
|
||||
|
|
|
|||
|
|
@ -2270,6 +2270,37 @@ add_new:
|
|||
return NM_ACT_STAGE_RETURN_SUCCESS;
|
||||
}
|
||||
|
||||
static void
|
||||
set_powersave(NMDevice *device)
|
||||
{
|
||||
NMDeviceIwd *self = NM_DEVICE_IWD(device);
|
||||
NMSettingWireless *s_wireless;
|
||||
NMSettingWirelessPowersave val;
|
||||
|
||||
s_wireless = nm_device_get_applied_setting(device, NM_TYPE_SETTING_WIRELESS);
|
||||
|
||||
g_return_if_fail(s_wireless);
|
||||
|
||||
val = nm_setting_wireless_get_powersave(s_wireless);
|
||||
if (val == NM_SETTING_WIRELESS_POWERSAVE_DEFAULT) {
|
||||
val = nm_config_data_get_connection_default_int64(NM_CONFIG_GET_DATA,
|
||||
"wifi.powersave",
|
||||
device,
|
||||
NM_SETTING_WIRELESS_POWERSAVE_IGNORE,
|
||||
NM_SETTING_WIRELESS_POWERSAVE_ENABLE,
|
||||
NM_SETTING_WIRELESS_POWERSAVE_IGNORE);
|
||||
}
|
||||
|
||||
_LOGT(LOGD_WIFI, "powersave is set to %u", (unsigned) val);
|
||||
|
||||
if (val == NM_SETTING_WIRELESS_POWERSAVE_IGNORE)
|
||||
return;
|
||||
|
||||
nm_platform_wifi_set_powersave(nm_device_get_platform(device),
|
||||
nm_device_get_ifindex(device),
|
||||
val == NM_SETTING_WIRELESS_POWERSAVE_ENABLE);
|
||||
}
|
||||
|
||||
static NMActStageReturn
|
||||
act_stage2_config(NMDevice *device, NMDeviceStateReason *out_failure_reason)
|
||||
{
|
||||
|
|
@ -2297,6 +2328,8 @@ act_stage2_config(NMDevice *device, NMDeviceStateReason *out_failure_reason)
|
|||
goto out_fail;
|
||||
}
|
||||
|
||||
set_powersave(device);
|
||||
|
||||
/* With priv->iwd_autoconnect we have to let IWD handle retries for
|
||||
* infrastructure networks. IWD will not necessarily retry the same
|
||||
* network after a failure but it will likely go into an autoconnect
|
||||
|
|
|
|||
|
|
@ -194,6 +194,9 @@ static void supplicant_iface_notify_p2p_available(NMSupplicantInterface *iface,
|
|||
static void supplicant_iface_notify_wpa_psk_mismatch_cb(NMSupplicantInterface *iface,
|
||||
NMDeviceWifi *self);
|
||||
|
||||
static void supplicant_iface_notify_wpa_sae_mismatch_cb(NMSupplicantInterface *iface,
|
||||
NMDeviceWifi *self);
|
||||
|
||||
static void periodic_update(NMDeviceWifi *self);
|
||||
|
||||
static void ap_add_remove(NMDeviceWifi *self,
|
||||
|
|
@ -631,6 +634,10 @@ supplicant_interface_acquire_cb(NMSupplicantManager *supplicant_manager,
|
|||
NM_SUPPLICANT_INTERFACE_PSK_MISMATCH,
|
||||
G_CALLBACK(supplicant_iface_notify_wpa_psk_mismatch_cb),
|
||||
self);
|
||||
g_signal_connect(priv->sup_iface,
|
||||
NM_SUPPLICANT_INTERFACE_SAE_MISMATCH,
|
||||
G_CALLBACK(supplicant_iface_notify_wpa_sae_mismatch_cb),
|
||||
self);
|
||||
|
||||
_scan_notify_is_scanning(self);
|
||||
|
||||
|
|
@ -2244,6 +2251,26 @@ wps_timeout_cb(gpointer user_data)
|
|||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
wifi_connection_is_new(NMDeviceWifi *self)
|
||||
{
|
||||
NMDevice *device = NM_DEVICE(self);
|
||||
NMActRequest *req;
|
||||
NMSettingsConnection *connection;
|
||||
guint64 timestamp = 0;
|
||||
|
||||
req = nm_device_get_act_request(device);
|
||||
g_return_val_if_fail(NM_IS_ACT_REQUEST(req), TRUE);
|
||||
|
||||
connection = nm_act_request_get_settings_connection(req);
|
||||
g_return_val_if_fail(NM_IS_SETTINGS_CONNECTION(connection), TRUE);
|
||||
|
||||
if (nm_settings_connection_get_timestamp(connection, ×tamp) && timestamp != 0)
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
wifi_secrets_get_secrets(NMDeviceWifi *self,
|
||||
const char *setting_name,
|
||||
|
|
@ -2398,10 +2425,11 @@ handle_8021x_or_psk_auth_fail(NMDeviceWifi *self,
|
|||
NMSupplicantInterfaceState old_state,
|
||||
int disconnect_reason)
|
||||
{
|
||||
NMDevice *device = NM_DEVICE(self);
|
||||
NMActRequest *req;
|
||||
const char *setting_name = NULL;
|
||||
gboolean handled = FALSE;
|
||||
NMDevice *device = NM_DEVICE(self);
|
||||
NMActRequest *req;
|
||||
const char *setting_name = NULL;
|
||||
NMSecretAgentGetSecretsFlags secret_flags = NM_SECRET_AGENT_GET_SECRETS_FLAG_ALLOW_INTERACTION
|
||||
| NM_SECRET_AGENT_GET_SECRETS_FLAG_REQUEST_NEW;
|
||||
|
||||
g_return_val_if_fail(new_state == NM_SUPPLICANT_INTERFACE_STATE_DISCONNECTED, FALSE);
|
||||
|
||||
|
|
@ -2411,8 +2439,7 @@ handle_8021x_or_psk_auth_fail(NMDeviceWifi *self,
|
|||
req = nm_device_get_act_request(NM_DEVICE(self));
|
||||
g_return_val_if_fail(req != NULL, FALSE);
|
||||
|
||||
if (need_new_8021x_secrets(self, old_state, &setting_name)
|
||||
|| need_new_wpa_psk(self, old_state, disconnect_reason, &setting_name)) {
|
||||
if (need_new_8021x_secrets(self, old_state, &setting_name)) {
|
||||
nm_act_request_clear_secrets(req);
|
||||
|
||||
_LOGI(LOGD_DEVICE | LOGD_WIFI,
|
||||
|
|
@ -2422,14 +2449,54 @@ handle_8021x_or_psk_auth_fail(NMDeviceWifi *self,
|
|||
nm_device_state_changed(device,
|
||||
NM_DEVICE_STATE_NEED_AUTH,
|
||||
NM_DEVICE_STATE_REASON_SUPPLICANT_DISCONNECT);
|
||||
wifi_secrets_get_secrets(self,
|
||||
setting_name,
|
||||
NM_SECRET_AGENT_GET_SECRETS_FLAG_ALLOW_INTERACTION
|
||||
| NM_SECRET_AGENT_GET_SECRETS_FLAG_REQUEST_NEW);
|
||||
handled = TRUE;
|
||||
wifi_secrets_get_secrets(self, setting_name, secret_flags);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return handled;
|
||||
if (need_new_wpa_psk(self, old_state, disconnect_reason, &setting_name)) {
|
||||
nm_act_request_clear_secrets(req);
|
||||
cleanup_association_attempt(self, TRUE);
|
||||
|
||||
if (wifi_connection_is_new(self)) {
|
||||
_LOGI(LOGD_DEVICE | LOGD_WIFI,
|
||||
"Activation: (wifi) new connection disconnected during association, asking for "
|
||||
"new key");
|
||||
nm_device_state_changed(device,
|
||||
NM_DEVICE_STATE_NEED_AUTH,
|
||||
NM_DEVICE_STATE_REASON_SUPPLICANT_DISCONNECT);
|
||||
wifi_secrets_get_secrets(self, setting_name, secret_flags);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (!nm_device_auth_retries_try_next(device)) {
|
||||
nm_device_state_changed(device,
|
||||
NM_DEVICE_STATE_FAILED,
|
||||
NM_DEVICE_STATE_REASON_NO_SECRETS);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (nm_device_auth_retries_has_next(device)) {
|
||||
secret_flags &= ~NM_SECRET_AGENT_GET_SECRETS_FLAG_REQUEST_NEW;
|
||||
_LOGI(
|
||||
LOGD_DEVICE | LOGD_WIFI,
|
||||
"Activation: (wifi) disconnected during association, reauthenticating connection");
|
||||
} else {
|
||||
_LOGI(LOGD_DEVICE | LOGD_WIFI,
|
||||
"Activation: (wifi) disconnected during association, asking for new key");
|
||||
}
|
||||
|
||||
nm_device_state_changed(device,
|
||||
NM_DEVICE_STATE_NEED_AUTH,
|
||||
NM_DEVICE_STATE_REASON_SUPPLICANT_DISCONNECT);
|
||||
wifi_secrets_get_secrets(self, setting_name, secret_flags);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
_LOGI(LOGD_DEVICE | LOGD_WIFI,
|
||||
"Activation: (wifi) disconnected during association, retrying connection");
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
|
|
@ -2861,6 +2928,12 @@ supplicant_iface_notify_wpa_psk_mismatch_cb(NMSupplicantInterface *iface, NMDevi
|
|||
if (nm_device_get_state(device) != NM_DEVICE_STATE_CONFIG)
|
||||
return;
|
||||
|
||||
if (!wifi_connection_is_new(self) && nm_device_auth_retries_has_next(device)) {
|
||||
_LOGI(LOGD_DEVICE | LOGD_WIFI,
|
||||
"Activation: (wifi) psk mismatch reported by supplicant, retrying connection");
|
||||
return;
|
||||
}
|
||||
|
||||
_LOGI(LOGD_DEVICE | LOGD_WIFI,
|
||||
"Activation: (wifi) psk mismatch reported by supplicant, asking for new key");
|
||||
|
||||
|
|
@ -2879,6 +2952,34 @@ supplicant_iface_notify_wpa_psk_mismatch_cb(NMSupplicantInterface *iface, NMDevi
|
|||
| NM_SECRET_AGENT_GET_SECRETS_FLAG_REQUEST_NEW);
|
||||
}
|
||||
|
||||
static void
|
||||
supplicant_iface_notify_wpa_sae_mismatch_cb(NMSupplicantInterface *iface, NMDeviceWifi *self)
|
||||
{
|
||||
NMDevice *device = NM_DEVICE(self);
|
||||
NMActRequest *req;
|
||||
const char *setting_name = NM_SETTING_WIRELESS_SECURITY_SETTING_NAME;
|
||||
|
||||
if (nm_device_get_state(device) != NM_DEVICE_STATE_CONFIG)
|
||||
return;
|
||||
|
||||
_LOGI(LOGD_DEVICE | LOGD_WIFI,
|
||||
"Activation: (wifi) SAE password mismatch reported by supplicant, asking for new key");
|
||||
|
||||
req = nm_device_get_act_request(NM_DEVICE(self));
|
||||
g_return_if_fail(req != NULL);
|
||||
|
||||
nm_act_request_clear_secrets(req);
|
||||
|
||||
cleanup_association_attempt(self, TRUE);
|
||||
nm_device_state_changed(device,
|
||||
NM_DEVICE_STATE_NEED_AUTH,
|
||||
NM_DEVICE_STATE_REASON_SUPPLICANT_DISCONNECT);
|
||||
wifi_secrets_get_secrets(self,
|
||||
setting_name,
|
||||
NM_SECRET_AGENT_GET_SECRETS_FLAG_ALLOW_INTERACTION
|
||||
| NM_SECRET_AGENT_GET_SECRETS_FLAG_REQUEST_NEW);
|
||||
}
|
||||
|
||||
/*
|
||||
* supplicant_connection_timeout_cb
|
||||
*
|
||||
|
|
@ -3222,8 +3323,19 @@ act_stage1_prepare(NMDevice *device, NMDeviceStateReason *out_failure_reason)
|
|||
static void
|
||||
ensure_hotspot_frequency(NMDeviceWifi *self, NMSettingWireless *s_wifi, NMWifiAP *ap)
|
||||
{
|
||||
guint32 a_freqs[] = {5180, 5200, 5220, 5745, 5765, 5785, 5805, 0};
|
||||
guint32 bg_freqs[] = {2412, 2437, 2462, 2472, 0};
|
||||
guint32 freqs_a[] = {5180, /* only U-NII-1 channels: non-DFS and available everywhere */
|
||||
5200,
|
||||
5220,
|
||||
5240,
|
||||
0};
|
||||
guint32 freqs_bg[] = {2412, 2437, 2462, 2472, 0};
|
||||
guint32 freqs_6ghz[] = {5975, /* only U-NII-5 PSC channels, for better compatibility */
|
||||
6055,
|
||||
6135,
|
||||
6215,
|
||||
6295,
|
||||
6375,
|
||||
0};
|
||||
guint32 *rnd_freqs;
|
||||
guint rnd_freqs_len;
|
||||
NMDevice *device = NM_DEVICE(self);
|
||||
|
|
@ -3234,7 +3346,7 @@ ensure_hotspot_frequency(NMDeviceWifi *self, NMSettingWireless *s_wifi, NMWifiAP
|
|||
guint l;
|
||||
|
||||
nm_assert(ap);
|
||||
nm_assert(NM_IN_STRSET(band, NULL, "a", "bg"));
|
||||
nm_assert(NM_IN_STRSET(band, NULL, "a", "bg", "6GHz"));
|
||||
|
||||
if (nm_wifi_ap_get_freq(ap))
|
||||
return;
|
||||
|
|
@ -3268,11 +3380,14 @@ ensure_hotspot_frequency(NMDeviceWifi *self, NMSettingWireless *s_wifi, NMWifiAP
|
|||
}
|
||||
|
||||
if (nm_streq0(band, "a")) {
|
||||
rnd_freqs = a_freqs;
|
||||
rnd_freqs_len = G_N_ELEMENTS(a_freqs) - 1;
|
||||
rnd_freqs = freqs_a;
|
||||
rnd_freqs_len = G_N_ELEMENTS(freqs_a) - 1;
|
||||
} else if (nm_streq0(band, "6GHz")) {
|
||||
rnd_freqs = freqs_6ghz;
|
||||
rnd_freqs_len = G_N_ELEMENTS(freqs_6ghz) - 1;
|
||||
} else {
|
||||
rnd_freqs = bg_freqs;
|
||||
rnd_freqs_len = G_N_ELEMENTS(bg_freqs) - 1;
|
||||
rnd_freqs = freqs_bg;
|
||||
rnd_freqs_len = G_N_ELEMENTS(freqs_bg) - 1;
|
||||
}
|
||||
|
||||
/* shuffle the frequencies (inplace). The idea is to choose
|
||||
|
|
|
|||
|
|
@ -574,16 +574,6 @@ nm_wifi_ap_to_string(const NMWifiAP *self, char *str_buf, gulong buf_len, gint64
|
|||
return str_buf;
|
||||
}
|
||||
|
||||
static guint
|
||||
freq_to_band(guint32 freq)
|
||||
{
|
||||
if (freq >= 4915 && freq <= 5825)
|
||||
return 5;
|
||||
else if (freq >= 2412 && freq <= 2484)
|
||||
return 2;
|
||||
return 0;
|
||||
}
|
||||
|
||||
gboolean
|
||||
nm_wifi_ap_check_compatible(NMWifiAP *self, NMConnection *connection)
|
||||
{
|
||||
|
|
@ -631,12 +621,12 @@ nm_wifi_ap_check_compatible(NMWifiAP *self, NMConnection *connection)
|
|||
|
||||
band = nm_setting_wireless_get_band(s_wireless);
|
||||
if (band) {
|
||||
guint ap_band = freq_to_band(priv->freq);
|
||||
const char *ap_band = nm_wifi_freq_to_band_prop(priv->freq);
|
||||
|
||||
if (!strcmp(band, "a") && ap_band != 5)
|
||||
return FALSE;
|
||||
else if (!strcmp(band, "bg") && ap_band != 2)
|
||||
if (!nm_streq(band, ap_band))
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
channel = nm_setting_wireless_get_channel(s_wireless);
|
||||
|
|
|
|||
|
|
@ -639,7 +639,7 @@ nm_wifi_utils_complete_connection(GBytes *ap_ssid,
|
|||
chan_valid = FALSE;
|
||||
}
|
||||
|
||||
band = nm_utils_wifi_freq_to_band(ap_freq);
|
||||
band = nm_wifi_freq_to_band_prop(ap_freq);
|
||||
if (band) {
|
||||
g_object_set(s_wifi, NM_SETTING_WIRELESS_BAND, band, NULL);
|
||||
} else {
|
||||
|
|
@ -1929,3 +1929,19 @@ nm_wifi_utils_wfd_info_eq(const NMIwdWfdInfo *a, const NMIwdWfdInfo *b)
|
|||
return a->source == b->source && a->sink == b->sink && a->port == b->port
|
||||
&& a->has_audio == b->has_audio && a->has_uibc == b->has_uibc && a->has_cp == b->has_cp;
|
||||
}
|
||||
|
||||
const char *
|
||||
nm_wifi_freq_to_band_prop(guint32 freq)
|
||||
{
|
||||
switch (nm_utils_wifi_freq_to_band(freq)) {
|
||||
case NM_WIFI_BAND_2_4_GHZ:
|
||||
return "bg";
|
||||
case NM_WIFI_BAND_5_GHZ:
|
||||
return "a";
|
||||
case NM_WIFI_BAND_6_GHZ:
|
||||
return "6GHz";
|
||||
default:
|
||||
case NM_WIFI_BAND_UNKNOWN:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -56,4 +56,6 @@ bool nm_wifi_utils_parse_wfd_ies(GBytes *ies, NMIwdWfdInfo *out_wfd);
|
|||
GBytes *nm_wifi_utils_build_wfd_ies(const NMIwdWfdInfo *wfd);
|
||||
bool nm_wifi_utils_wfd_info_eq(const NMIwdWfdInfo *a, const NMIwdWfdInfo *b);
|
||||
|
||||
const char *nm_wifi_freq_to_band_prop(guint32 freq);
|
||||
|
||||
#endif /* __NM_WIFI_UTILS_H__ */
|
||||
|
|
|
|||
|
|
@ -258,16 +258,7 @@ modm_handle_name_owner_changed(MMManager *modem_manager, GParamSpec *pspec, NMMo
|
|||
/* Available! */
|
||||
g_free(name_owner);
|
||||
|
||||
/* Hack alert: GDBusObjectManagerClient won't signal neither 'object-added'
|
||||
* nor 'object-removed' if it was created while there was no ModemManager in
|
||||
* the bus. This hack avoids this issue until we get a GIO with the fix
|
||||
* included... */
|
||||
modm_clear_manager(self);
|
||||
modm_ensure_manager(self);
|
||||
|
||||
/* Whenever GDBusObjectManagerClient is fixed, we can just do the following:
|
||||
* modm_manager_available (self);
|
||||
*/
|
||||
modm_manager_available(self);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
|
|||
|
|
@ -1460,7 +1460,9 @@ nm_dhcp_client_schedule_ipv6_only_restart(NMDhcpClient *self, guint timeout)
|
|||
nm_assert(!priv->is_stopped);
|
||||
|
||||
timeout = NM_MAX(priv->v4.ipv6_only_min_wait, timeout);
|
||||
_LOGI("received option \"ipv6-only-preferred\": stopping DHCPv4 for %u seconds", timeout);
|
||||
_LOGI("received option \"ipv6-only-preferred\": stopping DHCPv4 for %u seconds. Set "
|
||||
"ipv4.dhcp-ipv6-only-preferred=no to force the use of IPv4 on this IPv6-mostly network",
|
||||
timeout);
|
||||
|
||||
nm_dhcp_client_stop(self, FALSE);
|
||||
nm_clear_g_source_inst(&priv->no_lease_timeout_source);
|
||||
|
|
|
|||
|
|
@ -32,11 +32,11 @@ ip4_process_dhcpcd_rfc3442_routes(const char *iface,
|
|||
in_addr_t address,
|
||||
guint32 *out_gwaddr)
|
||||
{
|
||||
gs_free const char **routes = NULL;
|
||||
const char **r;
|
||||
gboolean have_routes = FALSE;
|
||||
gs_free char **routes = NULL;
|
||||
char **r;
|
||||
gboolean have_routes = FALSE;
|
||||
|
||||
routes = nm_strsplit_set(str, " ");
|
||||
routes = (char **) nm_strsplit_set(str, " ");
|
||||
if (!routes)
|
||||
return FALSE;
|
||||
|
||||
|
|
|
|||
|
|
@ -1510,8 +1510,8 @@ _domain_track_is_shadowed(GHashTable *ht,
|
|||
const char **out_parent,
|
||||
int *out_parent_priority)
|
||||
{
|
||||
char *parent;
|
||||
int parent_priority;
|
||||
const char *parent;
|
||||
int parent_priority;
|
||||
|
||||
if (!ht)
|
||||
return FALSE;
|
||||
|
|
|
|||
|
|
@ -461,14 +461,8 @@ main(int argc, char *argv[])
|
|||
/* the first access to State causes the file to be read (and possibly print a warning) */
|
||||
nm_config_state_get(config);
|
||||
|
||||
nm_log_dbg(LOGD_CORE,
|
||||
"WEXT support is %s",
|
||||
#if HAVE_WEXT
|
||||
"enabled"
|
||||
#else
|
||||
"disabled"
|
||||
#endif
|
||||
);
|
||||
nm_log_dbg(LOGD_CORE, "WEXT support is %s", HAVE_WEXT ? "enabled" : "disabled");
|
||||
nm_log_dbg(LOGD_CORE, "CLAT support is %s", HAVE_CLAT ? "enabled" : "disabled");
|
||||
|
||||
if (!_dbus_manager_init(config))
|
||||
goto done_no_manager;
|
||||
|
|
|
|||
|
|
@ -32,6 +32,15 @@ install_data(
|
|||
|
||||
core_plugins = []
|
||||
|
||||
subdir('bpf')
|
||||
|
||||
base_sources_addon = []
|
||||
base_deps_addon = []
|
||||
if enable_clat
|
||||
base_sources_addon += [clat_skel_h]
|
||||
base_deps_addon += [libbpf]
|
||||
endif
|
||||
|
||||
libNetworkManagerBase = static_library(
|
||||
'NetworkManagerBase',
|
||||
sources: files(
|
||||
|
|
@ -55,13 +64,13 @@ libNetworkManagerBase = static_library(
|
|||
'nm-l3cfg.c',
|
||||
'nm-bond-manager.c',
|
||||
'nm-ip-config.c',
|
||||
),
|
||||
) + base_sources_addon,
|
||||
dependencies: [
|
||||
core_default_dep,
|
||||
libnm_core_public_dep,
|
||||
libsystemd_dep,
|
||||
libudev_dep,
|
||||
],
|
||||
] + base_deps_addon,
|
||||
)
|
||||
|
||||
nm_deps = [
|
||||
|
|
|
|||
|
|
@ -401,6 +401,30 @@ receive_ra(struct ndp *ndp, struct ndp_msg *msg, gpointer user_data)
|
|||
}
|
||||
}
|
||||
|
||||
#if HAVE_CLAT
|
||||
/* PREF64 */
|
||||
ndp_msg_opt_for_each_offset (offset, msg, NDP_MSG_OPT_PREF64) {
|
||||
NMNDiscPref64 pref64;
|
||||
|
||||
pref64 = (NMNDiscPref64) {
|
||||
.prefix = *ndp_msg_opt_pref64_prefix(msg, offset),
|
||||
.plen = ndp_msg_opt_pref64_prefix_length(msg, offset),
|
||||
.gateway = gateway.address,
|
||||
.gateway_preference = gateway.preference,
|
||||
.expiry_msec =
|
||||
_nm_ndisc_lifetime_to_expiry(now_msec, ndp_msg_opt_pref64_lifetime(msg, offset)),
|
||||
.gateway_expiry_msec = gateway.expiry_msec,
|
||||
};
|
||||
|
||||
/* libndp should only return lengths defined in RFC 8781 */
|
||||
nm_assert(NM_IN_SET(pref64.plen, 96, 64, 56, 48, 40, 32));
|
||||
|
||||
if (nm_ndisc_add_pref64(ndisc, &pref64, now_msec)) {
|
||||
changed |= NM_NDISC_CONFIG_PREF64;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
nm_ndisc_ra_received(ndisc, now_msec, changed);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ struct _NMNDiscDataInternal {
|
|||
NMNDiscData public;
|
||||
GArray *gateways;
|
||||
GArray *addresses;
|
||||
GArray *pref64;
|
||||
GArray *routes;
|
||||
GArray *dns_servers;
|
||||
GArray *dns_domains;
|
||||
|
|
@ -28,6 +29,7 @@ gboolean nm_ndisc_add_gateway(NMNDisc *ndisc, const NMNDiscGateway *new_item, gi
|
|||
gboolean
|
||||
nm_ndisc_complete_and_add_address(NMNDisc *ndisc, const NMNDiscAddress *new_item, gint64 now_msec);
|
||||
gboolean nm_ndisc_add_route(NMNDisc *ndisc, const NMNDiscRoute *new_item, gint64 now_msec);
|
||||
gboolean nm_ndisc_add_pref64(NMNDisc *ndisc, const NMNDiscPref64 *new_item, gint64 now_msec);
|
||||
gboolean nm_ndisc_add_dns_server(NMNDisc *ndisc, const NMNDiscDNSServer *new_item, gint64 now_msec);
|
||||
gboolean nm_ndisc_add_dns_domain(NMNDisc *ndisc, const NMNDiscDNSDomain *new_item, gint64 now_msec);
|
||||
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@
|
|||
#define _SIZE_MAX_ROUTES 1000u
|
||||
#define _SIZE_MAX_DNS_SERVERS 64u
|
||||
#define _SIZE_MAX_DNS_DOMAINS 64u
|
||||
#define _SIZE_MAX_PREF64 8u
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
|
|
@ -109,7 +110,8 @@ nm_ndisc_data_to_l3cd(NMDedupMultiIndex *multi_idx,
|
|||
int ifindex,
|
||||
const NMNDiscData *rdata,
|
||||
NMSettingIP6ConfigPrivacy ip6_privacy,
|
||||
NMUtilsIPv6IfaceId *token)
|
||||
NMUtilsIPv6IfaceId *token,
|
||||
const char *network_id)
|
||||
{
|
||||
nm_auto_unref_l3cd_init NML3ConfigData *l3cd = NULL;
|
||||
guint32 ifa_flags;
|
||||
|
|
@ -211,13 +213,21 @@ nm_ndisc_data_to_l3cd(NMDedupMultiIndex *multi_idx,
|
|||
for (i = 0; i < rdata->dns_domains_n; i++)
|
||||
nm_l3_config_data_add_search(l3cd, AF_INET6, rdata->dns_domains[i].domain);
|
||||
|
||||
if (rdata->pref64_n > 0) {
|
||||
nm_l3_config_data_set_pref64(l3cd, rdata->pref64[0].prefix, rdata->pref64[0].plen);
|
||||
} else {
|
||||
nm_l3_config_data_set_pref64_valid(l3cd, FALSE);
|
||||
}
|
||||
|
||||
nm_l3_config_data_set_ndisc_hop_limit(l3cd, rdata->hop_limit);
|
||||
nm_l3_config_data_set_ndisc_reachable_time_msec(l3cd, rdata->reachable_time_ms);
|
||||
nm_l3_config_data_set_ndisc_retrans_timer_msec(l3cd, rdata->retrans_timer_ms);
|
||||
|
||||
nm_l3_config_data_set_ip6_mtu(l3cd, rdata->mtu);
|
||||
nm_l3_config_data_set_ip6_mtu_ra(l3cd, rdata->mtu);
|
||||
if (token)
|
||||
nm_l3_config_data_set_ip6_token(l3cd, *token);
|
||||
if (network_id)
|
||||
nm_l3_config_data_set_network_id(l3cd, network_id);
|
||||
|
||||
return g_steal_pointer(&l3cd);
|
||||
}
|
||||
|
|
@ -416,6 +426,7 @@ _data_complete(NMNDiscDataInternal *data)
|
|||
_SET(data, gateways);
|
||||
_SET(data, addresses);
|
||||
_SET(data, routes);
|
||||
_SET(data, pref64);
|
||||
_SET(data, dns_servers);
|
||||
_SET(data, dns_domains);
|
||||
#undef _SET
|
||||
|
|
@ -437,7 +448,8 @@ nm_ndisc_emit_config_change(NMNDisc *self, NMNDiscConfigMap changed)
|
|||
nm_l3cfg_get_ifindex(priv->config.l3cfg),
|
||||
rdata,
|
||||
priv->config.ip6_privacy,
|
||||
priv->iid_is_token ? &priv->iid : NULL);
|
||||
priv->iid_is_token ? &priv->iid : NULL,
|
||||
priv->config.network_id);
|
||||
l3cd = nm_l3_config_data_seal(l3cd);
|
||||
|
||||
if (!nm_l3_config_data_equal(priv->l3cd, l3cd))
|
||||
|
|
@ -760,6 +772,59 @@ nm_ndisc_add_route(NMNDisc *ndisc, const NMNDiscRoute *new_item, gint64 now_msec
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
nm_ndisc_add_pref64(NMNDisc *ndisc, const NMNDiscPref64 *new_item, gint64 now_msec)
|
||||
{
|
||||
NMNDiscDataInternal *rdata = &NM_NDISC_GET_PRIVATE(ndisc)->rdata;
|
||||
guint i;
|
||||
guint insert_idx = G_MAXUINT;
|
||||
|
||||
for (i = 0; i < rdata->pref64->len;) {
|
||||
NMNDiscPref64 *item = &nm_g_array_index(rdata->pref64, NMNDiscPref64, i);
|
||||
|
||||
if (item->plen == new_item->plen && IN6_ARE_ADDR_EQUAL(&item->prefix, &new_item->prefix)
|
||||
&& IN6_ARE_ADDR_EQUAL(&item->gateway, &new_item->gateway)) {
|
||||
if (new_item->expiry_msec <= now_msec) {
|
||||
g_array_remove_index(rdata->pref64, i);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (item->gateway_preference != new_item->gateway_preference) {
|
||||
g_array_remove_index(rdata->pref64, i);
|
||||
continue;
|
||||
}
|
||||
|
||||
item->gateway_expiry_msec = new_item->gateway_expiry_msec;
|
||||
|
||||
if (item->expiry_msec == new_item->expiry_msec)
|
||||
return FALSE;
|
||||
|
||||
item->expiry_msec = new_item->expiry_msec;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* Put before less preferable gateways. */
|
||||
if (_preference_to_priority(item->gateway_preference)
|
||||
< _preference_to_priority(new_item->gateway_preference)
|
||||
&& insert_idx == G_MAXUINT)
|
||||
insert_idx = i;
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
if (rdata->pref64->len >= _SIZE_MAX_PREF64)
|
||||
return FALSE;
|
||||
|
||||
if (new_item->expiry_msec <= now_msec)
|
||||
return FALSE;
|
||||
|
||||
g_array_insert_val(rdata->pref64,
|
||||
insert_idx == G_MAXUINT ? rdata->pref64->len : insert_idx,
|
||||
*new_item);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
nm_ndisc_add_dns_server(NMNDisc *ndisc, const NMNDiscDNSServer *new_item, gint64 now_msec)
|
||||
{
|
||||
|
|
@ -1400,6 +1465,17 @@ _config_changed_log(NMNDisc *ndisc, NMNDiscConfigMap changed)
|
|||
nm_icmpv6_router_pref_to_string(route->preference, str_pref, sizeof(str_pref)),
|
||||
get_exp(str_exp, now_msec, route));
|
||||
}
|
||||
for (i = 0; i < rdata->pref64->len; i++) {
|
||||
const NMNDiscPref64 *pref64 = &nm_g_array_index(rdata->pref64, NMNDiscPref64, i);
|
||||
char addrstr2[NM_INET_ADDRSTRLEN];
|
||||
|
||||
_LOGD(" pref64 %s/%u via %s exp %s",
|
||||
nm_inet6_ntop(&pref64->prefix, addrstr),
|
||||
pref64->plen,
|
||||
nm_inet6_ntop(&pref64->gateway, addrstr2),
|
||||
get_exp(str_exp, now_msec, pref64));
|
||||
}
|
||||
|
||||
for (i = 0; i < rdata->dns_servers->len; i++) {
|
||||
const NMNDiscDNSServer *dns_server =
|
||||
&nm_g_array_index(rdata->dns_servers, NMNDiscDNSServer, i);
|
||||
|
|
@ -1524,6 +1600,45 @@ clean_routes(NMNDisc *ndisc, gint64 now_msec, NMNDiscConfigMap *changed, gint64
|
|||
*changed |= NM_NDISC_CONFIG_ROUTES;
|
||||
}
|
||||
|
||||
static void
|
||||
clean_pref64(NMNDisc *ndisc, gint64 now_msec, NMNDiscConfigMap *changed, gint64 *next_msec)
|
||||
{
|
||||
NMNDiscDataInternal *rdata = &NM_NDISC_GET_PRIVATE(ndisc)->rdata;
|
||||
NMNDiscPref64 *arr;
|
||||
guint i;
|
||||
guint j;
|
||||
|
||||
if (rdata->pref64->len == 0)
|
||||
return;
|
||||
|
||||
arr = &nm_g_array_first(rdata->pref64, NMNDiscPref64);
|
||||
|
||||
for (i = 0, j = 0; i < rdata->pref64->len; i++) {
|
||||
if (!expiry_next(now_msec, arr[i].expiry_msec, next_msec)
|
||||
|| !expiry_next(now_msec,
|
||||
arr[i].gateway_expiry_msec,
|
||||
next_msec)) { /* no gateway no party */
|
||||
if (i == 0) {
|
||||
/* Emit the changed signal only when the first PREF64 expires,
|
||||
* because only the first item is exported into the l3cd. Changes
|
||||
* in other PREF64s are not relevant. */
|
||||
*changed |= NM_NDISC_CONFIG_PREF64;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (i != j)
|
||||
arr[j] = arr[i];
|
||||
j++;
|
||||
}
|
||||
|
||||
if (i != j) {
|
||||
g_array_set_size(rdata->pref64, j);
|
||||
}
|
||||
|
||||
_array_set_size_max(rdata->pref64, _SIZE_MAX_PREF64);
|
||||
}
|
||||
|
||||
static void
|
||||
clean_dns_servers(NMNDisc *ndisc, gint64 now_msec, NMNDiscConfigMap *changed, gint64 *next_msec)
|
||||
{
|
||||
|
|
@ -1600,6 +1715,7 @@ check_timestamps(NMNDisc *ndisc, gint64 now_msec, NMNDiscConfigMap changed)
|
|||
clean_gateways(ndisc, now_msec, &changed, &next_msec);
|
||||
clean_addresses(ndisc, now_msec, &changed, &next_msec);
|
||||
clean_routes(ndisc, now_msec, &changed, &next_msec);
|
||||
clean_pref64(ndisc, now_msec, &changed, &next_msec);
|
||||
clean_dns_servers(ndisc, now_msec, &changed, &next_msec);
|
||||
clean_dns_domains(ndisc, now_msec, &changed, &next_msec);
|
||||
|
||||
|
|
@ -1919,6 +2035,7 @@ nm_ndisc_init(NMNDisc *ndisc)
|
|||
rdata->gateways = g_array_new(FALSE, FALSE, sizeof(NMNDiscGateway));
|
||||
rdata->addresses = g_array_new(FALSE, FALSE, sizeof(NMNDiscAddress));
|
||||
rdata->routes = g_array_new(FALSE, FALSE, sizeof(NMNDiscRoute));
|
||||
rdata->pref64 = g_array_new(FALSE, FALSE, sizeof(NMNDiscPref64));
|
||||
rdata->dns_servers = g_array_new(FALSE, FALSE, sizeof(NMNDiscDNSServer));
|
||||
rdata->dns_domains = g_array_new(FALSE, FALSE, sizeof(NMNDiscDNSDomain));
|
||||
g_array_set_clear_func(rdata->dns_domains, dns_domain_free);
|
||||
|
|
@ -1951,6 +2068,7 @@ finalize(GObject *object)
|
|||
g_array_unref(rdata->gateways);
|
||||
g_array_unref(rdata->addresses);
|
||||
g_array_unref(rdata->routes);
|
||||
g_array_unref(rdata->pref64);
|
||||
g_array_unref(rdata->dns_servers);
|
||||
g_array_unref(rdata->dns_domains);
|
||||
|
||||
|
|
|
|||
|
|
@ -119,6 +119,15 @@ typedef struct _NMNDiscRoute {
|
|||
bool duplicate : 1;
|
||||
} NMNDiscRoute;
|
||||
|
||||
typedef struct _NMNDiscPref64 {
|
||||
struct in6_addr prefix;
|
||||
struct in6_addr gateway;
|
||||
gint64 expiry_msec;
|
||||
gint64 gateway_expiry_msec;
|
||||
NMIcmpv6RouterPref gateway_preference;
|
||||
guint8 plen;
|
||||
} NMNDiscPref64;
|
||||
|
||||
typedef struct {
|
||||
struct in6_addr address;
|
||||
gint64 expiry_msec;
|
||||
|
|
@ -141,6 +150,7 @@ typedef enum {
|
|||
NM_NDISC_CONFIG_MTU = 1 << 7,
|
||||
NM_NDISC_CONFIG_REACHABLE_TIME = 1 << 8,
|
||||
NM_NDISC_CONFIG_RETRANS_TIMER = 1 << 9,
|
||||
NM_NDISC_CONFIG_PREF64 = 1 << 10,
|
||||
} NMNDiscConfigMap;
|
||||
|
||||
typedef enum {
|
||||
|
|
@ -188,12 +198,14 @@ typedef struct {
|
|||
guint gateways_n;
|
||||
guint addresses_n;
|
||||
guint routes_n;
|
||||
guint pref64_n;
|
||||
guint dns_servers_n;
|
||||
guint dns_domains_n;
|
||||
|
||||
const NMNDiscGateway *gateways;
|
||||
const NMNDiscAddress *addresses;
|
||||
const NMNDiscRoute *routes;
|
||||
const NMNDiscPref64 *pref64;
|
||||
const NMNDiscDNSServer *dns_servers;
|
||||
const NMNDiscDNSDomain *dns_domains;
|
||||
} NMNDiscData;
|
||||
|
|
@ -282,6 +294,7 @@ struct _NML3ConfigData *nm_ndisc_data_to_l3cd(NMDedupMultiIndex *multi_id
|
|||
int ifindex,
|
||||
const NMNDiscData *rdata,
|
||||
NMSettingIP6ConfigPrivacy ip6_privacy,
|
||||
NMUtilsIPv6IfaceId *token);
|
||||
NMUtilsIPv6IfaceId *token,
|
||||
const char *network_id);
|
||||
|
||||
#endif /* __NETWORKMANAGER_NDISC_H__ */
|
||||
|
|
|
|||
|
|
@ -160,7 +160,7 @@ parse_connection_from_shadowed_file(const char *path, GError **error)
|
|||
{
|
||||
nm_auto_unref_keyfile GKeyFile *keyfile = NULL;
|
||||
gs_free char *base_dir = NULL;
|
||||
char *sep;
|
||||
const char *sep;
|
||||
|
||||
keyfile = g_key_file_new();
|
||||
if (!g_key_file_load_from_file(keyfile, path, G_KEY_FILE_NONE, error))
|
||||
|
|
|
|||
|
|
@ -892,6 +892,7 @@ static const ConfigGroup config_groups[] = {
|
|||
.is_prefix = TRUE,
|
||||
.keys = NM_MAKE_STRV(NM_CONFIG_KEYFILE_KEY_DEVICE_CARRIER_WAIT_TIMEOUT,
|
||||
NM_CONFIG_KEYFILE_KEY_DEVICE_IGNORE_CARRIER,
|
||||
NM_CONFIG_KEYFILE_KEY_DEVICE_CHECK_CONNECTIVITY,
|
||||
NM_CONFIG_KEYFILE_KEY_DEVICE_MANAGED,
|
||||
NM_CONFIG_KEYFILE_KEY_DEVICE_SRIOV_NUM_VFS,
|
||||
NM_CONFIG_KEYFILE_KEY_DEVICE_KEEP_CONFIGURATION,
|
||||
|
|
|
|||
|
|
@ -21,6 +21,10 @@
|
|||
#include <linux/if_infiniband.h>
|
||||
#include <net/if_arp.h>
|
||||
#include <net/ethernet.h>
|
||||
#include <netinet/ip_icmp.h>
|
||||
#include <netinet/icmp6.h>
|
||||
#include <netinet/ip6.h>
|
||||
#include <linux/if_packet.h>
|
||||
|
||||
#include "libnm-glib-aux/nm-uuid.h"
|
||||
#include "libnm-platform/nmp-base.h"
|
||||
|
|
@ -5002,6 +5006,469 @@ NM_UTILS_LOOKUP_STR_DEFINE(nm_activation_type_to_string,
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
typedef struct {
|
||||
NMIPAddrTyped address;
|
||||
char *addr_str;
|
||||
GTask *task;
|
||||
GSource *timeout_source;
|
||||
GSource *retry_source;
|
||||
GSource *input_source;
|
||||
gulong cancellable_id;
|
||||
int ifindex;
|
||||
int socket;
|
||||
guint16 seq;
|
||||
} PingInfo;
|
||||
|
||||
#define _NMLOG2_PREFIX_NAME "ping"
|
||||
#define _NMLOG2_DOMAIN LOGD_CORE
|
||||
#define _NMLOG2(level, info, ...) \
|
||||
G_STMT_START \
|
||||
{ \
|
||||
if (nm_logging_enabled((level), (_NMLOG2_DOMAIN))) { \
|
||||
PingInfo *_info = (info); \
|
||||
\
|
||||
_nm_log((level), \
|
||||
(_NMLOG2_DOMAIN), \
|
||||
0, \
|
||||
NULL, \
|
||||
NULL, \
|
||||
_NMLOG2_PREFIX_NAME "[" NM_HASH_OBFUSCATE_PTR_FMT \
|
||||
",if=%d,%s]: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \
|
||||
NM_HASH_OBFUSCATE_PTR(_info), \
|
||||
_info->ifindex, \
|
||||
_info->addr_str _NM_UTILS_MACRO_REST(__VA_ARGS__)); \
|
||||
} \
|
||||
} \
|
||||
G_STMT_END
|
||||
|
||||
static void
|
||||
ping_complete(PingInfo *info, GError *error)
|
||||
{
|
||||
nm_clear_g_cancellable_disconnect(g_task_get_cancellable(info->task), &info->cancellable_id);
|
||||
|
||||
if (error && !nm_utils_error_is_cancelled(error)) {
|
||||
_LOG2T(info, "terminated with error: %s", error->message);
|
||||
}
|
||||
|
||||
if (error)
|
||||
g_task_return_error(info->task, error);
|
||||
else
|
||||
g_task_return_boolean(info->task, TRUE);
|
||||
|
||||
nm_clear_g_source_inst(&info->timeout_source);
|
||||
nm_clear_g_source_inst(&info->retry_source);
|
||||
nm_clear_g_source_inst(&info->input_source);
|
||||
nm_clear_g_free(&info->addr_str);
|
||||
nm_clear_fd(&info->socket);
|
||||
g_object_unref(info->task);
|
||||
|
||||
g_free(info);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
ping_socket_data_cb(int fd, GIOCondition condition, gpointer user_data)
|
||||
{
|
||||
PingInfo *info = user_data;
|
||||
ssize_t len;
|
||||
union {
|
||||
struct icmphdr icmph;
|
||||
struct icmp6_hdr icmp6h;
|
||||
} pkt;
|
||||
|
||||
len = recv(fd, &pkt, sizeof(pkt), 0);
|
||||
|
||||
if (len < 0)
|
||||
return G_SOURCE_CONTINUE;
|
||||
|
||||
if (info->address.addr_family == AF_INET) {
|
||||
if (len >= sizeof(struct icmphdr) && pkt.icmph.type == ICMP_ECHOREPLY) {
|
||||
_LOG2T(info, "received echo-reply with seq %hu", ntohs(pkt.icmph.un.echo.sequence));
|
||||
ping_complete(info, NULL);
|
||||
return G_SOURCE_CONTINUE;
|
||||
}
|
||||
} else {
|
||||
if (len >= sizeof(struct icmp6_hdr) && pkt.icmp6h.icmp6_type == ICMP6_ECHO_REPLY) {
|
||||
_LOG2T(info, "received echo-reply with seq %hu", ntohs(pkt.icmp6h.icmp6_seq));
|
||||
ping_complete(info, NULL);
|
||||
return G_SOURCE_CONTINUE;
|
||||
}
|
||||
}
|
||||
|
||||
return G_SOURCE_CONTINUE;
|
||||
}
|
||||
|
||||
static void
|
||||
ping_send(PingInfo *info)
|
||||
{
|
||||
const bool IS_IPv4 = NM_IS_IPv4(info->address.addr_family);
|
||||
union {
|
||||
struct sockaddr_in6 sa6;
|
||||
struct sockaddr_in sa4;
|
||||
} sa;
|
||||
union {
|
||||
struct icmphdr icmph;
|
||||
struct icmp6_hdr icmp6h;
|
||||
} pkt;
|
||||
socklen_t sa_len;
|
||||
size_t pkt_len;
|
||||
nm_be32_t ifindex_be;
|
||||
int errsv;
|
||||
|
||||
info->seq++;
|
||||
|
||||
if (info->socket < 0) {
|
||||
info->socket = socket(info->address.addr_family,
|
||||
SOCK_DGRAM | SOCK_CLOEXEC,
|
||||
IS_IPv4 ? IPPROTO_ICMP : IPPROTO_ICMPV6);
|
||||
if (info->socket < 0) {
|
||||
errsv = errno;
|
||||
_LOG2T(info, "socket creation failed: %s", nm_strerror_native(errsv));
|
||||
/* Try again at the next iteration */
|
||||
return;
|
||||
}
|
||||
|
||||
memset(&sa, 0, sizeof(sa));
|
||||
if (IS_IPv4) {
|
||||
sa.sa4.sin_family = AF_INET;
|
||||
sa.sa4.sin_addr.s_addr = info->address.addr.addr4;
|
||||
sa_len = sizeof(struct sockaddr_in);
|
||||
} else {
|
||||
sa.sa6.sin6_family = AF_INET6;
|
||||
sa.sa6.sin6_addr = info->address.addr.addr6;
|
||||
if (IN6_IS_ADDR_LINKLOCAL(&info->address.addr.addr6))
|
||||
sa.sa6.sin6_scope_id = info->ifindex;
|
||||
sa_len = sizeof(struct sockaddr_in6);
|
||||
}
|
||||
|
||||
/* setsockopt(IP*_UNICAST_IF) must be called *before* connecting
|
||||
* the socket, otherwise it doesn't have any effect */
|
||||
ifindex_be = htonl(info->ifindex);
|
||||
if (setsockopt(info->socket,
|
||||
IS_IPv4 ? IPPROTO_IP : IPPROTO_IPV6,
|
||||
IS_IPv4 ? IP_UNICAST_IF : IPV6_UNICAST_IF,
|
||||
&ifindex_be,
|
||||
sizeof(ifindex_be))) {
|
||||
errsv = errno;
|
||||
_LOG2T(info,
|
||||
"failed to bind the socket to the interface: %s",
|
||||
nm_strerror_native(errsv));
|
||||
/* Try again at the next iteration */
|
||||
nm_clear_fd(&info->socket);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Connect the socket so that the kernel only delivers us packets
|
||||
* coming from the given remote address */
|
||||
if (connect(info->socket, (struct sockaddr *) &sa, sa_len) < 0) {
|
||||
errsv = errno;
|
||||
_LOG2T(info, "failed to connect the socket: %s", nm_strerror_native(errsv));
|
||||
/* try again at the next iteration */
|
||||
nm_clear_fd(&info->socket);
|
||||
return;
|
||||
}
|
||||
|
||||
info->input_source = nm_g_unix_fd_source_new(info->socket,
|
||||
G_IO_IN,
|
||||
G_PRIORITY_DEFAULT,
|
||||
ping_socket_data_cb,
|
||||
info,
|
||||
NULL);
|
||||
g_source_attach(info->input_source, g_task_get_context(info->task));
|
||||
}
|
||||
|
||||
if (IS_IPv4) {
|
||||
memset(&pkt.icmph, 0, sizeof(struct icmphdr));
|
||||
pkt.icmph.type = ICMP_ECHO;
|
||||
pkt.icmph.un.echo.sequence = htons(info->seq);
|
||||
pkt_len = sizeof(struct icmphdr);
|
||||
} else {
|
||||
memset(&pkt.icmp6h, 0, sizeof(struct icmp6_hdr));
|
||||
pkt.icmp6h.icmp6_type = ICMP6_ECHO_REQUEST;
|
||||
pkt.icmp6h.icmp6_seq = htons(info->seq);
|
||||
pkt_len = sizeof(struct icmp6_hdr);
|
||||
}
|
||||
/* The kernel will automatically set the ID ICMP field and filter
|
||||
* incoming packets by the same ID */
|
||||
|
||||
if (send(info->socket, &pkt, pkt_len, 0) < 0) {
|
||||
errsv = errno;
|
||||
_LOG2T(info, "error sending echo-request #%u: %s", info->seq, nm_strerror_native(errsv));
|
||||
return;
|
||||
}
|
||||
|
||||
_LOG2T(info, "sent echo-request #%u", info->seq);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
ping_timeout_cb(gpointer user_data)
|
||||
{
|
||||
PingInfo *info = user_data;
|
||||
|
||||
_LOG2T(info, "timeout");
|
||||
|
||||
nm_clear_g_source_inst(&info->timeout_source);
|
||||
ping_complete(info, g_error_new_literal(NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN, "timeout"));
|
||||
|
||||
return G_SOURCE_CONTINUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
ping_retry_cb(gpointer user_data)
|
||||
{
|
||||
PingInfo *info = user_data;
|
||||
|
||||
ping_send(info);
|
||||
|
||||
return G_SOURCE_CONTINUE;
|
||||
}
|
||||
|
||||
static void
|
||||
ping_cancelled(GObject *object, gpointer user_data)
|
||||
{
|
||||
PingInfo *info = user_data;
|
||||
GError *error = NULL;
|
||||
|
||||
nm_clear_g_signal_handler(g_task_get_cancellable(info->task), &info->cancellable_id);
|
||||
nm_utils_error_set_cancelled(&error, FALSE, NULL);
|
||||
ping_complete(info, error);
|
||||
}
|
||||
|
||||
void
|
||||
nm_utils_ping_host(NMIPAddrTyped address,
|
||||
int ifindex,
|
||||
guint timeout_sec,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer cb_data)
|
||||
{
|
||||
PingInfo *info;
|
||||
char buf[NM_INET_ADDRSTRLEN];
|
||||
gulong signal_id;
|
||||
|
||||
nm_assert(ifindex > 0);
|
||||
nm_assert(G_IS_CANCELLABLE(cancellable));
|
||||
nm_assert(callback);
|
||||
nm_assert(cb_data);
|
||||
|
||||
info = g_new0(PingInfo, 1);
|
||||
info->address = address;
|
||||
info->ifindex = ifindex;
|
||||
info->task = nm_g_task_new(NULL, cancellable, nm_utils_ping_host, callback, cb_data);
|
||||
info->socket = -1;
|
||||
|
||||
nm_inet_ntop(address.addr_family, address.addr.addr_ptr, buf);
|
||||
info->addr_str = g_strdup(buf);
|
||||
|
||||
_LOG2T(info, "started");
|
||||
|
||||
if (timeout_sec > 0) {
|
||||
info->timeout_source = nm_g_timeout_source_new_seconds(timeout_sec,
|
||||
G_PRIORITY_DEFAULT,
|
||||
ping_timeout_cb,
|
||||
info,
|
||||
NULL);
|
||||
g_source_attach(info->timeout_source, g_task_get_context(info->task));
|
||||
}
|
||||
|
||||
info->retry_source =
|
||||
nm_g_timeout_source_new_seconds(1, G_PRIORITY_DEFAULT, ping_retry_cb, info, NULL);
|
||||
g_source_attach(info->retry_source, g_task_get_context(info->task));
|
||||
|
||||
signal_id = g_cancellable_connect(cancellable, G_CALLBACK(ping_cancelled), info, NULL);
|
||||
if (signal_id == 0) {
|
||||
/* the callback was invoked synchronously, which destroyed @info.
|
||||
* We must not touch it anymore. */
|
||||
return;
|
||||
}
|
||||
info->cancellable_id = signal_id;
|
||||
|
||||
ping_send(info);
|
||||
}
|
||||
|
||||
gboolean
|
||||
nm_utils_ping_host_finish(GAsyncResult *result, GError **error)
|
||||
{
|
||||
GTask *task = G_TASK(result);
|
||||
|
||||
nm_assert(nm_g_task_is_valid(result, NULL, nm_utils_ping_host));
|
||||
|
||||
return g_task_propagate_boolean(task, error);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/*
|
||||
* nm_utils_icmp6_checksum:
|
||||
* @ip6_src: pointer to the IPv6 source address
|
||||
* @data_len: length of the data
|
||||
* @data: the data on which to compute the checksum
|
||||
*
|
||||
* Computes the ICMP6 checksum over @data (with length @data_len) and the IPv6
|
||||
* pseudo-header. @ip6_src points to the source address in the IPv6 header.
|
||||
*/
|
||||
uint16_t
|
||||
nm_utils_icmp6_checksum(const void *ip6_src, size_t data_len, const void *data)
|
||||
{
|
||||
uint32_t sum = 0;
|
||||
const uint16_t *ptr;
|
||||
const uint8_t *ptr8;
|
||||
size_t i;
|
||||
|
||||
/* Pseudo-header: source address */
|
||||
ptr = (const uint16_t *) ip6_src;
|
||||
for (i = 0; i < 8; i++)
|
||||
sum += *ptr++;
|
||||
|
||||
/* Pseudo-header: destination address */
|
||||
for (i = 0; i < 8; i++)
|
||||
sum += *ptr++;
|
||||
|
||||
/* Pseudo-header: payload length */
|
||||
sum += htons(data_len);
|
||||
|
||||
/* Pseudo-header: next header */
|
||||
sum += htons(IPPROTO_ICMPV6);
|
||||
|
||||
/* ICMPv6 data */
|
||||
ptr = (const uint16_t *) data;
|
||||
for (i = 0; i < data_len / 2; i++)
|
||||
sum += ptr[i];
|
||||
|
||||
/* Handle odd byte */
|
||||
if (data_len % 2) {
|
||||
ptr8 = &((const uint8_t *) data)[data_len - 1];
|
||||
sum += htons((guint16) (*ptr8) << 8);
|
||||
}
|
||||
|
||||
/* Fold 32-bit sum to 16 bits */
|
||||
while (sum >> 16)
|
||||
sum = (sum & 0xffff) + (sum >> 16);
|
||||
|
||||
return (uint16_t) ~sum;
|
||||
}
|
||||
|
||||
/*
|
||||
* nm_utils_ipv6_dad_send:
|
||||
* @addr: the target IPv6 address
|
||||
* @ifindex: the interface index
|
||||
* @arptype: the ARP hardware type of the interface (e.g. ARPHRD_ETHER, ARPHRD_NONE)
|
||||
*
|
||||
* Send an IPv6 Duplicate Address Detection (DAD) Neighbor Solicitation
|
||||
* for the given address.
|
||||
*
|
||||
* Returns: %TRUE if the packet was sent successfully, %FALSE on error
|
||||
*/
|
||||
gboolean
|
||||
nm_utils_ipv6_dad_send(const struct in6_addr *addr, int ifindex, int arptype)
|
||||
{
|
||||
/* DAD packet: IPv6 header + ICMPv6 NS + nonce option (RFC 3971) */
|
||||
struct _nm_packed {
|
||||
struct ip6_hdr ip6h;
|
||||
struct nd_neighbor_solicit ns;
|
||||
guint8 ns_opt_nr;
|
||||
guint8 ns_opt_len;
|
||||
guint8 ns_opt_nonce[6];
|
||||
} dad_pkt;
|
||||
nm_auto_close int fd = -1;
|
||||
int errsv;
|
||||
char sbuf[NM_INET_ADDRSTRLEN];
|
||||
|
||||
nm_assert(addr);
|
||||
nm_assert(ifindex > 0);
|
||||
|
||||
/* IPv6 header */
|
||||
dad_pkt.ip6h = (struct ip6_hdr) {
|
||||
.ip6_flow = htonl(6 << 28), /* version 6, tclass 0, flowlabel 0 */
|
||||
.ip6_plen = htons(sizeof(dad_pkt) - sizeof(struct ip6_hdr)),
|
||||
.ip6_nxt = IPPROTO_ICMPV6,
|
||||
.ip6_hlim = 255,
|
||||
.ip6_src = IN6ADDR_ANY_INIT,
|
||||
.ip6_dst.s6_addr = {0xff,
|
||||
0x02,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0x01,
|
||||
0xff,
|
||||
addr->s6_addr[13],
|
||||
addr->s6_addr[14],
|
||||
addr->s6_addr[15]},
|
||||
};
|
||||
|
||||
/* ICMPv6 Neighbor Solicitation */
|
||||
dad_pkt.ns = (struct nd_neighbor_solicit) {
|
||||
.nd_ns_type = ND_NEIGHBOR_SOLICIT,
|
||||
.nd_ns_target = *addr,
|
||||
};
|
||||
|
||||
/* Nonce option (RFC 3971) */
|
||||
dad_pkt.ns_opt_nr = 14;
|
||||
dad_pkt.ns_opt_len = 1; /* in units of 8 bytes */
|
||||
nm_random_get_bytes(dad_pkt.ns_opt_nonce, sizeof(dad_pkt.ns_opt_nonce));
|
||||
|
||||
/* Compute the ICMPv6 checksum */
|
||||
dad_pkt.ns.nd_ns_cksum = nm_utils_icmp6_checksum(&dad_pkt.ip6h.ip6_src,
|
||||
sizeof(dad_pkt) - sizeof(struct ip6_hdr),
|
||||
&dad_pkt.ns);
|
||||
|
||||
/* We need a ETH_P_IPV6 socket because we need to use a zero IPv6 source address */
|
||||
fd = socket(AF_PACKET, SOCK_DGRAM | SOCK_CLOEXEC, htons(ETH_P_IPV6));
|
||||
if (fd < 0) {
|
||||
errsv = errno;
|
||||
nm_log_warn(LOGD_CORE,
|
||||
"ipv6-dad: failed to create socket for %s: %s",
|
||||
nm_inet6_ntop(addr, sbuf),
|
||||
nm_strerror_native(errsv));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Build link-layer destination address. For Ethernet, use the solicited-node
|
||||
* multicast MAC address. For L3-only devices (ARPHRD_NONE, ARPHRD_RAWIP, etc.)
|
||||
* there is no L2 header, so set sll_halen to 0. */
|
||||
{
|
||||
struct sockaddr_ll dst_ll = {
|
||||
.sll_family = AF_PACKET,
|
||||
.sll_protocol = htons(ETH_P_IPV6),
|
||||
.sll_ifindex = ifindex,
|
||||
};
|
||||
|
||||
if (arptype == ARPHRD_ETHER) {
|
||||
dst_ll.sll_halen = ETH_ALEN;
|
||||
dst_ll.sll_addr[0] = 0x33;
|
||||
dst_ll.sll_addr[1] = 0x33;
|
||||
dst_ll.sll_addr[2] = 0xff;
|
||||
dst_ll.sll_addr[3] = addr->s6_addr[13];
|
||||
dst_ll.sll_addr[4] = addr->s6_addr[14];
|
||||
dst_ll.sll_addr[5] = addr->s6_addr[15];
|
||||
}
|
||||
|
||||
if (sendto(fd, &dad_pkt, sizeof(dad_pkt), 0, (struct sockaddr *) &dst_ll, sizeof(dst_ll))
|
||||
< 0) {
|
||||
errsv = errno;
|
||||
nm_log_warn(LOGD_CORE,
|
||||
"ipv6-dad: failed to send DAD NS for %s: %s",
|
||||
nm_inet6_ntop(addr, sbuf),
|
||||
nm_strerror_native(errsv));
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
nm_log_dbg(LOGD_CORE,
|
||||
"ipv6-dad: sent DAD NS for %s on ifindex %d",
|
||||
nm_inet6_ntop(addr, sbuf),
|
||||
ifindex);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
typedef struct {
|
||||
GPid pid;
|
||||
GTask *task;
|
||||
|
|
@ -5023,6 +5490,9 @@ typedef struct {
|
|||
gsize out_buffer_offset;
|
||||
} HelperInfo;
|
||||
|
||||
#undef _NMLOG2_PREFIX_NAME
|
||||
#undef _NMLOG2_DOMAIN
|
||||
#undef _NMLOG2
|
||||
#define _NMLOG2_PREFIX_NAME "nm-daemon-helper"
|
||||
#define _NMLOG2_DOMAIN LOGD_CORE
|
||||
#define _NMLOG2(level, info, ...) \
|
||||
|
|
|
|||
|
|
@ -304,6 +304,7 @@ typedef enum {
|
|||
NM_UTILS_STABLE_TYPE_STABLE_ID = 1,
|
||||
NM_UTILS_STABLE_TYPE_GENERATED = 2,
|
||||
NM_UTILS_STABLE_TYPE_RANDOM = 3,
|
||||
NM_UTILS_STABLE_TYPE_CLAT = 4,
|
||||
} NMUtilsStableType;
|
||||
|
||||
#define NM_UTILS_STABLE_TYPE_NONE ((NMUtilsStableType) - 1)
|
||||
|
|
@ -520,4 +521,19 @@ void nm_utils_read_private_files(const char *const *paths,
|
|||
gpointer cb_data);
|
||||
GHashTable *nm_utils_read_private_files_finish(GAsyncResult *result, GError **error);
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
void nm_utils_ping_host(NMIPAddrTyped address,
|
||||
int ifindex,
|
||||
guint timeout_sec,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer cb_data);
|
||||
|
||||
gboolean nm_utils_ping_host_finish(GAsyncResult *result, GError **error);
|
||||
|
||||
uint16_t nm_utils_icmp6_checksum(const void *ip6_src, size_t data_len, const void *data);
|
||||
|
||||
gboolean nm_utils_ipv6_dad_send(const struct in6_addr *addr, int ifindex, int arptype);
|
||||
|
||||
#endif /* __NM_CORE_UTILS_H__ */
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ GType nm_ip6_config_get_type(void);
|
|||
/*****************************************************************************/
|
||||
|
||||
#define NM_IP_CONFIG_ADDRESS_DATA "address-data"
|
||||
#define NM_IP_CONFIG_CLAT_ADDRESS "clat-address"
|
||||
#define NM_IP_CONFIG_DNS_OPTIONS "dns-options"
|
||||
#define NM_IP_CONFIG_DNS_PRIORITY "dns-priority"
|
||||
#define NM_IP_CONFIG_DOMAINS "domains"
|
||||
|
|
@ -41,6 +42,7 @@ NM_GOBJECT_PROPERTIES_DEFINE_FULL(_ip,
|
|||
NMIPConfig,
|
||||
PROP_IP_L3CFG,
|
||||
PROP_IP_ADDRESS_DATA,
|
||||
PROP_IP_CLAT_ADDRESS,
|
||||
PROP_IP_GATEWAY,
|
||||
PROP_IP_ROUTE_DATA,
|
||||
PROP_IP_DOMAINS,
|
||||
|
|
@ -164,6 +166,8 @@ get_property_ip(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec
|
|||
const int addr_family = nm_ip_config_get_addr_family(self);
|
||||
char **to_free = NULL;
|
||||
char sbuf_addr[NM_INET_ADDRSTRLEN];
|
||||
in_addr_t addr4;
|
||||
struct in6_addr addr6;
|
||||
const char *const *strv;
|
||||
guint len;
|
||||
int v_i;
|
||||
|
|
@ -218,6 +222,20 @@ get_property_ip(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec
|
|||
strv = nm_l3_config_data_get_dns_options(priv->l3cd, addr_family, &len);
|
||||
_value_set_variant_as(value, strv, len);
|
||||
break;
|
||||
case PROP_IP_CLAT_ADDRESS:
|
||||
if (nm_l3_config_data_get_clat_state(priv->l3cd, &addr6, NULL, NULL, &addr4)) {
|
||||
if (addr_family == AF_INET) {
|
||||
g_value_set_variant(value,
|
||||
g_variant_new_string(nm_inet_ntop(AF_INET, &addr4, sbuf_addr)));
|
||||
} else {
|
||||
g_value_set_variant(
|
||||
value,
|
||||
g_variant_new_string(nm_inet_ntop(AF_INET6, &addr6, sbuf_addr)));
|
||||
}
|
||||
} else {
|
||||
g_value_set_variant(value, nm_g_variant_singleton_s_empty());
|
||||
}
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
|
||||
break;
|
||||
|
|
@ -336,6 +354,13 @@ nm_ip_config_class_init(NMIPConfigClass *klass)
|
|||
G_VARIANT_TYPE("aa{sv}"),
|
||||
NULL,
|
||||
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
|
||||
obj_properties_ip[PROP_IP_CLAT_ADDRESS] =
|
||||
g_param_spec_variant(NM_IP_CONFIG_CLAT_ADDRESS,
|
||||
"",
|
||||
"",
|
||||
G_VARIANT_TYPE("s"),
|
||||
NULL,
|
||||
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
|
||||
obj_properties_ip[PROP_IP_GATEWAY] =
|
||||
g_param_spec_variant(NM_IP_CONFIG_GATEWAY,
|
||||
"",
|
||||
|
|
@ -512,6 +537,9 @@ static const NMDBusInterfaceInfoExtended interface_info_ip4_config = {
|
|||
NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("AddressData",
|
||||
"aa{sv}",
|
||||
NM_IP_CONFIG_ADDRESS_DATA),
|
||||
NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("ClatAddress",
|
||||
"s",
|
||||
NM_IP_CONFIG_CLAT_ADDRESS),
|
||||
NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Gateway", "s", NM_IP_CONFIG_GATEWAY),
|
||||
NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE(
|
||||
"Routes",
|
||||
|
|
@ -614,6 +642,7 @@ nm_ip4_config_class_init(NMIP4ConfigClass *klass)
|
|||
/*****************************************************************************/
|
||||
|
||||
/* public */
|
||||
#define NM_IP6_CONFIG_CLAT_PREF64 "clat-pref64"
|
||||
#define NM_IP6_CONFIG_NAMESERVERS "nameservers"
|
||||
|
||||
/* deprecated */
|
||||
|
|
@ -625,6 +654,7 @@ typedef struct _NMIP6ConfigClass NMIP6ConfigClass;
|
|||
|
||||
NM_GOBJECT_PROPERTIES_DEFINE_FULL(_ip6,
|
||||
NMIP6Config,
|
||||
PROP_IP6_CLAT_PREF64,
|
||||
PROP_IP6_NAMESERVERS,
|
||||
PROP_IP6_ADDRESSES,
|
||||
PROP_IP6_ROUTES, );
|
||||
|
|
@ -651,6 +681,12 @@ static const NMDBusInterfaceInfoExtended interface_info_ip6_config = {
|
|||
NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("AddressData",
|
||||
"aa{sv}",
|
||||
NM_IP_CONFIG_ADDRESS_DATA),
|
||||
NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("ClatAddress",
|
||||
"s",
|
||||
NM_IP_CONFIG_CLAT_ADDRESS),
|
||||
NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("ClatPref64",
|
||||
"s",
|
||||
NM_IP6_CONFIG_CLAT_PREF64),
|
||||
NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Gateway", "s", NM_IP_CONFIG_GATEWAY),
|
||||
NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE(
|
||||
"Routes",
|
||||
|
|
@ -682,11 +718,24 @@ get_property_ip6(GObject *object, guint prop_id, GValue *value, GParamSpec *pspe
|
|||
guint len;
|
||||
guint i;
|
||||
const char *const *strarr;
|
||||
guint8 plen;
|
||||
struct in6_addr addr6;
|
||||
char sbuf[NM_UTILS_INET_ADDRSTRLEN];
|
||||
|
||||
switch (prop_id) {
|
||||
case PROP_IP6_ADDRESSES:
|
||||
g_value_set_variant(value, priv->v_addresses);
|
||||
break;
|
||||
case PROP_IP6_CLAT_PREF64:
|
||||
if (nm_l3_config_data_get_clat_state(priv->l3cd, NULL, &addr6, &plen, NULL)) {
|
||||
nm_inet6_ntop(&addr6, sbuf);
|
||||
g_value_set_variant(value,
|
||||
g_variant_new_string(
|
||||
nm_sprintf_bufa(NM_INET_ADDRSTRLEN + 32, "%s/%u", sbuf, plen)));
|
||||
} else {
|
||||
g_value_set_variant(value, nm_g_variant_singleton_s_empty());
|
||||
}
|
||||
break;
|
||||
case PROP_IP6_ROUTES:
|
||||
g_value_set_variant(value, priv->v_routes);
|
||||
break;
|
||||
|
|
@ -740,6 +789,13 @@ nm_ip6_config_class_init(NMIP6ConfigClass *klass)
|
|||
G_VARIANT_TYPE("a(ayuay)"),
|
||||
NULL,
|
||||
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
|
||||
obj_properties_ip6[PROP_IP6_CLAT_PREF64] =
|
||||
g_param_spec_variant(NM_IP6_CONFIG_CLAT_PREF64,
|
||||
"",
|
||||
"",
|
||||
G_VARIANT_TYPE("s"),
|
||||
NULL,
|
||||
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
|
||||
obj_properties_ip6[PROP_IP6_ROUTES] =
|
||||
g_param_spec_variant(NM_IP6_CONFIG_ROUTES,
|
||||
"",
|
||||
|
|
@ -787,7 +843,7 @@ _handle_l3cd_changed(NMIPConfig *self, const NML3ConfigData *l3cd)
|
|||
const int IS_IPv4 = NM_IS_IPv4(addr_family);
|
||||
NMIPConfigPrivate *priv = NM_IP_CONFIG_GET_PRIVATE(self);
|
||||
nm_auto_unref_l3cd const NML3ConfigData *l3cd_old = NULL;
|
||||
GParamSpec *changed_params[8];
|
||||
GParamSpec *changed_params[10];
|
||||
guint n_changed_params = 0;
|
||||
const char *const *strarr;
|
||||
const char *const *strarr_old;
|
||||
|
|
@ -840,6 +896,59 @@ _handle_l3cd_changed(NMIPConfig *self, const NML3ConfigData *l3cd)
|
|||
}
|
||||
}
|
||||
|
||||
/* CLAT state */
|
||||
{
|
||||
struct in6_addr clat_ip6;
|
||||
struct in6_addr clat_pref64;
|
||||
guint8 clat_pref64_plen;
|
||||
in_addr_t clat_ip4;
|
||||
gboolean clat_enabled;
|
||||
struct in6_addr clat_ip6_old;
|
||||
struct in6_addr clat_pref64_old;
|
||||
guint8 clat_pref64_plen_old;
|
||||
in_addr_t clat_ip4_old;
|
||||
gboolean clat_enabled_old;
|
||||
gboolean changed;
|
||||
|
||||
clat_enabled_old = nm_l3_config_data_get_clat_state(l3cd_old,
|
||||
&clat_ip6_old,
|
||||
&clat_pref64_old,
|
||||
&clat_pref64_plen_old,
|
||||
&clat_ip4_old);
|
||||
clat_enabled = nm_l3_config_data_get_clat_state(priv->l3cd,
|
||||
&clat_ip6,
|
||||
&clat_pref64,
|
||||
&clat_pref64_plen,
|
||||
&clat_ip4);
|
||||
|
||||
/* CLAT address */
|
||||
if (clat_enabled != clat_enabled_old) {
|
||||
changed = TRUE;
|
||||
} else if (!clat_enabled) {
|
||||
changed = FALSE;
|
||||
} else if (IS_IPv4) {
|
||||
changed = (clat_ip4 != clat_ip4_old);
|
||||
} else {
|
||||
changed = !IN6_ARE_ADDR_EQUAL(&clat_ip6, &clat_ip6_old);
|
||||
}
|
||||
if (changed)
|
||||
changed_params[n_changed_params++] = obj_properties_ip[PROP_IP_CLAT_ADDRESS];
|
||||
|
||||
/* PREF64 */
|
||||
if (!IS_IPv4) {
|
||||
if (clat_enabled != clat_enabled_old) {
|
||||
changed = TRUE;
|
||||
} else if (!clat_enabled) {
|
||||
changed = FALSE;
|
||||
} else {
|
||||
changed = (clat_pref64_plen != clat_pref64_plen_old)
|
||||
|| (!IN6_ARE_ADDR_EQUAL(&clat_pref64, &clat_pref64_old));
|
||||
}
|
||||
if (changed)
|
||||
changed_params[n_changed_params++] = obj_properties_ip6[PROP_IP6_CLAT_PREF64];
|
||||
}
|
||||
}
|
||||
|
||||
_notify_all(self, changed_params, n_changed_params);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -50,6 +50,9 @@ struct _NML3ConfigData {
|
|||
const NMPObject *best_default_route_x[2];
|
||||
};
|
||||
|
||||
struct in6_addr pref64_prefix;
|
||||
guint32 pref64_plen;
|
||||
|
||||
GArray *wins;
|
||||
GArray *nis_servers;
|
||||
|
||||
|
|
@ -122,6 +125,19 @@ struct _NML3ConfigData {
|
|||
NMSettingConnectionDnsOverTls dns_over_tls;
|
||||
NMSettingConnectionDnssec dnssec;
|
||||
NMUtilsIPv6IfaceId ip6_token;
|
||||
NMRefString *network_id;
|
||||
NMSettingIp4ConfigClat clat_config; /* this indicates the 'administrative' CLAT
|
||||
* state, i.e. whether CLAT will be started
|
||||
* once we receive a PREF64 */
|
||||
|
||||
/* The runtime CLAT state */
|
||||
struct {
|
||||
struct in6_addr ip6;
|
||||
struct in6_addr pref64;
|
||||
in_addr_t ip4;
|
||||
guint8 pref64_plen;
|
||||
bool enabled;
|
||||
} clat_state;
|
||||
|
||||
NML3ConfigDatFlags flags;
|
||||
|
||||
|
|
@ -130,7 +146,8 @@ struct _NML3ConfigData {
|
|||
int ndisc_hop_limit_val;
|
||||
|
||||
guint32 mtu;
|
||||
guint32 ip6_mtu;
|
||||
guint32 ip6_mtu_static; /* IPv6 MTU from the connection profile */
|
||||
guint32 ip6_mtu_ra; /* IPv6 MTU from Router Advertisement */
|
||||
guint32 ndisc_reachable_time_msec_val;
|
||||
guint32 ndisc_retrans_timer_msec_val;
|
||||
|
||||
|
|
@ -167,6 +184,8 @@ struct _NML3ConfigData {
|
|||
|
||||
bool routed_dns_4 : 1;
|
||||
bool routed_dns_6 : 1;
|
||||
|
||||
bool pref64_valid : 1;
|
||||
};
|
||||
|
||||
/*****************************************************************************/
|
||||
|
|
@ -390,8 +409,11 @@ nm_l3_config_data_log(const NML3ConfigData *self,
|
|||
: "",
|
||||
!self->is_sealed ? ", not-sealed" : "");
|
||||
|
||||
if (self->mtu != 0 || self->ip6_mtu != 0) {
|
||||
_L("mtu: %u, ip6-mtu: %u", self->mtu, self->ip6_mtu);
|
||||
if (self->mtu != 0 || self->ip6_mtu_static != 0 || self->ip6_mtu_ra != 0) {
|
||||
_L("mtu: %u, ip6-mtu-static: %u, ip6-mtu-ra %u",
|
||||
self->mtu,
|
||||
self->ip6_mtu_static,
|
||||
self->ip6_mtu_ra);
|
||||
}
|
||||
|
||||
for (IS_IPv4 = 1; IS_IPv4 >= 0; IS_IPv4--) {
|
||||
|
|
@ -519,6 +541,27 @@ nm_l3_config_data_log(const NML3ConfigData *self,
|
|||
_L("nis-domain: %s", self->nis_domain->str);
|
||||
}
|
||||
|
||||
if (!IS_IPv4) {
|
||||
if (self->clat_config == NM_SETTING_IP4_CONFIG_CLAT_AUTO)
|
||||
_L("clat-config: auto");
|
||||
else if (self->clat_config == NM_SETTING_IP4_CONFIG_CLAT_FORCE)
|
||||
_L("clat-config: force");
|
||||
|
||||
if (self->clat_state.enabled) {
|
||||
_L("clat-state: ip4=%s/32, pref64=%s/%u, ip6=%s/64",
|
||||
nm_inet4_ntop(self->clat_state.ip4, sbuf + NM_INET_ADDRSTRLEN),
|
||||
nm_inet6_ntop(&self->clat_state.pref64, sbuf),
|
||||
self->clat_state.pref64_plen,
|
||||
nm_inet6_ntop(&self->clat_state.ip6, sbuf_addr));
|
||||
}
|
||||
}
|
||||
|
||||
if (!IS_IPv4 && self->pref64_valid) {
|
||||
_L("pref64_prefix: %s/%d",
|
||||
nm_utils_inet6_ntop(&self->pref64_prefix, sbuf_addr),
|
||||
self->pref64_plen);
|
||||
}
|
||||
|
||||
if (self->dhcp_lease_x[IS_IPv4]) {
|
||||
gs_free NMUtilsNamedValue *options_free = NULL;
|
||||
NMUtilsNamedValue options_buffer[30];
|
||||
|
|
@ -603,6 +646,10 @@ nm_l3_config_data_log(const NML3ConfigData *self,
|
|||
nm_utils_inet6_interface_identifier_to_token(&self->ip6_token, sbuf_addr));
|
||||
}
|
||||
|
||||
if (self->network_id) {
|
||||
_L("network-id: %s", self->network_id->str);
|
||||
}
|
||||
|
||||
if (self->metered != NM_TERNARY_DEFAULT)
|
||||
_L("metered: %s", self->metered ? "yes" : "no");
|
||||
|
||||
|
|
@ -709,6 +756,7 @@ nm_l3_config_data_new(NMDedupMultiIndex *multi_idx, int ifindex, NMIPConfigSourc
|
|||
.flags = NM_L3_CONFIG_DAT_FLAGS_NONE,
|
||||
.metered = NM_TERNARY_DEFAULT,
|
||||
.proxy_browser_only = NM_TERNARY_DEFAULT,
|
||||
.clat_config = NM_SETTING_IP4_CONFIG_CLAT_NO,
|
||||
.proxy_method = NM_PROXY_CONFIG_METHOD_UNKNOWN,
|
||||
.route_table_sync_4 = NM_IP_ROUTE_TABLE_SYNC_MODE_NONE,
|
||||
.route_table_sync_6 = NM_IP_ROUTE_TABLE_SYNC_MODE_NONE,
|
||||
|
|
@ -722,6 +770,7 @@ nm_l3_config_data_new(NMDedupMultiIndex *multi_idx, int ifindex, NMIPConfigSourc
|
|||
.ndisc_retrans_timer_msec_set = FALSE,
|
||||
.allow_routes_without_address_4 = TRUE,
|
||||
.allow_routes_without_address_6 = TRUE,
|
||||
.pref64_valid = FALSE,
|
||||
};
|
||||
|
||||
_idx_type_init(&self->idx_addresses_4, NMP_OBJECT_TYPE_IP4_ADDRESS);
|
||||
|
|
@ -822,6 +871,7 @@ nm_l3_config_data_unref(const NML3ConfigData *self)
|
|||
nm_ref_string_unref(mutable->nis_domain);
|
||||
nm_ref_string_unref(mutable->proxy_pac_url);
|
||||
nm_ref_string_unref(mutable->proxy_pac_script);
|
||||
nm_ref_string_unref(mutable->network_id);
|
||||
|
||||
nm_g_slice_free(mutable);
|
||||
}
|
||||
|
|
@ -1890,22 +1940,42 @@ nm_l3_config_data_set_mtu(NML3ConfigData *self, guint32 mtu)
|
|||
}
|
||||
|
||||
guint32
|
||||
nm_l3_config_data_get_ip6_mtu(const NML3ConfigData *self)
|
||||
nm_l3_config_data_get_ip6_mtu_static(const NML3ConfigData *self)
|
||||
{
|
||||
nm_assert(_NM_IS_L3_CONFIG_DATA(self, TRUE));
|
||||
|
||||
return self->ip6_mtu;
|
||||
return self->ip6_mtu_static;
|
||||
}
|
||||
|
||||
gboolean
|
||||
nm_l3_config_data_set_ip6_mtu(NML3ConfigData *self, guint32 ip6_mtu)
|
||||
nm_l3_config_data_set_ip6_mtu_static(NML3ConfigData *self, guint32 ip6_mtu)
|
||||
{
|
||||
nm_assert(_NM_IS_L3_CONFIG_DATA(self, FALSE));
|
||||
|
||||
if (self->ip6_mtu == ip6_mtu)
|
||||
if (self->ip6_mtu_static == ip6_mtu)
|
||||
return FALSE;
|
||||
|
||||
self->ip6_mtu = ip6_mtu;
|
||||
self->ip6_mtu_static = ip6_mtu;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
guint32
|
||||
nm_l3_config_data_get_ip6_mtu_ra(const NML3ConfigData *self)
|
||||
{
|
||||
nm_assert(_NM_IS_L3_CONFIG_DATA(self, TRUE));
|
||||
|
||||
return self->ip6_mtu_ra;
|
||||
}
|
||||
|
||||
gboolean
|
||||
nm_l3_config_data_set_ip6_mtu_ra(NML3ConfigData *self, guint32 ip6_mtu)
|
||||
{
|
||||
nm_assert(_NM_IS_L3_CONFIG_DATA(self, FALSE));
|
||||
|
||||
if (self->ip6_mtu_ra == ip6_mtu)
|
||||
return FALSE;
|
||||
|
||||
self->ip6_mtu_ra = ip6_mtu;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
|
@ -1957,6 +2027,132 @@ nm_l3_config_data_set_ip6_token(NML3ConfigData *self, NMUtilsIPv6IfaceId ipv6_to
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
const char *
|
||||
nm_l3_config_data_get_network_id(const NML3ConfigData *self)
|
||||
{
|
||||
nm_assert(_NM_IS_L3_CONFIG_DATA(self, TRUE));
|
||||
|
||||
return nm_ref_string_get_str(self->network_id);
|
||||
}
|
||||
|
||||
gboolean
|
||||
nm_l3_config_data_set_network_id(NML3ConfigData *self, const char *value)
|
||||
{
|
||||
nm_assert(_NM_IS_L3_CONFIG_DATA(self, FALSE));
|
||||
|
||||
return nm_ref_string_reset_str(&self->network_id, value);
|
||||
}
|
||||
|
||||
gboolean
|
||||
nm_l3_config_data_set_clat_config(NML3ConfigData *self, NMSettingIp4ConfigClat val)
|
||||
{
|
||||
nm_assert(_NM_IS_L3_CONFIG_DATA(self, FALSE));
|
||||
nm_assert(NM_IN_SET(val,
|
||||
NM_SETTING_IP4_CONFIG_CLAT_NO,
|
||||
NM_SETTING_IP4_CONFIG_CLAT_FORCE,
|
||||
NM_SETTING_IP4_CONFIG_CLAT_AUTO));
|
||||
|
||||
if (self->clat_config == val)
|
||||
return FALSE;
|
||||
self->clat_config = val;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
NMSettingIp4ConfigClat
|
||||
nm_l3_config_data_get_clat_config(const NML3ConfigData *self)
|
||||
{
|
||||
nm_assert(_NM_IS_L3_CONFIG_DATA(self, TRUE));
|
||||
|
||||
return self->clat_config;
|
||||
}
|
||||
|
||||
gboolean
|
||||
nm_l3_config_data_get_clat_state(const NML3ConfigData *self,
|
||||
struct in6_addr *out_ip6,
|
||||
struct in6_addr *out_pref64,
|
||||
guint8 *out_pref64_plen,
|
||||
in_addr_t *out_ip4)
|
||||
{
|
||||
if (!self || !self->clat_state.enabled)
|
||||
return FALSE;
|
||||
NM_SET_OUT(out_ip6, self->clat_state.ip6);
|
||||
NM_SET_OUT(out_pref64, self->clat_state.pref64);
|
||||
NM_SET_OUT(out_pref64_plen, self->clat_state.pref64_plen);
|
||||
NM_SET_OUT(out_ip4, self->clat_state.ip4);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
nm_l3_config_data_set_clat_state(NML3ConfigData *self,
|
||||
gboolean enabled,
|
||||
const struct in6_addr *ip6,
|
||||
const struct in6_addr *pref64,
|
||||
guint8 pref64_plen,
|
||||
in_addr_t ip4)
|
||||
{
|
||||
nm_assert(_NM_IS_L3_CONFIG_DATA(self, FALSE));
|
||||
|
||||
self->clat_state.enabled = enabled;
|
||||
if (enabled) {
|
||||
self->clat_state.ip6 = *ip6;
|
||||
self->clat_state.pref64 = *pref64;
|
||||
self->clat_state.pref64_plen = pref64_plen;
|
||||
self->clat_state.ip4 = ip4;
|
||||
} else {
|
||||
self->clat_state.ip6 = in6addr_any;
|
||||
self->clat_state.pref64 = in6addr_any;
|
||||
self->clat_state.pref64_plen = 0;
|
||||
self->clat_state.ip4 = 0;
|
||||
}
|
||||
}
|
||||
|
||||
gboolean
|
||||
nm_l3_config_data_set_pref64_valid(NML3ConfigData *self, gboolean val)
|
||||
{
|
||||
if (self->pref64_valid == val)
|
||||
return FALSE;
|
||||
self->pref64_valid = val;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
nm_l3_config_data_get_pref64_valid(const NML3ConfigData *self)
|
||||
{
|
||||
nm_assert(_NM_IS_L3_CONFIG_DATA(self, TRUE));
|
||||
|
||||
return self->pref64_valid;
|
||||
}
|
||||
|
||||
gboolean
|
||||
nm_l3_config_data_get_pref64(const NML3ConfigData *self,
|
||||
struct in6_addr *out_prefix,
|
||||
guint32 *out_plen)
|
||||
{
|
||||
nm_assert(_NM_IS_L3_CONFIG_DATA(self, TRUE));
|
||||
|
||||
if (!self->pref64_valid)
|
||||
return FALSE;
|
||||
NM_SET_OUT(out_prefix, self->pref64_prefix);
|
||||
NM_SET_OUT(out_plen, self->pref64_plen);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
nm_l3_config_data_set_pref64(NML3ConfigData *self, struct in6_addr prefix, guint32 plen)
|
||||
{
|
||||
if (self->pref64_valid) {
|
||||
if (self->pref64_plen == plen
|
||||
&& nm_ip6_addr_same_prefix(&self->pref64_prefix, &prefix, plen)) {
|
||||
return FALSE;
|
||||
}
|
||||
} else {
|
||||
self->pref64_valid = TRUE;
|
||||
}
|
||||
self->pref64_prefix = prefix;
|
||||
self->pref64_plen = plen;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
NMMptcpFlags
|
||||
nm_l3_config_data_get_mptcp_flags(const NML3ConfigData *self)
|
||||
{
|
||||
|
|
@ -2484,8 +2680,10 @@ nm_l3_config_data_cmp_full(const NML3ConfigData *a,
|
|||
if (NM_FLAGS_HAS(flags, NM_L3_CONFIG_CMP_FLAGS_OTHER)) {
|
||||
NM_CMP_DIRECT(a->flags, b->flags);
|
||||
NM_CMP_DIRECT(a->ip6_token.id, b->ip6_token.id);
|
||||
NM_CMP_DIRECT_REF_STRING(a->network_id, b->network_id);
|
||||
NM_CMP_DIRECT(a->mtu, b->mtu);
|
||||
NM_CMP_DIRECT(a->ip6_mtu, b->ip6_mtu);
|
||||
NM_CMP_DIRECT(a->ip6_mtu_static, b->ip6_mtu_static);
|
||||
NM_CMP_DIRECT(a->ip6_mtu_ra, b->ip6_mtu_ra);
|
||||
NM_CMP_DIRECT_UNSAFE(a->metered, b->metered);
|
||||
NM_CMP_DIRECT_UNSAFE(a->proxy_browser_only, b->proxy_browser_only);
|
||||
NM_CMP_DIRECT_UNSAFE(a->proxy_method, b->proxy_method);
|
||||
|
|
@ -2509,6 +2707,23 @@ nm_l3_config_data_cmp_full(const NML3ConfigData *a,
|
|||
NM_CMP_DIRECT_UNSAFE(a->routed_dns_4, b->routed_dns_4);
|
||||
NM_CMP_DIRECT_UNSAFE(a->routed_dns_6, b->routed_dns_6);
|
||||
|
||||
NM_CMP_DIRECT_UNSAFE(a->clat_config, b->clat_config);
|
||||
|
||||
NM_CMP_DIRECT(!!a->clat_state.enabled, !!b->clat_state.enabled);
|
||||
if (a->clat_state.enabled) {
|
||||
NM_CMP_DIRECT_IN6ADDR(&a->clat_state.ip6, &b->clat_state.ip6);
|
||||
NM_CMP_DIRECT_IN6ADDR(&a->clat_state.pref64, &b->clat_state.pref64);
|
||||
NM_CMP_DIRECT(a->clat_state.pref64_plen, b->clat_state.pref64_plen);
|
||||
NM_CMP_DIRECT(a->clat_state.ip4, b->clat_state.ip4);
|
||||
}
|
||||
|
||||
NM_CMP_DIRECT(!!a->pref64_valid, !!b->pref64_valid);
|
||||
if (a->pref64_valid) {
|
||||
NM_CMP_DIRECT(a->pref64_plen, b->pref64_plen);
|
||||
NM_CMP_RETURN_DIRECT(
|
||||
nm_ip6_addr_same_prefix_cmp(&a->pref64_prefix, &b->pref64_prefix, a->pref64_plen));
|
||||
}
|
||||
|
||||
NM_CMP_FIELD(a, b, source);
|
||||
}
|
||||
|
||||
|
|
@ -2524,8 +2739,10 @@ nm_l3_config_data_cmp_full(const NML3ConfigData *a,
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
static const NMPObject *
|
||||
_data_get_direct_route_for_host(const NML3ConfigData *self, int addr_family, gconstpointer host)
|
||||
const NMPObject *
|
||||
nm_l3_config_data_get_direct_route_for_host(const NML3ConfigData *self,
|
||||
int addr_family,
|
||||
gconstpointer host)
|
||||
{
|
||||
const int IS_IPv4 = NM_IS_IPv4(addr_family);
|
||||
const NMPObject *best_route_obj = NULL;
|
||||
|
|
@ -2683,7 +2900,7 @@ nm_l3_config_data_add_dependent_onlink_routes(NML3ConfigData *self, int addr_fam
|
|||
if (NM_FLAGS_HAS(route_src->rx.r_rtm_flags, (unsigned) RTNH_F_ONLINK))
|
||||
continue;
|
||||
|
||||
if (_data_get_direct_route_for_host(self, addr_family, p_gateway))
|
||||
if (nm_l3_config_data_get_direct_route_for_host(self, addr_family, p_gateway))
|
||||
continue;
|
||||
|
||||
new_route = nmp_object_clone(obj_src, FALSE);
|
||||
|
|
@ -3030,6 +3247,9 @@ _init_from_connection_ip(NML3ConfigData *self, int addr_family, NMConnection *co
|
|||
nm_l3_config_data_set_ip6_privacy(
|
||||
self,
|
||||
nm_setting_ip6_config_get_ip6_privacy(NM_SETTING_IP6_CONFIG(s_ip)));
|
||||
nm_l3_config_data_set_ip6_mtu_static(
|
||||
self,
|
||||
nm_setting_ip6_config_get_mtu(NM_SETTING_IP6_CONFIG(s_ip)));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -3506,6 +3726,9 @@ nm_l3_config_data_merge(NML3ConfigData *self,
|
|||
if (self->ip6_token.id == 0)
|
||||
self->ip6_token.id = src->ip6_token.id;
|
||||
|
||||
if (!self->network_id)
|
||||
self->network_id = nm_ref_string_ref(src->network_id);
|
||||
|
||||
self->metered = NM_MAX((NMTernary) self->metered, (NMTernary) src->metered);
|
||||
|
||||
if (self->proxy_method == NM_PROXY_CONFIG_METHOD_UNKNOWN)
|
||||
|
|
@ -3544,8 +3767,11 @@ nm_l3_config_data_merge(NML3ConfigData *self,
|
|||
if (self->mtu == 0u)
|
||||
self->mtu = src->mtu;
|
||||
|
||||
if (self->ip6_mtu == 0u)
|
||||
self->ip6_mtu = src->ip6_mtu;
|
||||
if (self->ip6_mtu_static == 0u)
|
||||
self->ip6_mtu_static = src->ip6_mtu_static;
|
||||
|
||||
if (self->ip6_mtu_ra == 0u)
|
||||
self->ip6_mtu_ra = src->ip6_mtu_ra;
|
||||
|
||||
if (NM_FLAGS_HAS(merge_flags, NM_L3_CONFIG_MERGE_FLAGS_CLONE)) {
|
||||
_nm_unused nm_auto_unref_dhcplease NMDhcpLease *dhcp_lease_6 =
|
||||
|
|
@ -3567,6 +3793,24 @@ nm_l3_config_data_merge(NML3ConfigData *self,
|
|||
self->routed_dns_4 = TRUE;
|
||||
if (src->routed_dns_6)
|
||||
self->routed_dns_6 = TRUE;
|
||||
|
||||
if (self->clat_config == NM_SETTING_IP4_CONFIG_CLAT_NO) {
|
||||
/* 'no' always loses to 'force' and 'auto' */
|
||||
self->clat_config = src->clat_config;
|
||||
} else if (src->clat_config == NM_SETTING_IP4_CONFIG_CLAT_FORCE) {
|
||||
/* 'force' always takes precedence */
|
||||
self->clat_config = src->clat_config;
|
||||
}
|
||||
|
||||
if (!self->clat_state.enabled && src->clat_state.enabled) {
|
||||
self->clat_state = src->clat_state;
|
||||
}
|
||||
|
||||
if (src->pref64_valid) {
|
||||
self->pref64_prefix = src->pref64_prefix;
|
||||
self->pref64_plen = src->pref64_plen;
|
||||
self->pref64_valid = src->pref64_valid;
|
||||
}
|
||||
}
|
||||
|
||||
NML3ConfigData *
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
#include "libnm-glib-aux/nm-dedup-multi.h"
|
||||
#include "nm-setting-connection.h"
|
||||
#include "nm-setting-ip4-config.h"
|
||||
#include "nm-setting-ip6-config.h"
|
||||
#include "libnm-platform/nm-platform.h"
|
||||
#include "libnm-platform/nmp-object.h"
|
||||
|
|
@ -225,6 +226,10 @@ nm_l3_config_data_equal(const NML3ConfigData *a, const NML3ConfigData *b)
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
const NMPObject *nm_l3_config_data_get_direct_route_for_host(const NML3ConfigData *self,
|
||||
int addr_family,
|
||||
gconstpointer host);
|
||||
|
||||
const NMDedupMultiIdxType *nm_l3_config_data_lookup_index(const NML3ConfigData *self,
|
||||
NMPObjectType obj_type);
|
||||
|
||||
|
|
@ -482,14 +487,49 @@ guint32 nm_l3_config_data_get_mtu(const NML3ConfigData *self);
|
|||
|
||||
gboolean nm_l3_config_data_set_mtu(NML3ConfigData *self, guint32 mtu);
|
||||
|
||||
guint32 nm_l3_config_data_get_ip6_mtu(const NML3ConfigData *self);
|
||||
guint32 nm_l3_config_data_get_ip6_mtu_static(const NML3ConfigData *self);
|
||||
|
||||
gboolean nm_l3_config_data_set_ip6_mtu(NML3ConfigData *self, guint32 ip6_mtu);
|
||||
gboolean nm_l3_config_data_set_ip6_mtu_static(NML3ConfigData *self, guint32 ip6_mtu);
|
||||
|
||||
guint32 nm_l3_config_data_get_ip6_mtu_ra(const NML3ConfigData *self);
|
||||
|
||||
gboolean nm_l3_config_data_set_ip6_mtu_ra(NML3ConfigData *self, guint32 ip6_mtu);
|
||||
|
||||
NMUtilsIPv6IfaceId nm_l3_config_data_get_ip6_token(const NML3ConfigData *self);
|
||||
|
||||
gboolean nm_l3_config_data_set_ip6_token(NML3ConfigData *self, NMUtilsIPv6IfaceId ipv6_token);
|
||||
|
||||
gboolean nm_l3_config_data_set_network_id(NML3ConfigData *self, const char *network_id);
|
||||
|
||||
const char *nm_l3_config_data_get_network_id(const NML3ConfigData *self);
|
||||
|
||||
gboolean nm_l3_config_data_set_clat_config(NML3ConfigData *self, NMSettingIp4ConfigClat val);
|
||||
|
||||
NMSettingIp4ConfigClat nm_l3_config_data_get_clat_config(const NML3ConfigData *self);
|
||||
|
||||
gboolean nm_l3_config_data_get_clat_state(const NML3ConfigData *self,
|
||||
struct in6_addr *out_ip6,
|
||||
struct in6_addr *out_pref64,
|
||||
guint8 *out_pref64_plen,
|
||||
in_addr_t *out_ip4);
|
||||
|
||||
void nm_l3_config_data_set_clat_state(NML3ConfigData *self,
|
||||
gboolean enabled,
|
||||
const struct in6_addr *ip6,
|
||||
const struct in6_addr *pref64,
|
||||
guint8 pref64_plen,
|
||||
in_addr_t ip4);
|
||||
|
||||
gboolean nm_l3_config_data_set_pref64_valid(NML3ConfigData *self, gboolean val);
|
||||
|
||||
gboolean nm_l3_config_data_get_pref64_valid(const NML3ConfigData *self);
|
||||
|
||||
gboolean nm_l3_config_data_get_pref64(const NML3ConfigData *self,
|
||||
struct in6_addr *out_prefix,
|
||||
guint32 *out_plen);
|
||||
|
||||
gboolean nm_l3_config_data_set_pref64(NML3ConfigData *self, struct in6_addr prefix, guint32 plen);
|
||||
|
||||
NMMptcpFlags nm_l3_config_data_get_mptcp_flags(const NML3ConfigData *self);
|
||||
|
||||
gboolean nm_l3_config_data_set_mptcp_flags(NML3ConfigData *self, NMMptcpFlags mptcp_flags);
|
||||
|
|
|
|||
|
|
@ -7,10 +7,15 @@
|
|||
#include "libnm-std-aux/nm-linux-compat.h"
|
||||
|
||||
#include <net/if.h>
|
||||
#include <net/if_arp.h>
|
||||
#include "nm-compat-headers/linux/if_addr.h"
|
||||
#include <linux/if_ether.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
#include <linux/fib_rules.h>
|
||||
#if HAVE_CLAT
|
||||
#include <bpf/libbpf.h>
|
||||
#include <bpf/bpf.h>
|
||||
#endif /* HAVE_CLAT */
|
||||
|
||||
#include "libnm-core-aux-intern/nm-libnm-core-utils.h"
|
||||
#include "libnm-glib-aux/nm-prioq.h"
|
||||
|
|
@ -22,6 +27,13 @@
|
|||
#include "n-acd/src/n-acd.h"
|
||||
#include "nm-l3-ipv4ll.h"
|
||||
#include "nm-ip-config.h"
|
||||
#include "nm-core-utils.h"
|
||||
#if HAVE_CLAT
|
||||
#include "bpf/clat.h"
|
||||
NM_PRAGMA_WARNING_DISABLE("-Wcast-align")
|
||||
#include "bpf/clat.skel.h"
|
||||
NM_PRAGMA_WARNING_REENABLE
|
||||
#endif /* HAVE_CLAT */
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
|
|
@ -289,6 +301,24 @@ typedef struct _NML3CfgPrivate {
|
|||
NMIPConfig *ipconfig_x[2];
|
||||
};
|
||||
|
||||
#if HAVE_CLAT
|
||||
/* The reserved IPv4 address for CLAT in the 192.0.0.0/28 range */
|
||||
NMNetnsIPReservation *clat_address_4;
|
||||
/* The IPv6 address for sending and receiving translated packets */
|
||||
NMPlatformIP6Address clat_address_6;
|
||||
|
||||
/* The same addresses as above, but already committed previously */
|
||||
NMNetnsIPReservation *clat_address_4_committed;
|
||||
NMPlatformIP6Address clat_address_6_committed;
|
||||
|
||||
/* If NULL, the BPF program hasn't been loaded or attached */
|
||||
struct clat_bpf *clat_bpf;
|
||||
struct bpf_link *clat_ingress_link;
|
||||
struct bpf_link *clat_egress_link;
|
||||
|
||||
int clat_socket;
|
||||
#endif /* HAVE_CLAT */
|
||||
|
||||
/* Whether we earlier configured MPTCP endpoints for the interface. */
|
||||
union {
|
||||
struct {
|
||||
|
|
@ -353,6 +383,9 @@ typedef struct _NML3CfgPrivate {
|
|||
|
||||
bool rp_filter_handled : 1;
|
||||
bool rp_filter_set : 1;
|
||||
|
||||
bool clat_address_6_valid : 1;
|
||||
bool clat_address_6_committed_valid : 1;
|
||||
} NML3CfgPrivate;
|
||||
|
||||
struct _NML3CfgClass {
|
||||
|
|
@ -4107,6 +4140,233 @@ update_routes:
|
|||
}
|
||||
}
|
||||
|
||||
static void
|
||||
_l3cfg_update_clat_config(NML3Cfg *self,
|
||||
NML3ConfigData *l3cd,
|
||||
const L3ConfigData **l3_config_datas_arr,
|
||||
guint l3_config_datas_len)
|
||||
{
|
||||
#if !HAVE_CLAT
|
||||
return;
|
||||
#else
|
||||
struct in6_addr pref64;
|
||||
guint32 pref64_plen;
|
||||
gboolean clat_enabled = FALSE;
|
||||
const NMPlatformIP4Route *ip4_route;
|
||||
NMDedupMultiIter iter;
|
||||
|
||||
switch (nm_l3_config_data_get_clat_config(l3cd)) {
|
||||
case NM_SETTING_IP4_CONFIG_CLAT_FORCE:
|
||||
clat_enabled = TRUE;
|
||||
break;
|
||||
case NM_SETTING_IP4_CONFIG_CLAT_NO:
|
||||
clat_enabled = FALSE;
|
||||
break;
|
||||
case NM_SETTING_IP4_CONFIG_CLAT_AUTO:
|
||||
clat_enabled = TRUE;
|
||||
/* disable if there is a native IPv4 gateway */
|
||||
nm_l3_config_data_iter_ip4_route_for_each (&iter, l3cd, &ip4_route) {
|
||||
if (ip4_route->network == INADDR_ANY && ip4_route->plen == 0
|
||||
&& ip4_route->gateway != INADDR_ANY)
|
||||
clat_enabled = FALSE;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case NM_SETTING_IP4_CONFIG_CLAT_DEFAULT:
|
||||
nm_assert_not_reached();
|
||||
clat_enabled = TRUE;
|
||||
break;
|
||||
}
|
||||
|
||||
if (clat_enabled && nm_l3_config_data_get_pref64_valid(l3cd)) {
|
||||
NMPlatformIPXRoute rx;
|
||||
NMIPAddrTyped best_v6_gateway;
|
||||
const NMPlatformIP6Route *best_v6_route;
|
||||
const NMPlatformIP6Address *ip6_entry;
|
||||
struct in6_addr ip6;
|
||||
const char *network_id;
|
||||
char buf[512];
|
||||
guint32 route4_metric = NM_PLATFORM_ROUTE_METRIC_DEFAULT_IP4;
|
||||
guint i;
|
||||
|
||||
/* If we have a valid NAT64 prefix, configure in kernel:
|
||||
*
|
||||
* - a CLAT IPv4 address (192.0.0.x)
|
||||
* - a IPv4 default route via the best IPv6 gateway
|
||||
*
|
||||
* We also set clat_address_6 as an additional /64 IPv6 address
|
||||
* determined according to https://www.rfc-editor.org/rfc/rfc6877#section-6.3 .
|
||||
* This address is used for sending and receiving translated packets,
|
||||
* but is not configured in kernel to avoid that it gets used by applications.
|
||||
* Later in _l3_commit_pref64() we use IPV6_JOIN_ANYCAST to let the kernel
|
||||
* handle ND for the address.
|
||||
*/
|
||||
|
||||
nm_l3_config_data_get_pref64(l3cd, &pref64, &pref64_plen);
|
||||
network_id = nm_l3_config_data_get_network_id(l3cd);
|
||||
|
||||
if (!self->priv.p->clat_address_6_valid && network_id) {
|
||||
nm_l3_config_data_iter_ip6_address_for_each (&iter, l3cd, &ip6_entry) {
|
||||
if (ip6_entry->addr_source == NM_IP_CONFIG_SOURCE_NDISC && ip6_entry->plen == 64) {
|
||||
ip6 = ip6_entry->address;
|
||||
|
||||
nm_utils_ipv6_addr_set_stable_privacy(NM_UTILS_STABLE_TYPE_CLAT,
|
||||
&ip6,
|
||||
nm_l3cfg_get_ifname(self, TRUE),
|
||||
network_id,
|
||||
0);
|
||||
self->priv.p->clat_address_6 = (NMPlatformIP6Address) {
|
||||
.ifindex = self->priv.ifindex,
|
||||
.address = ip6,
|
||||
.peer_address = ip6,
|
||||
.addr_source = NM_IP_CONFIG_SOURCE_CLAT,
|
||||
.plen = ip6_entry->plen,
|
||||
};
|
||||
|
||||
_LOGT("clat: using IPv6 address %s", nm_inet6_ntop(&ip6, buf));
|
||||
|
||||
self->priv.p->clat_address_6_valid = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Don't get a v4 address if we have no v6 address (otherwise, we could
|
||||
* potentially create broken v4 connectivity) */
|
||||
if (!self->priv.p->clat_address_6_valid) {
|
||||
_LOGW("CLAT is currently only supported when SLAAC is in use.");
|
||||
/* Deallocate the v4 address unless it's the committed one */
|
||||
if (self->priv.p->clat_address_4 != self->priv.p->clat_address_4_committed) {
|
||||
nm_clear_pointer(&self->priv.p->clat_address_4, nm_netns_ip_reservation_release);
|
||||
} else {
|
||||
self->priv.p->clat_address_4 = NULL;
|
||||
}
|
||||
} else if (!self->priv.p->clat_address_4) {
|
||||
/* We need a v4 /32 */
|
||||
self->priv.p->clat_address_4 =
|
||||
nm_netns_ip_reservation_get(self->priv.netns, NM_NETNS_IP_RESERVATION_TYPE_CLAT);
|
||||
}
|
||||
|
||||
{
|
||||
const NMPlatformIP4Route *r4;
|
||||
guint32 metric = 0;
|
||||
guint32 penalty = 0;
|
||||
|
||||
/* Find the IPv4 metric for the CLAT default route.
|
||||
* If there is another non-CLAT default route on the device, use the
|
||||
* same metric + 1, so that native connectivity is always preferred.
|
||||
* Otherwise, use the metric from the connection profile.
|
||||
*/
|
||||
|
||||
r4 = NMP_OBJECT_CAST_IP4_ROUTE(nm_l3_config_data_get_best_default_route(l3cd, AF_INET));
|
||||
|
||||
if (r4) {
|
||||
route4_metric = nm_add_clamped_u32(r4->metric, 1u);
|
||||
} else {
|
||||
for (i = 0; i < l3_config_datas_len; i++) {
|
||||
const L3ConfigData *l3cd_data = l3_config_datas_arr[i];
|
||||
|
||||
if (l3cd_data->default_route_metric_4 != NM_PLATFORM_ROUTE_METRIC_DEFAULT_IP4) {
|
||||
metric = l3cd_data->default_route_metric_4;
|
||||
}
|
||||
if (l3cd_data->default_route_penalty_4 != 0) {
|
||||
penalty = l3cd_data->default_route_penalty_4;
|
||||
}
|
||||
}
|
||||
route4_metric = nm_add_clamped_u32(metric, penalty);
|
||||
}
|
||||
}
|
||||
|
||||
if (self->priv.p->clat_address_4) {
|
||||
best_v6_route = NMP_OBJECT_CAST_IP6_ROUTE(
|
||||
nm_l3_config_data_get_direct_route_for_host(l3cd, AF_INET6, &pref64));
|
||||
if (!best_v6_route) {
|
||||
best_v6_route = NMP_OBJECT_CAST_IP6_ROUTE(
|
||||
nm_l3_config_data_get_best_default_route(l3cd, AF_INET6));
|
||||
}
|
||||
if (best_v6_route) {
|
||||
NMPlatformIP4Address addr = {
|
||||
.ifindex = self->priv.ifindex,
|
||||
.address = self->priv.p->clat_address_4->addr,
|
||||
.peer_address = self->priv.p->clat_address_4->addr,
|
||||
.addr_source = NM_IP_CONFIG_SOURCE_CLAT,
|
||||
.plen = 32,
|
||||
};
|
||||
const NMPlatformLink *pllink;
|
||||
guint mtu = 0;
|
||||
guint val = 0;
|
||||
|
||||
best_v6_gateway.addr_family = AF_INET6;
|
||||
best_v6_gateway.addr.addr6 = best_v6_route->gateway;
|
||||
|
||||
/* Determine the IPv6 MTU of the interface. Unfortunately,
|
||||
* the logic to set the MTU is in NMDevice and here we need
|
||||
* some duplication to find the actual value.
|
||||
* TODO: move the MTU handling into l3cfg. */
|
||||
|
||||
/* Get the link MTU */
|
||||
pllink = nm_l3cfg_get_pllink(self, TRUE);
|
||||
if (pllink)
|
||||
mtu = pllink->mtu;
|
||||
if (mtu == 0)
|
||||
mtu = 1500;
|
||||
|
||||
/* Update it with the IPv6 MTU value from the connection
|
||||
* or from RA */
|
||||
val = nm_l3_config_data_get_ip6_mtu_static(l3cd);
|
||||
if (val == 0) {
|
||||
val = nm_l3_config_data_get_ip6_mtu_ra(l3cd);
|
||||
}
|
||||
if (val != 0 && val < mtu) {
|
||||
mtu = val;
|
||||
}
|
||||
if (mtu < 1280)
|
||||
mtu = 1280;
|
||||
|
||||
/* Leave 20 additional bytes for the ipv4 -> ipv6 header translation,
|
||||
* plus 8 for a potential fragmentation extension header */
|
||||
mtu -= 28;
|
||||
|
||||
rx.r4 = (NMPlatformIP4Route) {
|
||||
.ifindex = self->priv.ifindex,
|
||||
.rt_source = NM_IP_CONFIG_SOURCE_CLAT,
|
||||
.network = 0, /* default route */
|
||||
.plen = 0,
|
||||
.table_coerced = nm_platform_route_table_coerce(RT_TABLE_MAIN),
|
||||
.scope_inv = nm_platform_route_scope_inv(RT_SCOPE_UNIVERSE),
|
||||
.type_coerced = nm_platform_route_type_coerce(RTN_UNICAST),
|
||||
.pref_src = self->priv.p->clat_address_4->addr,
|
||||
.via = best_v6_gateway,
|
||||
.metric = route4_metric,
|
||||
.mtu = mtu,
|
||||
};
|
||||
nm_platform_ip_route_normalize(AF_INET, &rx.rx);
|
||||
if (!nm_l3_config_data_lookup_route(l3cd, AF_INET, &rx.rx)) {
|
||||
nm_l3_config_data_add_route_4(l3cd, &rx.r4);
|
||||
}
|
||||
|
||||
_LOGT("clat: route %s", nm_platform_ip4_route_to_string(&rx.r4, buf, sizeof(buf)));
|
||||
|
||||
nm_l3_config_data_add_address_4(l3cd, &addr);
|
||||
} else {
|
||||
_LOGW("Couldn't find a good ipv6 route! Unable to set up CLAT!");
|
||||
}
|
||||
}
|
||||
|
||||
if (self->priv.p->clat_address_4 && self->priv.p->clat_address_6_valid) {
|
||||
nm_l3_config_data_set_clat_state(l3cd,
|
||||
TRUE,
|
||||
&self->priv.p->clat_address_6.address,
|
||||
&pref64,
|
||||
pref64_plen,
|
||||
self->priv.p->clat_address_4->addr);
|
||||
} else {
|
||||
nm_l3_config_data_set_clat_state(l3cd, FALSE, NULL, NULL, 0, INADDR_ANY);
|
||||
}
|
||||
}
|
||||
#endif /* HAVE_CLAT */
|
||||
}
|
||||
|
||||
static void
|
||||
_l3cfg_update_combined_config(NML3Cfg *self,
|
||||
gboolean to_commit,
|
||||
|
|
@ -4220,6 +4480,8 @@ _l3cfg_update_combined_config(NML3Cfg *self,
|
|||
&hook_data);
|
||||
}
|
||||
|
||||
_l3cfg_update_clat_config(self, l3cd, l3_config_datas_arr, l3_config_datas_len);
|
||||
|
||||
if (self->priv.ifindex == NM_LOOPBACK_IFINDEX) {
|
||||
NMPlatformIPXAddress ax;
|
||||
NMPlatformIPXRoute rx;
|
||||
|
|
@ -4280,6 +4542,18 @@ _l3cfg_update_combined_config(NML3Cfg *self,
|
|||
if (nm_l3_config_data_equal(l3cd, self->priv.p->combined_l3cd_merged))
|
||||
goto out;
|
||||
|
||||
#if HAVE_CLAT
|
||||
if (!l3cd) {
|
||||
self->priv.p->clat_address_6_valid = FALSE;
|
||||
/* Deallocate the v4 address unless it's the commited one */
|
||||
if (self->priv.p->clat_address_4 != self->priv.p->clat_address_4_committed) {
|
||||
nm_clear_pointer(&self->priv.p->clat_address_4, nm_netns_ip_reservation_release);
|
||||
} else {
|
||||
self->priv.p->clat_address_4 = NULL;
|
||||
}
|
||||
}
|
||||
#endif /* HAVE_CLAT */
|
||||
|
||||
l3cd_old = g_steal_pointer(&self->priv.p->combined_l3cd_merged);
|
||||
self->priv.p->combined_l3cd_merged = nm_l3_config_data_seal(g_steal_pointer(&l3cd));
|
||||
merged_changed = TRUE;
|
||||
|
|
@ -5379,6 +5653,251 @@ _l3_commit_one(NML3Cfg *self,
|
|||
_failedobj_handle_routes(self, addr_family, routes_failed);
|
||||
}
|
||||
|
||||
#if HAVE_CLAT
|
||||
static void
|
||||
_l3_clat_destroy(NML3Cfg *self)
|
||||
{
|
||||
char buf[100];
|
||||
int err;
|
||||
|
||||
if (self->priv.p->clat_bpf) {
|
||||
const struct clat_stats *s = &self->priv.p->clat_bpf->bss->stats;
|
||||
|
||||
_LOGT("clat: stats:"
|
||||
" egress (v4 to v6): tcp %" G_GUINT64_FORMAT ", udp %" G_GUINT64_FORMAT
|
||||
", icmp %" G_GUINT64_FORMAT ", other %" G_GUINT64_FORMAT
|
||||
", dropped %" G_GUINT64_FORMAT "; ingress (v6 to v4): tcp %" G_GUINT64_FORMAT
|
||||
", udp %" G_GUINT64_FORMAT ", icmp %" G_GUINT64_FORMAT ", other %" G_GUINT64_FORMAT
|
||||
", fragment %" G_GUINT64_FORMAT ", dropped %" G_GUINT64_FORMAT,
|
||||
(guint64) s->egress_tcp,
|
||||
(guint64) s->egress_udp,
|
||||
(guint64) s->egress_icmp,
|
||||
(guint64) s->egress_other,
|
||||
(guint64) s->egress_dropped,
|
||||
(guint64) s->ingress_tcp,
|
||||
(guint64) s->ingress_udp,
|
||||
(guint64) s->ingress_icmp,
|
||||
(guint64) s->ingress_other,
|
||||
(guint64) s->ingress_fragment,
|
||||
(guint64) s->ingress_dropped);
|
||||
}
|
||||
|
||||
if (self->priv.p->clat_ingress_link) {
|
||||
err = bpf_link__destroy(self->priv.p->clat_ingress_link);
|
||||
if (err != 0) {
|
||||
libbpf_strerror(err, buf, sizeof(buf));
|
||||
_LOGD("clat: failed to destroy the ingress link");
|
||||
}
|
||||
self->priv.p->clat_ingress_link = NULL;
|
||||
}
|
||||
|
||||
if (self->priv.p->clat_egress_link) {
|
||||
err = bpf_link__destroy(self->priv.p->clat_egress_link);
|
||||
if (err != 0) {
|
||||
libbpf_strerror(err, buf, sizeof(buf));
|
||||
_LOGD("clat: failed to destroy the egress link");
|
||||
}
|
||||
self->priv.p->clat_egress_link = NULL;
|
||||
}
|
||||
|
||||
nm_clear_pointer(&self->priv.p->clat_bpf, clat_bpf__destroy);
|
||||
}
|
||||
|
||||
static void
|
||||
_l3_commit_pref64(NML3Cfg *self, NML3CfgCommitType commit_type)
|
||||
{
|
||||
int err = 0;
|
||||
const NML3ConfigData *l3cd = self->priv.p->combined_l3cd_commited;
|
||||
struct in6_addr _l3cd_pref64_inner;
|
||||
const struct in6_addr *l3cd_pref64 = NULL;
|
||||
guint32 l3cd_pref64_plen;
|
||||
char buf[100];
|
||||
struct clat_config clat_config;
|
||||
gboolean v6_changed;
|
||||
const NMPlatformLink *pllink;
|
||||
gboolean has_ethernet_header = FALSE;
|
||||
|
||||
if (l3cd && nm_l3_config_data_get_pref64(l3cd, &_l3cd_pref64_inner, &l3cd_pref64_plen)) {
|
||||
l3cd_pref64 = &_l3cd_pref64_inner;
|
||||
}
|
||||
|
||||
if (l3cd_pref64 && self->priv.p->clat_address_4 && self->priv.p->clat_address_6_valid) {
|
||||
pllink = nm_l3cfg_get_pllink(self, TRUE);
|
||||
if (!pllink) {
|
||||
has_ethernet_header = TRUE;
|
||||
} else {
|
||||
switch (pllink->arptype) {
|
||||
case ARPHRD_ETHER:
|
||||
has_ethernet_header = TRUE;
|
||||
break;
|
||||
case ARPHRD_NONE:
|
||||
case ARPHRD_PPP:
|
||||
case ARPHRD_RAWIP:
|
||||
has_ethernet_header = FALSE;
|
||||
break;
|
||||
default:
|
||||
_LOGD("clat: unknown ARP type %u, assuming the interface uses no L2 header",
|
||||
pllink->arptype);
|
||||
has_ethernet_header = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
if (!self->priv.p->clat_bpf) {
|
||||
_LOGT("clat: attaching the BPF program");
|
||||
|
||||
self->priv.p->clat_bpf = clat_bpf__open();
|
||||
if (!self->priv.p->clat_bpf) {
|
||||
libbpf_strerror(errno, buf, sizeof(buf));
|
||||
_LOGW("clat: failed to open the BPF program: %s", buf);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Only load the programs for the right L2 type */
|
||||
bpf_program__set_autoload(self->priv.p->clat_bpf->progs.nm_clat_ingress_eth,
|
||||
has_ethernet_header);
|
||||
bpf_program__set_autoload(self->priv.p->clat_bpf->progs.nm_clat_egress_eth,
|
||||
has_ethernet_header);
|
||||
bpf_program__set_autoload(self->priv.p->clat_bpf->progs.nm_clat_ingress_rawip,
|
||||
!has_ethernet_header);
|
||||
bpf_program__set_autoload(self->priv.p->clat_bpf->progs.nm_clat_egress_rawip,
|
||||
!has_ethernet_header);
|
||||
|
||||
if (clat_bpf__load(self->priv.p->clat_bpf)) {
|
||||
libbpf_strerror(errno, buf, sizeof(buf));
|
||||
_LOGW("clat: failed to load the BPF program: %s", buf);
|
||||
nm_clear_pointer(&self->priv.p->clat_bpf, clat_bpf__destroy);
|
||||
return;
|
||||
}
|
||||
|
||||
self->priv.p->clat_ingress_link = bpf_program__attach_tcx(
|
||||
has_ethernet_header ? self->priv.p->clat_bpf->progs.nm_clat_ingress_eth
|
||||
: self->priv.p->clat_bpf->progs.nm_clat_ingress_rawip,
|
||||
self->priv.ifindex,
|
||||
NULL);
|
||||
if (!self->priv.p->clat_ingress_link) {
|
||||
libbpf_strerror(errno, buf, sizeof(buf));
|
||||
_LOGW("clat: failed to attach the ingress program: %s", buf);
|
||||
return;
|
||||
}
|
||||
|
||||
self->priv.p->clat_egress_link = bpf_program__attach_tcx(
|
||||
has_ethernet_header ? self->priv.p->clat_bpf->progs.nm_clat_egress_eth
|
||||
: self->priv.p->clat_bpf->progs.nm_clat_egress_rawip,
|
||||
self->priv.ifindex,
|
||||
NULL);
|
||||
if (!self->priv.p->clat_egress_link) {
|
||||
libbpf_strerror(errno, buf, sizeof(buf));
|
||||
_LOGW("clat: failed to attach the egress program: %s", buf);
|
||||
return;
|
||||
}
|
||||
|
||||
_LOGT("clat: program attached successfully");
|
||||
}
|
||||
|
||||
/* Pass configuration to the BPF program */
|
||||
memset(&clat_config, 0, sizeof(clat_config));
|
||||
clat_config.local_v4.s_addr = self->priv.p->clat_address_4->addr;
|
||||
clat_config.local_v6 = self->priv.p->clat_address_6.address;
|
||||
clat_config.pref64 = *l3cd_pref64;
|
||||
clat_config.pref64_len = l3cd_pref64_plen;
|
||||
self->priv.p->clat_bpf->bss->config = clat_config;
|
||||
|
||||
if (self->priv.p->clat_socket < 0) {
|
||||
self->priv.p->clat_socket = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
|
||||
if (self->priv.p->clat_socket < 0) {
|
||||
_LOGW("clat: couldn't create the socket: %s", nm_strerror_native(errno));
|
||||
}
|
||||
}
|
||||
if (self->priv.p->clat_socket >= 0) {
|
||||
err = setsockopt(self->priv.p->clat_socket,
|
||||
SOL_SOCKET,
|
||||
SO_BINDTOIFINDEX,
|
||||
&self->priv.ifindex,
|
||||
sizeof(self->priv.ifindex));
|
||||
if (err < 0) {
|
||||
_LOGW("clat: couldn't bind the socket: %s", nm_strerror_native(errno));
|
||||
}
|
||||
}
|
||||
|
||||
v6_changed =
|
||||
(self->priv.p->clat_address_6_valid != self->priv.p->clat_address_6_committed_valid)
|
||||
|| (self->priv.p->clat_address_6_valid && self->priv.p->clat_address_6_committed_valid
|
||||
&& memcmp(&self->priv.p->clat_address_6.address,
|
||||
&self->priv.p->clat_address_6_committed.address,
|
||||
sizeof(self->priv.p->clat_address_6_committed.address)));
|
||||
|
||||
if (self->priv.p->clat_socket > 0 && v6_changed) {
|
||||
struct ipv6_mreq mreq = {.ipv6mr_interface = self->priv.ifindex};
|
||||
|
||||
if (self->priv.p->clat_address_6_committed_valid) {
|
||||
mreq.ipv6mr_multiaddr = self->priv.p->clat_address_6_committed.address;
|
||||
|
||||
err = setsockopt(self->priv.p->clat_socket,
|
||||
SOL_IPV6,
|
||||
IPV6_LEAVE_ANYCAST,
|
||||
&mreq,
|
||||
sizeof(mreq));
|
||||
if (err < 0) {
|
||||
_LOGW("clat: couldn't leave the anycast group: %s", nm_strerror_native(errno));
|
||||
}
|
||||
}
|
||||
|
||||
if (self->priv.p->clat_address_6_valid) {
|
||||
/* As per draft-ietf-v6ops-claton-14, hosts must perform duplicate
|
||||
* addresses detection (DAD) on the generated CLAT IPv6 address. This is
|
||||
* necessary not only to avoid address collisions but also because some
|
||||
* networks drop traffic from addresses that have not done DAD.
|
||||
* Since doing true DAD adds complexity, adopt the same approach as
|
||||
* Android: start DAD by sending a neighbor solicitation and don't wait
|
||||
* for any reply. This avoids the problem with dropped traffic; it
|
||||
* doesn't help with collisions, but collisions are anyway very unlikely
|
||||
* because the interface identifier is a random 64-bit value.
|
||||
*/
|
||||
nm_utils_ipv6_dad_send(&self->priv.p->clat_address_6.address,
|
||||
self->priv.ifindex,
|
||||
pllink ? pllink->arptype : ARPHRD_ETHER);
|
||||
|
||||
mreq.ipv6mr_multiaddr = self->priv.p->clat_address_6.address;
|
||||
|
||||
err = setsockopt(self->priv.p->clat_socket,
|
||||
SOL_IPV6,
|
||||
IPV6_JOIN_ANYCAST,
|
||||
&mreq,
|
||||
sizeof(mreq));
|
||||
if (err < 0) {
|
||||
_LOGW("clat: couldn't join the anycast group: %s", nm_strerror_native(errno));
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (self->priv.p->clat_bpf) {
|
||||
_l3_clat_destroy(self);
|
||||
}
|
||||
|
||||
/* Committed will get cleaned up below */
|
||||
self->priv.p->clat_address_6_valid = FALSE;
|
||||
|
||||
nm_clear_fd(&self->priv.p->clat_socket);
|
||||
|
||||
/* Deallocate the v4 address. Committed address will get cleaned up below,
|
||||
but we need to make sure there's no double-free */
|
||||
if (self->priv.p->clat_address_4 != self->priv.p->clat_address_4_committed) {
|
||||
nm_clear_pointer(&self->priv.p->clat_address_4, nm_netns_ip_reservation_release);
|
||||
} else {
|
||||
self->priv.p->clat_address_4 = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Record the new state */
|
||||
if (self->priv.p->clat_address_4_committed != self->priv.p->clat_address_4) {
|
||||
nm_clear_pointer(&self->priv.p->clat_address_4_committed, nm_netns_ip_reservation_release);
|
||||
self->priv.p->clat_address_4_committed = self->priv.p->clat_address_4;
|
||||
}
|
||||
self->priv.p->clat_address_6_committed = self->priv.p->clat_address_6;
|
||||
self->priv.p->clat_address_6_committed_valid = self->priv.p->clat_address_6_valid;
|
||||
}
|
||||
#endif /* HAVE_CLAT */
|
||||
|
||||
static void
|
||||
_l3_commit(NML3Cfg *self, NML3CfgCommitType commit_type, gboolean is_idle)
|
||||
{
|
||||
|
|
@ -5461,6 +5980,10 @@ _l3_commit(NML3Cfg *self, NML3CfgCommitType commit_type, gboolean is_idle)
|
|||
|
||||
_l3_acd_data_process_changes(self);
|
||||
|
||||
#if HAVE_CLAT
|
||||
_l3_commit_pref64(self, commit_type);
|
||||
#endif /* HAVE_CLAT */
|
||||
|
||||
nm_assert(self->priv.p->commit_reentrant_count == 1);
|
||||
self->priv.p->commit_reentrant_count--;
|
||||
|
||||
|
|
@ -5842,6 +6365,10 @@ nm_l3cfg_init(NML3Cfg *self)
|
|||
{
|
||||
self->priv.p = G_TYPE_INSTANCE_GET_PRIVATE(self, NM_TYPE_L3CFG, NML3CfgPrivate);
|
||||
|
||||
#if HAVE_CLAT
|
||||
self->priv.p->clat_socket = -1;
|
||||
#endif /* HAVE_CLAT */
|
||||
|
||||
c_list_init(&self->priv.p->acd_lst_head);
|
||||
c_list_init(&self->priv.p->acd_event_notify_lst_head);
|
||||
c_list_init(&self->priv.p->commit_type_lst_head);
|
||||
|
|
@ -5950,6 +6477,14 @@ finalize(GObject *object)
|
|||
if (changed)
|
||||
nmp_global_tracker_sync_mptcp_addrs(self->priv.global_tracker, FALSE);
|
||||
|
||||
#if HAVE_CLAT
|
||||
self->priv.p->clat_address_4_committed = NULL;
|
||||
nm_clear_pointer(&self->priv.p->clat_address_4, nm_netns_ip_reservation_release);
|
||||
nm_clear_fd(&self->priv.p->clat_socket);
|
||||
if (self->priv.p->clat_bpf) {
|
||||
_l3_clat_destroy(self);
|
||||
}
|
||||
#endif
|
||||
g_clear_object(&self->priv.netns);
|
||||
g_clear_object(&self->priv.platform);
|
||||
nm_clear_pointer(&self->priv.global_tracker, nmp_global_tracker_unref);
|
||||
|
|
|
|||
|
|
@ -574,8 +574,8 @@ notify_watcher:
|
|||
typedef struct {
|
||||
const char *name;
|
||||
guint32 start_addr; /* host byte order */
|
||||
guint prefix_len;
|
||||
guint num_addrs;
|
||||
guint range_plen;
|
||||
guint addr_plen;
|
||||
gboolean allow_reuse;
|
||||
} IPReservationTypeDesc;
|
||||
|
||||
|
|
@ -583,11 +583,19 @@ static const IPReservationTypeDesc ip_reservation_types[_NM_NETNS_IP_RESERVATION
|
|||
[NM_NETNS_IP_RESERVATION_TYPE_SHARED4] =
|
||||
{
|
||||
.name = "shared-ip4",
|
||||
.start_addr = 0x0a2a0001, /* 10.42.0.1 */
|
||||
.prefix_len = 24,
|
||||
.num_addrs = 256,
|
||||
.start_addr = 0x0a2a0001, /* 10.42.{0-255}.1/24 */
|
||||
.range_plen = 16,
|
||||
.addr_plen = 24,
|
||||
.allow_reuse = TRUE,
|
||||
},
|
||||
[NM_NETNS_IP_RESERVATION_TYPE_CLAT] =
|
||||
{
|
||||
.name = "clat",
|
||||
.start_addr = 0xc0000005, /* 192.0.0.{5-7,0-4}/32 */
|
||||
.range_plen = 29,
|
||||
.addr_plen = 32,
|
||||
.allow_reuse = FALSE,
|
||||
},
|
||||
};
|
||||
|
||||
NMNetnsIPReservation *
|
||||
|
|
@ -613,13 +621,23 @@ nm_netns_ip_reservation_get(NMNetns *self, NMNetnsIPReservationType type)
|
|||
g_object_ref(self);
|
||||
} else {
|
||||
guint32 count;
|
||||
guint32 base_network;
|
||||
guint32 host_mask;
|
||||
guint32 increment;
|
||||
|
||||
nm_assert(g_hash_table_size(*table) > 0);
|
||||
nm_assert(desc->prefix_len > 0 && desc->prefix_len <= 32);
|
||||
nm_assert(desc->range_plen < 32);
|
||||
nm_assert(desc->addr_plen > 0 && desc->addr_plen <= 32);
|
||||
nm_assert(desc->addr_plen > desc->range_plen);
|
||||
|
||||
base_network = desc->start_addr & ~(0xFFFFFFFFu >> desc->range_plen);
|
||||
host_mask = 0xFFFFFFFFu >> desc->range_plen;
|
||||
increment = 1 << (32 - desc->addr_plen);
|
||||
|
||||
count = 0u;
|
||||
for (;;) {
|
||||
addr = htonl(desc->start_addr + (count << (32 - desc->prefix_len)));
|
||||
addr = htonl(base_network
|
||||
+ ((base_network + (desc->start_addr + count * increment)) & host_mask));
|
||||
|
||||
res = g_hash_table_lookup(*table, &addr);
|
||||
if (!res)
|
||||
|
|
@ -627,7 +645,7 @@ nm_netns_ip_reservation_get(NMNetns *self, NMNetnsIPReservationType type)
|
|||
|
||||
count++;
|
||||
|
||||
if (count >= desc->num_addrs) {
|
||||
if (count >= 1 << (desc->addr_plen - desc->range_plen)) {
|
||||
if (!desc->allow_reuse) {
|
||||
_LOGE("%s: ran out of IP addresses", desc->name);
|
||||
return NULL;
|
||||
|
|
@ -637,12 +655,12 @@ nm_netns_ip_reservation_get(NMNetns *self, NMNetnsIPReservationType type)
|
|||
_LOGE("%s: ran out of IP addresses. Reuse %s/%u",
|
||||
desc->name,
|
||||
nm_inet4_ntop(res->addr, buf),
|
||||
desc->prefix_len);
|
||||
desc->addr_plen);
|
||||
} else {
|
||||
_LOGD("%s: reserved IP address %s/%u (duplicate)",
|
||||
desc->name,
|
||||
nm_inet4_ntop(res->addr, buf),
|
||||
desc->prefix_len);
|
||||
desc->addr_plen);
|
||||
}
|
||||
res->_ref_count++;
|
||||
return res;
|
||||
|
|
@ -663,7 +681,7 @@ nm_netns_ip_reservation_get(NMNetns *self, NMNetnsIPReservationType type)
|
|||
_LOGD("%s: reserved IP address %s/%u",
|
||||
desc->name,
|
||||
nm_inet4_ntop(res->addr, buf),
|
||||
desc->prefix_len);
|
||||
desc->addr_plen);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
|
@ -695,7 +713,7 @@ nm_netns_ip_reservation_release(NMNetnsIPReservation *res)
|
|||
_LOGD("%s: release IP address reservation %s/%u (%d more references held)",
|
||||
desc->name,
|
||||
nm_inet4_ntop(res->addr, buf),
|
||||
desc->prefix_len,
|
||||
desc->addr_plen,
|
||||
res->_ref_count);
|
||||
return;
|
||||
}
|
||||
|
|
@ -706,7 +724,7 @@ nm_netns_ip_reservation_release(NMNetnsIPReservation *res)
|
|||
_LOGD("%s: release IP address reservation %s/%u",
|
||||
desc->name,
|
||||
nm_inet4_ntop(res->addr, buf),
|
||||
desc->prefix_len);
|
||||
desc->addr_plen);
|
||||
|
||||
if (g_hash_table_size(*table) == 0) {
|
||||
nm_clear_pointer(table, g_hash_table_unref);
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@ NML3Cfg *nm_netns_l3cfg_acquire(NMNetns *netns, int ifindex);
|
|||
|
||||
typedef enum {
|
||||
NM_NETNS_IP_RESERVATION_TYPE_SHARED4,
|
||||
NM_NETNS_IP_RESERVATION_TYPE_CLAT,
|
||||
|
||||
_NM_NETNS_IP_RESERVATION_TYPE_NUM,
|
||||
} NMNetnsIPReservationType;
|
||||
|
|
|
|||
|
|
@ -77,7 +77,7 @@ get_full_file_path(const char *ifcfg_path, const char *file_path)
|
|||
{
|
||||
const char *base = file_path;
|
||||
gs_free char *dirname = NULL;
|
||||
char *p;
|
||||
const char *p;
|
||||
|
||||
g_return_val_if_fail(ifcfg_path != NULL, NULL);
|
||||
g_return_val_if_fail(file_path != NULL, NULL);
|
||||
|
|
@ -4401,7 +4401,7 @@ make_wireless_setting(shvarFile *ifcfg, GError **error)
|
|||
NMSettingWireless *s_wireless;
|
||||
const char *cvalue;
|
||||
char *value = NULL;
|
||||
gint64 chan = 0;
|
||||
guint64 chan = 0;
|
||||
NMSettingMacRandomization mac_randomization;
|
||||
NMSettingWirelessPowersave powersave = NM_SETTING_WIRELESS_POWERSAVE_DEFAULT;
|
||||
NMTernary ternary;
|
||||
|
|
@ -4502,7 +4502,7 @@ make_wireless_setting(shvarFile *ifcfg, GError **error)
|
|||
|
||||
value = svGetValueStr_cp(ifcfg, "CHANNEL");
|
||||
if (value) {
|
||||
chan = _nm_utils_ascii_str_to_int64(value, 10, 1, 196, 0);
|
||||
chan = _nm_utils_ascii_str_to_int64(value, 10, 1, _NM_WIFI_CHANNEL_MAX, 0);
|
||||
if (chan == 0) {
|
||||
g_set_error(error,
|
||||
NM_SETTINGS_ERROR,
|
||||
|
|
@ -4518,44 +4518,47 @@ make_wireless_setting(shvarFile *ifcfg, GError **error)
|
|||
|
||||
value = svGetValueStr_cp(ifcfg, "BAND");
|
||||
if (value) {
|
||||
if (!strcmp(value, "a")) {
|
||||
if (chan && chan <= 14) {
|
||||
g_set_error(error,
|
||||
NM_SETTINGS_ERROR,
|
||||
NM_SETTINGS_ERROR_INVALID_CONNECTION,
|
||||
"Band '%s' invalid for channel %u",
|
||||
value,
|
||||
(guint32) chan);
|
||||
g_free(value);
|
||||
goto error;
|
||||
}
|
||||
} else if (!strcmp(value, "bg")) {
|
||||
if (chan && chan > 14) {
|
||||
g_set_error(error,
|
||||
NM_SETTINGS_ERROR,
|
||||
NM_SETTINGS_ERROR_INVALID_CONNECTION,
|
||||
"Band '%s' invalid for channel %u",
|
||||
value,
|
||||
(guint32) chan);
|
||||
g_free(value);
|
||||
goto error;
|
||||
}
|
||||
} else {
|
||||
if (!NM_IN_STRSET(value, "a", "bg", "6GHz")) {
|
||||
g_set_error(error,
|
||||
NM_SETTINGS_ERROR,
|
||||
NM_SETTINGS_ERROR_INVALID_CONNECTION,
|
||||
"Invalid wireless band '%s'",
|
||||
"Band '%s' invalid",
|
||||
value);
|
||||
g_free(value);
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (chan) {
|
||||
if (!nm_utils_wifi_is_channel_valid(chan, value)) {
|
||||
g_set_error(error,
|
||||
NM_SETTINGS_ERROR,
|
||||
NM_SETTINGS_ERROR_INVALID_CONNECTION,
|
||||
"Band '%s' invalid for channel %u",
|
||||
value,
|
||||
(guint32) chan);
|
||||
g_free(value);
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
g_object_set(s_wireless, NM_SETTING_WIRELESS_BAND, value, NULL);
|
||||
g_free(value);
|
||||
} else if (chan > 0) {
|
||||
if (chan > 14)
|
||||
if (chan > _NM_WIFI_CHANNEL_MAX_5GHZ) {
|
||||
g_set_error(error,
|
||||
NM_SETTINGS_ERROR,
|
||||
NM_SETTINGS_ERROR_INVALID_CONNECTION,
|
||||
"Setting channel without band is ambiguous and deprecated. Not supported "
|
||||
"for 6GHz.");
|
||||
g_free(value);
|
||||
goto error;
|
||||
} else if (chan > _NM_WIFI_CHANNEL_MAX_2GHZ) {
|
||||
PARSE_WARNING(
|
||||
"Setting channel without band is ambiguous and deprecated. Assuming band 'a'.");
|
||||
g_object_set(s_wireless, NM_SETTING_WIRELESS_BAND, "a", NULL);
|
||||
else
|
||||
} else {
|
||||
g_object_set(s_wireless, NM_SETTING_WIRELESS_BAND, "bg", NULL);
|
||||
}
|
||||
}
|
||||
|
||||
value = svGetValueStr_cp(ifcfg, "MTU");
|
||||
|
|
|
|||
|
|
@ -849,7 +849,7 @@ write_wireless_setting(NMConnection *connection,
|
|||
GBytes *ssid;
|
||||
const guint8 *ssid_data;
|
||||
gsize ssid_len;
|
||||
const char *mode, *bssid;
|
||||
const char *mode, *bssid, *band;
|
||||
const char *device_mac, *cloned_mac;
|
||||
guint32 mtu, chan, i;
|
||||
gboolean adhoc = FALSE, hex_ssid = FALSE;
|
||||
|
|
@ -968,9 +968,11 @@ write_wireless_setting(NMConnection *connection,
|
|||
chan = nm_setting_wireless_get_channel(s_wireless);
|
||||
if (chan) {
|
||||
svSetValueInt64(ifcfg, "CHANNEL", chan);
|
||||
} else {
|
||||
/* Band only set if channel is not, since channel implies band */
|
||||
svSetValueStr(ifcfg, "BAND", nm_setting_wireless_get_band(s_wireless));
|
||||
}
|
||||
|
||||
band = nm_setting_wireless_get_band(s_wireless);
|
||||
if (band) {
|
||||
svSetValueStr(ifcfg, "BAND", band);
|
||||
}
|
||||
|
||||
bssid = nm_setting_wireless_get_bssid(s_wireless);
|
||||
|
|
@ -3598,6 +3600,7 @@ do_write_construct(NMConnection *connection,
|
|||
} else
|
||||
route_ignore = FALSE;
|
||||
|
||||
/* Unsupported properties */
|
||||
if ((s_ip4 = nm_connection_get_setting_ip4_config(connection))) {
|
||||
if (nm_setting_ip_config_get_dhcp_dscp(s_ip4)) {
|
||||
set_error_unsupported(error,
|
||||
|
|
@ -3616,6 +3619,14 @@ do_write_construct(NMConnection *connection,
|
|||
FALSE);
|
||||
return FALSE;
|
||||
}
|
||||
if (nm_setting_ip4_config_get_clat(NM_SETTING_IP4_CONFIG(s_ip4))
|
||||
!= NM_SETTING_IP4_CONFIG_CLAT_DEFAULT) {
|
||||
set_error_unsupported(error,
|
||||
connection,
|
||||
NM_SETTING_IP4_CONFIG_SETTING_NAME "." NM_SETTING_IP4_CONFIG_CLAT,
|
||||
FALSE);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
write_ip4_setting(connection,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
ESSID=MySSID
|
||||
MODE=Ap
|
||||
CHANNEL=196
|
||||
CHANNEL=52
|
||||
BAND=a
|
||||
MAC_ADDRESS_RANDOMIZATION=default
|
||||
AP_ISOLATION=yes
|
||||
TYPE=Wireless
|
||||
|
|
|
|||
|
|
@ -0,0 +1,18 @@
|
|||
ESSID="Test SSID"
|
||||
MODE=Managed
|
||||
BAND=6GHz
|
||||
MAC_ADDRESS_RANDOMIZATION=default
|
||||
TYPE=Wireless
|
||||
PROXY_METHOD=none
|
||||
BROWSER_ONLY=no
|
||||
BOOTPROTO=dhcp
|
||||
DEFROUTE=yes
|
||||
IPV4_FAILURE_FATAL=no
|
||||
IPV6INIT=yes
|
||||
IPV6_AUTOCONF=yes
|
||||
IPV6_DEFROUTE=yes
|
||||
IPV6_FAILURE_FATAL=no
|
||||
IPV6_ADDR_GEN_MODE=default
|
||||
NAME="Test Write Wi-Fi Band 6GHz"
|
||||
UUID=${UUID}
|
||||
ONBOOT=yes
|
||||
|
|
@ -13,6 +13,6 @@ IPV6_AUTOCONF=yes
|
|||
IPV6_DEFROUTE=yes
|
||||
IPV6_FAILURE_FATAL=no
|
||||
IPV6_ADDR_GEN_MODE=default
|
||||
NAME="Test Write Wi-Fi Band A"
|
||||
NAME="Test Write Wi-Fi Band A - 5GHz"
|
||||
UUID=${UUID}
|
||||
ONBOOT=yes
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
TYPE=Wireless
|
||||
DEVICE=eth2
|
||||
HWADDR=00:16:41:11:22:33
|
||||
NM_CONTROLLED=yes
|
||||
BOOTPROTO=dhcp
|
||||
ESSID=blahblah
|
||||
BAND=6GHz
|
||||
MODE=Managed
|
||||
RATE=auto
|
||||
ONBOOT=yes
|
||||
USERCTL=yes
|
||||
PEERDNS=yes
|
||||
IPV6INIT=no
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
TYPE=Wireless
|
||||
DEVICE=eth2
|
||||
HWADDR=00:16:41:11:22:33
|
||||
BOOTPROTO=dhcp
|
||||
ESSID=blahblah
|
||||
CHANNEL=14
|
||||
BAND=6GHz
|
||||
MODE=Managed
|
||||
|
||||
|
|
@ -3991,7 +3991,7 @@ test_write_wifi_band_a(void)
|
|||
s_con = _nm_connection_new_setting(connection, NM_TYPE_SETTING_CONNECTION);
|
||||
g_object_set(s_con,
|
||||
NM_SETTING_CONNECTION_ID,
|
||||
"Test Write Wi-Fi Band A",
|
||||
"Test Write Wi-Fi Band A - 5GHz",
|
||||
NM_SETTING_CONNECTION_UUID,
|
||||
nm_uuid_generate_random_str_a(),
|
||||
NM_SETTING_CONNECTION_TYPE,
|
||||
|
|
@ -4012,7 +4012,7 @@ test_write_wifi_band_a(void)
|
|||
|
||||
_writer_new_connec_exp(connection,
|
||||
TEST_SCRATCH_DIR,
|
||||
TEST_IFCFG_DIR "/ifcfg-Test_Write_WiFi_Band_A.cexpected",
|
||||
TEST_IFCFG_DIR "/ifcfg-Test_Write_WiFi_Band_a.cexpected",
|
||||
&testfile);
|
||||
|
||||
f = _svOpenFile(testfile);
|
||||
|
|
@ -4024,6 +4024,77 @@ test_write_wifi_band_a(void)
|
|||
nmtst_assert_connection_equals(connection, TRUE, reread, FALSE);
|
||||
}
|
||||
|
||||
static void
|
||||
test_read_wifi_band_6ghz(void)
|
||||
{
|
||||
gs_unref_object NMConnection *connection = NULL;
|
||||
NMSettingConnection *s_con;
|
||||
NMSettingWireless *s_wifi;
|
||||
|
||||
connection = _connection_from_file(TEST_IFCFG_DIR "/ifcfg-test-wifi-band-6ghz",
|
||||
NULL,
|
||||
TYPE_WIRELESS,
|
||||
NULL);
|
||||
|
||||
s_con = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_CONNECTION);
|
||||
g_assert_cmpstr(nm_setting_connection_get_connection_type(s_con),
|
||||
==,
|
||||
NM_SETTING_WIRELESS_SETTING_NAME);
|
||||
|
||||
s_wifi = nmtst_connection_assert_setting(connection, NM_TYPE_SETTING_WIRELESS);
|
||||
g_assert_cmpstr(nm_setting_wireless_get_band(s_wifi), ==, "6GHz");
|
||||
}
|
||||
|
||||
static void
|
||||
test_write_wifi_band_6ghz(void)
|
||||
{
|
||||
nmtst_auto_unlinkfile char *testfile = NULL;
|
||||
gs_unref_object NMConnection *connection = NULL;
|
||||
gs_unref_object NMConnection *reread = NULL;
|
||||
NMSettingConnection *s_con;
|
||||
NMSettingWireless *s_wifi;
|
||||
shvarFile *f;
|
||||
gs_unref_bytes GBytes *ssid =
|
||||
nmtst_gbytes_from_arr(0x54, 0x65, 0x73, 0x74, 0x20, 0x53, 0x53, 0x49, 0x44);
|
||||
|
||||
connection = nm_simple_connection_new();
|
||||
|
||||
s_con = _nm_connection_new_setting(connection, NM_TYPE_SETTING_CONNECTION);
|
||||
g_object_set(s_con,
|
||||
NM_SETTING_CONNECTION_ID,
|
||||
"Test Write Wi-Fi Band 6GHz",
|
||||
NM_SETTING_CONNECTION_UUID,
|
||||
nm_uuid_generate_random_str_a(),
|
||||
NM_SETTING_CONNECTION_TYPE,
|
||||
NM_SETTING_WIRELESS_SETTING_NAME,
|
||||
NULL);
|
||||
|
||||
s_wifi = _nm_connection_new_setting(connection, NM_TYPE_SETTING_WIRELESS);
|
||||
g_object_set(s_wifi,
|
||||
NM_SETTING_WIRELESS_SSID,
|
||||
ssid,
|
||||
NM_SETTING_WIRELESS_MODE,
|
||||
"infrastructure",
|
||||
NM_SETTING_WIRELESS_BAND,
|
||||
"6GHz",
|
||||
NULL);
|
||||
|
||||
nmtst_assert_connection_verifies(connection);
|
||||
|
||||
_writer_new_connec_exp(connection,
|
||||
TEST_SCRATCH_DIR,
|
||||
TEST_IFCFG_DIR "/ifcfg-Test_Write_WiFi_Band_6ghz.cexpected",
|
||||
&testfile);
|
||||
|
||||
f = _svOpenFile(testfile);
|
||||
_svGetValue_check(f, "BAND", "6GHz");
|
||||
svCloseFile(f);
|
||||
|
||||
reread = _connection_from_file(testfile, NULL, TYPE_WIRELESS, NULL);
|
||||
|
||||
nmtst_assert_connection_equals(connection, TRUE, reread, FALSE);
|
||||
}
|
||||
|
||||
static void
|
||||
test_write_wifi_ap_mode(void)
|
||||
{
|
||||
|
|
@ -4055,7 +4126,7 @@ test_write_wifi_ap_mode(void)
|
|||
NM_SETTING_WIRELESS_BAND,
|
||||
"a",
|
||||
NM_SETTING_WIRELESS_CHANNEL,
|
||||
(guint) 196,
|
||||
(guint) 52,
|
||||
NM_SETTING_WIRELESS_AP_ISOLATION,
|
||||
NM_TERNARY_TRUE,
|
||||
NULL);
|
||||
|
|
@ -4072,6 +4143,18 @@ test_write_wifi_ap_mode(void)
|
|||
nmtst_assert_connection_equals(connection, TRUE, reread, FALSE);
|
||||
}
|
||||
|
||||
static void
|
||||
test_read_wifi_band_6ghz_channel_mismatch(void)
|
||||
{
|
||||
gs_free_error GError *error = NULL;
|
||||
|
||||
_connection_from_file_fail(TEST_IFCFG_DIR "/ifcfg-test-wifi-band-6ghz-channel-mismatch",
|
||||
NULL,
|
||||
TYPE_WIRELESS,
|
||||
&error);
|
||||
g_assert_error(error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION);
|
||||
}
|
||||
|
||||
static void
|
||||
test_read_wifi_band_a_channel_mismatch(void)
|
||||
{
|
||||
|
|
@ -10680,6 +10763,9 @@ main(int argc, char **argv)
|
|||
test_read_wifi_band_a_channel_mismatch);
|
||||
g_test_add_func(TPATH "wifi/read-band-bg-channel-mismatch",
|
||||
test_read_wifi_band_bg_channel_mismatch);
|
||||
g_test_add_func(TPATH "wifi/read-band-6ghz", test_read_wifi_band_6ghz);
|
||||
g_test_add_func(TPATH "wifi/read-band-6ghz-channel-mismatch",
|
||||
test_read_wifi_band_6ghz_channel_mismatch);
|
||||
g_test_add_func(TPATH "wifi/read-hidden", test_read_wifi_hidden);
|
||||
|
||||
nmtst_add_test_func(TPATH "wifi/read-mac-random-always",
|
||||
|
|
@ -10852,6 +10938,7 @@ main(int argc, char **argv)
|
|||
test_write_wifi_wpa_then_wep_with_perms);
|
||||
g_test_add_func(TPATH "wifi/write-hidden", test_write_wifi_hidden);
|
||||
g_test_add_func(TPATH "wifi/write-band-a", test_write_wifi_band_a);
|
||||
g_test_add_func(TPATH "wifi/write-band-6ghz", test_write_wifi_band_6ghz);
|
||||
g_test_add_func(TPATH "wifi/write-ap-mode", test_write_wifi_ap_mode);
|
||||
|
||||
g_test_add_func(TPATH "s390/read-qeth-static", test_read_wired_qeth_static);
|
||||
|
|
|
|||
|
|
@ -373,14 +373,24 @@ nm_supplicant_config_get_blobs(NMSupplicantConfig *self)
|
|||
}
|
||||
|
||||
static const char *
|
||||
wifi_freqs_to_string(gboolean bg_band)
|
||||
wifi_freqs_to_string(const char *band)
|
||||
{
|
||||
static const char *str_2ghz = NULL;
|
||||
static const char *str_5ghz = NULL;
|
||||
static const char *str_6ghz = NULL;
|
||||
const char **f_p;
|
||||
const char *f;
|
||||
|
||||
f_p = bg_band ? &str_2ghz : &str_5ghz;
|
||||
if (nm_streq0(band, "a"))
|
||||
f_p = &str_5ghz;
|
||||
else if (nm_streq0(band, "bg"))
|
||||
f_p = &str_2ghz;
|
||||
else if (nm_streq0(band, "6GHz"))
|
||||
f_p = &str_6ghz;
|
||||
else {
|
||||
nm_assert_not_reached();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
again:
|
||||
f = g_atomic_pointer_get(f_p);
|
||||
|
|
@ -390,7 +400,13 @@ again:
|
|||
const guint *freqs;
|
||||
int i;
|
||||
|
||||
freqs = bg_band ? nm_utils_wifi_2ghz_freqs() : nm_utils_wifi_5ghz_freqs();
|
||||
if (f_p == &str_2ghz)
|
||||
freqs = nm_utils_wifi_2ghz_freqs();
|
||||
else if (f_p == &str_5ghz)
|
||||
freqs = nm_utils_wifi_5ghz_freqs();
|
||||
else
|
||||
freqs = nm_utils_wifi_6ghz_freqs();
|
||||
|
||||
for (i = 0; freqs[i]; i++) {
|
||||
if (i > 0)
|
||||
nm_str_buf_append_c(&strbuf, ' ');
|
||||
|
|
@ -533,38 +549,47 @@ get_ap_params(guint freq,
|
|||
guint channel;
|
||||
guint center_channel = 0;
|
||||
|
||||
if (freq < 5000) {
|
||||
/* the setting is not valid */
|
||||
nm_assert_not_reached();
|
||||
return;
|
||||
}
|
||||
|
||||
/* Determine the center channel according to the table at
|
||||
* https://en.wikipedia.org/wiki/List_of_WLAN_channels */
|
||||
|
||||
channel = (freq - 5000) / 5;
|
||||
if (freq > 5950) {
|
||||
/* 6 GHz */
|
||||
channel = (freq - 5950) / 5;
|
||||
channel = ((channel - 1) / 16) * 16 + 7;
|
||||
|
||||
if (channel >= 36 && channel <= 48)
|
||||
center_channel = 42;
|
||||
else if (channel >= 52 && channel <= 64)
|
||||
center_channel = 58;
|
||||
else if (channel >= 100 && channel <= 112)
|
||||
center_channel = 106;
|
||||
else if (channel >= 116 && channel <= 128)
|
||||
center_channel = 122;
|
||||
else if (channel >= 132 && channel <= 144)
|
||||
center_channel = 138;
|
||||
else if (channel >= 149 && channel <= 161)
|
||||
center_channel = 155;
|
||||
else if (channel >= 165 && channel <= 177)
|
||||
center_channel = 171;
|
||||
|
||||
if (center_channel) {
|
||||
*out_ht40 = 1;
|
||||
*out_max_oper_chwidth = 1;
|
||||
*out_center_freq = 5000 + 5 * center_channel;
|
||||
}
|
||||
*out_center_freq = 5950 + 5 * channel;
|
||||
} else {
|
||||
/* 5 GHz */
|
||||
if (freq < 5000) {
|
||||
/* the setting is not valid */
|
||||
nm_assert_not_reached();
|
||||
return;
|
||||
}
|
||||
channel = (freq - 5000) / 5;
|
||||
|
||||
if (channel >= 36 && channel <= 48)
|
||||
center_channel = 42;
|
||||
else if (channel >= 52 && channel <= 64)
|
||||
center_channel = 58;
|
||||
else if (channel >= 100 && channel <= 112)
|
||||
center_channel = 106;
|
||||
else if (channel >= 116 && channel <= 128)
|
||||
center_channel = 122;
|
||||
else if (channel >= 132 && channel <= 144)
|
||||
center_channel = 138;
|
||||
else if (channel >= 149 && channel <= 161)
|
||||
center_channel = 155;
|
||||
else if (channel >= 165 && channel <= 177)
|
||||
center_channel = 171;
|
||||
|
||||
if (center_channel) {
|
||||
*out_ht40 = 1;
|
||||
*out_max_oper_chwidth = 1;
|
||||
*out_center_freq = 5000 + 5 * center_channel;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -711,10 +736,7 @@ nm_supplicant_config_add_setting_wireless(NMSupplicantConfig *self,
|
|||
} else {
|
||||
const char *freqs = NULL;
|
||||
|
||||
if (nm_streq(band, "a"))
|
||||
freqs = wifi_freqs_to_string(FALSE);
|
||||
else if (nm_streq(band, "bg"))
|
||||
freqs = wifi_freqs_to_string(TRUE);
|
||||
freqs = wifi_freqs_to_string(band);
|
||||
|
||||
if (freqs
|
||||
&& !nm_supplicant_config_add_option(self,
|
||||
|
|
|
|||
|
|
@ -67,6 +67,7 @@ enum {
|
|||
GROUP_STARTED, /* a new Group (interface) was created */
|
||||
GROUP_FINISHED, /* a Group (interface) has been finished */
|
||||
PSK_MISMATCH, /* supplicant reported incorrect PSK */
|
||||
SAE_MISMATCH, /* supplicant reported incorrect SAE Password */
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
|
|
@ -3237,6 +3238,11 @@ _signal_handle(NMSupplicantInterface *self,
|
|||
g_signal_emit(self, signals[PSK_MISMATCH], 0);
|
||||
return;
|
||||
}
|
||||
|
||||
if (nm_streq(signal_name, "SaePasswordMismatch")) {
|
||||
g_signal_emit(self, signals[SAE_MISMATCH], 0);
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -3879,4 +3885,13 @@ nm_supplicant_interface_class_init(NMSupplicantInterfaceClass *klass)
|
|||
NULL,
|
||||
G_TYPE_NONE,
|
||||
0);
|
||||
signals[SAE_MISMATCH] = g_signal_new(NM_SUPPLICANT_INTERFACE_SAE_MISMATCH,
|
||||
G_OBJECT_CLASS_TYPE(object_class),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
0,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
G_TYPE_NONE,
|
||||
0);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -87,6 +87,7 @@ typedef enum {
|
|||
#define NM_SUPPLICANT_INTERFACE_GROUP_STARTED "group-started"
|
||||
#define NM_SUPPLICANT_INTERFACE_GROUP_FINISHED "group-finished"
|
||||
#define NM_SUPPLICANT_INTERFACE_PSK_MISMATCH "wpa-psk-mismatch"
|
||||
#define NM_SUPPLICANT_INTERFACE_SAE_MISMATCH "wpa-sae-password-mismatch"
|
||||
|
||||
typedef struct _NMSupplicantInterfaceClass NMSupplicantInterfaceClass;
|
||||
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
#include "src/core/nm-default-daemon.h"
|
||||
|
||||
#include "nm-supplicant-settings-verify.h"
|
||||
#include "libnm-core-aux-intern/nm-libnm-core-utils.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
|
@ -71,7 +72,7 @@ static const struct Opt opt_table[] = {
|
|||
OPT_BYTES("engine_id", 0),
|
||||
OPT_INT("fragment_size", 1, 2000),
|
||||
OPT_KEYWORD("freq_list", NULL),
|
||||
OPT_INT("frequency", 2412, 5825),
|
||||
OPT_INT("frequency", _NM_WIFI_FREQ_MIN, _NM_WIFI_FREQ_MAX),
|
||||
OPT_KEYWORD("group", NM_MAKE_STRV("CCMP", "TKIP", "WEP104", "WEP40", "GCMP-256", )),
|
||||
OPT_INT("ht40", 0, 1),
|
||||
OPT_BYTES("identity", 0),
|
||||
|
|
@ -212,18 +213,19 @@ validate_type_utf8(const struct Opt *opt, const char *value, const guint32 len)
|
|||
}
|
||||
|
||||
static gboolean
|
||||
validate_type_keyword(const struct Opt *opt, const char *value, const guint32 len)
|
||||
validate_type_keyword(const struct Opt *opt, const char *value_in, const guint32 len)
|
||||
{
|
||||
gs_free char *value_free = NULL;
|
||||
char *value;
|
||||
|
||||
nm_assert(opt);
|
||||
nm_assert(value);
|
||||
nm_assert(value_in);
|
||||
|
||||
/* Allow everything */
|
||||
if (!opt->str_allowed)
|
||||
return TRUE;
|
||||
|
||||
value = nm_strndup_a(300, value, len, &value_free);
|
||||
value = nm_strndup_a(300, value_in, len, &value_free);
|
||||
|
||||
/* validate each space-separated word in 'value' */
|
||||
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
#include <net/if.h>
|
||||
#include <byteswap.h>
|
||||
#include <netinet/ip6.h>
|
||||
|
||||
/* need math.h for isinf() and INFINITY. No need to link with -lm */
|
||||
#include <math.h>
|
||||
|
|
@ -2770,6 +2771,56 @@ test_nm_firewall_nft_stdio_mlag(void)
|
|||
"nm-mlag-bond0\012delete table netdev nm-mlag-bond0\012");
|
||||
}
|
||||
|
||||
static void
|
||||
test_icmp6_checksum(void)
|
||||
{
|
||||
struct ip6_hdr ip6h = {};
|
||||
guint8 *data;
|
||||
guint16 c;
|
||||
|
||||
ip6h.ip6_src = NM_IN6ADDR_INIT(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
|
||||
ip6h.ip6_dst = NM_IN6ADDR_INIT(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
|
||||
data = (guint8[]) {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
|
||||
c = nm_utils_icmp6_checksum(&ip6h.ip6_src, 12, data);
|
||||
g_assert_cmpint(c, ==, htons(0xffb9));
|
||||
|
||||
ip6h.ip6_src = NM_IN6ADDR_INIT(0xfe,
|
||||
0x80,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0xc0,
|
||||
0x60,
|
||||
0x8c,
|
||||
0xaf,
|
||||
0xf6,
|
||||
0x9b,
|
||||
0xe4,
|
||||
0x1a);
|
||||
ip6h.ip6_dst = NM_IN6ADDR_INIT(0x20,
|
||||
0x02,
|
||||
0xaa,
|
||||
0xaa,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x64,
|
||||
0xd4,
|
||||
0x29,
|
||||
0x32,
|
||||
0x35,
|
||||
0x85,
|
||||
0x7c,
|
||||
0x89);
|
||||
data = (guint8[]) {0xdc, 0x74, 0x1a, 0xcc, 0xd3, 0x8e, 0xca, 0x34};
|
||||
c = nm_utils_icmp6_checksum(&ip6h.ip6_src, 8, data);
|
||||
g_assert_cmpint(c, ==, htons(0x39af));
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
NMTST_DEFINE();
|
||||
|
|
@ -2848,5 +2899,7 @@ main(int argc, char **argv)
|
|||
|
||||
g_test_add_func("/core/test_nm_firewall_nft_stdio_mlag", test_nm_firewall_nft_stdio_mlag);
|
||||
|
||||
g_test_add_func("/core/general/test_icmp6_checksum", test_icmp6_checksum);
|
||||
|
||||
return g_test_run();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -53,6 +53,44 @@ test_ip_reservation_shared4(void)
|
|||
}
|
||||
}
|
||||
|
||||
static void
|
||||
test_ip_reservation_clat(void)
|
||||
{
|
||||
gs_unref_object NMPlatform *platform = NULL;
|
||||
gs_unref_object NMNetns *netns = NULL;
|
||||
NMNetnsIPReservation *res[8];
|
||||
NMNetnsIPReservation *res1;
|
||||
char buf[NM_INET_ADDRSTRLEN];
|
||||
guint i;
|
||||
|
||||
platform = g_object_ref(NM_PLATFORM_GET);
|
||||
netns = nm_netns_new(platform);
|
||||
|
||||
/* Allocate addresses 192.0.0.{5,6,7,0,1,2,3,4} */
|
||||
for (i = 0; i < 8; i++) {
|
||||
res[i] = nm_netns_ip_reservation_get(netns, NM_NETNS_IP_RESERVATION_TYPE_CLAT);
|
||||
g_snprintf(buf, sizeof(buf), "192.0.0.%u", (i + 5) % 8);
|
||||
nmtst_assert_ip4_address(res[i]->addr, buf);
|
||||
g_assert_cmpint(res[i]->_ref_count, ==, 1);
|
||||
}
|
||||
|
||||
/* Release an address and get it back */
|
||||
nm_netns_ip_reservation_release(res[2]);
|
||||
res[2] = nm_netns_ip_reservation_get(netns, NM_NETNS_IP_RESERVATION_TYPE_CLAT);
|
||||
nmtst_assert_ip4_address(res[2]->addr, "192.0.0.7");
|
||||
|
||||
/* No reuse */
|
||||
NMTST_EXPECT_NM_ERROR("netns[*]: clat: ran out of IP addresses");
|
||||
res1 = nm_netns_ip_reservation_get(netns, NM_NETNS_IP_RESERVATION_TYPE_CLAT);
|
||||
g_test_assert_expected_messages();
|
||||
g_assert_null(res1);
|
||||
|
||||
/* Release all */
|
||||
for (i = 0; i < 8; i++) {
|
||||
nm_netns_ip_reservation_release(res[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
NMTST_DEFINE();
|
||||
|
|
@ -64,6 +102,7 @@ main(int argc, char **argv)
|
|||
nm_linux_platform_setup();
|
||||
|
||||
g_test_add_func("/netns/ip_reservation/shared4", test_ip_reservation_shared4);
|
||||
g_test_add_func("/netns/ip_reservation/clat", test_ip_reservation_clat);
|
||||
|
||||
return g_test_run();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -60,16 +60,21 @@ nm_vpn_manager_activate_connection(NMVpnManager *manager, NMVpnConnection *vpn,
|
|||
{
|
||||
NMVpnManagerPrivate *priv;
|
||||
NMVpnPluginInfo *plugin_info;
|
||||
NMConnection *applied;
|
||||
const char *service_name;
|
||||
NMDevice *device;
|
||||
const char *user;
|
||||
|
||||
g_return_val_if_fail(NM_IS_VPN_MANAGER(manager), FALSE);
|
||||
g_return_val_if_fail(NM_IS_VPN_CONNECTION(vpn), FALSE);
|
||||
g_return_val_if_fail(!error || !*error, FALSE);
|
||||
|
||||
priv = NM_VPN_MANAGER_GET_PRIVATE(manager);
|
||||
device = nm_active_connection_get_device(NM_ACTIVE_CONNECTION(vpn));
|
||||
g_assert(device);
|
||||
priv = NM_VPN_MANAGER_GET_PRIVATE(manager);
|
||||
device = nm_active_connection_get_device(NM_ACTIVE_CONNECTION(vpn));
|
||||
applied = nm_active_connection_get_applied_connection(NM_ACTIVE_CONNECTION(vpn));
|
||||
nm_assert(device);
|
||||
nm_assert(applied);
|
||||
|
||||
if (nm_device_get_state(device) != NM_DEVICE_STATE_ACTIVATED
|
||||
&& nm_device_get_state(device) != NM_DEVICE_STATE_SECONDARIES) {
|
||||
g_set_error_literal(error,
|
||||
|
|
@ -101,6 +106,30 @@ nm_vpn_manager_activate_connection(NMVpnManager *manager, NMVpnConnection *vpn,
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
user = nm_utils_get_connection_first_permissions_user(applied);
|
||||
if (user) {
|
||||
NMSettingConnection *s_con;
|
||||
|
||||
s_con = nm_connection_get_setting_connection(applied);
|
||||
nm_assert(s_con);
|
||||
if (_nm_setting_connection_get_num_permissions_users(s_con) > 1) {
|
||||
g_set_error_literal(error,
|
||||
NM_MANAGER_ERROR,
|
||||
NM_MANAGER_ERROR_CONNECTION_NOT_AVAILABLE,
|
||||
"private VPN connections with multiple users are not allowed.");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!nm_vpn_plugin_info_supports_safe_private_file_access(plugin_info)) {
|
||||
g_set_error(error,
|
||||
NM_MANAGER_ERROR,
|
||||
NM_MANAGER_ERROR_CONNECTION_NOT_AVAILABLE,
|
||||
"The '%s' plugin doesn't support private connections.",
|
||||
nm_vpn_plugin_info_get_name(plugin_info));
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
nm_vpn_connection_activate(vpn, plugin_info);
|
||||
|
||||
if (!nm_vpn_plugin_info_supports_multiple(plugin_info)) {
|
||||
|
|
|
|||
|
|
@ -345,6 +345,7 @@ typedef enum {
|
|||
NM_IP_CONFIG_SOURCE_VPN,
|
||||
NM_IP_CONFIG_SOURCE_DHCP,
|
||||
NM_IP_CONFIG_SOURCE_NDISC,
|
||||
NM_IP_CONFIG_SOURCE_CLAT,
|
||||
NM_IP_CONFIG_SOURCE_USER,
|
||||
} NMIPConfigSource;
|
||||
|
||||
|
|
|
|||
|
|
@ -65,6 +65,7 @@
|
|||
|
||||
#define NM_CONFIG_KEYFILE_KEY_DEVICE_MANAGED "managed"
|
||||
#define NM_CONFIG_KEYFILE_KEY_DEVICE_IGNORE_CARRIER "ignore-carrier"
|
||||
#define NM_CONFIG_KEYFILE_KEY_DEVICE_CHECK_CONNECTIVITY "check-connectivity"
|
||||
#define NM_CONFIG_KEYFILE_KEY_DEVICE_SRIOV_NUM_VFS "sriov-num-vfs"
|
||||
#define NM_CONFIG_KEYFILE_KEY_DEVICE_KEEP_CONFIGURATION "keep-configuration"
|
||||
#define NM_CONFIG_KEYFILE_KEY_DEVICE_ALLOWED_CONNECTIONS "allowed-connections"
|
||||
|
|
|
|||
|
|
@ -2103,3 +2103,14 @@ global:
|
|||
nm_utils_copy_cert_as_user;
|
||||
nm_vpn_plugin_info_supports_safe_private_file_access;
|
||||
} libnm_1_54_0;
|
||||
|
||||
libnm_1_58_0 {
|
||||
global:
|
||||
nm_ip_config_get_clat_address;
|
||||
nm_ip_config_get_clat_pref64;
|
||||
nm_setting_ip4_config_clat_get_type;
|
||||
nm_setting_ip4_config_get_clat;
|
||||
nm_utils_wifi_6ghz_freqs;
|
||||
nm_utils_wifi_freq_to_band;
|
||||
nm_wifi_band_get_type;
|
||||
} libnm_1_56_0;
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
|
||||
#include "nm-dbus-interface.h"
|
||||
#include "nm-object-private.h"
|
||||
#include "libnm-core-aux-intern/nm-libnm-core-utils.h"
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
|
|
@ -338,11 +339,14 @@ nm_access_point_connection_valid(NMAccessPoint *ap, NMConnection *connection)
|
|||
ap_freq = nm_access_point_get_frequency(ap);
|
||||
if (ap_freq) {
|
||||
setting_band = nm_setting_wireless_get_band(s_wifi);
|
||||
if (g_strcmp0(setting_band, "a") == 0) {
|
||||
if (ap_freq < 4915 || ap_freq > 5825)
|
||||
if (nm_streq0(setting_band, "a")) {
|
||||
if (ap_freq < _NM_WIFI_FREQ_MIN_5GHZ || ap_freq > _NM_WIFI_FREQ_MAX_5GHZ)
|
||||
return FALSE;
|
||||
} else if (g_strcmp0(setting_band, "bg") == 0) {
|
||||
if (ap_freq < 2412 || ap_freq > 2484)
|
||||
} else if (nm_streq0(setting_band, "bg")) {
|
||||
if (ap_freq < _NM_WIFI_FREQ_MIN_2GHZ || ap_freq > _NM_WIFI_FREQ_MAX_2GHZ)
|
||||
return FALSE;
|
||||
} else if (nm_streq0(setting_band, "6GHz")) {
|
||||
if (ap_freq < _NM_WIFI_FREQ_MIN_6GHZ || ap_freq > _NM_WIFI_FREQ_MAX_6GHZ)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -26,7 +26,9 @@ NM_GOBJECT_PROPERTIES_DEFINE(NMIPConfig,
|
|||
PROP_NAMESERVERS,
|
||||
PROP_DOMAINS,
|
||||
PROP_SEARCHES,
|
||||
PROP_WINS_SERVERS, );
|
||||
PROP_WINS_SERVERS,
|
||||
PROP_CLAT_ADDRESS,
|
||||
PROP_CLAT_PREF64, );
|
||||
|
||||
typedef struct _NMIPConfigPrivate {
|
||||
GPtrArray *addresses;
|
||||
|
|
@ -36,6 +38,8 @@ typedef struct _NMIPConfigPrivate {
|
|||
char **searches;
|
||||
char **wins_servers;
|
||||
char *gateway;
|
||||
char *clat_address;
|
||||
char *clat_pref64;
|
||||
|
||||
bool addresses_new_style : 1;
|
||||
bool routes_new_style : 1;
|
||||
|
|
@ -256,6 +260,12 @@ get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
|
|||
case PROP_GATEWAY:
|
||||
g_value_set_string(value, nm_ip_config_get_gateway(self));
|
||||
break;
|
||||
case PROP_CLAT_ADDRESS:
|
||||
g_value_set_string(value, nm_ip_config_get_clat_address(self));
|
||||
break;
|
||||
case PROP_CLAT_PREF64:
|
||||
g_value_set_string(value, nm_ip_config_get_clat_pref64(self));
|
||||
break;
|
||||
case PROP_ADDRESSES:
|
||||
g_value_take_boxed(value,
|
||||
_nm_utils_copy_array(nm_ip_config_get_addresses(self),
|
||||
|
|
@ -307,6 +317,8 @@ finalize(GObject *object)
|
|||
NMIPConfigPrivate *priv = NM_IP_CONFIG_GET_PRIVATE(object);
|
||||
|
||||
g_free(priv->gateway);
|
||||
g_free(priv->clat_address);
|
||||
g_free(priv->clat_pref64);
|
||||
|
||||
g_ptr_array_unref(priv->routes);
|
||||
g_ptr_array_unref(priv->addresses);
|
||||
|
|
@ -333,6 +345,10 @@ const NMLDBusMetaIface _nml_dbus_meta_iface_nm_ip4config = NML_DBUS_META_IFACE_I
|
|||
"aau",
|
||||
_notify_update_prop_addresses,
|
||||
.obj_property_no_reverse_idx = TRUE),
|
||||
NML_DBUS_META_PROPERTY_INIT_S("ClatAddress",
|
||||
PROP_CLAT_ADDRESS,
|
||||
NMIPConfigPrivate,
|
||||
clat_address),
|
||||
NML_DBUS_META_PROPERTY_INIT_TODO("DnsOptions", "as"),
|
||||
NML_DBUS_META_PROPERTY_INIT_TODO("DnsPriority", "i"),
|
||||
NML_DBUS_META_PROPERTY_INIT_AS("Domains", PROP_DOMAINS, NMIPConfigPrivate, domains),
|
||||
|
|
@ -381,6 +397,14 @@ const NMLDBusMetaIface _nml_dbus_meta_iface_nm_ip6config = NML_DBUS_META_IFACE_I
|
|||
"a(ayuay)",
|
||||
_notify_update_prop_addresses,
|
||||
.obj_property_no_reverse_idx = TRUE),
|
||||
NML_DBUS_META_PROPERTY_INIT_S("ClatAddress",
|
||||
PROP_CLAT_ADDRESS,
|
||||
NMIPConfigPrivate,
|
||||
clat_address),
|
||||
NML_DBUS_META_PROPERTY_INIT_S("ClatPref64",
|
||||
PROP_CLAT_PREF64,
|
||||
NMIPConfigPrivate,
|
||||
clat_pref64),
|
||||
NML_DBUS_META_PROPERTY_INIT_TODO("DnsOptions", "as"),
|
||||
NML_DBUS_META_PROPERTY_INIT_TODO("DnsPriority", "i"),
|
||||
NML_DBUS_META_PROPERTY_INIT_AS("Domains", PROP_DOMAINS, NMIPConfigPrivate, domains),
|
||||
|
|
@ -436,6 +460,34 @@ nm_ip_config_class_init(NMIPConfigClass *config_class)
|
|||
NULL,
|
||||
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
|
||||
|
||||
/**
|
||||
* NMIPConfig:clat-address:
|
||||
*
|
||||
* The IP address used by CLAT.
|
||||
*
|
||||
* Since: 1.58
|
||||
**/
|
||||
obj_properties[PROP_CLAT_ADDRESS] =
|
||||
g_param_spec_string(NM_IP_CONFIG_CLAT_ADDRESS,
|
||||
"",
|
||||
"",
|
||||
NULL,
|
||||
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
|
||||
|
||||
/**
|
||||
* NMIPConfig:clat-pref64:
|
||||
*
|
||||
* The NAT64 prefix used by CLAT.
|
||||
*
|
||||
* Since: 1.58
|
||||
**/
|
||||
obj_properties[PROP_CLAT_PREF64] =
|
||||
g_param_spec_string(NM_IP_CONFIG_CLAT_PREF64,
|
||||
"",
|
||||
"",
|
||||
NULL,
|
||||
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
|
||||
|
||||
/**
|
||||
* NMIPConfig:addresses:
|
||||
*
|
||||
|
|
@ -543,6 +595,42 @@ nm_ip_config_get_gateway(NMIPConfig *config)
|
|||
return _nml_coerce_property_str_not_empty(NM_IP_CONFIG_GET_PRIVATE(config)->gateway);
|
||||
}
|
||||
|
||||
/**
|
||||
* nm_ip_config_get_clat_address:
|
||||
* @config: a #NMIPConfig
|
||||
*
|
||||
* Gets the CLAT IP address.
|
||||
*
|
||||
* Returns: (transfer none): the CLAT IP address.
|
||||
*
|
||||
* Since: 1.58
|
||||
**/
|
||||
const char *
|
||||
nm_ip_config_get_clat_address(NMIPConfig *config)
|
||||
{
|
||||
g_return_val_if_fail(NM_IS_IP_CONFIG(config), NULL);
|
||||
|
||||
return _nml_coerce_property_str_not_empty(NM_IP_CONFIG_GET_PRIVATE(config)->clat_address);
|
||||
}
|
||||
|
||||
/**
|
||||
* nm_ip_config_get_clat_pref64:
|
||||
* @config: a #NMIPConfig
|
||||
*
|
||||
* Gets the NAT64 prefix used by CLAT.
|
||||
*
|
||||
* Returns: (transfer none): the NAT64 prefix.
|
||||
*
|
||||
* Since: 1.58
|
||||
**/
|
||||
const char *
|
||||
nm_ip_config_get_clat_pref64(NMIPConfig *config)
|
||||
{
|
||||
g_return_val_if_fail(NM_IS_IP_CONFIG(config), NULL);
|
||||
|
||||
return _nml_coerce_property_str_not_empty(NM_IP_CONFIG_GET_PRIVATE(config)->clat_pref64);
|
||||
}
|
||||
|
||||
/**
|
||||
* nm_ip_config_get_addresses:
|
||||
* @config: a #NMIPConfig
|
||||
|
|
|
|||
|
|
@ -516,6 +516,8 @@ nm_utils_fixup_product_string(const char *desc)
|
|||
"Network Everywhere",
|
||||
"N Wireless",
|
||||
"N+ Wireless",
|
||||
"NBase-T/IEEE 802.3an",
|
||||
"NBase-T/IEEE 802.3bz",
|
||||
"OCT To Fast Ethernet Converter",
|
||||
"PC Card",
|
||||
"PCI Express",
|
||||
|
|
@ -575,6 +577,7 @@ nm_utils_fixup_product_string(const char *desc)
|
|||
"10/100M",
|
||||
"10/20-Gigabit",
|
||||
"10/25/40/50GbE",
|
||||
"10/25GbE",
|
||||
"10/40G",
|
||||
"10base-FL",
|
||||
"10BaseT",
|
||||
|
|
@ -585,6 +588,7 @@ nm_utils_fixup_product_string(const char *desc)
|
|||
"10Gb/25Gb/40Gb/50Gb",
|
||||
"10Gbase-T",
|
||||
"10GBase-T",
|
||||
"10GBase-T/NBASE-T",
|
||||
"10GBASE-T",
|
||||
"10GbE",
|
||||
"10Gbps",
|
||||
|
|
@ -600,6 +604,7 @@ nm_utils_fixup_product_string(const char *desc)
|
|||
"16Gbps/10Gbps",
|
||||
"1GbE",
|
||||
"1x2:2",
|
||||
"2.5GbE",
|
||||
"20GbE",
|
||||
"25Gb",
|
||||
"25GbE",
|
||||
|
|
@ -615,6 +620,8 @@ nm_utils_fixup_product_string(const char *desc)
|
|||
"54Mbps",
|
||||
"56k",
|
||||
"5G",
|
||||
"5GbE",
|
||||
"5GBase-T/NBASE-T",
|
||||
"802.11",
|
||||
"802.11a/b/g",
|
||||
"802.11abg",
|
||||
|
|
|
|||
|
|
@ -694,6 +694,10 @@ test_fixup_product_string(void)
|
|||
T_DATA("Allnet ALL0283 [AR5523]", "Allnet ALL0283"),
|
||||
T_DATA("Allnet ALL0283 [AR5523](no firmware)", "Allnet ALL0283"),
|
||||
T_DATA("Allnet ALL0298 v2 802.11bg", "Allnet ALL0298"),
|
||||
T_DATA("Alveo X3522, Quad Port, 10/25GbE Adaptable Accelerator Card",
|
||||
"Alveo X3522 Quad Port Adaptable Accelerator"),
|
||||
T_DATA("Alveo X3522, Quad Port, 10/25GbE Low Latency Network Adapter",
|
||||
"Alveo X3522 Quad Port Low Latency"),
|
||||
T_DATA("AM10 v1 802.11n [Ralink RT3072]", "AM10"),
|
||||
T_DATA("AMD-8111 Ethernet", "AMD-8111"),
|
||||
T_DATA("AN2720 USB-USB Bridge", "AN2720 USB-USB Bridge"),
|
||||
|
|
@ -704,6 +708,28 @@ test_fixup_product_string(void)
|
|||
T_DATA("ANA620xx/ANA69011A", "ANA620xx/ANA69011A"),
|
||||
T_DATA("AN-WF500 802.11abgn + BT Wireless Adapter [Broadcom BCM43242]", "AN-WF500"),
|
||||
T_DATA("Aolynk WUB320g", "Aolynk WUB320g"),
|
||||
T_DATA("AQtion AQC100 NBase-T/IEEE 802.3an Ethernet Controller [Atlantic 10G]",
|
||||
"AQtion AQC100"),
|
||||
T_DATA("AQtion AQC100S NBase-T/IEEE 802.3an Ethernet Controller [Atlantic 10G]",
|
||||
"AQtion AQC100S"),
|
||||
T_DATA("AQtion AQC107 NBase-T/IEEE 802.3an Ethernet Controller [Atlantic 10G]",
|
||||
"AQtion AQC107"),
|
||||
T_DATA("AQtion AQC107S NBase-T/IEEE 802.3an Ethernet Controller [Atlantic 10G]",
|
||||
"AQtion AQC107S"),
|
||||
T_DATA("AQC107 NBase-T/IEEE 802.3bz Ethernet Controller [AQtion]", "AQC107"),
|
||||
T_DATA("AQC108 NBase-T/IEEE 802.3bz Ethernet Controller [AQtion]", "AQC108"),
|
||||
T_DATA("AQC111 NBase-T/IEEE 802.3bz Ethernet Controller [AQtion]", "AQC111"),
|
||||
T_DATA("AQC112 NBase-T/IEEE 802.3bz Ethernet Controller [AQtion]", "AQC112"),
|
||||
T_DATA("AQtion AQC113 NBase-T/IEEE 802.3an Ethernet Controller [Antigua 10G]",
|
||||
"AQtion AQC113"),
|
||||
T_DATA("AQC113C NBase-T/IEEE 802.3an Ethernet Controller [Marvell Scalable mGig]",
|
||||
"AQC113C"),
|
||||
T_DATA("AQtion AQC113CS NBase-T/IEEE 802.3an Ethernet Controller [Antigua 10G]",
|
||||
"AQtion AQC113CS"),
|
||||
T_DATA("AQtion AQC114CS NBase-T/IEEE 802.3bz Ethernet Controller [Antigua 5G]",
|
||||
"AQtion AQC114CS"),
|
||||
T_DATA("AQtion AQC115C NBase-T/IEEE 802.3bz Ethernet Controller [Antigua 2.5G]",
|
||||
"AQtion AQC115C"),
|
||||
T_DATA("AR2413/AR2414 Wireless Network Adapter [AR5005G(S) 802.11bg]", "AR2413/AR2414"),
|
||||
T_DATA("AR2417 Wireless Network Adapter [AR5007G 802.11bg]", "AR2417"),
|
||||
T_DATA("AR2425 Wireless Network Adapter [AR5007EG 802.11bg]", "AR2425"),
|
||||
|
|
@ -1684,6 +1710,9 @@ test_fixup_product_string(void)
|
|||
T_DATA("RTL8101/2/6E PCI Express Fast/Gigabit Ethernet controller", "RTL8101/2/6E"),
|
||||
T_DATA("RTL-8110SC/8169SC Gigabit Ethernet", "RTL-8110SC/8169SC"),
|
||||
T_DATA("RTL8111/8168/8411 PCI Express Gigabit Ethernet Controller", "RTL8111/8168/8411"),
|
||||
T_DATA("RTL8125 2.5GbE Controller", "RTL8125"),
|
||||
T_DATA("RTL8126 5GbE Controller", "RTL8126"),
|
||||
T_DATA("RTL8127 10GbE Controller", "RTL8127"),
|
||||
T_DATA("RTL-8129", "RTL-8129"),
|
||||
T_DATA("RTL8139D [Realtek] PCI 10/100BaseTX ethernet adaptor", "RTL8139D"),
|
||||
T_DATA("RTL8139 Ethernet", "RTL8139"),
|
||||
|
|
@ -1994,6 +2023,9 @@ test_fixup_product_string(void)
|
|||
"TEW-648UBM"),
|
||||
T_DATA("TG54USB 802.11bg", "TG54USB"),
|
||||
T_DATA("Thomson TG121N [Atheros AR9001U-(2)NG]", "Thomson TG121N"),
|
||||
T_DATA("TN9510 10GBase-T/NBASE-T Ethernet Adapter", "TN9510"),
|
||||
T_DATA("TN9710P 10GBase-T/NBASE-T Ethernet Adapter", "TN9710P"),
|
||||
T_DATA("TN9710Q 5GBase-T/NBASE-T Ethernet Adapter", "TN9710Q"),
|
||||
T_DATA("Top Global Gobi 2000 Wireless Modem", "Top Global Gobi 2000"),
|
||||
T_DATA("TP-Link TL-WN322G v3 / TL-WN422G v2 802.11g [Atheros AR9271]",
|
||||
"TP-Link TL-WN322G / TL-WN422G"),
|
||||
|
|
|
|||
|
|
@ -299,7 +299,7 @@ test_wifi_ap_added_removed(void)
|
|||
|
||||
ret = g_dbus_proxy_call_sync(sinfo->proxy,
|
||||
"AddWifiAp",
|
||||
g_variant_new("(sss)", "wlan0", "test-ap", expected_bssid),
|
||||
g_variant_new("(sssu)", "wlan0", "test-ap", expected_bssid, 2412),
|
||||
G_DBUS_CALL_FLAGS_NO_AUTO_START,
|
||||
3000,
|
||||
NULL,
|
||||
|
|
|
|||
|
|
@ -38,11 +38,17 @@ typedef struct _NMIPConfigClass NMIPConfigClass;
|
|||
#define NM_IP_CONFIG_DOMAINS "domains"
|
||||
#define NM_IP_CONFIG_SEARCHES "searches"
|
||||
#define NM_IP_CONFIG_WINS_SERVERS "wins-servers"
|
||||
#define NM_IP_CONFIG_CLAT_ADDRESS "clat-address"
|
||||
#define NM_IP_CONFIG_CLAT_PREF64 "clat-pref64"
|
||||
|
||||
GType nm_ip_config_get_type(void);
|
||||
|
||||
int nm_ip_config_get_family(NMIPConfig *config);
|
||||
const char *nm_ip_config_get_gateway(NMIPConfig *config);
|
||||
int nm_ip_config_get_family(NMIPConfig *config);
|
||||
const char *nm_ip_config_get_gateway(NMIPConfig *config);
|
||||
NM_AVAILABLE_IN_1_58
|
||||
const char *nm_ip_config_get_clat_address(NMIPConfig *config);
|
||||
NM_AVAILABLE_IN_1_58
|
||||
const char *nm_ip_config_get_clat_pref64(NMIPConfig *config);
|
||||
GPtrArray *nm_ip_config_get_addresses(NMIPConfig *config);
|
||||
GPtrArray *nm_ip_config_get_routes(NMIPConfig *config);
|
||||
const char *const *nm_ip_config_get_nameservers(NMIPConfig *config);
|
||||
|
|
|
|||
|
|
@ -483,8 +483,8 @@ nm_utils_validate_shared_dhcp_range(const char *shared_dhcp_range,
|
|||
GPtrArray *addresses,
|
||||
GError **error)
|
||||
{
|
||||
char *start_address_str;
|
||||
char *end_address_str;
|
||||
const char *start_address_str;
|
||||
const char *end_address_str;
|
||||
NMIPAddress *interface_address_with_prefix;
|
||||
NMIPAddr interface_address;
|
||||
NMIPAddr start_address;
|
||||
|
|
@ -825,7 +825,7 @@ nm_dns_uri_parse(int addr_family, const char *str, NMDnsServer *dns, GError **er
|
|||
addr = nm_strndup_a(100, addr_port, end - addr_port, &addr_heap);
|
||||
|
||||
/* IPv6 link-local scope-id */
|
||||
perc = strchr(addr, '%');
|
||||
perc = (char *) strchr(addr, '%');
|
||||
if (perc) {
|
||||
*perc = '\0';
|
||||
if (g_strlcpy(dns->interface, perc + 1, sizeof(dns->interface))
|
||||
|
|
|
|||
|
|
@ -342,4 +342,23 @@ const char *nm_dns_uri_normalize(int addr_family, const char *str, char **out_fr
|
|||
gboolean nm_setting_ovs_other_config_check_key(const char *key, GError **error);
|
||||
gboolean nm_setting_ovs_other_config_check_val(const char *val, GError **error);
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/* Wi-Fi frequencies range for each band */
|
||||
#define _NM_WIFI_FREQ_MIN_2GHZ 2412
|
||||
#define _NM_WIFI_FREQ_MAX_2GHZ 2484
|
||||
#define _NM_WIFI_FREQ_MIN_5GHZ 4915
|
||||
#define _NM_WIFI_FREQ_MAX_5GHZ 5825
|
||||
#define _NM_WIFI_FREQ_MIN_6GHZ 5955
|
||||
#define _NM_WIFI_FREQ_MAX_6GHZ 7115
|
||||
|
||||
#define _NM_WIFI_FREQ_MIN _NM_WIFI_FREQ_MIN_2GHZ
|
||||
#define _NM_WIFI_FREQ_MAX _NM_WIFI_FREQ_MAX_6GHZ
|
||||
|
||||
/* Max Wi-Fi channel for each band */
|
||||
#define _NM_WIFI_CHANNEL_MAX_2GHZ 14
|
||||
#define _NM_WIFI_CHANNEL_MAX_5GHZ 177
|
||||
#define _NM_WIFI_CHANNEL_MAX_6GHZ 233
|
||||
#define _NM_WIFI_CHANNEL_MAX _NM_WIFI_CHANNEL_MAX_6GHZ
|
||||
|
||||
#endif /* __NM_LIBNM_SHARED_UTILS_H__ */
|
||||
|
|
|
|||
|
|
@ -1652,6 +1652,10 @@
|
|||
dbus-type="i"
|
||||
gprop-type="NMTernary"
|
||||
/>
|
||||
<property name="clat"
|
||||
dbus-type="i"
|
||||
gprop-type="gint"
|
||||
/>
|
||||
<property name="dad-timeout"
|
||||
dbus-type="i"
|
||||
gprop-type="gint"
|
||||
|
|
|
|||
|
|
@ -472,17 +472,17 @@ nm_bridge_vlan_to_str(const NMBridgeVlan *vlan, GError **error)
|
|||
NMBridgeVlan *
|
||||
nm_bridge_vlan_from_str(const char *str, GError **error)
|
||||
{
|
||||
NMBridgeVlan *vlan = NULL;
|
||||
gs_free const char **tokens = NULL;
|
||||
guint i, vid_start, vid_end = 0;
|
||||
gboolean pvid = FALSE;
|
||||
gboolean untagged = FALSE;
|
||||
char *c;
|
||||
NMBridgeVlan *vlan = NULL;
|
||||
gs_free char **tokens = NULL;
|
||||
guint i, vid_start, vid_end = 0;
|
||||
gboolean pvid = FALSE;
|
||||
gboolean untagged = FALSE;
|
||||
char *c;
|
||||
|
||||
g_return_val_if_fail(str, NULL);
|
||||
g_return_val_if_fail(!error || !*error, NULL);
|
||||
|
||||
tokens = nm_utils_escaped_tokens_split(str, NM_ASCII_SPACES);
|
||||
tokens = (char **) nm_utils_escaped_tokens_split(str, NM_ASCII_SPACES);
|
||||
if (!tokens || !tokens[0]) {
|
||||
g_set_error_literal(error,
|
||||
NM_CONNECTION_ERROR,
|
||||
|
|
|
|||
|
|
@ -3328,9 +3328,8 @@ nm_setting_connection_class_init(NMSettingConnectionClass *klass)
|
|||
*
|
||||
* The number of retries for the authentication. Zero means to try indefinitely; -1 means
|
||||
* to use a global default. If the global default is not set, the authentication
|
||||
* retries for 3 times before failing the connection.
|
||||
*
|
||||
* Currently, this only applies to 802-1x authentication.
|
||||
* retries for 3 times before failing the connection. Connections using a pre-shared key
|
||||
* to authenticate will only prompt for a new key during the last authentication attempt.
|
||||
*
|
||||
* Since: 1.10
|
||||
**/
|
||||
|
|
|
|||
|
|
@ -40,7 +40,8 @@ NM_GOBJECT_PROPERTIES_DEFINE_BASE(PROP_DHCP_CLIENT_ID,
|
|||
PROP_DHCP_FQDN,
|
||||
PROP_DHCP_VENDOR_CLASS_IDENTIFIER,
|
||||
PROP_LINK_LOCAL,
|
||||
PROP_DHCP_IPV6_ONLY_PREFERRED, );
|
||||
PROP_DHCP_IPV6_ONLY_PREFERRED,
|
||||
PROP_CLAT, );
|
||||
|
||||
typedef struct {
|
||||
NMSettingIPConfigPrivate parent;
|
||||
|
|
@ -50,6 +51,7 @@ typedef struct {
|
|||
char *dhcp_vendor_class_identifier;
|
||||
gint32 link_local;
|
||||
gint32 dhcp_ipv6_only_preferred;
|
||||
gint32 clat;
|
||||
} NMSettingIP4ConfigPrivate;
|
||||
|
||||
/**
|
||||
|
|
@ -168,6 +170,24 @@ nm_setting_ip4_config_get_dhcp_ipv6_only_preferred(NMSettingIP4Config *setting)
|
|||
return NM_SETTING_IP4_CONFIG_GET_PRIVATE(setting)->dhcp_ipv6_only_preferred;
|
||||
}
|
||||
|
||||
/**
|
||||
* nm_setting_ip4_config_get_clat:
|
||||
* @setting: the #NMSettingIP4Config
|
||||
*
|
||||
* Returns the value in the #NMSettingIP4Config:clat property.
|
||||
*
|
||||
* Returns: the CLAT property value
|
||||
*
|
||||
* Since: 1.58
|
||||
*/
|
||||
NMSettingIp4ConfigClat
|
||||
nm_setting_ip4_config_get_clat(NMSettingIP4Config *setting)
|
||||
{
|
||||
g_return_val_if_fail(NM_IS_SETTING_IP4_CONFIG(setting), NM_SETTING_IP4_CONFIG_CLAT_DEFAULT);
|
||||
|
||||
return NM_SETTING_IP4_CONFIG_GET_PRIVATE(setting)->clat;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
verify(NMSetting *setting, NMConnection *connection, GError **error)
|
||||
{
|
||||
|
|
@ -186,12 +206,15 @@ verify(NMSetting *setting, NMConnection *connection, GError **error)
|
|||
|
||||
if (!strcmp(method, NM_SETTING_IP4_CONFIG_METHOD_MANUAL)) {
|
||||
if (nm_setting_ip_config_get_num_addresses(s_ip) == 0
|
||||
&& nm_setting_ip_config_get_num_routes(s_ip) == 0) {
|
||||
g_set_error(error,
|
||||
NM_CONNECTION_ERROR,
|
||||
NM_CONNECTION_ERROR_MISSING_PROPERTY,
|
||||
_("method '%s' requires at least an address or a route"),
|
||||
method);
|
||||
&& nm_setting_ip_config_get_num_routes(s_ip) == 0
|
||||
&& nm_setting_ip4_config_get_clat(NM_SETTING_IP4_CONFIG(s_ip))
|
||||
!= NM_SETTING_IP4_CONFIG_CLAT_FORCE) {
|
||||
g_set_error(
|
||||
error,
|
||||
NM_CONNECTION_ERROR,
|
||||
NM_CONNECTION_ERROR_MISSING_PROPERTY,
|
||||
_("method '%s' requires at least an address, a route, or CLAT set to 'force'"),
|
||||
method);
|
||||
g_prefix_error(error,
|
||||
"%s.%s: ",
|
||||
NM_SETTING_IP4_CONFIG_SETTING_NAME,
|
||||
|
|
@ -1353,18 +1376,25 @@ nm_setting_ip4_config_class_init(NMSettingIP4ConfigClass *klass)
|
|||
/**
|
||||
* NMSettingIP4Config:dhcp-ipv6-only-preferred
|
||||
*
|
||||
* Controls the "IPv6-Only Preferred" DHCPv4 option (RFC 8925).
|
||||
* Controls the "IPv6-Only Preferred" DHCPv4 option (option 108 - RFC 8925).
|
||||
*
|
||||
* When set to %NM_SETTING_IP4_DHCP_IPV6_ONLY_PREFERRED_YES, the host adds the
|
||||
* option to the parameter request list; if the DHCP server sends the option back,
|
||||
* the host stops the DHCP client for the time interval specified in the option.
|
||||
*
|
||||
* Enable this feature if the host supports an IPv6-only mode, i.e. either all
|
||||
* applications are IPv6-only capable or there is a form of 464XLAT deployed.
|
||||
* applications are IPv6-only capable or there is a form of CLAT (464XLAT)
|
||||
* deployed.
|
||||
*
|
||||
* If set to %NM_SETTING_IP4_DHCP_IPV6_ONLY_PREFERRED_AUTO, the option is
|
||||
* automatically turned on when the IPv6 method is "auto" and the connection
|
||||
* profile has ipv4.clat set to "yes" or "auto". If these two conditions are
|
||||
* met, the host can operate in IPv6-only mode and therefore it is safe to
|
||||
* disable DHCPv4 when the network also supports it.
|
||||
*
|
||||
* When set to %NM_SETTING_IP4_DHCP_IPV6_ONLY_PREFERRED_DEFAULT, the actual value
|
||||
* is looked up in the global configuration; if not specified, it defaults to
|
||||
* %NM_SETTING_IP4_DHCP_IPV6_ONLY_PREFERRED_NO.
|
||||
* %NM_SETTING_IP4_DHCP_IPV6_ONLY_PREFERRED_AUTO.
|
||||
*
|
||||
* If the connection has IPv6 method set to "disabled", this property does not
|
||||
* have effect and the "IPv6-Only Preferred" option is always disabled.
|
||||
|
|
@ -1382,6 +1412,39 @@ nm_setting_ip4_config_class_init(NMSettingIP4ConfigClass *klass)
|
|||
NMSettingIP4ConfigPrivate,
|
||||
dhcp_ipv6_only_preferred);
|
||||
|
||||
/**
|
||||
* NMSettingIP4Config:clat
|
||||
*
|
||||
* Controls the CLAT (Customer-side translator) functionality. CLAT is used to implement the
|
||||
* client part of 464XLAT (RFC 6877), an architecture that provides IPv4 connectivity to hosts
|
||||
* on IPv6-only networks.
|
||||
*
|
||||
* When CLAT is enabled, NetworkManager discovers the NAT64 prefix from IPv6 Router Advertisements;
|
||||
* if a NAT64 prefix is announced, NetworkManager installs a BPF program to perform the stateless
|
||||
* translation of packets between IPv4 and IPv6.
|
||||
*
|
||||
* Setting %NM_SETTING_IP4_CONFIG_CLAT_NO completely disables CLAT. %NM_SETTING_IP4_CONFIG_CLAT_AUTO
|
||||
* enables CLAT only when the IPv4 method is 'auto' and the device doesn't have a native IPv4 gateway.
|
||||
* %NM_SETTING_IP4_CONFIG_CLAT_FORCE enables CLAT even if the IPv4 method is not 'auto' and even if
|
||||
* the device has a native IPv4 gateway.
|
||||
*
|
||||
* When set to %NM_SETTING_IP4_CONFIG_CLAT_DEFAULT, the actual value is looked up in the global
|
||||
* configuration; if not specified it defaults to %NM_SETTING_IP4_CONFIG_CLAT_NO. In the future the
|
||||
* default fall back value will change to %NM_SETTING_IP4_CONFIG_CLAT_AUTO.
|
||||
*
|
||||
* Since: 1.58
|
||||
*/
|
||||
_nm_setting_property_define_direct_enum(properties_override,
|
||||
obj_properties,
|
||||
NM_SETTING_IP4_CONFIG_CLAT,
|
||||
PROP_CLAT,
|
||||
NM_TYPE_SETTING_IP4_CONFIG_CLAT,
|
||||
NM_SETTING_IP4_CONFIG_CLAT_DEFAULT,
|
||||
NM_SETTING_PARAM_NONE,
|
||||
NULL,
|
||||
NMSettingIP4ConfigPrivate,
|
||||
clat);
|
||||
|
||||
g_object_class_install_properties(object_class, _PROPERTY_ENUMS_LAST, obj_properties);
|
||||
|
||||
_nm_setting_class_commit(setting_class,
|
||||
|
|
|
|||
|
|
@ -1086,7 +1086,7 @@ verify(NMSetting *setting, NMConnection *connection, GError **error)
|
|||
NM_SETTING_WIRELESS_MODE_AP,
|
||||
NM_SETTING_WIRELESS_MODE_MESH,
|
||||
NULL};
|
||||
const char *valid_bands[] = {"a", "bg", NULL};
|
||||
const char *valid_bands[] = {"a", "bg", "6GHz", NULL};
|
||||
guint i;
|
||||
gsize length;
|
||||
GError *local = NULL;
|
||||
|
|
@ -1363,11 +1363,11 @@ verify(NMSetting *setting, NMConnection *connection, GError **error)
|
|||
}
|
||||
|
||||
if (priv->channel_width == NM_SETTING_WIRELESS_CHANNEL_WIDTH_80MHZ
|
||||
&& !nm_streq0(priv->band, "a")) {
|
||||
&& !NM_IN_STRSET(priv->band, "a", "6GHz")) {
|
||||
g_set_error_literal(error,
|
||||
NM_CONNECTION_ERROR,
|
||||
NM_CONNECTION_ERROR_INVALID_PROPERTY,
|
||||
_("80MHz channels are only supported in the 5GHz band"));
|
||||
_("80MHz channels are only supported in the 5GHz and 6GHz bands"));
|
||||
g_prefix_error(error,
|
||||
"%s.%s: ",
|
||||
NM_SETTING_WIRELESS_SETTING_NAME,
|
||||
|
|
@ -1636,17 +1636,18 @@ nm_setting_wireless_class_init(NMSettingWirelessClass *klass)
|
|||
/**
|
||||
* NMSettingWireless:band:
|
||||
*
|
||||
* 802.11 frequency band of the network. One of "a" for 5GHz 802.11a or
|
||||
* "bg" for 2.4GHz 802.11. This will lock associations to the Wi-Fi network
|
||||
* to the specific band, i.e. if "a" is specified, the device will not
|
||||
* associate with the same network in the 2.4GHz band even if the network's
|
||||
* settings are compatible. This setting depends on specific driver
|
||||
* capability and may not work with all drivers.
|
||||
* 802.11 frequency band of the network. One of "a" for 5GHz,
|
||||
* "bg" for 2.4GHz or "6GHz". This will lock associations to the
|
||||
* Wi-Fi network to the specific band, i.e. if "a" is specified,
|
||||
* the device will not associate with the same network in the
|
||||
* 2.4GHz (bg) or 6GHz bands even if the network's settings are
|
||||
* compatible. This setting depends on specific driver capability
|
||||
* and may not work with all drivers.
|
||||
**/
|
||||
/* ---ifcfg-rh---
|
||||
* property: band
|
||||
* variable: BAND(+)
|
||||
* values: a, bg
|
||||
* values: a, bg, 6GHz
|
||||
* description: BAND alone is honored, but CHANNEL overrides BAND since it
|
||||
* implies a band.
|
||||
* example: BAND=bg
|
||||
|
|
@ -1673,8 +1674,6 @@ nm_setting_wireless_class_init(NMSettingWirelessClass *klass)
|
|||
* property: channel
|
||||
* variable: CHANNEL
|
||||
* description: Channel used for the Wi-Fi communication.
|
||||
* Channels greater than 14 mean "a" band, otherwise the
|
||||
* band is "bg".
|
||||
* example: CHANNEL=6
|
||||
* ---end---
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -4523,7 +4523,7 @@ nm_range_from_str(const char *str, GError **error)
|
|||
gs_free char *str_free = NULL;
|
||||
guint64 start;
|
||||
guint64 end = 0;
|
||||
char *c;
|
||||
const char *c;
|
||||
|
||||
g_return_val_if_fail(str, NULL);
|
||||
g_return_val_if_fail(!error || !*error, NULL);
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@
|
|||
#include "libnm-glib-aux/nm-time-utils.h"
|
||||
#include "libnm-glib-aux/nm-secret-utils.h"
|
||||
#include "libnm-core-aux-intern/nm-common-macros.h"
|
||||
#include "libnm-core-aux-intern/nm-libnm-core-utils.h"
|
||||
#include "nm-utils-private.h"
|
||||
#include "nm-setting-private.h"
|
||||
#include "nm-setting-bond.h"
|
||||
|
|
@ -3697,43 +3698,78 @@ struct cf_pair {
|
|||
guint32 freq;
|
||||
};
|
||||
|
||||
static const struct cf_pair a_table[] = {
|
||||
/* A band */
|
||||
{7, 5035}, {8, 5040}, {9, 5045}, {11, 5055}, {12, 5060}, {16, 5080}, {34, 5170},
|
||||
{36, 5180}, {38, 5190}, {40, 5200}, {42, 5210}, {44, 5220}, {46, 5230}, {48, 5240},
|
||||
{50, 5250}, {52, 5260}, {56, 5280}, {58, 5290}, {60, 5300}, {64, 5320}, {100, 5500},
|
||||
{104, 5520}, {108, 5540}, {112, 5560}, {116, 5580}, {120, 5600}, {124, 5620}, {128, 5640},
|
||||
{132, 5660}, {136, 5680}, {140, 5700}, {149, 5745}, {152, 5760}, {153, 5765}, {157, 5785},
|
||||
{160, 5800}, {161, 5805}, {165, 5825}, {183, 4915}, {184, 4920}, {185, 4925}, {187, 4935},
|
||||
{188, 4945}, {192, 4960}, {196, 4980}, {0, 0}};
|
||||
static const struct cf_pair table_5ghz[] = {
|
||||
/* Special, 20MHz only */
|
||||
{32, 5160},
|
||||
|
||||
static const guint a_table_freqs[G_N_ELEMENTS(a_table)] = {
|
||||
/* A band */
|
||||
5035, 5040, 5045, 5055, 5060, 5080, 5170, 5180, 5190, 5200, 5210, 5220, 5230, 5240, 5250, 5260,
|
||||
5280, 5290, 5300, 5320, 5500, 5520, 5540, 5560, 5580, 5600, 5620, 5640, 5660, 5680, 5700, 5745,
|
||||
5760, 5765, 5785, 5800, 5805, 5825, 4915, 4920, 4925, 4935, 4945, 4960, 4980, 0,
|
||||
};
|
||||
/* UNII-1 (Indoor) */
|
||||
{36, 5180},
|
||||
{40, 5200},
|
||||
{44, 5220},
|
||||
{48, 5240},
|
||||
|
||||
/* UNII-2 (DFS) */
|
||||
{52, 5260},
|
||||
{56, 5280},
|
||||
{60, 5300},
|
||||
{64, 5320},
|
||||
|
||||
/* UNII-2C (DFS) */
|
||||
{100, 5500},
|
||||
{104, 5520},
|
||||
{108, 5540},
|
||||
{112, 5560},
|
||||
{116, 5580},
|
||||
{120, 5600},
|
||||
{124, 5620},
|
||||
{128, 5640},
|
||||
{132, 5660},
|
||||
{136, 5680},
|
||||
{140, 5700},
|
||||
{144, 5720},
|
||||
|
||||
/* UNII-3 */
|
||||
{149, 5745},
|
||||
{153, 5765},
|
||||
{157, 5785},
|
||||
{161, 5805},
|
||||
{165, 5825},
|
||||
|
||||
/* 4.9 GHz Public Safety Band (802.11y/j) */
|
||||
{183, 4915},
|
||||
{184, 4920},
|
||||
{185, 4925},
|
||||
{187, 4935},
|
||||
{188, 4940},
|
||||
{189, 4945},
|
||||
{192, 4960},
|
||||
{196, 4980},
|
||||
|
||||
static const struct cf_pair bg_table[] = {
|
||||
/* B/G band */
|
||||
{1, 2412},
|
||||
{2, 2417},
|
||||
{3, 2422},
|
||||
{4, 2427},
|
||||
{5, 2432},
|
||||
{6, 2437},
|
||||
{7, 2442},
|
||||
{8, 2447},
|
||||
{9, 2452},
|
||||
{10, 2457},
|
||||
{11, 2462},
|
||||
{12, 2467},
|
||||
{13, 2472},
|
||||
{14, 2484},
|
||||
{0, 0}};
|
||||
|
||||
static const guint bg_table_freqs[G_N_ELEMENTS(bg_table)] = {
|
||||
/* B/G band */
|
||||
static const guint table_5ghz_freqs[G_N_ELEMENTS(table_5ghz)] = {
|
||||
5160, 5180, 5200, 5220, 5240, 5260, 5280, 5300, 5320, 5500, 5520, 5540,
|
||||
5560, 5580, 5600, 5620, 5640, 5660, 5680, 5700, 5720, 5745, 5765, 5785,
|
||||
5805, 5825, 4915, 4920, 4925, 4935, 4940, 4945, 4960, 4980, 0,
|
||||
};
|
||||
|
||||
static const struct cf_pair table_2ghz[] = {{1, 2412},
|
||||
{2, 2417},
|
||||
{3, 2422},
|
||||
{4, 2427},
|
||||
{5, 2432},
|
||||
{6, 2437},
|
||||
{7, 2442},
|
||||
{8, 2447},
|
||||
{9, 2452},
|
||||
{10, 2457},
|
||||
{11, 2462},
|
||||
{12, 2467},
|
||||
{13, 2472},
|
||||
{14, 2484},
|
||||
{0, 0}};
|
||||
|
||||
static const guint table_2ghz_freqs[G_N_ELEMENTS(table_2ghz)] = {
|
||||
2412,
|
||||
2417,
|
||||
2422,
|
||||
|
|
@ -3751,6 +3787,24 @@ static const guint bg_table_freqs[G_N_ELEMENTS(bg_table)] = {
|
|||
0,
|
||||
};
|
||||
|
||||
static const struct cf_pair table_6ghz[] = {
|
||||
{1, 5955}, {5, 5975}, {9, 5995}, {13, 6015}, {17, 6035}, {21, 6055}, {25, 6075},
|
||||
{29, 6095}, {33, 6115}, {37, 6135}, {41, 6155}, {45, 6175}, {49, 6195}, {53, 6215},
|
||||
{57, 6235}, {61, 6255}, {65, 6275}, {69, 6295}, {73, 6315}, {77, 6335}, {81, 6355},
|
||||
{85, 6375}, {89, 6395}, {93, 6415}, {97, 6435}, {101, 6455}, {105, 6475}, {109, 6495},
|
||||
{113, 6515}, {117, 6535}, {121, 6555}, {125, 6575}, {129, 6595}, {133, 6615}, {137, 6635},
|
||||
{141, 6655}, {145, 6675}, {149, 6695}, {153, 6715}, {157, 6735}, {161, 6755}, {169, 6775},
|
||||
{173, 6815}, {177, 6835}, {181, 6855}, {185, 6875}, {189, 6895}, {193, 6915}, {197, 6935},
|
||||
{201, 6955}, {205, 6975}, {209, 6995}, {213, 7015}, {217, 7035}, {221, 7055}, {225, 7075},
|
||||
{229, 7095}, {233, 7115}, {0, 0}};
|
||||
|
||||
static const guint table_6ghz_freqs[G_N_ELEMENTS(table_6ghz)] = {
|
||||
5955, 5975, 5995, 6015, 6035, 6055, 6075, 6095, 6115, 6135, 6155, 6175, 6195, 6215, 6235,
|
||||
6255, 6275, 6295, 6315, 6335, 6355, 6375, 6395, 6415, 6435, 6455, 6475, 6495, 6515, 6535,
|
||||
6555, 6575, 6595, 6615, 6635, 6655, 6675, 6695, 6715, 6735, 6755, 6775, 6815, 6835, 6855,
|
||||
6875, 6895, 6915, 6935, 6955, 6975, 6995, 7015, 7035, 7055, 7075, 7095, 7115, 0,
|
||||
};
|
||||
|
||||
/**
|
||||
* nm_utils_wifi_freq_to_channel:
|
||||
* @freq: frequency
|
||||
|
|
@ -3762,42 +3816,51 @@ static const guint bg_table_freqs[G_N_ELEMENTS(bg_table)] = {
|
|||
guint32
|
||||
nm_utils_wifi_freq_to_channel(guint32 freq)
|
||||
{
|
||||
int i = 0;
|
||||
const struct cf_pair *table;
|
||||
int i = 0;
|
||||
|
||||
if (freq > 4900) {
|
||||
while (a_table[i].freq && (a_table[i].freq != freq))
|
||||
i++;
|
||||
return a_table[i].chan;
|
||||
if (freq >= _NM_WIFI_FREQ_MIN_6GHZ) {
|
||||
table = table_6ghz;
|
||||
} else if (freq >= _NM_WIFI_FREQ_MIN_5GHZ) {
|
||||
table = table_5ghz;
|
||||
} else {
|
||||
table = table_2ghz;
|
||||
}
|
||||
|
||||
while (bg_table[i].freq && (bg_table[i].freq != freq))
|
||||
while (table[i].freq && (table[i].freq != freq))
|
||||
i++;
|
||||
return bg_table[i].chan;
|
||||
|
||||
return table[i].chan;
|
||||
}
|
||||
|
||||
/**
|
||||
* nm_utils_wifi_freq_to_band:
|
||||
* @freq: frequency
|
||||
*
|
||||
* Utility function to translate a Wi-Fi frequency to its corresponding band.
|
||||
* Translates a Wi-Fi frequency to its corresponding band.
|
||||
*
|
||||
* Returns: the band containing the frequency or NULL if freq is invalid
|
||||
* Returns: the band containing the frequency or %NM_WIFI_BAND_UNKNOWN if
|
||||
* the frequency does not belong to a known band.
|
||||
*
|
||||
* Since: 1.58
|
||||
**/
|
||||
const char *
|
||||
NMWifiBand
|
||||
nm_utils_wifi_freq_to_band(guint32 freq)
|
||||
{
|
||||
if (freq >= 4915 && freq <= 5825)
|
||||
return "a";
|
||||
else if (freq >= 2412 && freq <= 2484)
|
||||
return "bg";
|
||||
if (freq >= _NM_WIFI_FREQ_MIN_2GHZ && freq <= _NM_WIFI_FREQ_MAX_2GHZ)
|
||||
return NM_WIFI_BAND_2_4_GHZ;
|
||||
else if (freq >= _NM_WIFI_FREQ_MIN_5GHZ && freq <= _NM_WIFI_FREQ_MAX_5GHZ)
|
||||
return NM_WIFI_BAND_5_GHZ;
|
||||
else if (freq >= _NM_WIFI_FREQ_MIN_6GHZ && freq <= _NM_WIFI_FREQ_MAX_6GHZ)
|
||||
return NM_WIFI_BAND_6_GHZ;
|
||||
|
||||
return NULL;
|
||||
return NM_WIFI_BAND_UNKNOWN;
|
||||
}
|
||||
|
||||
/**
|
||||
* nm_utils_wifi_channel_to_freq:
|
||||
* @channel: channel
|
||||
* @band: frequency band for wireless ("a" or "bg")
|
||||
* @band: frequency band for wireless ("a", "bg", "6GHz")
|
||||
*
|
||||
* Utility function to translate a Wi-Fi channel to its corresponding frequency.
|
||||
*
|
||||
|
|
@ -3808,34 +3871,33 @@ nm_utils_wifi_freq_to_band(guint32 freq)
|
|||
guint32
|
||||
nm_utils_wifi_channel_to_freq(guint32 channel, const char *band)
|
||||
{
|
||||
int i;
|
||||
const struct cf_pair *table;
|
||||
int i;
|
||||
|
||||
g_return_val_if_fail(band, 0);
|
||||
|
||||
if (nm_streq(band, "a")) {
|
||||
for (i = 0; a_table[i].chan; i++) {
|
||||
if (a_table[i].chan == channel)
|
||||
return a_table[i].freq;
|
||||
}
|
||||
return ((guint32) -1);
|
||||
if (nm_streq0(band, "a")) {
|
||||
table = table_5ghz;
|
||||
} else if (nm_streq0(band, "bg")) {
|
||||
table = table_2ghz;
|
||||
} else if (nm_streq0(band, "6GHz")) {
|
||||
table = table_6ghz;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (nm_streq(band, "bg")) {
|
||||
for (i = 0; bg_table[i].chan; i++) {
|
||||
if (bg_table[i].chan == channel)
|
||||
return bg_table[i].freq;
|
||||
}
|
||||
return ((guint32) -1);
|
||||
for (i = 0; table[i].chan; i++) {
|
||||
if (table[i].chan == channel)
|
||||
return table[i].freq;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return ((guint32) -1);
|
||||
}
|
||||
|
||||
/**
|
||||
* nm_utils_wifi_find_next_channel:
|
||||
* @channel: current channel
|
||||
* @direction: whether going downward (0 or less) or upward (1 or more)
|
||||
* @band: frequency band for wireless ("a" or "bg")
|
||||
* @band: frequency band for wireless ("a", "bg", "6GHz")
|
||||
*
|
||||
* Utility function to find out next/previous Wi-Fi channel for a channel.
|
||||
*
|
||||
|
|
@ -3844,35 +3906,36 @@ nm_utils_wifi_channel_to_freq(guint32 channel, const char *band)
|
|||
guint32
|
||||
nm_utils_wifi_find_next_channel(guint32 channel, int direction, char *band)
|
||||
{
|
||||
size_t a_size = G_N_ELEMENTS(a_table);
|
||||
size_t bg_size = G_N_ELEMENTS(bg_table);
|
||||
const struct cf_pair *pair;
|
||||
const struct cf_pair *table;
|
||||
guint table_size;
|
||||
|
||||
if (nm_streq(band, "a")) {
|
||||
if (channel < a_table[0].chan)
|
||||
return a_table[0].chan;
|
||||
if (channel > a_table[a_size - 2].chan)
|
||||
return a_table[a_size - 2].chan;
|
||||
pair = &a_table[0];
|
||||
} else if (nm_streq(band, "bg")) {
|
||||
if (channel < bg_table[0].chan)
|
||||
return bg_table[0].chan;
|
||||
if (channel > bg_table[bg_size - 2].chan)
|
||||
return bg_table[bg_size - 2].chan;
|
||||
pair = &bg_table[0];
|
||||
if (nm_streq0(band, "a")) {
|
||||
table = table_5ghz;
|
||||
table_size = G_N_ELEMENTS(table_5ghz);
|
||||
} else if (nm_streq0(band, "bg")) {
|
||||
table = table_2ghz;
|
||||
table_size = G_N_ELEMENTS(table_2ghz);
|
||||
} else if (nm_streq0(band, "6GHz")) {
|
||||
table = table_6ghz;
|
||||
table_size = G_N_ELEMENTS(table_6ghz);
|
||||
} else
|
||||
g_return_val_if_reached(0);
|
||||
|
||||
while (pair->chan) {
|
||||
if (channel == pair->chan)
|
||||
if (channel < table[0].chan)
|
||||
return table[0].chan;
|
||||
if (channel > table[table_size - 2].chan)
|
||||
return table[table_size - 2].chan;
|
||||
|
||||
while (table->chan) {
|
||||
if (channel == table->chan)
|
||||
return channel;
|
||||
if ((channel < (pair + 1)->chan) && (channel > pair->chan)) {
|
||||
if ((channel < (table + 1)->chan) && (channel > table->chan)) {
|
||||
if (direction > 0)
|
||||
return (pair + 1)->chan;
|
||||
return (table + 1)->chan;
|
||||
else
|
||||
return pair->chan;
|
||||
return table->chan;
|
||||
}
|
||||
pair++;
|
||||
table++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -3880,7 +3943,7 @@ nm_utils_wifi_find_next_channel(guint32 channel, int direction, char *band)
|
|||
/**
|
||||
* nm_utils_wifi_is_channel_valid:
|
||||
* @channel: channel
|
||||
* @band: frequency band for wireless ("a" or "bg")
|
||||
* @band: frequency band for wireless ("a", "bg", "6GHz")
|
||||
*
|
||||
* Utility function to verify Wi-Fi channel validity.
|
||||
*
|
||||
|
|
@ -3930,8 +3993,8 @@ nm_utils_wifi_is_channel_valid(guint32 channel, const char *band)
|
|||
const guint *
|
||||
nm_utils_wifi_2ghz_freqs(void)
|
||||
{
|
||||
_nm_assert_wifi_freqs(bg_table, bg_table_freqs);
|
||||
return bg_table_freqs;
|
||||
_nm_assert_wifi_freqs(table_2ghz, table_2ghz_freqs);
|
||||
return table_2ghz_freqs;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -3946,8 +4009,24 @@ nm_utils_wifi_2ghz_freqs(void)
|
|||
const guint *
|
||||
nm_utils_wifi_5ghz_freqs(void)
|
||||
{
|
||||
_nm_assert_wifi_freqs(a_table, a_table_freqs);
|
||||
return a_table_freqs;
|
||||
_nm_assert_wifi_freqs(table_5ghz, table_5ghz_freqs);
|
||||
return table_5ghz_freqs;
|
||||
}
|
||||
|
||||
/**
|
||||
* nm_utils_wifi_6ghz_freqs:
|
||||
*
|
||||
* Utility function to return 6 GHz Wi-Fi frequencies (802.11ax/be, Wi-Fi 6E).
|
||||
*
|
||||
* Returns: zero-terminated array of frequencies numbers (in MHz)
|
||||
*
|
||||
* Since: 1.58
|
||||
**/
|
||||
const guint *
|
||||
nm_utils_wifi_6ghz_freqs(void)
|
||||
{
|
||||
_nm_assert_wifi_freqs(table_6ghz, table_6ghz_freqs);
|
||||
return table_6ghz_freqs;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -4094,6 +4094,7 @@ test_connection_diff_a_only(void)
|
|||
{NM_SETTING_IP_CONFIG_DHCP_REJECT_SERVERS, NM_SETTING_DIFF_RESULT_IN_A},
|
||||
{NM_SETTING_IP4_CONFIG_LINK_LOCAL, NM_SETTING_DIFF_RESULT_IN_A},
|
||||
{NM_SETTING_IP4_CONFIG_DHCP_IPV6_ONLY_PREFERRED, NM_SETTING_DIFF_RESULT_IN_A},
|
||||
{NM_SETTING_IP4_CONFIG_CLAT, NM_SETTING_DIFF_RESULT_IN_A},
|
||||
{NM_SETTING_IP_CONFIG_AUTO_ROUTE_EXT_GW, NM_SETTING_DIFF_RESULT_IN_A},
|
||||
{NM_SETTING_IP_CONFIG_REPLACE_LOCAL_RULE, NM_SETTING_DIFF_RESULT_IN_A},
|
||||
{NM_SETTING_IP_CONFIG_DHCP_SEND_RELEASE, NM_SETTING_DIFF_RESULT_IN_A},
|
||||
|
|
@ -11140,7 +11141,7 @@ _do_wifi_ghz_freqs(const guint *freqs, const char *band)
|
|||
int j;
|
||||
int i;
|
||||
|
||||
g_assert(NM_IN_STRSET(band, "a", "bg"));
|
||||
g_assert(NM_IN_STRSET(band, "a", "bg", "6GHz"));
|
||||
g_assert(freqs);
|
||||
g_assert(freqs[0] != 0);
|
||||
|
||||
|
|
@ -11178,6 +11179,7 @@ test_nm_utils_wifi_ghz_freqs(void)
|
|||
{
|
||||
_do_wifi_ghz_freqs(nm_utils_wifi_2ghz_freqs(), "bg");
|
||||
_do_wifi_ghz_freqs(nm_utils_wifi_5ghz_freqs(), "a");
|
||||
_do_wifi_ghz_freqs(nm_utils_wifi_6ghz_freqs(), "6GHz");
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
|
|
|||
|
|
@ -1135,8 +1135,6 @@ gboolean nm_utils_base64secret_normalize(const char *base64_key,
|
|||
|
||||
gboolean nm_utils_connection_is_adhoc_wpa(NMConnection *connection);
|
||||
|
||||
const char *nm_utils_wifi_freq_to_band(guint32 freq);
|
||||
|
||||
gboolean _nm_utils_iaid_verify(const char *str, gint64 *out_value);
|
||||
|
||||
gboolean
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ G_BEGIN_DECLS
|
|||
#define NM_SETTING_IP4_CONFIG_DHCP_VENDOR_CLASS_IDENTIFIER "dhcp-vendor-class-identifier"
|
||||
#define NM_SETTING_IP4_CONFIG_DHCP_IPV6_ONLY_PREFERRED "dhcp-ipv6-only-preferred"
|
||||
#define NM_SETTING_IP4_CONFIG_LINK_LOCAL "link-local"
|
||||
#define NM_SETTING_IP4_CONFIG_CLAT "clat"
|
||||
|
||||
/**
|
||||
* NM_SETTING_IP4_CONFIG_METHOD_AUTO:
|
||||
|
|
@ -109,6 +110,8 @@ typedef enum {
|
|||
* @NM_SETTING_IP4_DHCP_IPV6_ONLY_PREFERRED_DEFAULT: use the global default value
|
||||
* @NM_SETTING_IP4_DHCP_IPV6_ONLY_PREFERRED_NO: the option is disabled
|
||||
* @NM_SETTING_IP4_DHCP_IPV6_ONLY_PREFERRED_YES: the option is enabled
|
||||
* @NM_SETTING_IP4_DHCP_IPV6_ONLY_PREFERRED_AUTO: the option is enabled when
|
||||
* the IPv6 method is "auto" and CLAT is enabled. Since: 1.58
|
||||
*
|
||||
* #NMSettingIP4DhcpIpv6OnlyPreferred values specify if the "IPv6-Only Preferred"
|
||||
* option (RFC 8925) for DHCPv4 is enabled.
|
||||
|
|
@ -119,8 +122,32 @@ typedef enum {
|
|||
NM_SETTING_IP4_DHCP_IPV6_ONLY_PREFERRED_DEFAULT = -1,
|
||||
NM_SETTING_IP4_DHCP_IPV6_ONLY_PREFERRED_NO = 0,
|
||||
NM_SETTING_IP4_DHCP_IPV6_ONLY_PREFERRED_YES = 1,
|
||||
NM_SETTING_IP4_DHCP_IPV6_ONLY_PREFERRED_AUTO = 2,
|
||||
} NMSettingIP4DhcpIpv6OnlyPreferred;
|
||||
|
||||
/**
|
||||
* NMSettingIp4ConfigClat:
|
||||
* @NM_SETTING_IP4_CONFIG_CLAT_DEFAULT: use the global default value
|
||||
* @NM_SETTING_IP4_CONFIG_CLAT_NO: disable CLAT
|
||||
* @NM_SETTING_IP4_CONFIG_CLAT_AUTO: enable CLAT only when the IPv4 method
|
||||
* is 'auto' and the device doesn't have a native IPv4 gateway.
|
||||
* @NM_SETTING_IP4_CONFIG_CLAT_FORCE: enable CLAT even with IPv4 methods
|
||||
* other than 'auto' and even if the device has a native IPv4 gateway.
|
||||
*
|
||||
* #NMSettingIP4ConfigClat values specify if CLAT (Customer-side translator)
|
||||
* is enabled or not. CLAT is used to implement the client part of 464XLAT
|
||||
* (RFC 6877), an architecture that provides IPv4 connectivity to hosts on
|
||||
* IPv6-only networks.
|
||||
*
|
||||
* Since: 1.58
|
||||
*/
|
||||
typedef enum {
|
||||
NM_SETTING_IP4_CONFIG_CLAT_DEFAULT = -1,
|
||||
NM_SETTING_IP4_CONFIG_CLAT_NO = 0,
|
||||
NM_SETTING_IP4_CONFIG_CLAT_AUTO = 1,
|
||||
NM_SETTING_IP4_CONFIG_CLAT_FORCE = 2,
|
||||
} NMSettingIp4ConfigClat;
|
||||
|
||||
typedef struct _NMSettingIP4ConfigClass NMSettingIP4ConfigClass;
|
||||
|
||||
GType nm_setting_ip4_config_get_type(void);
|
||||
|
|
@ -141,6 +168,9 @@ NM_AVAILABLE_IN_1_52
|
|||
NMSettingIP4DhcpIpv6OnlyPreferred
|
||||
nm_setting_ip4_config_get_dhcp_ipv6_only_preferred(NMSettingIP4Config *setting);
|
||||
|
||||
NM_AVAILABLE_IN_1_58
|
||||
NMSettingIp4ConfigClat nm_setting_ip4_config_get_clat(NMSettingIP4Config *setting);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __NM_SETTING_IP4_CONFIG_H__ */
|
||||
|
|
|
|||
|
|
@ -135,14 +135,36 @@ const char *nm_utils_file_search_in_paths(const char *prog
|
|||
gpointer user_data,
|
||||
GError **error);
|
||||
|
||||
guint32 nm_utils_wifi_freq_to_channel(guint32 freq);
|
||||
guint32 nm_utils_wifi_channel_to_freq(guint32 channel, const char *band);
|
||||
guint32 nm_utils_wifi_find_next_channel(guint32 channel, int direction, char *band);
|
||||
gboolean nm_utils_wifi_is_channel_valid(guint32 channel, const char *band);
|
||||
/**
|
||||
* NMWifiBand:
|
||||
* @NM_WIFI_BAND_UNKNOWN: the band is unknown
|
||||
* @NM_WIFI_BAND_2_4_GHZ: the 2.4 GHz band
|
||||
* @NM_WIFI_BAND_5_GHZ: the 5 GHz band
|
||||
* @NM_WIFI_BAND_6_GHZ: the 6 GHz band
|
||||
*
|
||||
* Describes a Wi-Fi radio frequency band.
|
||||
*
|
||||
* Since: 1.58
|
||||
*/
|
||||
typedef enum {
|
||||
NM_WIFI_BAND_UNKNOWN,
|
||||
NM_WIFI_BAND_2_4_GHZ,
|
||||
NM_WIFI_BAND_5_GHZ,
|
||||
NM_WIFI_BAND_6_GHZ,
|
||||
} NMWifiBand;
|
||||
|
||||
guint32 nm_utils_wifi_freq_to_channel(guint32 freq);
|
||||
NM_AVAILABLE_IN_1_58
|
||||
NMWifiBand nm_utils_wifi_freq_to_band(guint32 freq);
|
||||
guint32 nm_utils_wifi_channel_to_freq(guint32 channel, const char *band);
|
||||
guint32 nm_utils_wifi_find_next_channel(guint32 channel, int direction, char *band);
|
||||
gboolean nm_utils_wifi_is_channel_valid(guint32 channel, const char *band);
|
||||
NM_AVAILABLE_IN_1_2
|
||||
const guint *nm_utils_wifi_2ghz_freqs(void);
|
||||
NM_AVAILABLE_IN_1_2
|
||||
const guint *nm_utils_wifi_5ghz_freqs(void);
|
||||
NM_AVAILABLE_IN_1_58
|
||||
const guint *nm_utils_wifi_6ghz_freqs(void);
|
||||
|
||||
const char *nm_utils_wifi_strength_bars(guint8 strength);
|
||||
|
||||
|
|
|
|||
|
|
@ -79,6 +79,7 @@
|
|||
#define NM_VERSION_1_52 (NM_ENCODE_VERSION(1, 52, 0))
|
||||
#define NM_VERSION_1_54 (NM_ENCODE_VERSION(1, 54, 0))
|
||||
#define NM_VERSION_1_56 (NM_ENCODE_VERSION(1, 56, 0))
|
||||
#define NM_VERSION_1_58 (NM_ENCODE_VERSION(1, 58, 0))
|
||||
|
||||
/* For releases, NM_API_VERSION is equal to NM_VERSION.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -453,6 +453,20 @@
|
|||
#define NM_AVAILABLE_IN_1_56
|
||||
#endif
|
||||
|
||||
#if NM_VERSION_MIN_REQUIRED >= NM_VERSION_1_58
|
||||
#define NM_DEPRECATED_IN_1_58 G_DEPRECATED
|
||||
#define NM_DEPRECATED_IN_1_58_FOR(f) G_DEPRECATED_FOR(f)
|
||||
#else
|
||||
#define NM_DEPRECATED_IN_1_58
|
||||
#define NM_DEPRECATED_IN_1_58_FOR(f)
|
||||
#endif
|
||||
|
||||
#if NM_VERSION_MAX_ALLOWED < NM_VERSION_1_58
|
||||
#define NM_AVAILABLE_IN_1_58 G_UNAVAILABLE(1, 58)
|
||||
#else
|
||||
#define NM_AVAILABLE_IN_1_58
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Synchronous API for calling D-Bus in libnm is deprecated. See
|
||||
* https://networkmanager.dev/docs/libnm/latest/usage.html#sync-api
|
||||
|
|
|
|||
|
|
@ -25,15 +25,18 @@ void *xbsearch_r(const void *key, const void *base, size_t nmemb, size_t size,
|
|||
* Normal bsearch requires base to be nonnull. Here were require
|
||||
* that only if nmemb > 0.
|
||||
*/
|
||||
static inline void* bsearch_safe(const void *key, const void *base,
|
||||
static inline void* bsearch_safe_internal(const void *key, const void *base,
|
||||
size_t nmemb, size_t size, comparison_fn_t compar) {
|
||||
if (nmemb <= 0)
|
||||
return NULL;
|
||||
|
||||
assert(base);
|
||||
return bsearch(key, base, nmemb, size, compar);
|
||||
return (void*) bsearch(key, base, nmemb, size, compar);
|
||||
}
|
||||
|
||||
#define bsearch_safe(key, base, nmemb, size, compar) \
|
||||
const_generic((base), bsearch_safe_internal(key, base, nmemb, size, compar))
|
||||
|
||||
#define typesafe_bsearch(k, b, n, func) \
|
||||
({ \
|
||||
const typeof((b)[0]) *_k = k; \
|
||||
|
|
|
|||
|
|
@ -1470,7 +1470,7 @@ ssize_t strlevenshtein(const char *x, const char *y) {
|
|||
return t1[yl];
|
||||
}
|
||||
|
||||
char* strrstr(const char *haystack, const char *needle) {
|
||||
char* strrstr_internal(const char *haystack, const char *needle) {
|
||||
/* Like strstr() but returns the last rather than the first occurrence of "needle" in "haystack". */
|
||||
|
||||
if (!haystack || !needle)
|
||||
|
|
@ -1479,7 +1479,7 @@ char* strrstr(const char *haystack, const char *needle) {
|
|||
/* Special case: for the empty string we return the very last possible occurrence, i.e. *after* the
|
||||
* last char, not before. */
|
||||
if (*needle == 0)
|
||||
return strchr(haystack, 0);
|
||||
return (char*) strchr(haystack, 0);
|
||||
|
||||
for (const char *p = strstr(haystack, needle), *q; p; p = q) {
|
||||
q = strstr(p + 1, needle);
|
||||
|
|
|
|||
|
|
@ -27,24 +27,28 @@
|
|||
#define URI_UNRESERVED ALPHANUMERICAL "-._~" /* [RFC3986] */
|
||||
#define URI_VALID URI_RESERVED URI_UNRESERVED /* [RFC3986] */
|
||||
|
||||
static inline char* strstr_ptr(const char *haystack, const char *needle) {
|
||||
static inline char* strstr_ptr_internal(const char *haystack, const char *needle) {
|
||||
if (!haystack || !needle)
|
||||
return NULL;
|
||||
return strstr(haystack, needle);
|
||||
return (char*) strstr(haystack, needle);
|
||||
}
|
||||
|
||||
static inline char* strstrafter(const char *haystack, const char *needle) {
|
||||
char *p;
|
||||
#define strstr_ptr(haystack, needle) \
|
||||
const_generic(haystack, strstr_ptr_internal(haystack, needle))
|
||||
|
||||
static inline char* strstrafter_internal(const char *haystack, const char *needle) {
|
||||
/* Returns NULL if not found, or pointer to first character after needle if found */
|
||||
|
||||
p = strstr_ptr(haystack, needle);
|
||||
char *p = (char*) strstr_ptr(haystack, needle);
|
||||
if (!p)
|
||||
return NULL;
|
||||
|
||||
return p + strlen(needle);
|
||||
}
|
||||
|
||||
#define strstrafter(haystack, needle) \
|
||||
const_generic(haystack, strstrafter_internal(haystack, needle))
|
||||
|
||||
static inline const char* strnull(const char *s) {
|
||||
return s ?: "(null)";
|
||||
}
|
||||
|
|
@ -300,6 +304,8 @@ bool version_is_valid_versionspec(const char *s);
|
|||
|
||||
ssize_t strlevenshtein(const char *x, const char *y);
|
||||
|
||||
char* strrstr(const char *haystack, const char *needle);
|
||||
char* strrstr_internal(const char *haystack, const char *needle);
|
||||
#define strrstr(haystack, needle) \
|
||||
const_generic(haystack, strrstr_internal(haystack, needle))
|
||||
|
||||
size_t str_common_prefix(const char *a, const char *b);
|
||||
|
|
|
|||
|
|
@ -511,4 +511,11 @@ assert_cc(STRLEN(__FILE__) > STRLEN(RELATIVE_SOURCE_PATH) + 1);
|
|||
#define PROJECT_FILE (&__FILE__[STRLEN(RELATIVE_SOURCE_PATH) + 1])
|
||||
#else /* NM_IGNORED */
|
||||
#define PROJECT_FILE __FILE__
|
||||
#endif /* NM_IGNORED */
|
||||
#endif /* NM_IGNORED */
|
||||
|
||||
/* This macro is used to have a const-returning and non-const returning version of a function based on
|
||||
* whether its first argument is const or not (e.g. strstr()). */
|
||||
#define const_generic(ptr, call) \
|
||||
_Generic(0 ? (ptr) : (void*) 1, \
|
||||
const void*: (const typeof(*call)*) (call), \
|
||||
void*: (call))
|
||||
|
|
|
|||
|
|
@ -92,7 +92,8 @@ _subsystem_split(const char *subsystem_full,
|
|||
const char **out_devtype,
|
||||
char **to_free)
|
||||
{
|
||||
char *tmp, *s;
|
||||
char *tmp;
|
||||
const char *s;
|
||||
|
||||
nm_assert(subsystem_full);
|
||||
nm_assert(out_subsystem);
|
||||
|
|
@ -101,12 +102,12 @@ _subsystem_split(const char *subsystem_full,
|
|||
|
||||
s = strstr(subsystem_full, "/");
|
||||
if (s) {
|
||||
tmp = g_strdup(subsystem_full);
|
||||
s = &tmp[s - subsystem_full];
|
||||
*s = '\0';
|
||||
*out_subsystem = tmp;
|
||||
*out_devtype = &s[1];
|
||||
*to_free = tmp;
|
||||
tmp = g_strdup(subsystem_full);
|
||||
tmp[s - subsystem_full] = '\0';
|
||||
s = &tmp[s - subsystem_full];
|
||||
*out_subsystem = tmp;
|
||||
*out_devtype = &s[1];
|
||||
*to_free = tmp;
|
||||
} else {
|
||||
*out_subsystem = subsystem_full;
|
||||
*out_devtype = NULL;
|
||||
|
|
|
|||
|
|
@ -4292,7 +4292,8 @@ _set_fcn_wireless_channel(ARGS_SET_FCN)
|
|||
}
|
||||
|
||||
if (!nm_utils_wifi_is_channel_valid(chan_int, "a")
|
||||
&& !nm_utils_wifi_is_channel_valid(chan_int, "bg")) {
|
||||
&& !nm_utils_wifi_is_channel_valid(chan_int, "bg")
|
||||
&& !nm_utils_wifi_is_channel_valid(chan_int, "6GHz")) {
|
||||
nm_utils_error_set(error,
|
||||
NM_UTILS_ERROR_UNKNOWN,
|
||||
_("'%ld' is not a valid channel"),
|
||||
|
|
@ -6600,6 +6601,9 @@ static const NMMetaPropertyInfo *const property_infos_IP4_CONFIG[] = {
|
|||
PROPERTY_INFO_WITH_DESC (NM_SETTING_IP4_CONFIG_DHCP_IPV6_ONLY_PREFERRED,
|
||||
.property_type = &_pt_gobject_enum,
|
||||
),
|
||||
PROPERTY_INFO (NM_SETTING_IP4_CONFIG_CLAT, DESCRIBE_DOC_NM_SETTING_IP4_CONFIG_CLAT,
|
||||
.property_type = &_pt_gobject_enum,
|
||||
),
|
||||
PROPERTY_INFO_WITH_DESC (NM_SETTING_IP4_CONFIG_LINK_LOCAL,
|
||||
.property_type = &_pt_gobject_enum,
|
||||
.property_typ_data = DEFINE_PROPERTY_TYP_DATA (
|
||||
|
|
@ -8530,7 +8534,7 @@ static const NMMetaPropertyInfo *const property_infos_WIRELESS[] = {
|
|||
PROPERTY_INFO_WITH_DESC (NM_SETTING_WIRELESS_BAND,
|
||||
.property_type = &_pt_gobject_string,
|
||||
.property_typ_data = DEFINE_PROPERTY_TYP_DATA (
|
||||
.values_static = NM_MAKE_STRV ("a", "bg"),
|
||||
.values_static = NM_MAKE_STRV ("a", "bg", "6GHz"),
|
||||
),
|
||||
),
|
||||
PROPERTY_INFO_WITH_DESC (NM_SETTING_WIRELESS_CHANNEL,
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue