1
0
mirror of https://github.com/systemd/systemd synced 2026-03-29 11:14:50 +02:00

Compare commits

..

No commits in common. "721956f3e9332ebec0bb79429fc836c42501b128" and "41a978fdb16fa39411dbc3411d267797af1e453a" have entirely different histories.

80 changed files with 3274 additions and 3613 deletions

View File

@ -6,6 +6,7 @@ ADDITIONAL_DEPS=(
clang
expect
fdisk
iproute2
jekyll
lcov
libfdisk-dev
@ -19,6 +20,7 @@ ADDITIONAL_DEPS=(
perl
python3-libevdev
python3-pyparsing
util-linux
zstd
)
@ -53,7 +55,8 @@ for phase in "${PHASES[@]}"; do
fi
meson --werror -Dtests=unsafe -Dslow-tests=true -Dfuzz-tests=true "${MESON_ARGS[@]}" build
ninja -C build -v
meson test -C build --print-errorlogs
# Some of the unsafe tests irreparably break the host's network connectivity, so run them in a namespace
unshare -n bash -c 'ip link set dev lo up; meson test -C build --print-errorlogs'
if [[ "$phase" = "RUN_GCC" ]]; then
ninja -C build coverage
fi
@ -85,7 +88,7 @@ for phase in "${PHASES[@]}"; do
# during debugging, wonderful), so let's at least keep a workaround
# here to make the builds stable for the time being.
(set +x; while :; do echo -ne "\n[WATCHDOG] $(date)\n"; sleep 30; done) &
meson test --timeout-multiplier=3 -C build --print-errorlogs
unshare -n bash -c 'ip link set dev lo up; meson test --timeout-multiplier=3 -C build --print-errorlogs'
;;
CLEANUP)
info "Cleanup phase"

View File

@ -3,10 +3,6 @@
#
name: Unit tests
on:
# On push/merge to main we only run the GCC job, to get coverage data uploaded to coveralls.io
push:
branches:
- main
pull_request:
branches:
- main
@ -21,13 +17,10 @@ jobs:
steps:
- name: Repository checkout
uses: actions/checkout@v2
if: github.event_name == 'pull_request' || matrix.run_phase == 'GCC'
- name: Install build dependencies
run: sudo -E .github/workflows/unit_tests.sh SETUP
if: github.event_name == 'pull_request' || matrix.run_phase == 'GCC'
- name: Build & test (${{ matrix.run_phase }})
run: sudo -E .github/workflows/unit_tests.sh RUN_${{ matrix.run_phase }}
if: github.event_name == 'pull_request' || matrix.run_phase == 'GCC'
- name: Coveralls
if: matrix.run_phase == 'GCC' && github.repository == 'systemd/systemd'
uses: coverallsapp/github-action@master

5
NEWS
View File

@ -518,11 +518,6 @@ CHANGES WITH 249:
distribution does not install it yet, it might make sense to change
that.
* Intel HID rfkill event is no longer masked, since it's the only
source of rfkill event on newer HP laptops. To have both backward and
forward compatibility, userspace daemon needs to debounce duplicated
events in a short time window.
Contributions from: Aakash Singh, adrian5, Albert Brox,
Alexander Sverdlin, Alexander Tsoy, Alexey Rubtsov, alexlzhu,
Allen Webb, Alvin Šipraga, Alyssa Ross, Anders Wenhaug,

View File

@ -494,6 +494,9 @@ evdev:input:b0003v0458p0708*
# Hewlett Packard
###########################################################
evdev:name:Intel HID events:dmi:bvn*:bvr*:bd*:svnHP*:pn*:*
KEYBOARD_KEY_8=unknown # Use hp-wireless instead
evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pn*:*
evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHP*:pn*:*
KEYBOARD_KEY_81=fn_esc
@ -557,6 +560,9 @@ evdev:atkbd:dmi:bvn*:bvr*:svnHP*:pnHPElitex21013G3:*
KEYBOARD_KEY_92=brightnessdown
KEYBOARD_KEY_97=brightnessup
evdev:name:Intel HID events:dmi:bvn*:bvr*:svnHP*:pnHPElitex21013G3:*
KEYBOARD_KEY_08=unknown # rfkill is also reported by HP Wireless hotkeys
# Elitebook
evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pn*Compaq*:*
evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pn*EliteBook*:*

View File

@ -230,9 +230,8 @@ sensor:modalias:acpi:BOSC0200*:dmi:*:svnChuwi*:pnHi13:*
# Chuwi HiBook does not have its product name filled, so we
# match the entire dmi-alias, assuming that the use of a BOSC0200 +
# bios-version + bios-date combo is unique
# '*' in ":*svn" is there because kernels >= 5.8 have inserted a br field there
sensor:modalias:acpi:BOSC0200*:dmi:bvnAmericanMegatrendsInc.:bvr5.11:bd05/07/2016:*svnDefaultstring:pnDefaultstring:pvrDefaultstring:rvnHampoo:rnCherryTrailCR:rvrDefaultstring:cvnDefaultstring:ct3:cvrDefaultstring:*
sensor:modalias:acpi:BOSC0200*:dmi:bvnAmericanMegatrendsInc.:bvr5.11:bd05/28/2016:*svnDefaultstring:pnDefaultstring:pvrDefaultstring:rvnHampoo:rnCherryTrailCR:rvrDefaultstring:cvnDefaultstring:ct3:cvrDefaultstring:*
sensor:modalias:acpi:BOSC0200*:dmi:bvnAmericanMegatrendsInc.:bvr5.11:bd05/07/2016:svnDefaultstring:pnDefaultstring:pvrDefaultstring:rvnHampoo:rnCherryTrailCR:rvrDefaultstring:cvnDefaultstring:ct3:cvrDefaultstring:*
sensor:modalias:acpi:BOSC0200*:dmi:bvnAmericanMegatrendsInc.:bvr5.11:bd05/28/2016:svnDefaultstring:pnDefaultstring:pvrDefaultstring:rvnHampoo:rnCherryTrailCR:rvrDefaultstring:cvnDefaultstring:ct3:cvrDefaultstring:*
ACCEL_MOUNT_MATRIX=1, 0, 0; 0, -1, 0; 0, 0, 1
# Chuwi HiBook Pro (CWI526)
@ -242,8 +241,7 @@ sensor:modalias:acpi:BOSC0200*:dmi:*:svnHampoo*:pnP1D6_C109K:*
# Chuwi CoreBook
# Chuwi CoreBook does not have its product name filled, so we
# match the entire dmi-alias
# '*' in ":*svn" is there because kernels >= 5.8 have inserted a br field there
sensor:modalias:acpi:BOSC0200*:dmi:bvnAmericanMegatrendsInc.:bvrY13D_KB133.103:bd06/01/2018:*svnHampoo:pnDefaultstring:pvrV100:rvnHampoo:rnY13D_KB133:rvrV100:cvnDefaultstring:ct9:cvrDefaultstring:*
sensor:modalias:acpi:BOSC0200*:dmi:bvnAmericanMegatrendsInc.:bvrY13D_KB133.103:bd06/01/2018:svnHampoo:pnDefaultstring:pvrV100:rvnHampoo:rnY13D_KB133:rvrV100:cvnDefaultstring:ct9:cvrDefaultstring:*
ACCEL_MOUNT_MATRIX=-1, 0, 0; 0, 1, 0; 0, 0, 1
# Chuwi SurBook Mini (CWI540)
@ -412,14 +410,13 @@ sensor:modalias:acpi:KIOX000A*:dmi:bvnINSYDECorp.:bvrBYT70A.YNCHENG.WIN.007:*:sv
# and no other devices have both board_name *and* product_name set to
# "Default string". So combined with the sensor modalias and BIOS date this
# should be unique enough to identify the GPDwin
# '*' in ":*svn" is there because kernels >= 5.8 have inserted a br field there
sensor:modalias:acpi:KIOX000A*:dmi:bvnAmericanMegatrendsInc.:bvr5.11:bd10/25/2016:*svnDefaultstring:pnDefaultstring:pvrDefaultstring:rvnAMICorporation:rnDefaultstring:rvrDefaultstring:cvnDefaultstring:ct3:cvrDefaultstring:*
sensor:modalias:acpi:KIOX000A*:dmi:bvnAmericanMegatrendsInc.:bvr5.11:bd11/18/2016:*svnDefaultstring:pnDefaultstring:pvrDefaultstring:rvnAMICorporation:rnDefaultstring:rvrDefaultstring:cvnDefaultstring:ct3:cvrDefaultstring:*
sensor:modalias:acpi:KIOX000A*:dmi:bvnAmericanMegatrendsInc.:bvr5.11:bd12/23/2016:*svnDefaultstring:pnDefaultstring:pvrDefaultstring:rvnAMICorporation:rnDefaultstring:rvrDefaultstring:cvnDefaultstring:ct3:cvrDefaultstring:*
sensor:modalias:acpi:KIOX000A*:dmi:bvnAmericanMegatrendsInc.:bvr5.11:bd12/26/2016:*svnDefaultstring:pnDefaultstring:pvrDefaultstring:rvnAMICorporation:rnDefaultstring:rvrDefaultstring:cvnDefaultstring:ct3:cvrDefaultstring:*
sensor:modalias:acpi:KIOX000A*:dmi:bvnAmericanMegatrendsInc.:bvr5.11:bd02/21/2017:*svnDefaultstring:pnDefaultstring:pvrDefaultstring:rvnAMICorporation:rnDefaultstring:rvrDefaultstring:cvnDefaultstring:ct3:cvrDefaultstring:*
sensor:modalias:acpi:KIOX000A*:dmi:bvnAmericanMegatrendsInc.:bvr5.11:bd03/20/2017:*svnDefaultstring:pnDefaultstring:pvrDefaultstring:rvnAMICorporation:rnDefaultstring:rvrDefaultstring:cvnDefaultstring:ct3:cvrDefaultstring:*
sensor:modalias:acpi:KIOX000A*:dmi:bvnAmericanMegatrendsInc.:bvr5.11:bd05/25/2017:*svnDefaultstring:pnDefaultstring:pvrDefaultstring:rvnAMICorporation:rnDefaultstring:rvrDefaultstring:cvnDefaultstring:ct3:cvrDefaultstring:*
sensor:modalias:acpi:KIOX000A*:dmi:bvnAmericanMegatrendsInc.:bvr5.11:bd10/25/2016:svnDefaultstring:pnDefaultstring:pvrDefaultstring:rvnAMICorporation:rnDefaultstring:rvrDefaultstring:cvnDefaultstring:ct3:cvrDefaultstring:*
sensor:modalias:acpi:KIOX000A*:dmi:bvnAmericanMegatrendsInc.:bvr5.11:bd11/18/2016:svnDefaultstring:pnDefaultstring:pvrDefaultstring:rvnAMICorporation:rnDefaultstring:rvrDefaultstring:cvnDefaultstring:ct3:cvrDefaultstring:*
sensor:modalias:acpi:KIOX000A*:dmi:bvnAmericanMegatrendsInc.:bvr5.11:bd12/23/2016:svnDefaultstring:pnDefaultstring:pvrDefaultstring:rvnAMICorporation:rnDefaultstring:rvrDefaultstring:cvnDefaultstring:ct3:cvrDefaultstring:*
sensor:modalias:acpi:KIOX000A*:dmi:bvnAmericanMegatrendsInc.:bvr5.11:bd12/26/2016:svnDefaultstring:pnDefaultstring:pvrDefaultstring:rvnAMICorporation:rnDefaultstring:rvrDefaultstring:cvnDefaultstring:ct3:cvrDefaultstring:*
sensor:modalias:acpi:KIOX000A*:dmi:bvnAmericanMegatrendsInc.:bvr5.11:bd02/21/2017:svnDefaultstring:pnDefaultstring:pvrDefaultstring:rvnAMICorporation:rnDefaultstring:rvrDefaultstring:cvnDefaultstring:ct3:cvrDefaultstring:*
sensor:modalias:acpi:KIOX000A*:dmi:bvnAmericanMegatrendsInc.:bvr5.11:bd03/20/2017:svnDefaultstring:pnDefaultstring:pvrDefaultstring:rvnAMICorporation:rnDefaultstring:rvrDefaultstring:cvnDefaultstring:ct3:cvrDefaultstring:*
sensor:modalias:acpi:KIOX000A*:dmi:bvnAmericanMegatrendsInc.:bvr5.11:bd05/25/2017:svnDefaultstring:pnDefaultstring:pvrDefaultstring:rvnAMICorporation:rnDefaultstring:rvrDefaultstring:cvnDefaultstring:ct3:cvrDefaultstring:*
ACCEL_LOCATION=base
#########################################
@ -707,8 +704,7 @@ sensor:modalias:acpi:BMA250E*:dmi:bvnINSYDECorp.:bvrONDA.W89*:svnInsyde:pnONDATa
ACCEL_MOUNT_MATRIX=0, -1, 0; -1, 0, 0; 0, 0, 1
# Onda v975w, generic DMI strings, match entire dmi modalias inc. bios-date
# '*' in ":*svn" is there because kernels >= 5.8 have inserted a br field there
sensor:modalias:acpi:SMO8500*:dmi:bvnAmericanMegatrendsInc.:bvr5.6.5:bd07/25/2014:*svnTobefilledbyO.E.M.:pnTobefilledbyO.E.M.:pvrTobefilledbyO.E.M.:rvnAMICorporation:rnAptioCRB:rvrTobefilledbyO.E.M.:cvnToBeFilledByO.E.M.:ct3:cvrToBeFilledByO.E.M.:*
sensor:modalias:acpi:SMO8500*:dmi:bvnAmericanMegatrendsInc.:bvr5.6.5:bd07/25/2014:svnTobefilledbyO.E.M.:pnTobefilledbyO.E.M.:pvrTobefilledbyO.E.M.:rvnAMICorporation:rnAptioCRB:rvrTobefilledbyO.E.M.:cvnToBeFilledByO.E.M.:ct3:cvrToBeFilledByO.E.M.:*
ACCEL_MOUNT_MATRIX=0, -1, 0; -1, 0, 0; 0, 0, 1
#########################################
@ -717,8 +713,7 @@ sensor:modalias:acpi:SMO8500*:dmi:bvnAmericanMegatrendsInc.:bvr5.6.5:bd07/25/201
# One-netbook OneMix 2s
# OneMix 2s has no product name filled, matching entire dmi-alias
# '*' in ":*svn" is there because kernels >= 5.8 have inserted a br field there
sensor:modalias:acpi:BOSC0200*:dmi:bvnAmericanMegatrendsInc.:bvr5.12:bd10/26/2018:*svnDefaultstring:pnDefaultstring:pvrDefaultstring:rvnDefaultstring:rnDefaultstring:rvrDefaultstring:cvnDefaultstring:ct3:cvrDefaultstring:*
sensor:modalias:acpi:BOSC0200*:dmi:bvnAmericanMegatrendsInc.:bvr5.12:bd10/26/2018:br5.12:svnDefaultstring:pnDefaultstring:pvrDefaultstring:rvnDefaultstring:rnDefaultstring:rvrDefaultstring:cvnDefaultstring:ct3:cvrDefaultstring:*
ACCEL_MOUNT_MATRIX=0, 1, 0; 1, 0, 0; 0, 0, 1
# One-netbook OneMix 3 Pro
@ -727,8 +722,7 @@ sensor:modalias:acpi:BOSC0200*:dmi:*svnONE-NETBOOKTECHNOLOGYCO*:pnOne-Mix3Pro:*
# One-netbook OneMix 3s
# OneMix 3s has no product name filled, matching entire dmi-alias
# '*' in ":*svn" is there because kernels >= 5.8 have inserted a br field there
sensor:modalias:acpi:BOSC0200*:dmi:bvnAmericanMegatrendsInc.:bvr5.12:bd07/17/2019:*svnDefaultstring:pnDefaultstring:pvrDefaultstring:rvnDefaultstring:rnDefaultstring:rvrDefaultstring:cvnDefaultstring:ct3:cvrDefaultstring:*
sensor:modalias:acpi:BOSC0200*:dmi:bvnAmericanMegatrendsInc.:bvr5.12:bd07/17/2019:br5.12:svnDefaultstring:pnDefaultstring:pvrDefaultstring:rvnDefaultstring:rnDefaultstring:rvrDefaultstring:cvnDefaultstring:ct3:cvrDefaultstring:*
ACCEL_MOUNT_MATRIX=-1, 0, 0; 0, 1, 0; 0, 0, 1
#########################################
@ -760,9 +754,8 @@ sensor:modalias:acpi:BMA250E*:dmi:*:svnShenzhenPLOYER*:pnMOMO7W:*
# The Point of View TAB-P800W does not have its product name filled, so we
# match the entire dmi-alias, assuming that the use of a BMA250E +
# bios-version + bios-date combo is unique
# '*' in ":*svn" is there because kernels >= 5.8 have inserted a br field there
sensor:modalias:acpi:BMA250E*:dmi:bvnAmericanMegatrendsInc.:bvr3BAIR1013:bd08/22/2014:*svnTobefilledbyO.E.M.:pnTobefilledbyO.E.M.:pvrTobefilledbyO.E.M.:rvnAMICorporation:rnAptioCRB:rvrTobefilledbyO.E.M.:cvnToBeFilledByO.E.M.:ct3:cvrToBeFilledByO.E.M.:*
sensor:modalias:acpi:BMA250E*:dmi:bvnAmericanMegatrendsInc.:bvr3BAIR1014:bd10/24/2014:*svnTobefilledbyO.E.M.:pnTobefilledbyO.E.M.:pvrTobefilledbyO.E.M.:rvnAMICorporation:rnAptioCRB:rvrTobefilledbyO.E.M.:cvnToBeFilledByO.E.M.:ct3:cvrToBeFilledByO.E.M.:*
sensor:modalias:acpi:BMA250E*:dmi:bvnAmericanMegatrendsInc.:bvr3BAIR1013:bd08/22/2014:svnTobefilledbyO.E.M.:pnTobefilledbyO.E.M.:pvrTobefilledbyO.E.M.:rvnAMICorporation:rnAptioCRB:rvrTobefilledbyO.E.M.:cvnToBeFilledByO.E.M.:ct3:cvrToBeFilledByO.E.M.:*
sensor:modalias:acpi:BMA250E*:dmi:bvnAmericanMegatrendsInc.:bvr3BAIR1014:bd10/24/2014:svnTobefilledbyO.E.M.:pnTobefilledbyO.E.M.:pvrTobefilledbyO.E.M.:rvnAMICorporation:rnAptioCRB:rvrTobefilledbyO.E.M.:cvnToBeFilledByO.E.M.:ct3:cvrToBeFilledByO.E.M.:*
ACCEL_MOUNT_MATRIX=0, 1, 0; 1, 0, 0; 0, 0, 1
# Point of View TAB-P1005W-232 (v2.0)
@ -840,8 +833,7 @@ sensor:modalias:acpi:SMO8500*:dmi:*bd12/19/2014:*:rvnTECLAST:rntPAD:*
ACCEL_MOUNT_MATRIX=1, 0, 0; 0, -1, 0; 0, 0, 1
# Teclast X98 Plus I (A5C6), generic DMI strings, match entire dmi modalias inc. bios-date
# '*' in ":*svn" is there because kernels >= 5.8 have inserted a br field there
sensor:modalias:acpi:KIOX000A*:dmi:bvnAmericanMegatrendsInc.:bvr5.011:bd11/03/2015:*svnTobefilledbyO.E.M.:pnTobefilledbyO.E.M.:pvrTobefilledbyO.E.M.:rvnAMICorporation:rnCherryTrailCR:rvrTobefilledbyO.E.M.:cvnToBeFilledByO.E.M.:ct3:cvrToBeFilledByO.E.M.:*
sensor:modalias:acpi:KIOX000A*:dmi:bvnAmericanMegatrendsInc.:bvr5.011:bd11/03/2015:svnTobefilledbyO.E.M.:pnTobefilledbyO.E.M.:pvrTobefilledbyO.E.M.:rvnAMICorporation:rnCherryTrailCR:rvrTobefilledbyO.E.M.:cvnToBeFilledByO.E.M.:ct3:cvrToBeFilledByO.E.M.:*
ACCEL_MOUNT_MATRIX=0, 1, 0; 1, 0, 0; 0, 0, 1
# Teclast X98 Plus II
@ -853,8 +845,7 @@ sensor:modalias:acpi:KIOX000A*:dmi:*:svnTECLAST:pnX98PlusII:*
#########################################
# Thundersoft TST168 tablet, generic DMI strings, match entire dmi modalias inc. bios-date
# '*' in ":*svn" is there because kernels >= 5.8 have inserted a br field there
sensor:modalias:acpi:BMA250E*:dmi:bvnAmericanMegatrendsInc.:bvr5.6.5:bd04/15/2014:*svnTobefilledbyO.E.M.:pnTobefilledbyO.E.M.:pvrTobefilledbyO.E.M.:rvnAMICorporation:rnAptioCRB:rvrTobefilledbyO.E.M.:cvnToBeFilledByO.E.M.:ct3:cvrToBeFilledByO.E.M.:*
sensor:modalias:acpi:BMA250E*:dmi:bvnAmericanMegatrendsInc.:bvr5.6.5:bd04/15/2014:svnTobefilledbyO.E.M.:pnTobefilledbyO.E.M.:pvrTobefilledbyO.E.M.:rvnAMICorporation:rnAptioCRB:rvrTobefilledbyO.E.M.:cvnToBeFilledByO.E.M.:ct3:cvrToBeFilledByO.E.M.:*
ACCEL_MOUNT_MATRIX=-1, 0, 0; 0, 1, 0; 0, 0, 1
#########################################
@ -923,8 +914,7 @@ sensor:modalias:acpi:SMO8500*:dmi:*:svnUMAX:pnVisionBook10WiPlus:*
# The Winpad A15 does not have its product name filled, so we
# match the entire dmi-alias, assuming that the use of a SMO8500 +
# bios-version + bios-date combo is unique
# '*' in ":*svn" is there because kernels >= 5.8 have inserted a br field there
sensor:modalias:acpi:SMO8500*:dmi:bvnAmericanMegatrendsInc.:bvr5.6.5:bd11/20/2014:*svnTobefilledbyO.E.M.:pnTobefilledbyO.E.M.:pvrTobefilledbyO.E.M.:rvnAMICorporation:rnAptioCRB:rvrTobefilledbyO.E.M.:cvnToBeFilledByO.E.M.:ct3:cvrToBeFilledByO.E.M.:*
sensor:modalias:acpi:SMO8500*:dmi:bvnAmericanMegatrendsInc.:bvr5.6.5:bd11/20/2014:br5.6:svnTobefilledbyO.E.M.:pnTobefilledbyO.E.M.:pvrTobefilledbyO.E.M.:rvnAMICorporation:rnAptioCRB:rvrTobefilledbyO.E.M.:cvnToBeFilledByO.E.M.:ct3:cvrToBeFilledByO.E.M.:*
ACCEL_MOUNT_MATRIX=0, -1, 0; 1, 0, 0; 0, 0, -1
#########################################

View File

@ -1711,7 +1711,7 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
readonly s OnFailureJobMode = '...';
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly b IgnoreOnIsolate = ...;
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly b NeedDaemonReload = ...;
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
readonly as Markers = ['...', ...];

View File

@ -791,14 +791,6 @@
default will be used.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>Independent=</varname></term>
<listitem>
<para>Takes a boolean. When true, the vxlan interface is created without any underlying network
interface. Defaults to false, which means that a .network file that requests this VXLAN interface
using <varname>VXLAN=</varname> is required for the VXLAN to be created.</para>
</listitem>
</varlistentry>
</variablelist>
</refsect1>
@ -875,6 +867,14 @@
<para>Accepts the same key as in [VXLAN] section.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>Independent=</varname></term>
<listitem>
<para>Takes a boolean. When true, the vxlan interface is created without any underlying network
interface. Defaults to false, which means that a .network file that requests this tunnel using
<varname>Tunnel=</varname> is required for the tunnel to be created.</para>
</listitem>
</varlistentry>
</variablelist>
</refsect1>

View File

@ -98,24 +98,6 @@
</listitem>
</varlistentry>
<varlistentry>
<term><option>--property=<replaceable>NAME</replaceable></option></term>
<listitem>
<para>When showing device properties using the <option>--query=property</option>
option, limit display to properties specified in the argument. The argument should
be a comma-separated list of property names. If not specified, all known properties
are shown.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>--value</option></term>
<listitem>
<para>When showing device properties using the <option>--query=property</option>
option, print only their values, and skip the property name and <literal>=</literal>.</para>
<para>Cannot be used together with <option>-x/--export</option> or
<option>-P/--export-prefix</option>.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>-p</option></term>
<term><option>--path=<replaceable>DEVPATH</replaceable></option></term>

View File

@ -49,8 +49,8 @@ _udevadm() {
[COMMON]='-h --help -V --version'
[DEBUG]='-d --debug'
[INFO_STANDALONE]='-r --root -a --attribute-walk -x --export -e --export-db -c --cleanup-db
-w --wait-for-initialization --value'
[INFO_ARG]='-q --query -p --path -n --name -P --export-prefix -d --device-id-of-file --property'
-w --wait-for-initialization'
[INFO_ARG]='-q --query -p --path -n --name -P --export-prefix -d --device-id-of-file'
[TRIGGER_STANDALONE]='-v --verbose -n --dry-run -q --quiet -w --settle --wait-daemon --uuid'
[TRIGGER_ARG]='-t --type -c --action -s --subsystem-match -S --subsystem-nomatch
-a --attr-match -A --attr-nomatch -p --property-match

View File

@ -13,9 +13,7 @@ _udevadm_info(){
'--export-prefix=[Add a prefix to the key name of exported values.]:prefix' \
'--device-id-of-file=[Print major/minor numbers of the underlying device, where the file lives on.]:files:_udevadm_mounts' \
'--export-db[Export the content of the udev database.]' \
'--cleanup-db[Cleanup the udev database.]' \
'--value[When showing properties, print only their values.]' \
'--property=[Show only properties by this name.]'
'--cleanup-db[Cleanup the udev database.]'
}
(( $+functions[_udevadm_trigger] )) ||

View File

@ -1185,21 +1185,6 @@
* passed using %NL80211_ATTR_SAR_SPEC. %NL80211_ATTR_WIPHY is used to
* specify the wiphy index to be applied to.
*
* @NL80211_CMD_OBSS_COLOR_COLLISION: This notification is sent out whenever
* mac80211/drv detects a bss color collision.
*
* @NL80211_CMD_COLOR_CHANGE_REQUEST: This command is used to indicate that
* userspace wants to change the BSS color.
*
* @NL80211_CMD_COLOR_CHANGE_STARTED: Notify userland, that a color change has
* started
*
* @NL80211_CMD_COLOR_CHANGE_ABORTED: Notify userland, that the color change has
* been aborted
*
* @NL80211_CMD_COLOR_CHANGE_COMPLETED: Notify userland that the color change
* has completed
*
* @NL80211_CMD_MAX: highest used command number
* @__NL80211_CMD_AFTER_LAST: internal use
*/
@ -1432,14 +1417,6 @@ enum nl80211_commands {
NL80211_CMD_SET_SAR_SPECS,
NL80211_CMD_OBSS_COLOR_COLLISION,
NL80211_CMD_COLOR_CHANGE_REQUEST,
NL80211_CMD_COLOR_CHANGE_STARTED,
NL80211_CMD_COLOR_CHANGE_ABORTED,
NL80211_CMD_COLOR_CHANGE_COMPLETED,
/* add new commands above here */
/* used to define NL80211_CMD_MAX below */
@ -2583,16 +2560,6 @@ enum nl80211_commands {
* disassoc events to indicate that an immediate reconnect to the AP
* is desired.
*
* @NL80211_ATTR_OBSS_COLOR_BITMAP: bitmap of the u64 BSS colors for the
* %NL80211_CMD_OBSS_COLOR_COLLISION event.
*
* @NL80211_ATTR_COLOR_CHANGE_COUNT: u8 attribute specifying the number of TBTT's
* until the color switch event.
* @NL80211_ATTR_COLOR_CHANGE_COLOR: u8 attribute specifying the color that we are
* switching to
* @NL80211_ATTR_COLOR_CHANGE_ELEMS: Nested set of attributes containing the IE
* information for the time while performing a color switch.
*
* @NUM_NL80211_ATTR: total number of nl80211_attrs available
* @NL80211_ATTR_MAX: highest attribute number currently defined
* @__NL80211_ATTR_AFTER_LAST: internal use
@ -3090,12 +3057,6 @@ enum nl80211_attrs {
NL80211_ATTR_DISABLE_HE,
NL80211_ATTR_OBSS_COLOR_BITMAP,
NL80211_ATTR_COLOR_CHANGE_COUNT,
NL80211_ATTR_COLOR_CHANGE_COLOR,
NL80211_ATTR_COLOR_CHANGE_ELEMS,
/* add attributes here, update the policy in nl80211.c */
__NL80211_ATTR_AFTER_LAST,
@ -5992,9 +5953,6 @@ enum nl80211_feature_flags {
* frame protection for all management frames exchanged during the
* negotiation and range measurement procedure.
*
* @NL80211_EXT_FEATURE_BSS_COLOR: The driver supports BSS color collision
* detection and change announcemnts.
*
* @NUM_NL80211_EXT_FEATURES: number of extended features.
* @MAX_NL80211_EXT_FEATURES: highest extended feature index.
*/
@ -6059,7 +6017,6 @@ enum nl80211_ext_feature_index {
NL80211_EXT_FEATURE_SECURE_LTF,
NL80211_EXT_FEATURE_SECURE_RTT,
NL80211_EXT_FEATURE_PROT_RANGE_NEGO_AND_MEASURE,
NL80211_EXT_FEATURE_BSS_COLOR,
/* add new features before the definition below */
NUM_NL80211_EXT_FEATURES,

View File

@ -44,8 +44,3 @@
#ifndef BOND_MAX_ARP_TARGETS
#define BOND_MAX_ARP_TARGETS 16
#endif
/* Not exposed but defined in include/linux/ieee80211.h */
#ifndef IEEE80211_MAX_SSID_LEN
#define IEEE80211_MAX_SSID_LEN 32
#endif

View File

@ -300,24 +300,6 @@ int strv_split_full(char ***t, const char *s, const char *separators, ExtractFla
return (int) n;
}
int strv_split_and_extend_full(char ***t, const char *s, const char *separators, bool filter_duplicates, ExtractFlags flags) {
_cleanup_strv_free_ char **l = NULL;
int r;
assert(t);
assert(s);
r = strv_split_full(&l, s, separators, flags);
if (r < 0)
return r;
r = strv_extend_strv(t, l, filter_duplicates);
if (r < 0)
return r;
return (int) strv_length(*t);
}
int strv_split_colon_pairs(char ***t, const char *s) {
_cleanup_strv_free_ char **l = NULL;
size_t n = 0;

View File

@ -83,9 +83,6 @@ static inline char **strv_split(const char *s, const char *separators) {
return ret;
}
int strv_split_and_extend_full(char ***t, const char *s, const char *separators, bool filter_duplicates, ExtractFlags flags);
#define strv_split_and_extend(t, s, sep, dup) strv_split_and_extend_full(t, s, sep, dup, 0)
int strv_split_newlines_full(char ***ret, const char *s, ExtractFlags flags);
static inline char **strv_split_newlines(const char *s) {
char **ret;

View File

@ -284,7 +284,7 @@ int unit_file_build_name_map(
continue;
}
FOREACH_DIRENT_ALL(de, d, log_warning_errno(errno, "Failed to read \"%s\", ignoring: %m", *dir)) {
FOREACH_DIRENT(de, d, log_warning_errno(errno, "Failed to read \"%s\", ignoring: %m", *dir)) {
char *filename;
_unused_ _cleanup_free_ char *_filename_free = NULL;
_cleanup_free_ char *simplified = NULL;

View File

@ -909,7 +909,7 @@ const sd_bus_vtable bus_unit_vtable[] = {
SD_BUS_PROPERTY("OnSuccessJobMode", "s", property_get_job_mode, offsetof(Unit, on_success_job_mode), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("OnFailureJobMode", "s", property_get_job_mode, offsetof(Unit, on_failure_job_mode), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("IgnoreOnIsolate", "b", bus_property_get_bool, offsetof(Unit, ignore_on_isolate), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("NeedDaemonReload", "b", property_get_need_daemon_reload, 0, 0),
SD_BUS_PROPERTY("NeedDaemonReload", "b", property_get_need_daemon_reload, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("Markers", "as", property_get_markers, offsetof(Unit, markers), 0),
SD_BUS_PROPERTY("JobTimeoutUSec", "t", bus_property_get_usec, offsetof(Unit, job_timeout), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("JobRunningTimeoutUSec", "t", bus_property_get_usec, offsetof(Unit, job_running_timeout), SD_BUS_VTABLE_PROPERTY_CONST),

View File

@ -1575,10 +1575,6 @@ static int mount_setup_new_unit(
if (r < 0)
return r;
r = mount_add_non_exec_dependencies(MOUNT(u));
if (r < 0)
return r;
/* This unit was generated because /proc/self/mountinfo reported it. Remember this, so that by the time we load
* the unit file for it (and thus add in extra deps right after) we know what source to attributes the deps
* to. */

View File

@ -101,29 +101,15 @@ int dhcp6_option_append_fqdn(uint8_t **buf, size_t *buflen, const char *fqdn);
int dhcp6_option_append_user_class(uint8_t **buf, size_t *buflen, char * const *user_class);
int dhcp6_option_append_vendor_class(uint8_t **buf, size_t *buflen, char * const *user_class);
int dhcp6_option_append_vendor_option(uint8_t **buf, size_t *buflen, OrderedHashmap *vendor_options);
int dhcp6_option_parse(
const uint8_t *buf,
size_t buflen,
size_t *offset,
uint16_t *ret_option_code,
size_t *ret_option_data_len,
const uint8_t **ret_option_data);
int dhcp6_option_parse_status(const uint8_t *data, size_t data_len, char **ret_status_message);
int dhcp6_option_parse_ia(
sd_dhcp6_client *client,
be32_t iaid,
uint16_t option_code,
size_t option_data_len,
const uint8_t *option_data,
DHCP6IA *ret);
int dhcp6_option_parse_addresses(
const uint8_t *optval,
size_t optlen,
struct in6_addr **addrs,
size_t *count);
int dhcp6_option_parse_domainname_list(const uint8_t *optval, size_t optlen, char ***ret);
int dhcp6_option_parse_domainname(const uint8_t *optval, size_t optlen, char **ret);
int dhcp6_option_parse(uint8_t **buf, size_t *buflen, uint16_t *optcode,
size_t *optlen, uint8_t **optvalue);
int dhcp6_option_parse_status(DHCP6Option *option, size_t len);
int dhcp6_option_parse_ia(sd_dhcp6_client *client, DHCP6Option *iaoption, be32_t iaid, DHCP6IA *ia, uint16_t *ret_status_code);
int dhcp6_option_parse_ip6addrs(uint8_t *optval, uint16_t optlen,
struct in6_addr **addrs, size_t count);
int dhcp6_option_parse_domainname_list(const uint8_t *optval, uint16_t optlen,
char ***str_arr);
int dhcp6_option_parse_domainname(const uint8_t *optval, uint16_t optlen, char **str);
int dhcp6_network_bind_udp_socket(int ifindex, struct in6_addr *address);
int dhcp6_network_send_udp_socket(int s, struct in6_addr *address,

View File

@ -28,11 +28,11 @@ struct sd_dhcp6_lease {
struct in6_addr *dns;
size_t dns_count;
char **domains;
size_t domains_count;
struct in6_addr *ntp;
size_t ntp_count;
char **ntp_fqdn;
struct in6_addr *sntp;
size_t sntp_count;
size_t ntp_fqdn_count;
char *fqdn;
};
@ -50,10 +50,12 @@ int dhcp6_lease_get_rapid_commit(sd_dhcp6_lease *lease, bool *rapid_commit);
int dhcp6_lease_get_iaid(sd_dhcp6_lease *lease, be32_t *iaid);
int dhcp6_lease_get_pd_iaid(sd_dhcp6_lease *lease, be32_t *iaid);
int dhcp6_lease_add_dns(sd_dhcp6_lease *lease, const uint8_t *optval, size_t optlen);
int dhcp6_lease_add_domains(sd_dhcp6_lease *lease, const uint8_t *optval, size_t optlen);
int dhcp6_lease_add_ntp(sd_dhcp6_lease *lease, const uint8_t *optval, size_t optlen);
int dhcp6_lease_add_sntp(sd_dhcp6_lease *lease, const uint8_t *optval, size_t optlen) ;
int dhcp6_lease_set_dns(sd_dhcp6_lease *lease, uint8_t *optval, size_t optlen);
int dhcp6_lease_set_domains(sd_dhcp6_lease *lease, uint8_t *optval,
size_t optlen);
int dhcp6_lease_set_ntp(sd_dhcp6_lease *lease, uint8_t *optval, size_t optlen);
int dhcp6_lease_set_sntp(sd_dhcp6_lease *lease, uint8_t *optval,
size_t optlen) ;
int dhcp6_lease_set_fqdn(sd_dhcp6_lease *lease, const uint8_t *optval, size_t optlen);
int dhcp6_lease_new(sd_dhcp6_lease **ret);

View File

@ -14,12 +14,29 @@
#include "dhcp6-lease-internal.h"
#include "dhcp6-protocol.h"
#include "dns-domain.h"
#include "escape.h"
#include "memory-util.h"
#include "sparse-endian.h"
#include "strv.h"
#include "unaligned.h"
typedef struct DHCP6StatusOption {
struct DHCP6Option option;
be16_t status;
char msg[];
} _packed_ DHCP6StatusOption;
typedef struct DHCP6AddressOption {
struct DHCP6Option option;
struct iaaddr iaaddr;
uint8_t options[];
} _packed_ DHCP6AddressOption;
typedef struct DHCP6PDPrefixOption {
struct DHCP6Option option;
struct iapdprefix iapdprefix;
uint8_t options[];
} _packed_ DHCP6PDPrefixOption;
#define DHCP6_OPTION_IA_NA_LEN (sizeof(struct ia_na))
#define DHCP6_OPTION_IA_PD_LEN (sizeof(struct ia_pd))
#define DHCP6_OPTION_IA_TA_LEN (sizeof(struct ia_ta))
@ -353,410 +370,367 @@ int dhcp6_option_append_vendor_class(uint8_t **buf, size_t *buflen, char * const
return dhcp6_option_append(buf, buflen, SD_DHCP6_OPTION_VENDOR_CLASS, total, p);
}
int dhcp6_option_parse(
const uint8_t *buf,
size_t buflen,
size_t *offset,
uint16_t *ret_option_code,
size_t *ret_option_data_len,
const uint8_t **ret_option_data) {
static int option_parse_hdr(uint8_t **buf, size_t *buflen, uint16_t *optcode, size_t *optlen) {
DHCP6Option *option = (DHCP6Option*) *buf;
uint16_t len;
const DHCP6Option *option;
size_t len;
assert_return(buf, -EINVAL);
assert_return(optcode, -EINVAL);
assert_return(optlen, -EINVAL);
assert(buf);
assert(offset);
assert(ret_option_code);
assert(ret_option_data_len);
assert(ret_option_data);
if (buflen < offsetof(DHCP6Option, data))
return -EBADMSG;
if (*offset >= buflen - offsetof(DHCP6Option, data))
return -EBADMSG;
option = (const DHCP6Option*) (buf + *offset);
len = be16toh(option->len);
if (len > buflen - offsetof(DHCP6Option, data) - *offset)
return -EBADMSG;
*offset += offsetof(DHCP6Option, data) + len;
*ret_option_code = be16toh(option->code);
*ret_option_data_len = len;
*ret_option_data = option->data;
return 0;
}
int dhcp6_option_parse_status(const uint8_t *data, size_t data_len, char **ret_status_message) {
assert(data);
if (data_len < sizeof(uint16_t))
return -EBADMSG;
if (ret_status_message) {
char *msg;
/* The status message MUST NOT be null-terminated. See section 21.13 of RFC8415.
* Let's escape unsafe characters for safety. */
msg = cescape_length((const char*) (data + sizeof(uint16_t)), data_len - sizeof(uint16_t));
if (!msg)
return -ENOMEM;
*ret_status_message = msg;
}
return unaligned_read_be16(data);
}
static int dhcp6_option_parse_ia_options(sd_dhcp6_client *client, const uint8_t *buf, size_t buflen) {
int r;
assert(buf);
for(size_t offset = 0; offset < buflen;) {
const uint8_t *data;
size_t data_len;
uint16_t code;
r = dhcp6_option_parse(buf, buflen, &offset, &code, &data_len, &data);
if (r < 0)
return r;
switch(code) {
case SD_DHCP6_OPTION_STATUS_CODE: {
_cleanup_free_ char *msg = NULL;
r = dhcp6_option_parse_status(data, data_len, &msg);
if (r == -ENOMEM)
return r;
if (r < 0)
/* Let's log but ignore the invalid status option. */
log_dhcp6_client_errno(client, r,
"Received an IA address or PD prefix option with an invalid status sub option, ignoring: %m");
else if (r > 0)
return log_dhcp6_client_errno(client, SYNTHETIC_ERRNO(EINVAL),
"Received an IA address or PD prefix option with non-zero status: %s%s%s",
strempty(msg), isempty(msg) ? "" : ": ",
dhcp6_message_status_to_string(r));
break;
}
default:
log_dhcp6_client(client, "Received an unknown sub option %u in IA address or PD prefix, ignoring.", code);
}
}
return 0;
}
static int dhcp6_option_parse_ia_address(sd_dhcp6_client *client, const uint8_t *data, size_t len, DHCP6Address **ret) {
uint32_t lt_valid, lt_pref;
DHCP6Address *a;
int r;
assert(data);
assert(ret);
if (len < sizeof(struct iaaddr))
return -EBADMSG;
lt_valid = be32toh(((const struct iaaddr*) data)->lifetime_valid);
lt_pref = be32toh(((const struct iaaddr*) data)->lifetime_preferred);
if (lt_valid == 0)
return log_dhcp6_client_errno(client, SYNTHETIC_ERRNO(EINVAL),
"Received an IA address with zero valid lifetime, ignoring.");
if (lt_pref > lt_valid)
return log_dhcp6_client_errno(client, SYNTHETIC_ERRNO(EINVAL),
"Received an IA address with preferred lifetime %"PRIu32
" larger than valid lifetime %"PRIu32", ignoring.",
lt_pref, lt_valid);
if (len > sizeof(struct iaaddr)) {
r = dhcp6_option_parse_ia_options(client, data + sizeof(struct iaaddr), len - sizeof(struct iaaddr));
if (r < 0)
return r;
}
a = new(DHCP6Address, 1);
if (!a)
return -ENOMEM;
LIST_INIT(addresses, a);
memcpy(&a->iaaddr, data, sizeof(struct iaaddr));
*ret = a;
return 0;
}
static int dhcp6_option_parse_ia_pdprefix(sd_dhcp6_client *client, const uint8_t *data, size_t len, DHCP6Address **ret) {
uint32_t lt_valid, lt_pref;
DHCP6Address *a;
int r;
if (len < sizeof(struct iapdprefix))
if (*buflen < offsetof(DHCP6Option, data))
return -ENOMSG;
lt_valid = be32toh(((const struct iapdprefix*) data)->lifetime_valid);
lt_pref = be32toh(((const struct iapdprefix*) data)->lifetime_preferred);
len = be16toh(option->len);
if (lt_valid == 0)
if (len > *buflen)
return -ENOMSG;
*optcode = be16toh(option->code);
*optlen = len;
*buf += 4;
*buflen -= 4;
return 0;
}
int dhcp6_option_parse(uint8_t **buf, size_t *buflen, uint16_t *optcode,
size_t *optlen, uint8_t **optvalue) {
int r;
assert_return(buf && buflen && optcode && optlen && optvalue, -EINVAL);
r = option_parse_hdr(buf, buflen, optcode, optlen);
if (r < 0)
return r;
if (*optlen > *buflen)
return -ENOBUFS;
*optvalue = *buf;
*buflen -= *optlen;
*buf += *optlen;
return 0;
}
int dhcp6_option_parse_status(DHCP6Option *option, size_t len) {
DHCP6StatusOption *statusopt = (DHCP6StatusOption *)option;
if (len < sizeof(DHCP6StatusOption) ||
be16toh(option->len) + offsetof(DHCP6Option, data) < sizeof(DHCP6StatusOption))
return -ENOBUFS;
return be16toh(statusopt->status);
}
static int dhcp6_option_parse_address(sd_dhcp6_client *client, DHCP6Option *option, DHCP6IA *ia, uint32_t *ret_lifetime_valid) {
DHCP6AddressOption *addr_option = (DHCP6AddressOption *)option;
DHCP6Address *addr;
uint32_t lt_valid, lt_pref;
int r;
if (be16toh(option->len) + offsetof(DHCP6Option, data) < sizeof(*addr_option))
return -ENOBUFS;
lt_valid = be32toh(addr_option->iaaddr.lifetime_valid);
lt_pref = be32toh(addr_option->iaaddr.lifetime_preferred);
if (lt_valid == 0 || lt_pref > lt_valid)
return log_dhcp6_client_errno(client, SYNTHETIC_ERRNO(EINVAL),
"Received a PD prefix with zero valid lifetime, ignoring.");
if (lt_pref > lt_valid)
return log_dhcp6_client_errno(client, SYNTHETIC_ERRNO(EINVAL),
"Received a PD prefix with preferred lifetime %"PRIu32
" larger than valid lifetime %"PRIu32", ignoring.",
"Valid lifetime of an IA address is zero or "
"preferred lifetime %"PRIu32" > valid lifetime %"PRIu32,
lt_pref, lt_valid);
if (len > sizeof(struct iapdprefix)) {
r = dhcp6_option_parse_ia_options(client, data + sizeof(struct iapdprefix), len - sizeof(struct iapdprefix));
if (be16toh(option->len) + offsetof(DHCP6Option, data) > sizeof(*addr_option)) {
r = dhcp6_option_parse_status((DHCP6Option *)addr_option->options, be16toh(option->len) + offsetof(DHCP6Option, data) - sizeof(*addr_option));
if (r < 0)
return r;
if (r > 0)
return log_dhcp6_client_errno(client, SYNTHETIC_ERRNO(EINVAL),
"Non-zero status code '%s' for address is received",
dhcp6_message_status_to_string(r));
}
a = new(DHCP6Address, 1);
if (!a)
addr = new0(DHCP6Address, 1);
if (!addr)
return -ENOMEM;
LIST_INIT(addresses, a);
memcpy(&a->iapdprefix, data, sizeof(struct iapdprefix));
LIST_INIT(addresses, addr);
memcpy(&addr->iaaddr, option->data, sizeof(addr->iaaddr));
LIST_PREPEND(addresses, ia->addresses, addr);
*ret_lifetime_valid = be32toh(addr->iaaddr.lifetime_valid);
return 0;
}
static int dhcp6_option_parse_pdprefix(sd_dhcp6_client *client, DHCP6Option *option, DHCP6IA *ia, uint32_t *ret_lifetime_valid) {
DHCP6PDPrefixOption *pdprefix_option = (DHCP6PDPrefixOption *)option;
DHCP6Address *prefix;
uint32_t lt_valid, lt_pref;
int r;
if (be16toh(option->len) + offsetof(DHCP6Option, data) < sizeof(*pdprefix_option))
return -ENOBUFS;
lt_valid = be32toh(pdprefix_option->iapdprefix.lifetime_valid);
lt_pref = be32toh(pdprefix_option->iapdprefix.lifetime_preferred);
if (lt_valid == 0 || lt_pref > lt_valid)
return log_dhcp6_client_errno(client, SYNTHETIC_ERRNO(EINVAL),
"Valid lifetieme of a PD prefix is zero or "
"preferred lifetime %"PRIu32" > valid lifetime %"PRIu32,
lt_pref, lt_valid);
if (be16toh(option->len) + offsetof(DHCP6Option, data) > sizeof(*pdprefix_option)) {
r = dhcp6_option_parse_status((DHCP6Option *)pdprefix_option->options, be16toh(option->len) + offsetof(DHCP6Option, data) - sizeof(*pdprefix_option));
if (r < 0)
return r;
if (r > 0)
return log_dhcp6_client_errno(client, SYNTHETIC_ERRNO(EINVAL),
"Non-zero status code '%s' for PD prefix is received",
dhcp6_message_status_to_string(r));
}
prefix = new0(DHCP6Address, 1);
if (!prefix)
return -ENOMEM;
LIST_INIT(addresses, prefix);
memcpy(&prefix->iapdprefix, option->data, sizeof(prefix->iapdprefix));
LIST_PREPEND(addresses, ia->addresses, prefix);
*ret_lifetime_valid = be32toh(prefix->iapdprefix.lifetime_valid);
*ret = a;
return 0;
}
int dhcp6_option_parse_ia(
sd_dhcp6_client *client,
DHCP6Option *iaoption,
be32_t iaid,
uint16_t option_code,
size_t option_data_len,
const uint8_t *option_data,
DHCP6IA *ret) {
DHCP6IA *ia,
uint16_t *ret_status_code) {
_cleanup_(dhcp6_lease_free_ia) DHCP6IA ia = {};
uint32_t lt_t1, lt_t2, lt_min = UINT32_MAX;
be32_t received_iaid;
size_t offset;
int r;
uint32_t lt_t1, lt_t2, lt_valid = 0, lt_min = UINT32_MAX;
uint16_t iatype, optlen;
size_t iaaddr_offset;
int r = 0, status;
size_t i, len;
uint16_t opt;
assert(IN_SET(option_code, SD_DHCP6_OPTION_IA_NA, SD_DHCP6_OPTION_IA_TA, SD_DHCP6_OPTION_IA_PD));
assert(option_data);
assert(ret);
assert_return(ia, -EINVAL);
assert_return(!ia->addresses, -EINVAL);
/* This will return the following:
* -ENOMEM: memory allocation error,
* -ENOANO: unmatching IAID,
* -EINVAL: non-zero status code, or invalid lifetime,
* -EBADMSG: invalid message format,
* -ENODATA: no valid address or PD prefix,
* 0: success. */
iatype = be16toh(iaoption->code);
len = be16toh(iaoption->len);
switch (option_code) {
switch (iatype) {
case SD_DHCP6_OPTION_IA_NA:
if (option_data_len < DHCP6_OPTION_IA_NA_LEN)
return -EBADMSG;
if (len < DHCP6_OPTION_IA_NA_LEN)
return -ENOBUFS;
offset = DHCP6_OPTION_IA_NA_LEN;
/* According to RFC8415, IAs which do not match the client's IAID should be ignored,
* but not necessary to ignore or refuse the whole message. */
if (((const struct ia_na*) iaoption->data)->id != iaid)
/* ENOANO indicates the option should be ignored. */
return log_dhcp6_client_errno(client, SYNTHETIC_ERRNO(ENOANO),
"Received an IA_NA option with a different IAID "
"from the one chosen by the client, ignoring.");
iaaddr_offset = DHCP6_OPTION_IA_NA_LEN;
memcpy(&ia->ia_na, iaoption->data, sizeof(ia->ia_na));
lt_t1 = be32toh(ia->ia_na.lifetime_t1);
lt_t2 = be32toh(ia->ia_na.lifetime_t2);
if (lt_t1 > lt_t2)
return log_dhcp6_client_errno(client, SYNTHETIC_ERRNO(EINVAL),
"IA NA T1 %"PRIu32"sec > T2 %"PRIu32"sec",
lt_t1, lt_t2);
received_iaid = ((const struct ia_na*) option_data)->id;
lt_t1 = be32toh(((const struct ia_na*) option_data)->lifetime_t1);
lt_t2 = be32toh(((const struct ia_na*) option_data)->lifetime_t2);
break;
case SD_DHCP6_OPTION_IA_PD:
if (option_data_len < DHCP6_OPTION_IA_PD_LEN)
return -EBADMSG;
if (len < sizeof(ia->ia_pd))
return -ENOBUFS;
offset = DHCP6_OPTION_IA_PD_LEN;
/* According to RFC8415, IAs which do not match the client's IAID should be ignored,
* but not necessary to ignore or refuse the whole message. */
if (((const struct ia_pd*) iaoption->data)->id != iaid)
/* ENOANO indicates the option should be ignored. */
return log_dhcp6_client_errno(client, SYNTHETIC_ERRNO(ENOANO),
"Received an IA_PD option with a different IAID "
"from the one chosen by the client, ignoring.");
iaaddr_offset = sizeof(ia->ia_pd);
memcpy(&ia->ia_pd, iaoption->data, sizeof(ia->ia_pd));
lt_t1 = be32toh(ia->ia_pd.lifetime_t1);
lt_t2 = be32toh(ia->ia_pd.lifetime_t2);
if (lt_t1 > lt_t2)
return log_dhcp6_client_errno(client, SYNTHETIC_ERRNO(EINVAL),
"IA PD T1 %"PRIu32"sec > T2 %"PRIu32"sec",
lt_t1, lt_t2);
received_iaid = ((const struct ia_pd*) option_data)->id;
lt_t1 = be32toh(((const struct ia_pd*) option_data)->lifetime_t1);
lt_t2 = be32toh(((const struct ia_pd*) option_data)->lifetime_t2);
break;
case SD_DHCP6_OPTION_IA_TA:
if (option_data_len < DHCP6_OPTION_IA_TA_LEN)
return -ENOMSG;
if (len < DHCP6_OPTION_IA_TA_LEN)
return -ENOBUFS;
offset = DHCP6_OPTION_IA_TA_LEN;
/* According to RFC8415, IAs which do not match the client's IAID should be ignored,
* but not necessary to ignore or refuse the whole message. */
if (((const struct ia_ta*) iaoption->data)->id != iaid)
/* ENOANO indicates the option should be ignored. */
return log_dhcp6_client_errno(client, SYNTHETIC_ERRNO(ENOANO),
"Received an IA_TA option with a different IAID "
"from the one chosen by the client, ignoring.");
iaaddr_offset = DHCP6_OPTION_IA_TA_LEN;
memcpy(&ia->ia_ta, iaoption->data, sizeof(ia->ia_ta));
received_iaid = ((const struct ia_ta*) option_data)->id;
lt_t1 = lt_t2 = 0; /* No lifetime for IA_TA. */
break;
default:
assert_not_reached();
return -EINVAL;
}
/* According to RFC8415, IAs which do not match the client's IAID should be ignored,
* but not necessary to ignore or refuse the whole message. */
if (received_iaid != iaid)
return log_dhcp6_client_errno(client, SYNTHETIC_ERRNO(ENOANO),
"Received an IA option with a different IAID "
"from the one chosen by the client, ignoring.");
ia->type = iatype;
i = iaaddr_offset;
if (lt_t1 > lt_t2)
return log_dhcp6_client_errno(client, SYNTHETIC_ERRNO(EINVAL),
"Received an IA option with T1 %"PRIu32"sec > T2 %"PRIu32"sec, ignoring.",
lt_t1, lt_t2);
while (i < len) {
DHCP6Option *option = (DHCP6Option *)&iaoption->data[i];
for (; offset < option_data_len;) {
const uint8_t *subdata;
size_t subdata_len;
uint16_t subopt;
if (len < i + sizeof(*option) || len < i + sizeof(*option) + be16toh(option->len))
return -ENOBUFS;
r = dhcp6_option_parse(option_data, option_data_len, &offset, &subopt, &subdata_len, &subdata);
if (r < 0)
return r;
opt = be16toh(option->code);
optlen = be16toh(option->len);
switch (subopt) {
case SD_DHCP6_OPTION_IAADDR: {
DHCP6Address *a;
switch (opt) {
case SD_DHCP6_OPTION_IAADDR:
if (!IN_SET(option_code, SD_DHCP6_OPTION_IA_NA, SD_DHCP6_OPTION_IA_TA)) {
log_dhcp6_client(client, "Received an IA_PD option with an IA address, ignoring.");
continue;
}
r = dhcp6_option_parse_ia_address(client, subdata, subdata_len, &a);
if (r == -ENOMEM)
return r;
if (r < 0)
/* Ignore the sub-option on non-critical errors. */
continue;
lt_min = MIN(lt_min, a->iaaddr.lifetime_valid);
LIST_PREPEND(addresses, ia.addresses, a);
break;
}
case SD_DHCP6_OPTION_IA_PD_PREFIX: {
DHCP6Address *a;
if (option_code != SD_DHCP6_OPTION_IA_PD) {
log_dhcp6_client(client, "Received an IA_NA or IA_TA option with an PD prefix, ignoring");
continue;
}
r = dhcp6_option_parse_ia_pdprefix(client, subdata, subdata_len, &a);
if (r == -ENOMEM)
return r;
if (r < 0)
/* Ignore the sub-option on non-critical errors. */
continue;
lt_min = MIN(lt_min, a->iapdprefix.lifetime_valid);
LIST_PREPEND(addresses, ia.addresses, a);
break;
}
case SD_DHCP6_OPTION_STATUS_CODE: {
_cleanup_free_ char *msg = NULL;
r = dhcp6_option_parse_status(subdata, subdata_len, &msg);
if (r == -ENOMEM)
return r;
if (r < 0)
log_dhcp6_client_errno(client, r,
"Received an IA option with an invalid status sub option, ignoring: %m");
else if (r > 0)
if (!IN_SET(ia->type, SD_DHCP6_OPTION_IA_NA, SD_DHCP6_OPTION_IA_TA))
return log_dhcp6_client_errno(client, SYNTHETIC_ERRNO(EINVAL),
"Received an IA option with non-zero status: %s%s%s",
strempty(msg), isempty(msg) ? "" : ": ",
dhcp6_message_status_to_string(r));
"IA Address option not in IA NA or TA option");
r = dhcp6_option_parse_address(client, option, ia, &lt_valid);
if (r < 0 && r != -EINVAL)
return r;
if (r >= 0 && lt_valid < lt_min)
lt_min = lt_valid;
break;
case SD_DHCP6_OPTION_IA_PD_PREFIX:
if (ia->type != SD_DHCP6_OPTION_IA_PD)
return log_dhcp6_client_errno(client, SYNTHETIC_ERRNO(EINVAL),
"IA PD Prefix option not in IA PD option");
r = dhcp6_option_parse_pdprefix(client, option, ia, &lt_valid);
if (r < 0 && r != -EINVAL)
return r;
if (r >= 0 && lt_valid < lt_min)
lt_min = lt_valid;
break;
case SD_DHCP6_OPTION_STATUS_CODE:
status = dhcp6_option_parse_status(option, optlen + offsetof(DHCP6Option, data));
if (status < 0)
return status;
if (status > 0) {
if (ret_status_code)
*ret_status_code = status;
log_dhcp6_client(client, "IA status %s",
dhcp6_message_status_to_string(status));
return 0;
}
break;
default:
log_dhcp6_client(client, "Unknown IA option %d", opt);
break;
}
default:
log_dhcp6_client(client, "Received an IA option with an unknown sub-option %u, ignoring", subopt);
}
i += sizeof(*option) + optlen;
}
if (!ia.addresses)
return log_dhcp6_client_errno(client, SYNTHETIC_ERRNO(ENODATA),
"Received an IA option without valid IA addresses or PD prefixes, ignoring.");
if (IN_SET(option_code, SD_DHCP6_OPTION_IA_NA, SD_DHCP6_OPTION_IA_PD) &&
lt_t1 == 0 && lt_t2 == 0 && lt_min != UINT32_MAX) {
lt_t1 = lt_min / 2;
lt_t2 = lt_min / 10 * 8;
log_dhcp6_client(client, "Received an IA option with both T1 and T2 equal to zero. "
"Adjusting them based on the minimum valid lifetime of IA addresses or PD prefixes: "
"T1=%"PRIu32"sec, T2=%"PRIu32"sec", lt_t1, lt_t2);
}
switch(option_code) {
switch(iatype) {
case SD_DHCP6_OPTION_IA_NA:
*ret = (DHCP6IA) {
.type = option_code,
.ia_na.id = iaid,
.ia_na.lifetime_t1 = htobe32(lt_t1),
.ia_na.lifetime_t2 = htobe32(lt_t2),
.addresses = TAKE_PTR(ia.addresses),
};
break;
case SD_DHCP6_OPTION_IA_TA:
*ret = (DHCP6IA) {
.type = option_code,
.ia_ta.id = iaid,
.addresses = TAKE_PTR(ia.addresses),
};
if (ia->ia_na.lifetime_t1 == 0 && ia->ia_na.lifetime_t2 == 0 && lt_min != UINT32_MAX) {
lt_t1 = lt_min / 2;
lt_t2 = lt_min / 10 * 8;
ia->ia_na.lifetime_t1 = htobe32(lt_t1);
ia->ia_na.lifetime_t2 = htobe32(lt_t2);
log_dhcp6_client(client, "Computed IA NA T1 %"PRIu32"sec and T2 %"PRIu32"sec as both were zero",
lt_t1, lt_t2);
}
break;
case SD_DHCP6_OPTION_IA_PD:
*ret = (DHCP6IA) {
.type = option_code,
.ia_pd.id = iaid,
.ia_pd.lifetime_t1 = htobe32(lt_t1),
.ia_pd.lifetime_t2 = htobe32(lt_t2),
.addresses = TAKE_PTR(ia.addresses),
};
if (ia->ia_pd.lifetime_t1 == 0 && ia->ia_pd.lifetime_t2 == 0 && lt_min != UINT32_MAX) {
lt_t1 = lt_min / 2;
lt_t2 = lt_min / 10 * 8;
ia->ia_pd.lifetime_t1 = htobe32(lt_t1);
ia->ia_pd.lifetime_t2 = htobe32(lt_t2);
log_dhcp6_client(client, "Computed IA PD T1 %"PRIu32"sec and T2 %"PRIu32"sec as both were zero",
lt_t1, lt_t2);
}
break;
default:
assert_not_reached();
break;
}
return 0;
if (ret_status_code)
*ret_status_code = 0;
return 1;
}
int dhcp6_option_parse_addresses(
const uint8_t *optval,
size_t optlen,
struct in6_addr **addrs,
size_t *count) {
assert(optval);
assert(addrs);
assert(count);
int dhcp6_option_parse_ip6addrs(uint8_t *optval, uint16_t optlen,
struct in6_addr **addrs, size_t count) {
if (optlen == 0 || optlen % sizeof(struct in6_addr) != 0)
return -EBADMSG;
return -EINVAL;
if (!GREEDY_REALLOC(*addrs, *count + optlen / sizeof(struct in6_addr)))
if (!GREEDY_REALLOC(*addrs, count * sizeof(struct in6_addr) + optlen))
return -ENOMEM;
memcpy(*addrs + *count, optval, optlen);
*count += optlen / sizeof(struct in6_addr);
memcpy(*addrs + count, optval, optlen);
return 0;
count += optlen / sizeof(struct in6_addr);
return count;
}
static int parse_domain(const uint8_t **data, size_t *len, char **ret) {
_cleanup_free_ char *domain = NULL;
const uint8_t *optval;
size_t optlen, n = 0;
static int parse_domain(const uint8_t **data, uint16_t *len, char **out_domain) {
_cleanup_free_ char *ret = NULL;
const uint8_t *optval = *data;
uint16_t optlen = *len;
bool first = true;
size_t n = 0;
int r;
assert(data);
assert(*data);
assert(len);
assert(ret);
optval = *data;
optlen = *len;
if (optlen <= 1)
return -ENODATA;
@ -780,44 +754,42 @@ static int parse_domain(const uint8_t **data, size_t *len, char **ret) {
return -EMSGSIZE;
/* Literal label */
label = (const char*) optval;
label = (const char *)optval;
optval += c;
optlen -= c;
if (!GREEDY_REALLOC(domain, n + (n != 0) + DNS_LABEL_ESCAPED_MAX))
if (!GREEDY_REALLOC(ret, n + !first + DNS_LABEL_ESCAPED_MAX))
return -ENOMEM;
if (n != 0)
domain[n++] = '.';
if (first)
first = false;
else
ret[n++] = '.';
r = dns_label_escape(label, c, domain + n, DNS_LABEL_ESCAPED_MAX);
r = dns_label_escape(label, c, ret + n, DNS_LABEL_ESCAPED_MAX);
if (r < 0)
return r;
n += r;
}
if (n > 0) {
if (!GREEDY_REALLOC(domain, n + 1))
if (n) {
if (!GREEDY_REALLOC(ret, n + 1))
return -ENOMEM;
domain[n] = '\0';
ret[n] = 0;
}
*ret = TAKE_PTR(domain);
*out_domain = TAKE_PTR(ret);
*data = optval;
*len = optlen;
return n;
}
int dhcp6_option_parse_domainname(const uint8_t *optval, size_t optlen, char **ret) {
int dhcp6_option_parse_domainname(const uint8_t *optval, uint16_t optlen, char **str) {
_cleanup_free_ char *domain = NULL;
int r;
assert(optval);
assert(ret);
r = parse_domain(&optval, &optlen, &domain);
if (r < 0)
return r;
@ -826,38 +798,39 @@ int dhcp6_option_parse_domainname(const uint8_t *optval, size_t optlen, char **r
if (optlen != 0)
return -EINVAL;
*ret = TAKE_PTR(domain);
*str = TAKE_PTR(domain);
return 0;
}
int dhcp6_option_parse_domainname_list(const uint8_t *optval, size_t optlen, char ***ret) {
int dhcp6_option_parse_domainname_list(const uint8_t *optval, uint16_t optlen, char ***str_arr) {
size_t idx = 0;
_cleanup_strv_free_ char **names = NULL;
int r;
assert(optval);
assert(ret);
if (optlen <= 1)
return -ENODATA;
if (optval[optlen - 1] != '\0')
return -EINVAL;
while (optlen > 0) {
_cleanup_free_ char *name = NULL;
_cleanup_free_ char *ret = NULL;
r = parse_domain(&optval, &optlen, &name);
r = parse_domain(&optval, &optlen, &ret);
if (r < 0)
return r;
if (r == 0)
continue;
r = strv_consume(&names, TAKE_PTR(name));
r = strv_extend(&names, ret);
if (r < 0)
return r;
idx++;
}
*ret = TAKE_PTR(names);
return 0;
*str_arr = TAKE_PTR(names);
return idx;
}
static sd_dhcp6_option* dhcp6_option_free(sd_dhcp6_option *i) {

View File

@ -1109,9 +1109,11 @@ static int client_parse_message(
size_t len,
sd_dhcp6_lease *lease) {
uint32_t lt_t1 = UINT32_MAX, lt_t2 = UINT32_MAX;
uint16_t ia_na_status = 0, ia_pd_status = 0;
uint32_t lt_t1 = ~0, lt_t2 = ~0;
usec_t irt = IRT_DEFAULT;
bool clientid = false;
size_t pos = 0;
int r;
assert(client);
@ -1120,14 +1122,22 @@ static int client_parse_message(
assert(lease);
len -= sizeof(DHCP6Message);
for (size_t offset = 0; offset < len;) {
uint16_t optcode;
size_t optlen;
const uint8_t *optval;
r = dhcp6_option_parse(message->options, len, &offset, &optcode, &optlen, &optval);
if (r < 0)
return r;
while (pos < len) {
DHCP6Option *option = (DHCP6Option *) &message->options[pos];
uint16_t optcode, optlen;
int status;
uint8_t *optval;
if (len < pos + offsetof(DHCP6Option, data))
return -ENOBUFS;
optcode = be16toh(option->code);
optlen = be16toh(option->len);
optval = option->data;
if (len < pos + offsetof(DHCP6Option, data) + optlen)
return -ENOBUFS;
switch (optcode) {
case SD_DHCP6_OPTION_CLIENTID:
@ -1166,75 +1176,62 @@ static int client_parse_message(
break;
case SD_DHCP6_OPTION_STATUS_CODE: {
_cleanup_free_ char *msg = NULL;
case SD_DHCP6_OPTION_STATUS_CODE:
status = dhcp6_option_parse_status(option, optlen + sizeof(DHCP6Option));
if (status < 0)
return status;
r = dhcp6_option_parse_status(optval, optlen, &msg);
if (r < 0)
return r;
if (r > 0)
return log_dhcp6_client_errno(client, SYNTHETIC_ERRNO(EINVAL),
"Received %s message with non-zero status: %s%s%s",
if (status > 0)
return log_dhcp6_client_errno(client, SYNTHETIC_ERRNO(EINVAL), "%s Status %s",
dhcp6_message_type_to_string(message->type),
strempty(msg), isempty(msg) ? "" : ": ",
dhcp6_message_status_to_string(r));
break;
}
case SD_DHCP6_OPTION_IA_NA: {
_cleanup_(dhcp6_lease_free_ia) DHCP6IA ia = {};
dhcp6_message_status_to_string(status));
break;
case SD_DHCP6_OPTION_IA_NA:
if (client->state == DHCP6_STATE_INFORMATION_REQUEST) {
log_dhcp6_client(client, "Ignoring IA NA option in information requesting mode.");
break;
}
r = dhcp6_option_parse_ia(client, client->ia_pd.ia_na.id, optcode, optlen, optval, &ia);
if (r == -ENOMEM)
r = dhcp6_option_parse_ia(client, option, client->ia_pd.ia_na.id, &lease->ia, &ia_na_status);
if (r < 0 && r != -ENOANO)
return r;
if (r < 0)
continue;
if (lease->ia.addresses) {
log_dhcp6_client(client, "Received duplicate matching IA_NA option, ignoring.");
if (ia_na_status == DHCP6_STATUS_NO_ADDRS_AVAIL) {
pos += offsetof(DHCP6Option, data) + optlen;
continue;
}
lease->ia = ia;
ia = (DHCP6IA) {};
lt_t1 = MIN(lt_t1, be32toh(lease->ia.ia_na.lifetime_t1));
lt_t2 = MIN(lt_t2, be32toh(lease->ia.ia_na.lifetime_t2));
if (lease->ia.addresses) {
lt_t1 = MIN(lt_t1, be32toh(lease->ia.ia_na.lifetime_t1));
lt_t2 = MIN(lt_t2, be32toh(lease->ia.ia_na.lifetime_t2));
}
break;
}
case SD_DHCP6_OPTION_IA_PD: {
_cleanup_(dhcp6_lease_free_ia) DHCP6IA ia = {};
case SD_DHCP6_OPTION_IA_PD:
if (client->state == DHCP6_STATE_INFORMATION_REQUEST) {
log_dhcp6_client(client, "Ignoring IA PD option in information requesting mode.");
break;
}
r = dhcp6_option_parse_ia(client, client->ia_pd.ia_pd.id, optcode, optlen, optval, &ia);
if (r == -ENOMEM)
r = dhcp6_option_parse_ia(client, option, client->ia_pd.ia_pd.id, &lease->pd, &ia_pd_status);
if (r < 0 && r != -ENOANO)
return r;
if (r < 0)
continue;
if (lease->pd.addresses) {
log_dhcp6_client(client, "Received duplicate matching IA_PD option, ignoring.");
if (ia_pd_status == DHCP6_STATUS_NO_PREFIX_AVAIL) {
pos += offsetof(DHCP6Option, data) + optlen;
continue;
}
lease->pd = ia;
ia = (DHCP6IA) {};
lt_t1 = MIN(lt_t1, be32toh(lease->pd.ia_pd.lifetime_t1));
lt_t2 = MIN(lt_t2, be32toh(lease->pd.ia_pd.lifetime_t2));
if (lease->pd.addresses) {
lt_t1 = MIN(lt_t1, be32toh(lease->pd.ia_pd.lifetime_t1));
lt_t2 = MIN(lt_t2, be32toh(lease->pd.ia_pd.lifetime_t2));
}
break;
}
case SD_DHCP6_OPTION_RAPID_COMMIT:
r = dhcp6_lease_set_rapid_commit(lease);
if (r < 0)
@ -1243,28 +1240,28 @@ static int client_parse_message(
break;
case SD_DHCP6_OPTION_DNS_SERVERS:
r = dhcp6_lease_add_dns(lease, optval, optlen);
r = dhcp6_lease_set_dns(lease, optval, optlen);
if (r < 0)
return r;
break;
case SD_DHCP6_OPTION_DOMAIN_LIST:
r = dhcp6_lease_add_domains(lease, optval, optlen);
r = dhcp6_lease_set_domains(lease, optval, optlen);
if (r < 0)
return r;
break;
case SD_DHCP6_OPTION_NTP_SERVER:
r = dhcp6_lease_add_ntp(lease, optval, optlen);
r = dhcp6_lease_set_ntp(lease, optval, optlen);
if (r < 0)
return r;
break;
case SD_DHCP6_OPTION_SNTP_SERVERS:
r = dhcp6_lease_add_sntp(lease, optval, optlen);
r = dhcp6_lease_set_sntp(lease, optval, optlen);
if (r < 0)
return r;
@ -1284,8 +1281,13 @@ static int client_parse_message(
irt = unaligned_read_be32((be32_t *) optval) * USEC_PER_SEC;
break;
}
pos += offsetof(DHCP6Option, data) + optlen;
}
if (ia_na_status > 0 && ia_pd_status > 0)
return log_dhcp6_client_errno(client, SYNTHETIC_ERRNO(EINVAL), "No IA_PD prefix or IA_NA address received. Ignoring.");
if (!clientid)
return log_dhcp6_client_errno(client, SYNTHETIC_ERRNO(EINVAL), "%s has incomplete options",
dhcp6_message_type_to_string(message->type));
@ -1295,19 +1297,16 @@ static int client_parse_message(
if (r < 0)
return log_dhcp6_client_errno(client, r, "%s has no server id",
dhcp6_message_type_to_string(message->type));
}
if (!lease->ia.addresses && !lease->pd.addresses)
return log_dhcp6_client_errno(client, SYNTHETIC_ERRNO(EINVAL), "No IA_PD prefix or IA_NA address received. Ignoring.");
if (lease->ia.addresses) {
lease->ia.ia_na.lifetime_t1 = htobe32(lt_t1);
lease->ia.ia_na.lifetime_t2 = htobe32(lt_t2);
}
if (lease->ia.addresses) {
lease->ia.ia_na.lifetime_t1 = htobe32(lt_t1);
lease->ia.ia_na.lifetime_t2 = htobe32(lt_t2);
}
if (lease->pd.addresses) {
lease->pd.ia_pd.lifetime_t1 = htobe32(lt_t1);
lease->pd.ia_pd.lifetime_t2 = htobe32(lt_t2);
}
if (lease->pd.addresses) {
lease->pd.ia_pd.lifetime_t1 = htobe32(lt_t1);
lease->pd.ia_pd.lifetime_t2 = htobe32(lt_t2);
}
client->information_refresh_time_usec = MAX(irt, IRT_MINIMUM);

View File

@ -193,69 +193,86 @@ void sd_dhcp6_lease_reset_pd_prefix_iter(sd_dhcp6_lease *lease) {
lease->prefix_iter = lease->pd.addresses;
}
int dhcp6_lease_add_dns(sd_dhcp6_lease *lease, const uint8_t *optval, size_t optlen) {
assert_return(lease, -EINVAL);
assert_return(optval, -EINVAL);
if (optlen == 0)
return 0;
return dhcp6_option_parse_addresses(optval, optlen, &lease->dns, &lease->dns_count);
}
int sd_dhcp6_lease_get_dns(sd_dhcp6_lease *lease, const struct in6_addr **ret) {
assert_return(lease, -EINVAL);
assert_return(ret, -EINVAL);
if (!lease->dns)
return -ENOENT;
*ret = lease->dns;
return lease->dns_count;
}
int dhcp6_lease_add_domains(sd_dhcp6_lease *lease, const uint8_t *optval, size_t optlen) {
_cleanup_strv_free_ char **domains = NULL;
int dhcp6_lease_set_dns(sd_dhcp6_lease *lease, uint8_t *optval, size_t optlen) {
int r;
assert_return(lease, -EINVAL);
assert_return(optval, -EINVAL);
if (optlen == 0)
if (!optlen)
return 0;
r = dhcp6_option_parse_ip6addrs(optval, optlen, &lease->dns,
lease->dns_count);
if (r < 0)
return r;
lease->dns_count = r;
return 0;
}
int sd_dhcp6_lease_get_dns(sd_dhcp6_lease *lease, const struct in6_addr **addrs) {
assert_return(lease, -EINVAL);
assert_return(addrs, -EINVAL);
if (lease->dns_count) {
*addrs = lease->dns;
return lease->dns_count;
}
return -ENOENT;
}
int dhcp6_lease_set_domains(sd_dhcp6_lease *lease, uint8_t *optval,
size_t optlen) {
int r;
char **domains;
assert_return(lease, -EINVAL);
assert_return(optval, -EINVAL);
if (!optlen)
return 0;
r = dhcp6_option_parse_domainname_list(optval, optlen, &domains);
if (r < 0)
return r;
return 0;
return strv_extend_strv(&lease->domains, domains, true);
strv_free_and_replace(lease->domains, domains);
lease->domains_count = r;
return r;
}
int sd_dhcp6_lease_get_domains(sd_dhcp6_lease *lease, char ***ret) {
int sd_dhcp6_lease_get_domains(sd_dhcp6_lease *lease, char ***domains) {
assert_return(lease, -EINVAL);
assert_return(ret, -EINVAL);
assert_return(domains, -EINVAL);
if (!lease->domains)
return -ENOENT;
if (lease->domains_count) {
*domains = lease->domains;
return lease->domains_count;
}
*ret = lease->domains;
return strv_length(lease->domains);
return -ENOENT;
}
int dhcp6_lease_add_ntp(sd_dhcp6_lease *lease, const uint8_t *optval, size_t optlen) {
int dhcp6_lease_set_ntp(sd_dhcp6_lease *lease, uint8_t *optval, size_t optlen) {
int r;
uint16_t subopt;
size_t sublen;
uint8_t *subval;
assert_return(lease, -EINVAL);
assert_return(optval, -EINVAL);
for (size_t offset = 0; offset < optlen;) {
const uint8_t *subval;
size_t sublen;
uint16_t subopt;
lease->ntp = mfree(lease->ntp);
lease->ntp_count = 0;
r = dhcp6_option_parse(optval, optlen, &offset, &subopt, &sublen, &subval);
if (r < 0)
return r;
while ((r = dhcp6_option_parse(&optval, &optlen, &subopt, &sublen,
&subval)) >= 0) {
int s;
char **servers;
switch(subopt) {
case DHCP6_NTP_SUBOPTION_SRV_ADDR:
@ -263,74 +280,86 @@ int dhcp6_lease_add_ntp(sd_dhcp6_lease *lease, const uint8_t *optval, size_t opt
if (sublen != 16)
return 0;
r = dhcp6_option_parse_addresses(subval, sublen, &lease->ntp, &lease->ntp_count);
if (r < 0)
return r;
s = dhcp6_option_parse_ip6addrs(subval, sublen,
&lease->ntp,
lease->ntp_count);
if (s < 0)
return s;
lease->ntp_count = s;
break;
case DHCP6_NTP_SUBOPTION_SRV_FQDN: {
_cleanup_free_ char *server = NULL;
r = dhcp6_option_parse_domainname(subval, sublen, &server);
case DHCP6_NTP_SUBOPTION_SRV_FQDN:
r = dhcp6_option_parse_domainname_list(subval, sublen,
&servers);
if (r < 0)
return r;
return 0;
if (strv_contains(lease->ntp_fqdn, server))
continue;
r = strv_consume(&lease->ntp_fqdn, TAKE_PTR(server));
if (r < 0)
return r;
strv_free_and_replace(lease->ntp_fqdn, servers);
lease->ntp_fqdn_count = r;
break;
}}
}
}
if (r != -ENOMSG)
return r;
return 0;
}
int dhcp6_lease_add_sntp(sd_dhcp6_lease *lease, const uint8_t *optval, size_t optlen) {
int dhcp6_lease_set_sntp(sd_dhcp6_lease *lease, uint8_t *optval, size_t optlen) {
int r;
assert_return(lease, -EINVAL);
assert_return(optval, -EINVAL);
if (optlen == 0)
if (!optlen)
return 0;
/* SNTP option is defined in RFC4075, and deprecated by RFC5908. */
return dhcp6_option_parse_addresses(optval, optlen, &lease->sntp, &lease->sntp_count);
if (lease->ntp || lease->ntp_fqdn)
return -EEXIST;
/* Using deprecated SNTP information */
r = dhcp6_option_parse_ip6addrs(optval, optlen, &lease->ntp,
lease->ntp_count);
if (r < 0)
return r;
lease->ntp_count = r;
return 0;
}
int sd_dhcp6_lease_get_ntp_addrs(sd_dhcp6_lease *lease, const struct in6_addr **ret) {
int sd_dhcp6_lease_get_ntp_addrs(sd_dhcp6_lease *lease,
const struct in6_addr **addrs) {
assert_return(lease, -EINVAL);
assert_return(ret, -EINVAL);
assert_return(addrs, -EINVAL);
if (lease->ntp) {
*ret = lease->ntp;
if (lease->ntp_count) {
*addrs = lease->ntp;
return lease->ntp_count;
}
if (lease->sntp && !lease->ntp_fqdn) {
/* Fallback to the deprecated SNTP option. */
*ret = lease->sntp;
return lease->sntp_count;
}
return -ENOENT;
}
int sd_dhcp6_lease_get_ntp_fqdn(sd_dhcp6_lease *lease, char ***ret) {
int sd_dhcp6_lease_get_ntp_fqdn(sd_dhcp6_lease *lease, char ***ntp_fqdn) {
assert_return(lease, -EINVAL);
assert_return(ret, -EINVAL);
assert_return(ntp_fqdn, -EINVAL);
if (!lease->ntp_fqdn)
return -ENOENT;
if (lease->ntp_fqdn_count) {
*ntp_fqdn = lease->ntp_fqdn;
return lease->ntp_fqdn_count;
}
*ret = lease->ntp_fqdn;
return strv_length(lease->ntp_fqdn);
return -ENOENT;
}
int dhcp6_lease_set_fqdn(sd_dhcp6_lease *lease, const uint8_t *optval, size_t optlen) {
int dhcp6_lease_set_fqdn(sd_dhcp6_lease *lease, const uint8_t *optval,
size_t optlen) {
int r;
char *fqdn;
@ -349,31 +378,33 @@ int dhcp6_lease_set_fqdn(sd_dhcp6_lease *lease, const uint8_t *optval, size_t op
return free_and_replace(lease->fqdn, fqdn);
}
int sd_dhcp6_lease_get_fqdn(sd_dhcp6_lease *lease, const char **ret) {
int sd_dhcp6_lease_get_fqdn(sd_dhcp6_lease *lease, const char **fqdn) {
assert_return(lease, -EINVAL);
assert_return(ret, -EINVAL);
assert_return(fqdn, -EINVAL);
if (!lease->fqdn)
return -ENOENT;
if (lease->fqdn) {
*fqdn = lease->fqdn;
return 0;
}
*ret = lease->fqdn;
return 0;
return -ENOENT;
}
static sd_dhcp6_lease *dhcp6_lease_free(sd_dhcp6_lease *lease) {
if (!lease)
return NULL;
assert(lease);
free(lease->serverid);
dhcp6_lease_free_ia(&lease->ia);
dhcp6_lease_free_ia(&lease->pd);
free(lease->dns);
free(lease->fqdn);
strv_free(lease->domains);
free(lease->ntp);
strv_free(lease->ntp_fqdn);
free(lease->sntp);
lease->domains = strv_free(lease->domains);
free(lease->ntp);
lease->ntp_fqdn = strv_free(lease->ntp_fqdn);
return mfree(lease);
}

View File

@ -137,7 +137,7 @@ static int test_parse_domain(sd_event *e) {
data = (uint8_t []) { 7, 'e', 'x', 'a', 'm', 'p', 'l', 'e', 3, 'c', 'o', 'm', 0,
6, 'f', 'o', 'o', 'b', 'a', 'r', 0 };
r = dhcp6_option_parse_domainname_list(data, 21, &list);
assert_se(r == 0);
assert_se(r == 2);
assert_se(list);
assert_se(streq(list[0], "example.com"));
assert_se(streq(list[1], "foobar"));
@ -156,7 +156,7 @@ static int test_parse_domain(sd_event *e) {
static int test_option(sd_event *e) {
uint8_t packet[] = {
'F', 'O', 'O', 'H', 'O', 'G', 'E',
'F', 'O', 'O',
0x00, SD_DHCP6_OPTION_ORO, 0x00, 0x07,
'A', 'B', 'C', 'D', 'E', 'F', 'G',
0x00, SD_DHCP6_OPTION_VENDOR_CLASS, 0x00, 0x09,
@ -164,66 +164,53 @@ static int test_option(sd_event *e) {
'B', 'A', 'R',
};
uint8_t result[] = {
'F', 'O', 'O', 'H', 'O', 'G', 'E',
'F', 'O', 'O',
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
'B', 'A', 'R',
};
_cleanup_free_ uint8_t *buf = NULL;
size_t offset, pos, optlen, outlen = sizeof(result);
const uint8_t *optval;
uint16_t optcode;
uint8_t *out;
size_t optlen;
uint8_t *optval, *buf, *out;
size_t zero = 0, pos = 3;
size_t buflen = sizeof(packet), outlen = sizeof(result);
log_debug("/* %s */", __func__);
assert_se(sizeof(packet) == sizeof(result));
assert_se(buflen == outlen);
offset = 0;
assert_se(dhcp6_option_parse(packet, 0, &offset, &optcode, &optlen, &optval) == -EBADMSG);
assert_se(dhcp6_option_parse(&buf, &zero, &optcode, &optlen,
&optval) == -ENOMSG);
offset = 3;
assert_se(dhcp6_option_parse(packet, 0, &offset, &optcode, &optlen, &optval) == -EBADMSG);
/* Tests for reading unaligned data. */
assert_se(buf = new(uint8_t, sizeof(packet)));
for (size_t i = 0; i <= 7; i++) {
memcpy(buf, packet + i, sizeof(packet) - i);
offset = 7 - i;
assert_se(dhcp6_option_parse(buf, sizeof(packet), &offset, &optcode, &optlen, &optval) >= 0);
assert_se(optcode == SD_DHCP6_OPTION_ORO);
assert_se(optlen == 7);
assert_se(optval == buf + 11 - i);
}
offset = 7;
assert_se(dhcp6_option_parse(packet, sizeof(packet), &offset, &optcode, &optlen, &optval) >= 0);
buflen -= 3;
buf = &packet[3];
outlen -= 3;
out = &result[3];
assert_se(dhcp6_option_parse(&buf, &buflen, &optcode, &optlen,
&optval) >= 0);
pos += 4 + optlen;
assert_se(buf == &packet[pos]);
assert_se(optcode == SD_DHCP6_OPTION_ORO);
assert_se(optlen == 7);
assert_se(optval == packet + 11);
assert_se(buflen + pos == sizeof(packet));
pos = 7;
outlen -= 7;
out = &result[pos];
assert_se(dhcp6_option_append(&out, &outlen, optcode, optlen, optval) >= 0);
pos += 4 + optlen;
assert_se(dhcp6_option_append(&out, &outlen, optcode, optlen,
optval) >= 0);
assert_se(out == &result[pos]);
assert_se(*out == 0x00);
assert_se(dhcp6_option_parse(packet, sizeof(packet), &offset, &optcode, &optlen, &optval) >= 0);
assert_se(dhcp6_option_parse(&buf, &buflen, &optcode, &optlen,
&optval) >= 0);
pos += 4 + optlen;
assert_se(buf == &packet[pos]);
assert_se(optcode == SD_DHCP6_OPTION_VENDOR_CLASS);
assert_se(optlen == 9);
assert_se(optval == packet + 22);
assert_se(buflen + pos == sizeof(packet));
assert_se(dhcp6_option_append(&out, &outlen, optcode, optlen, optval) >= 0);
pos += 4 + optlen;
assert_se(dhcp6_option_append(&out, &outlen, optcode, optlen,
optval) >= 0);
assert_se(out == &result[pos]);
assert_se(*out == 'B');
@ -249,7 +236,7 @@ static int test_option_status(sd_event *e) {
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
0x01, 0x02, 0x03, 0x04, 0x0a, 0x0b, 0x0c, 0x0d,
/* IA address status option */
/* status option */
0x00, 0x0d, 0x00, 0x02, 0x00, 0x01,
};
static const uint8_t option3[] = {
@ -261,7 +248,7 @@ static int test_option_status(sd_event *e) {
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
0x01, 0x02, 0x03, 0x04, 0x0a, 0x0b, 0x0c, 0x0d,
/* IA address status option */
/* status option */
0x00, 0x0d, 0x00, 0x08, 0x00, 0x00, 'f', 'o',
'o', 'b', 'a', 'r',
};
@ -275,7 +262,7 @@ static int test_option_status(sd_event *e) {
0x80, 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe,
0xef, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00,
/* PD prefix status option */
/* status option */
0x00, 0x0d, 0x00, 0x02, 0x00, 0x00,
};
static const uint8_t option5[] = {
@ -288,7 +275,7 @@ static int test_option_status(sd_event *e) {
0x80, 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe,
0xef, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00,
/* PD prefix status option */
/* status option */
0x00, 0x0d, 0x00, 0x02, 0x00, 0x00,
/* IA PD Prefix #2 */
0x00, 0x1a, 0x00, 0x1f,
@ -296,7 +283,6 @@ static int test_option_status(sd_event *e) {
0x80, 0x20, 0x01, 0x0d, 0xb8, 0xc0, 0x0l, 0xd0,
0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00,
/* PD prefix status option */
0x00, 0x0d, 0x00, 0x02, 0x00, 0x00,
};
DHCP6Option *option;
@ -309,62 +295,62 @@ static int test_option_status(sd_event *e) {
memcpy(&iaid, option1 + 4, sizeof(iaid));
zero(ia);
option = (DHCP6Option*) option1;
option = (DHCP6Option *)option1;
assert_se(sizeof(option1) == sizeof(DHCP6Option) + be16toh(option->len));
r = dhcp6_option_parse_ia(NULL, 0, be16toh(option->code), be16toh(option->len), option->data, &ia);
r = dhcp6_option_parse_ia(NULL, option, 0, &ia, NULL);
assert_se(r == -ENOANO);
r = dhcp6_option_parse_ia(NULL, iaid, be16toh(option->code), be16toh(option->len), option->data, &ia);
assert_se(r == -EINVAL);
assert_se(!ia.addresses);
r = dhcp6_option_parse_ia(NULL, option, iaid, &ia, NULL);
assert_se(r == 0);
assert_se(ia.addresses == NULL);
option->len = htobe16(17);
r = dhcp6_option_parse_ia(NULL, iaid, be16toh(option->code), be16toh(option->len), option->data, &ia);
assert_se(r == -EBADMSG);
assert_se(!ia.addresses);
r = dhcp6_option_parse_ia(NULL, option, iaid, &ia, NULL);
assert_se(r == -ENOBUFS);
assert_se(ia.addresses == NULL);
option->len = htobe16(sizeof(DHCP6Option));
r = dhcp6_option_parse_ia(NULL, iaid, be16toh(option->code), be16toh(option->len), option->data, &ia);
assert_se(r == -EBADMSG);
assert_se(!ia.addresses);
r = dhcp6_option_parse_ia(NULL, option, iaid, &ia, NULL);
assert_se(r == -ENOBUFS);
assert_se(ia.addresses == NULL);
zero(ia);
option = (DHCP6Option*) option2;
option = (DHCP6Option *)option2;
assert_se(sizeof(option2) == sizeof(DHCP6Option) + be16toh(option->len));
r = dhcp6_option_parse_ia(NULL, iaid, be16toh(option->code), be16toh(option->len), option->data, &ia);
assert_se(r == -ENODATA);
assert_se(!ia.addresses);
r = dhcp6_option_parse_ia(NULL, option, iaid, &ia, NULL);
assert_se(r >= 0);
assert_se(ia.addresses == NULL);
zero(ia);
option = (DHCP6Option*) option3;
option = (DHCP6Option *)option3;
assert_se(sizeof(option3) == sizeof(DHCP6Option) + be16toh(option->len));
r = dhcp6_option_parse_ia(NULL, iaid, be16toh(option->code), be16toh(option->len), option->data, &ia);
r = dhcp6_option_parse_ia(NULL, option, iaid, &ia, NULL);
assert_se(r >= 0);
assert_se(ia.addresses);
assert_se(ia.addresses != NULL);
dhcp6_lease_free_ia(&ia);
zero(pd);
option = (DHCP6Option*) option4;
option = (DHCP6Option *)option4;
assert_se(sizeof(option4) == sizeof(DHCP6Option) + be16toh(option->len));
r = dhcp6_option_parse_ia(NULL, iaid, be16toh(option->code), be16toh(option->len), option->data, &pd);
r = dhcp6_option_parse_ia(NULL, option, iaid, &pd, NULL);
assert_se(r >= 0);
assert_se(pd.addresses);
assert_se(pd.addresses != NULL);
assert_se(memcmp(&pd.ia_pd.id, &option4[4], 4) == 0);
assert_se(memcmp(&pd.ia_pd.lifetime_t1, &option4[8], 4) == 0);
assert_se(memcmp(&pd.ia_pd.lifetime_t2, &option4[12], 4) == 0);
dhcp6_lease_free_ia(&pd);
zero(pd);
option = (DHCP6Option*) option5;
option = (DHCP6Option *)option5;
assert_se(sizeof(option5) == sizeof(DHCP6Option) + be16toh(option->len));
r = dhcp6_option_parse_ia(NULL, iaid, be16toh(option->code), be16toh(option->len), option->data, &pd);
r = dhcp6_option_parse_ia(NULL, option, iaid, &pd, NULL);
assert_se(r >= 0);
assert_se(pd.addresses);
assert_se(pd.addresses != NULL);
dhcp6_lease_free_ia(&pd);
return 0;
@ -482,7 +468,7 @@ static int test_advertise_option(sd_event *e) {
val = htobe32(120);
assert_se(!memcmp(optval + 8, &val, sizeof(val)));
assert_se(dhcp6_option_parse_ia(NULL, iaid, optcode, optlen, optval, &lease->ia) >= 0);
assert_se(dhcp6_option_parse_ia(NULL, option, iaid, &lease->ia, NULL) >= 0);
break;
}
@ -510,17 +496,20 @@ static int test_advertise_option(sd_event *e) {
case SD_DHCP6_OPTION_DNS_SERVERS:
assert_se(optlen == 16);
assert_se(dhcp6_lease_add_dns(lease, optval, optlen) >= 0);
assert_se(dhcp6_lease_set_dns(lease, optval,
optlen) >= 0);
break;
case SD_DHCP6_OPTION_DOMAIN_LIST:
assert_se(optlen == 11);
assert_se(dhcp6_lease_add_domains(lease, optval, optlen) >= 0);
assert_se(dhcp6_lease_set_domains(lease, optval,
optlen) >= 0);
break;
case SD_DHCP6_OPTION_SNTP_SERVERS:
assert_se(optlen == 16);
assert_se(dhcp6_lease_add_sntp(lease, optval, optlen) >= 0);
assert_se(dhcp6_lease_set_sntp(lease, optval,
optlen) >= 0);
break;
default:
@ -676,7 +665,7 @@ static int test_client_verify_request(DHCP6Message *request, size_t len) {
assert_se(!memcmp(optval + 8, &val, sizeof(val)));
/* Then, this should refuse all addresses. */
assert_se(dhcp6_option_parse_ia(NULL, test_iaid, optcode, optlen, optval, &lease->ia) == -ENODATA);
assert_se(dhcp6_option_parse_ia(NULL, option, test_iaid, &lease->ia, NULL) >= 0);
break;

View File

@ -53,42 +53,6 @@ void genl_clear_family(sd_netlink *nl) {
nl->genl_family_by_id = hashmap_free_with_destructor(nl->genl_family_by_id, genl_family_free);
}
static int genl_family_new_unsupported(
sd_netlink *nl,
const char *family_name,
const NLTypeSystem *type_system) {
_cleanup_(genl_family_freep) GenericNetlinkFamily *f = NULL;
int r;
assert(nl);
assert(family_name);
assert(type_system);
/* Kernel does not support the genl family? To prevent from resolving the family name again,
* let's store the family with zero id to indicate that. */
f = new(GenericNetlinkFamily, 1);
if (!f)
return -ENOMEM;
*f = (GenericNetlinkFamily) {
.type_system = type_system,
};
f->name = strdup(family_name);
if (!f->name)
return -ENOMEM;
r = hashmap_ensure_put(&nl->genl_family_by_name, &string_hash_ops, f->name, f);
if (r < 0)
return r;
f->genl = nl;
TAKE_PTR(f);
return 0;
}
static int genl_family_new(
sd_netlink *nl,
const char *expected_family_name,
@ -115,6 +79,28 @@ static int genl_family_new(
.type_system = type_system,
};
if (sd_netlink_message_is_error(message)) {
int e;
/* Kernel does not support the genl family? To prevent from resolving the family name
* again, let's store the family with zero id to indicate that. */
e = sd_netlink_message_get_errno(message);
if (e >= 0) /* Huh? */
e = -EOPNOTSUPP;
f->name = strdup(expected_family_name);
if (!f->name)
return e;
if (hashmap_ensure_put(&nl->genl_family_by_name, &string_hash_ops, f->name, f) < 0)
return e;
f->genl = nl;
TAKE_PTR(f);
return e;
}
r = sd_genl_message_get_family_name(nl, message, &family_name);
if (r < 0)
return r;
@ -275,10 +261,9 @@ static int genl_family_get_by_name_internal(
if (r < 0)
return r;
if (sd_netlink_call(nl, req, 0, &reply) < 0) {
(void) genl_family_new_unsupported(nl, name, type_system);
return -EOPNOTSUPP;
}
r = sd_netlink_call(nl, req, 0, &reply);
if (r < 0)
return r;
return genl_family_new(nl, name, type_system, reply, ret);
}

View File

@ -123,8 +123,8 @@ struct sd_netlink_message {
struct nlmsghdr *hdr;
struct netlink_container containers[NETLINK_CONTAINER_DEPTH];
unsigned n_containers; /* number of containers */
uint32_t multicast_group;
bool sealed:1;
bool broadcast:1;
sd_netlink_message *next; /* next in a chain of multi-part messages */
};

View File

@ -116,8 +116,8 @@ int message_new_synthetic_error(sd_netlink *nl, int error, uint32_t serial, sd_n
int sd_netlink_message_request_dump(sd_netlink_message *m, int dump) {
assert_return(m, -EINVAL);
assert_return(m->hdr, -EINVAL);
assert_return(m->protocol != NETLINK_ROUTE ||
IN_SET(m->hdr->nlmsg_type,
assert_return(IN_SET(m->hdr->nlmsg_type,
RTM_GETLINK, RTM_GETLINKPROP, RTM_GETADDR, RTM_GETROUTE, RTM_GETNEIGH,
RTM_GETRULE, RTM_GETADDRLABEL, RTM_GETNEXTHOP), -EINVAL);
@ -166,7 +166,7 @@ int sd_netlink_message_set_flags(sd_netlink_message *m, uint16_t flags) {
int sd_netlink_message_is_broadcast(sd_netlink_message *m) {
assert_return(m, -EINVAL);
return m->multicast_group != 0;
return m->broadcast;
}
/* If successful the updated message will be correctly aligned, if
@ -751,7 +751,7 @@ int sd_netlink_message_read(sd_netlink_message *m, unsigned short type, size_t s
}
int sd_netlink_message_read_data(sd_netlink_message *m, unsigned short type, size_t *ret_size, void **ret_data) {
void *attr_data;
void *attr_data, *data;
int r;
assert_return(m, -EINVAL);
@ -761,8 +761,6 @@ int sd_netlink_message_read_data(sd_netlink_message *m, unsigned short type, siz
return r;
if (ret_data) {
void *data;
data = memdup(attr_data, r);
if (!data)
return -ENOMEM;
@ -776,34 +774,9 @@ int sd_netlink_message_read_data(sd_netlink_message *m, unsigned short type, siz
return r;
}
int sd_netlink_message_read_data_suffix0(sd_netlink_message *m, unsigned short type, size_t *ret_size, void **ret_data) {
void *attr_data;
int r;
assert_return(m, -EINVAL);
r = netlink_message_read_internal(m, type, &attr_data, NULL);
if (r < 0)
return r;
if (ret_data) {
void *data;
data = memdup_suffix0(attr_data, r);
if (!data)
return -ENOMEM;
*ret_data = data;
}
if (ret_size)
*ret_size = r;
return r;
}
int sd_netlink_message_read_string_strdup(sd_netlink_message *m, unsigned short type, char **data) {
void *attr_data;
char *str;
int r;
assert_return(m, -EINVAL);
@ -817,8 +790,6 @@ int sd_netlink_message_read_string_strdup(sd_netlink_message *m, unsigned short
return r;
if (data) {
char *str;
str = strndup(attr_data, r);
if (!str)
return -ENOMEM;
@ -830,8 +801,8 @@ int sd_netlink_message_read_string_strdup(sd_netlink_message *m, unsigned short
}
int sd_netlink_message_read_string(sd_netlink_message *m, unsigned short type, const char **data) {
void *attr_data;
int r;
void *attr_data;
assert_return(m, -EINVAL);
@ -842,8 +813,7 @@ int sd_netlink_message_read_string(sd_netlink_message *m, unsigned short type, c
r = netlink_message_read_internal(m, type, &attr_data, NULL);
if (r < 0)
return r;
if (strnlen(attr_data, r) >= (size_t) r)
else if (strnlen(attr_data, r) >= (size_t) r)
return -EIO;
if (data)
@ -853,8 +823,8 @@ int sd_netlink_message_read_string(sd_netlink_message *m, unsigned short type, c
}
int sd_netlink_message_read_u8(sd_netlink_message *m, unsigned short type, uint8_t *data) {
void *attr_data;
int r;
void *attr_data;
assert_return(m, -EINVAL);
@ -865,8 +835,7 @@ int sd_netlink_message_read_u8(sd_netlink_message *m, unsigned short type, uint8
r = netlink_message_read_internal(m, type, &attr_data, NULL);
if (r < 0)
return r;
if ((size_t) r < sizeof(uint8_t))
else if ((size_t) r < sizeof(uint8_t))
return -EIO;
if (data)
@ -889,8 +858,7 @@ int sd_netlink_message_read_u16(sd_netlink_message *m, unsigned short type, uint
r = netlink_message_read_internal(m, type, &attr_data, &net_byteorder);
if (r < 0)
return r;
if ((size_t) r < sizeof(uint16_t))
else if ((size_t) r < sizeof(uint16_t))
return -EIO;
if (data) {
@ -917,8 +885,7 @@ int sd_netlink_message_read_u32(sd_netlink_message *m, unsigned short type, uint
r = netlink_message_read_internal(m, type, &attr_data, &net_byteorder);
if (r < 0)
return r;
if ((size_t) r < sizeof(uint32_t))
else if ((size_t) r < sizeof(uint32_t))
return -EIO;
if (data) {
@ -932,8 +899,8 @@ int sd_netlink_message_read_u32(sd_netlink_message *m, unsigned short type, uint
}
int sd_netlink_message_read_ether_addr(sd_netlink_message *m, unsigned short type, struct ether_addr *data) {
void *attr_data;
int r;
void *attr_data;
assert_return(m, -EINVAL);
@ -944,8 +911,7 @@ int sd_netlink_message_read_ether_addr(sd_netlink_message *m, unsigned short typ
r = netlink_message_read_internal(m, type, &attr_data, NULL);
if (r < 0)
return r;
if ((size_t) r < sizeof(struct ether_addr))
else if ((size_t) r < sizeof(struct ether_addr))
return -EIO;
if (data)
@ -955,8 +921,8 @@ int sd_netlink_message_read_ether_addr(sd_netlink_message *m, unsigned short typ
}
int netlink_message_read_hw_addr(sd_netlink_message *m, unsigned short type, struct hw_addr_data *data) {
void *attr_data;
int r;
void *attr_data;
assert_return(m, -EINVAL);
@ -967,8 +933,7 @@ int netlink_message_read_hw_addr(sd_netlink_message *m, unsigned short type, str
r = netlink_message_read_internal(m, type, &attr_data, NULL);
if (r < 0)
return r;
if (r > HW_ADDR_MAX_SIZE)
else if (r > HW_ADDR_MAX_SIZE)
return -EIO;
if (data) {
@ -980,8 +945,8 @@ int netlink_message_read_hw_addr(sd_netlink_message *m, unsigned short type, str
}
int sd_netlink_message_read_cache_info(sd_netlink_message *m, unsigned short type, struct ifa_cacheinfo *info) {
void *attr_data;
int r;
void *attr_data;
assert_return(m, -EINVAL);
@ -992,8 +957,7 @@ int sd_netlink_message_read_cache_info(sd_netlink_message *m, unsigned short typ
r = netlink_message_read_internal(m, type, &attr_data, NULL);
if (r < 0)
return r;
if ((size_t) r < sizeof(struct ifa_cacheinfo))
else if ((size_t) r < sizeof(struct ifa_cacheinfo))
return -EIO;
if (info)
@ -1016,8 +980,7 @@ int netlink_message_read_in_addr_union(sd_netlink_message *m, unsigned short typ
r = netlink_message_read_internal(m, type, &attr_data, NULL);
if (r < 0)
return r;
if ((size_t) r < FAMILY_ADDRESS_SIZE(family))
else if ((size_t) r < FAMILY_ADDRESS_SIZE(family))
return -EIO;
if (data)

View File

@ -81,11 +81,13 @@ int socket_bind(sd_netlink *nl) {
addrlen = sizeof(nl->sockaddr);
r = bind(nl->fd, &nl->sockaddr.sa, addrlen);
/* ignore EINVAL to allow binding an already bound socket */
if (bind(nl->fd, &nl->sockaddr.sa, addrlen) < 0 && errno != EINVAL)
if (r < 0 && errno != EINVAL)
return -errno;
if (getsockname(nl->fd, &nl->sockaddr.sa, &addrlen) < 0)
r = getsockname(nl->fd, &nl->sockaddr.sa, &addrlen);
if (r < 0)
return -errno;
return broadcast_groups_get(nl);
@ -326,7 +328,7 @@ int socket_read_message(sd_netlink *nl) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
size_t size;
if (group == 0 && new_msg->nlmsg_pid != nl->sockaddr.nl.nl_pid)
if (!group && new_msg->nlmsg_pid != nl->sockaddr.nl.nl_pid)
/* not broadcast and not for us */
continue;
@ -363,7 +365,8 @@ int socket_read_message(sd_netlink *nl) {
if (r < 0)
return r;
m->multicast_group = group;
m->broadcast = !!group;
m->hdr = memdup(new_msg, new_msg->nlmsg_len);
if (!m->hdr)
return -ENOMEM;

View File

@ -11,7 +11,6 @@
#include <linux/nl80211.h>
#include <linux/wireguard.h>
#include "missing_network.h"
#include "netlink-genl.h"
#include "netlink-types-internal.h"
@ -180,15 +179,10 @@ static const NLType genl_macsec_types[] = {
/***************** genl nl80211 type systems *****************/
static const NLType genl_nl80211_types[] = {
[NL80211_ATTR_WIPHY] = { .type = NETLINK_TYPE_U32 },
[NL80211_ATTR_WIPHY_NAME] = { .type = NETLINK_TYPE_STRING },
[NL80211_ATTR_IFINDEX] = { .type = NETLINK_TYPE_U32 },
[NL80211_ATTR_IFNAME] = { .type = NETLINK_TYPE_STRING, .size = IFNAMSIZ-1 },
[NL80211_ATTR_IFTYPE] = { .type = NETLINK_TYPE_U32 },
[NL80211_ATTR_MAC] = { .type = NETLINK_TYPE_ETHER_ADDR, .size = ETH_ALEN },
[NL80211_ATTR_SSID] = { .type = NETLINK_TYPE_BINARY, .size = IEEE80211_MAX_SSID_LEN },
[NL80211_ATTR_STATUS_CODE] = { .type = NETLINK_TYPE_U16 },
[NL80211_ATTR_4ADDR] = { .type = NETLINK_TYPE_U8 },
[NL80211_ATTR_IFINDEX] = { .type = NETLINK_TYPE_U32 },
[NL80211_ATTR_MAC] = { .type = NETLINK_TYPE_ETHER_ADDR },
[NL80211_ATTR_SSID] = { .type = NETLINK_TYPE_STRING },
[NL80211_ATTR_IFTYPE] = { .type = NETLINK_TYPE_U32 },
};
/***************** genl wireguard type systems *****************/

View File

@ -116,16 +116,6 @@ int rtnl_log_create_error(int r);
userdata, description); \
})
#define genl_add_match(nl, ret_slot, family, group, cmd, callback, destroy_callback, userdata, description) \
({ \
int (*_callback_)(sd_netlink *, sd_netlink_message *, typeof(userdata)) = callback; \
void (*_destroy_)(typeof(userdata)) = destroy_callback; \
sd_genl_add_match(nl, ret_slot, family, group, cmd, \
(sd_netlink_message_handler_t) _callback_, \
(sd_netlink_destroy_t) _destroy_, \
userdata, description); \
})
int netlink_message_append_hw_addr(sd_netlink_message *m, unsigned short type, const struct hw_addr_data *data);
int netlink_message_append_in_addr_union(sd_netlink_message *m, unsigned short type, int family, const union in_addr_union *data);
int netlink_message_append_sockaddr_union(sd_netlink_message *m, unsigned short type, const union sockaddr_union *data);

View File

@ -81,7 +81,8 @@ int sd_netlink_new_from_fd(sd_netlink **ret, int fd) {
addrlen = sizeof(nl->sockaddr);
if (getsockname(fd, &nl->sockaddr.sa, &addrlen) < 0)
r = getsockname(fd, &nl->sockaddr.sa, &addrlen);
if (r < 0)
return -errno;
if (nl->sockaddr.nl.nl_family != AF_NETLINK)
@ -445,22 +446,12 @@ static int process_match(sd_netlink *nl, sd_netlink_message *m) {
LIST_FOREACH(match_callbacks, c, nl->match_callbacks) {
sd_netlink_slot *slot;
bool found = false;
if (c->type != type)
continue;
if (c->cmd != 0 && c->cmd != cmd)
continue;
for (size_t i = 0; i < c->n_groups; i++)
if (c->groups[i] == m->multicast_group) {
found = true;
break;
}
if (!found)
continue;
slot = container_of(c, sd_netlink_slot, match_callback);
r = c->callback(nl, m, slot->userdata);
@ -492,12 +483,15 @@ static int process_running(sd_netlink *nl, sd_netlink_message **ret) {
if (!m)
goto null_message;
if (sd_netlink_message_is_broadcast(m))
if (sd_netlink_message_is_broadcast(m)) {
r = process_match(nl, m);
else
if (r != 0)
goto null_message;
} else {
r = process_reply(nl, m);
if (r != 0)
goto null_message;
if (r != 0)
goto null_message;
}
if (ret) {
*ret = TAKE_PTR(m);

View File

@ -19,7 +19,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
assert_se(fwrite(data, size, 1, f) == 1);
fflush(f);
assert_se(manager_new(&manager, /* test_mode = */ true) >= 0);
assert_se(manager_new(&manager) >= 0);
(void) netdev_load_one(manager, netdev_config);
return 0;
}

View File

@ -22,7 +22,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
assert_se(fwrite(data, size, 1, f) == 1);
fflush(f);
assert_se(manager_new(&manager, /* test_mode = */ true) >= 0);
assert_se(manager_new(&manager) >= 0);
(void) network_load_one(manager, &manager->networks, network_config);
return 0;
}

View File

@ -285,6 +285,10 @@ static int l2tp_acquire_local_address(L2tpTunnel *t, Link *link, union in_addr_u
if (l2tp_acquire_local_address_one(t, a, ret) >= 0)
return 1;
SET_FOREACH(a, link->addresses_foreign)
if (l2tp_acquire_local_address_one(t, a, ret) >= 0)
return 1;
return -ENODATA;
}

View File

@ -106,6 +106,24 @@ static bool address_pool_prefix_is_taken(
if (in_addr_prefix_intersect(p->family, u, prefixlen, &a->in_addr, a->prefixlen))
return true;
}
/* Don't clash with assigned foreign addresses */
SET_FOREACH(a, l->addresses_foreign) {
if (a->family != p->family)
continue;
if (in_addr_prefix_intersect(p->family, u, prefixlen, &a->in_addr, a->prefixlen))
return true;
}
/* Don't clash with addresses already pulled from the pool, but not assigned yet */
SET_FOREACH(a, l->pool_addresses) {
if (a->family != p->family)
continue;
if (in_addr_prefix_intersect(p->family, u, prefixlen, &a->in_addr, a->prefixlen))
return true;
}
}
/* And don't clash with configured but un-assigned addresses either */

View File

@ -9,12 +9,10 @@
#include "netlink-util.h"
#include "networkd-address-pool.h"
#include "networkd-address.h"
#include "networkd-dhcp-server.h"
#include "networkd-ipv4acd.h"
#include "networkd-manager.h"
#include "networkd-network.h"
#include "networkd-queue.h"
#include "networkd-route.h"
#include "parse-util.h"
#include "string-util.h"
#include "strv.h"
@ -133,7 +131,7 @@ static int address_new_static(Network *network, const char *filename, unsigned s
address->network = network;
address->section = TAKE_PTR(n);
address->source = NETWORK_CONFIG_SOURCE_STATIC;
address->is_static = true;
r = ordered_hashmap_ensure_put(&network->addresses_by_section, &network_config_hash_ops, address->section, address);
if (r < 0)
@ -153,7 +151,23 @@ Address *address_free(Address *address) {
}
if (address->link) {
NDiscAddress *n;
set_remove(address->link->addresses, address);
set_remove(address->link->addresses_foreign, address);
set_remove(address->link->addresses_ipv4acd, address);
set_remove(address->link->static_addresses, address);
if (address->link->dhcp_address == address)
address->link->dhcp_address = NULL;
if (address->link->dhcp_address_old == address)
address->link->dhcp_address_old = NULL;
set_remove(address->link->dhcp6_addresses, address);
set_remove(address->link->dhcp6_addresses_old, address);
set_remove(address->link->dhcp6_pd_addresses, address);
set_remove(address->link->dhcp6_pd_addresses_old, address);
SET_FOREACH(n, address->link->ndisc_addresses)
if (address_equal(n->address, address))
free(set_remove(address->link->ndisc_addresses, n));
if (address->family == AF_INET6 &&
in6_addr_equal(&address->in_addr.in6, &address->link->ipv6ll_address))
@ -167,41 +181,6 @@ Address *address_free(Address *address) {
return mfree(address);
}
bool address_is_ready(const Address *a) {
assert(a);
if (FLAGS_SET(a->flags, IFA_F_TENTATIVE))
return false;
if (FLAGS_SET(a->state, NETWORK_CONFIG_STATE_REMOVING))
return false;
if (FLAGS_SET(a->state, NETWORK_CONFIG_STATE_PROBING))
return false;
if (!FLAGS_SET(a->state, NETWORK_CONFIG_STATE_CONFIGURED))
return false;
return true;
}
void link_mark_addresses(Link *link, NetworkConfigSource source, const struct in6_addr *router) {
Address *a;
assert(link);
SET_FOREACH(a, link->addresses) {
if (a->source != source)
continue;
if (source == NETWORK_CONFIG_SOURCE_NDISC &&
router && !in6_addr_equal(router, &a->provider.in6))
continue;
address_mark(a);
}
}
static bool address_may_have_broadcast(const Address *a) {
assert(a);
@ -316,6 +295,16 @@ int address_compare_func(const Address *a1, const Address *a2) {
DEFINE_HASH_OPS_WITH_KEY_DESTRUCTOR(address_hash_ops, Address, address_hash_func, address_compare_func, address_free);
bool address_equal(const Address *a1, const Address *a2) {
if (a1 == a2)
return true;
if (!a1 || !a2)
return false;
return address_compare_func(a1, a2) == 0;
}
int address_dup(const Address *src, Address **ret) {
_cleanup_(address_freep) Address *dest = NULL;
int r;
@ -382,19 +371,67 @@ static int address_set_masquerade(Address *address, bool add) {
return 0;
}
static int address_add(Link *link, Address *address) {
static int address_add_internal(Link *link, Set **addresses, const Address *in, Address **ret) {
_cleanup_(address_freep) Address *address = NULL;
int r;
assert(link);
assert(address);
assert(addresses);
assert(in);
r = set_ensure_put(&link->addresses, &address_hash_ops, address);
r = address_dup(in, &address);
if (r < 0)
return r;
/* Consider address tentative until we get the real flags from the kernel */
address->flags |= IFA_F_TENTATIVE;
r = set_ensure_put(addresses, &address_hash_ops, address);
if (r < 0)
return r;
if (r == 0)
return -EEXIST;
address->link = link;
if (ret)
*ret = address;
TAKE_PTR(address);
return 0;
}
static int address_add_foreign(Link *link, const Address *in, Address **ret) {
return address_add_internal(link, &link->addresses_foreign, in, ret);
}
static int address_add(Link *link, const Address *in, Address **ret) {
Address *address;
int r;
assert(link);
assert(in);
r = address_get(link, in, &address);
if (r == -ENOENT) {
/* Address does not exist, create a new one */
r = address_add_internal(link, &link->addresses, in, &address);
if (r < 0)
return r;
} else if (r == 0) {
/* Take over a foreign address */
r = set_ensure_put(&link->addresses, &address_hash_ops, address);
if (r < 0)
return r;
set_remove(link->addresses_foreign, address);
} else if (r == 1) {
/* Already exists, do nothing */
;
} else
return r;
if (ret)
*ret = address;
return 0;
}
@ -404,13 +441,13 @@ static int address_update(Address *address, const Address *src) {
assert(address);
assert(address->link);
assert(src);
link = address->link;
if (src) {
address->flags = src->flags;
address->scope = src->scope;
address->cinfo = src->cinfo;
}
address->flags = src->flags;
address->scope = src->scope;
address->cinfo = src->cinfo;
if (address_is_ready(address) &&
address->family == AF_INET6 &&
@ -447,8 +484,8 @@ static int address_drop(Address *address) {
bool ready;
int r;
assert(address);
assert(address->link);
if (!address)
return 0;
ready = address_is_ready(address);
link = address->link;
@ -457,8 +494,7 @@ static int address_drop(Address *address) {
if (r < 0)
log_link_warning_errno(link, r, "Failed to disable IP masquerading, ignoring: %m");
if (address->state == 0)
address_free(address);
address_free(address);
link_update_operstate(link, true);
@ -475,12 +511,20 @@ int address_get(Link *link, const Address *in, Address **ret) {
assert(in);
existing = set_get(link->addresses, in);
if (!existing)
return -ENOENT;
if (existing) {
if (ret)
*ret = existing;
return 1;
}
if (ret)
*ret = existing;
return 0;
existing = set_get(link->addresses_foreign, in);
if (existing) {
if (ret)
*ret = existing;
return 0;
}
return -ENOENT;
}
int link_get_ipv6_address(Link *link, const struct in6_addr *address, Address **ret) {
@ -502,6 +546,27 @@ int link_get_ipv6_address(Link *link, const struct in6_addr *address, Address **
return address_get(link, a, ret);
}
static int addresses_get_ipv4_address(Set *addresses, const struct in_addr *address, Address **ret) {
Address *a;
assert(address);
SET_FOREACH(a, addresses) {
if (a->family != AF_INET)
continue;
if (!in4_addr_equal(&a->in_addr.in, address))
continue;
if (ret)
*ret = a;
return 0;
}
return -ENOENT;
}
int link_get_ipv4_address(Link *link, const struct in_addr *address, unsigned char prefixlen, Address **ret) {
int r;
@ -522,24 +587,11 @@ int link_get_ipv4_address(Link *link, const struct in_addr *address, unsigned ch
a->prefixlen = prefixlen;
return address_get(link, a, ret);
} else {
Address *a;
SET_FOREACH(a, link->addresses) {
if (a->family != AF_INET)
continue;
if (!in4_addr_equal(&a->in_addr.in, address))
continue;
if (ret)
*ret = a;
return 0;
}
return -ENOENT;
}
if (addresses_get_ipv4_address(link->addresses, address, ret) >= 0)
return 0;
return addresses_get_ipv4_address(link->addresses_foreign, address, ret);
}
int manager_has_address(Manager *manager, int family, const union in_addr_union *address, bool check_ready) {
@ -554,7 +606,7 @@ int manager_has_address(Manager *manager, int family, const union in_addr_union
if (family == AF_INET) {
HASHMAP_FOREACH(link, manager->links_by_index)
if (link_get_ipv4_address(link, &address->in, 0, &a) >= 0)
return check_ready ? address_is_ready(a) : address_exists(a);
return !check_ready || address_is_ready(a);
} else {
_cleanup_(address_freep) Address *tmp = NULL;
@ -567,7 +619,7 @@ int manager_has_address(Manager *manager, int family, const union in_addr_union
HASHMAP_FOREACH(link, manager->links_by_index)
if (address_get(link, tmp, &a) >= 0)
return check_ready ? address_is_ready(a) : address_exists(a);
return !check_ready || address_is_ready(a);
}
return false;
@ -587,7 +639,7 @@ const char* format_lifetime(char *buf, size_t l, uint32_t lifetime) {
}
static void log_address_debug(const Address *address, const char *str, const Link *link) {
_cleanup_free_ char *state = NULL, *addr = NULL, *peer = NULL, *flags_str = NULL;
_cleanup_free_ char *addr = NULL, *peer = NULL, *flags_str = NULL;
assert(address);
assert(str);
@ -596,16 +648,14 @@ static void log_address_debug(const Address *address, const char *str, const Lin
if (!DEBUG_LOGGING)
return;
(void) network_config_state_to_string_alloc(address->state, &state);
(void) in_addr_to_string(address->family, &address->in_addr, &addr);
if (in_addr_is_set(address->family, &address->in_addr_peer))
(void) in_addr_to_string(address->family, &address->in_addr_peer, &peer);
(void) address_flags_to_string_alloc(address->flags, address->family, &flags_str);
log_link_debug(link, "%s %s address (%s): %s%s%s/%u (valid %s, preferred %s), flags: %s",
str, strna(network_config_source_to_string(address->source)), strna(state),
strnull(addr), peer ? " peer " : "", strempty(peer), address->prefixlen,
log_link_debug(link, "%s address: %s%s%s/%u (valid %s, preferred %s), flags: %s",
str, strnull(addr), peer ? " peer " : "", strempty(peer), address->prefixlen,
FORMAT_LIFETIME(address->cinfo.ifa_valid),
FORMAT_LIFETIME(address->cinfo.ifa_prefered),
strna(flags_str));
@ -648,8 +698,12 @@ static int address_set_netlink_message(const Address *address, sd_netlink_messag
static int address_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
int r;
assert(rtnl);
assert(m);
assert(link);
assert(link->address_remove_messages > 0);
link->address_remove_messages--;
if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
return 0;
@ -661,19 +715,16 @@ static int address_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, Link
return 1;
}
int address_remove(Address *address) {
int address_remove(const Address *address, Link *link) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
Link *link;
int r;
assert(address);
assert(IN_SET(address->family, AF_INET, AF_INET6));
assert(address->link);
assert(address->link->ifindex > 0);
assert(address->link->manager);
assert(address->link->manager->rtnl);
link = address->link;
assert(link);
assert(link->ifindex > 0);
assert(link->manager);
assert(link->manager->rtnl);
log_address_debug(address, "Removing", link);
@ -693,11 +744,27 @@ int address_remove(Address *address) {
return log_link_error_errno(link, r, "Could not send rtnetlink message: %m");
link_ref(link);
link->address_remove_messages++;
address_enter_removing(address);
return 0;
}
static bool link_is_static_address_configured(const Link *link, const Address *address) {
Address *net_address;
assert(link);
assert(address);
if (!link->network)
return false;
ORDERED_HASHMAP_FOREACH(net_address, link->network->addresses_by_section)
if (address_equal(net_address, address))
return true;
return false;
}
bool link_address_is_dynamic(const Link *link, const Address *address) {
Route *route;
@ -710,10 +777,7 @@ bool link_address_is_dynamic(const Link *link, const Address *address) {
/* Even when the address is leased from a DHCP server, networkd assign the address
* without lifetime when KeepConfiguration=dhcp. So, let's check that we have
* corresponding routes with RTPROT_DHCP. */
SET_FOREACH(route, link->routes) {
if (route->source != NETWORK_CONFIG_SOURCE_FOREIGN)
continue;
SET_FOREACH(route, link->routes_foreign) {
if (route->protocol != RTPROT_DHCP)
continue;
@ -757,7 +821,6 @@ int link_drop_ipv6ll_addresses(Link *link) {
_cleanup_(address_freep) Address *a = NULL;
unsigned char flags, prefixlen;
struct in6_addr address;
Address *existing;
int ifindex;
/* NETLINK_GET_STRICT_CHK socket option is supported since kernel 4.20. To support
@ -803,15 +866,7 @@ int link_drop_ipv6ll_addresses(Link *link) {
a->prefixlen = prefixlen;
a->flags = flags;
if (address_get(link, a, &existing) < 0) {
r = address_add(link, a);
if (r < 0)
return r;
existing = TAKE_PTR(a);
}
r = address_remove(existing);
r = address_remove(a, link);
if (r < 0)
return r;
}
@ -824,80 +879,63 @@ int link_drop_foreign_addresses(Link *link) {
int k, r = 0;
assert(link);
assert(link->network);
/* First, mark all addresses. */
SET_FOREACH(address, link->addresses) {
SET_FOREACH(address, link->addresses_foreign) {
/* We consider IPv6LL addresses to be managed by the kernel, or dropped in link_drop_ipv6ll_addresses() */
if (address->family == AF_INET6 && in6_addr_is_link_local(&address->in_addr.in6))
continue;
/* Ignore addresses we configured. */
if (address->source != NETWORK_CONFIG_SOURCE_FOREIGN)
continue;
/* Ignore addresses not assigned yet or already removing. */
if (!address_exists(address))
continue;
if (link_address_is_dynamic(link, address)) {
if (link->network && FLAGS_SET(link->network->keep_configuration, KEEP_CONFIGURATION_DHCP))
continue;
} else if (link->network && FLAGS_SET(link->network->keep_configuration, KEEP_CONFIGURATION_STATIC))
continue;
address_mark(address);
}
/* Then, unmark requested addresses. */
ORDERED_HASHMAP_FOREACH(address, link->network->addresses_by_section) {
Address *existing;
if (address_get(link, address, &existing) >= 0)
address_unmark(existing);
}
/* Finally, remove all marked addresses. */
SET_FOREACH(address, link->addresses) {
if (!address_is_marked(address))
continue;
k = address_remove(address);
if (k < 0 && r >= 0)
r = k;
}
return r;
}
int link_drop_addresses(Link *link) {
Address *address;
int k, r = 0;
assert(link);
SET_FOREACH(address, link->addresses) {
/* Ignore addresses not assigned yet or already removing. */
if (!address_exists(address))
continue;
/* We consider IPv6LL addresses to be managed by the kernel, or dropped in link_drop_ipv6ll_addresses() */
if (address->family == AF_INET6 && in6_addr_is_link_local(&address->in_addr.in6))
continue;
k = address_remove(address);
if (k < 0 && r >= 0) {
r = k;
continue;
if (link_is_static_address_configured(link, address)) {
k = address_add(link, address, NULL);
if (k < 0) {
log_link_error_errno(link, k, "Failed to add address: %m");
if (r >= 0)
r = k;
}
} else {
k = address_remove(address, link);
if (k < 0 && r >= 0)
r = k;
}
}
return r;
}
int link_drop_addresses(Link *link) {
Address *address, *pool_address;
int k, r = 0;
assert(link);
SET_FOREACH(address, link->addresses) {
/* We consider IPv6LL addresses to be managed by the kernel, or dropped in link_drop_ipv6ll_addresses() */
if (address->family == AF_INET6 && in6_addr_is_link_local(&address->in_addr.in6))
continue;
k = address_remove(address, link);
if (k < 0 && r >= 0) {
r = k;
continue;
}
SET_FOREACH(pool_address, link->pool_addresses)
if (address_equal(address, pool_address))
address_free(set_remove(link->pool_addresses, pool_address));
}
return r;
}
static int address_acquire(Link *link, const Address *original, Address **ret) {
union in_addr_union in_addr = IN_ADDR_NULL;
_cleanup_(address_freep) Address *na = NULL;
union in_addr_union in_addr;
int r;
assert(link);
@ -931,6 +969,12 @@ static int address_acquire(Link *link, const Address *original, Address **ret) {
na->in_addr = in_addr;
address_set_broadcast(na);
r = set_ensure_put(&link->pool_addresses, &address_hash_ops, na);
if (r < 0)
return r;
if (r == 0)
return -EEXIST;
*ret = TAKE_PTR(na);
return 1;
}
@ -1019,25 +1063,6 @@ static int address_configure(
return 0;
}
void address_cancel_request(Address *address) {
Request req;
assert(address);
assert(address->link);
if (!address_is_requesting(address))
return;
req = (Request) {
.link = address->link,
.type = REQUEST_TYPE_ADDRESS,
.address = address,
};
request_drop(ordered_set_get(address->link->manager->request_queue, &req));
address_cancel_requesting(address);
}
static int static_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
int r;
@ -1059,6 +1084,25 @@ static int static_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link
return 1;
}
static int static_address_after_configure(Request *req, void *object) {
Address *address = object;
Link *link;
int r;
assert(req);
assert(req->link);
assert(req->type == REQUEST_TYPE_ADDRESS);
assert(address);
link = req->link;
r = set_ensure_put(&link->static_addresses, &address_hash_ops, address);
if (r < 0)
return log_link_warning_errno(link, r, "Failed to store static address: %m");
return 0;
}
int link_request_address(
Link *link,
Address *address,
@ -1067,72 +1111,50 @@ int link_request_address(
link_netlink_message_handler_t netlink_handler,
Request **ret) {
Address *acquired, *existing;
Address *acquired;
int r;
assert(link);
assert(address);
assert(address->source != NETWORK_CONFIG_SOURCE_FOREIGN);
r = address_acquire(link, address, &acquired);
if (r < 0)
return log_link_warning_errno(link, r, "Failed to acquire an address from pool: %m");
if (r > 0) {
if (consume_object)
if (consume_object) {
address_free(address);
consume_object = false; /* address from pool is already managed by Link. */
}
address = acquired;
consume_object = true;
}
if (address_get(link, address, &existing) < 0) {
_cleanup_(address_freep) Address *tmp = NULL;
r = address_dup(address, &tmp);
if (r < 0)
return r;
/* Consider address tentative until we get the real flags from the kernel */
tmp->flags |= IFA_F_TENTATIVE;
r = address_add(link, tmp);
if (r < 0)
return r;
existing = TAKE_PTR(tmp);
} else {
existing->source = address->source;
existing->provider = address->provider;
}
r = ipv4acd_configure(existing);
if (r < 0)
return r;
log_address_debug(address, "Requesting", link);
r = link_queue_request(link, REQUEST_TYPE_ADDRESS, address, consume_object,
message_counter, netlink_handler, ret);
if (r < 0)
return log_link_warning_errno(link, r, "Failed to request address: %m");
if (r == 0)
return 0;
address_enter_requesting(existing);
return 1;
return r;
}
int link_request_static_address(Link *link, Address *address, bool consume) {
Request *req;
int r;
assert(link);
assert(address);
assert(address->source == NETWORK_CONFIG_SOURCE_STATIC);
return link_request_address(link, address, consume, &link->static_address_messages,
static_address_handler, NULL);
r = link_request_address(link, address, consume, &link->static_address_messages,
static_address_handler, &req);
if (r <= 0)
return r;
req->after_configure = static_address_after_configure;
return 0;
}
int link_request_static_addresses(Link *link) {
Address *a;
Prefix *p;
int r;
assert(link);
@ -1146,13 +1168,52 @@ int link_request_static_addresses(Link *link) {
return r;
}
r = link_request_radv_addresses(link);
if (r < 0)
return r;
HASHMAP_FOREACH(p, link->network->prefixes_by_section) {
_cleanup_(address_freep) Address *address = NULL;
r = link_request_dhcp_server_address(link);
if (r < 0)
return r;
if (!p->assign)
continue;
r = address_new(&address);
if (r < 0)
return log_oom();
r = sd_radv_prefix_get_prefix(p->radv_prefix, &address->in_addr.in6, &address->prefixlen);
if (r < 0)
return log_link_warning_errno(link, r, "Could not get RA prefix: %m");
r = generate_ipv6_eui_64_address(link, &address->in_addr.in6);
if (r < 0)
return log_link_warning_errno(link, r, "Could not generate EUI64 address: %m");
address->family = AF_INET6;
address->route_metric = p->route_metric;
r = link_request_static_address(link, TAKE_PTR(address), true);
if (r < 0)
return r;
}
if (in4_addr_is_set(&link->network->dhcp_server_address)) {
_cleanup_(address_freep) Address *address = NULL;
r = address_new(&address);
if (r < 0)
return log_oom();
address->family = AF_INET;
address->in_addr.in = link->network->dhcp_server_address;
address->prefixlen = link->network->dhcp_server_address_prefixlen;
address_set_broadcast(address);
/* The same address may be explicitly configured in [Address] or [Network] section.
* Configure the DHCP server address only when it is not. */
if (!link_is_static_address_configured(link, address)) {
r = link_request_static_address(link, TAKE_PTR(address), true);
if (r < 0)
return r;
}
}
if (link->static_address_messages == 0) {
link->static_addresses_configured = true;
@ -1165,25 +1226,41 @@ int link_request_static_addresses(Link *link) {
return 0;
}
static bool address_is_ready_to_configure(Link *link, const Address *address) {
static int address_is_ready_to_configure(Link *link, const Address *address) {
int r;
assert(link);
assert(address);
if (!link_is_ready_to_configure(link, false))
return false;
if (FLAGS_SET(address->state, NETWORK_CONFIG_STATE_PROBING))
if (link->address_remove_messages > 0)
return false;
/* Refuse adding more than the limit */
if (address_get(link, address, NULL) >= 0)
return true;
/* If this is a new address, then refuse adding more than the limit */
if (set_size(link->addresses) >= ADDRESSES_PER_LINK_MAX)
return false;
return log_link_warning_errno(link, SYNTHETIC_ERRNO(E2BIG),
"Too many addresses are configured, refusing: %m");
if (address->family == AF_INET &&
address->duplicate_address_detection & ADDRESS_FAMILY_IPV4 &&
link->hw_addr.length == ETH_ALEN &&
!ether_addr_is_null(&link->hw_addr.ether))
return ipv4acd_address_is_ready_to_configure(link, address);
r = address_add(link, address, NULL);
if (r < 0)
return log_link_warning_errno(link, r, "Could not add address: %m");;
return true;
}
int request_process_address(Request *req) {
Address *existing;
Address *a;
Link *link;
int r;
@ -1194,18 +1271,26 @@ int request_process_address(Request *req) {
link = req->link;
r = address_get(link, req->address, &existing);
if (r < 0)
return log_link_warning_errno(link, r, "Failed to get address: %m");
if (!address_is_ready_to_configure(link, existing))
return 0;
r = address_is_ready_to_configure(link, req->address);
if (r <= 0)
return r;
r = address_configure(req->address, link, req->netlink_handler);
if (r < 0)
return log_link_warning_errno(link, r, "Failed to configure address: %m");
return r;
address_enter_configuring(existing);
/* To prevent a double decrement on failure in after_configure(). */
req->message_counter = NULL;
r = address_get(link, req->address, &a);
if (r < 0)
return r;
if (req->after_configure) {
r = req->after_configure(req, a);
if (r < 0)
return r;
}
return 1;
}
@ -1356,14 +1441,10 @@ int manager_rtnl_process_address(sd_netlink *rtnl, sd_netlink_message *message,
switch (type) {
case RTM_NEWADDR:
if (address) {
address_enter_configured(address);
log_address_debug(address, "Remembering updated", link);
} else {
address_enter_configured(tmp);
log_address_debug(tmp, "Received new", link);
r = address_add(link, tmp);
log_address_debug(tmp, address ? "Remembering updated" : "Remembering foreign", link);
if (!address) {
/* An address appeared that we did not request */
r = address_add_foreign(link, tmp, &address);
if (r < 0) {
_cleanup_free_ char *buf = NULL;
@ -1372,8 +1453,6 @@ int manager_rtnl_process_address(sd_netlink *rtnl, sd_netlink_message *message,
strnull(buf));
return 0;
}
address = TAKE_PTR(tmp);
}
/* address_update() logs internally, so we don't need to here. */
@ -1384,12 +1463,8 @@ int manager_rtnl_process_address(sd_netlink *rtnl, sd_netlink_message *message,
break;
case RTM_DELADDR:
if (address) {
address_enter_removed(address);
log_address_debug(address, address->state == 0 ? "Forgetting" : "Removed", link);
(void) address_drop(address);
} else
log_address_debug(tmp, "Kernel removed unknown", link);
log_address_debug(tmp, address ? "Forgetting" : "Kernel removed unknown", link);
(void) address_drop(address);
break;
@ -1847,6 +1922,12 @@ int config_parse_duplicate_address_detection(
return 0;
}
bool address_is_ready(const Address *a) {
assert(a);
return !(a->flags & IFA_F_TENTATIVE);
}
static int address_section_verify(Address *address) {
if (section_is_invalid(address->section))
return -EINVAL;

View File

@ -21,12 +21,10 @@ typedef struct Request Request;
typedef int (*address_ready_callback_t)(Address *address);
struct Address {
Link *link;
Network *network;
NetworkConfigSection *section;
NetworkConfigSource source;
NetworkConfigState state;
union in_addr_union provider; /* DHCP server or router address */
Link *link;
int family;
unsigned char prefixlen;
@ -44,6 +42,8 @@ struct Address {
bool scope_set:1;
bool ip_masquerade_done:1;
bool is_static:1; /* currently only used by IPv4ACD */
bool acd_announced:1;
AddressFamily duplicate_address_detection;
sd_ipv4acd *acd;
@ -62,7 +62,8 @@ int address_new(Address **ret);
Address* address_free(Address *address);
int address_get(Link *link, const Address *in, Address **ret);
int address_configure_handler_internal(sd_netlink *rtnl, sd_netlink_message *m, Link *link, const char *error_msg);
int address_remove(Address *address);
int address_remove(const Address *address, Link *link);
bool address_equal(const Address *a1, const Address *a2);
int address_dup(const Address *src, Address **ret);
bool address_is_ready(const Address *a);
void address_set_broadcast(Address *a);
@ -79,7 +80,6 @@ int link_get_ipv6_address(Link *link, const struct in6_addr *address, Address **
int link_get_ipv4_address(Link *link, const struct in_addr *address, unsigned char prefixlen, Address **ret);
int manager_has_address(Manager *manager, int family, const union in_addr_union *address, bool check_ready);
void address_cancel_request(Address *address);
int link_request_address(
Link *link,
Address *address,
@ -99,16 +99,6 @@ void address_hash_func(const Address *a, struct siphash *state);
int address_compare_func(const Address *a1, const Address *a2);
extern const struct hash_ops address_hash_ops;
DEFINE_NETWORK_CONFIG_STATE_FUNCTIONS(Address, address);
static inline void address_enter_probing(Address *address) {
address_update_state(address, NETWORK_CONFIG_STATE_PROBING, NETWORK_CONFIG_STATE_PROBING);
}
static inline void address_cancel_probing(Address *address) {
address_update_state(address, NETWORK_CONFIG_STATE_PROBING, 0);
}
void link_mark_addresses(Link *link, NetworkConfigSource source, const struct in6_addr *router);
CONFIG_PARSER_PROTOTYPE(config_parse_address);
CONFIG_PARSER_PROTOTYPE(config_parse_broadcast);
CONFIG_PARSER_PROTOTYPE(config_parse_label);

View File

@ -16,7 +16,6 @@
#include "networkd-manager.h"
#include "networkd-network.h"
#include "networkd-queue.h"
#include "networkd-route.h"
#include "parse-util.h"
#include "socket-netlink.h"
#include "string-table.h"
@ -75,40 +74,6 @@ void network_adjust_dhcp_server(Network *network) {
}
}
int link_request_dhcp_server_address(Link *link) {
_cleanup_(address_freep) Address *address = NULL;
Address *existing;
int r;
assert(link);
assert(link->network);
if (!link_dhcp4_server_enabled(link))
return 0;
if (!in4_addr_is_set(&link->network->dhcp_server_address))
return 0;
r = address_new(&address);
if (r < 0)
return r;
address->source = NETWORK_CONFIG_SOURCE_STATIC;
address->family = AF_INET;
address->in_addr.in = link->network->dhcp_server_address;
address->prefixlen = link->network->dhcp_server_address_prefixlen;
address_set_broadcast(address);
if (address_get(link, address, &existing) >= 0 &&
address_exists(existing) &&
existing->source == NETWORK_CONFIG_SOURCE_STATIC)
/* The same address seems explicitly configured in [Address] or [Network] section.
* Configure the DHCP server address only when it is not. */
return 0;
return link_request_static_address(link, TAKE_PTR(address), true);
}
static int link_find_dhcp_server_address(Link *link, Address **ret) {
Address *address;
@ -121,21 +86,13 @@ static int link_find_dhcp_server_address(Link *link, Address **ret) {
link->network->dhcp_server_address_prefixlen, ret);
/* If not, then select one from static addresses. */
SET_FOREACH(address, link->addresses) {
if (address->source != NETWORK_CONFIG_SOURCE_STATIC)
continue;
if (!address_exists(address))
continue;
if (address->family != AF_INET)
continue;
if (in4_addr_is_localhost(&address->in_addr.in))
continue;
if (in4_addr_is_set(&address->in_addr_peer.in))
continue;
*ret = address;
return 0;
}
SET_FOREACH(address, link->static_addresses)
if (address->family == AF_INET &&
!in4_addr_is_localhost(&address->in_addr.in) &&
in4_addr_is_null(&address->in_addr_peer.in)) {
*ret = address;
return 0;
}
return -ENOENT;
}
@ -548,6 +505,9 @@ static bool dhcp_server_is_ready_to_configure(Link *link) {
if (!link_has_carrier(link))
return false;
if (link->address_remove_messages > 0)
return false;
if (!link->static_addresses_configured)
return false;

View File

@ -9,7 +9,6 @@ typedef struct Request Request;
void network_adjust_dhcp_server(Network *network);
int link_request_dhcp_server_address(Link *link);
int link_request_dhcp_server(Link *link);
int request_process_dhcp_server(Request *req);

View File

@ -27,7 +27,7 @@
#include "sysctl-util.h"
static int dhcp4_request_address_and_routes(Link *link, bool announce);
static int dhcp4_check_ready(Link *link);
static int dhcp4_remove_all(Link *link);
void network_adjust_dhcp4(Network *network) {
assert(network);
@ -54,106 +54,84 @@ void network_adjust_dhcp4(Network *network) {
network->dhcp_client_identifier = network->dhcp_anonymize ? DHCP_CLIENT_ID_MAC : DHCP_CLIENT_ID_DUID;
}
static int dhcp4_remove_address_and_routes(Link *link, bool only_marked) {
Address *address;
static int dhcp4_release_old_lease(Link *link) {
Route *route;
int k, r = 0;
assert(link);
SET_FOREACH(route, link->routes) {
if (route->source != NETWORK_CONFIG_SOURCE_DHCP4)
continue;
if (only_marked && !route_is_marked(route))
continue;
if (!link->dhcp_address_old && set_isempty(link->dhcp_routes_old))
return 0;
k = route_remove(route);
log_link_debug(link, "Removing old DHCPv4 address and routes.");
SET_FOREACH(route, link->dhcp_routes_old) {
k = route_remove(route, NULL, link);
if (k < 0)
r = k;
route_cancel_request(route);
}
SET_FOREACH(address, link->addresses) {
if (address->source != NETWORK_CONFIG_SOURCE_DHCP4)
continue;
if (only_marked && !address_is_marked(address))
continue;
k = address_remove(address);
if (link->dhcp_address_old) {
k = address_remove(link->dhcp_address_old, link);
if (k < 0)
r = k;
address_cancel_request(address);
}
return r;
}
static int dhcp4_address_get(Link *link, Address **ret) {
Address *address;
assert(link);
SET_FOREACH(address, link->addresses) {
if (address->source != NETWORK_CONFIG_SOURCE_DHCP4)
continue;
if (address_is_marked(address))
continue;
if (ret)
*ret = address;
return 0;
}
return -ENOENT;
}
static int dhcp4_address_ready_callback(Address *address) {
assert(address);
assert(address->link);
/* Do not call this again. */
address->callback = NULL;
return dhcp4_check_ready(address->link);
}
static int dhcp4_check_ready(Link *link) {
Address *address;
static void dhcp4_check_ready(Link *link) {
int r;
assert(link);
if (link->dhcp4_messages > 0) {
log_link_debug(link, "%s(): DHCPv4 address and routes are not set.", __func__);
return 0;
return;
}
if (dhcp4_address_get(link, &address) < 0) {
if (!link->dhcp_address) {
log_link_debug(link, "%s(): DHCPv4 address is not set.", __func__);
return 0;
return;
}
if (!address_is_ready(address)) {
if (!address_is_ready(link->dhcp_address)) {
log_link_debug(link, "%s(): DHCPv4 address is not ready.", __func__);
address->callback = dhcp4_address_ready_callback;
return 0;
return;
}
link->dhcp4_configured = true;
log_link_debug(link, "DHCPv4 address and routes set.");
/* New address and routes are configured now. Let's release old lease. */
r = dhcp4_remove_address_and_routes(link, /* only_marked = */ true);
if (r < 0)
return r;
r = dhcp4_release_old_lease(link);
if (r < 0) {
link_enter_failed(link);
return;
}
r = sd_ipv4ll_stop(link->ipv4ll);
if (r < 0)
return log_link_warning_errno(link, r, "Failed to drop IPv4 link-local address: %m");
log_link_warning_errno(link, r, "Failed to drop IPv4 link-local address, ignoring: %m");
link_check_ready(link);
}
static int dhcp4_after_route_configure(Request *req, void *object) {
Route *route = object;
Link *link;
int r;
assert(req);
assert(req->link);
assert(req->type == REQUEST_TYPE_ROUTE);
assert(route);
link = req->link;
r = set_ensure_put(&link->dhcp_routes, &route_hash_ops, route);
if (r < 0)
return log_link_error_errno(link, r, "Failed to store DHCPv4 route: %m");
set_remove(link->dhcp_routes_old, route);
return 0;
}
@ -162,7 +140,7 @@ static int dhcp4_retry(Link *link) {
assert(link);
r = dhcp4_remove_address_and_routes(link, /* only_marked = */ false);
r = dhcp4_remove_all(link);
if (r < 0)
return r;
@ -214,29 +192,19 @@ static int dhcp4_route_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *li
return 1;
}
r = dhcp4_check_ready(link);
if (r < 0)
link_enter_failed(link);
dhcp4_check_ready(link);
return 1;
}
static int dhcp4_request_route(Route *in, Link *link) {
_cleanup_(route_freep) Route *route = in;
struct in_addr server;
Route *existing;
Request *req;
int r;
assert(route);
assert(link);
assert(link->dhcp_lease);
r = sd_dhcp_lease_get_server_identifier(link->dhcp_lease, &server);
if (r < 0)
return log_link_debug_errno(link, r, "Failed to get DHCP server IP address: %m");
route->source = NETWORK_CONFIG_SOURCE_DHCP4;
route->provider.in = server;
route->family = AF_INET;
if (!route->protocol_set)
route->protocol = RTPROT_DHCP;
@ -247,13 +215,20 @@ static int dhcp4_request_route(Route *in, Link *link) {
if (route->mtu == 0)
route->mtu = link->network->dhcp_route_mtu;
if (route_get(NULL, link, route, &existing) < 0) /* This is a new route. */
r = link_has_route(link, route);
if (r < 0)
return r;
if (r == 0)
link->dhcp4_configured = false;
else
route_unmark(existing);
return link_request_route(link, TAKE_PTR(route), true, &link->dhcp4_messages,
dhcp4_route_handler, NULL);
r = link_request_route(link, TAKE_PTR(route), true, &link->dhcp4_messages,
dhcp4_route_handler, &req);
if (r <= 0)
return r;
req->after_configure = dhcp4_after_route_configure;
return 0;
}
static bool link_prefixroute(Link *link) {
@ -700,10 +675,19 @@ static int dhcp4_request_routes_to_ntp(Link *link, const struct in_addr *gw) {
static int dhcp4_request_routes(Link *link) {
struct in_addr gw = {};
Route *rt;
int r;
assert(link);
assert(link->dhcp_lease);
if (!link->dhcp_lease)
return 0;
while ((rt = set_steal_first(link->dhcp_routes))) {
r = set_ensure_put(&link->dhcp_routes_old, &route_hash_ops, rt);
if (r < 0)
return log_link_error_errno(link, r, "Failed to store old DHCPv4 route: %m");
}
r = dhcp4_request_prefix_route(link);
if (r < 0)
@ -784,6 +768,27 @@ static int dhcp_reset_hostname(Link *link) {
return 0;
}
static int dhcp4_remove_all(Link *link) {
Route *route;
int k, r = 0;
assert(link);
SET_FOREACH(route, link->dhcp_routes) {
k = route_remove(route, NULL, link);
if (k < 0)
r = k;
}
if (link->dhcp_address) {
k = address_remove(link->dhcp_address, link);
if (k < 0)
r = k;
}
return r;
}
int dhcp4_lease_lost(Link *link) {
int k, r = 0;
@ -794,7 +799,12 @@ int dhcp4_lease_lost(Link *link) {
link->dhcp4_configured = false;
k = dhcp4_remove_address_and_routes(link, /* only_marked = */ false);
/* dhcp4_lease_lost() may be called during renewing IP address. */
k = dhcp4_release_old_lease(link);
if (k < 0)
r = k;
k = dhcp4_remove_all(link);
if (k < 0)
r = k;
@ -809,7 +819,24 @@ int dhcp4_lease_lost(Link *link) {
link->dhcp_lease = sd_dhcp_lease_unref(link->dhcp_lease);
link_dirty(link);
/* If one of the above failed. Do not request nexthops and routes. */
if (link->network->dhcp_send_decline) {
Address *a;
/* The acquired address may be still ARP probing and not configured. */
SET_FOREACH(a, link->addresses_ipv4acd)
if (!a->is_static && address_get(link, a, NULL) < 0) {
Request req = {
.link = link,
.address = a,
};
log_link_debug(link, "Canceling the request to configure DHCPv4 address "IPV4_ADDRESS_FMT_STR,
IPV4_ADDRESS_FMT_VAL(a->in_addr.in));
request_drop(ordered_set_get(link->manager->request_queue, &req));
}
}
if (r < 0)
return r;
@ -820,6 +847,43 @@ int dhcp4_lease_lost(Link *link) {
return link_request_static_routes(link, true);
}
static int dhcp4_address_ready_callback(Address *address) {
assert(address);
/* Do not call this again. */
address->callback = NULL;
dhcp4_check_ready(address->link);
return 0;
}
static int dhcp4_after_address_configure(Request *req, void *object) {
Address *address = object;
Link *link;
int r;
assert(req);
assert(req->link);
assert(req->type == REQUEST_TYPE_ADDRESS);
assert(address);
link = req->link;
if (!address_equal(link->dhcp_address, address)) {
if (link->dhcp_address_old &&
!address_equal(link->dhcp_address_old, link->dhcp_address)) {
/* Still too old address exists? Let's remove it immediately. */
r = address_remove(link->dhcp_address_old, link);
if (r < 0)
return r;
}
link->dhcp_address_old = link->dhcp_address;
}
link->dhcp_address = address;
return 0;
}
static int dhcp4_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
int r;
@ -832,9 +896,12 @@ static int dhcp4_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *
if (r <= 0)
return r;
r = dhcp4_check_ready(link);
if (r < 0)
link_enter_failed(link);
if (address_is_ready(link->dhcp_address)) {
r = dhcp4_address_ready_callback(link->dhcp_address);
if (r < 0)
link_enter_failed(link);
} else
link->dhcp_address->callback = dhcp4_address_ready_callback;
return 1;
}
@ -844,12 +911,14 @@ static int dhcp4_request_address(Link *link, bool announce) {
uint32_t lifetime = CACHE_INFO_INFINITY_LIFE_TIME;
struct in_addr address, netmask, server;
unsigned prefixlen;
Address *existing;
Request *req;
int r;
assert(link);
assert(link->network);
assert(link->dhcp_lease);
if (!link->dhcp_lease)
return 0;
r = sd_dhcp_lease_get_address(link->dhcp_lease, &address);
if (r < 0)
@ -904,8 +973,6 @@ static int dhcp4_request_address(Link *link, bool announce) {
if (r < 0)
return log_oom();
addr->source = NETWORK_CONFIG_SOURCE_DHCP4;
addr->provider.in = server;
addr->family = AF_INET;
addr->in_addr.in.s_addr = address.s_addr;
addr->cinfo.ifa_prefered = lifetime;
@ -921,15 +988,17 @@ static int dhcp4_request_address(Link *link, bool announce) {
if (r < 0)
return r;
if (address_get(link, addr, &existing) < 0) /* The address is new. */
if (address_get(link, addr, NULL) < 0)
link->dhcp4_configured = false;
else
address_unmark(existing);
r = link_request_address(link, TAKE_PTR(addr), true, &link->dhcp4_messages,
dhcp4_address_handler, NULL);
dhcp4_address_handler, &req);
if (r < 0)
return log_link_error_errno(link, r, "Failed to request DHCPv4 address: %m");
if (r == 0)
return 0;
req->after_configure = dhcp4_after_address_configure;
return 0;
}
@ -939,9 +1008,6 @@ static int dhcp4_request_address_and_routes(Link *link, bool announce) {
assert(link);
link_mark_addresses(link, NETWORK_CONFIG_SOURCE_DHCP4, NULL);
link_mark_routes(link, NETWORK_CONFIG_SOURCE_DHCP4, NULL);
r = dhcp4_request_address(link, announce);
if (r < 0)
return r;
@ -950,10 +1016,8 @@ static int dhcp4_request_address_and_routes(Link *link, bool announce) {
if (r < 0)
return r;
if (!link->dhcp4_configured) {
link_set_state(link, LINK_STATE_CONFIGURING);
link_check_ready(link);
}
link_set_state(link, LINK_STATE_CONFIGURING);
link_check_ready(link);
return 0;
}
@ -1308,9 +1372,7 @@ static int dhcp4_set_request_address(Link *link) {
if (!FLAGS_SET(link->network->keep_configuration, KEEP_CONFIGURATION_DHCP))
return 0;
SET_FOREACH(a, link->addresses) {
if (a->source != NETWORK_CONFIG_SOURCE_FOREIGN)
continue;
SET_FOREACH(a, link->addresses_foreign) {
if (a->family != AF_INET)
continue;
if (link_address_is_dynamic(link, a))

File diff suppressed because it is too large Load Diff

View File

@ -16,9 +16,18 @@ typedef enum DHCP6ClientStartMode {
typedef struct Link Link;
typedef struct Request Request;
typedef struct DHCP6DelegatedPrefix {
struct in6_addr prefix; /* Prefix assigned to the link */
struct in6_addr pd_prefix; /* PD prefix provided by DHCP6 lease */
Link *link;
} DHCP6DelegatedPrefix;
DHCP6DelegatedPrefix *dhcp6_pd_free(DHCP6DelegatedPrefix *p);
DEFINE_TRIVIAL_CLEANUP_FUNC(DHCP6DelegatedPrefix*, dhcp6_pd_free);
bool link_dhcp6_with_address_enabled(Link *link);
bool link_dhcp6_pd_is_enabled(Link *link);
int dhcp6_pd_remove(Link *link, bool only_marked);
int dhcp6_pd_remove(Link *link);
int dhcp6_update_mac(Link *link);
int dhcp6_start(Link *link);
int dhcp6_request_information(Link *link, int ir);

View File

@ -9,26 +9,19 @@
#include "networkd-link.h"
#include "networkd-manager.h"
static int static_ipv4acd_address_remove(Link *link, Address *address, bool on_conflict) {
static int static_address_on_stop(Link *link, Address *address) {
int r;
assert(link);
assert(address);
/* Prevent form the address being freed. */
address_enter_probing(address);
if (address_get(link, address, NULL) < 0)
return 0;
if (!address_exists(address))
return 0; /* Not assigned. */
log_link_debug(link, "Removing address "IPV4_ADDRESS_FMT_STR", as the ACD client is stopped.",
IPV4_ADDRESS_FMT_VAL(address->in_addr.in));
if (on_conflict)
log_link_warning(link, "Dropping address "IPV4_ADDRESS_FMT_STR", as an address conflict was detected.",
IPV4_ADDRESS_FMT_VAL(address->in_addr.in));
else
log_link_debug(link, "Removing address "IPV4_ADDRESS_FMT_STR", as the ACD client is stopped.",
IPV4_ADDRESS_FMT_VAL(address->in_addr.in));
r = address_remove(address);
r = address_remove(address, link);
if (r < 0)
return log_link_warning_errno(link, r, "Failed to remove address "IPV4_ADDRESS_FMT_STR": %m",
IPV4_ADDRESS_FMT_VAL(address->in_addr.in));
@ -36,7 +29,30 @@ static int static_ipv4acd_address_remove(Link *link, Address *address, bool on_c
return 0;
}
static int dhcp4_address_on_conflict(Link *link, Address *address) {
static int static_address_on_conflict(Link *link, Address *address) {
int r;
assert(link);
assert(address);
if (address_get(link, address, NULL) < 0) {
log_link_warning(link, "Cannot configure requested address "IPV4_ADDRESS_FMT_STR", as an address conflict was detected.",
IPV4_ADDRESS_FMT_VAL(address->in_addr.in));
return 0;
}
log_link_warning(link, "Dropping address "IPV4_ADDRESS_FMT_STR", as an address conflict was detected.",
IPV4_ADDRESS_FMT_VAL(address->in_addr.in));
r = address_remove(address, link);
if (r < 0)
return log_link_warning_errno(link, r, "Failed to remove address "IPV4_ADDRESS_FMT_STR": %m",
IPV4_ADDRESS_FMT_VAL(address->in_addr.in));
return 0;
}
static int dhcp4_address_on_conflict(Link *link) {
int r;
assert(link);
@ -55,14 +71,11 @@ static int dhcp4_address_on_conflict(Link *link, Address *address) {
if (r < 0)
return log_link_warning_errno(link, r, "Failed to drop DHCPv4 lease: %m");
/* make the address will be freed. */
address_cancel_probing(address);
/* It is not necessary to call address_remove() here, as dhcp4_lease_lost() removes it. */
return 0;
}
static void on_acd(sd_ipv4acd *acd, int event, void *userdata) {
static void on_acd(sd_ipv4acd *acd, int event, void *userdata, bool is_static) {
Address *address = userdata;
Link *link;
int r;
@ -72,14 +85,13 @@ static void on_acd(sd_ipv4acd *acd, int event, void *userdata) {
assert(address->acd == acd);
assert(address->link);
assert(address->family == AF_INET);
assert(IN_SET(address->source, NETWORK_CONFIG_SOURCE_STATIC, NETWORK_CONFIG_SOURCE_DHCP4));
link = address->link;
switch (event) {
case SD_IPV4ACD_EVENT_STOP:
if (address->source == NETWORK_CONFIG_SOURCE_STATIC) {
r = static_ipv4acd_address_remove(link, address, /* on_conflict = */ false);
if (is_static) {
r = static_address_on_stop(link, address);
if (r < 0)
link_enter_failed(link);
}
@ -92,17 +104,14 @@ static void on_acd(sd_ipv4acd *acd, int event, void *userdata) {
log_link_debug(link, "Successfully claimed address "IPV4_ADDRESS_FMT_STR,
IPV4_ADDRESS_FMT_VAL(address->in_addr.in));
address_cancel_probing(address);
address->acd_announced = true;
break;
case SD_IPV4ACD_EVENT_CONFLICT:
log_link_warning(link, "Dropping address "IPV4_ADDRESS_FMT_STR", as an address conflict was detected.",
IPV4_ADDRESS_FMT_VAL(address->in_addr.in));
if (address->source == NETWORK_CONFIG_SOURCE_STATIC)
r = static_ipv4acd_address_remove(link, address, /* on_conflict = */ true);
if (is_static)
r = static_address_on_conflict(link, address);
else
r = dhcp4_address_on_conflict(link, address);
r = dhcp4_address_on_conflict(link);
if (r < 0)
link_enter_failed(link);
break;
@ -112,6 +121,14 @@ static void on_acd(sd_ipv4acd *acd, int event, void *userdata) {
}
}
static void static_address_on_acd(sd_ipv4acd *acd, int event, void *userdata) {
on_acd(acd, event, userdata, true);
}
static void dhcp4_address_on_acd(sd_ipv4acd *acd, int event, void *userdata) {
on_acd(acd, event, userdata, false);
}
static int ipv4acd_check_mac(sd_ipv4acd *acd, const struct ether_addr *mac, void *userdata) {
Manager *m = userdata;
struct hw_addr_data hw_addr;
@ -127,31 +144,27 @@ static int ipv4acd_check_mac(sd_ipv4acd *acd, const struct ether_addr *mac, void
return link_get_by_hw_addr(m, &hw_addr, NULL) >= 0;
}
int ipv4acd_configure(Address *address) {
Link *link;
static int ipv4acd_configure(Link *link, const Address *a) {
_cleanup_(address_freep) Address *address = NULL;
int r;
assert(address);
assert(address->link);
if (address->family != AF_INET)
return 0;
if (!FLAGS_SET(address->duplicate_address_detection, ADDRESS_FAMILY_IPV4))
return 0;
/* Currently, only static and DHCP4 addresses are supported. */
assert(IN_SET(address->source, NETWORK_CONFIG_SOURCE_STATIC, NETWORK_CONFIG_SOURCE_DHCP4));
if (address->acd) {
address_enter_probing(address);
return 0;
}
link = address->link;
assert(link);
assert(a);
assert(a->family == AF_INET);
log_link_debug(link, "Configuring IPv4ACD for address "IPV4_ADDRESS_FMT_STR,
IPV4_ADDRESS_FMT_VAL(address->in_addr.in));
IPV4_ADDRESS_FMT_VAL(a->in_addr.in));
r = address_dup(a, &address);
if (r < 0)
return r;
r = set_ensure_put(&link->addresses_ipv4acd, &address_hash_ops, address);
if (r < 0)
return r;
if (r == 0)
return -EEXIST;
address->link = link;
r = sd_ipv4acd_new(&address->acd);
if (r < 0)
@ -173,7 +186,9 @@ int ipv4acd_configure(Address *address) {
if (r < 0)
return r;
r = sd_ipv4acd_set_callback(address->acd, on_acd, address);
r = sd_ipv4acd_set_callback(address->acd,
address->is_static ? static_address_on_acd : dhcp4_address_on_acd,
address);
if (r < 0)
return r;
@ -187,10 +202,36 @@ int ipv4acd_configure(Address *address) {
return r;
}
address_enter_probing(address);
TAKE_PTR(address);
return 0;
}
int ipv4acd_address_is_ready_to_configure(Link *link, const Address *address) {
Address *acd_address;
int r;
acd_address = set_get(link->addresses_ipv4acd, address);
if (!acd_address) {
r = ipv4acd_configure(link, address);
if (r < 0)
return log_link_warning_errno(link, r, "Failed to configure IPv4ACD client: %m");
return false;
}
if (!acd_address->acd_announced)
return false;
r = set_ensure_put(&link->addresses, &address_hash_ops, acd_address);
if (r < 0)
return log_oom();
if (r == 0)
return log_link_warning_errno(link, SYNTHETIC_ERRNO(EEXIST), "Address already exists.");
acd_address->flags |= IFA_F_TENTATIVE;
return true;
}
int ipv4acd_update_mac(Link *link) {
Address *address;
int k, r = 0;
@ -202,9 +243,8 @@ int ipv4acd_update_mac(Link *link) {
if (ether_addr_is_null(&link->hw_addr.ether))
return 0;
SET_FOREACH(address, link->addresses) {
if (!address->acd)
continue;
SET_FOREACH(address, link->addresses_ipv4acd) {
assert(address->acd);
k = sd_ipv4acd_set_mac(address->acd, &link->hw_addr.ether);
if (k < 0)
@ -222,10 +262,7 @@ int ipv4acd_start(Link *link) {
assert(link);
SET_FOREACH(address, link->addresses) {
if (!address->acd)
continue;
SET_FOREACH(address, link->addresses_ipv4acd) {
if (sd_ipv4acd_is_running(address->acd))
continue;
@ -243,10 +280,7 @@ int ipv4acd_stop(Link *link) {
assert(link);
SET_FOREACH(address, link->addresses) {
if (!address->acd)
continue;
SET_FOREACH(address, link->addresses_ipv4acd) {
k = sd_ipv4acd_stop(address->acd);
if (k < 0)
r = k;
@ -261,10 +295,7 @@ int ipv4acd_set_ifname(Link *link) {
assert(link);
SET_FOREACH(address, link->addresses) {
if (!address->acd)
continue;
SET_FOREACH(address, link->addresses_ipv4acd) {
r = sd_ipv4acd_set_ifname(address->acd, link->ifname);
if (r < 0)
return r;

View File

@ -4,7 +4,7 @@
typedef struct Address Address;
typedef struct Link Link;
int ipv4acd_configure(Address *address);
int ipv4acd_address_is_ready_to_configure(Link *link, const Address *address);
int ipv4acd_update_mac(Link *link);
int ipv4acd_start(Link *link);
int ipv4acd_stop(Link *link);

View File

@ -28,7 +28,6 @@ static int address_new_from_ipv4ll(Link *link, Address **ret) {
if (r < 0)
return -ENOMEM;
address->source = NETWORK_CONFIG_SOURCE_IPV4LL;
address->family = AF_INET;
address->in_addr.in = addr;
address->prefixlen = 16;
@ -42,7 +41,6 @@ static int address_new_from_ipv4ll(Link *link, Address **ret) {
static int ipv4ll_address_lost(Link *link) {
_cleanup_(address_freep) Address *address = NULL;
Address *existing;
int r;
assert(link);
@ -55,19 +53,10 @@ static int ipv4ll_address_lost(Link *link) {
if (r < 0)
return r;
if (address_get(link, address, &existing) < 0)
return 0;
if (existing->source != NETWORK_CONFIG_SOURCE_IPV4LL)
return 0;
if (!address_exists(existing))
return 0;
log_link_debug(link, "IPv4 link-local release "IPV4_ADDRESS_FMT_STR,
IPV4_ADDRESS_FMT_VAL(address->in_addr.in));
return address_remove(existing);
return address_remove(address, link);
}
static int ipv4ll_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {

View File

@ -48,12 +48,12 @@
#include "networkd-nexthop.h"
#include "networkd-queue.h"
#include "networkd-radv.h"
#include "networkd-route.h"
#include "networkd-routing-policy-rule.h"
#include "networkd-setlink.h"
#include "networkd-sriov.h"
#include "networkd-state-file.h"
#include "networkd-sysctl.h"
#include "networkd-wifi.h"
#include "set.h"
#include "socket-util.h"
#include "stat-util.h"
@ -228,12 +228,29 @@ static Link *link_free(Link *link) {
link_dns_settings_clear(link);
link->routes = set_free(link->routes);
link->routes_foreign = set_free(link->routes_foreign);
link->dhcp_routes = set_free(link->dhcp_routes);
link->dhcp_routes_old = set_free(link->dhcp_routes_old);
link->dhcp6_routes = set_free(link->dhcp6_routes);
link->dhcp6_routes_old = set_free(link->dhcp6_routes_old);
link->dhcp6_pd_routes = set_free(link->dhcp6_pd_routes);
link->dhcp6_pd_routes_old = set_free(link->dhcp6_pd_routes_old);
link->ndisc_routes = set_free(link->ndisc_routes);
link->nexthops = set_free(link->nexthops);
link->neighbors = set_free(link->neighbors);
link->addresses = set_free(link->addresses);
link->addresses_foreign = set_free(link->addresses_foreign);
link->addresses_ipv4acd = set_free(link->addresses_ipv4acd);
link->pool_addresses = set_free(link->pool_addresses);
link->static_addresses = set_free(link->static_addresses);
link->dhcp6_addresses = set_free(link->dhcp6_addresses);
link->dhcp6_addresses_old = set_free(link->dhcp6_addresses_old);
link->dhcp6_pd_addresses = set_free(link->dhcp6_pd_addresses);
link->dhcp6_pd_addresses_old = set_free(link->dhcp6_pd_addresses_old);
link->ndisc_addresses = set_free(link->ndisc_addresses);
link->dhcp6_pd_prefixes = set_free(link->dhcp6_pd_prefixes);
@ -378,7 +395,7 @@ int link_stop_engines(Link *link, bool may_keep_dhcp) {
if (k < 0)
r = log_link_warning_errno(link, k, "Could not stop DHCPv6 client: %m");
k = dhcp6_pd_remove(link, /* only_marked = */ false);
k = dhcp6_pd_remove(link);
if (k < 0)
r = log_link_warning_errno(link, k, "Could not remove DHCPv6 PD addresses and routes: %m");
@ -443,7 +460,7 @@ void link_check_ready(Link *link) {
_cleanup_free_ char *str = NULL;
(void) in_addr_prefix_to_string(a->family, &a->in_addr, a->prefixlen, &str);
return (void) log_link_debug(link, "%s(): address %s is not ready.", __func__, strna(str));
return (void) log_link_debug(link, "%s(): an address %s is not ready.", __func__, strna(str));
}
if (!link->static_address_labels_configured)
@ -479,42 +496,44 @@ void link_check_ready(Link *link) {
!in6_addr_is_set(&link->ipv6ll_address))
return (void) log_link_debug(link, "%s(): IPv6LL is not configured yet.", __func__);
bool has_dynamic_address = false;
SET_FOREACH(a, link->addresses) {
if (address_is_marked(a))
continue;
if (!address_exists(a))
continue;
if (IN_SET(a->source,
NETWORK_CONFIG_SOURCE_IPV4LL, NETWORK_CONFIG_SOURCE_DHCP4,
NETWORK_CONFIG_SOURCE_DHCP6, NETWORK_CONFIG_SOURCE_NDISC)) {
has_dynamic_address = true;
bool has_ndisc_address = false;
NDiscAddress *n;
SET_FOREACH(n, link->ndisc_addresses)
if (!n->marked) {
has_ndisc_address = true;
break;
}
}
if ((link_ipv4ll_enabled(link) || link_dhcp4_enabled(link) || link_dhcp6_with_address_enabled(link) ||
(link_dhcp6_pd_is_enabled(link) && link->network->dhcp6_pd_assign)) && !has_dynamic_address)
if ((link_dhcp4_enabled(link) || link_dhcp6_with_address_enabled(link) || link_ipv4ll_enabled(link)) &&
!link->dhcp_address && set_isempty(link->dhcp6_addresses) && !has_ndisc_address &&
!link->ipv4ll_address_configured)
/* When DHCP[46] or IPv4LL is enabled, at least one address is acquired by them. */
return (void) log_link_debug(link, "%s(): DHCPv4, DHCPv6 or IPv4LL is enabled but no dynamic address is assigned yet.", __func__);
/* Ignore NDisc when ConfigureWithoutCarrier= is enabled, as IPv6AcceptRA= is enabled by default. */
if (link_ipv4ll_enabled(link) || link_dhcp4_enabled(link) ||
link_dhcp6_enabled(link) || link_dhcp6_pd_is_enabled(link) ||
(!link->network->configure_without_carrier && link_ipv6_accept_ra_enabled(link))) {
if (link_dhcp4_enabled(link) || link_dhcp6_enabled(link) || link_dhcp6_pd_is_enabled(link) ||
(!link->network->configure_without_carrier && link_ipv6_accept_ra_enabled(link)) ||
link_ipv4ll_enabled(link)) {
if (!link->ipv4ll_address_configured && !link->dhcp4_configured &&
!link->dhcp6_configured && !link->dhcp6_pd_configured && !link->ndisc_configured)
if (!link->dhcp4_configured &&
!(link->dhcp6_address_configured && link->dhcp6_route_configured) &&
!(link->dhcp6_pd_address_configured && link->dhcp6_pd_route_configured) &&
!(link->ndisc_addresses_configured && link->ndisc_routes_configured) &&
!link->ipv4ll_address_configured)
/* When DHCP[46], NDisc, or IPv4LL is enabled, at least one protocol must be finished. */
return (void) log_link_debug(link, "%s(): dynamic addresses or routes are not configured.", __func__);
log_link_debug(link, "%s(): IPv4LL:%s DHCPv4:%s DHCPv6:%s DHCPv6PD:%s NDisc:%s",
log_link_debug(link, "%s(): DHCPv4:%s IPv4LL:%s DHCPv6_addresses:%s DHCPv6_routes:%s "
"DHCPv6PD_addresses:%s DHCPv6PD_routes:%s NDisc_addresses:%s NDisc_routes:%s",
__func__,
yes_no(link->ipv4ll_address_configured),
yes_no(link->dhcp4_configured),
yes_no(link->dhcp6_configured),
yes_no(link->dhcp6_pd_configured),
yes_no(link->ndisc_configured));
yes_no(link->ipv4ll_address_configured),
yes_no(link->dhcp6_address_configured),
yes_no(link->dhcp6_route_configured),
yes_no(link->dhcp6_pd_address_configured),
yes_no(link->dhcp6_pd_route_configured),
yes_no(link->ndisc_addresses_configured),
yes_no(link->ndisc_routes_configured));
}
link_set_state(link, LINK_STATE_CONFIGURED);
@ -964,9 +983,7 @@ static Link *link_drop(Link *link) {
link_drop_from_master(link);
if (link->state_file)
(void) unlink(link->state_file);
(void) unlink(link->state_file);
link_clean(link);
STRV_FOREACH(n, link->alternative_names)
@ -1278,15 +1295,28 @@ static int link_reconfigure_impl(Link *link, bool force) {
return 1;
}
static int link_reconfigure_handler_internal(sd_netlink *rtnl, sd_netlink_message *m, Link *link, bool force) {
static int link_reconfigure_handler_internal(sd_netlink *rtnl, sd_netlink_message *m, Link *link, bool force, bool update_wifi) {
bool link_was_lower_up;
int r;
assert(link);
link_was_lower_up = link->flags & IFF_LOWER_UP;
r = link_getlink_handler_internal(rtnl, m, link, "Failed to update link state");
if (r <= 0)
return r;
if (update_wifi && link_was_lower_up && link->flags & IFF_LOWER_UP) {
/* If the interface's L1 was not up, then wifi_get_info() is already called in
* link_update_flags(). So, it is not necessary to re-call here. */
r = wifi_get_info(link);
if (r < 0) {
link_enter_failed(link);
return 0;
}
}
r = link_reconfigure_impl(link, force);
if (r < 0) {
link_enter_failed(link);
@ -1297,11 +1327,11 @@ static int link_reconfigure_handler_internal(sd_netlink *rtnl, sd_netlink_messag
}
static int link_reconfigure_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
return link_reconfigure_handler_internal(rtnl, m, link, /* force = */ false);
return link_reconfigure_handler_internal(rtnl, m, link, /* force = */ false, /* update_wifi = */ false);
}
static int link_force_reconfigure_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
return link_reconfigure_handler_internal(rtnl, m, link, /* force = */ true);
return link_reconfigure_handler_internal(rtnl, m, link, /* force = */ true, /* update_wifi = */ false);
}
static int link_reconfigure_after_sleep_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
@ -1309,7 +1339,7 @@ static int link_reconfigure_after_sleep_handler(sd_netlink *rtnl, sd_netlink_mes
assert(link);
r = link_reconfigure_handler_internal(rtnl, m, link, /* force = */ false);
r = link_reconfigure_handler_internal(rtnl, m, link, /* force = */ false, /* update_wifi = */ true);
if (r != 0)
return r;
@ -1374,12 +1404,6 @@ static int link_initialized_and_synced(Link *link) {
assert(link->ifname);
assert(link->manager);
if (link->manager->test_mode) {
log_link_debug(link, "Running in test mode, refusing to enter initialized state.");
link_set_state(link, LINK_STATE_UNMANAGED);
return 0;
}
/* We may get called either from the asynchronous netlink callback,
* or directly from link_check_initialized() if running in a container. */
if (!IN_SET(link->state, LINK_STATE_PENDING, LINK_STATE_INITIALIZED))
@ -1397,6 +1421,10 @@ static int link_initialized_and_synced(Link *link) {
return r;
if (!link->network) {
r = wifi_get_info(link);
if (r < 0)
return r;
r = link_get_network(link, &network);
if (r == -ENOENT) {
link_set_state(link, LINK_STATE_UNMANAGED);
@ -1609,7 +1637,11 @@ static int link_carrier_lost(Link *link) {
return r;
}
return link_drop_config(link);
r = link_drop_config(link);
if (r < 0)
return r;
return link_drop_foreign_config(link);
}
static int link_admin_state_up(Link *link) {
@ -1735,6 +1767,18 @@ void link_update_operstate(Link *link, bool also_update_master) {
ipv6_scope = MIN(ipv6_scope, address->scope);
}
/* for operstate we also take foreign addresses into account */
SET_FOREACH(address, link->addresses_foreign) {
if (!address_is_ready(address))
continue;
if (address->family == AF_INET)
ipv4_scope = MIN(ipv4_scope, address->scope);
if (address->family == AF_INET6)
ipv6_scope = MIN(ipv6_scope, address->scope);
}
ipv4_address_state = address_state_from_scope(ipv4_scope);
ipv6_address_state = address_state_from_scope(ipv6_scope);
address_state = address_state_from_scope(MIN(ipv4_scope, ipv6_scope));
@ -1849,7 +1893,7 @@ void link_update_operstate(Link *link, bool also_update_master) {
: "")
static int link_update_flags(Link *link, sd_netlink_message *message) {
bool link_was_admin_up, had_carrier;
bool link_was_lower_up, link_was_admin_up, had_carrier;
uint8_t operstate;
unsigned flags;
int r;
@ -1911,6 +1955,7 @@ static int link_update_flags(Link *link, sd_netlink_message *message) {
log_link_debug(link, "Unknown link flags lost, ignoring: %#.5x", unknown_flags_removed);
}
link_was_lower_up = link->flags & IFF_LOWER_UP;
link_was_admin_up = link->flags & IFF_UP;
had_carrier = link_has_carrier(link);
@ -1919,6 +1964,19 @@ static int link_update_flags(Link *link, sd_netlink_message *message) {
link_update_operstate(link, true);
if (!link_was_lower_up && (link->flags & IFF_LOWER_UP)) {
r = wifi_get_info(link);
if (r < 0)
return r;
if (r > 0) {
/* All link information is up-to-date. So, it is not necessary to call
* RTM_GETLINK netlink method again. */
r = link_reconfigure_impl(link, /* force = */ false);
if (r < 0)
return r;
}
}
if (!link_was_admin_up && (link->flags & IFF_UP)) {
log_link_info(link, "Link UP");
@ -1936,15 +1994,6 @@ static int link_update_flags(Link *link, sd_netlink_message *message) {
if (!had_carrier && link_has_carrier(link)) {
log_link_info(link, "Gained carrier");
if (IN_SET(link->state, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED)) {
/* At this stage, both wlan and link information should be up-to-date. Hence,
* it is not necessary to call RTM_GETLINK, NL80211_CMD_GET_INTERFACE, or
* NL80211_CMD_GET_STATION commands, and simply call link_reconfigure_impl(). */
r = link_reconfigure_impl(link, /* force = */ false);
if (r < 0)
return r;
}
r = link_carrier_gained(link);
if (r < 0)
return r;
@ -2332,17 +2381,14 @@ static int link_new(Manager *manager, sd_netlink_message *message, Link **ret) {
return log_debug_errno(r, "rtnl: failed to exit IFLA_LINKINFO container: %m");
}
if (!manager->test_mode) {
/* Do not update state files when running in test mode. */
if (asprintf(&state_file, "/run/systemd/netif/links/%d", ifindex) < 0)
return log_oom_debug();
if (asprintf(&state_file, "/run/systemd/netif/links/%d", ifindex) < 0)
return log_oom_debug();
if (asprintf(&lease_file, "/run/systemd/netif/leases/%d", ifindex) < 0)
return log_oom_debug();
if (asprintf(&lease_file, "/run/systemd/netif/leases/%d", ifindex) < 0)
return log_oom_debug();
if (asprintf(&lldp_file, "/run/systemd/netif/lldp/%d", ifindex) < 0)
return log_oom_debug();
}
if (asprintf(&lldp_file, "/run/systemd/netif/lldp/%d", ifindex) < 0)
return log_oom_debug();
link = new(Link, 1);
if (!link)

View File

@ -39,6 +39,7 @@ typedef enum LinkState {
typedef struct Manager Manager;
typedef struct Network Network;
typedef struct Address Address;
typedef struct DUID DUID;
typedef struct Link {
@ -91,6 +92,8 @@ typedef struct Link {
unsigned static_nexthop_messages;
unsigned static_route_messages;
unsigned static_routing_policy_rule_messages;
unsigned address_remove_messages;
unsigned route_remove_messages;
unsigned tc_messages;
unsigned sr_iov_messages;
unsigned set_link_messages;
@ -99,12 +102,19 @@ typedef struct Link {
unsigned create_stacked_netdev_after_configured_messages;
Set *addresses;
Set *addresses_foreign;
Set *addresses_ipv4acd;
Set *pool_addresses;
Set *static_addresses;
Set *neighbors;
Set *routes;
Set *routes_foreign;
Set *nexthops;
sd_dhcp_client *dhcp_client;
sd_dhcp_lease *dhcp_lease;
Address *dhcp_address, *dhcp_address_old;
Set *dhcp_routes, *dhcp_routes_old;
char *lease_file;
unsigned dhcp4_messages;
bool dhcp4_route_failed:1;
@ -135,18 +145,31 @@ typedef struct Link {
sd_ndisc *ndisc;
Set *ndisc_rdnss;
Set *ndisc_dnssl;
unsigned ndisc_messages;
bool ndisc_configured:1;
Set *ndisc_addresses;
Set *ndisc_routes;
unsigned ndisc_addresses_messages;
unsigned ndisc_routes_messages;
bool ndisc_addresses_configured:1;
bool ndisc_routes_configured:1;
sd_radv *radv;
sd_dhcp6_client *dhcp6_client;
sd_dhcp6_lease *dhcp6_lease;
Set *dhcp6_addresses, *dhcp6_addresses_old;
Set *dhcp6_routes, *dhcp6_routes_old;
Set *dhcp6_pd_prefixes;
unsigned dhcp6_messages;
unsigned dhcp6_pd_messages;
bool dhcp6_configured:1;
bool dhcp6_pd_configured:1;
Set *dhcp6_pd_addresses, *dhcp6_pd_addresses_old;
Set *dhcp6_pd_routes, *dhcp6_pd_routes_old;
unsigned dhcp6_address_messages;
unsigned dhcp6_route_messages;
unsigned dhcp6_pd_address_messages;
unsigned dhcp6_pd_route_messages;
bool dhcp6_address_configured:1;
bool dhcp6_route_configured:1;
bool dhcp6_pd_address_configured:1;
bool dhcp6_pd_route_configured:1;
bool dhcp6_pd_prefixes_assigned:1;
/* This is about LLDP reception */
sd_lldp_rx *lldp_rx;

View File

@ -114,9 +114,7 @@ int link_lldp_save(Link *link) {
int n = 0, r, i;
assert(link);
if (isempty(link->lldp_file))
return 0; /* Do not update state file when running in test mode. */
assert(link->lldp_file);
if (!link->lldp_rx) {
(void) unlink(link->lldp_file);

View File

@ -6,7 +6,6 @@
#include <linux/if.h>
#include <linux/fib_rules.h>
#include <linux/nexthop.h>
#include <linux/nl80211.h>
#include "sd-daemon.h"
#include "sd-netlink.h"
@ -27,7 +26,6 @@
#include "netlink-util.h"
#include "network-internal.h"
#include "networkd-address-pool.h"
#include "networkd-address.h"
#include "networkd-dhcp-server-bus.h"
#include "networkd-dhcp6.h"
#include "networkd-link-bus.h"
@ -37,11 +35,9 @@
#include "networkd-network-bus.h"
#include "networkd-nexthop.h"
#include "networkd-queue.h"
#include "networkd-route.h"
#include "networkd-routing-policy-rule.h"
#include "networkd-speed-meter.h"
#include "networkd-state-file.h"
#include "networkd-wifi.h"
#include "ordered-set.h"
#include "path-lookup.h"
#include "path-util.h"
@ -113,11 +109,13 @@ static int on_connected(sd_bus_message *message, void *userdata, sd_bus_error *r
return 0;
}
static int manager_connect_bus(Manager *m) {
int manager_connect_bus(Manager *m) {
int r;
assert(m);
assert(!m->bus);
if (m->bus)
return 0;
r = bus_open_system_watch_bind_with_description(&m->bus, "bus-api-network");
if (r < 0)
@ -250,16 +248,6 @@ static int manager_connect_genl(Manager *m) {
if (r < 0)
return r;
r = genl_add_match(m->genl, NULL, NL80211_GENL_NAME, NL80211_MULTICAST_GROUP_CONFIG, 0,
&manager_genl_process_nl80211_config, NULL, m, "network-genl_process_nl80211_config");
if (r < 0 && r != -EOPNOTSUPP)
return r;
r = genl_add_match(m->genl, NULL, NL80211_GENL_NAME, NL80211_MULTICAST_GROUP_MLME, 0,
&manager_genl_process_nl80211_mlme, NULL, m, "network-genl_process_nl80211_mlme");
if (r < 0 && r != -EOPNOTSUPP)
return r;
return 0;
}
@ -384,10 +372,28 @@ static int signal_restart_callback(sd_event_source *s, const struct signalfd_sig
return sd_event_exit(sd_event_source_get_event(s), 0);
}
int manager_setup(Manager *m) {
int manager_new(Manager **ret) {
_cleanup_(manager_freep) Manager *m = NULL;
int r;
assert(m);
m = new(Manager, 1);
if (!m)
return -ENOMEM;
*m = (Manager) {
.speed_meter_interval_usec = SPEED_METER_DEFAULT_TIME_INTERVAL,
.online_state = _LINK_ONLINE_STATE_INVALID,
.manage_foreign_routes = true,
.manage_foreign_rules = true,
.ethtool_fd = -1,
.dhcp_duid.type = DUID_TYPE_EN,
.dhcp6_duid.type = DUID_TYPE_EN,
.duid_product_uuid.type = DUID_TYPE_UUID,
};
m->state_file = strdup("/run/systemd/netif/state");
if (!m->state_file)
return -ENOMEM;
r = sd_event_default(&m->event);
if (r < 0)
@ -416,13 +422,6 @@ int manager_setup(Manager *m) {
if (r < 0)
return r;
if (m->test_mode)
return 0;
r = manager_connect_bus(m);
if (r < 0)
return r;
r = manager_connect_udev(m);
if (r < 0)
return r;
@ -439,33 +438,8 @@ int manager_setup(Manager *m) {
if (r < 0)
return r;
m->state_file = strdup("/run/systemd/netif/state");
if (!m->state_file)
return -ENOMEM;
return 0;
}
int manager_new(Manager **ret, bool test_mode) {
_cleanup_(manager_freep) Manager *m = NULL;
m = new(Manager, 1);
if (!m)
return -ENOMEM;
*m = (Manager) {
.test_mode = test_mode,
.speed_meter_interval_usec = SPEED_METER_DEFAULT_TIME_INTERVAL,
.online_state = _LINK_ONLINE_STATE_INVALID,
.manage_foreign_routes = true,
.manage_foreign_rules = true,
.ethtool_fd = -1,
.dhcp_duid.type = DUID_TYPE_EN,
.dhcp6_duid.type = DUID_TYPE_EN,
.duid_product_uuid.type = DUID_TYPE_UUID,
};
*ret = TAKE_PTR(m);
return 0;
}
@ -482,6 +456,9 @@ Manager* manager_free(Manager *m) {
m->request_queue = ordered_set_free(m->request_queue);
m->dhcp6_prefixes = hashmap_free_with_destructor(m->dhcp6_prefixes, dhcp6_pd_free);
m->dhcp6_pd_prefixes = set_free_with_destructor(m->dhcp6_pd_prefixes, dhcp6_pd_free);
m->dirty_links = set_free_with_destructor(m->dirty_links, link_unref);
m->links_by_name = hashmap_free(m->links_by_name);
m->links_by_hw_addr = hashmap_free(m->links_by_hw_addr);
@ -579,15 +556,15 @@ bool manager_should_reload(Manager *m) {
static int manager_enumerate_internal(
Manager *m,
sd_netlink *nl,
sd_netlink_message *req,
int (*process)(sd_netlink *, sd_netlink_message *, Manager *)) {
int (*process)(sd_netlink *, sd_netlink_message *, Manager *),
const char *name) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *reply = NULL;
int k, r;
int r;
assert(m);
assert(nl);
assert(m->rtnl);
assert(req);
assert(process);
@ -595,14 +572,22 @@ static int manager_enumerate_internal(
if (r < 0)
return r;
r = sd_netlink_call(nl, req, 0, &reply);
if (r < 0)
r = sd_netlink_call(m->rtnl, req, 0, &reply);
if (r < 0) {
if (name && (r == -EOPNOTSUPP || (r == -EINVAL && mac_selinux_enforcing()))) {
log_debug_errno(r, "%s are not supported by the kernel. Ignoring.", name);
return 0;
}
return r;
}
for (sd_netlink_message *reply_one = reply; reply_one; reply_one = sd_netlink_message_next(reply_one)) {
int k;
m->enumerating = true;
k = process(nl, reply_one, m);
k = process(m->rtnl, reply_one, m);
if (k < 0 && r >= 0)
r = k;
@ -623,7 +608,7 @@ static int manager_enumerate_links(Manager *m) {
if (r < 0)
return r;
return manager_enumerate_internal(m, m->rtnl, req, manager_rtnl_process_link);
return manager_enumerate_internal(m, req, manager_rtnl_process_link, NULL);
}
static int manager_enumerate_addresses(Manager *m) {
@ -637,7 +622,7 @@ static int manager_enumerate_addresses(Manager *m) {
if (r < 0)
return r;
return manager_enumerate_internal(m, m->rtnl, req, manager_rtnl_process_address);
return manager_enumerate_internal(m, req, manager_rtnl_process_address, NULL);
}
static int manager_enumerate_neighbors(Manager *m) {
@ -651,7 +636,7 @@ static int manager_enumerate_neighbors(Manager *m) {
if (r < 0)
return r;
return manager_enumerate_internal(m, m->rtnl, req, manager_rtnl_process_neighbor);
return manager_enumerate_internal(m, req, manager_rtnl_process_neighbor, NULL);
}
static int manager_enumerate_routes(Manager *m) {
@ -668,7 +653,7 @@ static int manager_enumerate_routes(Manager *m) {
if (r < 0)
return r;
return manager_enumerate_internal(m, m->rtnl, req, manager_rtnl_process_route);
return manager_enumerate_internal(m, req, manager_rtnl_process_route, NULL);
}
static int manager_enumerate_rules(Manager *m) {
@ -685,7 +670,7 @@ static int manager_enumerate_rules(Manager *m) {
if (r < 0)
return r;
return manager_enumerate_internal(m, m->rtnl, req, manager_rtnl_process_rule);
return manager_enumerate_internal(m, req, manager_rtnl_process_rule, "Routing policy rules");
}
static int manager_enumerate_nexthop(Manager *m) {
@ -699,50 +684,7 @@ static int manager_enumerate_nexthop(Manager *m) {
if (r < 0)
return r;
return manager_enumerate_internal(m, m->rtnl, req, manager_rtnl_process_nexthop);
}
static int manager_enumerate_nl80211_config(Manager *m) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
int r;
assert(m);
assert(m->genl);
r = sd_genl_message_new(m->genl, NL80211_GENL_NAME, NL80211_CMD_GET_INTERFACE, &req);
if (r < 0)
return r;
return manager_enumerate_internal(m, m->genl, req, manager_genl_process_nl80211_config);
}
static int manager_enumerate_nl80211_mlme(Manager *m) {
Link *link;
int r;
assert(m);
assert(m->genl);
HASHMAP_FOREACH(link, m->links_by_index) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
if (link->wlan_iftype != NL80211_IFTYPE_STATION)
continue;
r = sd_genl_message_new(m->genl, NL80211_GENL_NAME, NL80211_CMD_GET_STATION, &req);
if (r < 0)
return r;
r = sd_netlink_message_append_u32(req, NL80211_ATTR_IFINDEX, link->ifindex);
if (r < 0)
return r;
r = manager_enumerate_internal(m, m->genl, req, manager_genl_process_nl80211_mlme);
if (r < 0)
return r;
}
return 0;
return manager_enumerate_internal(m, req, manager_rtnl_process_nexthop, "Nexthop rules");
}
int manager_enumerate(Manager *m) {
@ -760,37 +702,18 @@ int manager_enumerate(Manager *m) {
if (r < 0)
return log_error_errno(r, "Could not enumerate neighbors: %m");
/* NextHop support is added in kernel v5.3 (65ee00a9409f751188a8cdc0988167858eb4a536),
* and older kernels return -EOPNOTSUPP, or -EINVAL if SELinux is enabled. */
r = manager_enumerate_nexthop(m);
if (r == -EOPNOTSUPP || (r == -EINVAL && mac_selinux_enforcing()))
log_debug_errno(r, "Could not enumerate nexthops, ignoring: %m");
else if (r < 0)
return log_error_errno(r, "Could not enumerate nexthops: %m");
if (r < 0)
return log_error_errno(r, "Could not enumerate nexthop rules: %m");
r = manager_enumerate_routes(m);
if (r < 0)
return log_error_errno(r, "Could not enumerate routes: %m");
/* If kernel is built with CONFIG_FIB_RULES=n, it returns -EOPNOTSUPP. */
r = manager_enumerate_rules(m);
if (r == -EOPNOTSUPP)
log_debug_errno(r, "Could not enumerate routing policy rules, ignoring: %m");
else if (r < 0)
if (r < 0)
return log_error_errno(r, "Could not enumerate routing policy rules: %m");
r = manager_enumerate_nl80211_config(m);
if (r == -EOPNOTSUPP)
log_debug_errno(r, "Could not enumerate wireless LAN interfaces, ignoring: %m");
else if (r < 0)
return log_error_errno(r, "Could not enumerate wireless LAN interfaces: %m");
r = manager_enumerate_nl80211_mlme(m);
if (r == -EOPNOTSUPP)
log_debug_errno(r, "Could not enumerate wireless LAN stations, ignoring: %m");
else if (r < 0)
return log_error_errno(r, "Could not enumerate wireless LAN stations: %m");
return 0;
}

View File

@ -28,7 +28,6 @@ struct Manager {
Hashmap *polkit_registry;
int ethtool_fd;
bool test_mode;
bool enumerating;
bool dirty;
bool restarting;
@ -50,6 +49,8 @@ struct Manager {
Hashmap *links_by_hw_addr;
Hashmap *netdevs;
OrderedHashmap *networks;
Hashmap *dhcp6_prefixes;
Set *dhcp6_pd_prefixes;
OrderedSet *address_pools;
usec_t network_dirs_ts_usec;
@ -95,10 +96,10 @@ struct Manager {
OrderedSet *request_queue;
};
int manager_new(Manager **ret, bool test_mode);
int manager_new(Manager **ret);
Manager* manager_free(Manager *m);
int manager_setup(Manager *m);
int manager_connect_bus(Manager *m);
int manager_start(Manager *m);
int manager_load_config(Manager *m);

View File

@ -16,7 +16,6 @@
#include "networkd-manager.h"
#include "networkd-ndisc.h"
#include "networkd-queue.h"
#include "networkd-route.h"
#include "networkd-state-file.h"
#include "string-table.h"
#include "string-util.h"
@ -97,65 +96,115 @@ void network_adjust_ipv6_accept_ra(Network *network) {
network->ndisc_deny_listed_route_prefix = set_free_free(network->ndisc_deny_listed_route_prefix);
}
static int ndisc_remove(Link *link, struct in6_addr *router) {
bool updated = false;
static int ndisc_remove_old_one(Link *link, const struct in6_addr *router, bool force);
static int ndisc_address_callback(Address *address) {
struct in6_addr router = {};
NDiscAddress *n;
assert(address);
assert(address->link);
assert(address->family == AF_INET6);
SET_FOREACH(n, address->link->ndisc_addresses)
if (n->address == address) {
router = n->router;
break;
}
if (in6_addr_is_null(&router)) {
_cleanup_free_ char *buf = NULL;
(void) in6_addr_prefix_to_string(&address->in_addr.in6, address->prefixlen, &buf);
log_link_debug(address->link, "%s is called for %s, but it is already removed, ignoring.",
__func__, strna(buf));
return 0;
}
/* Make this called only once */
SET_FOREACH(n, address->link->ndisc_addresses)
if (in6_addr_equal(&n->router, &router))
n->address->callback = NULL;
return ndisc_remove_old_one(address->link, &router, true);
}
static int ndisc_remove_old_one(Link *link, const struct in6_addr *router, bool force) {
NDiscAddress *na;
NDiscRoute *nr;
NDiscDNSSL *dnssl;
NDiscRDNSS *rdnss;
Address *address;
Route *route;
int k, r = 0;
bool updated = false;
assert(link);
assert(router);
SET_FOREACH(route, link->routes) {
if (route->source != NETWORK_CONFIG_SOURCE_NDISC)
continue;
if (!route_is_marked(route))
continue;
if (router && !in6_addr_equal(router, &route->provider.in6))
continue;
if (!force) {
bool set_callback = false;
k = route_remove(route);
if (k < 0)
r = k;
SET_FOREACH(na, link->ndisc_addresses)
if (!na->marked && in6_addr_equal(&na->router, router)) {
set_callback = true;
break;
}
route_cancel_request(route);
if (set_callback)
SET_FOREACH(na, link->ndisc_addresses)
if (!na->marked && address_is_ready(na->address)) {
set_callback = false;
break;
}
if (set_callback) {
SET_FOREACH(na, link->ndisc_addresses)
if (!na->marked && in6_addr_equal(&na->router, router))
na->address->callback = ndisc_address_callback;
if (DEBUG_LOGGING) {
_cleanup_free_ char *buf = NULL;
(void) in6_addr_to_string(router, &buf);
log_link_debug(link, "No SLAAC address obtained from %s is ready. "
"The old NDisc information will be removed later.",
strna(buf));
}
return 0;
}
}
SET_FOREACH(address, link->addresses) {
if (address->source != NETWORK_CONFIG_SOURCE_NDISC)
continue;
if (!address_is_marked(address))
continue;
if (router && !in6_addr_equal(router, &address->provider.in6))
continue;
if (DEBUG_LOGGING) {
_cleanup_free_ char *buf = NULL;
k = address_remove(address);
if (k < 0)
r = k;
address_cancel_request(address);
(void) in6_addr_to_string(router, &buf);
log_link_debug(link, "Removing old NDisc information obtained from %s.", strna(buf));
}
SET_FOREACH(rdnss, link->ndisc_rdnss) {
if (!rdnss->marked)
continue;
if (router && !in6_addr_equal(router, &rdnss->router))
continue;
SET_FOREACH(na, link->ndisc_addresses)
if (na->marked && in6_addr_equal(&na->router, router)) {
k = address_remove(na->address, link);
if (k < 0)
r = k;
}
free(set_remove(link->ndisc_rdnss, rdnss));
updated = true;
}
SET_FOREACH(nr, link->ndisc_routes)
if (nr->marked && in6_addr_equal(&nr->router, router)) {
k = route_remove(nr->route, NULL, link);
if (k < 0)
r = k;
}
SET_FOREACH(dnssl, link->ndisc_dnssl) {
if (!dnssl->marked)
continue;
if (router && !in6_addr_equal(router, &dnssl->router))
continue;
SET_FOREACH(rdnss, link->ndisc_rdnss)
if (rdnss->marked && in6_addr_equal(&rdnss->router, router)) {
free(set_remove(link->ndisc_rdnss, rdnss));
updated = true;
}
free(set_remove(link->ndisc_dnssl, dnssl));
updated = true;
}
SET_FOREACH(dnssl, link->ndisc_dnssl)
if (dnssl->marked && in6_addr_equal(&dnssl->router, router)) {
free(set_remove(link->ndisc_dnssl, dnssl));
updated = true;
}
if (updated)
link_dirty(link);
@ -163,100 +212,197 @@ static int ndisc_remove(Link *link, struct in6_addr *router) {
return r;
}
static int ndisc_check_ready(Link *link);
static int ndisc_address_ready_callback(Address *address) {
Address *a;
assert(address);
assert(address->link);
SET_FOREACH(a, address->link->addresses)
if (a->source == NETWORK_CONFIG_SOURCE_NDISC)
a->callback = NULL;
return ndisc_check_ready(address->link);
}
static int ndisc_check_ready(Link *link) {
bool found = false, ready = false;
Address *address;
int r;
static int ndisc_remove_old(Link *link) {
_cleanup_set_free_free_ Set *routers = NULL;
_cleanup_free_ struct in6_addr *router = NULL;
struct in6_addr *a;
NDiscAddress *na;
NDiscRoute *nr;
NDiscDNSSL *dnssl;
NDiscRDNSS *rdnss;
int k, r;
assert(link);
if (link->ndisc_messages > 0) {
log_link_debug(link, "%s(): SLAAC addresses and routes are not set.", __func__);
if (link->ndisc_addresses_messages > 0 ||
link->ndisc_routes_messages > 0)
return 0;
}
SET_FOREACH(address, link->addresses) {
if (address->source != NETWORK_CONFIG_SOURCE_NDISC)
continue;
routers = set_new(&in6_addr_hash_ops);
if (!routers)
return -ENOMEM;
found = true;
SET_FOREACH(na, link->ndisc_addresses)
if (!set_contains(routers, &na->router)) {
router = newdup(struct in6_addr, &na->router, 1);
if (!router)
return -ENOMEM;
if (address_is_ready(address)) {
ready = true;
break;
r = set_put(routers, router);
if (r < 0)
return r;
assert(r > 0);
TAKE_PTR(router);
}
SET_FOREACH(nr, link->ndisc_routes)
if (!set_contains(routers, &nr->router)) {
router = newdup(struct in6_addr, &nr->router, 1);
if (!router)
return -ENOMEM;
r = set_put(routers, router);
if (r < 0)
return r;
assert(r > 0);
TAKE_PTR(router);
}
SET_FOREACH(rdnss, link->ndisc_rdnss)
if (!set_contains(routers, &rdnss->router)) {
router = newdup(struct in6_addr, &rdnss->router, 1);
if (!router)
return -ENOMEM;
r = set_put(routers, router);
if (r < 0)
return r;
assert(r > 0);
TAKE_PTR(router);
}
SET_FOREACH(dnssl, link->ndisc_dnssl)
if (!set_contains(routers, &dnssl->router)) {
router = newdup(struct in6_addr, &dnssl->router, 1);
if (!router)
return -ENOMEM;
r = set_put(routers, router);
if (r < 0)
return r;
assert(r > 0);
TAKE_PTR(router);
}
r = 0;
SET_FOREACH(a, routers) {
k = ndisc_remove_old_one(link, a, false);
if (k < 0)
r = k;
}
if (found && !ready) {
SET_FOREACH(address, link->addresses)
if (address->source == NETWORK_CONFIG_SOURCE_NDISC)
address->callback = ndisc_address_ready_callback;
log_link_debug(link, "%s(): no SLAAC address is ready.", __func__);
return 0;
}
link->ndisc_configured = true;
log_link_debug(link, "SLAAC addresses and routes set.");
r = ndisc_remove(link, NULL);
if (r < 0)
return r;
link_check_ready(link);
return 0;
return r;
}
static void ndisc_route_hash_func(const NDiscRoute *x, struct siphash *state) {
route_hash_func(x->route, state);
}
static int ndisc_route_compare_func(const NDiscRoute *a, const NDiscRoute *b) {
return route_compare_func(a->route, b->route);
}
DEFINE_PRIVATE_HASH_OPS_WITH_KEY_DESTRUCTOR(
ndisc_route_hash_ops,
NDiscRoute,
ndisc_route_hash_func,
ndisc_route_compare_func,
free);
static int ndisc_route_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
int r;
assert(link);
assert(link->ndisc_messages > 0);
assert(link->ndisc_routes_messages > 0);
link->ndisc_messages--;
link->ndisc_routes_messages--;
r = route_configure_handler_internal(rtnl, m, link, "Could not set NDisc route");
if (r <= 0)
return r;
r = ndisc_check_ready(link);
if (r < 0)
link_enter_failed(link);
if (link->ndisc_routes_messages == 0) {
log_link_debug(link, "NDisc routes set.");
link->ndisc_routes_configured = true;
r = ndisc_remove_old(link);
if (r < 0) {
link_enter_failed(link);
return 1;
}
link_check_ready(link);
}
return 1;
}
static int ndisc_after_route_configure(Request *req, void *object) {
_cleanup_free_ NDiscRoute *nr = NULL;
NDiscRoute *nr_exist;
struct in6_addr router;
Route *route = object;
sd_ndisc_router *rt;
Link *link;
int r;
assert(req);
assert(req->link);
assert(req->type == REQUEST_TYPE_ROUTE);
assert(req->userdata);
assert(route);
link = req->link;
rt = req->userdata;
r = sd_ndisc_router_get_address(rt, &router);
if (r < 0)
return log_link_error_errno(link, r, "Failed to get router address from RA: %m");
nr = new(NDiscRoute, 1);
if (!nr)
return log_oom();
*nr = (NDiscRoute) {
.router = router,
.route = route,
};
nr_exist = set_get(link->ndisc_routes, nr);
if (nr_exist) {
nr_exist->marked = false;
nr_exist->router = router;
return 0;
}
r = set_ensure_put(&link->ndisc_routes, &ndisc_route_hash_ops, nr);
if (r < 0)
return log_link_error_errno(link, r, "Failed to store NDisc SLAAC route: %m");
assert(r > 0);
TAKE_PTR(nr);
return 0;
}
static void ndisc_request_on_free(Request *req) {
assert(req);
sd_ndisc_router_unref(req->userdata);
}
static int ndisc_request_route(Route *in, Link *link, sd_ndisc_router *rt) {
_cleanup_(route_freep) Route *route = in;
struct in6_addr router;
Route *existing;
Request *req;
int r;
assert(route);
assert(link);
assert(rt);
r = sd_ndisc_router_get_address(rt, &router);
if (r < 0)
return r;
route->source = NETWORK_CONFIG_SOURCE_NDISC;
route->provider.in6 = router;
if (!route->table_set)
route->table = link_get_ipv6_accept_ra_route_table(link);
if (!route->priority_set)
@ -264,58 +410,134 @@ static int ndisc_request_route(Route *in, Link *link, sd_ndisc_router *rt) {
if (!route->protocol_set)
route->protocol = RTPROT_RA;
if (route_get(NULL, link, route, &existing) < 0)
link->ndisc_configured = false;
else
route_unmark(existing);
r = link_has_route(link, route);
if (r < 0)
return r;
if (r == 0)
link->ndisc_routes_configured = false;
return link_request_route(link, TAKE_PTR(route), true, &link->ndisc_messages,
ndisc_route_handler, NULL);
r = link_request_route(link, TAKE_PTR(route), true, &link->ndisc_routes_messages,
ndisc_route_handler, &req);
if (r <= 0)
return r;
req->userdata = sd_ndisc_router_ref(rt);
req->after_configure = ndisc_after_route_configure;
req->on_free = ndisc_request_on_free;
return 0;
}
static void ndisc_address_hash_func(const NDiscAddress *x, struct siphash *state) {
address_hash_func(x->address, state);
}
static int ndisc_address_compare_func(const NDiscAddress *a, const NDiscAddress *b) {
return address_compare_func(a->address, b->address);
}
DEFINE_PRIVATE_HASH_OPS_WITH_KEY_DESTRUCTOR(
ndisc_address_hash_ops,
NDiscAddress,
ndisc_address_hash_func,
ndisc_address_compare_func,
free);
static int ndisc_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
int r;
assert(link);
assert(link->ndisc_messages > 0);
assert(link->ndisc_addresses_messages > 0);
link->ndisc_messages--;
link->ndisc_addresses_messages--;
r = address_configure_handler_internal(rtnl, m, link, "Could not set NDisc address");
if (r <= 0)
return r;
r = ndisc_check_ready(link);
if (r < 0)
link_enter_failed(link);
if (link->ndisc_addresses_messages == 0) {
log_link_debug(link, "NDisc SLAAC addresses set.");
link->ndisc_addresses_configured = true;
r = ndisc_remove_old(link);
if (r < 0) {
link_enter_failed(link);
return 1;
}
}
return 1;
}
static int ndisc_after_address_configure(Request *req, void *object) {
_cleanup_free_ NDiscAddress *na = NULL;
NDiscAddress *na_exist;
struct in6_addr router;
sd_ndisc_router *rt;
Address *address = object;
Link *link;
int r;
assert(req);
assert(req->link);
assert(req->type == REQUEST_TYPE_ADDRESS);
assert(req->userdata);
assert(address);
link = req->link;
rt = req->userdata;
r = sd_ndisc_router_get_address(rt, &router);
if (r < 0)
return log_link_error_errno(link, r, "Failed to get router address from RA: %m");
na = new(NDiscAddress, 1);
if (!na)
return log_oom();
*na = (NDiscAddress) {
.router = router,
.address = address,
};
na_exist = set_get(link->ndisc_addresses, na);
if (na_exist) {
na_exist->marked = false;
na_exist->router = router;
return 0;
}
r = set_ensure_put(&link->ndisc_addresses, &ndisc_address_hash_ops, na);
if (r < 0)
return log_link_error_errno(link, r, "Failed to store NDisc SLAAC address: %m");
assert(r > 0);
TAKE_PTR(na);
return 0;
}
static int ndisc_request_address(Address *in, Link *link, sd_ndisc_router *rt) {
_cleanup_(address_freep) Address *address = in;
struct in6_addr router;
Address *existing;
Request *req;
int r;
assert(address);
assert(link);
assert(rt);
r = sd_ndisc_router_get_address(rt, &router);
if (r < 0)
if (address_get(link, address, NULL) < 0)
link->ndisc_addresses_configured = false;
r = link_request_address(link, TAKE_PTR(address), true, &link->ndisc_addresses_messages,
ndisc_address_handler, &req);
if (r <= 0)
return r;
address->source = NETWORK_CONFIG_SOURCE_NDISC;
address->provider.in6 = router;
req->userdata = sd_ndisc_router_ref(rt);
req->after_configure = ndisc_after_address_configure;
req->on_free = ndisc_request_on_free;
if (address_get(link, address, &existing) < 0)
link->ndisc_configured = false;
else
address_unmark(existing);
return link_request_address(link, TAKE_PTR(address), true, &link->ndisc_messages,
ndisc_address_handler, NULL);
return 0;
}
static int ndisc_router_process_default(Link *link, sd_ndisc_router *rt) {
@ -765,6 +987,7 @@ static int ndisc_router_process_rdnss(Link *link, sd_ndisc_router *rt) {
uint32_t lifetime;
const struct in6_addr *a;
struct in6_addr router;
NDiscRDNSS *rdnss;
usec_t time_now;
bool updated = false;
int n, r;
@ -788,6 +1011,10 @@ static int ndisc_router_process_rdnss(Link *link, sd_ndisc_router *rt) {
if (n < 0)
return log_link_error_errno(link, n, "Failed to get RDNSS addresses: %m");
SET_FOREACH(rdnss, link->ndisc_rdnss)
if (in6_addr_equal(&rdnss->router, &router))
rdnss->marked = true;
if (lifetime == 0)
return 0;
@ -798,7 +1025,7 @@ static int ndisc_router_process_rdnss(Link *link, sd_ndisc_router *rt) {
for (int j = 0; j < n; j++) {
_cleanup_free_ NDiscRDNSS *x = NULL;
NDiscRDNSS *rdnss, d = {
NDiscRDNSS d = {
.address = a[j],
};
@ -854,6 +1081,7 @@ static int ndisc_router_process_dnssl(Link *link, sd_ndisc_router *rt) {
struct in6_addr router;
uint32_t lifetime;
usec_t time_now;
NDiscDNSSL *dnssl;
bool updated = false;
char **j;
int r;
@ -877,6 +1105,10 @@ static int ndisc_router_process_dnssl(Link *link, sd_ndisc_router *rt) {
if (r < 0)
return log_link_error_errno(link, r, "Failed to get DNSSL addresses: %m");
SET_FOREACH(dnssl, link->ndisc_dnssl)
if (in6_addr_equal(&dnssl->router, &router))
dnssl->marked = true;
if (lifetime == 0)
return 0;
@ -888,7 +1120,6 @@ static int ndisc_router_process_dnssl(Link *link, sd_ndisc_router *rt) {
STRV_FOREACH(j, l) {
_cleanup_free_ NDiscDNSSL *s = NULL;
NDiscDNSSL *dnssl;
s = malloc0(ALIGN(sizeof(NDiscDNSSL)) + strlen(*j) + 1);
if (!s)
@ -1011,28 +1242,11 @@ static int ndisc_router_process_options(Link *link, sd_ndisc_router *rt) {
}
}
static void ndisc_mark(Link *link, const struct in6_addr *router) {
NDiscRDNSS *rdnss;
NDiscDNSSL *dnssl;
assert(link);
assert(router);
link_mark_addresses(link, NETWORK_CONFIG_SOURCE_NDISC, router);
link_mark_routes(link, NETWORK_CONFIG_SOURCE_NDISC, router);
SET_FOREACH(rdnss, link->ndisc_rdnss)
if (in6_addr_equal(&rdnss->router, router))
rdnss->marked = true;
SET_FOREACH(dnssl, link->ndisc_dnssl)
if (in6_addr_equal(&dnssl->router, router))
dnssl->marked = true;
}
static int ndisc_router_handler(Link *link, sd_ndisc_router *rt) {
struct in6_addr router;
uint64_t flags;
NDiscAddress *na;
NDiscRoute *nr;
int r;
assert(link);
@ -1057,7 +1271,13 @@ static int ndisc_router_handler(Link *link, sd_ndisc_router *rt) {
return 0;
}
ndisc_mark(link, &router);
SET_FOREACH(na, link->ndisc_addresses)
if (in6_addr_equal(&na->router, &router))
na->marked = true;
SET_FOREACH(nr, link->ndisc_routes)
if (in6_addr_equal(&nr->router, &router))
nr->marked = true;
r = sd_ndisc_router_get_flags(rt, &flags);
if (r < 0)
@ -1087,16 +1307,21 @@ static int ndisc_router_handler(Link *link, sd_ndisc_router *rt) {
if (r < 0)
return r;
if (link->ndisc_messages == 0) {
link->ndisc_configured = true;
if (link->ndisc_addresses_messages == 0)
link->ndisc_addresses_configured = true;
else
log_link_debug(link, "Setting SLAAC addresses.");
r = ndisc_remove(link, &router);
if (r < 0)
return r;
} else
log_link_debug(link, "Setting SLAAC addresses and router.");
if (link->ndisc_routes_messages == 0)
link->ndisc_routes_configured = true;
else
log_link_debug(link, "Setting NDisc routes.");
if (!link->ndisc_configured)
r = ndisc_remove_old(link);
if (r < 0)
return r;
if (!link->ndisc_addresses_configured || !link->ndisc_routes_configured)
link_set_state(link, LINK_STATE_CONFIGURING);
link_check_ready(link);
@ -1124,8 +1349,9 @@ static void ndisc_handler(sd_ndisc *nd, sd_ndisc_event_t event, sd_ndisc_router
case SD_NDISC_EVENT_TIMEOUT:
log_link_debug(link, "NDisc handler get timeout event");
if (link->ndisc_messages == 0) {
link->ndisc_configured = true;
if (link->ndisc_addresses_messages == 0 && link->ndisc_routes_messages == 0) {
link->ndisc_addresses_configured = true;
link->ndisc_routes_configured = true;
link_check_ready(link);
}
break;
@ -1177,9 +1403,6 @@ int ndisc_start(Link *link) {
if (!link_has_carrier(link))
return 0;
if (in6_addr_is_null(&link->ipv6ll_address))
return 0;
log_link_debug(link, "Discovering IPv6 routers");
return sd_ndisc_start(link->ndisc);
@ -1336,15 +1559,14 @@ int config_parse_address_generation_type(
return 0;
}
DEFINE_CONFIG_PARSE_ENUM(config_parse_ipv6_accept_ra_use_domains, dhcp_use_domains, DHCPUseDomains,
"Failed to parse UseDomains= setting");
DEFINE_CONFIG_PARSE_ENUM(config_parse_ipv6_accept_ra_start_dhcp6_client, ipv6_accept_ra_start_dhcp6_client, IPv6AcceptRAStartDHCP6Client,
"Failed to parse DHCPv6Client= setting");
static const char* const ipv6_accept_ra_start_dhcp6_client_table[_IPV6_ACCEPT_RA_START_DHCP6_CLIENT_MAX] = {
[IPV6_ACCEPT_RA_START_DHCP6_CLIENT_NO] = "no",
[IPV6_ACCEPT_RA_START_DHCP6_CLIENT_ALWAYS] = "always",
[IPV6_ACCEPT_RA_START_DHCP6_CLIENT_YES] = "yes",
};
DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING_WITH_BOOLEAN(ipv6_accept_ra_start_dhcp6_client, IPv6AcceptRAStartDHCP6Client, IPV6_ACCEPT_RA_START_DHCP6_CLIENT_YES);
DEFINE_CONFIG_PARSE_ENUM(config_parse_ipv6_accept_ra_use_domains, dhcp_use_domains, DHCPUseDomains,
"Failed to parse UseDomains= setting");
DEFINE_CONFIG_PARSE_ENUM(config_parse_ipv6_accept_ra_start_dhcp6_client, ipv6_accept_ra_start_dhcp6_client, IPv6AcceptRAStartDHCP6Client,
"Failed to parse DHCPv6Client= setting");
DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(ipv6_accept_ra_start_dhcp6_client, IPv6AcceptRAStartDHCP6Client, IPV6_ACCEPT_RA_START_DHCP6_CLIENT_YES);

View File

@ -2,11 +2,11 @@
#pragma once
#include "conf-parser.h"
#include "networkd-address.h"
#include "networkd-link.h"
#include "networkd-route.h"
#include "time-util.h"
typedef struct Link Link;
typedef struct Network Network;
typedef enum IPv6AcceptRAStartDHCP6Client {
IPV6_ACCEPT_RA_START_DHCP6_CLIENT_NO,
IPV6_ACCEPT_RA_START_DHCP6_CLIENT_ALWAYS,
@ -15,6 +15,20 @@ typedef enum IPv6AcceptRAStartDHCP6Client {
_IPV6_ACCEPT_RA_START_DHCP6_CLIENT_INVALID = -EINVAL,
} IPv6AcceptRAStartDHCP6Client;
typedef struct NDiscAddress {
/* Used when GC'ing old DNS servers when configuration changes. */
bool marked;
struct in6_addr router;
Address *address;
} NDiscAddress;
typedef struct NDiscRoute {
/* Used when GC'ing old DNS servers when configuration changes. */
bool marked;
struct in6_addr router;
Route *route;
} NDiscRoute;
typedef struct NDiscRDNSS {
/* Used when GC'ing old DNS servers when configuration changes. */
bool marked;
@ -47,3 +61,6 @@ void ndisc_flush(Link *link);
CONFIG_PARSER_PROTOTYPE(config_parse_address_generation_type);
CONFIG_PARSER_PROTOTYPE(config_parse_ipv6_accept_ra_start_dhcp6_client);
CONFIG_PARSER_PROTOTYPE(config_parse_ipv6_accept_ra_use_domains);
const char* ipv6_accept_ra_start_dhcp6_client_to_string(IPv6AcceptRAStartDHCP6Client i) _const_;
IPv6AcceptRAStartDHCP6Client ipv6_accept_ra_start_dhcp6_client_from_string(const char *s) _pure_;

View File

@ -49,7 +49,7 @@ Match.PermanentMACAddress, config_parse_hwaddrs,
Match.Path, config_parse_match_strv, 0, offsetof(Network, match.path)
Match.Driver, config_parse_match_strv, 0, offsetof(Network, match.driver)
Match.Type, config_parse_match_strv, 0, offsetof(Network, match.iftype)
Match.WLANInterfaceType, config_parse_match_strv, 0, offsetof(Network, match.wlan_iftype)
Match.WLANInterfaceType, config_parse_match_strv, 0, offsetof(Network, match.wifi_iftype)
Match.SSID, config_parse_match_strv, 0, offsetof(Network, match.ssid)
Match.BSSID, config_parse_hwaddrs, 0, offsetof(Network, match.bssid)
Match.Name, config_parse_match_ifnames, IFNAME_VALID_ALTERNATIVE, offsetof(Network, match.ifname)

View File

@ -28,7 +28,6 @@
#include "networkd-network.h"
#include "networkd-nexthop.h"
#include "networkd-radv.h"
#include "networkd-route.h"
#include "networkd-routing-policy-rule.h"
#include "networkd-sriov.h"
#include "parse-util.h"

View File

@ -743,6 +743,8 @@ static bool nexthop_is_ready_to_configure(Link *link, const NextHop *nexthop) {
return false;
if (nexthop_owned_by_link(nexthop)) {
Link *l;
/* TODO: fdb nexthop does not require IFF_UP. The conditions below needs to be updated
* when fdb nexthop support is added. See rtm_to_nh_config() in net/ipv4/nexthop.c of
* kernel. */
@ -750,6 +752,13 @@ static bool nexthop_is_ready_to_configure(Link *link, const NextHop *nexthop) {
return false;
if (!FLAGS_SET(link->flags, IFF_UP))
return false;
HASHMAP_FOREACH(l, link->manager->links_by_index) {
if (l->address_remove_messages > 0)
return false;
if (l->route_remove_messages > 0)
return false;
}
}
/* All group members must be configured first. */

View File

@ -70,6 +70,9 @@ static Request *request_free(Request *req) {
/* To prevent from triggering assertions in hash functions, remove this request before
* freeing object below. */
ordered_set_remove(req->link->manager->request_queue, req);
if (req->on_free)
/* on_free() may use object. So, let's call this earlier. */
req->on_free(req);
if (req->consume_object)
request_free_object(req->type, req->object);
link_unref(req->link);

View File

@ -15,6 +15,11 @@ typedef struct NextHop NextHop;
typedef struct Route Route;
typedef struct RoutingPolicyRule RoutingPolicyRule;
typedef struct Request Request;
typedef int (*request_after_configure_handler_t)(Request*, void*);
typedef void (*request_on_free_handler_t)(Request*);
typedef enum RequestType {
REQUEST_TYPE_ACTIVATE_LINK,
REQUEST_TYPE_ADDRESS,
@ -58,6 +63,8 @@ typedef struct Request {
void *userdata;
unsigned *message_counter;
link_netlink_message_handler_t netlink_handler;
request_after_configure_handler_t after_configure;
request_on_free_handler_t on_free;
} Request;
void request_drop(Request *req);

View File

@ -7,13 +7,11 @@
#include <arpa/inet.h>
#include "dns-domain.h"
#include "networkd-address.h"
#include "networkd-link.h"
#include "networkd-manager.h"
#include "networkd-network.h"
#include "networkd-queue.h"
#include "networkd-radv.h"
#include "networkd-route.h"
#include "parse-util.h"
#include "string-util.h"
#include "string-table.h"
@ -204,54 +202,6 @@ void network_adjust_radv(Network *network) {
}
}
static bool link_radv_enabled(Link *link) {
assert(link);
if (!link_ipv6ll_enabled(link))
return false;
return link->network->router_prefix_delegation;
}
int link_request_radv_addresses(Link *link) {
Prefix *p;
int r;
assert(link);
if (!link_radv_enabled(link))
return 0;
HASHMAP_FOREACH(p, link->network->prefixes_by_section) {
_cleanup_(address_freep) Address *address = NULL;
if (!p->assign)
continue;
r = address_new(&address);
if (r < 0)
return log_oom();
r = sd_radv_prefix_get_prefix(p->radv_prefix, &address->in_addr.in6, &address->prefixlen);
if (r < 0)
return r;
r = generate_ipv6_eui_64_address(link, &address->in_addr.in6);
if (r < 0)
return r;
address->source = NETWORK_CONFIG_SOURCE_STATIC;
address->family = AF_INET6;
address->route_metric = p->route_metric;
r = link_request_static_address(link, TAKE_PTR(address), true);
if (r < 0)
return r;
}
return 0;
}
int config_parse_prefix(
const char *unit,
const char *filename,
@ -710,6 +660,15 @@ static int radv_find_uplink(Link *link, Link **ret) {
return 0;
}
static bool link_radv_enabled(Link *link) {
assert(link);
if (!link_ipv6ll_enabled(link))
return false;
return link->network->router_prefix_delegation;
}
static int radv_configure(Link *link) {
uint16_t router_lifetime;
Link *uplink = NULL;

View File

@ -51,8 +51,6 @@ void network_drop_invalid_prefixes(Network *network);
void network_drop_invalid_route_prefixes(Network *network);
void network_adjust_radv(Network *network);
int link_request_radv_addresses(Link *link);
int radv_update_mac(Link *link);
int radv_add_prefix(Link *link, const struct in6_addr *prefix, uint8_t prefix_len,
uint32_t lifetime_preferred, uint32_t lifetime_valid);

File diff suppressed because it is too large Load Diff

View File

@ -16,13 +16,11 @@ typedef struct Network Network;
typedef struct Request Request;
typedef struct Route {
Link *link;
Manager *manager;
Network *network;
NetworkConfigSection *section;
NetworkConfigSource source;
NetworkConfigState state;
union in_addr_union provider; /* DHCP server or router address */
Link *link;
Manager *manager;
int family;
int gw_family;
@ -54,6 +52,7 @@ typedef struct Route {
bool protocol_set:1;
bool pref_set:1;
bool gateway_from_dhcp_or_ra:1;
bool removing:1;
union in_addr_union gw;
union in_addr_union dst;
@ -67,6 +66,7 @@ typedef struct Route {
void route_hash_func(const Route *route, struct siphash *state);
int route_compare_func(const Route *a, const Route *b);
bool route_equal(const Route *r1, const Route *r2);
extern const struct hash_ops route_hash_ops;
int route_new(Route **ret);
@ -75,16 +75,15 @@ DEFINE_NETWORK_SECTION_FUNCTIONS(Route, route_free);
int route_dup(const Route *src, Route **ret);
int route_configure_handler_internal(sd_netlink *rtnl, sd_netlink_message *m, Link *link, const char *error_msg);
int route_remove(Route *route);
int route_remove(const Route *route, Manager *manager, Link *link);
int route_get(Manager *manager, Link *link, const Route *in, Route **ret);
int link_has_route(Link *link, const Route *route);
int manager_find_uplink(Manager *m, int family, Link *exclude, Link **ret);
bool gateway_is_ready(Link *link, int onlink, int family, const union in_addr_union *gw);
int link_drop_routes(Link *link);
int link_drop_foreign_routes(Link *link);
void route_cancel_request(Route *route);
int link_request_route(
Link *link,
Route *route,
@ -104,9 +103,6 @@ void network_drop_invalid_routes(Network *network);
int manager_get_route_table_from_string(const Manager *m, const char *table, uint32_t *ret);
int manager_get_route_table_to_string(const Manager *m, uint32_t table, char **ret);
DEFINE_NETWORK_CONFIG_STATE_FUNCTIONS(Route, route);
void link_mark_routes(Link *link, NetworkConfigSource source, const struct in6_addr *router);
CONFIG_PARSER_PROTOTYPE(config_parse_gateway);
CONFIG_PARSER_PROTOTYPE(config_parse_preferred_src);
CONFIG_PARSER_PROTOTYPE(config_parse_destination);

View File

@ -6,7 +6,6 @@
#include "missing_network.h"
#include "netlink-util.h"
#include "networkd-address.h"
#include "networkd-can.h"
#include "networkd-link.h"
#include "networkd-manager.h"

View File

@ -119,9 +119,7 @@ int manager_save(Manager *m) {
int r;
assert(m);
if (isempty(m->state_file))
return 0; /* Do not update state file when running in test mode. */
assert(m->state_file);
HASHMAP_FOREACH(link, m->links_by_index) {
const struct in_addr *addresses;
@ -425,11 +423,10 @@ int link_save(Link *link) {
int r;
assert(link);
assert(link->state_file);
assert(link->lease_file);
assert(link->manager);
if (isempty(link->state_file))
return 0; /* Do not update state files when running in test mode. */
if (link->state == LINK_STATE_LINGER)
return 0;

View File

@ -3,7 +3,11 @@
#include <net/ethernet.h>
#include <linux/nl80211.h>
#include "sd-bus.h"
#include "bus-util.h"
#include "ether-addr-util.h"
#include "netlink-internal.h"
#include "netlink-util.h"
#include "networkd-link.h"
#include "networkd-manager.h"
@ -11,275 +15,56 @@
#include "string-util.h"
#include "wifi-util.h"
static int link_get_wlan_interface(Link *link) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL;
int wifi_get_info(Link *link) {
_cleanup_free_ char *ssid = NULL;
enum nl80211_iftype iftype;
bool updated = false;
const char *type;
int r;
assert(link);
r = sd_genl_message_new(link->manager->genl, NL80211_GENL_NAME, NL80211_CMD_GET_INTERFACE, &req);
if (!link->sd_device)
return 0;
r = sd_device_get_devtype(link->sd_device, &type);
if (r == -ENOENT)
return 0;
else if (r < 0)
return r;
if (!streq(type, "wlan"))
return 0;
r = wifi_get_interface(link->manager->genl, link->ifindex, &iftype, &ssid);
if (r < 0)
return log_link_debug_errno(link, r, "Failed to create generic netlink message: %m");
return r;
if (r == 0)
iftype = link->wlan_iftype; /* Assume iftype is not changed. */
r = sd_netlink_message_append_u32(req, NL80211_ATTR_IFINDEX, link->ifindex);
if (r < 0)
return log_link_debug_errno(link, r, "Could not append NL80211_ATTR_IFINDEX attribute: %m");
r = sd_netlink_call(link->manager->genl, req, 0, &reply);
if (r < 0)
return log_link_debug_errno(link, r, "Failed to request information about wlan interface: %m");
if (!reply) {
log_link_debug(link, "No reply received to request for information about wifi interface, ignoring.");
return 0;
}
return manager_genl_process_nl80211_config(link->manager->genl, reply, link->manager);
}
int manager_genl_process_nl80211_config(sd_netlink *genl, sd_netlink_message *message, Manager *manager) {
_cleanup_free_ char *ssid = NULL;
uint32_t ifindex, wlan_iftype;
const char *family, *ifname;
uint8_t cmd;
size_t len;
Link *link;
int r;
assert(genl);
assert(message);
assert(manager);
if (sd_netlink_message_is_error(message)) {
r = sd_netlink_message_get_errno(message);
if (r < 0)
log_message_warning_errno(message, r, "nl80211: received error message, ignoring");
return 0;
}
r = sd_genl_message_get_family_name(genl, message, &family);
if (r < 0) {
log_debug_errno(r, "nl80211: failed to determine genl family, ignoring: %m");
return 0;
}
if (!streq(family, NL80211_GENL_NAME)) {
log_debug("nl80211: received message of unexpected genl family '%s', ignoring.", family);
return 0;
}
r = sd_genl_message_get_command(genl, message, &cmd);
if (r < 0) {
log_debug_errno(r, "nl80211: failed to determine genl message command, ignoring: %m");
return 0;
}
if (!IN_SET(cmd, NL80211_CMD_SET_INTERFACE, NL80211_CMD_NEW_INTERFACE, NL80211_CMD_DEL_INTERFACE)) {
log_debug("nl80211: ignoring nl80211 %s(%u) message.",
strna(nl80211_cmd_to_string(cmd)), cmd);
return 0;
}
r = sd_netlink_message_read_u32(message, NL80211_ATTR_IFINDEX, &ifindex);
if (r < 0) {
log_debug_errno(r, "nl80211: received %s(%u) message without valid ifindex, ignoring: %m",
strna(nl80211_cmd_to_string(cmd)), cmd);
return 0;
}
r = link_get_by_index(manager, ifindex, &link);
if (r < 0) {
log_debug_errno(r, "nl80211: received %s(%u) message for link '%"PRIu32"' we don't know about, ignoring.",
strna(nl80211_cmd_to_string(cmd)), cmd, ifindex);
return 0;
}
r = sd_netlink_message_read_string(message, NL80211_ATTR_IFNAME, &ifname);
if (r < 0) {
log_link_debug_errno(link, r, "nl80211: received %s(%u) message without valid interface name, ignoring: %m",
strna(nl80211_cmd_to_string(cmd)), cmd);
return 0;
}
if (!streq(ifname, link->ifname)) {
log_link_debug_errno(link, r, "nl80211: received %s(%u) message with invalid interface name '%s', ignoring: %m",
strna(nl80211_cmd_to_string(cmd)), cmd, ifname);
return 0;
}
r = sd_netlink_message_read_u32(message, NL80211_ATTR_IFTYPE, &wlan_iftype);
if (r < 0) {
log_link_debug_errno(link, r, "nl80211: received %s(%u) message without valid wlan interface type, ignoring: %m",
strna(nl80211_cmd_to_string(cmd)), cmd);
return 0;
}
r = sd_netlink_message_read_data_suffix0(message, NL80211_ATTR_SSID, &len, (void**) &ssid);
if (r < 0 && r != -ENODATA) {
log_link_debug_errno(link, r, "nl80211: received %s(%u) message without valid SSID, ignoring: %m",
strna(nl80211_cmd_to_string(cmd)), cmd);
return 0;
}
if (r >= 0) {
if (len == 0) {
log_link_debug(link, "nl80211: received SSID has zero length, ignoring the received SSID: %m");
ssid = mfree(ssid);
} else if (strlen_ptr(ssid) != len) {
log_link_debug(link, "nl80211: received SSID contains NUL character(s), ignoring the received SSID.");
ssid = mfree(ssid);
}
}
log_link_debug(link, "nl80211: received %s(%u) message: iftype=%s, ssid=%s",
strna(nl80211_cmd_to_string(cmd)), cmd,
strna(nl80211_iftype_to_string(wlan_iftype)), ssid);
switch(cmd) {
case NL80211_CMD_SET_INTERFACE:
case NL80211_CMD_NEW_INTERFACE:
link->wlan_iftype = wlan_iftype;
free_and_replace(link->ssid, ssid);
break;
case NL80211_CMD_DEL_INTERFACE:
link->wlan_iftype = NL80211_IFTYPE_UNSPECIFIED;
link->ssid = mfree(link->ssid);
break;
default:
assert_not_reached();
}
return 0;
}
int manager_genl_process_nl80211_mlme(sd_netlink *genl, sd_netlink_message *message, Manager *manager) {
const char *family;
uint32_t ifindex;
uint8_t cmd;
Link *link;
int r;
assert(genl);
assert(message);
assert(manager);
if (sd_netlink_message_is_error(message)) {
r = sd_netlink_message_get_errno(message);
if (r < 0)
log_message_warning_errno(message, r, "nl80211: received error message, ignoring");
return 0;
}
r = sd_genl_message_get_family_name(genl, message, &family);
if (r < 0) {
log_debug_errno(r, "nl80211: failed to determine genl family, ignoring: %m");
return 0;
}
if (!streq(family, NL80211_GENL_NAME)) {
log_debug("nl80211: Received message of unexpected genl family '%s', ignoring.", family);
return 0;
}
r = sd_genl_message_get_command(genl, message, &cmd);
if (r < 0) {
log_debug_errno(r, "nl80211: failed to determine genl message command, ignoring: %m");
return 0;
}
r = sd_netlink_message_read_u32(message, NL80211_ATTR_IFINDEX, &ifindex);
if (r < 0) {
log_debug_errno(r, "nl80211: received %s(%u) message without valid ifindex, ignoring: %m",
strna(nl80211_cmd_to_string(cmd)), cmd);
return 0;
}
r = link_get_by_index(manager, ifindex, &link);
if (r < 0) {
log_debug_errno(r, "nl80211: received %s(%u) message for link '%"PRIu32"' we don't know about, ignoring.",
strna(nl80211_cmd_to_string(cmd)), cmd, ifindex);
return 0;
}
switch(cmd) {
case NL80211_CMD_NEW_STATION:
case NL80211_CMD_DEL_STATION: {
if (iftype == NL80211_IFTYPE_STATION) {
struct ether_addr bssid;
r = sd_netlink_message_read_ether_addr(message, NL80211_ATTR_MAC, &bssid);
if (r < 0) {
log_link_debug_errno(link, r, "nl80211: received %s(%u) message without valid BSSID, ignoring: %m",
strna(nl80211_cmd_to_string(cmd)), cmd);
return 0;
}
log_link_debug(link, "nl80211: received %s(%u) message: bssid=%s",
strna(nl80211_cmd_to_string(cmd)), cmd, ETHER_ADDR_TO_STR(&bssid));
if (cmd == NL80211_CMD_DEL_STATION) {
link->bssid = ETHER_ADDR_NULL;
return 0;
}
r = wifi_get_station(link->manager->genl, link->ifindex, &bssid);
if (r < 0)
return r;
updated = !ether_addr_equal(&link->bssid, &bssid);
link->bssid = bssid;
if (manager->enumerating &&
link->wlan_iftype == NL80211_IFTYPE_STATION && link->ssid)
log_link_info(link, "Connected WiFi access point: %s (%s)",
link->ssid, ETHER_ADDR_TO_STR(&link->bssid));
break;
}
case NL80211_CMD_CONNECT: {
struct ether_addr bssid;
uint16_t status_code;
r = sd_netlink_message_read_ether_addr(message, NL80211_ATTR_MAC, &bssid);
if (r < 0 && r != -ENODATA) {
log_link_debug_errno(link, r, "nl80211: received %s(%u) message without valid BSSID, ignoring: %m",
strna(nl80211_cmd_to_string(cmd)), cmd);
return 0;
}
r = sd_netlink_message_read_u16(message, NL80211_ATTR_STATUS_CODE, &status_code);
if (r < 0) {
log_link_debug_errno(link, r, "nl80211: received %s(%u) message without valid status code, ignoring: %m",
strna(nl80211_cmd_to_string(cmd)), cmd);
return 0;
}
log_link_debug(link, "nl80211: received %s(%u) message: status=%u, bssid=%s",
strna(nl80211_cmd_to_string(cmd)), cmd, status_code, ETHER_ADDR_TO_STR(&bssid));
if (status_code != 0)
return 0;
link->bssid = bssid;
if (!manager->enumerating) {
r = link_get_wlan_interface(link);
if (r < 0) {
log_link_warning_errno(link, r, "Failed to update wireless LAN interface: %m");
link_enter_failed(link);
return 0;
}
}
updated = updated || link->wlan_iftype != iftype;
link->wlan_iftype = iftype;
updated = updated || !streq_ptr(link->ssid, ssid);
free_and_replace(link->ssid, ssid);
if (updated) {
if (link->wlan_iftype == NL80211_IFTYPE_STATION && link->ssid)
log_link_info(link, "Connected WiFi access point: %s (%s)",
link->ssid, ETHER_ADDR_TO_STR(&link->bssid));
break;
}
case NL80211_CMD_DISCONNECT:
log_link_debug(link, "nl80211: received %s(%u) message.",
strna(nl80211_cmd_to_string(cmd)), cmd);
link->bssid = ETHER_ADDR_NULL;
link->ssid = mfree(link->ssid);
break;
default:
log_link_debug(link, "nl80211: received %s(%u) message.",
strna(nl80211_cmd_to_string(cmd)), cmd);
return 1; /* Some information is updated. */
}
return 0;
return 0; /* No new information. */
}

View File

@ -1,9 +1,8 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include "sd-netlink.h"
#include "sd-bus.h"
typedef struct Manager Manager;
typedef struct Link Link;
int manager_genl_process_nl80211_config(sd_netlink *genl, sd_netlink_message *message, Manager *manager);
int manager_genl_process_nl80211_mlme(sd_netlink *genl, sd_netlink_message *message, Manager *manager);
int wifi_get_info(Link *link);

View File

@ -73,13 +73,13 @@ static int run(int argc, char *argv[]) {
assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGTERM, SIGINT, -1) >= 0);
r = manager_new(&m, /* test_mode = */ false);
r = manager_new(&m);
if (r < 0)
return log_error_errno(r, "Could not create manager: %m");
r = manager_setup(m);
r = manager_connect_bus(m);
if (r < 0)
return log_error_errno(r, "Could not setup manager: %m");
return log_error_errno(r, "Could not connect to bus: %m");
r = manager_parse_config_file(m);
if (r < 0)

View File

@ -10,9 +10,7 @@
#include "ether-addr-util.h"
#include "hostname-setup.h"
#include "network-internal.h"
#include "networkd-address.h"
#include "networkd-manager.h"
#include "networkd-route.h"
#include "string-util.h"
#include "strv.h"
#include "tests.h"
@ -170,16 +168,6 @@ static int test_load_config(Manager *manager) {
return 0;
}
static bool address_equal(const Address *a1, const Address *a2) {
if (a1 == a2)
return true;
if (!a1 || !a2)
return false;
return address_compare_func(a1, a2) == 0;
}
static void test_address_equality(void) {
_cleanup_(address_freep) Address *a1 = NULL, *a2 = NULL;
@ -281,8 +269,7 @@ int main(void) {
test_address_equality();
test_dhcp_hostname_shorten_overlong();
assert_se(manager_new(&manager, /* test_mode = */ true) >= 0);
assert_se(manager_setup(manager) >= 0);
assert_se(manager_new(&manager) >= 0);
test_route_tables(manager);

View File

@ -4,7 +4,6 @@
#include "log.h"
#include "macro.h"
#include "net-condition.h"
#include "networkd-address.h"
#include "networkd-conf.h"
#include "networkd-network.h"
#include "strv.h"

View File

@ -39,8 +39,8 @@ static int resolvconf_help(void) {
"This is a compatibility alias for the resolvectl(1) tool, providing native\n"
"command line compatibility with the resolvconf(8) tool of various Linux\n"
"distributions and BSD systems. Some options supported by other implementations\n"
"are not supported and are ignored: -m, -p, -u. Various options supported by other\n"
"implementations are not supported and will cause the invocation to fail:\n"
"are not supported and are ignored: -m, -p. Various options supported by other\n"
"implementations are not supported and will cause the invocation to fail: -u,\n"
"-I, -i, -l, -R, -r, -v, -V, --enable-updates, --disable-updates,\n"
"--updates-are-enabled.\n"
"\nSee the %2$s for details.\n",
@ -171,11 +171,8 @@ int resolvconf_parse_argv(int argc, char *argv[]) {
log_debug("Switch -%c ignored.", c);
break;
/* -u supposedly should "update all subscribers". We have no subscribers, hence let's make
this a NOP, and exit immediately, cleanly. */
/* Everybody else can agree on the existence of -u but we don't support it. */
case 'u':
log_info("Switch -%c ignored.", c);
return 0;
/* The following options are openresolv inventions we don't support. */
case 'I':

View File

@ -10,7 +10,6 @@
#include "socket-util.h"
#include "string-table.h"
#include "strv.h"
#include "wifi-util.h"
void net_match_clear(NetMatch *match) {
if (!match)
@ -23,7 +22,7 @@ void net_match_clear(NetMatch *match) {
match->iftype = strv_free(match->iftype);
match->ifname = strv_free(match->ifname);
match->property = strv_free(match->property);
match->wlan_iftype = strv_free(match->wlan_iftype);
match->wifi_iftype = strv_free(match->wifi_iftype);
match->ssid = strv_free(match->ssid);
match->bssid = set_free_free(match->bssid);
}
@ -39,7 +38,7 @@ bool net_match_is_empty(const NetMatch *match) {
strv_isempty(match->iftype) &&
strv_isempty(match->ifname) &&
strv_isempty(match->property) &&
strv_isempty(match->wlan_iftype) &&
strv_isempty(match->wifi_iftype) &&
strv_isempty(match->ssid) &&
set_isempty(match->bssid);
}
@ -118,6 +117,23 @@ static int net_condition_test_property(char * const *match_property, sd_device *
return true;
}
static const char *const wifi_iftype_table[NL80211_IFTYPE_MAX+1] = {
[NL80211_IFTYPE_ADHOC] = "ad-hoc",
[NL80211_IFTYPE_STATION] = "station",
[NL80211_IFTYPE_AP] = "ap",
[NL80211_IFTYPE_AP_VLAN] = "ap-vlan",
[NL80211_IFTYPE_WDS] = "wds",
[NL80211_IFTYPE_MONITOR] = "monitor",
[NL80211_IFTYPE_MESH_POINT] = "mesh-point",
[NL80211_IFTYPE_P2P_CLIENT] = "p2p-client",
[NL80211_IFTYPE_P2P_GO] = "p2p-go",
[NL80211_IFTYPE_P2P_DEVICE] = "p2p-device",
[NL80211_IFTYPE_OCB] = "ocb",
[NL80211_IFTYPE_NAN] = "nan",
};
DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(wifi_iftype, enum nl80211_iftype);
int net_match_config(
const NetMatch *match,
sd_device *device,
@ -127,7 +143,7 @@ int net_match_config(
unsigned short iftype,
const char *ifname,
char * const *alternative_names,
enum nl80211_iftype wlan_iftype,
enum nl80211_iftype wifi_iftype,
const char *ssid,
const struct ether_addr *bssid) {
@ -178,7 +194,7 @@ int net_match_config(
if (!net_condition_test_property(match->property, device))
return false;
if (!net_condition_test_strv(match->wlan_iftype, nl80211_iftype_to_string(wlan_iftype)))
if (!net_condition_test_strv(match->wifi_iftype, wifi_iftype_to_string(wifi_iftype)))
return false;
if (!net_condition_test_strv(match->ssid, ssid))

View File

@ -18,7 +18,7 @@ typedef struct NetMatch {
char **iftype;
char **ifname;
char **property;
char **wlan_iftype;
char **wifi_iftype;
char **ssid;
Set *bssid;
} NetMatch;
@ -35,7 +35,7 @@ int net_match_config(
unsigned short iftype,
const char *ifname,
char * const *alternative_names,
enum nl80211_iftype wlan_iftype,
enum nl80211_iftype wifi_iftype,
const char *ssid,
const struct ether_addr *bssid);

View File

@ -1,16 +1,12 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include "log.h"
#include "string-table.h"
#include "string-util.h"
#include "wifi-util.h"
int wifi_get_interface(sd_netlink *genl, int ifindex, enum nl80211_iftype *ret_iftype, char **ret_ssid) {
int wifi_get_interface(sd_netlink *genl, int ifindex, enum nl80211_iftype *iftype, char **ssid) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL, *reply = NULL;
_cleanup_free_ char *ssid = NULL;
const char *family;
uint32_t iftype;
size_t len;
int r;
assert(genl);
@ -51,47 +47,41 @@ int wifi_get_interface(sd_netlink *genl, int ifindex, enum nl80211_iftype *ret_i
goto nodata;
}
r = sd_netlink_message_read_u32(reply, NL80211_ATTR_IFTYPE, &iftype);
if (r < 0)
return log_debug_errno(r, "Failed to get NL80211_ATTR_IFTYPE attribute: %m");
if (iftype) {
uint32_t t;
r = sd_netlink_message_read_data_suffix0(reply, NL80211_ATTR_SSID, &len, (void**) &ssid);
if (r < 0 && r != -ENODATA)
return log_debug_errno(r, "Failed to get NL80211_ATTR_SSID attribute: %m");
if (r >= 0) {
if (len == 0) {
log_debug("SSID has zero length, ignoring the received SSID.");
ssid = mfree(ssid);
} else if (strlen_ptr(ssid) != len) {
log_debug("SSID contains NUL character(s), ignoring the received SSID.");
ssid = mfree(ssid);
}
r = sd_netlink_message_read_u32(reply, NL80211_ATTR_IFTYPE, &t);
if (r < 0)
return log_debug_errno(r, "Failed to get NL80211_ATTR_IFTYPE attribute: %m");
*iftype = t;
}
if (ret_iftype)
*ret_iftype = iftype;
if (ret_ssid)
*ret_ssid = TAKE_PTR(ssid);
if (ssid) {
r = sd_netlink_message_read_string_strdup(reply, NL80211_ATTR_SSID, ssid);
if (r == -ENODATA)
*ssid = NULL;
else if (r < 0)
return log_debug_errno(r, "Failed to get NL80211_ATTR_SSID attribute: %m");
}
return 1;
nodata:
if (ret_iftype)
*ret_iftype = 0;
if (ret_ssid)
*ret_ssid = NULL;
if (iftype)
*iftype = 0;
if (ssid)
*ssid = NULL;
return 0;
}
int wifi_get_station(sd_netlink *genl, int ifindex, struct ether_addr *ret_bssid) {
int wifi_get_station(sd_netlink *genl, int ifindex, struct ether_addr *bssid) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL, *reply = NULL;
const char *family;
int r;
assert(genl);
assert(ifindex > 0);
assert(ret_bssid);
assert(bssid);
r = sd_genl_message_new(genl, NL80211_GENL_NAME, NL80211_CMD_GET_STATION, &m);
if (r < 0)
@ -125,7 +115,7 @@ int wifi_get_station(sd_netlink *genl, int ifindex, struct ether_addr *ret_bssid
goto nodata;
}
r = sd_netlink_message_read_ether_addr(reply, NL80211_ATTR_MAC, ret_bssid);
r = sd_netlink_message_read_ether_addr(reply, NL80211_ATTR_MAC, bssid);
if (r == -ENODATA)
goto nodata;
if (r < 0)
@ -134,173 +124,6 @@ int wifi_get_station(sd_netlink *genl, int ifindex, struct ether_addr *ret_bssid
return 1;
nodata:
*ret_bssid = ETHER_ADDR_NULL;
*bssid = (struct ether_addr) {};
return 0;
}
static const char * const nl80211_iftype_table[NUM_NL80211_IFTYPES] = {
[NL80211_IFTYPE_ADHOC] = "ad-hoc",
[NL80211_IFTYPE_STATION] = "station",
[NL80211_IFTYPE_AP] = "ap",
[NL80211_IFTYPE_AP_VLAN] = "ap-vlan",
[NL80211_IFTYPE_WDS] = "wds",
[NL80211_IFTYPE_MONITOR] = "monitor",
[NL80211_IFTYPE_MESH_POINT] = "mesh-point",
[NL80211_IFTYPE_P2P_CLIENT] = "p2p-client",
[NL80211_IFTYPE_P2P_GO] = "p2p-go",
[NL80211_IFTYPE_P2P_DEVICE] = "p2p-device",
[NL80211_IFTYPE_OCB] = "ocb",
[NL80211_IFTYPE_NAN] = "nan",
};
DEFINE_STRING_TABLE_LOOKUP_TO_STRING(nl80211_iftype, enum nl80211_iftype);
static const char * const nl80211_cmd_table[__NL80211_CMD_AFTER_LAST] = {
[NL80211_CMD_GET_WIPHY] = "get_wiphy",
[NL80211_CMD_SET_WIPHY] = "set_wiphy",
[NL80211_CMD_NEW_WIPHY] = "new_wiphy",
[NL80211_CMD_DEL_WIPHY] = "del_wiphy",
[NL80211_CMD_GET_INTERFACE] = "get_interface",
[NL80211_CMD_SET_INTERFACE] = "set_interface",
[NL80211_CMD_NEW_INTERFACE] = "new_interface",
[NL80211_CMD_DEL_INTERFACE] = "del_interface",
[NL80211_CMD_GET_KEY] = "get_key",
[NL80211_CMD_SET_KEY] = "set_key",
[NL80211_CMD_NEW_KEY] = "new_key",
[NL80211_CMD_DEL_KEY] = "del_key",
[NL80211_CMD_GET_BEACON] = "get_beacon",
[NL80211_CMD_SET_BEACON] = "set_beacon",
[NL80211_CMD_START_AP] = "start_ap",
[NL80211_CMD_STOP_AP] = "stop_ap",
[NL80211_CMD_GET_STATION] = "get_station",
[NL80211_CMD_SET_STATION] = "set_station",
[NL80211_CMD_NEW_STATION] = "new_station",
[NL80211_CMD_DEL_STATION] = "del_station",
[NL80211_CMD_GET_MPATH] = "get_mpath",
[NL80211_CMD_SET_MPATH] = "set_mpath",
[NL80211_CMD_NEW_MPATH] = "new_mpath",
[NL80211_CMD_DEL_MPATH] = "del_mpath",
[NL80211_CMD_SET_BSS] = "set_bss",
[NL80211_CMD_SET_REG] = "set_reg",
[NL80211_CMD_REQ_SET_REG] = "req_set_reg",
[NL80211_CMD_GET_MESH_CONFIG] = "get_mesh_config",
[NL80211_CMD_SET_MESH_CONFIG] = "set_mesh_config",
[NL80211_CMD_SET_MGMT_EXTRA_IE] = "set_mgmt_extra_ie",
[NL80211_CMD_GET_REG] = "get_reg",
[NL80211_CMD_GET_SCAN] = "get_scan",
[NL80211_CMD_TRIGGER_SCAN] = "trigger_scan",
[NL80211_CMD_NEW_SCAN_RESULTS] = "new_scan_results",
[NL80211_CMD_SCAN_ABORTED] = "scan_aborted",
[NL80211_CMD_REG_CHANGE] = "reg_change",
[NL80211_CMD_AUTHENTICATE] = "authenticate",
[NL80211_CMD_ASSOCIATE] = "associate",
[NL80211_CMD_DEAUTHENTICATE] = "deauthenticate",
[NL80211_CMD_DISASSOCIATE] = "disassociate",
[NL80211_CMD_MICHAEL_MIC_FAILURE] = "michael_mic_failure",
[NL80211_CMD_REG_BEACON_HINT] = "reg_beacon_hint",
[NL80211_CMD_JOIN_IBSS] = "join_ibss",
[NL80211_CMD_LEAVE_IBSS] = "leave_ibss",
[NL80211_CMD_TESTMODE] = "testmode",
[NL80211_CMD_CONNECT] = "connect",
[NL80211_CMD_ROAM] = "roam",
[NL80211_CMD_DISCONNECT] = "disconnect",
[NL80211_CMD_SET_WIPHY_NETNS] = "set_wiphy_netns",
[NL80211_CMD_GET_SURVEY] = "get_survey",
[NL80211_CMD_NEW_SURVEY_RESULTS] = "new_survey_results",
[NL80211_CMD_SET_PMKSA] = "set_pmksa",
[NL80211_CMD_DEL_PMKSA] = "del_pmksa",
[NL80211_CMD_FLUSH_PMKSA] = "flush_pmksa",
[NL80211_CMD_REMAIN_ON_CHANNEL] = "remain_on_channel",
[NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL] = "cancel_remain_on_channel",
[NL80211_CMD_SET_TX_BITRATE_MASK] = "set_tx_bitrate_mask",
[NL80211_CMD_REGISTER_FRAME] = "register_frame",
[NL80211_CMD_FRAME] = "frame",
[NL80211_CMD_FRAME_TX_STATUS] = "frame_tx_status",
[NL80211_CMD_SET_POWER_SAVE] = "set_power_save",
[NL80211_CMD_GET_POWER_SAVE] = "get_power_save",
[NL80211_CMD_SET_CQM] = "set_cqm",
[NL80211_CMD_NOTIFY_CQM] = "notify_cqm",
[NL80211_CMD_SET_CHANNEL] = "set_channel",
[NL80211_CMD_SET_WDS_PEER] = "set_wds_peer",
[NL80211_CMD_FRAME_WAIT_CANCEL] = "frame_wait_cancel",
[NL80211_CMD_JOIN_MESH] = "join_mesh",
[NL80211_CMD_LEAVE_MESH] = "leave_mesh",
[NL80211_CMD_UNPROT_DEAUTHENTICATE] = "unprot_deauthenticate",
[NL80211_CMD_UNPROT_DISASSOCIATE] = "unprot_disassociate",
[NL80211_CMD_NEW_PEER_CANDIDATE] = "new_peer_candidate",
[NL80211_CMD_GET_WOWLAN] = "get_wowlan",
[NL80211_CMD_SET_WOWLAN] = "set_wowlan",
[NL80211_CMD_START_SCHED_SCAN] = "start_sched_scan",
[NL80211_CMD_STOP_SCHED_SCAN] = "stop_sched_scan",
[NL80211_CMD_SCHED_SCAN_RESULTS] = "sched_scan_results",
[NL80211_CMD_SCHED_SCAN_STOPPED] = "sched_scan_stopped",
[NL80211_CMD_SET_REKEY_OFFLOAD] = "set_rekey_offload",
[NL80211_CMD_PMKSA_CANDIDATE] = "pmksa_candidate",
[NL80211_CMD_TDLS_OPER] = "tdls_oper",
[NL80211_CMD_TDLS_MGMT] = "tdls_mgmt",
[NL80211_CMD_UNEXPECTED_FRAME] = "unexpected_frame",
[NL80211_CMD_PROBE_CLIENT] = "probe_client",
[NL80211_CMD_REGISTER_BEACONS] = "register_beacons",
[NL80211_CMD_UNEXPECTED_4ADDR_FRAME] = "unexpected_4addr_frame",
[NL80211_CMD_SET_NOACK_MAP] = "set_noack_map",
[NL80211_CMD_CH_SWITCH_NOTIFY] = "ch_switch_notify",
[NL80211_CMD_START_P2P_DEVICE] = "start_p2p_device",
[NL80211_CMD_STOP_P2P_DEVICE] = "stop_p2p_device",
[NL80211_CMD_CONN_FAILED] = "conn_failed",
[NL80211_CMD_SET_MCAST_RATE] = "set_mcast_rate",
[NL80211_CMD_SET_MAC_ACL] = "set_mac_acl",
[NL80211_CMD_RADAR_DETECT] = "radar_detect",
[NL80211_CMD_GET_PROTOCOL_FEATURES] = "get_protocol_features",
[NL80211_CMD_UPDATE_FT_IES] = "update_ft_ies",
[NL80211_CMD_FT_EVENT] = "ft_event",
[NL80211_CMD_CRIT_PROTOCOL_START] = "crit_protocol_start",
[NL80211_CMD_CRIT_PROTOCOL_STOP] = "crit_protocol_stop",
[NL80211_CMD_GET_COALESCE] = "get_coalesce",
[NL80211_CMD_SET_COALESCE] = "set_coalesce",
[NL80211_CMD_CHANNEL_SWITCH] = "channel_switch",
[NL80211_CMD_VENDOR] = "vendor",
[NL80211_CMD_SET_QOS_MAP] = "set_qos_map",
[NL80211_CMD_ADD_TX_TS] = "add_tx_ts",
[NL80211_CMD_DEL_TX_TS] = "del_tx_ts",
[NL80211_CMD_GET_MPP] = "get_mpp",
[NL80211_CMD_JOIN_OCB] = "join_ocb",
[NL80211_CMD_LEAVE_OCB] = "leave_ocb",
[NL80211_CMD_CH_SWITCH_STARTED_NOTIFY] = "ch_switch_started_notify",
[NL80211_CMD_TDLS_CHANNEL_SWITCH] = "tdls_channel_switch",
[NL80211_CMD_TDLS_CANCEL_CHANNEL_SWITCH] = "tdls_cancel_channel_switch",
[NL80211_CMD_WIPHY_REG_CHANGE] = "wiphy_reg_change",
[NL80211_CMD_ABORT_SCAN] = "abort_scan",
[NL80211_CMD_START_NAN] = "start_nan",
[NL80211_CMD_STOP_NAN] = "stop_nan",
[NL80211_CMD_ADD_NAN_FUNCTION] = "add_nan_function",
[NL80211_CMD_DEL_NAN_FUNCTION] = "del_nan_function",
[NL80211_CMD_CHANGE_NAN_CONFIG] = "change_nan_config",
[NL80211_CMD_NAN_MATCH] = "nan_match",
[NL80211_CMD_SET_MULTICAST_TO_UNICAST] = "set_multicast_to_unicast",
[NL80211_CMD_UPDATE_CONNECT_PARAMS] = "update_connect_params",
[NL80211_CMD_SET_PMK] = "set_pmk",
[NL80211_CMD_DEL_PMK] = "del_pmk",
[NL80211_CMD_PORT_AUTHORIZED] = "port_authorized",
[NL80211_CMD_RELOAD_REGDB] = "reload_regdb",
[NL80211_CMD_EXTERNAL_AUTH] = "external_auth",
[NL80211_CMD_STA_OPMODE_CHANGED] = "sta_opmode_changed",
[NL80211_CMD_CONTROL_PORT_FRAME] = "control_port_frame",
[NL80211_CMD_GET_FTM_RESPONDER_STATS] = "get_ftm_responder_stats",
[NL80211_CMD_PEER_MEASUREMENT_START] = "peer_measurement_start",
[NL80211_CMD_PEER_MEASUREMENT_RESULT] = "peer_measurement_result",
[NL80211_CMD_PEER_MEASUREMENT_COMPLETE] = "peer_measurement_complete",
[NL80211_CMD_NOTIFY_RADAR] = "notify_radar",
[NL80211_CMD_UPDATE_OWE_INFO] = "update_owe_info",
[NL80211_CMD_PROBE_MESH_LINK] = "probe_mesh_link",
[NL80211_CMD_SET_TID_CONFIG] = "set_tid_config",
[NL80211_CMD_UNPROT_BEACON] = "unprot_beacon",
[NL80211_CMD_CONTROL_PORT_FRAME_TX_STATUS] = "control_port_frame_tx_status",
[NL80211_CMD_SET_SAR_SPECS] = "set_sar_specs",
[NL80211_CMD_OBSS_COLOR_COLLISION] = "obss_color_collision",
[NL80211_CMD_COLOR_CHANGE_REQUEST] = "color_change_request",
[NL80211_CMD_COLOR_CHANGE_STARTED] = "color_change_started",
[NL80211_CMD_COLOR_CHANGE_ABORTED] = "color_change_aborted",
[NL80211_CMD_COLOR_CHANGE_COMPLETED] = "color_change_completed",
};
DEFINE_STRING_TABLE_LOOKUP_TO_STRING(nl80211_cmd, int);

View File

@ -3,13 +3,9 @@
#pragma once
#include <linux/nl80211.h>
#include <net/ethernet.h>
#include "sd-netlink.h"
#include "ether-addr-util.h"
int wifi_get_interface(sd_netlink *genl, int ifindex, enum nl80211_iftype *ret_iftype, char **ret_ssid);
int wifi_get_station(sd_netlink *genl, int ifindex, struct ether_addr *ret_bssid);
const char *nl80211_iftype_to_string(enum nl80211_iftype iftype) _const_;
const char *nl80211_cmd_to_string(int cmd) _const_;
int wifi_get_interface(sd_netlink *genl, int ifindex, enum nl80211_iftype *iftype, char **ssid);
int wifi_get_station(sd_netlink *genl, int ifindex, struct ether_addr *bssid);

View File

@ -39,11 +39,11 @@ int sd_dhcp6_lease_get_pd(sd_dhcp6_lease *lease, struct in6_addr *prefix,
uint32_t *lifetime_preferred,
uint32_t *lifetime_valid);
int sd_dhcp6_lease_get_dns(sd_dhcp6_lease *lease, const struct in6_addr **ret);
int sd_dhcp6_lease_get_domains(sd_dhcp6_lease *lease, char ***ret);
int sd_dhcp6_lease_get_ntp_addrs(sd_dhcp6_lease *lease, const struct in6_addr **ret);
int sd_dhcp6_lease_get_ntp_fqdn(sd_dhcp6_lease *lease, char ***ret);
int sd_dhcp6_lease_get_fqdn(sd_dhcp6_lease *lease, const char **ret);
int sd_dhcp6_lease_get_dns(sd_dhcp6_lease *lease, const struct in6_addr **addrs);
int sd_dhcp6_lease_get_domains(sd_dhcp6_lease *lease, char ***domains);
int sd_dhcp6_lease_get_ntp_addrs(sd_dhcp6_lease *lease, const struct in6_addr **addrs);
int sd_dhcp6_lease_get_ntp_fqdn(sd_dhcp6_lease *lease, char ***ntp_fqdn);
int sd_dhcp6_lease_get_fqdn(sd_dhcp6_lease *lease, const char **fqdn);
sd_dhcp6_lease *sd_dhcp6_lease_ref(sd_dhcp6_lease *lease);
sd_dhcp6_lease *sd_dhcp6_lease_unref(sd_dhcp6_lease *lease);

View File

@ -95,7 +95,6 @@ int sd_netlink_message_close_container(sd_netlink_message *m);
int sd_netlink_message_read(sd_netlink_message *m, unsigned short type, size_t size, void *data);
int sd_netlink_message_read_data(sd_netlink_message *m, unsigned short type, size_t *ret_size, void **ret_data);
int sd_netlink_message_read_data_suffix0(sd_netlink_message *m, unsigned short type, size_t *ret_size, void **ret_data);
int sd_netlink_message_read_string_strdup(sd_netlink_message *m, unsigned short type, char **data);
int sd_netlink_message_read_string(sd_netlink_message *m, unsigned short type, const char **data);
int sd_netlink_message_read_strv(sd_netlink_message *m, unsigned short container_type, unsigned short type_id, char ***ret);

View File

@ -390,28 +390,6 @@ static void test_strv_split_full(void) {
assert_se(streq_ptr(l[5], NULL));
}
static void test_strv_split_and_extend_full(void) {
_cleanup_strv_free_ char **l = NULL;
const char *str1 = ":foo\\:bar:";
const char *str2 = "waldo::::::baz";
int r;
log_info("/* %s */", __func__);
r = strv_split_and_extend(&l, "", ":", false);
assert_se(r == (int) strv_length(l));
r = strv_split_and_extend_full(&l, str1, ":", false, EXTRACT_DONT_COALESCE_SEPARATORS);
assert_se(r == (int) strv_length(l));
assert_se(streq_ptr(l[0], ""));
assert_se(streq_ptr(l[1], "foo:bar"));
assert_se(streq_ptr(l[2], ""));
r = strv_split_and_extend_full(&l, str2, ":", false, 0);
assert_se(r == (int) strv_length(l));
assert_se(streq_ptr(l[3], "waldo"));
assert_se(streq_ptr(l[4], "baz"));
assert_se(streq_ptr(l[5], NULL));
}
static void test_strv_split_colon_pairs(void) {
_cleanup_strv_free_ char **l = NULL;
const char *str = "one:two three four:five six seven:eight\\:nine ten\\:eleven\\\\",
@ -1050,7 +1028,6 @@ int main(int argc, char *argv[]) {
test_strv_split();
test_strv_split_empty();
test_strv_split_full();
test_strv_split_and_extend_full();
test_strv_split_colon_pairs();
test_strv_split_newlines();
test_strv_split_newlines_full();

View File

@ -18,7 +18,6 @@
#include "dirent-util.h"
#include "fd-util.h"
#include "sort-util.h"
#include "static-destruct.h"
#include "string-table.h"
#include "string-util.h"
#include "udev-util.h"
@ -39,10 +38,8 @@ typedef enum QueryType {
QUERY_ALL,
} QueryType;
static char **arg_properties = NULL;
static bool arg_root = false;
static bool arg_export = false;
static bool arg_value = false;
static const char *arg_export_prefix = NULL;
static usec_t arg_wait_for_initialization_timeout = 0;
@ -63,8 +60,6 @@ typedef struct SysAttr {
const char *value;
} SysAttr;
STATIC_DESTRUCTOR_REGISTER(arg_properties, strv_freep);
static int sysattr_compare(const SysAttr *a, const SysAttr *b) {
return strcmp(a->name, b->name);
}
@ -321,18 +316,11 @@ static int query_device(QueryType query, sd_device* device) {
case QUERY_PROPERTY: {
const char *key, *value;
FOREACH_DEVICE_PROPERTY(device, key, value) {
if (arg_properties && !strv_contains(arg_properties, key))
continue;
FOREACH_DEVICE_PROPERTY(device, key, value)
if (arg_export)
printf("%s%s='%s'\n", strempty(arg_export_prefix), key, value);
else if (arg_value)
printf("%s\n", value);
else
printf("%s=%s\n", key, value);
}
return 0;
}
@ -355,8 +343,6 @@ static int help(void) {
" path sysfs device path\n"
" property The device properties\n"
" all All values\n"
" --property=NAME Show only properties by this name\n"
" --value When showing properties, print only their values\n"
" -p --path=SYSPATH sysfs device path used for query or attribute walk\n"
" -n --name=NAME Node or symlink name used for query or attribute walk\n"
" -r --root Prepend dev directory to path names\n"
@ -379,27 +365,20 @@ int info_main(int argc, char *argv[], void *userdata) {
_cleanup_free_ char *name = NULL;
int c, r;
enum {
ARG_PROPERTY = 0x100,
ARG_VALUE,
};
static const struct option options[] = {
{ "attribute-walk", no_argument, NULL, 'a' },
{ "cleanup-db", no_argument, NULL, 'c' },
{ "device-id-of-file", required_argument, NULL, 'd' },
{ "export", no_argument, NULL, 'x' },
{ "export-db", no_argument, NULL, 'e' },
{ "export-prefix", required_argument, NULL, 'P' },
{ "help", no_argument, NULL, 'h' },
{ "name", required_argument, NULL, 'n' },
{ "path", required_argument, NULL, 'p' },
{ "property", required_argument, NULL, ARG_PROPERTY },
{ "query", required_argument, NULL, 'q' },
{ "root", no_argument, NULL, 'r' },
{ "value", no_argument, NULL, ARG_VALUE },
{ "version", no_argument, NULL, 'V' },
{ "wait-for-initialization", optional_argument, NULL, 'w' },
{ "name", required_argument, NULL, 'n' },
{ "path", required_argument, NULL, 'p' },
{ "query", required_argument, NULL, 'q' },
{ "attribute-walk", no_argument, NULL, 'a' },
{ "cleanup-db", no_argument, NULL, 'c' },
{ "export-db", no_argument, NULL, 'e' },
{ "root", no_argument, NULL, 'r' },
{ "device-id-of-file", required_argument, NULL, 'd' },
{ "export", no_argument, NULL, 'x' },
{ "export-prefix", required_argument, NULL, 'P' },
{ "wait-for-initialization", optional_argument, NULL, 'w' },
{ "version", no_argument, NULL, 'V' },
{ "help", no_argument, NULL, 'h' },
{}
};
@ -408,22 +387,6 @@ int info_main(int argc, char *argv[], void *userdata) {
while ((c = getopt_long(argc, argv, "aced:n:p:q:rxP:w::Vh", options, NULL)) >= 0)
switch (c) {
case ARG_PROPERTY:
/* Make sure that if the empty property list was specified, we won't show any
properties. */
if (isempty(optarg) && !arg_properties) {
arg_properties = new0(char*, 1);
if (!arg_properties)
return log_oom();
} else {
r = strv_split_and_extend(&arg_properties, optarg, ",", true);
if (r < 0)
return log_oom();
}
break;
case ARG_VALUE:
arg_value = true;
break;
case 'n':
case 'p': {
const char *prefix = c == 'n' ? "/dev/" : "/sys/";
@ -515,10 +478,6 @@ int info_main(int argc, char *argv[], void *userdata) {
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Only one device may be specified with -a/--attribute-walk");
if (arg_export && arg_value)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"-x/--export or -P/--export-prefix cannot be used with --value");
char **p;
STRV_FOREACH(p, devices) {
_cleanup_(sd_device_unrefp) sd_device *device = NULL;

View File

@ -11,8 +11,6 @@ set -e
TEST_DESCRIPTION="systemd-udev storage tests"
IMAGE_NAME="default"
TEST_NO_NSPAWN=1
# Save only journals of failing test cases by default (to conserve space)
TEST_SAVE_JOURNAL="${TEST_SAVE_JOURNAL:-fail}"
QEMU_TIMEOUT="${QEMU_TIMEOUT:-600}"
# shellcheck source=test/test-functions
@ -30,20 +28,14 @@ _host_has_feature() {(
set -e
case "${1:?}" in
btrfs)
modprobe -nv btrfs && command -v mkfs.btrfs && command -v btrfs || return $?
;;
iscsi)
# Client/initiator (Open-iSCSI)
command -v iscsiadm && command -v iscsid || return $?
# Server/target (TGT)
command -v tgtadm && command -v tgtd || return $?
multipath)
command -v multipath && command -v multipathd || return $?
;;
lvm)
command -v lvm || return $?
;;
multipath)
command -v multipath && command -v multipathd || return $?
btrfs)
modprobe -nv btrfs && command -v mkfs.btrfs && command -v btrfs || return $?
;;
*)
echo >&2 "ERROR: Unknown feature '$1'"
@ -62,7 +54,6 @@ test_append_files() {(
# checked for here
local -A features=(
[btrfs]=install_btrfs
[iscsi]=install_iscsi
[lvm]=install_lvm
[multipath]=install_multipath
)
@ -369,35 +360,6 @@ testcase_btrfs_basic() {
rm -f "${TESTDIR:?}"/btrfsbasic*.img
}
testcase_iscsi_lvm() {
if ! _host_has_feature "iscsi" || ! _host_has_feature "lvm"; then
echo "Missing iSCSI client/server tools (Open-iSCSI/TGT) or LVM utilities, skipping the test..."
return 77
fi
local qemu_opts=("-device ahci,id=ahci0")
local diskpath i size
for i in {0..3}; do
diskpath="${TESTDIR:?}/iscsibasic${i}.img"
# Make the first disk larger for multi-partition tests
[[ $i -eq 0 ]] && size=150 || size=64
# Make the first disk larger for multi-partition tests
dd if=/dev/zero of="$diskpath" bs=1M count="$size"
qemu_opts+=(
"-device ide-hd,bus=ahci0.$i,drive=drive$i,model=foobar,serial=deadbeefiscsi$i"
"-drive format=raw,cache=unsafe,file=$diskpath,if=none,id=drive$i"
)
done
KERNEL_APPEND="systemd.setenv=TEST_FUNCTION_NAME=${FUNCNAME[0]} ${USER_KERNEL_APPEND:-}"
QEMU_OPTIONS="${qemu_opts[*]} ${USER_QEMU_OPTIONS:-}"
test_run_one "${1:?}" || return $?
rm -f "${TESTDIR:?}"/iscsibasic*.img
}
# Allow overriding which tests should be run from the "outside", useful for manual
# testing (make -C test/... TESTCASES="testcase1 testcase2")
if [[ -v "TESTCASES" && -n "$TESTCASES" ]]; then

View File

@ -959,45 +959,6 @@ install_btrfs() {
inst_rules 64-btrfs-dm.rules
}
install_iscsi() {
# Install both client and server side stuff by default
local inst="${1:-}"
local file
# Install client-side stuff ("initiator" in iSCSI jargon) - Open-iSCSI in this case
# (open-iscsi on Debian, iscsi-initiator-utils on Fedora, etc.)
if [[ -z "$inst" || "$inst" =~ (client|initiator) ]]; then
image_install iscsi-iname iscsiadm iscsid iscsistart
image_install -o "${ROOTLIBDIR:?}"/system/iscsi-{init,onboot,shutdown}.service
image_install "${ROOTLIBDIR:?}"/system/iscsid.{service,socket}
image_install "${ROOTLIBDIR:?}"/system/iscsi.service
mkdir -p "${initdir:?}"/var/lib/iscsi/{ifaces,isns,nodes,send_targets,slp,static}
mkdir -p "${initdir:?}/etc/iscsi"
echo "iscsid.startup = /bin/systemctl start iscsid.socket" >"${initdir:?}/etc/iscsi/iscsid.conf"
inst_simple "/etc/iscsi/initiatorname.iscsi"
fi
# Install server-side stuff ("target" in iSCSI jargon) - TGT in this case
# (tgt on Debian, scsi-target-utils on Fedora, etc.)
if [[ -z "$inst" || "$inst" =~ (server|target) ]]; then
image_install tgt-admin tgt-setup-lun tgtadm tgtd tgtimg
image_install -o /etc/sysconfig/tgtd
image_install "${ROOTLIBDIR:?}"/system/tgtd.service
mkdir -p "${initdir:?}/etc/tgt"
touch "${initdir:?}"/etc/tgt/{tgtd,targets}.conf
# Install perl modules required by tgt-admin
#
# Forgive me father for I have sinned. The monstrosity below appends
# a perl snippet to the `tgt-admin` perl script on the fly, which
# dumps a list of files (perl modules) required by `tgt-admin` at
# the runtime plus any DSOs loaded via DynaLoader. This list is then
# passed to `inst_simple` which installs the necessary files into the image
while read -r file; do
inst_simple "$file"
done < <(perl -- <(cat $(command -v tgt-admin) <(echo -e 'use DynaLoader; print map { "$_\n" } values %INC; print join("\n", @DynaLoader::dl_shared_objects)')) -p | awk '/^\// { print $1 }')
fi
}
install_compiled_systemd() {
dinfo "Install compiled systemd"
@ -2358,8 +2319,6 @@ inst() {
for fun in inst_symlink inst_script inst_binary inst_simple; do
"$fun" "$@" && return 0
done
dwarn "Failed to install '$1'"
return 1
}

View File

@ -40,57 +40,6 @@ helper_check_device_symlinks() {(
done < <(find "${paths[@]}" -type l)
)}
# Wait for a specific device link to appear
# Arguments:
# $1 - device path
# $2 - number of retries (default: 10)
helper_wait_for_dev() {
local dev="${1:?}"
local ntries="${2:-10}"
local i
for ((i = 0; i < ntries; i++)); do
test ! -e "$dev" || return 0
sleep .2
done
return 1
}
# Wait for the lvm2-pvscan@.service of a specific device to finish
# Arguments:
# $1 - device path
# $2 - number of retries (default: 10)
helper_wait_for_pvscan() {
local dev="${1:?}"
local ntries="${2:-10}"
local MAJOR MINOR pvscan_svc real_dev
# Sanity check we got a valid block device (or a symlink to it)
real_dev="$(readlink -f "$dev")"
if [[ ! -b "$real_dev" ]]; then
echo >&2 "ERROR: '$dev ($real_dev) is not a valid block device'"
return 1
fi
# Get major and minor numbers from the udev database
# (udevadm returns MAJOR= and MINOR= expressions, so let's pull them into
# the current environment via `source` for easier parsing)
source <(udevadm info -q property "$real_dev" | grep -E "(MAJOR|MINOR)=")
# Sanity check if we got correct major and minor numbers
test -e "/sys/dev/block/$MAJOR:$MINOR/"
# Wait n_tries*0.5 seconds until the respective lvm2-pvscan service becomes
# active (i.e. it got executed and finished)
pvscan_svc="lvm2-pvscan@$MAJOR:$MINOR.service"
for ((i = 0; i < ntries; i++)); do
! systemctl -q is-active "$pvscan_svc" || return 0
sleep .5
done
return 1
}
testcase_megasas2_basic() {
lsblk -S
[[ "$(lsblk --scsi --noheadings | wc -l)" -ge 128 ]]
@ -448,144 +397,6 @@ EOF
udevadm settle
}
testcase_iscsi_lvm() {
local dev i label link lun_id mpoint target_name uuid
local target_ip="127.0.0.1"
local target_port="3260"
local vgroup="iscsi_lvm$RANDOM"
local expected_symlinks=()
local devices=(
/dev/disk/by-id/ata-foobar_deadbeefiscsi{0..3}
)
ls -l "${devices[@]}"
# Start the target daemon
systemctl start tgtd
systemctl status tgtd
echo "iSCSI LUNs backed by devices"
# See RFC3721 and RFC7143
target_name="iqn.2021-09.com.example:iscsi.test"
# Initialize a new iSCSI target <$target_name> consisting of 4 LUNs, each
# backed by a device
tgtadm --lld iscsi --op new --mode target --tid=1 --targetname "$target_name"
for ((i = 0; i < ${#devices[@]}; i++)); do
# lun-0 is reserved by iSCSI
lun_id="$((i + 1))"
tgtadm --lld iscsi --op new --mode logicalunit --tid 1 --lun "$lun_id" -b "${devices[$i]}"
tgtadm --lld iscsi --op update --mode logicalunit --tid 1 --lun "$lun_id"
expected_symlinks+=(
"/dev/disk/by-path/ip-$target_ip:$target_port-iscsi-$target_name-lun-$lun_id"
)
done
tgtadm --lld iscsi --op bind --mode target --tid 1 -I ALL
# Configure the iSCSI initiator
iscsiadm --mode discoverydb --type sendtargets --portal "$target_ip" --discover
iscsiadm --mode node --targetname "$target_name" --portal "$target_ip:$target_port" --login
udevadm settle
# Check if all device symlinks are valid and if all expected device symlinks exist
for link in "${expected_symlinks[@]}"; do
# We need to do some active waiting anyway, as it may take kernel a bit
# to attach the newly connected SCSI devices
helper_wait_for_dev "$link"
test -e "$link"
done
udevadm settle
helper_check_device_symlinks
# Cleanup
iscsiadm --mode node --targetname "$target_name" --portal "$target_ip:$target_port" --logout
tgtadm --lld iscsi --op delete --mode target --tid=1
echo "iSCSI LUNs backed by files + LVM"
# Note: we use files here to "trick" LVM the disks are indeed on a different
# host, so it doesn't automagically detect another path to the backing
# device once we disconnect the iSCSI devices
target_name="iqn.2021-09.com.example:iscsi.lvm.test"
mpoint="$(mktemp -d /iscsi_storeXXX)"
expected_symlinks=()
# Use the first device as it's configured with larger capacity
mkfs.ext4 -L iscsi_store "${devices[0]}"
udevadm settle
mount "${devices[0]}" "$mpoint"
for i in {1..4}; do
dd if=/dev/zero of="$mpoint/lun$i.img" bs=1M count=32
done
# Initialize a new iSCSI target <$target_name> consisting of 4 LUNs, each
# backed by a file
tgtadm --lld iscsi --op new --mode target --tid=2 --targetname "$target_name"
# lun-0 is reserved by iSCSI
for i in {1..4}; do
tgtadm --lld iscsi --op new --mode logicalunit --tid 2 --lun "$i" -b "$mpoint/lun$i.img"
tgtadm --lld iscsi --op update --mode logicalunit --tid 2 --lun "$i"
expected_symlinks+=(
"/dev/disk/by-path/ip-$target_ip:$target_port-iscsi-$target_name-lun-$i"
)
done
tgtadm --lld iscsi --op bind --mode target --tid 2 -I ALL
# Configure the iSCSI initiator
iscsiadm --mode discoverydb --type sendtargets --portal "$target_ip" --discover
iscsiadm --mode node --targetname "$target_name" --portal "$target_ip:$target_port" --login
udevadm settle
# Check if all device symlinks are valid and if all expected device symlinks exist
for link in "${expected_symlinks[@]}"; do
# We need to do some active waiting anyway, as it may take kernel a bit
# to attach the newly connected SCSI devices
helper_wait_for_dev "$link"
test -e "$link"
done
udevadm settle
helper_check_device_symlinks
# Add all iSCSI devices into a LVM volume group, create two logical volumes,
# and check if necessary symlinks exist (and are valid)
lvm pvcreate -y "${expected_symlinks[@]}"
lvm pvs
lvm vgcreate "$vgroup" -y "${expected_symlinks[@]}"
lvm vgs
lvm vgchange -ay "$vgroup"
lvm lvcreate -y -L 4M "$vgroup" -n mypart1
lvm lvcreate -y -L 8M "$vgroup" -n mypart2
lvm lvs
udevadm settle
test -e "/dev/$vgroup/mypart1"
test -e "/dev/$vgroup/mypart2"
mkfs.ext4 -L mylvpart1 "/dev/$vgroup/mypart1"
udevadm settle
test -e "/dev/disk/by-label/mylvpart1"
helper_check_device_symlinks "/dev/disk" "/dev/$vgroup"
# Disconnect the iSCSI devices and check all the symlinks
iscsiadm --mode node --targetname "$target_name" --portal "$target_ip:$target_port" --logout
# "Reset" the DM state, since we yanked the backing storage from under the LVM,
# so the currently active VGs/LVs are invalid
dmsetup remove_all --deferred
udevadm settle
# The LVM and iSCSI related symlinks should be gone
test ! -e "/dev/$vgroup"
test ! -e "/dev/disk/by-label/mylvpart1"
for link in "${expected_symlinks[@]}"; do
test ! -e "$link"
done
helper_check_device_symlinks "/dev/disk"
# Reconnect the iSCSI devices and check if everything get detected correctly
iscsiadm --mode discoverydb --type sendtargets --portal "$target_ip" --discover
iscsiadm --mode node --targetname "$target_name" --portal "$target_ip:$target_port" --login
udevadm settle
for link in "${expected_symlinks[@]}"; do
helper_wait_for_dev "$link"
helper_wait_for_pvscan "$link"
test -e "$link"
done
udevadm settle
test -e "/dev/$vgroup/mypart1"
test -e "/dev/$vgroup/mypart2"
test -e "/dev/disk/by-label/mylvpart1"
helper_check_device_symlinks "/dev/disk" "/dev/$vgroup"
# Cleanup
iscsiadm --mode node --targetname "$target_name" --portal "$target_ip:$target_port" --logout
tgtadm --lld iscsi --op delete --mode target --tid=2
umount "$mpoint"
rm -rf "$mpoint"
}
: >/failed
udevadm settle

View File

@ -68,12 +68,6 @@ cat <<EOF >/tmp/testfile.service
ExecStart = echo hello
EOF
# Prevent regression from #13380 and #20859 where we can't verify hidden files
cp /tmp/testfile.service /tmp/.testfile.service
systemd-analyze verify /tmp/.testfile.service
rm /tmp/.testfile.service
# Zero exit status since the value used for comparison determine exposure to security threats is by default 100
systemd-analyze security --offline=true /tmp/testfile.service