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.
721956f3e9
...
41a978fdb1
7
.github/workflows/unit_tests.sh
vendored
7
.github/workflows/unit_tests.sh
vendored
@ -6,6 +6,7 @@ ADDITIONAL_DEPS=(
|
|||||||
clang
|
clang
|
||||||
expect
|
expect
|
||||||
fdisk
|
fdisk
|
||||||
|
iproute2
|
||||||
jekyll
|
jekyll
|
||||||
lcov
|
lcov
|
||||||
libfdisk-dev
|
libfdisk-dev
|
||||||
@ -19,6 +20,7 @@ ADDITIONAL_DEPS=(
|
|||||||
perl
|
perl
|
||||||
python3-libevdev
|
python3-libevdev
|
||||||
python3-pyparsing
|
python3-pyparsing
|
||||||
|
util-linux
|
||||||
zstd
|
zstd
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -53,7 +55,8 @@ for phase in "${PHASES[@]}"; do
|
|||||||
fi
|
fi
|
||||||
meson --werror -Dtests=unsafe -Dslow-tests=true -Dfuzz-tests=true "${MESON_ARGS[@]}" build
|
meson --werror -Dtests=unsafe -Dslow-tests=true -Dfuzz-tests=true "${MESON_ARGS[@]}" build
|
||||||
ninja -C build -v
|
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
|
if [[ "$phase" = "RUN_GCC" ]]; then
|
||||||
ninja -C build coverage
|
ninja -C build coverage
|
||||||
fi
|
fi
|
||||||
@ -85,7 +88,7 @@ for phase in "${PHASES[@]}"; do
|
|||||||
# during debugging, wonderful), so let's at least keep a workaround
|
# during debugging, wonderful), so let's at least keep a workaround
|
||||||
# here to make the builds stable for the time being.
|
# here to make the builds stable for the time being.
|
||||||
(set +x; while :; do echo -ne "\n[WATCHDOG] $(date)\n"; sleep 30; done) &
|
(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)
|
CLEANUP)
|
||||||
info "Cleanup phase"
|
info "Cleanup phase"
|
||||||
|
|||||||
7
.github/workflows/unit_tests.yml
vendored
7
.github/workflows/unit_tests.yml
vendored
@ -3,10 +3,6 @@
|
|||||||
#
|
#
|
||||||
name: Unit tests
|
name: Unit tests
|
||||||
on:
|
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:
|
pull_request:
|
||||||
branches:
|
branches:
|
||||||
- main
|
- main
|
||||||
@ -21,13 +17,10 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- name: Repository checkout
|
- name: Repository checkout
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
if: github.event_name == 'pull_request' || matrix.run_phase == 'GCC'
|
|
||||||
- name: Install build dependencies
|
- name: Install build dependencies
|
||||||
run: sudo -E .github/workflows/unit_tests.sh SETUP
|
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 }})
|
- name: Build & test (${{ matrix.run_phase }})
|
||||||
run: sudo -E .github/workflows/unit_tests.sh RUN_${{ 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
|
- name: Coveralls
|
||||||
if: matrix.run_phase == 'GCC' && github.repository == 'systemd/systemd'
|
if: matrix.run_phase == 'GCC' && github.repository == 'systemd/systemd'
|
||||||
uses: coverallsapp/github-action@master
|
uses: coverallsapp/github-action@master
|
||||||
|
|||||||
5
NEWS
5
NEWS
@ -518,11 +518,6 @@ CHANGES WITH 249:
|
|||||||
distribution does not install it yet, it might make sense to change
|
distribution does not install it yet, it might make sense to change
|
||||||
that.
|
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,
|
Contributions from: Aakash Singh, adrian5, Albert Brox,
|
||||||
Alexander Sverdlin, Alexander Tsoy, Alexey Rubtsov, alexlzhu,
|
Alexander Sverdlin, Alexander Tsoy, Alexey Rubtsov, alexlzhu,
|
||||||
Allen Webb, Alvin Šipraga, Alyssa Ross, Anders Wenhaug,
|
Allen Webb, Alvin Šipraga, Alyssa Ross, Anders Wenhaug,
|
||||||
|
|||||||
@ -494,6 +494,9 @@ evdev:input:b0003v0458p0708*
|
|||||||
# Hewlett Packard
|
# 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*:svnHewlett-Packard*:pn*:*
|
||||||
evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHP*:pn*:*
|
evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHP*:pn*:*
|
||||||
KEYBOARD_KEY_81=fn_esc
|
KEYBOARD_KEY_81=fn_esc
|
||||||
@ -557,6 +560,9 @@ evdev:atkbd:dmi:bvn*:bvr*:svnHP*:pnHPElitex21013G3:*
|
|||||||
KEYBOARD_KEY_92=brightnessdown
|
KEYBOARD_KEY_92=brightnessdown
|
||||||
KEYBOARD_KEY_97=brightnessup
|
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
|
# Elitebook
|
||||||
evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pn*Compaq*:*
|
evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pn*Compaq*:*
|
||||||
evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pn*EliteBook*:*
|
evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pn*EliteBook*:*
|
||||||
|
|||||||
@ -230,9 +230,8 @@ sensor:modalias:acpi:BOSC0200*:dmi:*:svnChuwi*:pnHi13:*
|
|||||||
# Chuwi HiBook does not have its product name filled, so we
|
# Chuwi HiBook does not have its product name filled, so we
|
||||||
# match the entire dmi-alias, assuming that the use of a BOSC0200 +
|
# match the entire dmi-alias, assuming that the use of a BOSC0200 +
|
||||||
# bios-version + bios-date combo is unique
|
# 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/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/28/2016:*svnDefaultstring:pnDefaultstring:pvrDefaultstring:rvnHampoo:rnCherryTrailCR:rvrDefaultstring:cvnDefaultstring:ct3:cvrDefaultstring:*
|
|
||||||
ACCEL_MOUNT_MATRIX=1, 0, 0; 0, -1, 0; 0, 0, 1
|
ACCEL_MOUNT_MATRIX=1, 0, 0; 0, -1, 0; 0, 0, 1
|
||||||
|
|
||||||
# Chuwi HiBook Pro (CWI526)
|
# Chuwi HiBook Pro (CWI526)
|
||||||
@ -242,8 +241,7 @@ sensor:modalias:acpi:BOSC0200*:dmi:*:svnHampoo*:pnP1D6_C109K:*
|
|||||||
# Chuwi CoreBook
|
# Chuwi CoreBook
|
||||||
# Chuwi CoreBook does not have its product name filled, so we
|
# Chuwi CoreBook does not have its product name filled, so we
|
||||||
# match the entire dmi-alias
|
# 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
|
ACCEL_MOUNT_MATRIX=-1, 0, 0; 0, 1, 0; 0, 0, 1
|
||||||
|
|
||||||
# Chuwi SurBook Mini (CWI540)
|
# 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
|
# 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
|
# "Default string". So combined with the sensor modalias and BIOS date this
|
||||||
# should be unique enough to identify the GPDwin
|
# 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: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: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/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: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: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: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:bd05/25/2017:*svnDefaultstring:pnDefaultstring:pvrDefaultstring:rvnAMICorporation:rnDefaultstring:rvrDefaultstring:cvnDefaultstring:ct3:cvrDefaultstring:*
|
|
||||||
ACCEL_LOCATION=base
|
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
|
ACCEL_MOUNT_MATRIX=0, -1, 0; -1, 0, 0; 0, 0, 1
|
||||||
|
|
||||||
# Onda v975w, generic DMI strings, match entire dmi modalias inc. bios-date
|
# 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
|
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
|
# One-netbook OneMix 2s
|
||||||
# OneMix 2s has no product name filled, matching entire dmi-alias
|
# 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:br5.12:svnDefaultstring:pnDefaultstring:pvrDefaultstring:rvnDefaultstring:rnDefaultstring:rvrDefaultstring:cvnDefaultstring:ct3:cvrDefaultstring:*
|
||||||
sensor:modalias:acpi:BOSC0200*:dmi:bvnAmericanMegatrendsInc.:bvr5.12:bd10/26/2018:*svnDefaultstring:pnDefaultstring:pvrDefaultstring:rvnDefaultstring:rnDefaultstring:rvrDefaultstring:cvnDefaultstring:ct3:cvrDefaultstring:*
|
|
||||||
ACCEL_MOUNT_MATRIX=0, 1, 0; 1, 0, 0; 0, 0, 1
|
ACCEL_MOUNT_MATRIX=0, 1, 0; 1, 0, 0; 0, 0, 1
|
||||||
|
|
||||||
# One-netbook OneMix 3 Pro
|
# One-netbook OneMix 3 Pro
|
||||||
@ -727,8 +722,7 @@ sensor:modalias:acpi:BOSC0200*:dmi:*svnONE-NETBOOKTECHNOLOGYCO*:pnOne-Mix3Pro:*
|
|||||||
|
|
||||||
# One-netbook OneMix 3s
|
# One-netbook OneMix 3s
|
||||||
# OneMix 3s has no product name filled, matching entire dmi-alias
|
# 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:br5.12:svnDefaultstring:pnDefaultstring:pvrDefaultstring:rvnDefaultstring:rnDefaultstring:rvrDefaultstring:cvnDefaultstring:ct3:cvrDefaultstring:*
|
||||||
sensor:modalias:acpi:BOSC0200*:dmi:bvnAmericanMegatrendsInc.:bvr5.12:bd07/17/2019:*svnDefaultstring:pnDefaultstring:pvrDefaultstring:rvnDefaultstring:rnDefaultstring:rvrDefaultstring:cvnDefaultstring:ct3:cvrDefaultstring:*
|
|
||||||
ACCEL_MOUNT_MATRIX=-1, 0, 0; 0, 1, 0; 0, 0, 1
|
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
|
# 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 +
|
# match the entire dmi-alias, assuming that the use of a BMA250E +
|
||||||
# bios-version + bios-date combo is unique
|
# 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.: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.: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
|
ACCEL_MOUNT_MATRIX=0, 1, 0; 1, 0, 0; 0, 0, 1
|
||||||
|
|
||||||
# Point of View TAB-P1005W-232 (v2.0)
|
# 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
|
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
|
# 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
|
ACCEL_MOUNT_MATRIX=0, 1, 0; 1, 0, 0; 0, 0, 1
|
||||||
|
|
||||||
# Teclast X98 Plus II
|
# 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
|
# 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
|
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
|
# The Winpad A15 does not have its product name filled, so we
|
||||||
# match the entire dmi-alias, assuming that the use of a SMO8500 +
|
# match the entire dmi-alias, assuming that the use of a SMO8500 +
|
||||||
# bios-version + bios-date combo is unique
|
# 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:br5.6: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:*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
|
ACCEL_MOUNT_MATRIX=0, -1, 0; 1, 0, 0; 0, 0, -1
|
||||||
|
|
||||||
#########################################
|
#########################################
|
||||||
|
|||||||
@ -1711,7 +1711,7 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
|
|||||||
readonly s OnFailureJobMode = '...';
|
readonly s OnFailureJobMode = '...';
|
||||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||||
readonly b IgnoreOnIsolate = ...;
|
readonly b IgnoreOnIsolate = ...;
|
||||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||||
readonly b NeedDaemonReload = ...;
|
readonly b NeedDaemonReload = ...;
|
||||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
|
||||||
readonly as Markers = ['...', ...];
|
readonly as Markers = ['...', ...];
|
||||||
|
|||||||
@ -791,14 +791,6 @@
|
|||||||
default will be used.</para>
|
default will be used.</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</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>
|
</variablelist>
|
||||||
</refsect1>
|
</refsect1>
|
||||||
|
|
||||||
@ -875,6 +867,14 @@
|
|||||||
<para>Accepts the same key as in [VXLAN] section.</para>
|
<para>Accepts the same key as in [VXLAN] section.</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</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>
|
</variablelist>
|
||||||
</refsect1>
|
</refsect1>
|
||||||
|
|
||||||
|
|||||||
@ -98,24 +98,6 @@
|
|||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</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>
|
<varlistentry>
|
||||||
<term><option>-p</option></term>
|
<term><option>-p</option></term>
|
||||||
<term><option>--path=<replaceable>DEVPATH</replaceable></option></term>
|
<term><option>--path=<replaceable>DEVPATH</replaceable></option></term>
|
||||||
|
|||||||
@ -49,8 +49,8 @@ _udevadm() {
|
|||||||
[COMMON]='-h --help -V --version'
|
[COMMON]='-h --help -V --version'
|
||||||
[DEBUG]='-d --debug'
|
[DEBUG]='-d --debug'
|
||||||
[INFO_STANDALONE]='-r --root -a --attribute-walk -x --export -e --export-db -c --cleanup-db
|
[INFO_STANDALONE]='-r --root -a --attribute-walk -x --export -e --export-db -c --cleanup-db
|
||||||
-w --wait-for-initialization --value'
|
-w --wait-for-initialization'
|
||||||
[INFO_ARG]='-q --query -p --path -n --name -P --export-prefix -d --device-id-of-file --property'
|
[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_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
|
[TRIGGER_ARG]='-t --type -c --action -s --subsystem-match -S --subsystem-nomatch
|
||||||
-a --attr-match -A --attr-nomatch -p --property-match
|
-a --attr-match -A --attr-nomatch -p --property-match
|
||||||
|
|||||||
@ -13,9 +13,7 @@ _udevadm_info(){
|
|||||||
'--export-prefix=[Add a prefix to the key name of exported values.]:prefix' \
|
'--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' \
|
'--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.]' \
|
'--export-db[Export the content of the udev database.]' \
|
||||||
'--cleanup-db[Cleanup the udev database.]' \
|
'--cleanup-db[Cleanup the udev database.]'
|
||||||
'--value[When showing properties, print only their values.]' \
|
|
||||||
'--property=[Show only properties by this name.]'
|
|
||||||
}
|
}
|
||||||
|
|
||||||
(( $+functions[_udevadm_trigger] )) ||
|
(( $+functions[_udevadm_trigger] )) ||
|
||||||
|
|||||||
@ -1185,21 +1185,6 @@
|
|||||||
* passed using %NL80211_ATTR_SAR_SPEC. %NL80211_ATTR_WIPHY is used to
|
* passed using %NL80211_ATTR_SAR_SPEC. %NL80211_ATTR_WIPHY is used to
|
||||||
* specify the wiphy index to be applied 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_MAX: highest used command number
|
||||||
* @__NL80211_CMD_AFTER_LAST: internal use
|
* @__NL80211_CMD_AFTER_LAST: internal use
|
||||||
*/
|
*/
|
||||||
@ -1432,14 +1417,6 @@ enum nl80211_commands {
|
|||||||
|
|
||||||
NL80211_CMD_SET_SAR_SPECS,
|
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 */
|
/* add new commands above here */
|
||||||
|
|
||||||
/* used to define NL80211_CMD_MAX below */
|
/* 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
|
* disassoc events to indicate that an immediate reconnect to the AP
|
||||||
* is desired.
|
* 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
|
* @NUM_NL80211_ATTR: total number of nl80211_attrs available
|
||||||
* @NL80211_ATTR_MAX: highest attribute number currently defined
|
* @NL80211_ATTR_MAX: highest attribute number currently defined
|
||||||
* @__NL80211_ATTR_AFTER_LAST: internal use
|
* @__NL80211_ATTR_AFTER_LAST: internal use
|
||||||
@ -3090,12 +3057,6 @@ enum nl80211_attrs {
|
|||||||
|
|
||||||
NL80211_ATTR_DISABLE_HE,
|
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 */
|
/* add attributes here, update the policy in nl80211.c */
|
||||||
|
|
||||||
__NL80211_ATTR_AFTER_LAST,
|
__NL80211_ATTR_AFTER_LAST,
|
||||||
@ -5992,9 +5953,6 @@ enum nl80211_feature_flags {
|
|||||||
* frame protection for all management frames exchanged during the
|
* frame protection for all management frames exchanged during the
|
||||||
* negotiation and range measurement procedure.
|
* 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.
|
* @NUM_NL80211_EXT_FEATURES: number of extended features.
|
||||||
* @MAX_NL80211_EXT_FEATURES: highest extended feature index.
|
* @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_LTF,
|
||||||
NL80211_EXT_FEATURE_SECURE_RTT,
|
NL80211_EXT_FEATURE_SECURE_RTT,
|
||||||
NL80211_EXT_FEATURE_PROT_RANGE_NEGO_AND_MEASURE,
|
NL80211_EXT_FEATURE_PROT_RANGE_NEGO_AND_MEASURE,
|
||||||
NL80211_EXT_FEATURE_BSS_COLOR,
|
|
||||||
|
|
||||||
/* add new features before the definition below */
|
/* add new features before the definition below */
|
||||||
NUM_NL80211_EXT_FEATURES,
|
NUM_NL80211_EXT_FEATURES,
|
||||||
|
|||||||
@ -44,8 +44,3 @@
|
|||||||
#ifndef BOND_MAX_ARP_TARGETS
|
#ifndef BOND_MAX_ARP_TARGETS
|
||||||
#define BOND_MAX_ARP_TARGETS 16
|
#define BOND_MAX_ARP_TARGETS 16
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Not exposed but defined in include/linux/ieee80211.h */
|
|
||||||
#ifndef IEEE80211_MAX_SSID_LEN
|
|
||||||
#define IEEE80211_MAX_SSID_LEN 32
|
|
||||||
#endif
|
|
||||||
|
|||||||
@ -300,24 +300,6 @@ int strv_split_full(char ***t, const char *s, const char *separators, ExtractFla
|
|||||||
return (int) n;
|
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) {
|
int strv_split_colon_pairs(char ***t, const char *s) {
|
||||||
_cleanup_strv_free_ char **l = NULL;
|
_cleanup_strv_free_ char **l = NULL;
|
||||||
size_t n = 0;
|
size_t n = 0;
|
||||||
|
|||||||
@ -83,9 +83,6 @@ static inline char **strv_split(const char *s, const char *separators) {
|
|||||||
return ret;
|
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);
|
int strv_split_newlines_full(char ***ret, const char *s, ExtractFlags flags);
|
||||||
static inline char **strv_split_newlines(const char *s) {
|
static inline char **strv_split_newlines(const char *s) {
|
||||||
char **ret;
|
char **ret;
|
||||||
|
|||||||
@ -284,7 +284,7 @@ int unit_file_build_name_map(
|
|||||||
continue;
|
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;
|
char *filename;
|
||||||
_unused_ _cleanup_free_ char *_filename_free = NULL;
|
_unused_ _cleanup_free_ char *_filename_free = NULL;
|
||||||
_cleanup_free_ char *simplified = NULL;
|
_cleanup_free_ char *simplified = NULL;
|
||||||
|
|||||||
@ -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("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("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("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("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("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),
|
SD_BUS_PROPERTY("JobRunningTimeoutUSec", "t", bus_property_get_usec, offsetof(Unit, job_running_timeout), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||||
|
|||||||
@ -1575,10 +1575,6 @@ static int mount_setup_new_unit(
|
|||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
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
|
/* 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
|
* the unit file for it (and thus add in extra deps right after) we know what source to attributes the deps
|
||||||
* to. */
|
* to. */
|
||||||
|
|||||||
@ -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_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_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_append_vendor_option(uint8_t **buf, size_t *buflen, OrderedHashmap *vendor_options);
|
||||||
|
int dhcp6_option_parse(uint8_t **buf, size_t *buflen, uint16_t *optcode,
|
||||||
int dhcp6_option_parse(
|
size_t *optlen, uint8_t **optvalue);
|
||||||
const uint8_t *buf,
|
int dhcp6_option_parse_status(DHCP6Option *option, size_t len);
|
||||||
size_t buflen,
|
int dhcp6_option_parse_ia(sd_dhcp6_client *client, DHCP6Option *iaoption, be32_t iaid, DHCP6IA *ia, uint16_t *ret_status_code);
|
||||||
size_t *offset,
|
int dhcp6_option_parse_ip6addrs(uint8_t *optval, uint16_t optlen,
|
||||||
uint16_t *ret_option_code,
|
struct in6_addr **addrs, size_t count);
|
||||||
size_t *ret_option_data_len,
|
int dhcp6_option_parse_domainname_list(const uint8_t *optval, uint16_t optlen,
|
||||||
const uint8_t **ret_option_data);
|
char ***str_arr);
|
||||||
int dhcp6_option_parse_status(const uint8_t *data, size_t data_len, char **ret_status_message);
|
int dhcp6_option_parse_domainname(const uint8_t *optval, uint16_t optlen, char **str);
|
||||||
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_network_bind_udp_socket(int ifindex, struct in6_addr *address);
|
int dhcp6_network_bind_udp_socket(int ifindex, struct in6_addr *address);
|
||||||
int dhcp6_network_send_udp_socket(int s, struct in6_addr *address,
|
int dhcp6_network_send_udp_socket(int s, struct in6_addr *address,
|
||||||
|
|||||||
@ -28,11 +28,11 @@ struct sd_dhcp6_lease {
|
|||||||
struct in6_addr *dns;
|
struct in6_addr *dns;
|
||||||
size_t dns_count;
|
size_t dns_count;
|
||||||
char **domains;
|
char **domains;
|
||||||
|
size_t domains_count;
|
||||||
struct in6_addr *ntp;
|
struct in6_addr *ntp;
|
||||||
size_t ntp_count;
|
size_t ntp_count;
|
||||||
char **ntp_fqdn;
|
char **ntp_fqdn;
|
||||||
struct in6_addr *sntp;
|
size_t ntp_fqdn_count;
|
||||||
size_t sntp_count;
|
|
||||||
char *fqdn;
|
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_iaid(sd_dhcp6_lease *lease, be32_t *iaid);
|
||||||
int dhcp6_lease_get_pd_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_set_dns(sd_dhcp6_lease *lease, 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_set_domains(sd_dhcp6_lease *lease, uint8_t *optval,
|
||||||
int dhcp6_lease_add_ntp(sd_dhcp6_lease *lease, const uint8_t *optval, size_t optlen);
|
size_t optlen);
|
||||||
int dhcp6_lease_add_sntp(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 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_set_fqdn(sd_dhcp6_lease *lease, const uint8_t *optval, size_t optlen);
|
||||||
|
|
||||||
int dhcp6_lease_new(sd_dhcp6_lease **ret);
|
int dhcp6_lease_new(sd_dhcp6_lease **ret);
|
||||||
|
|||||||
@ -14,12 +14,29 @@
|
|||||||
#include "dhcp6-lease-internal.h"
|
#include "dhcp6-lease-internal.h"
|
||||||
#include "dhcp6-protocol.h"
|
#include "dhcp6-protocol.h"
|
||||||
#include "dns-domain.h"
|
#include "dns-domain.h"
|
||||||
#include "escape.h"
|
|
||||||
#include "memory-util.h"
|
#include "memory-util.h"
|
||||||
#include "sparse-endian.h"
|
#include "sparse-endian.h"
|
||||||
#include "strv.h"
|
#include "strv.h"
|
||||||
#include "unaligned.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_NA_LEN (sizeof(struct ia_na))
|
||||||
#define DHCP6_OPTION_IA_PD_LEN (sizeof(struct ia_pd))
|
#define DHCP6_OPTION_IA_PD_LEN (sizeof(struct ia_pd))
|
||||||
#define DHCP6_OPTION_IA_TA_LEN (sizeof(struct ia_ta))
|
#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);
|
return dhcp6_option_append(buf, buflen, SD_DHCP6_OPTION_VENDOR_CLASS, total, p);
|
||||||
}
|
}
|
||||||
|
|
||||||
int dhcp6_option_parse(
|
static int option_parse_hdr(uint8_t **buf, size_t *buflen, uint16_t *optcode, size_t *optlen) {
|
||||||
const uint8_t *buf,
|
DHCP6Option *option = (DHCP6Option*) *buf;
|
||||||
size_t buflen,
|
uint16_t len;
|
||||||
size_t *offset,
|
|
||||||
uint16_t *ret_option_code,
|
|
||||||
size_t *ret_option_data_len,
|
|
||||||
const uint8_t **ret_option_data) {
|
|
||||||
|
|
||||||
const DHCP6Option *option;
|
assert_return(buf, -EINVAL);
|
||||||
size_t len;
|
assert_return(optcode, -EINVAL);
|
||||||
|
assert_return(optlen, -EINVAL);
|
||||||
|
|
||||||
assert(buf);
|
if (*buflen < offsetof(DHCP6Option, data))
|
||||||
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))
|
|
||||||
return -ENOMSG;
|
return -ENOMSG;
|
||||||
|
|
||||||
lt_valid = be32toh(((const struct iapdprefix*) data)->lifetime_valid);
|
len = be16toh(option->len);
|
||||||
lt_pref = be32toh(((const struct iapdprefix*) data)->lifetime_preferred);
|
|
||||||
|
|
||||||
if (lt_valid == 0)
|
if (len > *buflen)
|
||||||
return log_dhcp6_client_errno(client, SYNTHETIC_ERRNO(EINVAL),
|
return -ENOMSG;
|
||||||
"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.",
|
|
||||||
lt_pref, lt_valid);
|
|
||||||
|
|
||||||
if (len > sizeof(struct iapdprefix)) {
|
*optcode = be16toh(option->code);
|
||||||
r = dhcp6_option_parse_ia_options(client, data + sizeof(struct iapdprefix), len - sizeof(struct iapdprefix));
|
*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)
|
if (r < 0)
|
||||||
return r;
|
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),
|
||||||
|
"Valid lifetime of an IA address is zero or "
|
||||||
|
"preferred lifetime %"PRIu32" > valid lifetime %"PRIu32,
|
||||||
|
lt_pref, lt_valid);
|
||||||
|
|
||||||
|
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);
|
addr = new0(DHCP6Address, 1);
|
||||||
if (!a)
|
if (!addr)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
LIST_INIT(addresses, a);
|
LIST_INIT(addresses, addr);
|
||||||
memcpy(&a->iapdprefix, data, sizeof(struct iapdprefix));
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int dhcp6_option_parse_ia(
|
int dhcp6_option_parse_ia(
|
||||||
sd_dhcp6_client *client,
|
sd_dhcp6_client *client,
|
||||||
|
DHCP6Option *iaoption,
|
||||||
be32_t iaid,
|
be32_t iaid,
|
||||||
uint16_t option_code,
|
DHCP6IA *ia,
|
||||||
size_t option_data_len,
|
uint16_t *ret_status_code) {
|
||||||
const uint8_t *option_data,
|
|
||||||
DHCP6IA *ret) {
|
|
||||||
|
|
||||||
_cleanup_(dhcp6_lease_free_ia) DHCP6IA ia = {};
|
uint32_t lt_t1, lt_t2, lt_valid = 0, lt_min = UINT32_MAX;
|
||||||
uint32_t lt_t1, lt_t2, lt_min = UINT32_MAX;
|
uint16_t iatype, optlen;
|
||||||
be32_t received_iaid;
|
size_t iaaddr_offset;
|
||||||
size_t offset;
|
int r = 0, status;
|
||||||
int r;
|
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_return(ia, -EINVAL);
|
||||||
assert(option_data);
|
assert_return(!ia->addresses, -EINVAL);
|
||||||
assert(ret);
|
|
||||||
|
|
||||||
/* This will return the following:
|
iatype = be16toh(iaoption->code);
|
||||||
* -ENOMEM: memory allocation error,
|
len = be16toh(iaoption->len);
|
||||||
* -ENOANO: unmatching IAID,
|
|
||||||
* -EINVAL: non-zero status code, or invalid lifetime,
|
|
||||||
* -EBADMSG: invalid message format,
|
|
||||||
* -ENODATA: no valid address or PD prefix,
|
|
||||||
* 0: success. */
|
|
||||||
|
|
||||||
switch (option_code) {
|
switch (iatype) {
|
||||||
case SD_DHCP6_OPTION_IA_NA:
|
case SD_DHCP6_OPTION_IA_NA:
|
||||||
|
|
||||||
if (option_data_len < DHCP6_OPTION_IA_NA_LEN)
|
if (len < DHCP6_OPTION_IA_NA_LEN)
|
||||||
return -EBADMSG;
|
return -ENOBUFS;
|
||||||
|
|
||||||
offset = DHCP6_OPTION_IA_NA_LEN;
|
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
offset = DHCP6_OPTION_IA_PD_LEN;
|
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
offset = DHCP6_OPTION_IA_TA_LEN;
|
|
||||||
|
|
||||||
received_iaid = ((const struct ia_ta*) option_data)->id;
|
|
||||||
lt_t1 = lt_t2 = 0; /* No lifetime for IA_TA. */
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
assert_not_reached();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* According to RFC8415, IAs which do not match the client's IAID should be ignored,
|
/* 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. */
|
* but not necessary to ignore or refuse the whole message. */
|
||||||
if (received_iaid != iaid)
|
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),
|
return log_dhcp6_client_errno(client, SYNTHETIC_ERRNO(ENOANO),
|
||||||
"Received an IA option with a different IAID "
|
"Received an IA_NA option with a different IAID "
|
||||||
"from the one chosen by the client, ignoring.");
|
"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)
|
if (lt_t1 > lt_t2)
|
||||||
return log_dhcp6_client_errno(client, SYNTHETIC_ERRNO(EINVAL),
|
return log_dhcp6_client_errno(client, SYNTHETIC_ERRNO(EINVAL),
|
||||||
"Received an IA option with T1 %"PRIu32"sec > T2 %"PRIu32"sec, ignoring.",
|
"IA NA T1 %"PRIu32"sec > T2 %"PRIu32"sec",
|
||||||
lt_t1, lt_t2);
|
lt_t1, lt_t2);
|
||||||
|
|
||||||
for (; offset < option_data_len;) {
|
|
||||||
const uint8_t *subdata;
|
|
||||||
size_t subdata_len;
|
|
||||||
uint16_t subopt;
|
|
||||||
|
|
||||||
r = dhcp6_option_parse(option_data, option_data_len, &offset, &subopt, &subdata_len, &subdata);
|
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
|
|
||||||
switch (subopt) {
|
|
||||||
case SD_DHCP6_OPTION_IAADDR: {
|
|
||||||
DHCP6Address *a;
|
|
||||||
|
|
||||||
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;
|
break;
|
||||||
}
|
|
||||||
case SD_DHCP6_OPTION_IA_PD_PREFIX: {
|
|
||||||
DHCP6Address *a;
|
|
||||||
|
|
||||||
if (option_code != SD_DHCP6_OPTION_IA_PD) {
|
case 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 (len < sizeof(ia->ia_pd))
|
||||||
if (r == -ENOMEM)
|
return -ENOBUFS;
|
||||||
return r;
|
|
||||||
if (r < 0)
|
|
||||||
/* Ignore the sub-option on non-critical errors. */
|
|
||||||
continue;
|
|
||||||
|
|
||||||
lt_min = MIN(lt_min, a->iapdprefix.lifetime_valid);
|
/* According to RFC8415, IAs which do not match the client's IAID should be ignored,
|
||||||
LIST_PREPEND(addresses, ia.addresses, a);
|
* but not necessary to ignore or refuse the whole message. */
|
||||||
break;
|
if (((const struct ia_pd*) iaoption->data)->id != iaid)
|
||||||
}
|
/* ENOANO indicates the option should be ignored. */
|
||||||
case SD_DHCP6_OPTION_STATUS_CODE: {
|
return log_dhcp6_client_errno(client, SYNTHETIC_ERRNO(ENOANO),
|
||||||
_cleanup_free_ char *msg = NULL;
|
"Received an IA_PD option with a different IAID "
|
||||||
|
"from the one chosen by the client, ignoring.");
|
||||||
|
|
||||||
r = dhcp6_option_parse_status(subdata, subdata_len, &msg);
|
iaaddr_offset = sizeof(ia->ia_pd);
|
||||||
if (r == -ENOMEM)
|
memcpy(&ia->ia_pd, iaoption->data, sizeof(ia->ia_pd));
|
||||||
return r;
|
|
||||||
if (r < 0)
|
lt_t1 = be32toh(ia->ia_pd.lifetime_t1);
|
||||||
log_dhcp6_client_errno(client, r,
|
lt_t2 = be32toh(ia->ia_pd.lifetime_t2);
|
||||||
"Received an IA option with an invalid status sub option, ignoring: %m");
|
|
||||||
else if (r > 0)
|
if (lt_t1 > lt_t2)
|
||||||
return log_dhcp6_client_errno(client, SYNTHETIC_ERRNO(EINVAL),
|
return log_dhcp6_client_errno(client, SYNTHETIC_ERRNO(EINVAL),
|
||||||
"Received an IA option with non-zero status: %s%s%s",
|
"IA PD T1 %"PRIu32"sec > T2 %"PRIu32"sec",
|
||||||
strempty(msg), isempty(msg) ? "" : ": ",
|
lt_t1, lt_t2);
|
||||||
dhcp6_message_status_to_string(r));
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SD_DHCP6_OPTION_IA_TA:
|
||||||
|
if (len < DHCP6_OPTION_IA_TA_LEN)
|
||||||
|
return -ENOBUFS;
|
||||||
|
|
||||||
|
/* 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));
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
ia->type = iatype;
|
||||||
|
i = iaaddr_offset;
|
||||||
|
|
||||||
|
while (i < len) {
|
||||||
|
DHCP6Option *option = (DHCP6Option *)&iaoption->data[i];
|
||||||
|
|
||||||
|
if (len < i + sizeof(*option) || len < i + sizeof(*option) + be16toh(option->len))
|
||||||
|
return -ENOBUFS;
|
||||||
|
|
||||||
|
opt = be16toh(option->code);
|
||||||
|
optlen = be16toh(option->len);
|
||||||
|
|
||||||
|
switch (opt) {
|
||||||
|
case SD_DHCP6_OPTION_IAADDR:
|
||||||
|
|
||||||
|
if (!IN_SET(ia->type, SD_DHCP6_OPTION_IA_NA, SD_DHCP6_OPTION_IA_TA))
|
||||||
|
return log_dhcp6_client_errno(client, SYNTHETIC_ERRNO(EINVAL),
|
||||||
|
"IA Address option not in IA NA or TA option");
|
||||||
|
|
||||||
|
r = dhcp6_option_parse_address(client, option, ia, <_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, <_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;
|
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)
|
switch(iatype) {
|
||||||
return log_dhcp6_client_errno(client, SYNTHETIC_ERRNO(ENODATA),
|
case SD_DHCP6_OPTION_IA_NA:
|
||||||
"Received an IA option without valid IA addresses or PD prefixes, ignoring.");
|
if (ia->ia_na.lifetime_t1 == 0 && ia->ia_na.lifetime_t2 == 0 && lt_min != UINT32_MAX) {
|
||||||
|
|
||||||
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_t1 = lt_min / 2;
|
||||||
lt_t2 = lt_min / 10 * 8;
|
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, "Received an IA option with both T1 and T2 equal to zero. "
|
log_dhcp6_client(client, "Computed IA NA T1 %"PRIu32"sec and T2 %"PRIu32"sec as both were zero",
|
||||||
"Adjusting them based on the minimum valid lifetime of IA addresses or PD prefixes: "
|
lt_t1, lt_t2);
|
||||||
"T1=%"PRIu32"sec, T2=%"PRIu32"sec", lt_t1, lt_t2);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
switch(option_code) {
|
|
||||||
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),
|
|
||||||
};
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SD_DHCP6_OPTION_IA_PD:
|
case SD_DHCP6_OPTION_IA_PD:
|
||||||
*ret = (DHCP6IA) {
|
if (ia->ia_pd.lifetime_t1 == 0 && ia->ia_pd.lifetime_t2 == 0 && lt_min != UINT32_MAX) {
|
||||||
.type = option_code,
|
lt_t1 = lt_min / 2;
|
||||||
.ia_pd.id = iaid,
|
lt_t2 = lt_min / 10 * 8;
|
||||||
.ia_pd.lifetime_t1 = htobe32(lt_t1),
|
ia->ia_pd.lifetime_t1 = htobe32(lt_t1);
|
||||||
.ia_pd.lifetime_t2 = htobe32(lt_t2),
|
ia->ia_pd.lifetime_t2 = htobe32(lt_t2);
|
||||||
.addresses = TAKE_PTR(ia.addresses),
|
|
||||||
};
|
log_dhcp6_client(client, "Computed IA PD T1 %"PRIu32"sec and T2 %"PRIu32"sec as both were zero",
|
||||||
break;
|
lt_t1, lt_t2);
|
||||||
default:
|
|
||||||
assert_not_reached();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret_status_code)
|
||||||
|
*ret_status_code = 0;
|
||||||
|
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int dhcp6_option_parse_addresses(
|
int dhcp6_option_parse_ip6addrs(uint8_t *optval, uint16_t optlen,
|
||||||
const uint8_t *optval,
|
struct in6_addr **addrs, size_t count) {
|
||||||
size_t optlen,
|
|
||||||
struct in6_addr **addrs,
|
|
||||||
size_t *count) {
|
|
||||||
|
|
||||||
assert(optval);
|
|
||||||
assert(addrs);
|
|
||||||
assert(count);
|
|
||||||
|
|
||||||
if (optlen == 0 || optlen % sizeof(struct in6_addr) != 0)
|
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;
|
return -ENOMEM;
|
||||||
|
|
||||||
memcpy(*addrs + *count, optval, optlen);
|
memcpy(*addrs + count, optval, optlen);
|
||||||
*count += optlen / sizeof(struct in6_addr);
|
|
||||||
|
|
||||||
return 0;
|
count += optlen / sizeof(struct in6_addr);
|
||||||
|
|
||||||
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int parse_domain(const uint8_t **data, size_t *len, char **ret) {
|
static int parse_domain(const uint8_t **data, uint16_t *len, char **out_domain) {
|
||||||
_cleanup_free_ char *domain = NULL;
|
_cleanup_free_ char *ret = NULL;
|
||||||
const uint8_t *optval;
|
const uint8_t *optval = *data;
|
||||||
size_t optlen, n = 0;
|
uint16_t optlen = *len;
|
||||||
|
bool first = true;
|
||||||
|
size_t n = 0;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
assert(data);
|
|
||||||
assert(*data);
|
|
||||||
assert(len);
|
|
||||||
assert(ret);
|
|
||||||
|
|
||||||
optval = *data;
|
|
||||||
optlen = *len;
|
|
||||||
|
|
||||||
if (optlen <= 1)
|
if (optlen <= 1)
|
||||||
return -ENODATA;
|
return -ENODATA;
|
||||||
|
|
||||||
@ -780,44 +754,42 @@ static int parse_domain(const uint8_t **data, size_t *len, char **ret) {
|
|||||||
return -EMSGSIZE;
|
return -EMSGSIZE;
|
||||||
|
|
||||||
/* Literal label */
|
/* Literal label */
|
||||||
label = (const char*) optval;
|
label = (const char *)optval;
|
||||||
optval += c;
|
optval += c;
|
||||||
optlen -= 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;
|
return -ENOMEM;
|
||||||
|
|
||||||
if (n != 0)
|
if (first)
|
||||||
domain[n++] = '.';
|
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)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
n += r;
|
n += r;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (n > 0) {
|
if (n) {
|
||||||
if (!GREEDY_REALLOC(domain, n + 1))
|
if (!GREEDY_REALLOC(ret, n + 1))
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
ret[n] = 0;
|
||||||
domain[n] = '\0';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
*ret = TAKE_PTR(domain);
|
*out_domain = TAKE_PTR(ret);
|
||||||
*data = optval;
|
*data = optval;
|
||||||
*len = optlen;
|
*len = optlen;
|
||||||
|
|
||||||
return n;
|
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;
|
_cleanup_free_ char *domain = NULL;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
assert(optval);
|
|
||||||
assert(ret);
|
|
||||||
|
|
||||||
r = parse_domain(&optval, &optlen, &domain);
|
r = parse_domain(&optval, &optlen, &domain);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
@ -826,38 +798,39 @@ int dhcp6_option_parse_domainname(const uint8_t *optval, size_t optlen, char **r
|
|||||||
if (optlen != 0)
|
if (optlen != 0)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
*ret = TAKE_PTR(domain);
|
*str = TAKE_PTR(domain);
|
||||||
return 0;
|
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;
|
_cleanup_strv_free_ char **names = NULL;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
assert(optval);
|
|
||||||
assert(ret);
|
|
||||||
|
|
||||||
if (optlen <= 1)
|
if (optlen <= 1)
|
||||||
return -ENODATA;
|
return -ENODATA;
|
||||||
if (optval[optlen - 1] != '\0')
|
if (optval[optlen - 1] != '\0')
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
while (optlen > 0) {
|
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)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
if (r == 0)
|
if (r == 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
r = strv_consume(&names, TAKE_PTR(name));
|
r = strv_extend(&names, ret);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
|
idx++;
|
||||||
}
|
}
|
||||||
|
|
||||||
*ret = TAKE_PTR(names);
|
*str_arr = TAKE_PTR(names);
|
||||||
return 0;
|
|
||||||
|
return idx;
|
||||||
}
|
}
|
||||||
|
|
||||||
static sd_dhcp6_option* dhcp6_option_free(sd_dhcp6_option *i) {
|
static sd_dhcp6_option* dhcp6_option_free(sd_dhcp6_option *i) {
|
||||||
|
|||||||
@ -1109,9 +1109,11 @@ static int client_parse_message(
|
|||||||
size_t len,
|
size_t len,
|
||||||
sd_dhcp6_lease *lease) {
|
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;
|
usec_t irt = IRT_DEFAULT;
|
||||||
bool clientid = false;
|
bool clientid = false;
|
||||||
|
size_t pos = 0;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
assert(client);
|
assert(client);
|
||||||
@ -1120,14 +1122,22 @@ static int client_parse_message(
|
|||||||
assert(lease);
|
assert(lease);
|
||||||
|
|
||||||
len -= sizeof(DHCP6Message);
|
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);
|
while (pos < len) {
|
||||||
if (r < 0)
|
DHCP6Option *option = (DHCP6Option *) &message->options[pos];
|
||||||
return r;
|
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) {
|
switch (optcode) {
|
||||||
case SD_DHCP6_OPTION_CLIENTID:
|
case SD_DHCP6_OPTION_CLIENTID:
|
||||||
@ -1166,75 +1176,62 @@ static int client_parse_message(
|
|||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SD_DHCP6_OPTION_STATUS_CODE: {
|
case SD_DHCP6_OPTION_STATUS_CODE:
|
||||||
_cleanup_free_ char *msg = NULL;
|
status = dhcp6_option_parse_status(option, optlen + sizeof(DHCP6Option));
|
||||||
|
if (status < 0)
|
||||||
|
return status;
|
||||||
|
|
||||||
r = dhcp6_option_parse_status(optval, optlen, &msg);
|
if (status > 0)
|
||||||
if (r < 0)
|
return log_dhcp6_client_errno(client, SYNTHETIC_ERRNO(EINVAL), "%s Status %s",
|
||||||
return r;
|
|
||||||
|
|
||||||
if (r > 0)
|
|
||||||
return log_dhcp6_client_errno(client, SYNTHETIC_ERRNO(EINVAL),
|
|
||||||
"Received %s message with non-zero status: %s%s%s",
|
|
||||||
dhcp6_message_type_to_string(message->type),
|
dhcp6_message_type_to_string(message->type),
|
||||||
strempty(msg), isempty(msg) ? "" : ": ",
|
dhcp6_message_status_to_string(status));
|
||||||
dhcp6_message_status_to_string(r));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case SD_DHCP6_OPTION_IA_NA: {
|
|
||||||
_cleanup_(dhcp6_lease_free_ia) DHCP6IA ia = {};
|
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SD_DHCP6_OPTION_IA_NA:
|
||||||
if (client->state == DHCP6_STATE_INFORMATION_REQUEST) {
|
if (client->state == DHCP6_STATE_INFORMATION_REQUEST) {
|
||||||
log_dhcp6_client(client, "Ignoring IA NA option in information requesting mode.");
|
log_dhcp6_client(client, "Ignoring IA NA option in information requesting mode.");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
r = dhcp6_option_parse_ia(client, client->ia_pd.ia_na.id, optcode, optlen, optval, &ia);
|
r = dhcp6_option_parse_ia(client, option, client->ia_pd.ia_na.id, &lease->ia, &ia_na_status);
|
||||||
if (r == -ENOMEM)
|
if (r < 0 && r != -ENOANO)
|
||||||
return r;
|
return r;
|
||||||
if (r < 0)
|
|
||||||
|
if (ia_na_status == DHCP6_STATUS_NO_ADDRS_AVAIL) {
|
||||||
|
pos += offsetof(DHCP6Option, data) + optlen;
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (lease->ia.addresses) {
|
if (lease->ia.addresses) {
|
||||||
log_dhcp6_client(client, "Received duplicate matching IA_NA option, ignoring.");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
lease->ia = ia;
|
|
||||||
ia = (DHCP6IA) {};
|
|
||||||
|
|
||||||
lt_t1 = MIN(lt_t1, be32toh(lease->ia.ia_na.lifetime_t1));
|
lt_t1 = MIN(lt_t1, be32toh(lease->ia.ia_na.lifetime_t1));
|
||||||
lt_t2 = MIN(lt_t2, be32toh(lease->ia.ia_na.lifetime_t2));
|
lt_t2 = MIN(lt_t2, be32toh(lease->ia.ia_na.lifetime_t2));
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
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) {
|
if (client->state == DHCP6_STATE_INFORMATION_REQUEST) {
|
||||||
log_dhcp6_client(client, "Ignoring IA PD option in information requesting mode.");
|
log_dhcp6_client(client, "Ignoring IA PD option in information requesting mode.");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
r = dhcp6_option_parse_ia(client, client->ia_pd.ia_pd.id, optcode, optlen, optval, &ia);
|
r = dhcp6_option_parse_ia(client, option, client->ia_pd.ia_pd.id, &lease->pd, &ia_pd_status);
|
||||||
if (r == -ENOMEM)
|
if (r < 0 && r != -ENOANO)
|
||||||
return r;
|
return r;
|
||||||
if (r < 0)
|
|
||||||
|
if (ia_pd_status == DHCP6_STATUS_NO_PREFIX_AVAIL) {
|
||||||
|
pos += offsetof(DHCP6Option, data) + optlen;
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (lease->pd.addresses) {
|
if (lease->pd.addresses) {
|
||||||
log_dhcp6_client(client, "Received duplicate matching IA_PD option, ignoring.");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
lease->pd = ia;
|
|
||||||
ia = (DHCP6IA) {};
|
|
||||||
|
|
||||||
lt_t1 = MIN(lt_t1, be32toh(lease->pd.ia_pd.lifetime_t1));
|
lt_t1 = MIN(lt_t1, be32toh(lease->pd.ia_pd.lifetime_t1));
|
||||||
lt_t2 = MIN(lt_t2, be32toh(lease->pd.ia_pd.lifetime_t2));
|
lt_t2 = MIN(lt_t2, be32toh(lease->pd.ia_pd.lifetime_t2));
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
case SD_DHCP6_OPTION_RAPID_COMMIT:
|
case SD_DHCP6_OPTION_RAPID_COMMIT:
|
||||||
r = dhcp6_lease_set_rapid_commit(lease);
|
r = dhcp6_lease_set_rapid_commit(lease);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
@ -1243,28 +1240,28 @@ static int client_parse_message(
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case SD_DHCP6_OPTION_DNS_SERVERS:
|
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)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SD_DHCP6_OPTION_DOMAIN_LIST:
|
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)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SD_DHCP6_OPTION_NTP_SERVER:
|
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)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SD_DHCP6_OPTION_SNTP_SERVERS:
|
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)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
@ -1284,8 +1281,13 @@ static int client_parse_message(
|
|||||||
irt = unaligned_read_be32((be32_t *) optval) * USEC_PER_SEC;
|
irt = unaligned_read_be32((be32_t *) optval) * USEC_PER_SEC;
|
||||||
break;
|
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)
|
if (!clientid)
|
||||||
return log_dhcp6_client_errno(client, SYNTHETIC_ERRNO(EINVAL), "%s has incomplete options",
|
return log_dhcp6_client_errno(client, SYNTHETIC_ERRNO(EINVAL), "%s has incomplete options",
|
||||||
dhcp6_message_type_to_string(message->type));
|
dhcp6_message_type_to_string(message->type));
|
||||||
@ -1295,9 +1297,7 @@ static int client_parse_message(
|
|||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_dhcp6_client_errno(client, r, "%s has no server id",
|
return log_dhcp6_client_errno(client, r, "%s has no server id",
|
||||||
dhcp6_message_type_to_string(message->type));
|
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) {
|
if (lease->ia.addresses) {
|
||||||
lease->ia.ia_na.lifetime_t1 = htobe32(lt_t1);
|
lease->ia.ia_na.lifetime_t1 = htobe32(lt_t1);
|
||||||
@ -1308,7 +1308,6 @@ static int client_parse_message(
|
|||||||
lease->pd.ia_pd.lifetime_t1 = htobe32(lt_t1);
|
lease->pd.ia_pd.lifetime_t1 = htobe32(lt_t1);
|
||||||
lease->pd.ia_pd.lifetime_t2 = htobe32(lt_t2);
|
lease->pd.ia_pd.lifetime_t2 = htobe32(lt_t2);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
client->information_refresh_time_usec = MAX(irt, IRT_MINIMUM);
|
client->information_refresh_time_usec = MAX(irt, IRT_MINIMUM);
|
||||||
|
|
||||||
|
|||||||
@ -193,69 +193,86 @@ void sd_dhcp6_lease_reset_pd_prefix_iter(sd_dhcp6_lease *lease) {
|
|||||||
lease->prefix_iter = lease->pd.addresses;
|
lease->prefix_iter = lease->pd.addresses;
|
||||||
}
|
}
|
||||||
|
|
||||||
int dhcp6_lease_add_dns(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) {
|
||||||
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 r;
|
int r;
|
||||||
|
|
||||||
assert_return(lease, -EINVAL);
|
assert_return(lease, -EINVAL);
|
||||||
assert_return(optval, -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;
|
return 0;
|
||||||
|
|
||||||
r = dhcp6_option_parse_domainname_list(optval, optlen, &domains);
|
r = dhcp6_option_parse_domainname_list(optval, optlen, &domains);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
strv_free_and_replace(lease->domains, domains);
|
||||||
|
lease->domains_count = r;
|
||||||
|
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
return strv_extend_strv(&lease->domains, domains, true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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(lease, -EINVAL);
|
||||||
assert_return(ret, -EINVAL);
|
assert_return(domains, -EINVAL);
|
||||||
|
|
||||||
|
if (lease->domains_count) {
|
||||||
|
*domains = lease->domains;
|
||||||
|
return lease->domains_count;
|
||||||
|
}
|
||||||
|
|
||||||
if (!lease->domains)
|
|
||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
|
|
||||||
*ret = lease->domains;
|
|
||||||
return strv_length(lease->domains);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
int r;
|
||||||
|
uint16_t subopt;
|
||||||
|
size_t sublen;
|
||||||
|
uint8_t *subval;
|
||||||
|
|
||||||
assert_return(lease, -EINVAL);
|
assert_return(lease, -EINVAL);
|
||||||
assert_return(optval, -EINVAL);
|
assert_return(optval, -EINVAL);
|
||||||
|
|
||||||
for (size_t offset = 0; offset < optlen;) {
|
lease->ntp = mfree(lease->ntp);
|
||||||
const uint8_t *subval;
|
lease->ntp_count = 0;
|
||||||
size_t sublen;
|
|
||||||
uint16_t subopt;
|
|
||||||
|
|
||||||
r = dhcp6_option_parse(optval, optlen, &offset, &subopt, &sublen, &subval);
|
while ((r = dhcp6_option_parse(&optval, &optlen, &subopt, &sublen,
|
||||||
if (r < 0)
|
&subval)) >= 0) {
|
||||||
return r;
|
int s;
|
||||||
|
char **servers;
|
||||||
|
|
||||||
switch(subopt) {
|
switch(subopt) {
|
||||||
case DHCP6_NTP_SUBOPTION_SRV_ADDR:
|
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)
|
if (sublen != 16)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
r = dhcp6_option_parse_addresses(subval, sublen, &lease->ntp, &lease->ntp_count);
|
s = dhcp6_option_parse_ip6addrs(subval, sublen,
|
||||||
if (r < 0)
|
&lease->ntp,
|
||||||
return r;
|
lease->ntp_count);
|
||||||
|
if (s < 0)
|
||||||
|
return s;
|
||||||
|
|
||||||
|
lease->ntp_count = s;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DHCP6_NTP_SUBOPTION_SRV_FQDN: {
|
case DHCP6_NTP_SUBOPTION_SRV_FQDN:
|
||||||
_cleanup_free_ char *server = NULL;
|
r = dhcp6_option_parse_domainname_list(subval, sublen,
|
||||||
|
&servers);
|
||||||
r = dhcp6_option_parse_domainname(subval, sublen, &server);
|
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return 0;
|
||||||
|
|
||||||
if (strv_contains(lease->ntp_fqdn, server))
|
strv_free_and_replace(lease->ntp_fqdn, servers);
|
||||||
continue;
|
lease->ntp_fqdn_count = r;
|
||||||
|
|
||||||
r = strv_consume(&lease->ntp_fqdn, TAKE_PTR(server));
|
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (r != -ENOMSG)
|
||||||
|
return r;
|
||||||
|
|
||||||
return 0;
|
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(lease, -EINVAL);
|
||||||
assert_return(optval, -EINVAL);
|
assert_return(optval, -EINVAL);
|
||||||
|
|
||||||
if (optlen == 0)
|
if (!optlen)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/* SNTP option is defined in RFC4075, and deprecated by RFC5908. */
|
if (lease->ntp || lease->ntp_fqdn)
|
||||||
return dhcp6_option_parse_addresses(optval, optlen, &lease->sntp, &lease->sntp_count);
|
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(lease, -EINVAL);
|
||||||
assert_return(ret, -EINVAL);
|
assert_return(addrs, -EINVAL);
|
||||||
|
|
||||||
if (lease->ntp) {
|
if (lease->ntp_count) {
|
||||||
*ret = lease->ntp;
|
*addrs = lease->ntp;
|
||||||
return lease->ntp_count;
|
return lease->ntp_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lease->sntp && !lease->ntp_fqdn) {
|
return -ENOENT;
|
||||||
/* Fallback to the deprecated SNTP option. */
|
}
|
||||||
*ret = lease->sntp;
|
|
||||||
return lease->sntp_count;
|
int sd_dhcp6_lease_get_ntp_fqdn(sd_dhcp6_lease *lease, char ***ntp_fqdn) {
|
||||||
|
assert_return(lease, -EINVAL);
|
||||||
|
assert_return(ntp_fqdn, -EINVAL);
|
||||||
|
|
||||||
|
if (lease->ntp_fqdn_count) {
|
||||||
|
*ntp_fqdn = lease->ntp_fqdn;
|
||||||
|
return lease->ntp_fqdn_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
}
|
}
|
||||||
|
|
||||||
int sd_dhcp6_lease_get_ntp_fqdn(sd_dhcp6_lease *lease, char ***ret) {
|
int dhcp6_lease_set_fqdn(sd_dhcp6_lease *lease, const uint8_t *optval,
|
||||||
assert_return(lease, -EINVAL);
|
size_t optlen) {
|
||||||
assert_return(ret, -EINVAL);
|
|
||||||
|
|
||||||
if (!lease->ntp_fqdn)
|
|
||||||
return -ENOENT;
|
|
||||||
|
|
||||||
*ret = lease->ntp_fqdn;
|
|
||||||
return strv_length(lease->ntp_fqdn);
|
|
||||||
}
|
|
||||||
|
|
||||||
int dhcp6_lease_set_fqdn(sd_dhcp6_lease *lease, const uint8_t *optval, size_t optlen) {
|
|
||||||
int r;
|
int r;
|
||||||
char *fqdn;
|
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);
|
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(lease, -EINVAL);
|
||||||
assert_return(ret, -EINVAL);
|
assert_return(fqdn, -EINVAL);
|
||||||
|
|
||||||
if (!lease->fqdn)
|
if (lease->fqdn) {
|
||||||
return -ENOENT;
|
*fqdn = lease->fqdn;
|
||||||
|
|
||||||
*ret = lease->fqdn;
|
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -ENOENT;
|
||||||
}
|
}
|
||||||
|
|
||||||
static sd_dhcp6_lease *dhcp6_lease_free(sd_dhcp6_lease *lease) {
|
static sd_dhcp6_lease *dhcp6_lease_free(sd_dhcp6_lease *lease) {
|
||||||
if (!lease)
|
assert(lease);
|
||||||
return NULL;
|
|
||||||
|
|
||||||
free(lease->serverid);
|
free(lease->serverid);
|
||||||
dhcp6_lease_free_ia(&lease->ia);
|
dhcp6_lease_free_ia(&lease->ia);
|
||||||
dhcp6_lease_free_ia(&lease->pd);
|
dhcp6_lease_free_ia(&lease->pd);
|
||||||
|
|
||||||
free(lease->dns);
|
free(lease->dns);
|
||||||
free(lease->fqdn);
|
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);
|
return mfree(lease);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -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,
|
data = (uint8_t []) { 7, 'e', 'x', 'a', 'm', 'p', 'l', 'e', 3, 'c', 'o', 'm', 0,
|
||||||
6, 'f', 'o', 'o', 'b', 'a', 'r', 0 };
|
6, 'f', 'o', 'o', 'b', 'a', 'r', 0 };
|
||||||
r = dhcp6_option_parse_domainname_list(data, 21, &list);
|
r = dhcp6_option_parse_domainname_list(data, 21, &list);
|
||||||
assert_se(r == 0);
|
assert_se(r == 2);
|
||||||
assert_se(list);
|
assert_se(list);
|
||||||
assert_se(streq(list[0], "example.com"));
|
assert_se(streq(list[0], "example.com"));
|
||||||
assert_se(streq(list[1], "foobar"));
|
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) {
|
static int test_option(sd_event *e) {
|
||||||
uint8_t packet[] = {
|
uint8_t packet[] = {
|
||||||
'F', 'O', 'O', 'H', 'O', 'G', 'E',
|
'F', 'O', 'O',
|
||||||
0x00, SD_DHCP6_OPTION_ORO, 0x00, 0x07,
|
0x00, SD_DHCP6_OPTION_ORO, 0x00, 0x07,
|
||||||
'A', 'B', 'C', 'D', 'E', 'F', 'G',
|
'A', 'B', 'C', 'D', 'E', 'F', 'G',
|
||||||
0x00, SD_DHCP6_OPTION_VENDOR_CLASS, 0x00, 0x09,
|
0x00, SD_DHCP6_OPTION_VENDOR_CLASS, 0x00, 0x09,
|
||||||
@ -164,66 +164,53 @@ static int test_option(sd_event *e) {
|
|||||||
'B', 'A', 'R',
|
'B', 'A', 'R',
|
||||||
};
|
};
|
||||||
uint8_t result[] = {
|
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,
|
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',
|
'B', 'A', 'R',
|
||||||
};
|
};
|
||||||
_cleanup_free_ uint8_t *buf = NULL;
|
|
||||||
size_t offset, pos, optlen, outlen = sizeof(result);
|
|
||||||
const uint8_t *optval;
|
|
||||||
uint16_t optcode;
|
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__);
|
log_debug("/* %s */", __func__);
|
||||||
|
|
||||||
assert_se(sizeof(packet) == sizeof(result));
|
assert_se(buflen == outlen);
|
||||||
|
|
||||||
offset = 0;
|
assert_se(dhcp6_option_parse(&buf, &zero, &optcode, &optlen,
|
||||||
assert_se(dhcp6_option_parse(packet, 0, &offset, &optcode, &optlen, &optval) == -EBADMSG);
|
&optval) == -ENOMSG);
|
||||||
|
|
||||||
offset = 3;
|
buflen -= 3;
|
||||||
assert_se(dhcp6_option_parse(packet, 0, &offset, &optcode, &optlen, &optval) == -EBADMSG);
|
buf = &packet[3];
|
||||||
|
outlen -= 3;
|
||||||
/* Tests for reading unaligned data. */
|
out = &result[3];
|
||||||
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);
|
|
||||||
|
|
||||||
assert_se(optcode == SD_DHCP6_OPTION_ORO);
|
|
||||||
assert_se(optlen == 7);
|
|
||||||
assert_se(optval == packet + 11);
|
|
||||||
|
|
||||||
pos = 7;
|
|
||||||
outlen -= 7;
|
|
||||||
out = &result[pos];
|
|
||||||
|
|
||||||
assert_se(dhcp6_option_append(&out, &outlen, optcode, optlen, optval) >= 0);
|
|
||||||
|
|
||||||
|
assert_se(dhcp6_option_parse(&buf, &buflen, &optcode, &optlen,
|
||||||
|
&optval) >= 0);
|
||||||
pos += 4 + optlen;
|
pos += 4 + optlen;
|
||||||
|
assert_se(buf == &packet[pos]);
|
||||||
|
assert_se(optcode == SD_DHCP6_OPTION_ORO);
|
||||||
|
assert_se(optlen == 7);
|
||||||
|
assert_se(buflen + pos == sizeof(packet));
|
||||||
|
|
||||||
|
assert_se(dhcp6_option_append(&out, &outlen, optcode, optlen,
|
||||||
|
optval) >= 0);
|
||||||
assert_se(out == &result[pos]);
|
assert_se(out == &result[pos]);
|
||||||
assert_se(*out == 0x00);
|
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(optcode == SD_DHCP6_OPTION_VENDOR_CLASS);
|
||||||
assert_se(optlen == 9);
|
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);
|
assert_se(dhcp6_option_append(&out, &outlen, optcode, optlen,
|
||||||
|
optval) >= 0);
|
||||||
pos += 4 + optlen;
|
|
||||||
assert_se(out == &result[pos]);
|
assert_se(out == &result[pos]);
|
||||||
assert_se(*out == 'B');
|
assert_se(*out == 'B');
|
||||||
|
|
||||||
@ -249,7 +236,7 @@ static int test_option_status(sd_event *e) {
|
|||||||
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
|
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
|
||||||
0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
|
0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
|
||||||
0x01, 0x02, 0x03, 0x04, 0x0a, 0x0b, 0x0c, 0x0d,
|
0x01, 0x02, 0x03, 0x04, 0x0a, 0x0b, 0x0c, 0x0d,
|
||||||
/* IA address status option */
|
/* status option */
|
||||||
0x00, 0x0d, 0x00, 0x02, 0x00, 0x01,
|
0x00, 0x0d, 0x00, 0x02, 0x00, 0x01,
|
||||||
};
|
};
|
||||||
static const uint8_t option3[] = {
|
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,
|
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
|
||||||
0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
|
0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
|
||||||
0x01, 0x02, 0x03, 0x04, 0x0a, 0x0b, 0x0c, 0x0d,
|
0x01, 0x02, 0x03, 0x04, 0x0a, 0x0b, 0x0c, 0x0d,
|
||||||
/* IA address status option */
|
/* status option */
|
||||||
0x00, 0x0d, 0x00, 0x08, 0x00, 0x00, 'f', 'o',
|
0x00, 0x0d, 0x00, 0x08, 0x00, 0x00, 'f', 'o',
|
||||||
'o', 'b', 'a', 'r',
|
'o', 'b', 'a', 'r',
|
||||||
};
|
};
|
||||||
@ -275,7 +262,7 @@ static int test_option_status(sd_event *e) {
|
|||||||
0x80, 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe,
|
0x80, 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe,
|
||||||
0xef, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
0xef, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
0x00,
|
0x00,
|
||||||
/* PD prefix status option */
|
/* status option */
|
||||||
0x00, 0x0d, 0x00, 0x02, 0x00, 0x00,
|
0x00, 0x0d, 0x00, 0x02, 0x00, 0x00,
|
||||||
};
|
};
|
||||||
static const uint8_t option5[] = {
|
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,
|
0x80, 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe,
|
||||||
0xef, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
0xef, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
0x00,
|
0x00,
|
||||||
/* PD prefix status option */
|
/* status option */
|
||||||
0x00, 0x0d, 0x00, 0x02, 0x00, 0x00,
|
0x00, 0x0d, 0x00, 0x02, 0x00, 0x00,
|
||||||
/* IA PD Prefix #2 */
|
/* IA PD Prefix #2 */
|
||||||
0x00, 0x1a, 0x00, 0x1f,
|
0x00, 0x1a, 0x00, 0x1f,
|
||||||
@ -296,7 +283,6 @@ static int test_option_status(sd_event *e) {
|
|||||||
0x80, 0x20, 0x01, 0x0d, 0xb8, 0xc0, 0x0l, 0xd0,
|
0x80, 0x20, 0x01, 0x0d, 0xb8, 0xc0, 0x0l, 0xd0,
|
||||||
0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
0x00,
|
0x00,
|
||||||
/* PD prefix status option */
|
|
||||||
0x00, 0x0d, 0x00, 0x02, 0x00, 0x00,
|
0x00, 0x0d, 0x00, 0x02, 0x00, 0x00,
|
||||||
};
|
};
|
||||||
DHCP6Option *option;
|
DHCP6Option *option;
|
||||||
@ -309,62 +295,62 @@ static int test_option_status(sd_event *e) {
|
|||||||
memcpy(&iaid, option1 + 4, sizeof(iaid));
|
memcpy(&iaid, option1 + 4, sizeof(iaid));
|
||||||
|
|
||||||
zero(ia);
|
zero(ia);
|
||||||
option = (DHCP6Option*) option1;
|
option = (DHCP6Option *)option1;
|
||||||
assert_se(sizeof(option1) == sizeof(DHCP6Option) + be16toh(option->len));
|
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);
|
assert_se(r == -ENOANO);
|
||||||
|
|
||||||
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 == -EINVAL);
|
assert_se(r == 0);
|
||||||
assert_se(!ia.addresses);
|
assert_se(ia.addresses == NULL);
|
||||||
|
|
||||||
option->len = htobe16(17);
|
option->len = htobe16(17);
|
||||||
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 == -EBADMSG);
|
assert_se(r == -ENOBUFS);
|
||||||
assert_se(!ia.addresses);
|
assert_se(ia.addresses == NULL);
|
||||||
|
|
||||||
option->len = htobe16(sizeof(DHCP6Option));
|
option->len = htobe16(sizeof(DHCP6Option));
|
||||||
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 == -EBADMSG);
|
assert_se(r == -ENOBUFS);
|
||||||
assert_se(!ia.addresses);
|
assert_se(ia.addresses == NULL);
|
||||||
|
|
||||||
zero(ia);
|
zero(ia);
|
||||||
option = (DHCP6Option*) option2;
|
option = (DHCP6Option *)option2;
|
||||||
assert_se(sizeof(option2) == sizeof(DHCP6Option) + be16toh(option->len));
|
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);
|
r = dhcp6_option_parse_ia(NULL, option, iaid, &ia, NULL);
|
||||||
assert_se(r == -ENODATA);
|
assert_se(r >= 0);
|
||||||
assert_se(!ia.addresses);
|
assert_se(ia.addresses == NULL);
|
||||||
|
|
||||||
zero(ia);
|
zero(ia);
|
||||||
option = (DHCP6Option*) option3;
|
option = (DHCP6Option *)option3;
|
||||||
assert_se(sizeof(option3) == sizeof(DHCP6Option) + be16toh(option->len));
|
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(r >= 0);
|
||||||
assert_se(ia.addresses);
|
assert_se(ia.addresses != NULL);
|
||||||
dhcp6_lease_free_ia(&ia);
|
dhcp6_lease_free_ia(&ia);
|
||||||
|
|
||||||
zero(pd);
|
zero(pd);
|
||||||
option = (DHCP6Option*) option4;
|
option = (DHCP6Option *)option4;
|
||||||
assert_se(sizeof(option4) == sizeof(DHCP6Option) + be16toh(option->len));
|
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(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.id, &option4[4], 4) == 0);
|
||||||
assert_se(memcmp(&pd.ia_pd.lifetime_t1, &option4[8], 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);
|
assert_se(memcmp(&pd.ia_pd.lifetime_t2, &option4[12], 4) == 0);
|
||||||
dhcp6_lease_free_ia(&pd);
|
dhcp6_lease_free_ia(&pd);
|
||||||
|
|
||||||
zero(pd);
|
zero(pd);
|
||||||
option = (DHCP6Option*) option5;
|
option = (DHCP6Option *)option5;
|
||||||
assert_se(sizeof(option5) == sizeof(DHCP6Option) + be16toh(option->len));
|
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(r >= 0);
|
||||||
assert_se(pd.addresses);
|
assert_se(pd.addresses != NULL);
|
||||||
dhcp6_lease_free_ia(&pd);
|
dhcp6_lease_free_ia(&pd);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -482,7 +468,7 @@ static int test_advertise_option(sd_event *e) {
|
|||||||
val = htobe32(120);
|
val = htobe32(120);
|
||||||
assert_se(!memcmp(optval + 8, &val, sizeof(val)));
|
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;
|
break;
|
||||||
}
|
}
|
||||||
@ -510,17 +496,20 @@ static int test_advertise_option(sd_event *e) {
|
|||||||
|
|
||||||
case SD_DHCP6_OPTION_DNS_SERVERS:
|
case SD_DHCP6_OPTION_DNS_SERVERS:
|
||||||
assert_se(optlen == 16);
|
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;
|
break;
|
||||||
|
|
||||||
case SD_DHCP6_OPTION_DOMAIN_LIST:
|
case SD_DHCP6_OPTION_DOMAIN_LIST:
|
||||||
assert_se(optlen == 11);
|
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;
|
break;
|
||||||
|
|
||||||
case SD_DHCP6_OPTION_SNTP_SERVERS:
|
case SD_DHCP6_OPTION_SNTP_SERVERS:
|
||||||
assert_se(optlen == 16);
|
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;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@ -676,7 +665,7 @@ static int test_client_verify_request(DHCP6Message *request, size_t len) {
|
|||||||
assert_se(!memcmp(optval + 8, &val, sizeof(val)));
|
assert_se(!memcmp(optval + 8, &val, sizeof(val)));
|
||||||
|
|
||||||
/* Then, this should refuse all addresses. */
|
/* 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;
|
break;
|
||||||
|
|
||||||
|
|||||||
@ -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);
|
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(
|
static int genl_family_new(
|
||||||
sd_netlink *nl,
|
sd_netlink *nl,
|
||||||
const char *expected_family_name,
|
const char *expected_family_name,
|
||||||
@ -115,6 +79,28 @@ static int genl_family_new(
|
|||||||
.type_system = type_system,
|
.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);
|
r = sd_genl_message_get_family_name(nl, message, &family_name);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
@ -275,10 +261,9 @@ static int genl_family_get_by_name_internal(
|
|||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
if (sd_netlink_call(nl, req, 0, &reply) < 0) {
|
r = sd_netlink_call(nl, req, 0, &reply);
|
||||||
(void) genl_family_new_unsupported(nl, name, type_system);
|
if (r < 0)
|
||||||
return -EOPNOTSUPP;
|
return r;
|
||||||
}
|
|
||||||
|
|
||||||
return genl_family_new(nl, name, type_system, reply, ret);
|
return genl_family_new(nl, name, type_system, reply, ret);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -123,8 +123,8 @@ struct sd_netlink_message {
|
|||||||
struct nlmsghdr *hdr;
|
struct nlmsghdr *hdr;
|
||||||
struct netlink_container containers[NETLINK_CONTAINER_DEPTH];
|
struct netlink_container containers[NETLINK_CONTAINER_DEPTH];
|
||||||
unsigned n_containers; /* number of containers */
|
unsigned n_containers; /* number of containers */
|
||||||
uint32_t multicast_group;
|
|
||||||
bool sealed:1;
|
bool sealed:1;
|
||||||
|
bool broadcast:1;
|
||||||
|
|
||||||
sd_netlink_message *next; /* next in a chain of multi-part messages */
|
sd_netlink_message *next; /* next in a chain of multi-part messages */
|
||||||
};
|
};
|
||||||
|
|||||||
@ -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) {
|
int sd_netlink_message_request_dump(sd_netlink_message *m, int dump) {
|
||||||
assert_return(m, -EINVAL);
|
assert_return(m, -EINVAL);
|
||||||
assert_return(m->hdr, -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_GETLINK, RTM_GETLINKPROP, RTM_GETADDR, RTM_GETROUTE, RTM_GETNEIGH,
|
||||||
RTM_GETRULE, RTM_GETADDRLABEL, RTM_GETNEXTHOP), -EINVAL);
|
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) {
|
int sd_netlink_message_is_broadcast(sd_netlink_message *m) {
|
||||||
assert_return(m, -EINVAL);
|
assert_return(m, -EINVAL);
|
||||||
|
|
||||||
return m->multicast_group != 0;
|
return m->broadcast;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If successful the updated message will be correctly aligned, if
|
/* 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) {
|
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;
|
int r;
|
||||||
|
|
||||||
assert_return(m, -EINVAL);
|
assert_return(m, -EINVAL);
|
||||||
@ -761,8 +761,6 @@ int sd_netlink_message_read_data(sd_netlink_message *m, unsigned short type, siz
|
|||||||
return r;
|
return r;
|
||||||
|
|
||||||
if (ret_data) {
|
if (ret_data) {
|
||||||
void *data;
|
|
||||||
|
|
||||||
data = memdup(attr_data, r);
|
data = memdup(attr_data, r);
|
||||||
if (!data)
|
if (!data)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
@ -776,34 +774,9 @@ int sd_netlink_message_read_data(sd_netlink_message *m, unsigned short type, siz
|
|||||||
return r;
|
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) {
|
int sd_netlink_message_read_string_strdup(sd_netlink_message *m, unsigned short type, char **data) {
|
||||||
void *attr_data;
|
void *attr_data;
|
||||||
|
char *str;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
assert_return(m, -EINVAL);
|
assert_return(m, -EINVAL);
|
||||||
@ -817,8 +790,6 @@ int sd_netlink_message_read_string_strdup(sd_netlink_message *m, unsigned short
|
|||||||
return r;
|
return r;
|
||||||
|
|
||||||
if (data) {
|
if (data) {
|
||||||
char *str;
|
|
||||||
|
|
||||||
str = strndup(attr_data, r);
|
str = strndup(attr_data, r);
|
||||||
if (!str)
|
if (!str)
|
||||||
return -ENOMEM;
|
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) {
|
int sd_netlink_message_read_string(sd_netlink_message *m, unsigned short type, const char **data) {
|
||||||
void *attr_data;
|
|
||||||
int r;
|
int r;
|
||||||
|
void *attr_data;
|
||||||
|
|
||||||
assert_return(m, -EINVAL);
|
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);
|
r = netlink_message_read_internal(m, type, &attr_data, NULL);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
else if (strnlen(attr_data, r) >= (size_t) r)
|
||||||
if (strnlen(attr_data, r) >= (size_t) r)
|
|
||||||
return -EIO;
|
return -EIO;
|
||||||
|
|
||||||
if (data)
|
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) {
|
int sd_netlink_message_read_u8(sd_netlink_message *m, unsigned short type, uint8_t *data) {
|
||||||
void *attr_data;
|
|
||||||
int r;
|
int r;
|
||||||
|
void *attr_data;
|
||||||
|
|
||||||
assert_return(m, -EINVAL);
|
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);
|
r = netlink_message_read_internal(m, type, &attr_data, NULL);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
else if ((size_t) r < sizeof(uint8_t))
|
||||||
if ((size_t) r < sizeof(uint8_t))
|
|
||||||
return -EIO;
|
return -EIO;
|
||||||
|
|
||||||
if (data)
|
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);
|
r = netlink_message_read_internal(m, type, &attr_data, &net_byteorder);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
else if ((size_t) r < sizeof(uint16_t))
|
||||||
if ((size_t) r < sizeof(uint16_t))
|
|
||||||
return -EIO;
|
return -EIO;
|
||||||
|
|
||||||
if (data) {
|
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);
|
r = netlink_message_read_internal(m, type, &attr_data, &net_byteorder);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
else if ((size_t) r < sizeof(uint32_t))
|
||||||
if ((size_t) r < sizeof(uint32_t))
|
|
||||||
return -EIO;
|
return -EIO;
|
||||||
|
|
||||||
if (data) {
|
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) {
|
int sd_netlink_message_read_ether_addr(sd_netlink_message *m, unsigned short type, struct ether_addr *data) {
|
||||||
void *attr_data;
|
|
||||||
int r;
|
int r;
|
||||||
|
void *attr_data;
|
||||||
|
|
||||||
assert_return(m, -EINVAL);
|
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);
|
r = netlink_message_read_internal(m, type, &attr_data, NULL);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
else if ((size_t) r < sizeof(struct ether_addr))
|
||||||
if ((size_t) r < sizeof(struct ether_addr))
|
|
||||||
return -EIO;
|
return -EIO;
|
||||||
|
|
||||||
if (data)
|
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) {
|
int netlink_message_read_hw_addr(sd_netlink_message *m, unsigned short type, struct hw_addr_data *data) {
|
||||||
void *attr_data;
|
|
||||||
int r;
|
int r;
|
||||||
|
void *attr_data;
|
||||||
|
|
||||||
assert_return(m, -EINVAL);
|
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);
|
r = netlink_message_read_internal(m, type, &attr_data, NULL);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
else if (r > HW_ADDR_MAX_SIZE)
|
||||||
if (r > HW_ADDR_MAX_SIZE)
|
|
||||||
return -EIO;
|
return -EIO;
|
||||||
|
|
||||||
if (data) {
|
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) {
|
int sd_netlink_message_read_cache_info(sd_netlink_message *m, unsigned short type, struct ifa_cacheinfo *info) {
|
||||||
void *attr_data;
|
|
||||||
int r;
|
int r;
|
||||||
|
void *attr_data;
|
||||||
|
|
||||||
assert_return(m, -EINVAL);
|
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);
|
r = netlink_message_read_internal(m, type, &attr_data, NULL);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
else if ((size_t) r < sizeof(struct ifa_cacheinfo))
|
||||||
if ((size_t) r < sizeof(struct ifa_cacheinfo))
|
|
||||||
return -EIO;
|
return -EIO;
|
||||||
|
|
||||||
if (info)
|
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);
|
r = netlink_message_read_internal(m, type, &attr_data, NULL);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
else if ((size_t) r < FAMILY_ADDRESS_SIZE(family))
|
||||||
if ((size_t) r < FAMILY_ADDRESS_SIZE(family))
|
|
||||||
return -EIO;
|
return -EIO;
|
||||||
|
|
||||||
if (data)
|
if (data)
|
||||||
|
|||||||
@ -81,11 +81,13 @@ int socket_bind(sd_netlink *nl) {
|
|||||||
|
|
||||||
addrlen = sizeof(nl->sockaddr);
|
addrlen = sizeof(nl->sockaddr);
|
||||||
|
|
||||||
|
r = bind(nl->fd, &nl->sockaddr.sa, addrlen);
|
||||||
/* ignore EINVAL to allow binding an already bound socket */
|
/* 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;
|
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 -errno;
|
||||||
|
|
||||||
return broadcast_groups_get(nl);
|
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;
|
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
|
||||||
size_t size;
|
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 */
|
/* not broadcast and not for us */
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@ -363,7 +365,8 @@ int socket_read_message(sd_netlink *nl) {
|
|||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
m->multicast_group = group;
|
m->broadcast = !!group;
|
||||||
|
|
||||||
m->hdr = memdup(new_msg, new_msg->nlmsg_len);
|
m->hdr = memdup(new_msg, new_msg->nlmsg_len);
|
||||||
if (!m->hdr)
|
if (!m->hdr)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|||||||
@ -11,7 +11,6 @@
|
|||||||
#include <linux/nl80211.h>
|
#include <linux/nl80211.h>
|
||||||
#include <linux/wireguard.h>
|
#include <linux/wireguard.h>
|
||||||
|
|
||||||
#include "missing_network.h"
|
|
||||||
#include "netlink-genl.h"
|
#include "netlink-genl.h"
|
||||||
#include "netlink-types-internal.h"
|
#include "netlink-types-internal.h"
|
||||||
|
|
||||||
@ -180,15 +179,10 @@ static const NLType genl_macsec_types[] = {
|
|||||||
|
|
||||||
/***************** genl nl80211 type systems *****************/
|
/***************** genl nl80211 type systems *****************/
|
||||||
static const NLType genl_nl80211_types[] = {
|
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_IFINDEX] = { .type = NETLINK_TYPE_U32 },
|
||||||
[NL80211_ATTR_IFNAME] = { .type = NETLINK_TYPE_STRING, .size = IFNAMSIZ-1 },
|
[NL80211_ATTR_MAC] = { .type = NETLINK_TYPE_ETHER_ADDR },
|
||||||
|
[NL80211_ATTR_SSID] = { .type = NETLINK_TYPE_STRING },
|
||||||
[NL80211_ATTR_IFTYPE] = { .type = NETLINK_TYPE_U32 },
|
[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 },
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/***************** genl wireguard type systems *****************/
|
/***************** genl wireguard type systems *****************/
|
||||||
|
|||||||
@ -116,16 +116,6 @@ int rtnl_log_create_error(int r);
|
|||||||
userdata, description); \
|
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_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_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);
|
int netlink_message_append_sockaddr_union(sd_netlink_message *m, unsigned short type, const union sockaddr_union *data);
|
||||||
|
|||||||
@ -81,7 +81,8 @@ int sd_netlink_new_from_fd(sd_netlink **ret, int fd) {
|
|||||||
|
|
||||||
addrlen = sizeof(nl->sockaddr);
|
addrlen = sizeof(nl->sockaddr);
|
||||||
|
|
||||||
if (getsockname(fd, &nl->sockaddr.sa, &addrlen) < 0)
|
r = getsockname(fd, &nl->sockaddr.sa, &addrlen);
|
||||||
|
if (r < 0)
|
||||||
return -errno;
|
return -errno;
|
||||||
|
|
||||||
if (nl->sockaddr.nl.nl_family != AF_NETLINK)
|
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) {
|
LIST_FOREACH(match_callbacks, c, nl->match_callbacks) {
|
||||||
sd_netlink_slot *slot;
|
sd_netlink_slot *slot;
|
||||||
bool found = false;
|
|
||||||
|
|
||||||
if (c->type != type)
|
if (c->type != type)
|
||||||
continue;
|
continue;
|
||||||
if (c->cmd != 0 && c->cmd != cmd)
|
if (c->cmd != 0 && c->cmd != cmd)
|
||||||
continue;
|
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);
|
slot = container_of(c, sd_netlink_slot, match_callback);
|
||||||
|
|
||||||
r = c->callback(nl, m, slot->userdata);
|
r = c->callback(nl, m, slot->userdata);
|
||||||
@ -492,12 +483,15 @@ static int process_running(sd_netlink *nl, sd_netlink_message **ret) {
|
|||||||
if (!m)
|
if (!m)
|
||||||
goto null_message;
|
goto null_message;
|
||||||
|
|
||||||
if (sd_netlink_message_is_broadcast(m))
|
if (sd_netlink_message_is_broadcast(m)) {
|
||||||
r = process_match(nl, m);
|
r = process_match(nl, m);
|
||||||
else
|
if (r != 0)
|
||||||
|
goto null_message;
|
||||||
|
} else {
|
||||||
r = process_reply(nl, m);
|
r = process_reply(nl, m);
|
||||||
if (r != 0)
|
if (r != 0)
|
||||||
goto null_message;
|
goto null_message;
|
||||||
|
}
|
||||||
|
|
||||||
if (ret) {
|
if (ret) {
|
||||||
*ret = TAKE_PTR(m);
|
*ret = TAKE_PTR(m);
|
||||||
|
|||||||
@ -19,7 +19,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
|
|||||||
assert_se(fwrite(data, size, 1, f) == 1);
|
assert_se(fwrite(data, size, 1, f) == 1);
|
||||||
|
|
||||||
fflush(f);
|
fflush(f);
|
||||||
assert_se(manager_new(&manager, /* test_mode = */ true) >= 0);
|
assert_se(manager_new(&manager) >= 0);
|
||||||
(void) netdev_load_one(manager, netdev_config);
|
(void) netdev_load_one(manager, netdev_config);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -22,7 +22,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
|
|||||||
assert_se(fwrite(data, size, 1, f) == 1);
|
assert_se(fwrite(data, size, 1, f) == 1);
|
||||||
|
|
||||||
fflush(f);
|
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);
|
(void) network_load_one(manager, &manager->networks, network_config);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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)
|
if (l2tp_acquire_local_address_one(t, a, ret) >= 0)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
|
SET_FOREACH(a, link->addresses_foreign)
|
||||||
|
if (l2tp_acquire_local_address_one(t, a, ret) >= 0)
|
||||||
|
return 1;
|
||||||
|
|
||||||
return -ENODATA;
|
return -ENODATA;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -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))
|
if (in_addr_prefix_intersect(p->family, u, prefixlen, &a->in_addr, a->prefixlen))
|
||||||
return true;
|
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 */
|
/* And don't clash with configured but un-assigned addresses either */
|
||||||
|
|||||||
@ -9,12 +9,10 @@
|
|||||||
#include "netlink-util.h"
|
#include "netlink-util.h"
|
||||||
#include "networkd-address-pool.h"
|
#include "networkd-address-pool.h"
|
||||||
#include "networkd-address.h"
|
#include "networkd-address.h"
|
||||||
#include "networkd-dhcp-server.h"
|
|
||||||
#include "networkd-ipv4acd.h"
|
#include "networkd-ipv4acd.h"
|
||||||
#include "networkd-manager.h"
|
#include "networkd-manager.h"
|
||||||
#include "networkd-network.h"
|
#include "networkd-network.h"
|
||||||
#include "networkd-queue.h"
|
#include "networkd-queue.h"
|
||||||
#include "networkd-route.h"
|
|
||||||
#include "parse-util.h"
|
#include "parse-util.h"
|
||||||
#include "string-util.h"
|
#include "string-util.h"
|
||||||
#include "strv.h"
|
#include "strv.h"
|
||||||
@ -133,7 +131,7 @@ static int address_new_static(Network *network, const char *filename, unsigned s
|
|||||||
|
|
||||||
address->network = network;
|
address->network = network;
|
||||||
address->section = TAKE_PTR(n);
|
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);
|
r = ordered_hashmap_ensure_put(&network->addresses_by_section, &network_config_hash_ops, address->section, address);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
@ -153,7 +151,23 @@ Address *address_free(Address *address) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (address->link) {
|
if (address->link) {
|
||||||
|
NDiscAddress *n;
|
||||||
|
|
||||||
set_remove(address->link->addresses, address);
|
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 &&
|
if (address->family == AF_INET6 &&
|
||||||
in6_addr_equal(&address->in_addr.in6, &address->link->ipv6ll_address))
|
in6_addr_equal(&address->in_addr.in6, &address->link->ipv6ll_address))
|
||||||
@ -167,41 +181,6 @@ Address *address_free(Address *address) {
|
|||||||
return mfree(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) {
|
static bool address_may_have_broadcast(const Address *a) {
|
||||||
assert(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);
|
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) {
|
int address_dup(const Address *src, Address **ret) {
|
||||||
_cleanup_(address_freep) Address *dest = NULL;
|
_cleanup_(address_freep) Address *dest = NULL;
|
||||||
int r;
|
int r;
|
||||||
@ -382,19 +371,67 @@ static int address_set_masquerade(Address *address, bool add) {
|
|||||||
return 0;
|
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;
|
int r;
|
||||||
|
|
||||||
assert(link);
|
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)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
if (r == 0)
|
if (r == 0)
|
||||||
return -EEXIST;
|
return -EEXIST;
|
||||||
|
|
||||||
address->link = link;
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -404,13 +441,13 @@ static int address_update(Address *address, const Address *src) {
|
|||||||
|
|
||||||
assert(address);
|
assert(address);
|
||||||
assert(address->link);
|
assert(address->link);
|
||||||
|
assert(src);
|
||||||
|
|
||||||
link = address->link;
|
link = address->link;
|
||||||
if (src) {
|
|
||||||
address->flags = src->flags;
|
address->flags = src->flags;
|
||||||
address->scope = src->scope;
|
address->scope = src->scope;
|
||||||
address->cinfo = src->cinfo;
|
address->cinfo = src->cinfo;
|
||||||
}
|
|
||||||
|
|
||||||
if (address_is_ready(address) &&
|
if (address_is_ready(address) &&
|
||||||
address->family == AF_INET6 &&
|
address->family == AF_INET6 &&
|
||||||
@ -447,8 +484,8 @@ static int address_drop(Address *address) {
|
|||||||
bool ready;
|
bool ready;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
assert(address);
|
if (!address)
|
||||||
assert(address->link);
|
return 0;
|
||||||
|
|
||||||
ready = address_is_ready(address);
|
ready = address_is_ready(address);
|
||||||
link = address->link;
|
link = address->link;
|
||||||
@ -457,7 +494,6 @@ static int address_drop(Address *address) {
|
|||||||
if (r < 0)
|
if (r < 0)
|
||||||
log_link_warning_errno(link, r, "Failed to disable IP masquerading, ignoring: %m");
|
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);
|
link_update_operstate(link, true);
|
||||||
@ -475,12 +511,20 @@ int address_get(Link *link, const Address *in, Address **ret) {
|
|||||||
assert(in);
|
assert(in);
|
||||||
|
|
||||||
existing = set_get(link->addresses, in);
|
existing = set_get(link->addresses, in);
|
||||||
if (!existing)
|
if (existing) {
|
||||||
return -ENOENT;
|
if (ret)
|
||||||
|
*ret = existing;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
existing = set_get(link->addresses_foreign, in);
|
||||||
|
if (existing) {
|
||||||
if (ret)
|
if (ret)
|
||||||
*ret = existing;
|
*ret = existing;
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -ENOENT;
|
||||||
}
|
}
|
||||||
|
|
||||||
int link_get_ipv6_address(Link *link, const struct in6_addr *address, Address **ret) {
|
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);
|
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 link_get_ipv4_address(Link *link, const struct in_addr *address, unsigned char prefixlen, Address **ret) {
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
@ -522,24 +587,11 @@ int link_get_ipv4_address(Link *link, const struct in_addr *address, unsigned ch
|
|||||||
a->prefixlen = prefixlen;
|
a->prefixlen = prefixlen;
|
||||||
|
|
||||||
return address_get(link, a, ret);
|
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;
|
|
||||||
|
|
||||||
|
if (addresses_get_ipv4_address(link->addresses, address, ret) >= 0)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
return addresses_get_ipv4_address(link->addresses_foreign, address, ret);
|
||||||
|
|
||||||
return -ENOENT;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int manager_has_address(Manager *manager, int family, const union in_addr_union *address, bool check_ready) {
|
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) {
|
if (family == AF_INET) {
|
||||||
HASHMAP_FOREACH(link, manager->links_by_index)
|
HASHMAP_FOREACH(link, manager->links_by_index)
|
||||||
if (link_get_ipv4_address(link, &address->in, 0, &a) >= 0)
|
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 {
|
} else {
|
||||||
_cleanup_(address_freep) Address *tmp = NULL;
|
_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)
|
HASHMAP_FOREACH(link, manager->links_by_index)
|
||||||
if (address_get(link, tmp, &a) >= 0)
|
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;
|
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) {
|
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(address);
|
||||||
assert(str);
|
assert(str);
|
||||||
@ -596,16 +648,14 @@ static void log_address_debug(const Address *address, const char *str, const Lin
|
|||||||
if (!DEBUG_LOGGING)
|
if (!DEBUG_LOGGING)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
(void) network_config_state_to_string_alloc(address->state, &state);
|
|
||||||
(void) in_addr_to_string(address->family, &address->in_addr, &addr);
|
(void) in_addr_to_string(address->family, &address->in_addr, &addr);
|
||||||
if (in_addr_is_set(address->family, &address->in_addr_peer))
|
if (in_addr_is_set(address->family, &address->in_addr_peer))
|
||||||
(void) in_addr_to_string(address->family, &address->in_addr_peer, &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);
|
(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",
|
log_link_debug(link, "%s address: %s%s%s/%u (valid %s, preferred %s), flags: %s",
|
||||||
str, strna(network_config_source_to_string(address->source)), strna(state),
|
str, strnull(addr), peer ? " peer " : "", strempty(peer), address->prefixlen,
|
||||||
strnull(addr), peer ? " peer " : "", strempty(peer), address->prefixlen,
|
|
||||||
FORMAT_LIFETIME(address->cinfo.ifa_valid),
|
FORMAT_LIFETIME(address->cinfo.ifa_valid),
|
||||||
FORMAT_LIFETIME(address->cinfo.ifa_prefered),
|
FORMAT_LIFETIME(address->cinfo.ifa_prefered),
|
||||||
strna(flags_str));
|
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) {
|
static int address_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
|
assert(rtnl);
|
||||||
assert(m);
|
assert(m);
|
||||||
assert(link);
|
assert(link);
|
||||||
|
assert(link->address_remove_messages > 0);
|
||||||
|
|
||||||
|
link->address_remove_messages--;
|
||||||
|
|
||||||
if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
|
if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
|
||||||
return 0;
|
return 0;
|
||||||
@ -661,19 +715,16 @@ static int address_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, Link
|
|||||||
return 1;
|
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;
|
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
|
||||||
Link *link;
|
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
assert(address);
|
assert(address);
|
||||||
assert(IN_SET(address->family, AF_INET, AF_INET6));
|
assert(IN_SET(address->family, AF_INET, AF_INET6));
|
||||||
assert(address->link);
|
assert(link);
|
||||||
assert(address->link->ifindex > 0);
|
assert(link->ifindex > 0);
|
||||||
assert(address->link->manager);
|
assert(link->manager);
|
||||||
assert(address->link->manager->rtnl);
|
assert(link->manager->rtnl);
|
||||||
|
|
||||||
link = address->link;
|
|
||||||
|
|
||||||
log_address_debug(address, "Removing", link);
|
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");
|
return log_link_error_errno(link, r, "Could not send rtnetlink message: %m");
|
||||||
|
|
||||||
link_ref(link);
|
link_ref(link);
|
||||||
|
link->address_remove_messages++;
|
||||||
|
|
||||||
address_enter_removing(address);
|
|
||||||
return 0;
|
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) {
|
bool link_address_is_dynamic(const Link *link, const Address *address) {
|
||||||
Route *route;
|
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
|
/* 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
|
* without lifetime when KeepConfiguration=dhcp. So, let's check that we have
|
||||||
* corresponding routes with RTPROT_DHCP. */
|
* corresponding routes with RTPROT_DHCP. */
|
||||||
SET_FOREACH(route, link->routes) {
|
SET_FOREACH(route, link->routes_foreign) {
|
||||||
if (route->source != NETWORK_CONFIG_SOURCE_FOREIGN)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (route->protocol != RTPROT_DHCP)
|
if (route->protocol != RTPROT_DHCP)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@ -757,7 +821,6 @@ int link_drop_ipv6ll_addresses(Link *link) {
|
|||||||
_cleanup_(address_freep) Address *a = NULL;
|
_cleanup_(address_freep) Address *a = NULL;
|
||||||
unsigned char flags, prefixlen;
|
unsigned char flags, prefixlen;
|
||||||
struct in6_addr address;
|
struct in6_addr address;
|
||||||
Address *existing;
|
|
||||||
int ifindex;
|
int ifindex;
|
||||||
|
|
||||||
/* NETLINK_GET_STRICT_CHK socket option is supported since kernel 4.20. To support
|
/* 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->prefixlen = prefixlen;
|
||||||
a->flags = flags;
|
a->flags = flags;
|
||||||
|
|
||||||
if (address_get(link, a, &existing) < 0) {
|
r = address_remove(a, link);
|
||||||
r = address_add(link, a);
|
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
|
|
||||||
existing = TAKE_PTR(a);
|
|
||||||
}
|
|
||||||
|
|
||||||
r = address_remove(existing);
|
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
@ -824,80 +879,63 @@ int link_drop_foreign_addresses(Link *link) {
|
|||||||
int k, r = 0;
|
int k, r = 0;
|
||||||
|
|
||||||
assert(link);
|
assert(link);
|
||||||
assert(link->network);
|
|
||||||
|
|
||||||
/* First, mark all addresses. */
|
SET_FOREACH(address, link->addresses_foreign) {
|
||||||
SET_FOREACH(address, link->addresses) {
|
|
||||||
/* We consider IPv6LL addresses to be managed by the kernel, or dropped in link_drop_ipv6ll_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))
|
if (address->family == AF_INET6 && in6_addr_is_link_local(&address->in_addr.in6))
|
||||||
continue;
|
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_address_is_dynamic(link, address)) {
|
||||||
if (link->network && FLAGS_SET(link->network->keep_configuration, KEEP_CONFIGURATION_DHCP))
|
if (link->network && FLAGS_SET(link->network->keep_configuration, KEEP_CONFIGURATION_DHCP))
|
||||||
continue;
|
continue;
|
||||||
} else if (link->network && FLAGS_SET(link->network->keep_configuration, KEEP_CONFIGURATION_STATIC))
|
} else if (link->network && FLAGS_SET(link->network->keep_configuration, KEEP_CONFIGURATION_STATIC))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
address_mark(address);
|
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 {
|
||||||
/* Then, unmark requested addresses. */
|
k = address_remove(address, link);
|
||||||
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)
|
if (k < 0 && r >= 0)
|
||||||
r = k;
|
r = k;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
int link_drop_addresses(Link *link) {
|
int link_drop_addresses(Link *link) {
|
||||||
Address *address;
|
Address *address, *pool_address;
|
||||||
int k, r = 0;
|
int k, r = 0;
|
||||||
|
|
||||||
assert(link);
|
assert(link);
|
||||||
|
|
||||||
SET_FOREACH(address, link->addresses) {
|
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() */
|
/* 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))
|
if (address->family == AF_INET6 && in6_addr_is_link_local(&address->in_addr.in6))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
k = address_remove(address);
|
k = address_remove(address, link);
|
||||||
if (k < 0 && r >= 0) {
|
if (k < 0 && r >= 0) {
|
||||||
r = k;
|
r = k;
|
||||||
continue;
|
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;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int address_acquire(Link *link, const Address *original, Address **ret) {
|
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;
|
_cleanup_(address_freep) Address *na = NULL;
|
||||||
union in_addr_union in_addr;
|
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
assert(link);
|
assert(link);
|
||||||
@ -931,6 +969,12 @@ static int address_acquire(Link *link, const Address *original, Address **ret) {
|
|||||||
na->in_addr = in_addr;
|
na->in_addr = in_addr;
|
||||||
address_set_broadcast(na);
|
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);
|
*ret = TAKE_PTR(na);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@ -1019,25 +1063,6 @@ static int address_configure(
|
|||||||
return 0;
|
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) {
|
static int static_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
@ -1059,6 +1084,25 @@ static int static_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link
|
|||||||
return 1;
|
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(
|
int link_request_address(
|
||||||
Link *link,
|
Link *link,
|
||||||
Address *address,
|
Address *address,
|
||||||
@ -1067,72 +1111,50 @@ int link_request_address(
|
|||||||
link_netlink_message_handler_t netlink_handler,
|
link_netlink_message_handler_t netlink_handler,
|
||||||
Request **ret) {
|
Request **ret) {
|
||||||
|
|
||||||
Address *acquired, *existing;
|
Address *acquired;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
assert(link);
|
assert(link);
|
||||||
assert(address);
|
assert(address);
|
||||||
assert(address->source != NETWORK_CONFIG_SOURCE_FOREIGN);
|
|
||||||
|
|
||||||
r = address_acquire(link, address, &acquired);
|
r = address_acquire(link, address, &acquired);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_link_warning_errno(link, r, "Failed to acquire an address from pool: %m");
|
return log_link_warning_errno(link, r, "Failed to acquire an address from pool: %m");
|
||||||
if (r > 0) {
|
if (r > 0) {
|
||||||
if (consume_object)
|
if (consume_object) {
|
||||||
address_free(address);
|
address_free(address);
|
||||||
|
consume_object = false; /* address from pool is already managed by Link. */
|
||||||
|
}
|
||||||
address = acquired;
|
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);
|
log_address_debug(address, "Requesting", link);
|
||||||
r = link_queue_request(link, REQUEST_TYPE_ADDRESS, address, consume_object,
|
r = link_queue_request(link, REQUEST_TYPE_ADDRESS, address, consume_object,
|
||||||
message_counter, netlink_handler, ret);
|
message_counter, netlink_handler, ret);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_link_warning_errno(link, r, "Failed to request address: %m");
|
return log_link_warning_errno(link, r, "Failed to request address: %m");
|
||||||
if (r == 0)
|
return r;
|
||||||
return 0;
|
|
||||||
|
|
||||||
address_enter_requesting(existing);
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int link_request_static_address(Link *link, Address *address, bool consume) {
|
int link_request_static_address(Link *link, Address *address, bool consume) {
|
||||||
|
Request *req;
|
||||||
|
int r;
|
||||||
|
|
||||||
assert(link);
|
assert(link);
|
||||||
assert(address);
|
assert(address);
|
||||||
assert(address->source == NETWORK_CONFIG_SOURCE_STATIC);
|
|
||||||
|
|
||||||
return link_request_address(link, address, consume, &link->static_address_messages,
|
r = link_request_address(link, address, consume, &link->static_address_messages,
|
||||||
static_address_handler, NULL);
|
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) {
|
int link_request_static_addresses(Link *link) {
|
||||||
Address *a;
|
Address *a;
|
||||||
|
Prefix *p;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
assert(link);
|
assert(link);
|
||||||
@ -1146,13 +1168,52 @@ int link_request_static_addresses(Link *link) {
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
r = link_request_radv_addresses(link);
|
HASHMAP_FOREACH(p, link->network->prefixes_by_section) {
|
||||||
if (r < 0)
|
_cleanup_(address_freep) Address *address = NULL;
|
||||||
return r;
|
|
||||||
|
|
||||||
r = link_request_dhcp_server_address(link);
|
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)
|
if (r < 0)
|
||||||
return r;
|
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) {
|
if (link->static_address_messages == 0) {
|
||||||
link->static_addresses_configured = true;
|
link->static_addresses_configured = true;
|
||||||
@ -1165,25 +1226,41 @@ int link_request_static_addresses(Link *link) {
|
|||||||
return 0;
|
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(link);
|
||||||
assert(address);
|
assert(address);
|
||||||
|
|
||||||
if (!link_is_ready_to_configure(link, false))
|
if (!link_is_ready_to_configure(link, false))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (FLAGS_SET(address->state, NETWORK_CONFIG_STATE_PROBING))
|
if (link->address_remove_messages > 0)
|
||||||
return false;
|
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)
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
int request_process_address(Request *req) {
|
int request_process_address(Request *req) {
|
||||||
Address *existing;
|
Address *a;
|
||||||
Link *link;
|
Link *link;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
@ -1194,18 +1271,26 @@ int request_process_address(Request *req) {
|
|||||||
|
|
||||||
link = req->link;
|
link = req->link;
|
||||||
|
|
||||||
r = address_get(link, req->address, &existing);
|
r = address_is_ready_to_configure(link, req->address);
|
||||||
if (r < 0)
|
if (r <= 0)
|
||||||
return log_link_warning_errno(link, r, "Failed to get address: %m");
|
return r;
|
||||||
|
|
||||||
if (!address_is_ready_to_configure(link, existing))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
r = address_configure(req->address, link, req->netlink_handler);
|
r = address_configure(req->address, link, req->netlink_handler);
|
||||||
if (r < 0)
|
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;
|
return 1;
|
||||||
}
|
}
|
||||||
@ -1356,14 +1441,10 @@ int manager_rtnl_process_address(sd_netlink *rtnl, sd_netlink_message *message,
|
|||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case RTM_NEWADDR:
|
case RTM_NEWADDR:
|
||||||
if (address) {
|
log_address_debug(tmp, address ? "Remembering updated" : "Remembering foreign", link);
|
||||||
address_enter_configured(address);
|
if (!address) {
|
||||||
log_address_debug(address, "Remembering updated", link);
|
/* An address appeared that we did not request */
|
||||||
} else {
|
r = address_add_foreign(link, tmp, &address);
|
||||||
address_enter_configured(tmp);
|
|
||||||
log_address_debug(tmp, "Received new", link);
|
|
||||||
|
|
||||||
r = address_add(link, tmp);
|
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
_cleanup_free_ char *buf = NULL;
|
_cleanup_free_ char *buf = NULL;
|
||||||
|
|
||||||
@ -1372,8 +1453,6 @@ int manager_rtnl_process_address(sd_netlink *rtnl, sd_netlink_message *message,
|
|||||||
strnull(buf));
|
strnull(buf));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
address = TAKE_PTR(tmp);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* address_update() logs internally, so we don't need to here. */
|
/* 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;
|
break;
|
||||||
|
|
||||||
case RTM_DELADDR:
|
case RTM_DELADDR:
|
||||||
if (address) {
|
log_address_debug(tmp, address ? "Forgetting" : "Kernel removed unknown", link);
|
||||||
address_enter_removed(address);
|
|
||||||
log_address_debug(address, address->state == 0 ? "Forgetting" : "Removed", link);
|
|
||||||
(void) address_drop(address);
|
(void) address_drop(address);
|
||||||
} else
|
|
||||||
log_address_debug(tmp, "Kernel removed unknown", link);
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -1847,6 +1922,12 @@ int config_parse_duplicate_address_detection(
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool address_is_ready(const Address *a) {
|
||||||
|
assert(a);
|
||||||
|
|
||||||
|
return !(a->flags & IFA_F_TENTATIVE);
|
||||||
|
}
|
||||||
|
|
||||||
static int address_section_verify(Address *address) {
|
static int address_section_verify(Address *address) {
|
||||||
if (section_is_invalid(address->section))
|
if (section_is_invalid(address->section))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|||||||
@ -21,12 +21,10 @@ typedef struct Request Request;
|
|||||||
typedef int (*address_ready_callback_t)(Address *address);
|
typedef int (*address_ready_callback_t)(Address *address);
|
||||||
|
|
||||||
struct Address {
|
struct Address {
|
||||||
Link *link;
|
|
||||||
Network *network;
|
Network *network;
|
||||||
NetworkConfigSection *section;
|
NetworkConfigSection *section;
|
||||||
NetworkConfigSource source;
|
|
||||||
NetworkConfigState state;
|
Link *link;
|
||||||
union in_addr_union provider; /* DHCP server or router address */
|
|
||||||
|
|
||||||
int family;
|
int family;
|
||||||
unsigned char prefixlen;
|
unsigned char prefixlen;
|
||||||
@ -44,6 +42,8 @@ struct Address {
|
|||||||
|
|
||||||
bool scope_set:1;
|
bool scope_set:1;
|
||||||
bool ip_masquerade_done:1;
|
bool ip_masquerade_done:1;
|
||||||
|
bool is_static:1; /* currently only used by IPv4ACD */
|
||||||
|
bool acd_announced:1;
|
||||||
AddressFamily duplicate_address_detection;
|
AddressFamily duplicate_address_detection;
|
||||||
sd_ipv4acd *acd;
|
sd_ipv4acd *acd;
|
||||||
|
|
||||||
@ -62,7 +62,8 @@ int address_new(Address **ret);
|
|||||||
Address* address_free(Address *address);
|
Address* address_free(Address *address);
|
||||||
int address_get(Link *link, const Address *in, Address **ret);
|
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_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);
|
int address_dup(const Address *src, Address **ret);
|
||||||
bool address_is_ready(const Address *a);
|
bool address_is_ready(const Address *a);
|
||||||
void address_set_broadcast(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 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);
|
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(
|
int link_request_address(
|
||||||
Link *link,
|
Link *link,
|
||||||
Address *address,
|
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);
|
int address_compare_func(const Address *a1, const Address *a2);
|
||||||
extern const struct hash_ops address_hash_ops;
|
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_address);
|
||||||
CONFIG_PARSER_PROTOTYPE(config_parse_broadcast);
|
CONFIG_PARSER_PROTOTYPE(config_parse_broadcast);
|
||||||
CONFIG_PARSER_PROTOTYPE(config_parse_label);
|
CONFIG_PARSER_PROTOTYPE(config_parse_label);
|
||||||
|
|||||||
@ -16,7 +16,6 @@
|
|||||||
#include "networkd-manager.h"
|
#include "networkd-manager.h"
|
||||||
#include "networkd-network.h"
|
#include "networkd-network.h"
|
||||||
#include "networkd-queue.h"
|
#include "networkd-queue.h"
|
||||||
#include "networkd-route.h"
|
|
||||||
#include "parse-util.h"
|
#include "parse-util.h"
|
||||||
#include "socket-netlink.h"
|
#include "socket-netlink.h"
|
||||||
#include "string-table.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) {
|
static int link_find_dhcp_server_address(Link *link, Address **ret) {
|
||||||
Address *address;
|
Address *address;
|
||||||
|
|
||||||
@ -121,18 +86,10 @@ static int link_find_dhcp_server_address(Link *link, Address **ret) {
|
|||||||
link->network->dhcp_server_address_prefixlen, ret);
|
link->network->dhcp_server_address_prefixlen, ret);
|
||||||
|
|
||||||
/* If not, then select one from static addresses. */
|
/* If not, then select one from static addresses. */
|
||||||
SET_FOREACH(address, link->addresses) {
|
SET_FOREACH(address, link->static_addresses)
|
||||||
if (address->source != NETWORK_CONFIG_SOURCE_STATIC)
|
if (address->family == AF_INET &&
|
||||||
continue;
|
!in4_addr_is_localhost(&address->in_addr.in) &&
|
||||||
if (!address_exists(address))
|
in4_addr_is_null(&address->in_addr_peer.in)) {
|
||||||
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;
|
*ret = address;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -548,6 +505,9 @@ static bool dhcp_server_is_ready_to_configure(Link *link) {
|
|||||||
if (!link_has_carrier(link))
|
if (!link_has_carrier(link))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
if (link->address_remove_messages > 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
if (!link->static_addresses_configured)
|
if (!link->static_addresses_configured)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
|||||||
@ -9,7 +9,6 @@ typedef struct Request Request;
|
|||||||
|
|
||||||
void network_adjust_dhcp_server(Network *network);
|
void network_adjust_dhcp_server(Network *network);
|
||||||
|
|
||||||
int link_request_dhcp_server_address(Link *link);
|
|
||||||
int link_request_dhcp_server(Link *link);
|
int link_request_dhcp_server(Link *link);
|
||||||
int request_process_dhcp_server(Request *req);
|
int request_process_dhcp_server(Request *req);
|
||||||
|
|
||||||
|
|||||||
@ -27,7 +27,7 @@
|
|||||||
#include "sysctl-util.h"
|
#include "sysctl-util.h"
|
||||||
|
|
||||||
static int dhcp4_request_address_and_routes(Link *link, bool announce);
|
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) {
|
void network_adjust_dhcp4(Network *network) {
|
||||||
assert(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;
|
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) {
|
static int dhcp4_release_old_lease(Link *link) {
|
||||||
Address *address;
|
|
||||||
Route *route;
|
Route *route;
|
||||||
int k, r = 0;
|
int k, r = 0;
|
||||||
|
|
||||||
assert(link);
|
assert(link);
|
||||||
|
|
||||||
SET_FOREACH(route, link->routes) {
|
if (!link->dhcp_address_old && set_isempty(link->dhcp_routes_old))
|
||||||
if (route->source != NETWORK_CONFIG_SOURCE_DHCP4)
|
return 0;
|
||||||
continue;
|
|
||||||
if (only_marked && !route_is_marked(route))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
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)
|
if (k < 0)
|
||||||
r = k;
|
r = k;
|
||||||
|
|
||||||
route_cancel_request(route);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SET_FOREACH(address, link->addresses) {
|
if (link->dhcp_address_old) {
|
||||||
if (address->source != NETWORK_CONFIG_SOURCE_DHCP4)
|
k = address_remove(link->dhcp_address_old, link);
|
||||||
continue;
|
|
||||||
if (only_marked && !address_is_marked(address))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
k = address_remove(address);
|
|
||||||
if (k < 0)
|
if (k < 0)
|
||||||
r = k;
|
r = k;
|
||||||
|
|
||||||
address_cancel_request(address);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int dhcp4_address_get(Link *link, Address **ret) {
|
static void dhcp4_check_ready(Link *link) {
|
||||||
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;
|
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
assert(link);
|
|
||||||
|
|
||||||
if (link->dhcp4_messages > 0) {
|
if (link->dhcp4_messages > 0) {
|
||||||
log_link_debug(link, "%s(): DHCPv4 address and routes are not set.", __func__);
|
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__);
|
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__);
|
log_link_debug(link, "%s(): DHCPv4 address is not ready.", __func__);
|
||||||
address->callback = dhcp4_address_ready_callback;
|
return;
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
link->dhcp4_configured = true;
|
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. */
|
/* New address and routes are configured now. Let's release old lease. */
|
||||||
r = dhcp4_remove_address_and_routes(link, /* only_marked = */ true);
|
r = dhcp4_release_old_lease(link);
|
||||||
if (r < 0)
|
if (r < 0) {
|
||||||
return r;
|
link_enter_failed(link);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
r = sd_ipv4ll_stop(link->ipv4ll);
|
r = sd_ipv4ll_stop(link->ipv4ll);
|
||||||
if (r < 0)
|
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);
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -162,7 +140,7 @@ static int dhcp4_retry(Link *link) {
|
|||||||
|
|
||||||
assert(link);
|
assert(link);
|
||||||
|
|
||||||
r = dhcp4_remove_address_and_routes(link, /* only_marked = */ false);
|
r = dhcp4_remove_all(link);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
@ -214,29 +192,19 @@ static int dhcp4_route_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *li
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
r = dhcp4_check_ready(link);
|
dhcp4_check_ready(link);
|
||||||
if (r < 0)
|
|
||||||
link_enter_failed(link);
|
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int dhcp4_request_route(Route *in, Link *link) {
|
static int dhcp4_request_route(Route *in, Link *link) {
|
||||||
_cleanup_(route_freep) Route *route = in;
|
_cleanup_(route_freep) Route *route = in;
|
||||||
struct in_addr server;
|
Request *req;
|
||||||
Route *existing;
|
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
assert(route);
|
assert(route);
|
||||||
assert(link);
|
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;
|
route->family = AF_INET;
|
||||||
if (!route->protocol_set)
|
if (!route->protocol_set)
|
||||||
route->protocol = RTPROT_DHCP;
|
route->protocol = RTPROT_DHCP;
|
||||||
@ -247,13 +215,20 @@ static int dhcp4_request_route(Route *in, Link *link) {
|
|||||||
if (route->mtu == 0)
|
if (route->mtu == 0)
|
||||||
route->mtu = link->network->dhcp_route_mtu;
|
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;
|
link->dhcp4_configured = false;
|
||||||
else
|
|
||||||
route_unmark(existing);
|
|
||||||
|
|
||||||
return link_request_route(link, TAKE_PTR(route), true, &link->dhcp4_messages,
|
r = link_request_route(link, TAKE_PTR(route), true, &link->dhcp4_messages,
|
||||||
dhcp4_route_handler, NULL);
|
dhcp4_route_handler, &req);
|
||||||
|
if (r <= 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
req->after_configure = dhcp4_after_route_configure;
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool link_prefixroute(Link *link) {
|
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) {
|
static int dhcp4_request_routes(Link *link) {
|
||||||
struct in_addr gw = {};
|
struct in_addr gw = {};
|
||||||
|
Route *rt;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
assert(link);
|
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);
|
r = dhcp4_request_prefix_route(link);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
@ -784,6 +768,27 @@ static int dhcp_reset_hostname(Link *link) {
|
|||||||
return 0;
|
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 dhcp4_lease_lost(Link *link) {
|
||||||
int k, r = 0;
|
int k, r = 0;
|
||||||
|
|
||||||
@ -794,7 +799,12 @@ int dhcp4_lease_lost(Link *link) {
|
|||||||
|
|
||||||
link->dhcp4_configured = false;
|
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)
|
if (k < 0)
|
||||||
r = k;
|
r = k;
|
||||||
|
|
||||||
@ -809,7 +819,24 @@ int dhcp4_lease_lost(Link *link) {
|
|||||||
link->dhcp_lease = sd_dhcp_lease_unref(link->dhcp_lease);
|
link->dhcp_lease = sd_dhcp_lease_unref(link->dhcp_lease);
|
||||||
link_dirty(link);
|
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)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
@ -820,6 +847,43 @@ int dhcp4_lease_lost(Link *link) {
|
|||||||
return link_request_static_routes(link, true);
|
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) {
|
static int dhcp4_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
@ -832,9 +896,12 @@ static int dhcp4_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *
|
|||||||
if (r <= 0)
|
if (r <= 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
r = dhcp4_check_ready(link);
|
if (address_is_ready(link->dhcp_address)) {
|
||||||
|
r = dhcp4_address_ready_callback(link->dhcp_address);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
link_enter_failed(link);
|
link_enter_failed(link);
|
||||||
|
} else
|
||||||
|
link->dhcp_address->callback = dhcp4_address_ready_callback;
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@ -844,12 +911,14 @@ static int dhcp4_request_address(Link *link, bool announce) {
|
|||||||
uint32_t lifetime = CACHE_INFO_INFINITY_LIFE_TIME;
|
uint32_t lifetime = CACHE_INFO_INFINITY_LIFE_TIME;
|
||||||
struct in_addr address, netmask, server;
|
struct in_addr address, netmask, server;
|
||||||
unsigned prefixlen;
|
unsigned prefixlen;
|
||||||
Address *existing;
|
Request *req;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
assert(link);
|
assert(link);
|
||||||
assert(link->network);
|
assert(link->network);
|
||||||
assert(link->dhcp_lease);
|
|
||||||
|
if (!link->dhcp_lease)
|
||||||
|
return 0;
|
||||||
|
|
||||||
r = sd_dhcp_lease_get_address(link->dhcp_lease, &address);
|
r = sd_dhcp_lease_get_address(link->dhcp_lease, &address);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
@ -904,8 +973,6 @@ static int dhcp4_request_address(Link *link, bool announce) {
|
|||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_oom();
|
return log_oom();
|
||||||
|
|
||||||
addr->source = NETWORK_CONFIG_SOURCE_DHCP4;
|
|
||||||
addr->provider.in = server;
|
|
||||||
addr->family = AF_INET;
|
addr->family = AF_INET;
|
||||||
addr->in_addr.in.s_addr = address.s_addr;
|
addr->in_addr.in.s_addr = address.s_addr;
|
||||||
addr->cinfo.ifa_prefered = lifetime;
|
addr->cinfo.ifa_prefered = lifetime;
|
||||||
@ -921,15 +988,17 @@ static int dhcp4_request_address(Link *link, bool announce) {
|
|||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
if (address_get(link, addr, &existing) < 0) /* The address is new. */
|
if (address_get(link, addr, NULL) < 0)
|
||||||
link->dhcp4_configured = false;
|
link->dhcp4_configured = false;
|
||||||
else
|
|
||||||
address_unmark(existing);
|
|
||||||
|
|
||||||
r = link_request_address(link, TAKE_PTR(addr), true, &link->dhcp4_messages,
|
r = link_request_address(link, TAKE_PTR(addr), true, &link->dhcp4_messages,
|
||||||
dhcp4_address_handler, NULL);
|
dhcp4_address_handler, &req);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_link_error_errno(link, r, "Failed to request DHCPv4 address: %m");
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -939,9 +1008,6 @@ static int dhcp4_request_address_and_routes(Link *link, bool announce) {
|
|||||||
|
|
||||||
assert(link);
|
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);
|
r = dhcp4_request_address(link, announce);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
@ -950,10 +1016,8 @@ static int dhcp4_request_address_and_routes(Link *link, bool announce) {
|
|||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
if (!link->dhcp4_configured) {
|
|
||||||
link_set_state(link, LINK_STATE_CONFIGURING);
|
link_set_state(link, LINK_STATE_CONFIGURING);
|
||||||
link_check_ready(link);
|
link_check_ready(link);
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -1308,9 +1372,7 @@ static int dhcp4_set_request_address(Link *link) {
|
|||||||
if (!FLAGS_SET(link->network->keep_configuration, KEEP_CONFIGURATION_DHCP))
|
if (!FLAGS_SET(link->network->keep_configuration, KEEP_CONFIGURATION_DHCP))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
SET_FOREACH(a, link->addresses) {
|
SET_FOREACH(a, link->addresses_foreign) {
|
||||||
if (a->source != NETWORK_CONFIG_SOURCE_FOREIGN)
|
|
||||||
continue;
|
|
||||||
if (a->family != AF_INET)
|
if (a->family != AF_INET)
|
||||||
continue;
|
continue;
|
||||||
if (link_address_is_dynamic(link, a))
|
if (link_address_is_dynamic(link, a))
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -16,9 +16,18 @@ typedef enum DHCP6ClientStartMode {
|
|||||||
typedef struct Link Link;
|
typedef struct Link Link;
|
||||||
typedef struct Request Request;
|
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_with_address_enabled(Link *link);
|
||||||
bool link_dhcp6_pd_is_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_update_mac(Link *link);
|
||||||
int dhcp6_start(Link *link);
|
int dhcp6_start(Link *link);
|
||||||
int dhcp6_request_information(Link *link, int ir);
|
int dhcp6_request_information(Link *link, int ir);
|
||||||
|
|||||||
@ -9,26 +9,19 @@
|
|||||||
#include "networkd-link.h"
|
#include "networkd-link.h"
|
||||||
#include "networkd-manager.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;
|
int r;
|
||||||
|
|
||||||
assert(link);
|
assert(link);
|
||||||
assert(address);
|
assert(address);
|
||||||
|
|
||||||
/* Prevent form the address being freed. */
|
if (address_get(link, address, NULL) < 0)
|
||||||
address_enter_probing(address);
|
return 0;
|
||||||
|
|
||||||
if (!address_exists(address))
|
|
||||||
return 0; /* Not assigned. */
|
|
||||||
|
|
||||||
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.",
|
log_link_debug(link, "Removing address "IPV4_ADDRESS_FMT_STR", as the ACD client is stopped.",
|
||||||
IPV4_ADDRESS_FMT_VAL(address->in_addr.in));
|
IPV4_ADDRESS_FMT_VAL(address->in_addr.in));
|
||||||
|
|
||||||
r = address_remove(address);
|
r = address_remove(address, link);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_link_warning_errno(link, r, "Failed to remove address "IPV4_ADDRESS_FMT_STR": %m",
|
return log_link_warning_errno(link, r, "Failed to remove address "IPV4_ADDRESS_FMT_STR": %m",
|
||||||
IPV4_ADDRESS_FMT_VAL(address->in_addr.in));
|
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;
|
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;
|
int r;
|
||||||
|
|
||||||
assert(link);
|
assert(link);
|
||||||
@ -55,14 +71,11 @@ static int dhcp4_address_on_conflict(Link *link, Address *address) {
|
|||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_link_warning_errno(link, r, "Failed to drop DHCPv4 lease: %m");
|
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. */
|
/* It is not necessary to call address_remove() here, as dhcp4_lease_lost() removes it. */
|
||||||
return 0;
|
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;
|
Address *address = userdata;
|
||||||
Link *link;
|
Link *link;
|
||||||
int r;
|
int r;
|
||||||
@ -72,14 +85,13 @@ static void on_acd(sd_ipv4acd *acd, int event, void *userdata) {
|
|||||||
assert(address->acd == acd);
|
assert(address->acd == acd);
|
||||||
assert(address->link);
|
assert(address->link);
|
||||||
assert(address->family == AF_INET);
|
assert(address->family == AF_INET);
|
||||||
assert(IN_SET(address->source, NETWORK_CONFIG_SOURCE_STATIC, NETWORK_CONFIG_SOURCE_DHCP4));
|
|
||||||
|
|
||||||
link = address->link;
|
link = address->link;
|
||||||
|
|
||||||
switch (event) {
|
switch (event) {
|
||||||
case SD_IPV4ACD_EVENT_STOP:
|
case SD_IPV4ACD_EVENT_STOP:
|
||||||
if (address->source == NETWORK_CONFIG_SOURCE_STATIC) {
|
if (is_static) {
|
||||||
r = static_ipv4acd_address_remove(link, address, /* on_conflict = */ false);
|
r = static_address_on_stop(link, address);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
link_enter_failed(link);
|
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,
|
log_link_debug(link, "Successfully claimed address "IPV4_ADDRESS_FMT_STR,
|
||||||
IPV4_ADDRESS_FMT_VAL(address->in_addr.in));
|
IPV4_ADDRESS_FMT_VAL(address->in_addr.in));
|
||||||
|
|
||||||
address_cancel_probing(address);
|
address->acd_announced = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SD_IPV4ACD_EVENT_CONFLICT:
|
case SD_IPV4ACD_EVENT_CONFLICT:
|
||||||
log_link_warning(link, "Dropping address "IPV4_ADDRESS_FMT_STR", as an address conflict was detected.",
|
if (is_static)
|
||||||
IPV4_ADDRESS_FMT_VAL(address->in_addr.in));
|
r = static_address_on_conflict(link, address);
|
||||||
|
|
||||||
if (address->source == NETWORK_CONFIG_SOURCE_STATIC)
|
|
||||||
r = static_ipv4acd_address_remove(link, address, /* on_conflict = */ true);
|
|
||||||
else
|
else
|
||||||
r = dhcp4_address_on_conflict(link, address);
|
r = dhcp4_address_on_conflict(link);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
link_enter_failed(link);
|
link_enter_failed(link);
|
||||||
break;
|
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) {
|
static int ipv4acd_check_mac(sd_ipv4acd *acd, const struct ether_addr *mac, void *userdata) {
|
||||||
Manager *m = userdata;
|
Manager *m = userdata;
|
||||||
struct hw_addr_data hw_addr;
|
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;
|
return link_get_by_hw_addr(m, &hw_addr, NULL) >= 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ipv4acd_configure(Address *address) {
|
static int ipv4acd_configure(Link *link, const Address *a) {
|
||||||
Link *link;
|
_cleanup_(address_freep) Address *address = NULL;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
assert(address);
|
assert(link);
|
||||||
assert(address->link);
|
assert(a);
|
||||||
|
assert(a->family == AF_INET);
|
||||||
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;
|
|
||||||
|
|
||||||
log_link_debug(link, "Configuring IPv4ACD for address "IPV4_ADDRESS_FMT_STR,
|
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);
|
r = sd_ipv4acd_new(&address->acd);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
@ -173,7 +186,9 @@ int ipv4acd_configure(Address *address) {
|
|||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
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)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
@ -187,10 +202,36 @@ int ipv4acd_configure(Address *address) {
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
address_enter_probing(address);
|
TAKE_PTR(address);
|
||||||
return 0;
|
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) {
|
int ipv4acd_update_mac(Link *link) {
|
||||||
Address *address;
|
Address *address;
|
||||||
int k, r = 0;
|
int k, r = 0;
|
||||||
@ -202,9 +243,8 @@ int ipv4acd_update_mac(Link *link) {
|
|||||||
if (ether_addr_is_null(&link->hw_addr.ether))
|
if (ether_addr_is_null(&link->hw_addr.ether))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
SET_FOREACH(address, link->addresses) {
|
SET_FOREACH(address, link->addresses_ipv4acd) {
|
||||||
if (!address->acd)
|
assert(address->acd);
|
||||||
continue;
|
|
||||||
|
|
||||||
k = sd_ipv4acd_set_mac(address->acd, &link->hw_addr.ether);
|
k = sd_ipv4acd_set_mac(address->acd, &link->hw_addr.ether);
|
||||||
if (k < 0)
|
if (k < 0)
|
||||||
@ -222,10 +262,7 @@ int ipv4acd_start(Link *link) {
|
|||||||
|
|
||||||
assert(link);
|
assert(link);
|
||||||
|
|
||||||
SET_FOREACH(address, link->addresses) {
|
SET_FOREACH(address, link->addresses_ipv4acd) {
|
||||||
if (!address->acd)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (sd_ipv4acd_is_running(address->acd))
|
if (sd_ipv4acd_is_running(address->acd))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@ -243,10 +280,7 @@ int ipv4acd_stop(Link *link) {
|
|||||||
|
|
||||||
assert(link);
|
assert(link);
|
||||||
|
|
||||||
SET_FOREACH(address, link->addresses) {
|
SET_FOREACH(address, link->addresses_ipv4acd) {
|
||||||
if (!address->acd)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
k = sd_ipv4acd_stop(address->acd);
|
k = sd_ipv4acd_stop(address->acd);
|
||||||
if (k < 0)
|
if (k < 0)
|
||||||
r = k;
|
r = k;
|
||||||
@ -261,10 +295,7 @@ int ipv4acd_set_ifname(Link *link) {
|
|||||||
|
|
||||||
assert(link);
|
assert(link);
|
||||||
|
|
||||||
SET_FOREACH(address, link->addresses) {
|
SET_FOREACH(address, link->addresses_ipv4acd) {
|
||||||
if (!address->acd)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
r = sd_ipv4acd_set_ifname(address->acd, link->ifname);
|
r = sd_ipv4acd_set_ifname(address->acd, link->ifname);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|||||||
@ -4,7 +4,7 @@
|
|||||||
typedef struct Address Address;
|
typedef struct Address Address;
|
||||||
typedef struct Link Link;
|
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_update_mac(Link *link);
|
||||||
int ipv4acd_start(Link *link);
|
int ipv4acd_start(Link *link);
|
||||||
int ipv4acd_stop(Link *link);
|
int ipv4acd_stop(Link *link);
|
||||||
|
|||||||
@ -28,7 +28,6 @@ static int address_new_from_ipv4ll(Link *link, Address **ret) {
|
|||||||
if (r < 0)
|
if (r < 0)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
address->source = NETWORK_CONFIG_SOURCE_IPV4LL;
|
|
||||||
address->family = AF_INET;
|
address->family = AF_INET;
|
||||||
address->in_addr.in = addr;
|
address->in_addr.in = addr;
|
||||||
address->prefixlen = 16;
|
address->prefixlen = 16;
|
||||||
@ -42,7 +41,6 @@ static int address_new_from_ipv4ll(Link *link, Address **ret) {
|
|||||||
|
|
||||||
static int ipv4ll_address_lost(Link *link) {
|
static int ipv4ll_address_lost(Link *link) {
|
||||||
_cleanup_(address_freep) Address *address = NULL;
|
_cleanup_(address_freep) Address *address = NULL;
|
||||||
Address *existing;
|
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
assert(link);
|
assert(link);
|
||||||
@ -55,19 +53,10 @@ static int ipv4ll_address_lost(Link *link) {
|
|||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
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,
|
log_link_debug(link, "IPv4 link-local release "IPV4_ADDRESS_FMT_STR,
|
||||||
IPV4_ADDRESS_FMT_VAL(address->in_addr.in));
|
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) {
|
static int ipv4ll_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
|
||||||
|
|||||||
@ -48,12 +48,12 @@
|
|||||||
#include "networkd-nexthop.h"
|
#include "networkd-nexthop.h"
|
||||||
#include "networkd-queue.h"
|
#include "networkd-queue.h"
|
||||||
#include "networkd-radv.h"
|
#include "networkd-radv.h"
|
||||||
#include "networkd-route.h"
|
|
||||||
#include "networkd-routing-policy-rule.h"
|
#include "networkd-routing-policy-rule.h"
|
||||||
#include "networkd-setlink.h"
|
#include "networkd-setlink.h"
|
||||||
#include "networkd-sriov.h"
|
#include "networkd-sriov.h"
|
||||||
#include "networkd-state-file.h"
|
#include "networkd-state-file.h"
|
||||||
#include "networkd-sysctl.h"
|
#include "networkd-sysctl.h"
|
||||||
|
#include "networkd-wifi.h"
|
||||||
#include "set.h"
|
#include "set.h"
|
||||||
#include "socket-util.h"
|
#include "socket-util.h"
|
||||||
#include "stat-util.h"
|
#include "stat-util.h"
|
||||||
@ -228,12 +228,29 @@ static Link *link_free(Link *link) {
|
|||||||
link_dns_settings_clear(link);
|
link_dns_settings_clear(link);
|
||||||
|
|
||||||
link->routes = set_free(link->routes);
|
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->nexthops = set_free(link->nexthops);
|
||||||
|
|
||||||
link->neighbors = set_free(link->neighbors);
|
link->neighbors = set_free(link->neighbors);
|
||||||
|
|
||||||
link->addresses = set_free(link->addresses);
|
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);
|
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)
|
if (k < 0)
|
||||||
r = log_link_warning_errno(link, k, "Could not stop DHCPv6 client: %m");
|
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)
|
if (k < 0)
|
||||||
r = log_link_warning_errno(link, k, "Could not remove DHCPv6 PD addresses and routes: %m");
|
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;
|
_cleanup_free_ char *str = NULL;
|
||||||
|
|
||||||
(void) in_addr_prefix_to_string(a->family, &a->in_addr, a->prefixlen, &str);
|
(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)
|
if (!link->static_address_labels_configured)
|
||||||
@ -479,42 +496,44 @@ void link_check_ready(Link *link) {
|
|||||||
!in6_addr_is_set(&link->ipv6ll_address))
|
!in6_addr_is_set(&link->ipv6ll_address))
|
||||||
return (void) log_link_debug(link, "%s(): IPv6LL is not configured yet.", __func__);
|
return (void) log_link_debug(link, "%s(): IPv6LL is not configured yet.", __func__);
|
||||||
|
|
||||||
bool has_dynamic_address = false;
|
bool has_ndisc_address = false;
|
||||||
SET_FOREACH(a, link->addresses) {
|
NDiscAddress *n;
|
||||||
if (address_is_marked(a))
|
SET_FOREACH(n, link->ndisc_addresses)
|
||||||
continue;
|
if (!n->marked) {
|
||||||
if (!address_exists(a))
|
has_ndisc_address = true;
|
||||||
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;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if ((link_ipv4ll_enabled(link) || link_dhcp4_enabled(link) || link_dhcp6_with_address_enabled(link) ||
|
if ((link_dhcp4_enabled(link) || link_dhcp6_with_address_enabled(link) || link_ipv4ll_enabled(link)) &&
|
||||||
(link_dhcp6_pd_is_enabled(link) && link->network->dhcp6_pd_assign)) && !has_dynamic_address)
|
!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. */
|
/* 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__);
|
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. */
|
/* Ignore NDisc when ConfigureWithoutCarrier= is enabled, as IPv6AcceptRA= is enabled by default. */
|
||||||
if (link_ipv4ll_enabled(link) || link_dhcp4_enabled(link) ||
|
if (link_dhcp4_enabled(link) || link_dhcp6_enabled(link) || link_dhcp6_pd_is_enabled(link) ||
|
||||||
link_dhcp6_enabled(link) || link_dhcp6_pd_is_enabled(link) ||
|
(!link->network->configure_without_carrier && link_ipv6_accept_ra_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 &&
|
if (!link->dhcp4_configured &&
|
||||||
!link->dhcp6_configured && !link->dhcp6_pd_configured && !link->ndisc_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. */
|
/* 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__);
|
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__,
|
__func__,
|
||||||
yes_no(link->ipv4ll_address_configured),
|
|
||||||
yes_no(link->dhcp4_configured),
|
yes_no(link->dhcp4_configured),
|
||||||
yes_no(link->dhcp6_configured),
|
yes_no(link->ipv4ll_address_configured),
|
||||||
yes_no(link->dhcp6_pd_configured),
|
yes_no(link->dhcp6_address_configured),
|
||||||
yes_no(link->ndisc_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);
|
link_set_state(link, LINK_STATE_CONFIGURED);
|
||||||
@ -964,9 +983,7 @@ static Link *link_drop(Link *link) {
|
|||||||
|
|
||||||
link_drop_from_master(link);
|
link_drop_from_master(link);
|
||||||
|
|
||||||
if (link->state_file)
|
|
||||||
(void) unlink(link->state_file);
|
(void) unlink(link->state_file);
|
||||||
|
|
||||||
link_clean(link);
|
link_clean(link);
|
||||||
|
|
||||||
STRV_FOREACH(n, link->alternative_names)
|
STRV_FOREACH(n, link->alternative_names)
|
||||||
@ -1278,15 +1295,28 @@ static int link_reconfigure_impl(Link *link, bool force) {
|
|||||||
return 1;
|
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;
|
int r;
|
||||||
|
|
||||||
assert(link);
|
assert(link);
|
||||||
|
|
||||||
|
link_was_lower_up = link->flags & IFF_LOWER_UP;
|
||||||
|
|
||||||
r = link_getlink_handler_internal(rtnl, m, link, "Failed to update link state");
|
r = link_getlink_handler_internal(rtnl, m, link, "Failed to update link state");
|
||||||
if (r <= 0)
|
if (r <= 0)
|
||||||
return r;
|
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);
|
r = link_reconfigure_impl(link, force);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
link_enter_failed(link);
|
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) {
|
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) {
|
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) {
|
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);
|
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)
|
if (r != 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
@ -1374,12 +1404,6 @@ static int link_initialized_and_synced(Link *link) {
|
|||||||
assert(link->ifname);
|
assert(link->ifname);
|
||||||
assert(link->manager);
|
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,
|
/* We may get called either from the asynchronous netlink callback,
|
||||||
* or directly from link_check_initialized() if running in a container. */
|
* or directly from link_check_initialized() if running in a container. */
|
||||||
if (!IN_SET(link->state, LINK_STATE_PENDING, LINK_STATE_INITIALIZED))
|
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;
|
return r;
|
||||||
|
|
||||||
if (!link->network) {
|
if (!link->network) {
|
||||||
|
r = wifi_get_info(link);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
r = link_get_network(link, &network);
|
r = link_get_network(link, &network);
|
||||||
if (r == -ENOENT) {
|
if (r == -ENOENT) {
|
||||||
link_set_state(link, LINK_STATE_UNMANAGED);
|
link_set_state(link, LINK_STATE_UNMANAGED);
|
||||||
@ -1609,7 +1637,11 @@ static int link_carrier_lost(Link *link) {
|
|||||||
return r;
|
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) {
|
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);
|
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);
|
ipv4_address_state = address_state_from_scope(ipv4_scope);
|
||||||
ipv6_address_state = address_state_from_scope(ipv6_scope);
|
ipv6_address_state = address_state_from_scope(ipv6_scope);
|
||||||
address_state = address_state_from_scope(MIN(ipv4_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) {
|
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;
|
uint8_t operstate;
|
||||||
unsigned flags;
|
unsigned flags;
|
||||||
int r;
|
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);
|
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;
|
link_was_admin_up = link->flags & IFF_UP;
|
||||||
had_carrier = link_has_carrier(link);
|
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);
|
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)) {
|
if (!link_was_admin_up && (link->flags & IFF_UP)) {
|
||||||
log_link_info(link, "Link 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)) {
|
if (!had_carrier && link_has_carrier(link)) {
|
||||||
log_link_info(link, "Gained carrier");
|
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);
|
r = link_carrier_gained(link);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
@ -2332,8 +2381,6 @@ 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");
|
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)
|
if (asprintf(&state_file, "/run/systemd/netif/links/%d", ifindex) < 0)
|
||||||
return log_oom_debug();
|
return log_oom_debug();
|
||||||
|
|
||||||
@ -2342,7 +2389,6 @@ static int link_new(Manager *manager, sd_netlink_message *message, Link **ret) {
|
|||||||
|
|
||||||
if (asprintf(&lldp_file, "/run/systemd/netif/lldp/%d", ifindex) < 0)
|
if (asprintf(&lldp_file, "/run/systemd/netif/lldp/%d", ifindex) < 0)
|
||||||
return log_oom_debug();
|
return log_oom_debug();
|
||||||
}
|
|
||||||
|
|
||||||
link = new(Link, 1);
|
link = new(Link, 1);
|
||||||
if (!link)
|
if (!link)
|
||||||
|
|||||||
@ -39,6 +39,7 @@ typedef enum LinkState {
|
|||||||
|
|
||||||
typedef struct Manager Manager;
|
typedef struct Manager Manager;
|
||||||
typedef struct Network Network;
|
typedef struct Network Network;
|
||||||
|
typedef struct Address Address;
|
||||||
typedef struct DUID DUID;
|
typedef struct DUID DUID;
|
||||||
|
|
||||||
typedef struct Link {
|
typedef struct Link {
|
||||||
@ -91,6 +92,8 @@ typedef struct Link {
|
|||||||
unsigned static_nexthop_messages;
|
unsigned static_nexthop_messages;
|
||||||
unsigned static_route_messages;
|
unsigned static_route_messages;
|
||||||
unsigned static_routing_policy_rule_messages;
|
unsigned static_routing_policy_rule_messages;
|
||||||
|
unsigned address_remove_messages;
|
||||||
|
unsigned route_remove_messages;
|
||||||
unsigned tc_messages;
|
unsigned tc_messages;
|
||||||
unsigned sr_iov_messages;
|
unsigned sr_iov_messages;
|
||||||
unsigned set_link_messages;
|
unsigned set_link_messages;
|
||||||
@ -99,12 +102,19 @@ typedef struct Link {
|
|||||||
unsigned create_stacked_netdev_after_configured_messages;
|
unsigned create_stacked_netdev_after_configured_messages;
|
||||||
|
|
||||||
Set *addresses;
|
Set *addresses;
|
||||||
|
Set *addresses_foreign;
|
||||||
|
Set *addresses_ipv4acd;
|
||||||
|
Set *pool_addresses;
|
||||||
|
Set *static_addresses;
|
||||||
Set *neighbors;
|
Set *neighbors;
|
||||||
Set *routes;
|
Set *routes;
|
||||||
|
Set *routes_foreign;
|
||||||
Set *nexthops;
|
Set *nexthops;
|
||||||
|
|
||||||
sd_dhcp_client *dhcp_client;
|
sd_dhcp_client *dhcp_client;
|
||||||
sd_dhcp_lease *dhcp_lease;
|
sd_dhcp_lease *dhcp_lease;
|
||||||
|
Address *dhcp_address, *dhcp_address_old;
|
||||||
|
Set *dhcp_routes, *dhcp_routes_old;
|
||||||
char *lease_file;
|
char *lease_file;
|
||||||
unsigned dhcp4_messages;
|
unsigned dhcp4_messages;
|
||||||
bool dhcp4_route_failed:1;
|
bool dhcp4_route_failed:1;
|
||||||
@ -135,18 +145,31 @@ typedef struct Link {
|
|||||||
sd_ndisc *ndisc;
|
sd_ndisc *ndisc;
|
||||||
Set *ndisc_rdnss;
|
Set *ndisc_rdnss;
|
||||||
Set *ndisc_dnssl;
|
Set *ndisc_dnssl;
|
||||||
unsigned ndisc_messages;
|
Set *ndisc_addresses;
|
||||||
bool ndisc_configured:1;
|
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_radv *radv;
|
||||||
|
|
||||||
sd_dhcp6_client *dhcp6_client;
|
sd_dhcp6_client *dhcp6_client;
|
||||||
sd_dhcp6_lease *dhcp6_lease;
|
sd_dhcp6_lease *dhcp6_lease;
|
||||||
|
Set *dhcp6_addresses, *dhcp6_addresses_old;
|
||||||
|
Set *dhcp6_routes, *dhcp6_routes_old;
|
||||||
Set *dhcp6_pd_prefixes;
|
Set *dhcp6_pd_prefixes;
|
||||||
unsigned dhcp6_messages;
|
Set *dhcp6_pd_addresses, *dhcp6_pd_addresses_old;
|
||||||
unsigned dhcp6_pd_messages;
|
Set *dhcp6_pd_routes, *dhcp6_pd_routes_old;
|
||||||
bool dhcp6_configured:1;
|
unsigned dhcp6_address_messages;
|
||||||
bool dhcp6_pd_configured:1;
|
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 */
|
/* This is about LLDP reception */
|
||||||
sd_lldp_rx *lldp_rx;
|
sd_lldp_rx *lldp_rx;
|
||||||
|
|||||||
@ -114,9 +114,7 @@ int link_lldp_save(Link *link) {
|
|||||||
int n = 0, r, i;
|
int n = 0, r, i;
|
||||||
|
|
||||||
assert(link);
|
assert(link);
|
||||||
|
assert(link->lldp_file);
|
||||||
if (isempty(link->lldp_file))
|
|
||||||
return 0; /* Do not update state file when running in test mode. */
|
|
||||||
|
|
||||||
if (!link->lldp_rx) {
|
if (!link->lldp_rx) {
|
||||||
(void) unlink(link->lldp_file);
|
(void) unlink(link->lldp_file);
|
||||||
|
|||||||
@ -6,7 +6,6 @@
|
|||||||
#include <linux/if.h>
|
#include <linux/if.h>
|
||||||
#include <linux/fib_rules.h>
|
#include <linux/fib_rules.h>
|
||||||
#include <linux/nexthop.h>
|
#include <linux/nexthop.h>
|
||||||
#include <linux/nl80211.h>
|
|
||||||
|
|
||||||
#include "sd-daemon.h"
|
#include "sd-daemon.h"
|
||||||
#include "sd-netlink.h"
|
#include "sd-netlink.h"
|
||||||
@ -27,7 +26,6 @@
|
|||||||
#include "netlink-util.h"
|
#include "netlink-util.h"
|
||||||
#include "network-internal.h"
|
#include "network-internal.h"
|
||||||
#include "networkd-address-pool.h"
|
#include "networkd-address-pool.h"
|
||||||
#include "networkd-address.h"
|
|
||||||
#include "networkd-dhcp-server-bus.h"
|
#include "networkd-dhcp-server-bus.h"
|
||||||
#include "networkd-dhcp6.h"
|
#include "networkd-dhcp6.h"
|
||||||
#include "networkd-link-bus.h"
|
#include "networkd-link-bus.h"
|
||||||
@ -37,11 +35,9 @@
|
|||||||
#include "networkd-network-bus.h"
|
#include "networkd-network-bus.h"
|
||||||
#include "networkd-nexthop.h"
|
#include "networkd-nexthop.h"
|
||||||
#include "networkd-queue.h"
|
#include "networkd-queue.h"
|
||||||
#include "networkd-route.h"
|
|
||||||
#include "networkd-routing-policy-rule.h"
|
#include "networkd-routing-policy-rule.h"
|
||||||
#include "networkd-speed-meter.h"
|
#include "networkd-speed-meter.h"
|
||||||
#include "networkd-state-file.h"
|
#include "networkd-state-file.h"
|
||||||
#include "networkd-wifi.h"
|
|
||||||
#include "ordered-set.h"
|
#include "ordered-set.h"
|
||||||
#include "path-lookup.h"
|
#include "path-lookup.h"
|
||||||
#include "path-util.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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int manager_connect_bus(Manager *m) {
|
int manager_connect_bus(Manager *m) {
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
assert(m);
|
assert(m);
|
||||||
assert(!m->bus);
|
|
||||||
|
if (m->bus)
|
||||||
|
return 0;
|
||||||
|
|
||||||
r = bus_open_system_watch_bind_with_description(&m->bus, "bus-api-network");
|
r = bus_open_system_watch_bind_with_description(&m->bus, "bus-api-network");
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
@ -250,16 +248,6 @@ static int manager_connect_genl(Manager *m) {
|
|||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
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;
|
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);
|
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;
|
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);
|
r = sd_event_default(&m->event);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
@ -416,13 +422,6 @@ int manager_setup(Manager *m) {
|
|||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
if (m->test_mode)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
r = manager_connect_bus(m);
|
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
|
|
||||||
r = manager_connect_udev(m);
|
r = manager_connect_udev(m);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
@ -439,33 +438,8 @@ int manager_setup(Manager *m) {
|
|||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
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);
|
*ret = TAKE_PTR(m);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -482,6 +456,9 @@ Manager* manager_free(Manager *m) {
|
|||||||
|
|
||||||
m->request_queue = ordered_set_free(m->request_queue);
|
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->dirty_links = set_free_with_destructor(m->dirty_links, link_unref);
|
||||||
m->links_by_name = hashmap_free(m->links_by_name);
|
m->links_by_name = hashmap_free(m->links_by_name);
|
||||||
m->links_by_hw_addr = hashmap_free(m->links_by_hw_addr);
|
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(
|
static int manager_enumerate_internal(
|
||||||
Manager *m,
|
Manager *m,
|
||||||
sd_netlink *nl,
|
|
||||||
sd_netlink_message *req,
|
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;
|
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *reply = NULL;
|
||||||
int k, r;
|
int r;
|
||||||
|
|
||||||
assert(m);
|
assert(m);
|
||||||
assert(nl);
|
assert(m->rtnl);
|
||||||
assert(req);
|
assert(req);
|
||||||
assert(process);
|
assert(process);
|
||||||
|
|
||||||
@ -595,14 +572,22 @@ static int manager_enumerate_internal(
|
|||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
r = sd_netlink_call(nl, req, 0, &reply);
|
r = sd_netlink_call(m->rtnl, req, 0, &reply);
|
||||||
if (r < 0)
|
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;
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
for (sd_netlink_message *reply_one = reply; reply_one; reply_one = sd_netlink_message_next(reply_one)) {
|
for (sd_netlink_message *reply_one = reply; reply_one; reply_one = sd_netlink_message_next(reply_one)) {
|
||||||
|
int k;
|
||||||
|
|
||||||
m->enumerating = true;
|
m->enumerating = true;
|
||||||
|
|
||||||
k = process(nl, reply_one, m);
|
k = process(m->rtnl, reply_one, m);
|
||||||
if (k < 0 && r >= 0)
|
if (k < 0 && r >= 0)
|
||||||
r = k;
|
r = k;
|
||||||
|
|
||||||
@ -623,7 +608,7 @@ static int manager_enumerate_links(Manager *m) {
|
|||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
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) {
|
static int manager_enumerate_addresses(Manager *m) {
|
||||||
@ -637,7 +622,7 @@ static int manager_enumerate_addresses(Manager *m) {
|
|||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
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) {
|
static int manager_enumerate_neighbors(Manager *m) {
|
||||||
@ -651,7 +636,7 @@ static int manager_enumerate_neighbors(Manager *m) {
|
|||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
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) {
|
static int manager_enumerate_routes(Manager *m) {
|
||||||
@ -668,7 +653,7 @@ static int manager_enumerate_routes(Manager *m) {
|
|||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
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) {
|
static int manager_enumerate_rules(Manager *m) {
|
||||||
@ -685,7 +670,7 @@ static int manager_enumerate_rules(Manager *m) {
|
|||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
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) {
|
static int manager_enumerate_nexthop(Manager *m) {
|
||||||
@ -699,50 +684,7 @@ static int manager_enumerate_nexthop(Manager *m) {
|
|||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
return manager_enumerate_internal(m, m->rtnl, req, manager_rtnl_process_nexthop);
|
return manager_enumerate_internal(m, req, manager_rtnl_process_nexthop, "Nexthop rules");
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int manager_enumerate(Manager *m) {
|
int manager_enumerate(Manager *m) {
|
||||||
@ -760,37 +702,18 @@ int manager_enumerate(Manager *m) {
|
|||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Could not enumerate neighbors: %m");
|
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);
|
r = manager_enumerate_nexthop(m);
|
||||||
if (r == -EOPNOTSUPP || (r == -EINVAL && mac_selinux_enforcing()))
|
if (r < 0)
|
||||||
log_debug_errno(r, "Could not enumerate nexthops, ignoring: %m");
|
return log_error_errno(r, "Could not enumerate nexthop rules: %m");
|
||||||
else if (r < 0)
|
|
||||||
return log_error_errno(r, "Could not enumerate nexthops: %m");
|
|
||||||
|
|
||||||
r = manager_enumerate_routes(m);
|
r = manager_enumerate_routes(m);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Could not enumerate routes: %m");
|
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);
|
r = manager_enumerate_rules(m);
|
||||||
if (r == -EOPNOTSUPP)
|
if (r < 0)
|
||||||
log_debug_errno(r, "Could not enumerate routing policy rules, ignoring: %m");
|
|
||||||
else if (r < 0)
|
|
||||||
return log_error_errno(r, "Could not enumerate routing policy rules: %m");
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -28,7 +28,6 @@ struct Manager {
|
|||||||
Hashmap *polkit_registry;
|
Hashmap *polkit_registry;
|
||||||
int ethtool_fd;
|
int ethtool_fd;
|
||||||
|
|
||||||
bool test_mode;
|
|
||||||
bool enumerating;
|
bool enumerating;
|
||||||
bool dirty;
|
bool dirty;
|
||||||
bool restarting;
|
bool restarting;
|
||||||
@ -50,6 +49,8 @@ struct Manager {
|
|||||||
Hashmap *links_by_hw_addr;
|
Hashmap *links_by_hw_addr;
|
||||||
Hashmap *netdevs;
|
Hashmap *netdevs;
|
||||||
OrderedHashmap *networks;
|
OrderedHashmap *networks;
|
||||||
|
Hashmap *dhcp6_prefixes;
|
||||||
|
Set *dhcp6_pd_prefixes;
|
||||||
OrderedSet *address_pools;
|
OrderedSet *address_pools;
|
||||||
|
|
||||||
usec_t network_dirs_ts_usec;
|
usec_t network_dirs_ts_usec;
|
||||||
@ -95,10 +96,10 @@ struct Manager {
|
|||||||
OrderedSet *request_queue;
|
OrderedSet *request_queue;
|
||||||
};
|
};
|
||||||
|
|
||||||
int manager_new(Manager **ret, bool test_mode);
|
int manager_new(Manager **ret);
|
||||||
Manager* manager_free(Manager *m);
|
Manager* manager_free(Manager *m);
|
||||||
|
|
||||||
int manager_setup(Manager *m);
|
int manager_connect_bus(Manager *m);
|
||||||
int manager_start(Manager *m);
|
int manager_start(Manager *m);
|
||||||
|
|
||||||
int manager_load_config(Manager *m);
|
int manager_load_config(Manager *m);
|
||||||
|
|||||||
@ -16,7 +16,6 @@
|
|||||||
#include "networkd-manager.h"
|
#include "networkd-manager.h"
|
||||||
#include "networkd-ndisc.h"
|
#include "networkd-ndisc.h"
|
||||||
#include "networkd-queue.h"
|
#include "networkd-queue.h"
|
||||||
#include "networkd-route.h"
|
|
||||||
#include "networkd-state-file.h"
|
#include "networkd-state-file.h"
|
||||||
#include "string-table.h"
|
#include "string-table.h"
|
||||||
#include "string-util.h"
|
#include "string-util.h"
|
||||||
@ -97,62 +96,112 @@ void network_adjust_ipv6_accept_ra(Network *network) {
|
|||||||
network->ndisc_deny_listed_route_prefix = set_free_free(network->ndisc_deny_listed_route_prefix);
|
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) {
|
static int ndisc_remove_old_one(Link *link, const struct in6_addr *router, bool force);
|
||||||
bool updated = false;
|
|
||||||
|
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;
|
NDiscDNSSL *dnssl;
|
||||||
NDiscRDNSS *rdnss;
|
NDiscRDNSS *rdnss;
|
||||||
Address *address;
|
|
||||||
Route *route;
|
|
||||||
int k, r = 0;
|
int k, r = 0;
|
||||||
|
bool updated = false;
|
||||||
|
|
||||||
assert(link);
|
assert(link);
|
||||||
|
assert(router);
|
||||||
|
|
||||||
SET_FOREACH(route, link->routes) {
|
if (!force) {
|
||||||
if (route->source != NETWORK_CONFIG_SOURCE_NDISC)
|
bool set_callback = false;
|
||||||
continue;
|
|
||||||
if (!route_is_marked(route))
|
|
||||||
continue;
|
|
||||||
if (router && !in6_addr_equal(router, &route->provider.in6))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
k = route_remove(route);
|
SET_FOREACH(na, link->ndisc_addresses)
|
||||||
if (k < 0)
|
if (!na->marked && in6_addr_equal(&na->router, router)) {
|
||||||
r = k;
|
set_callback = true;
|
||||||
|
break;
|
||||||
route_cancel_request(route);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SET_FOREACH(address, link->addresses) {
|
if (set_callback)
|
||||||
if (address->source != NETWORK_CONFIG_SOURCE_NDISC)
|
SET_FOREACH(na, link->ndisc_addresses)
|
||||||
continue;
|
if (!na->marked && address_is_ready(na->address)) {
|
||||||
if (!address_is_marked(address))
|
set_callback = false;
|
||||||
continue;
|
break;
|
||||||
if (router && !in6_addr_equal(router, &address->provider.in6))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
k = address_remove(address);
|
|
||||||
if (k < 0)
|
|
||||||
r = k;
|
|
||||||
|
|
||||||
address_cancel_request(address);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SET_FOREACH(rdnss, link->ndisc_rdnss) {
|
if (set_callback) {
|
||||||
if (!rdnss->marked)
|
SET_FOREACH(na, link->ndisc_addresses)
|
||||||
continue;
|
if (!na->marked && in6_addr_equal(&na->router, router))
|
||||||
if (router && !in6_addr_equal(router, &rdnss->router))
|
na->address->callback = ndisc_address_callback;
|
||||||
continue;
|
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (DEBUG_LOGGING) {
|
||||||
|
_cleanup_free_ char *buf = NULL;
|
||||||
|
|
||||||
|
(void) in6_addr_to_string(router, &buf);
|
||||||
|
log_link_debug(link, "Removing old NDisc information obtained from %s.", strna(buf));
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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(rdnss, link->ndisc_rdnss)
|
||||||
|
if (rdnss->marked && in6_addr_equal(&rdnss->router, router)) {
|
||||||
free(set_remove(link->ndisc_rdnss, rdnss));
|
free(set_remove(link->ndisc_rdnss, rdnss));
|
||||||
updated = true;
|
updated = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
SET_FOREACH(dnssl, link->ndisc_dnssl) {
|
SET_FOREACH(dnssl, link->ndisc_dnssl)
|
||||||
if (!dnssl->marked)
|
if (dnssl->marked && in6_addr_equal(&dnssl->router, router)) {
|
||||||
continue;
|
|
||||||
if (router && !in6_addr_equal(router, &dnssl->router))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
free(set_remove(link->ndisc_dnssl, dnssl));
|
free(set_remove(link->ndisc_dnssl, dnssl));
|
||||||
updated = true;
|
updated = true;
|
||||||
}
|
}
|
||||||
@ -163,100 +212,197 @@ static int ndisc_remove(Link *link, struct in6_addr *router) {
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ndisc_check_ready(Link *link);
|
static int ndisc_remove_old(Link *link) {
|
||||||
|
_cleanup_set_free_free_ Set *routers = NULL;
|
||||||
static int ndisc_address_ready_callback(Address *address) {
|
_cleanup_free_ struct in6_addr *router = NULL;
|
||||||
Address *a;
|
struct in6_addr *a;
|
||||||
|
NDiscAddress *na;
|
||||||
assert(address);
|
NDiscRoute *nr;
|
||||||
assert(address->link);
|
NDiscDNSSL *dnssl;
|
||||||
|
NDiscRDNSS *rdnss;
|
||||||
SET_FOREACH(a, address->link->addresses)
|
int k, r;
|
||||||
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;
|
|
||||||
|
|
||||||
assert(link);
|
assert(link);
|
||||||
|
|
||||||
if (link->ndisc_messages > 0) {
|
if (link->ndisc_addresses_messages > 0 ||
|
||||||
log_link_debug(link, "%s(): SLAAC addresses and routes are not set.", __func__);
|
link->ndisc_routes_messages > 0)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
|
||||||
|
|
||||||
SET_FOREACH(address, link->addresses) {
|
routers = set_new(&in6_addr_hash_ops);
|
||||||
if (address->source != NETWORK_CONFIG_SOURCE_NDISC)
|
if (!routers)
|
||||||
continue;
|
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)) {
|
r = set_put(routers, router);
|
||||||
ready = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
link_check_ready(link);
|
assert(r > 0);
|
||||||
return 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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) {
|
static int ndisc_route_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
assert(link);
|
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");
|
r = route_configure_handler_internal(rtnl, m, link, "Could not set NDisc route");
|
||||||
if (r <= 0)
|
if (r <= 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
r = ndisc_check_ready(link);
|
if (link->ndisc_routes_messages == 0) {
|
||||||
if (r < 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);
|
link_enter_failed(link);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
link_check_ready(link);
|
||||||
|
}
|
||||||
|
|
||||||
return 1;
|
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) {
|
static int ndisc_request_route(Route *in, Link *link, sd_ndisc_router *rt) {
|
||||||
_cleanup_(route_freep) Route *route = in;
|
_cleanup_(route_freep) Route *route = in;
|
||||||
struct in6_addr router;
|
Request *req;
|
||||||
Route *existing;
|
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
assert(route);
|
assert(route);
|
||||||
assert(link);
|
assert(link);
|
||||||
assert(rt);
|
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)
|
if (!route->table_set)
|
||||||
route->table = link_get_ipv6_accept_ra_route_table(link);
|
route->table = link_get_ipv6_accept_ra_route_table(link);
|
||||||
if (!route->priority_set)
|
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)
|
if (!route->protocol_set)
|
||||||
route->protocol = RTPROT_RA;
|
route->protocol = RTPROT_RA;
|
||||||
|
|
||||||
if (route_get(NULL, link, route, &existing) < 0)
|
r = link_has_route(link, route);
|
||||||
link->ndisc_configured = false;
|
if (r < 0)
|
||||||
else
|
return r;
|
||||||
route_unmark(existing);
|
if (r == 0)
|
||||||
|
link->ndisc_routes_configured = false;
|
||||||
|
|
||||||
return link_request_route(link, TAKE_PTR(route), true, &link->ndisc_messages,
|
r = link_request_route(link, TAKE_PTR(route), true, &link->ndisc_routes_messages,
|
||||||
ndisc_route_handler, NULL);
|
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) {
|
static int ndisc_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
assert(link);
|
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");
|
r = address_configure_handler_internal(rtnl, m, link, "Could not set NDisc address");
|
||||||
if (r <= 0)
|
if (r <= 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
r = ndisc_check_ready(link);
|
if (link->ndisc_addresses_messages == 0) {
|
||||||
if (r < 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);
|
link_enter_failed(link);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
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) {
|
static int ndisc_request_address(Address *in, Link *link, sd_ndisc_router *rt) {
|
||||||
_cleanup_(address_freep) Address *address = in;
|
_cleanup_(address_freep) Address *address = in;
|
||||||
struct in6_addr router;
|
Request *req;
|
||||||
Address *existing;
|
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
assert(address);
|
assert(address);
|
||||||
assert(link);
|
assert(link);
|
||||||
assert(rt);
|
assert(rt);
|
||||||
|
|
||||||
r = sd_ndisc_router_get_address(rt, &router);
|
if (address_get(link, address, NULL) < 0)
|
||||||
if (r < 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;
|
return r;
|
||||||
|
|
||||||
address->source = NETWORK_CONFIG_SOURCE_NDISC;
|
req->userdata = sd_ndisc_router_ref(rt);
|
||||||
address->provider.in6 = router;
|
req->after_configure = ndisc_after_address_configure;
|
||||||
|
req->on_free = ndisc_request_on_free;
|
||||||
|
|
||||||
if (address_get(link, address, &existing) < 0)
|
return 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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ndisc_router_process_default(Link *link, sd_ndisc_router *rt) {
|
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;
|
uint32_t lifetime;
|
||||||
const struct in6_addr *a;
|
const struct in6_addr *a;
|
||||||
struct in6_addr router;
|
struct in6_addr router;
|
||||||
|
NDiscRDNSS *rdnss;
|
||||||
usec_t time_now;
|
usec_t time_now;
|
||||||
bool updated = false;
|
bool updated = false;
|
||||||
int n, r;
|
int n, r;
|
||||||
@ -788,6 +1011,10 @@ static int ndisc_router_process_rdnss(Link *link, sd_ndisc_router *rt) {
|
|||||||
if (n < 0)
|
if (n < 0)
|
||||||
return log_link_error_errno(link, n, "Failed to get RDNSS addresses: %m");
|
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)
|
if (lifetime == 0)
|
||||||
return 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++) {
|
for (int j = 0; j < n; j++) {
|
||||||
_cleanup_free_ NDiscRDNSS *x = NULL;
|
_cleanup_free_ NDiscRDNSS *x = NULL;
|
||||||
NDiscRDNSS *rdnss, d = {
|
NDiscRDNSS d = {
|
||||||
.address = a[j],
|
.address = a[j],
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -854,6 +1081,7 @@ static int ndisc_router_process_dnssl(Link *link, sd_ndisc_router *rt) {
|
|||||||
struct in6_addr router;
|
struct in6_addr router;
|
||||||
uint32_t lifetime;
|
uint32_t lifetime;
|
||||||
usec_t time_now;
|
usec_t time_now;
|
||||||
|
NDiscDNSSL *dnssl;
|
||||||
bool updated = false;
|
bool updated = false;
|
||||||
char **j;
|
char **j;
|
||||||
int r;
|
int r;
|
||||||
@ -877,6 +1105,10 @@ static int ndisc_router_process_dnssl(Link *link, sd_ndisc_router *rt) {
|
|||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_link_error_errno(link, r, "Failed to get DNSSL addresses: %m");
|
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)
|
if (lifetime == 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
@ -888,7 +1120,6 @@ static int ndisc_router_process_dnssl(Link *link, sd_ndisc_router *rt) {
|
|||||||
|
|
||||||
STRV_FOREACH(j, l) {
|
STRV_FOREACH(j, l) {
|
||||||
_cleanup_free_ NDiscDNSSL *s = NULL;
|
_cleanup_free_ NDiscDNSSL *s = NULL;
|
||||||
NDiscDNSSL *dnssl;
|
|
||||||
|
|
||||||
s = malloc0(ALIGN(sizeof(NDiscDNSSL)) + strlen(*j) + 1);
|
s = malloc0(ALIGN(sizeof(NDiscDNSSL)) + strlen(*j) + 1);
|
||||||
if (!s)
|
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) {
|
static int ndisc_router_handler(Link *link, sd_ndisc_router *rt) {
|
||||||
struct in6_addr router;
|
struct in6_addr router;
|
||||||
uint64_t flags;
|
uint64_t flags;
|
||||||
|
NDiscAddress *na;
|
||||||
|
NDiscRoute *nr;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
assert(link);
|
assert(link);
|
||||||
@ -1057,7 +1271,13 @@ static int ndisc_router_handler(Link *link, sd_ndisc_router *rt) {
|
|||||||
return 0;
|
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);
|
r = sd_ndisc_router_get_flags(rt, &flags);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
@ -1087,16 +1307,21 @@ static int ndisc_router_handler(Link *link, sd_ndisc_router *rt) {
|
|||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
if (link->ndisc_messages == 0) {
|
if (link->ndisc_addresses_messages == 0)
|
||||||
link->ndisc_configured = true;
|
link->ndisc_addresses_configured = true;
|
||||||
|
else
|
||||||
|
log_link_debug(link, "Setting SLAAC addresses.");
|
||||||
|
|
||||||
r = ndisc_remove(link, &router);
|
if (link->ndisc_routes_messages == 0)
|
||||||
|
link->ndisc_routes_configured = true;
|
||||||
|
else
|
||||||
|
log_link_debug(link, "Setting NDisc routes.");
|
||||||
|
|
||||||
|
r = ndisc_remove_old(link);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
} else
|
|
||||||
log_link_debug(link, "Setting SLAAC addresses and router.");
|
|
||||||
|
|
||||||
if (!link->ndisc_configured)
|
if (!link->ndisc_addresses_configured || !link->ndisc_routes_configured)
|
||||||
link_set_state(link, LINK_STATE_CONFIGURING);
|
link_set_state(link, LINK_STATE_CONFIGURING);
|
||||||
|
|
||||||
link_check_ready(link);
|
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:
|
case SD_NDISC_EVENT_TIMEOUT:
|
||||||
log_link_debug(link, "NDisc handler get timeout event");
|
log_link_debug(link, "NDisc handler get timeout event");
|
||||||
if (link->ndisc_messages == 0) {
|
if (link->ndisc_addresses_messages == 0 && link->ndisc_routes_messages == 0) {
|
||||||
link->ndisc_configured = true;
|
link->ndisc_addresses_configured = true;
|
||||||
|
link->ndisc_routes_configured = true;
|
||||||
link_check_ready(link);
|
link_check_ready(link);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -1177,9 +1403,6 @@ int ndisc_start(Link *link) {
|
|||||||
if (!link_has_carrier(link))
|
if (!link_has_carrier(link))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (in6_addr_is_null(&link->ipv6ll_address))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
log_link_debug(link, "Discovering IPv6 routers");
|
log_link_debug(link, "Discovering IPv6 routers");
|
||||||
|
|
||||||
return sd_ndisc_start(link->ndisc);
|
return sd_ndisc_start(link->ndisc);
|
||||||
@ -1336,15 +1559,14 @@ int config_parse_address_generation_type(
|
|||||||
return 0;
|
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] = {
|
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_NO] = "no",
|
||||||
[IPV6_ACCEPT_RA_START_DHCP6_CLIENT_ALWAYS] = "always",
|
[IPV6_ACCEPT_RA_START_DHCP6_CLIENT_ALWAYS] = "always",
|
||||||
[IPV6_ACCEPT_RA_START_DHCP6_CLIENT_YES] = "yes",
|
[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_STRING_TABLE_LOOKUP_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");
|
|
||||||
|
|||||||
@ -2,11 +2,11 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "conf-parser.h"
|
#include "conf-parser.h"
|
||||||
|
#include "networkd-address.h"
|
||||||
|
#include "networkd-link.h"
|
||||||
|
#include "networkd-route.h"
|
||||||
#include "time-util.h"
|
#include "time-util.h"
|
||||||
|
|
||||||
typedef struct Link Link;
|
|
||||||
typedef struct Network Network;
|
|
||||||
|
|
||||||
typedef enum IPv6AcceptRAStartDHCP6Client {
|
typedef enum IPv6AcceptRAStartDHCP6Client {
|
||||||
IPV6_ACCEPT_RA_START_DHCP6_CLIENT_NO,
|
IPV6_ACCEPT_RA_START_DHCP6_CLIENT_NO,
|
||||||
IPV6_ACCEPT_RA_START_DHCP6_CLIENT_ALWAYS,
|
IPV6_ACCEPT_RA_START_DHCP6_CLIENT_ALWAYS,
|
||||||
@ -15,6 +15,20 @@ typedef enum IPv6AcceptRAStartDHCP6Client {
|
|||||||
_IPV6_ACCEPT_RA_START_DHCP6_CLIENT_INVALID = -EINVAL,
|
_IPV6_ACCEPT_RA_START_DHCP6_CLIENT_INVALID = -EINVAL,
|
||||||
} IPv6AcceptRAStartDHCP6Client;
|
} 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 {
|
typedef struct NDiscRDNSS {
|
||||||
/* Used when GC'ing old DNS servers when configuration changes. */
|
/* Used when GC'ing old DNS servers when configuration changes. */
|
||||||
bool marked;
|
bool marked;
|
||||||
@ -47,3 +61,6 @@ void ndisc_flush(Link *link);
|
|||||||
CONFIG_PARSER_PROTOTYPE(config_parse_address_generation_type);
|
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_start_dhcp6_client);
|
||||||
CONFIG_PARSER_PROTOTYPE(config_parse_ipv6_accept_ra_use_domains);
|
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_;
|
||||||
|
|||||||
@ -49,7 +49,7 @@ Match.PermanentMACAddress, config_parse_hwaddrs,
|
|||||||
Match.Path, config_parse_match_strv, 0, offsetof(Network, match.path)
|
Match.Path, config_parse_match_strv, 0, offsetof(Network, match.path)
|
||||||
Match.Driver, config_parse_match_strv, 0, offsetof(Network, match.driver)
|
Match.Driver, config_parse_match_strv, 0, offsetof(Network, match.driver)
|
||||||
Match.Type, config_parse_match_strv, 0, offsetof(Network, match.iftype)
|
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.SSID, config_parse_match_strv, 0, offsetof(Network, match.ssid)
|
||||||
Match.BSSID, config_parse_hwaddrs, 0, offsetof(Network, match.bssid)
|
Match.BSSID, config_parse_hwaddrs, 0, offsetof(Network, match.bssid)
|
||||||
Match.Name, config_parse_match_ifnames, IFNAME_VALID_ALTERNATIVE, offsetof(Network, match.ifname)
|
Match.Name, config_parse_match_ifnames, IFNAME_VALID_ALTERNATIVE, offsetof(Network, match.ifname)
|
||||||
|
|||||||
@ -28,7 +28,6 @@
|
|||||||
#include "networkd-network.h"
|
#include "networkd-network.h"
|
||||||
#include "networkd-nexthop.h"
|
#include "networkd-nexthop.h"
|
||||||
#include "networkd-radv.h"
|
#include "networkd-radv.h"
|
||||||
#include "networkd-route.h"
|
|
||||||
#include "networkd-routing-policy-rule.h"
|
#include "networkd-routing-policy-rule.h"
|
||||||
#include "networkd-sriov.h"
|
#include "networkd-sriov.h"
|
||||||
#include "parse-util.h"
|
#include "parse-util.h"
|
||||||
|
|||||||
@ -743,6 +743,8 @@ static bool nexthop_is_ready_to_configure(Link *link, const NextHop *nexthop) {
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (nexthop_owned_by_link(nexthop)) {
|
if (nexthop_owned_by_link(nexthop)) {
|
||||||
|
Link *l;
|
||||||
|
|
||||||
/* TODO: fdb nexthop does not require IFF_UP. The conditions below needs to be updated
|
/* 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
|
* when fdb nexthop support is added. See rtm_to_nh_config() in net/ipv4/nexthop.c of
|
||||||
* kernel. */
|
* kernel. */
|
||||||
@ -750,6 +752,13 @@ static bool nexthop_is_ready_to_configure(Link *link, const NextHop *nexthop) {
|
|||||||
return false;
|
return false;
|
||||||
if (!FLAGS_SET(link->flags, IFF_UP))
|
if (!FLAGS_SET(link->flags, IFF_UP))
|
||||||
return false;
|
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. */
|
/* All group members must be configured first. */
|
||||||
|
|||||||
@ -70,6 +70,9 @@ static Request *request_free(Request *req) {
|
|||||||
/* To prevent from triggering assertions in hash functions, remove this request before
|
/* To prevent from triggering assertions in hash functions, remove this request before
|
||||||
* freeing object below. */
|
* freeing object below. */
|
||||||
ordered_set_remove(req->link->manager->request_queue, req);
|
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)
|
if (req->consume_object)
|
||||||
request_free_object(req->type, req->object);
|
request_free_object(req->type, req->object);
|
||||||
link_unref(req->link);
|
link_unref(req->link);
|
||||||
|
|||||||
@ -15,6 +15,11 @@ typedef struct NextHop NextHop;
|
|||||||
typedef struct Route Route;
|
typedef struct Route Route;
|
||||||
typedef struct RoutingPolicyRule RoutingPolicyRule;
|
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 {
|
typedef enum RequestType {
|
||||||
REQUEST_TYPE_ACTIVATE_LINK,
|
REQUEST_TYPE_ACTIVATE_LINK,
|
||||||
REQUEST_TYPE_ADDRESS,
|
REQUEST_TYPE_ADDRESS,
|
||||||
@ -58,6 +63,8 @@ typedef struct Request {
|
|||||||
void *userdata;
|
void *userdata;
|
||||||
unsigned *message_counter;
|
unsigned *message_counter;
|
||||||
link_netlink_message_handler_t netlink_handler;
|
link_netlink_message_handler_t netlink_handler;
|
||||||
|
request_after_configure_handler_t after_configure;
|
||||||
|
request_on_free_handler_t on_free;
|
||||||
} Request;
|
} Request;
|
||||||
|
|
||||||
void request_drop(Request *req);
|
void request_drop(Request *req);
|
||||||
|
|||||||
@ -7,13 +7,11 @@
|
|||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
|
|
||||||
#include "dns-domain.h"
|
#include "dns-domain.h"
|
||||||
#include "networkd-address.h"
|
|
||||||
#include "networkd-link.h"
|
#include "networkd-link.h"
|
||||||
#include "networkd-manager.h"
|
#include "networkd-manager.h"
|
||||||
#include "networkd-network.h"
|
#include "networkd-network.h"
|
||||||
#include "networkd-queue.h"
|
#include "networkd-queue.h"
|
||||||
#include "networkd-radv.h"
|
#include "networkd-radv.h"
|
||||||
#include "networkd-route.h"
|
|
||||||
#include "parse-util.h"
|
#include "parse-util.h"
|
||||||
#include "string-util.h"
|
#include "string-util.h"
|
||||||
#include "string-table.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(
|
int config_parse_prefix(
|
||||||
const char *unit,
|
const char *unit,
|
||||||
const char *filename,
|
const char *filename,
|
||||||
@ -710,6 +660,15 @@ static int radv_find_uplink(Link *link, Link **ret) {
|
|||||||
return 0;
|
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) {
|
static int radv_configure(Link *link) {
|
||||||
uint16_t router_lifetime;
|
uint16_t router_lifetime;
|
||||||
Link *uplink = NULL;
|
Link *uplink = NULL;
|
||||||
|
|||||||
@ -51,8 +51,6 @@ void network_drop_invalid_prefixes(Network *network);
|
|||||||
void network_drop_invalid_route_prefixes(Network *network);
|
void network_drop_invalid_route_prefixes(Network *network);
|
||||||
void network_adjust_radv(Network *network);
|
void network_adjust_radv(Network *network);
|
||||||
|
|
||||||
int link_request_radv_addresses(Link *link);
|
|
||||||
|
|
||||||
int radv_update_mac(Link *link);
|
int radv_update_mac(Link *link);
|
||||||
int radv_add_prefix(Link *link, const struct in6_addr *prefix, uint8_t prefix_len,
|
int radv_add_prefix(Link *link, const struct in6_addr *prefix, uint8_t prefix_len,
|
||||||
uint32_t lifetime_preferred, uint32_t lifetime_valid);
|
uint32_t lifetime_preferred, uint32_t lifetime_valid);
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -16,13 +16,11 @@ typedef struct Network Network;
|
|||||||
typedef struct Request Request;
|
typedef struct Request Request;
|
||||||
|
|
||||||
typedef struct Route {
|
typedef struct Route {
|
||||||
Link *link;
|
|
||||||
Manager *manager;
|
|
||||||
Network *network;
|
Network *network;
|
||||||
NetworkConfigSection *section;
|
NetworkConfigSection *section;
|
||||||
NetworkConfigSource source;
|
|
||||||
NetworkConfigState state;
|
Link *link;
|
||||||
union in_addr_union provider; /* DHCP server or router address */
|
Manager *manager;
|
||||||
|
|
||||||
int family;
|
int family;
|
||||||
int gw_family;
|
int gw_family;
|
||||||
@ -54,6 +52,7 @@ typedef struct Route {
|
|||||||
bool protocol_set:1;
|
bool protocol_set:1;
|
||||||
bool pref_set:1;
|
bool pref_set:1;
|
||||||
bool gateway_from_dhcp_or_ra:1;
|
bool gateway_from_dhcp_or_ra:1;
|
||||||
|
bool removing:1;
|
||||||
|
|
||||||
union in_addr_union gw;
|
union in_addr_union gw;
|
||||||
union in_addr_union dst;
|
union in_addr_union dst;
|
||||||
@ -67,6 +66,7 @@ typedef struct Route {
|
|||||||
|
|
||||||
void route_hash_func(const Route *route, struct siphash *state);
|
void route_hash_func(const Route *route, struct siphash *state);
|
||||||
int route_compare_func(const Route *a, const Route *b);
|
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;
|
extern const struct hash_ops route_hash_ops;
|
||||||
|
|
||||||
int route_new(Route **ret);
|
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_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_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);
|
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);
|
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_routes(Link *link);
|
||||||
int link_drop_foreign_routes(Link *link);
|
int link_drop_foreign_routes(Link *link);
|
||||||
|
|
||||||
void route_cancel_request(Route *route);
|
|
||||||
int link_request_route(
|
int link_request_route(
|
||||||
Link *link,
|
Link *link,
|
||||||
Route *route,
|
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_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);
|
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_gateway);
|
||||||
CONFIG_PARSER_PROTOTYPE(config_parse_preferred_src);
|
CONFIG_PARSER_PROTOTYPE(config_parse_preferred_src);
|
||||||
CONFIG_PARSER_PROTOTYPE(config_parse_destination);
|
CONFIG_PARSER_PROTOTYPE(config_parse_destination);
|
||||||
|
|||||||
@ -6,7 +6,6 @@
|
|||||||
|
|
||||||
#include "missing_network.h"
|
#include "missing_network.h"
|
||||||
#include "netlink-util.h"
|
#include "netlink-util.h"
|
||||||
#include "networkd-address.h"
|
|
||||||
#include "networkd-can.h"
|
#include "networkd-can.h"
|
||||||
#include "networkd-link.h"
|
#include "networkd-link.h"
|
||||||
#include "networkd-manager.h"
|
#include "networkd-manager.h"
|
||||||
|
|||||||
@ -119,9 +119,7 @@ int manager_save(Manager *m) {
|
|||||||
int r;
|
int r;
|
||||||
|
|
||||||
assert(m);
|
assert(m);
|
||||||
|
assert(m->state_file);
|
||||||
if (isempty(m->state_file))
|
|
||||||
return 0; /* Do not update state file when running in test mode. */
|
|
||||||
|
|
||||||
HASHMAP_FOREACH(link, m->links_by_index) {
|
HASHMAP_FOREACH(link, m->links_by_index) {
|
||||||
const struct in_addr *addresses;
|
const struct in_addr *addresses;
|
||||||
@ -425,11 +423,10 @@ int link_save(Link *link) {
|
|||||||
int r;
|
int r;
|
||||||
|
|
||||||
assert(link);
|
assert(link);
|
||||||
|
assert(link->state_file);
|
||||||
|
assert(link->lease_file);
|
||||||
assert(link->manager);
|
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)
|
if (link->state == LINK_STATE_LINGER)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
|||||||
@ -3,7 +3,11 @@
|
|||||||
#include <net/ethernet.h>
|
#include <net/ethernet.h>
|
||||||
#include <linux/nl80211.h>
|
#include <linux/nl80211.h>
|
||||||
|
|
||||||
|
#include "sd-bus.h"
|
||||||
|
|
||||||
|
#include "bus-util.h"
|
||||||
#include "ether-addr-util.h"
|
#include "ether-addr-util.h"
|
||||||
|
#include "netlink-internal.h"
|
||||||
#include "netlink-util.h"
|
#include "netlink-util.h"
|
||||||
#include "networkd-link.h"
|
#include "networkd-link.h"
|
||||||
#include "networkd-manager.h"
|
#include "networkd-manager.h"
|
||||||
@ -11,275 +15,56 @@
|
|||||||
#include "string-util.h"
|
#include "string-util.h"
|
||||||
#include "wifi-util.h"
|
#include "wifi-util.h"
|
||||||
|
|
||||||
static int link_get_wlan_interface(Link *link) {
|
int wifi_get_info(Link *link) {
|
||||||
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL;
|
_cleanup_free_ char *ssid = NULL;
|
||||||
|
enum nl80211_iftype iftype;
|
||||||
|
bool updated = false;
|
||||||
|
const char *type;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
assert(link);
|
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)
|
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 (iftype == NL80211_IFTYPE_STATION) {
|
||||||
|
struct ether_addr bssid;
|
||||||
|
|
||||||
|
r = wifi_get_station(link->manager->genl, link->ifindex, &bssid);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_link_debug_errno(link, r, "Could not append NL80211_ATTR_IFINDEX attribute: %m");
|
return r;
|
||||||
|
|
||||||
r = sd_netlink_call(link->manager->genl, req, 0, &reply);
|
updated = !ether_addr_equal(&link->bssid, &bssid);
|
||||||
if (r < 0)
|
link->bssid = bssid;
|
||||||
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);
|
updated = updated || link->wlan_iftype != iftype;
|
||||||
}
|
link->wlan_iftype = iftype;
|
||||||
|
updated = updated || !streq_ptr(link->ssid, ssid);
|
||||||
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);
|
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: {
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if (updated) {
|
||||||
if (link->wlan_iftype == NL80211_IFTYPE_STATION && link->ssid)
|
if (link->wlan_iftype == NL80211_IFTYPE_STATION && link->ssid)
|
||||||
log_link_info(link, "Connected WiFi access point: %s (%s)",
|
log_link_info(link, "Connected WiFi access point: %s (%s)",
|
||||||
link->ssid, ETHER_ADDR_TO_STR(&link->bssid));
|
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;
|
return 1; /* Some information is updated. */
|
||||||
link->ssid = mfree(link->ssid);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
log_link_debug(link, "nl80211: received %s(%u) message.",
|
|
||||||
strna(nl80211_cmd_to_string(cmd)), cmd);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0; /* No new information. */
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,9 +1,8 @@
|
|||||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||||
#pragma once
|
#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 wifi_get_info(Link *link);
|
||||||
int manager_genl_process_nl80211_mlme(sd_netlink *genl, sd_netlink_message *message, Manager *manager);
|
|
||||||
|
|||||||
@ -73,13 +73,13 @@ static int run(int argc, char *argv[]) {
|
|||||||
|
|
||||||
assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGTERM, SIGINT, -1) >= 0);
|
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)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Could not create manager: %m");
|
return log_error_errno(r, "Could not create manager: %m");
|
||||||
|
|
||||||
r = manager_setup(m);
|
r = manager_connect_bus(m);
|
||||||
if (r < 0)
|
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);
|
r = manager_parse_config_file(m);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
|
|||||||
@ -10,9 +10,7 @@
|
|||||||
#include "ether-addr-util.h"
|
#include "ether-addr-util.h"
|
||||||
#include "hostname-setup.h"
|
#include "hostname-setup.h"
|
||||||
#include "network-internal.h"
|
#include "network-internal.h"
|
||||||
#include "networkd-address.h"
|
|
||||||
#include "networkd-manager.h"
|
#include "networkd-manager.h"
|
||||||
#include "networkd-route.h"
|
|
||||||
#include "string-util.h"
|
#include "string-util.h"
|
||||||
#include "strv.h"
|
#include "strv.h"
|
||||||
#include "tests.h"
|
#include "tests.h"
|
||||||
@ -170,16 +168,6 @@ static int test_load_config(Manager *manager) {
|
|||||||
return 0;
|
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) {
|
static void test_address_equality(void) {
|
||||||
_cleanup_(address_freep) Address *a1 = NULL, *a2 = NULL;
|
_cleanup_(address_freep) Address *a1 = NULL, *a2 = NULL;
|
||||||
|
|
||||||
@ -281,8 +269,7 @@ int main(void) {
|
|||||||
test_address_equality();
|
test_address_equality();
|
||||||
test_dhcp_hostname_shorten_overlong();
|
test_dhcp_hostname_shorten_overlong();
|
||||||
|
|
||||||
assert_se(manager_new(&manager, /* test_mode = */ true) >= 0);
|
assert_se(manager_new(&manager) >= 0);
|
||||||
assert_se(manager_setup(manager) >= 0);
|
|
||||||
|
|
||||||
test_route_tables(manager);
|
test_route_tables(manager);
|
||||||
|
|
||||||
|
|||||||
@ -4,7 +4,6 @@
|
|||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "macro.h"
|
#include "macro.h"
|
||||||
#include "net-condition.h"
|
#include "net-condition.h"
|
||||||
#include "networkd-address.h"
|
|
||||||
#include "networkd-conf.h"
|
#include "networkd-conf.h"
|
||||||
#include "networkd-network.h"
|
#include "networkd-network.h"
|
||||||
#include "strv.h"
|
#include "strv.h"
|
||||||
|
|||||||
@ -39,8 +39,8 @@ static int resolvconf_help(void) {
|
|||||||
"This is a compatibility alias for the resolvectl(1) tool, providing native\n"
|
"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"
|
"command line compatibility with the resolvconf(8) tool of various Linux\n"
|
||||||
"distributions and BSD systems. Some options supported by other implementations\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"
|
"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:\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"
|
"-I, -i, -l, -R, -r, -v, -V, --enable-updates, --disable-updates,\n"
|
||||||
"--updates-are-enabled.\n"
|
"--updates-are-enabled.\n"
|
||||||
"\nSee the %2$s for details.\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);
|
log_debug("Switch -%c ignored.", c);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* -u supposedly should "update all subscribers". We have no subscribers, hence let's make
|
/* Everybody else can agree on the existence of -u but we don't support it. */
|
||||||
this a NOP, and exit immediately, cleanly. */
|
|
||||||
case 'u':
|
case 'u':
|
||||||
log_info("Switch -%c ignored.", c);
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
/* The following options are openresolv inventions we don't support. */
|
/* The following options are openresolv inventions we don't support. */
|
||||||
case 'I':
|
case 'I':
|
||||||
|
|||||||
@ -10,7 +10,6 @@
|
|||||||
#include "socket-util.h"
|
#include "socket-util.h"
|
||||||
#include "string-table.h"
|
#include "string-table.h"
|
||||||
#include "strv.h"
|
#include "strv.h"
|
||||||
#include "wifi-util.h"
|
|
||||||
|
|
||||||
void net_match_clear(NetMatch *match) {
|
void net_match_clear(NetMatch *match) {
|
||||||
if (!match)
|
if (!match)
|
||||||
@ -23,7 +22,7 @@ void net_match_clear(NetMatch *match) {
|
|||||||
match->iftype = strv_free(match->iftype);
|
match->iftype = strv_free(match->iftype);
|
||||||
match->ifname = strv_free(match->ifname);
|
match->ifname = strv_free(match->ifname);
|
||||||
match->property = strv_free(match->property);
|
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->ssid = strv_free(match->ssid);
|
||||||
match->bssid = set_free_free(match->bssid);
|
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->iftype) &&
|
||||||
strv_isempty(match->ifname) &&
|
strv_isempty(match->ifname) &&
|
||||||
strv_isempty(match->property) &&
|
strv_isempty(match->property) &&
|
||||||
strv_isempty(match->wlan_iftype) &&
|
strv_isempty(match->wifi_iftype) &&
|
||||||
strv_isempty(match->ssid) &&
|
strv_isempty(match->ssid) &&
|
||||||
set_isempty(match->bssid);
|
set_isempty(match->bssid);
|
||||||
}
|
}
|
||||||
@ -118,6 +117,23 @@ static int net_condition_test_property(char * const *match_property, sd_device *
|
|||||||
return true;
|
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(
|
int net_match_config(
|
||||||
const NetMatch *match,
|
const NetMatch *match,
|
||||||
sd_device *device,
|
sd_device *device,
|
||||||
@ -127,7 +143,7 @@ int net_match_config(
|
|||||||
unsigned short iftype,
|
unsigned short iftype,
|
||||||
const char *ifname,
|
const char *ifname,
|
||||||
char * const *alternative_names,
|
char * const *alternative_names,
|
||||||
enum nl80211_iftype wlan_iftype,
|
enum nl80211_iftype wifi_iftype,
|
||||||
const char *ssid,
|
const char *ssid,
|
||||||
const struct ether_addr *bssid) {
|
const struct ether_addr *bssid) {
|
||||||
|
|
||||||
@ -178,7 +194,7 @@ int net_match_config(
|
|||||||
if (!net_condition_test_property(match->property, device))
|
if (!net_condition_test_property(match->property, device))
|
||||||
return false;
|
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;
|
return false;
|
||||||
|
|
||||||
if (!net_condition_test_strv(match->ssid, ssid))
|
if (!net_condition_test_strv(match->ssid, ssid))
|
||||||
|
|||||||
@ -18,7 +18,7 @@ typedef struct NetMatch {
|
|||||||
char **iftype;
|
char **iftype;
|
||||||
char **ifname;
|
char **ifname;
|
||||||
char **property;
|
char **property;
|
||||||
char **wlan_iftype;
|
char **wifi_iftype;
|
||||||
char **ssid;
|
char **ssid;
|
||||||
Set *bssid;
|
Set *bssid;
|
||||||
} NetMatch;
|
} NetMatch;
|
||||||
@ -35,7 +35,7 @@ int net_match_config(
|
|||||||
unsigned short iftype,
|
unsigned short iftype,
|
||||||
const char *ifname,
|
const char *ifname,
|
||||||
char * const *alternative_names,
|
char * const *alternative_names,
|
||||||
enum nl80211_iftype wlan_iftype,
|
enum nl80211_iftype wifi_iftype,
|
||||||
const char *ssid,
|
const char *ssid,
|
||||||
const struct ether_addr *bssid);
|
const struct ether_addr *bssid);
|
||||||
|
|
||||||
|
|||||||
@ -1,16 +1,12 @@
|
|||||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||||
|
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "string-table.h"
|
|
||||||
#include "string-util.h"
|
#include "string-util.h"
|
||||||
#include "wifi-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_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL, *reply = NULL;
|
||||||
_cleanup_free_ char *ssid = NULL;
|
|
||||||
const char *family;
|
const char *family;
|
||||||
uint32_t iftype;
|
|
||||||
size_t len;
|
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
assert(genl);
|
assert(genl);
|
||||||
@ -51,47 +47,41 @@ int wifi_get_interface(sd_netlink *genl, int ifindex, enum nl80211_iftype *ret_i
|
|||||||
goto nodata;
|
goto nodata;
|
||||||
}
|
}
|
||||||
|
|
||||||
r = sd_netlink_message_read_u32(reply, NL80211_ATTR_IFTYPE, &iftype);
|
if (iftype) {
|
||||||
|
uint32_t t;
|
||||||
|
|
||||||
|
r = sd_netlink_message_read_u32(reply, NL80211_ATTR_IFTYPE, &t);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_debug_errno(r, "Failed to get NL80211_ATTR_IFTYPE attribute: %m");
|
return log_debug_errno(r, "Failed to get NL80211_ATTR_IFTYPE attribute: %m");
|
||||||
|
*iftype = t;
|
||||||
|
}
|
||||||
|
|
||||||
r = sd_netlink_message_read_data_suffix0(reply, NL80211_ATTR_SSID, &len, (void**) &ssid);
|
if (ssid) {
|
||||||
if (r < 0 && r != -ENODATA)
|
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 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);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (ret_iftype)
|
|
||||||
*ret_iftype = iftype;
|
|
||||||
|
|
||||||
if (ret_ssid)
|
|
||||||
*ret_ssid = TAKE_PTR(ssid);
|
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
nodata:
|
nodata:
|
||||||
if (ret_iftype)
|
if (iftype)
|
||||||
*ret_iftype = 0;
|
*iftype = 0;
|
||||||
if (ret_ssid)
|
if (ssid)
|
||||||
*ret_ssid = NULL;
|
*ssid = NULL;
|
||||||
return 0;
|
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;
|
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL, *reply = NULL;
|
||||||
const char *family;
|
const char *family;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
assert(genl);
|
assert(genl);
|
||||||
assert(ifindex > 0);
|
assert(ifindex > 0);
|
||||||
assert(ret_bssid);
|
assert(bssid);
|
||||||
|
|
||||||
r = sd_genl_message_new(genl, NL80211_GENL_NAME, NL80211_CMD_GET_STATION, &m);
|
r = sd_genl_message_new(genl, NL80211_GENL_NAME, NL80211_CMD_GET_STATION, &m);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
@ -125,7 +115,7 @@ int wifi_get_station(sd_netlink *genl, int ifindex, struct ether_addr *ret_bssid
|
|||||||
goto nodata;
|
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)
|
if (r == -ENODATA)
|
||||||
goto nodata;
|
goto nodata;
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
@ -134,173 +124,6 @@ int wifi_get_station(sd_netlink *genl, int ifindex, struct ether_addr *ret_bssid
|
|||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
nodata:
|
nodata:
|
||||||
*ret_bssid = ETHER_ADDR_NULL;
|
*bssid = (struct ether_addr) {};
|
||||||
return 0;
|
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);
|
|
||||||
|
|||||||
@ -3,13 +3,9 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <linux/nl80211.h>
|
#include <linux/nl80211.h>
|
||||||
|
#include <net/ethernet.h>
|
||||||
|
|
||||||
#include "sd-netlink.h"
|
#include "sd-netlink.h"
|
||||||
|
|
||||||
#include "ether-addr-util.h"
|
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);
|
||||||
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_;
|
|
||||||
|
|||||||
@ -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_preferred,
|
||||||
uint32_t *lifetime_valid);
|
uint32_t *lifetime_valid);
|
||||||
|
|
||||||
int sd_dhcp6_lease_get_dns(sd_dhcp6_lease *lease, const struct in6_addr **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 ***ret);
|
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 **ret);
|
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 ***ret);
|
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 **ret);
|
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_ref(sd_dhcp6_lease *lease);
|
||||||
sd_dhcp6_lease *sd_dhcp6_lease_unref(sd_dhcp6_lease *lease);
|
sd_dhcp6_lease *sd_dhcp6_lease_unref(sd_dhcp6_lease *lease);
|
||||||
|
|||||||
@ -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(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(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_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_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);
|
int sd_netlink_message_read_strv(sd_netlink_message *m, unsigned short container_type, unsigned short type_id, char ***ret);
|
||||||
|
|||||||
@ -390,28 +390,6 @@ static void test_strv_split_full(void) {
|
|||||||
assert_se(streq_ptr(l[5], NULL));
|
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) {
|
static void test_strv_split_colon_pairs(void) {
|
||||||
_cleanup_strv_free_ char **l = NULL;
|
_cleanup_strv_free_ char **l = NULL;
|
||||||
const char *str = "one:two three four:five six seven:eight\\:nine ten\\:eleven\\\\",
|
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();
|
||||||
test_strv_split_empty();
|
test_strv_split_empty();
|
||||||
test_strv_split_full();
|
test_strv_split_full();
|
||||||
test_strv_split_and_extend_full();
|
|
||||||
test_strv_split_colon_pairs();
|
test_strv_split_colon_pairs();
|
||||||
test_strv_split_newlines();
|
test_strv_split_newlines();
|
||||||
test_strv_split_newlines_full();
|
test_strv_split_newlines_full();
|
||||||
|
|||||||
@ -18,7 +18,6 @@
|
|||||||
#include "dirent-util.h"
|
#include "dirent-util.h"
|
||||||
#include "fd-util.h"
|
#include "fd-util.h"
|
||||||
#include "sort-util.h"
|
#include "sort-util.h"
|
||||||
#include "static-destruct.h"
|
|
||||||
#include "string-table.h"
|
#include "string-table.h"
|
||||||
#include "string-util.h"
|
#include "string-util.h"
|
||||||
#include "udev-util.h"
|
#include "udev-util.h"
|
||||||
@ -39,10 +38,8 @@ typedef enum QueryType {
|
|||||||
QUERY_ALL,
|
QUERY_ALL,
|
||||||
} QueryType;
|
} QueryType;
|
||||||
|
|
||||||
static char **arg_properties = NULL;
|
|
||||||
static bool arg_root = false;
|
static bool arg_root = false;
|
||||||
static bool arg_export = false;
|
static bool arg_export = false;
|
||||||
static bool arg_value = false;
|
|
||||||
static const char *arg_export_prefix = NULL;
|
static const char *arg_export_prefix = NULL;
|
||||||
static usec_t arg_wait_for_initialization_timeout = 0;
|
static usec_t arg_wait_for_initialization_timeout = 0;
|
||||||
|
|
||||||
@ -63,8 +60,6 @@ typedef struct SysAttr {
|
|||||||
const char *value;
|
const char *value;
|
||||||
} SysAttr;
|
} SysAttr;
|
||||||
|
|
||||||
STATIC_DESTRUCTOR_REGISTER(arg_properties, strv_freep);
|
|
||||||
|
|
||||||
static int sysattr_compare(const SysAttr *a, const SysAttr *b) {
|
static int sysattr_compare(const SysAttr *a, const SysAttr *b) {
|
||||||
return strcmp(a->name, b->name);
|
return strcmp(a->name, b->name);
|
||||||
}
|
}
|
||||||
@ -321,18 +316,11 @@ static int query_device(QueryType query, sd_device* device) {
|
|||||||
case QUERY_PROPERTY: {
|
case QUERY_PROPERTY: {
|
||||||
const char *key, *value;
|
const char *key, *value;
|
||||||
|
|
||||||
FOREACH_DEVICE_PROPERTY(device, key, value) {
|
FOREACH_DEVICE_PROPERTY(device, key, value)
|
||||||
if (arg_properties && !strv_contains(arg_properties, key))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (arg_export)
|
if (arg_export)
|
||||||
printf("%s%s='%s'\n", strempty(arg_export_prefix), key, value);
|
printf("%s%s='%s'\n", strempty(arg_export_prefix), key, value);
|
||||||
else if (arg_value)
|
|
||||||
printf("%s\n", value);
|
|
||||||
else
|
else
|
||||||
printf("%s=%s\n", key, value);
|
printf("%s=%s\n", key, value);
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -355,8 +343,6 @@ static int help(void) {
|
|||||||
" path sysfs device path\n"
|
" path sysfs device path\n"
|
||||||
" property The device properties\n"
|
" property The device properties\n"
|
||||||
" all All values\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"
|
" -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"
|
" -n --name=NAME Node or symlink name used for query or attribute walk\n"
|
||||||
" -r --root Prepend dev directory to path names\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;
|
_cleanup_free_ char *name = NULL;
|
||||||
int c, r;
|
int c, r;
|
||||||
|
|
||||||
enum {
|
|
||||||
ARG_PROPERTY = 0x100,
|
|
||||||
ARG_VALUE,
|
|
||||||
};
|
|
||||||
|
|
||||||
static const struct option options[] = {
|
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' },
|
{ "name", required_argument, NULL, 'n' },
|
||||||
{ "path", required_argument, NULL, 'p' },
|
{ "path", required_argument, NULL, 'p' },
|
||||||
{ "property", required_argument, NULL, ARG_PROPERTY },
|
|
||||||
{ "query", required_argument, NULL, 'q' },
|
{ "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' },
|
{ "root", no_argument, NULL, 'r' },
|
||||||
{ "value", no_argument, NULL, ARG_VALUE },
|
{ "device-id-of-file", required_argument, NULL, 'd' },
|
||||||
{ "version", no_argument, NULL, 'V' },
|
{ "export", no_argument, NULL, 'x' },
|
||||||
|
{ "export-prefix", required_argument, NULL, 'P' },
|
||||||
{ "wait-for-initialization", optional_argument, NULL, 'w' },
|
{ "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)
|
while ((c = getopt_long(argc, argv, "aced:n:p:q:rxP:w::Vh", options, NULL)) >= 0)
|
||||||
switch (c) {
|
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 'n':
|
||||||
case 'p': {
|
case 'p': {
|
||||||
const char *prefix = c == 'n' ? "/dev/" : "/sys/";
|
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),
|
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||||
"Only one device may be specified with -a/--attribute-walk");
|
"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;
|
char **p;
|
||||||
STRV_FOREACH(p, devices) {
|
STRV_FOREACH(p, devices) {
|
||||||
_cleanup_(sd_device_unrefp) sd_device *device = NULL;
|
_cleanup_(sd_device_unrefp) sd_device *device = NULL;
|
||||||
|
|||||||
@ -11,8 +11,6 @@ set -e
|
|||||||
TEST_DESCRIPTION="systemd-udev storage tests"
|
TEST_DESCRIPTION="systemd-udev storage tests"
|
||||||
IMAGE_NAME="default"
|
IMAGE_NAME="default"
|
||||||
TEST_NO_NSPAWN=1
|
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}"
|
QEMU_TIMEOUT="${QEMU_TIMEOUT:-600}"
|
||||||
|
|
||||||
# shellcheck source=test/test-functions
|
# shellcheck source=test/test-functions
|
||||||
@ -30,20 +28,14 @@ _host_has_feature() {(
|
|||||||
set -e
|
set -e
|
||||||
|
|
||||||
case "${1:?}" in
|
case "${1:?}" in
|
||||||
btrfs)
|
multipath)
|
||||||
modprobe -nv btrfs && command -v mkfs.btrfs && command -v btrfs || return $?
|
command -v multipath && command -v multipathd || return $?
|
||||||
;;
|
|
||||||
iscsi)
|
|
||||||
# Client/initiator (Open-iSCSI)
|
|
||||||
command -v iscsiadm && command -v iscsid || return $?
|
|
||||||
# Server/target (TGT)
|
|
||||||
command -v tgtadm && command -v tgtd || return $?
|
|
||||||
;;
|
;;
|
||||||
lvm)
|
lvm)
|
||||||
command -v lvm || return $?
|
command -v lvm || return $?
|
||||||
;;
|
;;
|
||||||
multipath)
|
btrfs)
|
||||||
command -v multipath && command -v multipathd || return $?
|
modprobe -nv btrfs && command -v mkfs.btrfs && command -v btrfs || return $?
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
echo >&2 "ERROR: Unknown feature '$1'"
|
echo >&2 "ERROR: Unknown feature '$1'"
|
||||||
@ -62,7 +54,6 @@ test_append_files() {(
|
|||||||
# checked for here
|
# checked for here
|
||||||
local -A features=(
|
local -A features=(
|
||||||
[btrfs]=install_btrfs
|
[btrfs]=install_btrfs
|
||||||
[iscsi]=install_iscsi
|
|
||||||
[lvm]=install_lvm
|
[lvm]=install_lvm
|
||||||
[multipath]=install_multipath
|
[multipath]=install_multipath
|
||||||
)
|
)
|
||||||
@ -369,35 +360,6 @@ testcase_btrfs_basic() {
|
|||||||
rm -f "${TESTDIR:?}"/btrfsbasic*.img
|
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
|
# Allow overriding which tests should be run from the "outside", useful for manual
|
||||||
# testing (make -C test/... TESTCASES="testcase1 testcase2")
|
# testing (make -C test/... TESTCASES="testcase1 testcase2")
|
||||||
if [[ -v "TESTCASES" && -n "$TESTCASES" ]]; then
|
if [[ -v "TESTCASES" && -n "$TESTCASES" ]]; then
|
||||||
|
|||||||
@ -959,45 +959,6 @@ install_btrfs() {
|
|||||||
inst_rules 64-btrfs-dm.rules
|
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() {
|
install_compiled_systemd() {
|
||||||
dinfo "Install compiled systemd"
|
dinfo "Install compiled systemd"
|
||||||
|
|
||||||
@ -2358,8 +2319,6 @@ inst() {
|
|||||||
for fun in inst_symlink inst_script inst_binary inst_simple; do
|
for fun in inst_symlink inst_script inst_binary inst_simple; do
|
||||||
"$fun" "$@" && return 0
|
"$fun" "$@" && return 0
|
||||||
done
|
done
|
||||||
|
|
||||||
dwarn "Failed to install '$1'"
|
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -40,57 +40,6 @@ helper_check_device_symlinks() {(
|
|||||||
done < <(find "${paths[@]}" -type l)
|
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() {
|
testcase_megasas2_basic() {
|
||||||
lsblk -S
|
lsblk -S
|
||||||
[[ "$(lsblk --scsi --noheadings | wc -l)" -ge 128 ]]
|
[[ "$(lsblk --scsi --noheadings | wc -l)" -ge 128 ]]
|
||||||
@ -448,144 +397,6 @@ EOF
|
|||||||
udevadm settle
|
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
|
: >/failed
|
||||||
|
|
||||||
udevadm settle
|
udevadm settle
|
||||||
|
|||||||
@ -68,12 +68,6 @@ cat <<EOF >/tmp/testfile.service
|
|||||||
ExecStart = echo hello
|
ExecStart = echo hello
|
||||||
EOF
|
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
|
# 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
|
systemd-analyze security --offline=true /tmp/testfile.service
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user