summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile.am32
-rw-r--r--man/systemctl.xml21
-rw-r--r--man/systemd-cgtop.xml9
-rw-r--r--man/systemd.special.xml45
-rw-r--r--po/LINGUAS1
-rw-r--r--po/de.po170
-rw-r--r--po/tr.po598
-rw-r--r--shell-completion/bash/systemd-cgtop17
-rw-r--r--src/cgtop/cgtop.c57
-rw-r--r--src/core/dbus-manager.c32
-rw-r--r--src/core/kill.c5
-rw-r--r--src/core/kill.h3
-rw-r--r--src/core/load-fragment.c14
-rw-r--r--src/core/main.c21
-rw-r--r--src/core/manager.h5
-rw-r--r--src/core/shutdown.c22
-rw-r--r--src/core/unit.c26
-rw-r--r--src/libsystemd-network/arp-util.c153
-rw-r--r--src/libsystemd-network/arp-util.h (renamed from src/libsystemd-network/ipv4ll-internal.h)14
-rw-r--r--src/libsystemd-network/ipv4ll-network.c91
-rw-r--r--src/libsystemd-network/ipv4ll-packet.c71
-rw-r--r--src/libsystemd-network/sd-ipv4acd.c529
-rw-r--r--src/libsystemd-network/sd-ipv4ll.c641
-rw-r--r--src/libsystemd-network/test-acd.c117
-rw-r--r--src/libsystemd-network/test-ipv4ll-manual.c129
-rw-r--r--src/libsystemd-network/test-ipv4ll.c82
-rw-r--r--src/network/networkd-ipv4ll.c9
-rw-r--r--src/systemctl/systemctl.c38
-rw-r--r--src/systemd/sd-ipv4acd.h55
-rw-r--r--src/systemd/sd-ipv4ll.h2
-rw-r--r--units/.gitignore1
-rw-r--r--units/exit.target17
-rw-r--r--units/systemd-exit.service.in17
33 files changed, 2234 insertions, 810 deletions
diff --git a/Makefile.am b/Makefile.am
index c395840759..5b1431c866 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -474,6 +474,7 @@ dist_systemunit_DATA = \
units/getty.target \
units/halt.target \
units/kexec.target \
+ units/exit.target \
units/local-fs.target \
units/local-fs-pre.target \
units/initrd.target \
@@ -550,6 +551,7 @@ nodist_systemunit_DATA = \
units/systemd-poweroff.service \
units/systemd-reboot.service \
units/systemd-kexec.service \
+ units/systemd-exit.service \
units/systemd-fsck@.service \
units/systemd-fsck-root.service \
units/systemd-machine-id-commit.service \
@@ -601,6 +603,7 @@ EXTRA_DIST += \
units/systemd-poweroff.service.in \
units/systemd-reboot.service.in \
units/systemd-kexec.service.in \
+ units/systemd-exit.service.in \
units/user/systemd-exit.service.in \
units/systemd-fsck@.service.in \
units/systemd-fsck-root.service.in \
@@ -1367,7 +1370,9 @@ manual_tests += \
test-watchdog \
test-log \
test-ipcrm \
- test-btrfs
+ test-btrfs \
+ test-acd \
+ test-ipv4ll-manual
if HAVE_LIBIPTC
manual_tests += \
@@ -3198,6 +3203,7 @@ libsystemd_network_la_SOURCES = \
src/systemd/sd-dhcp-server.h \
src/systemd/sd-dhcp-lease.h \
src/systemd/sd-ipv4ll.h \
+ src/systemd/sd-ipv4acd.h \
src/systemd/sd-icmp6-nd.h \
src/systemd/sd-dhcp6-client.h \
src/systemd/sd-dhcp6-lease.h \
@@ -3214,9 +3220,9 @@ libsystemd_network_la_SOURCES = \
src/libsystemd-network/dhcp-lease-internal.h \
src/libsystemd-network/sd-dhcp-lease.c \
src/libsystemd-network/sd-ipv4ll.c \
- src/libsystemd-network/ipv4ll-network.c \
- src/libsystemd-network/ipv4ll-packet.c \
- src/libsystemd-network/ipv4ll-internal.h \
+ src/libsystemd-network/sd-ipv4acd.c \
+ src/libsystemd-network/arp-util.h \
+ src/libsystemd-network/arp-util.c \
src/libsystemd-network/sd-pppoe.c \
src/libsystemd-network/network-internal.c \
src/libsystemd-network/network-internal.h \
@@ -3273,13 +3279,29 @@ test_dhcp_server_LDADD = \
test_ipv4ll_SOURCES = \
src/systemd/sd-ipv4ll.h \
- src/libsystemd-network/ipv4ll-internal.h \
+ src/libsystemd-network/arp-util.h \
src/libsystemd-network/test-ipv4ll.c
test_ipv4ll_LDADD = \
libsystemd-network.la \
libshared.la
+test_ipv4ll_manual_SOURCES = \
+ src/systemd/sd-ipv4ll.h \
+ src/libsystemd-network/test-ipv4ll-manual.c
+
+test_ipv4ll_manual_LDADD = \
+ libsystemd-network.la \
+ libshared.la
+
+test_acd_SOURCES = \
+ src/systemd/sd-ipv4acd.h \
+ src/libsystemd-network/test-acd.c
+
+test_acd_LDADD = \
+ libsystemd-network.la \
+ libshared.la
+
test_pppoe_SOURCES = \
src/systemd/sd-pppoe.h \
src/libsystemd-network/test-pppoe.c
diff --git a/man/systemctl.xml b/man/systemctl.xml
index 37ba4ab6de..c1359d1678 100644
--- a/man/systemctl.xml
+++ b/man/systemctl.xml
@@ -295,6 +295,17 @@
</varlistentry>
<varlistentry>
+ <term><option>--fail</option></term>
+
+ <listitem>
+ <para>Shorthand for <option>--job-mode=</option>fail.</para>
+ <para>When used with the <command>kill</command> command,
+ if no units were killed, the operation results in an error.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
<term><option>-i</option></term>
<term><option>--ignore-inhibitors</option></term>
@@ -1622,13 +1633,17 @@ kobject-uevent 1 systemd-udevd-kernel.socket systemd-udevd.service
</varlistentry>
<varlistentry>
- <term><command>exit</command></term>
+ <term><command>exit <optional><replaceable>EXIT_CODE</replaceable></optional></command></term>
<listitem>
<para>Ask the systemd manager to quit. This is only
supported for user service managers (i.e. in conjunction
- with the <option>--user</option> option) and will fail
- otherwise.</para>
+ with the <option>--user</option> option) or in containers
+ and is equivalent to <command>poweroff</command> otherwise.</para>
+
+ <para>The systemd manager can exit with a non-zero exit
+ code if the optional argument
+ <replaceable>EXIT_CODE</replaceable> is given.</para>
</listitem>
</varlistentry>
diff --git a/man/systemd-cgtop.xml b/man/systemd-cgtop.xml
index 859c1a2865..1c90c0a659 100644
--- a/man/systemd-cgtop.xml
+++ b/man/systemd-cgtop.xml
@@ -246,6 +246,15 @@
3.</para></listitem>
</varlistentry>
+ <varlistentry>
+ <term><option>-M <replaceable>MACHINE</replaceable></option></term>
+ <term><option>--machine=<replaceable>MACHINE</replaceable></option></term>
+
+ <listitem><para>Limit control groups shown to the part
+ corresponding to the container
+ <replaceable>MACHINE</replaceable>.</para></listitem>
+ </varlistentry>
+
<xi:include href="standard-options.xml" xpointer="help" />
<xi:include href="standard-options.xml" xpointer="version" />
</variablelist>
diff --git a/man/systemd.special.xml b/man/systemd.special.xml
index e4700d950b..6e0dff9b47 100644
--- a/man/systemd.special.xml
+++ b/man/systemd.special.xml
@@ -212,6 +212,26 @@
</listitem>
</varlistentry>
<varlistentry>
+ <term><filename>exit.target</filename></term>
+ <listitem>
+ <para>A special service unit for shutting down the system or
+ user service manager. It also works in containers and is
+ equivalent to <filename>poweroff.target</filename> on
+ non-container systems.</para>
+
+ <para>Applications wanting to terminate the user service
+ manager should start this unit. If systemd receives
+ <constant>SIGTERM</constant> or <constant>SIGINT</constant>
+ when running as user service daemon, it will start this
+ unit.</para>
+
+ <para>Normally, this pulls in
+ <filename>shutdown.target</filename> which in turn should be
+ conflicted by all units that want to be shut down on user
+ service manager exit.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
<term><filename>final.target</filename></term>
<listitem>
<para>A special target unit that is used during the shutdown
@@ -797,6 +817,7 @@
<para>When systemd runs as a user instance, the following special
units are available, which have similar definitions as their
system counterparts:
+ <filename>exit.target</filename>,
<filename>default.target</filename>,
<filename>shutdown.target</filename>,
<filename>sockets.target</filename>,
@@ -806,30 +827,6 @@
<filename>printer.target</filename>,
<filename>smartcard.target</filename>,
<filename>sound.target</filename>.</para>
-
- <para>In addition, the following special unit is understood only
- when systemd runs as service instance:</para>
-
- <variablelist>
- <varlistentry>
- <term><filename>exit.target</filename></term>
- <listitem>
- <para>A special service unit for shutting down the user
- service manager.</para>
-
- <para>Applications wanting to terminate the user service
- manager should start this unit. If systemd receives
- <constant>SIGTERM</constant> or <constant>SIGINT</constant>
- when running as user service daemon, it will start this
- unit.</para>
-
- <para>Normally, this pulls in
- <filename>shutdown.target</filename> which in turn should be
- conflicted by all units that want to be shut down on user
- service manager exit.</para>
- </listitem>
- </varlistentry>
- </variablelist>
</refsect1>
<refsect1>
diff --git a/po/LINGUAS b/po/LINGUAS
index bc32cb0e6c..6c6f3934b3 100644
--- a/po/LINGUAS
+++ b/po/LINGUAS
@@ -13,3 +13,4 @@ es
zh_TW
be
be@latin
+tr
diff --git a/po/de.po b/po/de.po
index fa13d34343..72075e81fd 100644
--- a/po/de.po
+++ b/po/de.po
@@ -1,23 +1,24 @@
# German translation for systemd.
# Copyright (C) 2014 systemd's COPYRIGHT HOLDER
# This file is distributed under the same license as the systemd package.
-# Christian Kirbach <Christian.Kirbach@gmail.com>, 2014.
+# Christian Kirbach <Christian.Kirbach@gmail.com>, 2014, 2015.
# Benjamin Steinwender <b@stbe.at>, 2014.
+# Bernd Homuth <dev@hmt.im>, 2015.
#
msgid ""
msgstr ""
"Project-Id-Version: systemd master\n"
-"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2015-06-18 00:53+0200\n"
-"PO-Revision-Date: 2015-02-18 17:08+0100\n"
-"Last-Translator: Martin Pitt <martin.pitt@ubuntu.com>\n"
-"Language-Team: German <gnome-de@gnome.org>\n"
+"Report-Msgid-Bugs-To: https://github.com/systemd/systemd/issues\n"
+"POT-Creation-Date: 2015-09-19 12:09+0000\n"
+"PO-Revision-Date: 2015-09-19 20:02+0200\n"
+"Last-Translator: Bernd Homuth <dev@hmt.im>\n"
+"Language-Team: Deutsch <gnome-de@gnome.org>\n"
"Language: de\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
-"X-Generator: Poedit 1.5.4\n"
+"X-Generator: Gtranslator 2.91.6\n"
#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:1
msgid "Send passphrase back to system"
@@ -31,16 +32,14 @@ msgstr ""
"notwendig."
#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:3
-#, fuzzy
msgid "Manage system services or other units"
-msgstr "Systemdienste und Einheiten verwalten"
+msgstr "Systemdienste und andere Einheiten verwalten"
#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:4
-#, fuzzy
msgid "Authentication is required to manage system services or other units."
msgstr ""
"Legitimierung ist notwendig für die Verwaltung von Systemdiensten und "
-"Einheiten"
+"anderen Einheiten."
#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:5
msgid "Manage system service or unit files"
@@ -53,18 +52,15 @@ msgstr ""
"Einheitendateien."
#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:7
-#, fuzzy
msgid "Set or unset system and service manager environment variables"
-msgstr "Privilegierter Zugriff auf die System- und Dienstverwaltung"
+msgstr ""
+"Umgebungsvariablen der System- und Dienstverwaltung festlegen oder entfernen"
#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:8
-#, fuzzy
msgid ""
"Authentication is required to set or unset system and service manager "
"environment variables."
-msgstr ""
-"Legitimierung ist notwendig für die Verwaltung von Systemdiensten und "
-"Einheitendateien."
+msgstr "Legitimierung ist notwendig für die System- und Dienstverwaltung."
#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:9
msgid "Reload the systemd state"
@@ -105,27 +101,23 @@ msgstr ""
"erforderlich."
#: ../src/import/org.freedesktop.import1.policy.in.h:1
-#, fuzzy
msgid "Import a VM or container image"
-msgstr "Abbild einer VM oder eines Containers herunterladen"
+msgstr "Abbild einer VM oder eines Containers importieren"
#: ../src/import/org.freedesktop.import1.policy.in.h:2
-#, fuzzy
msgid "Authentication is required to import a VM or container image"
msgstr ""
-"Legitimierung ist zum Herunterladen eines VM- oder Containerabbilds "
+"Legitimierung ist zum Importieren eines VM- oder Containerabbilds "
"erforderlich"
#: ../src/import/org.freedesktop.import1.policy.in.h:3
-#, fuzzy
msgid "Export a VM or container image"
-msgstr "Abbild einer VM oder eines Containers herunterladen"
+msgstr "Abbild einer VM oder eines Containers exportieren"
#: ../src/import/org.freedesktop.import1.policy.in.h:4
-#, fuzzy
msgid "Authentication is required to export a VM or container image"
msgstr ""
-"Legitimierung ist zum Herunterladen eines VM- oder Containerabbilds "
+"Legitimierung ist zum Exportieren eines VM- oder Containerabbilds "
"erforderlich"
#: ../src/import/org.freedesktop.import1.policy.in.h:5
@@ -441,70 +433,125 @@ msgstr ""
#: ../src/login/org.freedesktop.login1.policy.in.h:49
msgid "Manage active sessions, users and seats"
-msgstr ""
+msgstr "Aktive Sitzungen, Benutzer und Arbeitsstationen verwalten"
# www.freedesktop.org/wiki/Software/systemd/multiseat/
#: ../src/login/org.freedesktop.login1.policy.in.h:50
-#, fuzzy
msgid ""
"Authentication is required for managing active sessions, users and seats."
msgstr ""
-"Legitimierung ist zum Anschließen eines Geräts an eine Arbeitsstation "
-"notwendig."
+"Legitimierung ist zur Verwaltung aktiver Sitzungen, Benutzern und "
+"Arbeitsstationen notwendig."
#: ../src/login/org.freedesktop.login1.policy.in.h:51
msgid "Lock or unlock active sessions"
-msgstr ""
+msgstr "Aktive Sitzungen sperren und entsperren"
#: ../src/login/org.freedesktop.login1.policy.in.h:52
-#, fuzzy
msgid "Authentication is required to lock or unlock active sessions."
-msgstr "Legitimierung ist zum Anmelden in einem lokalen Container notwendig"
+msgstr ""
+"Legitimierung ist zum Sperren und Entsperren aktiver Sitzungen notwendig."
#: ../src/login/org.freedesktop.login1.policy.in.h:53
msgid "Allow indication to the firmware to boot to setup interface"
msgstr ""
+"Mitteilungen an die Firmware zum Starten in die Einrichtungsoberfläche "
+"zulassen"
#: ../src/login/org.freedesktop.login1.policy.in.h:54
-#, fuzzy
msgid ""
"Authentication is required to indicate to the firmware to boot to setup "
"interface."
-msgstr "Legitimierung ist zum Festlegen des lokalen Rechnernamens notwendig"
+msgstr ""
+"Legitimierung ist zum Starten der Firmware in die Einrichtungsoberfläche "
+"notwendig."
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:55
+msgid "Set a wall message"
+msgstr "Nachricht an alle einstellen"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:56
+msgid "Authentication is required to set a wall message"
+msgstr "Legitimierung ist zum Einstellen einer Nachricht an alle notwendig"
#: ../src/machine/org.freedesktop.machine1.policy.in.h:1
msgid "Log into a local container"
msgstr "In einem lokalen Container anmelden"
#: ../src/machine/org.freedesktop.machine1.policy.in.h:2
-#, fuzzy
msgid "Authentication is required to log into a local container."
-msgstr "Legitimierung ist zum Anmelden in einem lokalen Container notwendig"
+msgstr "Legitimierung ist zum Anmelden in einem lokalen Container notwendig."
#: ../src/machine/org.freedesktop.machine1.policy.in.h:3
-msgid "Manage local virtual machines and containers"
-msgstr ""
+msgid "Log into the local host"
+msgstr "Am lokalen Rechner anmelden"
#: ../src/machine/org.freedesktop.machine1.policy.in.h:4
-#, fuzzy
+msgid "Authentication is required to log into the local host."
+msgstr "Legitimierung ist zum Anmelden am lokalen Rechner notwendig."
+
+#: ../src/machine/org.freedesktop.machine1.policy.in.h:5
+msgid "Acquire a shell in a local container"
+msgstr "Eine Shell in einem lokalen Container erhalten"
+
+#: ../src/machine/org.freedesktop.machine1.policy.in.h:6
+msgid "Authentication is required to acquire a shell in a local container."
+msgstr ""
+"Legitimierung ist zum Erhalten einer Shell in einem lokalen Container "
+"notwendig."
+
+#: ../src/machine/org.freedesktop.machine1.policy.in.h:7
+msgid "Acquire a shell on the local host"
+msgstr "Eine Shell auf dem lokalen Rechner erhalten"
+
+#: ../src/machine/org.freedesktop.machine1.policy.in.h:8
+msgid "Authentication is required to acquire a shell on the local host."
+msgstr ""
+"Legitimierung ist zum Erhalten einer Shell auf dem lokalen Rechner notwendig."
+
+#: ../src/machine/org.freedesktop.machine1.policy.in.h:9
+msgid "Acquire a pseudo TTY in a local container"
+msgstr "Ein Pseudo-TTY in einem lokalen Container erhalten"
+
+#: ../src/machine/org.freedesktop.machine1.policy.in.h:10
+msgid ""
+"Authentication is required to acquire a pseudo TTY in a local container."
+msgstr ""
+"Legitimierung ist zum Erhalten eines Pseudo-TTY in einem lokalen Container "
+"notwendig."
+
+#: ../src/machine/org.freedesktop.machine1.policy.in.h:11
+msgid "Acquire a pseudo TTY on the local host"
+msgstr "Ein Pseudo-TTY auf dem lokalen Rechner erhalten"
+
+#: ../src/machine/org.freedesktop.machine1.policy.in.h:12
+msgid "Authentication is required to acquire a pseudo TTY on the local host."
+msgstr ""
+"Legitimierung ist zum Erhalten eines Pseudo-TTY auf dem lokalen Rechner "
+"notwendig."
+
+#: ../src/machine/org.freedesktop.machine1.policy.in.h:13
+msgid "Manage local virtual machines and containers"
+msgstr "Lokale virtuelle Maschinen und Container verwalten"
+
+#: ../src/machine/org.freedesktop.machine1.policy.in.h:14
msgid ""
"Authentication is required to manage local virtual machines and containers."
msgstr ""
-"Legitimierung ist zum Festlegen der lokalen Maschinen-Information "
+"Legitimierung ist zum Verwalten lokaler virtueller Maschinen und Container "
"erforderlich."
-#: ../src/machine/org.freedesktop.machine1.policy.in.h:5
+#: ../src/machine/org.freedesktop.machine1.policy.in.h:15
msgid "Manage local virtual machine and container images"
-msgstr ""
+msgstr "Lokale virtuelle Maschinen und Containerabbilder verwalten"
-#: ../src/machine/org.freedesktop.machine1.policy.in.h:6
-#, fuzzy
+#: ../src/machine/org.freedesktop.machine1.policy.in.h:16
msgid ""
"Authentication is required to manage local virtual machine and container "
"images."
msgstr ""
-"Legitimierung ist zum Herunterladen eines VM- oder Containerabbilds "
-"erforderlich"
+"Legitimierung ist zum Verwalten lokaler virtueller Maschinen und "
+"Containerabbildern erforderlich."
#: ../src/timedate/org.freedesktop.timedate1.policy.in.h:1
msgid "Set system time"
@@ -546,6 +593,37 @@ msgstr ""
"Legitimierung ist zum Festlegen, ob Netzwerkzeitabgeich eingeschaltet sein "
"soll, erforderlich."
+#: ../src/core/dbus-unit.c:428
+msgid "Authentication is required to start '$(unit)'."
+msgstr "Legitimierung ist zum Starten von »$(unit)« notwendig."
+
+#: ../src/core/dbus-unit.c:429
+msgid "Authentication is required to stop '$(unit)'."
+msgstr "Legitimierung ist zum Stoppen von »$(unit)« notwendig."
+
+#: ../src/core/dbus-unit.c:430
+msgid "Authentication is required to reload '$(unit)'."
+msgstr "Legitimierung ist zum erneuten Laden von »$(unit)« notwendig."
+
+#: ../src/core/dbus-unit.c:431 ../src/core/dbus-unit.c:432
+msgid "Authentication is required to restart '$(unit)'."
+msgstr "Legitimierung ist zum Neustarten von »$(unit)« notwendig."
+
+#: ../src/core/dbus-unit.c:535
+msgid "Authentication is required to kill '$(unit)'."
+msgstr "Legitimierung ist zum Eliminieren von »$(unit)« notwendig."
+
+#: ../src/core/dbus-unit.c:565
+msgid "Authentication is required to reset the \"failed\" state of '$(unit)'."
+msgstr ""
+"Legitimierung ist zum Zurücksetzen des Status »fehlgeschlagen« von »$(unit)« "
+"notwendig"
+
+#: ../src/core/dbus-unit.c:597
+msgid "Authentication is required to set properties on '$(unit)'."
+msgstr ""
+"Legitimierung ist zum Festlegen der Eigenschaften von »$(unit)« notwendig."
+
#~ msgid "Press Ctrl+C to cancel all filesystem checks in progress"
#~ msgstr "Strl+C drücken um laufende Dateisystem-Prüfungen abzubrechen"
diff --git a/po/tr.po b/po/tr.po
new file mode 100644
index 0000000000..076627e428
--- /dev/null
+++ b/po/tr.po
@@ -0,0 +1,598 @@
+# Turkish translation for systemd.
+# Copyright (C) 2014-2015 systemd's COPYRIGHT HOLDER
+# This file is distributed under the same license as the systemd package.
+# Necdet Yücel <necdetyucel@gmail.com>, 2014.
+# Gökhan Gurbetoğlu <ggurbet@gmail.com>, 2015.
+# Muhammet Kara <muhammetk@gmail.com>, 2015.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: systemd master\n"
+"Report-Msgid-Bugs-To: https://github.com/systemd/systemd/issues\n"
+"POT-Creation-Date: 2015-09-18 00:07+0000\n"
+"PO-Revision-Date: 2015-09-19 08:31+0300\n"
+"Last-Translator: Muhammet Kara <muhammetk@gmail.com>\n"
+"Language-Team: Türkçe <gnome-turk@gnome.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Language: tr_TR\n"
+"Plural-Forms: nplurals=1; plural=0;\n"
+"X-Generator: Gtranslator 2.91.7\n"
+
+#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:1
+msgid "Send passphrase back to system"
+msgstr "Sisteme parolayı geri gönder"
+
+#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:2
+msgid ""
+"Authentication is required to send the entered passphrase back to the system."
+msgstr "Sisteme parolayı geri göndermek kimlik doğrulaması gerektiriyor."
+
+#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:3
+msgid "Manage system services or other units"
+msgstr "Sistem servislerini veya diğer birimlerini yönet"
+
+#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:4
+msgid "Authentication is required to manage system services or other units."
+msgstr ""
+"Sistem servislerini veya diğer birimlerini yönetmek kimlik doğrulaması "
+"gerektiriyor."
+
+#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:5
+msgid "Manage system service or unit files"
+msgstr "Sistem servislerini veya birim dosyalarını yönet"
+
+#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:6
+msgid "Authentication is required to manage system service or unit files."
+msgstr ""
+"Sistem servislerini veya birim dosyalarını yönetmek kimlik doğrulaması "
+"gerektiriyor."
+
+#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:7
+msgid "Set or unset system and service manager environment variables"
+msgstr "Sistem ve servis yöneticisi ortam değişkenlerini ayarla ya da kaldır"
+
+#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:8
+msgid ""
+"Authentication is required to set or unset system and service manager "
+"environment variables."
+msgstr ""
+"Sistem ve servis yöneticisi ortam değişkenlerini ayarlamak ya da kaldırmak "
+"kimlik doğrulaması gerektiriyor."
+
+#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:9
+msgid "Reload the systemd state"
+msgstr "systemd durumunu yeniden yükle"
+
+#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:10
+msgid "Authentication is required to reload the systemd state."
+msgstr "systemd durumunu yeniden yüklemek kimlik doğrulaması gerektiriyor."
+
+#: ../src/hostname/org.freedesktop.hostname1.policy.in.h:1
+msgid "Set host name"
+msgstr "Makine adını ayarla"
+
+#: ../src/hostname/org.freedesktop.hostname1.policy.in.h:2
+msgid "Authentication is required to set the local host name."
+msgstr "Yerel makine adını ayarlamak kimlik doğrulaması gerektiriyor."
+
+#: ../src/hostname/org.freedesktop.hostname1.policy.in.h:3
+msgid "Set static host name"
+msgstr "Statik makine adı ayarla"
+
+#: ../src/hostname/org.freedesktop.hostname1.policy.in.h:4
+msgid ""
+"Authentication is required to set the statically configured local host name, "
+"as well as the pretty host name."
+msgstr ""
+"Statik olarak yapılandırılmış konak makine adını ve yerel makine adını "
+"ayarlamak kimlik doğrulaması gerektiriyor."
+
+#: ../src/hostname/org.freedesktop.hostname1.policy.in.h:5
+msgid "Set machine information"
+msgstr "Makine bilgisini ayarla"
+
+#: ../src/hostname/org.freedesktop.hostname1.policy.in.h:6
+msgid "Authentication is required to set local machine information."
+msgstr "Yerel makine bilgisini ayarlamak kimlik doğrulaması gerektiriyor."
+
+#: ../src/import/org.freedesktop.import1.policy.in.h:1
+msgid "Import a VM or container image"
+msgstr "Bir SM ya da kapsayıcı kalıbını içe aktar"
+
+#: ../src/import/org.freedesktop.import1.policy.in.h:2
+msgid "Authentication is required to import a VM or container image"
+msgstr ""
+"Bir SM ya da kapsayıcı kalıbını içe aktarmak için kimlik doğrulaması "
+"gereklidir"
+
+#: ../src/import/org.freedesktop.import1.policy.in.h:3
+msgid "Export a VM or container image"
+msgstr "Bir SM ya da kapsayıcı kalıbını dışa aktar"
+
+#: ../src/import/org.freedesktop.import1.policy.in.h:4
+msgid "Authentication is required to export a VM or container image"
+msgstr ""
+"Bir SM ya da kapsayıcı kalıbını dışa aktarmak için kimlik doğrulaması "
+"gereklidir"
+
+#: ../src/import/org.freedesktop.import1.policy.in.h:5
+msgid "Download a VM or container image"
+msgstr "Bir SM ya da kapsayıcı kalıbını indir"
+
+#: ../src/import/org.freedesktop.import1.policy.in.h:6
+msgid "Authentication is required to download a VM or container image"
+msgstr ""
+"Bir SM ya da kapsayıcı kalıbını indirmek için kimlik doğrulaması gereklidir"
+
+#: ../src/locale/org.freedesktop.locale1.policy.in.h:1
+msgid "Set system locale"
+msgstr "Sistem yerelini ayarla"
+
+#: ../src/locale/org.freedesktop.locale1.policy.in.h:2
+msgid "Authentication is required to set the system locale."
+msgstr "Sistem yerelini ayarlamak kimlik doğrulaması gerektiriyor."
+
+#: ../src/locale/org.freedesktop.locale1.policy.in.h:3
+msgid "Set system keyboard settings"
+msgstr "Sistem klavye ayarlarını ayarla"
+
+#: ../src/locale/org.freedesktop.locale1.policy.in.h:4
+msgid "Authentication is required to set the system keyboard settings."
+msgstr "Sistem klavye ayarlarını ayarlamak kimlik doğrulaması gerektiriyor."
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:1
+msgid "Allow applications to inhibit system shutdown"
+msgstr "Uygulamaların sistemin kapanmasına engel olmasına izin ver"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:2
+msgid ""
+"Authentication is required for an application to inhibit system shutdown."
+msgstr ""
+"Bir uygulamanın sistemin kapanmasına engel olması için kimlik doğrulaması "
+"gereklidir."
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:3
+msgid "Allow applications to delay system shutdown"
+msgstr "Uygulamaların sistemin kapanmasını geciktirmelerine izin ver"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:4
+msgid "Authentication is required for an application to delay system shutdown."
+msgstr ""
+"Bir uygulamanın sistemin kapanmasını geciktirmesi için kimlik doğrulaması "
+"gereklidir."
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:5
+msgid "Allow applications to inhibit system sleep"
+msgstr "Uygulamaların sistemin beklemeye geçmesini engellemesine izin ver"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:6
+msgid "Authentication is required for an application to inhibit system sleep."
+msgstr ""
+"Bir uygulamanın sistemin uykuya geçmesine engel olması için kimlik "
+"doğrulaması gereklidir."
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:7
+msgid "Allow applications to delay system sleep"
+msgstr "Uygulamaların sistemin beklemeye geçmesini ertelemesine izin ver"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:8
+msgid "Authentication is required for an application to delay system sleep."
+msgstr ""
+"Bir uygulamanın sistemin uykuya geçmesini geciktirmesi için kimlik "
+"doğrulaması gereklidir."
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:9
+msgid "Allow applications to inhibit automatic system suspend"
+msgstr ""
+"Uygulamaların sistemin otomatik bekletmeye geçmesini engellemesine izin ver"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:10
+msgid ""
+"Authentication is required for an application to inhibit automatic system "
+"suspend."
+msgstr ""
+"Bir uygulamanın sistemin otomatik olarak askıya alınmasına engel olması için "
+"kimlik doğrulaması gereklidir."
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:11
+msgid "Allow applications to inhibit system handling of the power key"
+msgstr "Uygulamaların sistemin güç tuşunun kullanımını engellemesine izin ver"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:12
+msgid ""
+"Authentication is required for an application to inhibit system handling of "
+"the power key."
+msgstr ""
+"Bir uygulamanın sistemin güç tuşunu idare etmesine engel olması için kimlik "
+"doğrulaması gereklidir."
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:13
+msgid "Allow applications to inhibit system handling of the suspend key"
+msgstr ""
+"Uygulamaların sistemin beklet tuşunun kullanımını engellemesine izin ver"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:14
+msgid ""
+"Authentication is required for an application to inhibit system handling of "
+"the suspend key."
+msgstr ""
+"Bir uygulamanın sistemin askıya alma tuşunu idare etmesine engel olması için "
+"kimlik doğrulaması gereklidir."
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:15
+msgid "Allow applications to inhibit system handling of the hibernate key"
+msgstr ""
+"Uygulamaların sistemin uykuya geçme tuşunun kullanımını engellemesine izin "
+"ver"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:16
+msgid ""
+"Authentication is required for an application to inhibit system handling of "
+"the hibernate key."
+msgstr ""
+"Bir uygulamanın sistemin hazırda bekletme tuşunu idare etmesine engel olması "
+"için kimlik doğrulaması gereklidir."
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:17
+msgid "Allow applications to inhibit system handling of the lid switch"
+msgstr ""
+"Uygulamaların sistemin kapak anahtarının kullanımını engellemesine izin ver"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:18
+msgid ""
+"Authentication is required for an application to inhibit system handling of "
+"the lid switch."
+msgstr ""
+"Bir uygulamanın sistemin kapak anahtarını idare etmesine engel olması için "
+"kimlik doğrulaması gereklidir."
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:19
+msgid "Allow non-logged-in users to run programs"
+msgstr "Oturum açmamış kullanıcıların program çalıştırmasına izin ver"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:20
+msgid "Authentication is required to run programs as a non-logged-in user."
+msgstr ""
+"Oturum açmamış bir kullanıcı olarak program çalıştırmak için kimlik "
+"doğrulaması gereklidir."
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:21
+msgid "Allow attaching devices to seats"
+msgstr "Aygıtların yuvaya takılmasına izin ver"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:22
+msgid "Authentication is required for attaching a device to a seat."
+msgstr ""
+"Bir aygıtın yuvaya takılmasına izin vermek kimlik doğrulaması gerektiriyor."
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:23
+msgid "Flush device to seat attachments"
+msgstr "Aygıtın yuvaya eklenmesini sıfırla"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:24
+msgid ""
+"Authentication is required for resetting how devices are attached to seats."
+msgstr ""
+"Aygıtların yuvalara nasıl takıldığını sıfırlamak kimlik doğrulama "
+"gerektiriyor."
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:25
+msgid "Power off the system"
+msgstr "Sistemi kapat"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:26
+msgid "Authentication is required for powering off the system."
+msgstr "Sistemi kapatmak için kimlik doğrulaması gerekiyor."
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:27
+msgid "Power off the system while other users are logged in"
+msgstr "Diğer kullanıcılar oturum açmışken sistemi kapat"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:28
+msgid ""
+"Authentication is required for powering off the system while other users are "
+"logged in."
+msgstr ""
+"Diğer kullanıcılar oturum açmışken sistemi kapatmak kimlik doğrulaması "
+"gerektiriyor."
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:29
+msgid "Power off the system while an application asked to inhibit it"
+msgstr "Bir uygulama engellenmesini isterken sistemi kapat"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:30
+msgid ""
+"Authentication is required for powering off the system while an application "
+"asked to inhibit it."
+msgstr ""
+"Bir uygulama engellenmesini isterken sistemi kapatmak kimlik doğrulaması "
+"gerektiriyor."
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:31
+msgid "Reboot the system"
+msgstr "Sistemi yeniden başlat"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:32
+msgid "Authentication is required for rebooting the system."
+msgstr "Sistemi yeniden başlatmak kimlik doğrulaması gerektiriyor."
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:33
+msgid "Reboot the system while other users are logged in"
+msgstr "Diğer kullanıcılar oturum açmışken sistemi yeniden başlat"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:34
+msgid ""
+"Authentication is required for rebooting the system while other users are "
+"logged in."
+msgstr ""
+"Diğer kullanıcılar oturum açmışken sistemi yeniden başlatmak kimlik "
+"doğrulaması gerektiriyor."
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:35
+msgid "Reboot the system while an application asked to inhibit it"
+msgstr "Bir uygulama engellenmesini isterken sistemi yeniden başlat"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:36
+msgid ""
+"Authentication is required for rebooting the system while an application "
+"asked to inhibit it."
+msgstr ""
+"Bir uygulama engellenmesini isterken sistemi yeniden başlatmak kimlik "
+"doğrulaması gerektiriyor."
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:37
+msgid "Suspend the system"
+msgstr "Sistemi askıya al"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:38
+msgid "Authentication is required for suspending the system."
+msgstr "Sistemi askıya almak kimlik doğrulaması gerektiriyor."
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:39
+msgid "Suspend the system while other users are logged in"
+msgstr "Diğer kullanıcılar oturum açmışken sistemi askıya al"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:40
+msgid ""
+"Authentication is required for suspending the system while other users are "
+"logged in."
+msgstr ""
+"Diğer kullanıcılar oturum açmışken sistemi askıya almak kimlik doğrulaması "
+"gerektiriyor."
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:41
+msgid "Suspend the system while an application asked to inhibit it"
+msgstr "Bir uygulama engellenmesini isterken sistemi askıya al"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:42
+msgid ""
+"Authentication is required for suspending the system while an application "
+"asked to inhibit it."
+msgstr ""
+"Bir uygulama engellenmesini isterken sistemi askıya almak kimlik doğrulaması "
+"gerektiriyor."
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:43
+msgid "Hibernate the system"
+msgstr "Sistemi hazırda beklet"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:44
+msgid "Authentication is required for hibernating the system."
+msgstr "Sistemi hazırda bekletmek kimlik doğrulaması gerektiriyor."
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:45
+msgid "Hibernate the system while other users are logged in"
+msgstr "Diğer kullanıcılar oturum açmışken sistemi hazırda beklet"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:46
+msgid ""
+"Authentication is required for hibernating the system while other users are "
+"logged in."
+msgstr ""
+"Diğer kullanıcılar oturum açmışken sistemi hazırda bekletmek kimlik "
+"doğrulaması gerektiriyor."
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:47
+msgid "Hibernate the system while an application asked to inhibit it"
+msgstr "Bir uygulama engellenmesini isterken sistemi hazırda beklet"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:48
+msgid ""
+"Authentication is required for hibernating the system while an application "
+"asked to inhibit it."
+msgstr ""
+"Bir uygulama engellenmesini isterken sistemi hazırda bekletmek kimlik "
+"doğrulaması gerektiriyor."
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:49
+msgid "Manage active sessions, users and seats"
+msgstr "Aktif oturumları, kullanıcıları ve yuvaları yönet"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:50
+msgid ""
+"Authentication is required for managing active sessions, users and seats."
+msgstr ""
+"Aktif oturumları, kullanıcıları ve yuvaları yönetmek için kimlik doğrulaması "
+"gereklidir."
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:51
+msgid "Lock or unlock active sessions"
+msgstr "Aktif oturumları kilitle ya da kilidini aç"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:52
+msgid "Authentication is required to lock or unlock active sessions."
+msgstr ""
+"Aktif oturumları kilitlemek ve bunların kilidini açmak için kimlik "
+"doğrulaması gereklidir."
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:53
+msgid "Allow indication to the firmware to boot to setup interface"
+msgstr ""
+"Kurulum arayüzünü önyüklemek için ürün yazılımının belirtilmesine izin ver"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:54
+msgid ""
+"Authentication is required to indicate to the firmware to boot to setup "
+"interface."
+msgstr ""
+"Kurulum arayüzünü önyüklemek için ürün yazılımının belirtilmesi için kimlik "
+"doğrulaması gereklidir."
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:55
+msgid "Set a wall message"
+msgstr "Bir duvar mesajı ayarla"
+
+#: ../src/login/org.freedesktop.login1.policy.in.h:56
+msgid "Authentication is required to set a wall message"
+msgstr "Duvar mesajı ayarlamak için kimlik doğrulaması gereklidir"
+
+#: ../src/machine/org.freedesktop.machine1.policy.in.h:1
+msgid "Log into a local container"
+msgstr "Yerel kapsayıcıya giriş yap"
+
+#: ../src/machine/org.freedesktop.machine1.policy.in.h:2
+msgid "Authentication is required to log into a local container."
+msgstr "Yerel kapsayıcıda oturum açmak için kimlik doğrulaması gereklidir."
+
+#: ../src/machine/org.freedesktop.machine1.policy.in.h:3
+msgid "Log into the local host"
+msgstr "Yerel (ana) makineye giriş yap"
+
+#: ../src/machine/org.freedesktop.machine1.policy.in.h:4
+msgid "Authentication is required to log into the local host."
+msgstr "Yerel (ana) makinede oturum açmak için kimlik doğrulaması gereklidir."
+
+#: ../src/machine/org.freedesktop.machine1.policy.in.h:5
+msgid "Acquire a shell in a local container"
+msgstr "Yerel kapsayıcıda kabuk (shell) aç"
+
+#: ../src/machine/org.freedesktop.machine1.policy.in.h:6
+msgid "Authentication is required to acquire a shell in a local container."
+msgstr ""
+"Yerel kapsayıcıda kabuk (shell) açmak için kimlik doğrulaması gereklidir."
+
+#: ../src/machine/org.freedesktop.machine1.policy.in.h:7
+msgid "Acquire a shell on the local host"
+msgstr "Yerel (ana) makinede kabuk (shell) aç"
+
+#: ../src/machine/org.freedesktop.machine1.policy.in.h:8
+msgid "Authentication is required to acquire a shell on the local host."
+msgstr ""
+"Yerel (ana) makinede kabuk (shell) açmak için kimlik doğrulaması gereklidir."
+
+#: ../src/machine/org.freedesktop.machine1.policy.in.h:9
+msgid "Acquire a pseudo TTY in a local container"
+msgstr "Yerel kapsayıcıda sözde (pseudo) TTY al"
+
+#: ../src/machine/org.freedesktop.machine1.policy.in.h:10
+msgid ""
+"Authentication is required to acquire a pseudo TTY in a local container."
+msgstr ""
+"Yerel kapsayıcıda sözde (pseudo) TTY almak için kimlik doğrulaması "
+"gereklidir."
+
+#: ../src/machine/org.freedesktop.machine1.policy.in.h:11
+msgid "Acquire a pseudo TTY on the local host"
+msgstr "Yerel (ana) makinede sözde (pseudo) TTY al"
+
+#: ../src/machine/org.freedesktop.machine1.policy.in.h:12
+msgid "Authentication is required to acquire a pseudo TTY on the local host."
+msgstr ""
+"Yerel (ana) makinede sözde (pseudo) TTY almak için kimlik doğrulaması "
+"gereklidir."
+
+#: ../src/machine/org.freedesktop.machine1.policy.in.h:13
+msgid "Manage local virtual machines and containers"
+msgstr "Yerel sanal makineleri ve kapsayıcıları yönet"
+
+#: ../src/machine/org.freedesktop.machine1.policy.in.h:14
+msgid ""
+"Authentication is required to manage local virtual machines and containers."
+msgstr ""
+"Yerel sanal makineleri ve kapsayıcıları yönetmek için kimlik doğrulaması "
+"gereklidir."
+
+#: ../src/machine/org.freedesktop.machine1.policy.in.h:15
+msgid "Manage local virtual machine and container images"
+msgstr "Yerel sanal makine ve kapsayıcı kalıplarını yönet"
+
+#: ../src/machine/org.freedesktop.machine1.policy.in.h:16
+msgid ""
+"Authentication is required to manage local virtual machine and container "
+"images."
+msgstr ""
+"Yerel sanal makineler ve kapsayıcı kalıplarını yönetmek için kimlik "
+"doğrulaması gereklidir."
+
+#: ../src/timedate/org.freedesktop.timedate1.policy.in.h:1
+msgid "Set system time"
+msgstr "Sistem zamanını ayarla"
+
+#: ../src/timedate/org.freedesktop.timedate1.policy.in.h:2
+msgid "Authentication is required to set the system time."
+msgstr "Sistem zamanını ayarlamak kimlik doğrulaması gerektiriyor."
+
+#: ../src/timedate/org.freedesktop.timedate1.policy.in.h:3
+msgid "Set system timezone"
+msgstr "Sistem zaman dilimini ayarla"
+
+#: ../src/timedate/org.freedesktop.timedate1.policy.in.h:4
+msgid "Authentication is required to set the system timezone."
+msgstr "Sistem zaman dilimini ayarlamak kimlik doğrulaması gerektiriyor."
+
+#: ../src/timedate/org.freedesktop.timedate1.policy.in.h:5
+msgid "Set RTC to local timezone or UTC"
+msgstr "Gerçek zamanlı saat olarak yerel zaman dilimini veya UTC'yi ayarla"
+
+#: ../src/timedate/org.freedesktop.timedate1.policy.in.h:6
+msgid ""
+"Authentication is required to control whether the RTC stores the local or "
+"UTC time."
+msgstr ""
+"Gerçek zamanlı saat olarak yerel zaman dilimini veya UTC'yi ayarlamak kimlik "
+"doğrulaması gerektiriyor."
+
+#: ../src/timedate/org.freedesktop.timedate1.policy.in.h:7
+msgid "Turn network time synchronization on or off"
+msgstr "Ağ zaman eş zamanlamasını aç veya kapat"
+
+#: ../src/timedate/org.freedesktop.timedate1.policy.in.h:8
+msgid ""
+"Authentication is required to control whether network time synchronization "
+"shall be enabled."
+msgstr ""
+"Ağ zaman eş zamanlamasını kontrol etmek kimlik doğrulaması gerektiriyor."
+
+#: ../src/core/dbus-unit.c:428
+msgid "Authentication is required to start '$(unit)'."
+msgstr "'$(unit)' başlatmak için kimlik doğrulaması gereklidir."
+
+#: ../src/core/dbus-unit.c:429
+msgid "Authentication is required to stop '$(unit)'."
+msgstr "'$(unit)' durdurmak için kimlik doğrulaması gereklidir."
+
+#: ../src/core/dbus-unit.c:430
+msgid "Authentication is required to reload '$(unit)'."
+msgstr "'$(unit)' yeniden yüklemek için kimlik doğrulaması gereklidir."
+
+#: ../src/core/dbus-unit.c:431 ../src/core/dbus-unit.c:432
+msgid "Authentication is required to restart '$(unit)'."
+msgstr "'$(unit)' yeniden başlatmak için kimlik doğrulaması gereklidir."
+
+#: ../src/core/dbus-unit.c:535
+msgid "Authentication is required to kill '$(unit)'."
+msgstr "'$(unit)' sonlandırmak için kimlik doğrulaması gereklidir."
+
+#: ../src/core/dbus-unit.c:565
+msgid "Authentication is required to reset the \"failed\" state of '$(unit)'."
+msgstr ""
+"'$(unit)'in \"failed\" (başarısız) durumunu sıfırlamak için kimlik "
+"doğrulaması gereklidir."
+
+#: ../src/core/dbus-unit.c:597
+msgid "Authentication is required to set properties on '$(unit)'."
+msgstr ""
+"'$(unit)' üzerindeki özellikleri ayarlamak için kimlik doğrulaması "
+"gereklidir."
diff --git a/shell-completion/bash/systemd-cgtop b/shell-completion/bash/systemd-cgtop
index 50464990ab..eefb8fc5c4 100644
--- a/shell-completion/bash/systemd-cgtop
+++ b/shell-completion/bash/systemd-cgtop
@@ -24,17 +24,32 @@ __contains_word() {
done
}
+__get_machines() {
+ local a b
+ machinectl list --no-legend --no-pager | { while read a b; do echo " $a"; done; };
+}
+
_systemd_cgtop() {
local cur=${COMP_WORDS[COMP_CWORD]} prev=${COMP_WORDS[COMP_CWORD-1]}
local comps
local -A OPTS=(
[STANDALONE]='-h --help --version -p -t -c -m -i -b --batch -n --iterations -d --delay'
- [ARG]='--cpu --depth'
+ [ARG]='--cpu --depth -M --machine'
)
_init_completion || return
+ if __contains_word "$prev" ${OPTS[ARG]}; then
+ case $prev in
+ --machine|-M)
+ comps=$( __get_machines )
+ ;;
+ esac
+ COMPREPLY=( $(compgen -W '$comps' -- "$cur") )
+ return 0
+ fi
+
COMPREPLY=( $(compgen -W '${OPTS[*]}' -- "$cur") )
}
diff --git a/src/cgtop/cgtop.c b/src/cgtop/cgtop.c
index 4786a155da..1307a34ab7 100644
--- a/src/cgtop/cgtop.c
+++ b/src/cgtop/cgtop.c
@@ -36,6 +36,10 @@
#include "cgroup-util.h"
#include "build.h"
#include "fileio.h"
+#include "sd-bus.h"
+#include "bus-util.h"
+#include "bus-error.h"
+#include "unit-name.h"
typedef struct Group {
char *path;
@@ -65,6 +69,7 @@ static unsigned arg_iterations = (unsigned) -1;
static bool arg_batch = false;
static bool arg_raw = false;
static usec_t arg_delay = 1*USEC_PER_SEC;
+static char* arg_machine = NULL;
enum {
COUNT_PIDS,
@@ -645,6 +650,7 @@ static void help(void) {
" -n --iterations=N Run for N iterations before exiting\n"
" -b --batch Run in batch mode, accepting no input\n"
" --depth=DEPTH Maximum traversal depth (default: %u)\n"
+ " -M --machine= Show container\n"
, program_invocation_short_name, arg_depth);
}
@@ -669,6 +675,7 @@ static int parse_argv(int argc, char *argv[]) {
{ "cpu", optional_argument, NULL, ARG_CPU_TYPE },
{ "order", required_argument, NULL, ARG_ORDER },
{ "recursive", required_argument, NULL, ARG_RECURSIVE },
+ { "machine", required_argument, NULL, 'M' },
{}
};
@@ -678,7 +685,7 @@ static int parse_argv(int argc, char *argv[]) {
assert(argc >= 1);
assert(argv);
- while ((c = getopt_long(argc, argv, "hptcmin:brd:kP", options, NULL)) >= 0)
+ while ((c = getopt_long(argc, argv, "hptcmin:brd:kPM:", options, NULL)) >= 0)
switch (c) {
@@ -797,6 +804,10 @@ static int parse_argv(int argc, char *argv[]) {
recursive_unset = r == 0;
break;
+ case 'M':
+ arg_machine = optarg;
+ break;
+
case '?':
return -EINVAL;
@@ -826,6 +837,48 @@ static const char* counting_what(void) {
return "userspace processes (excl. kernel)";
}
+static int get_cgroup_root(char **ret) {
+ _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+ _cleanup_bus_flush_close_unref_ sd_bus *bus = NULL;
+ _cleanup_free_ char *unit = NULL, *path = NULL;
+ const char *m;
+ int r;
+
+ if (!arg_machine) {
+ r = cg_get_root_path(ret);
+ if (r < 0)
+ return log_error_errno(r, "Failed to get root control group path: %m");
+
+ return 0;
+ }
+
+ m = strjoina("/run/systemd/machines/", arg_machine);
+ r = parse_env_file(m, NEWLINE, "SCOPE", &unit, NULL);
+ if (r < 0)
+ return log_error_errno(r, "Failed to load machine data: %m");
+
+ path = unit_dbus_path_from_name(unit);
+ if (!path)
+ return log_oom();
+
+ r = bus_open_transport(BUS_TRANSPORT_LOCAL, NULL, false, &bus);
+ if (r < 0)
+ return log_error_errno(r, "Failed to create bus connection: %m");
+
+ r = sd_bus_get_property_string(
+ bus,
+ "org.freedesktop.systemd1",
+ path,
+ unit_dbus_interface_from_name(unit),
+ "ControlGroup",
+ &error,
+ ret);
+ if (r < 0)
+ return log_error_errno(r, "Failed to query unit control group path: %s", bus_error_message(&error, r));
+
+ return 0;
+}
+
int main(int argc, char *argv[]) {
int r;
Hashmap *a = NULL, *b = NULL;
@@ -850,7 +903,7 @@ int main(int argc, char *argv[]) {
if (r <= 0)
goto finish;
- r = cg_get_root_path(&root);
+ r = get_cgroup_root(&root);
if (r < 0) {
log_error_errno(r, "Failed to get root control group path: %m");
goto finish;
diff --git a/src/core/dbus-manager.c b/src/core/dbus-manager.c
index 4e5d67fc19..561b6f8bfa 100644
--- a/src/core/dbus-manager.c
+++ b/src/core/dbus-manager.c
@@ -1201,8 +1201,10 @@ static int method_exit(sd_bus_message *message, void *userdata, sd_bus_error *er
if (r < 0)
return r;
- if (m->running_as == MANAGER_SYSTEM)
- return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Exit is only supported for user service managers.");
+ /* Exit() (in contrast to SetExitCode()) is actually allowed even if
+ * we are running on the host. It will fall back on reboot() in
+ * systemd-shutdown if it cannot do the exit() because it isn't a
+ * container. */
m->exit_code = MANAGER_EXIT;
@@ -1450,6 +1452,30 @@ static int method_unset_and_set_environment(sd_bus_message *message, void *userd
return sd_bus_reply_method_return(message, NULL);
}
+static int method_set_exit_code(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+ uint8_t code;
+ Manager *m = userdata;
+ int r;
+
+ assert(message);
+ assert(m);
+
+ r = mac_selinux_access_check(message, "exit", error);
+ if (r < 0)
+ return r;
+
+ r = sd_bus_message_read_basic(message, 'y', &code);
+ if (r < 0)
+ return r;
+
+ if (m->running_as == MANAGER_SYSTEM && detect_container() <= 0)
+ return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "ExitCode can only be set for user service managers or in containers.");
+
+ m->return_value = code;
+
+ return sd_bus_reply_method_return(message, NULL);
+}
+
static int method_list_unit_files(sd_bus_message *message, void *userdata, sd_bus_error *error) {
_cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
Manager *m = userdata;
@@ -1933,6 +1959,7 @@ const sd_bus_vtable bus_manager_vtable[] = {
SD_BUS_WRITABLE_PROPERTY("ShutdownWatchdogUSec", "t", bus_property_get_usec, bus_property_set_usec, offsetof(Manager, shutdown_watchdog), 0),
SD_BUS_PROPERTY("ControlGroup", "s", NULL, offsetof(Manager, cgroup_root), 0),
SD_BUS_PROPERTY("SystemState", "s", property_get_system_state, 0, 0),
+ SD_BUS_PROPERTY("ExitCode", "y", bus_property_get_unsigned, offsetof(Manager, return_value), 0),
SD_BUS_METHOD("GetUnit", "s", "o", method_get_unit, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("GetUnitByPID", "u", "o", method_get_unit_by_pid, SD_BUS_VTABLE_UNPRIVILEGED),
@@ -1986,6 +2013,7 @@ const sd_bus_vtable bus_manager_vtable[] = {
SD_BUS_METHOD("GetDefaultTarget", NULL, "s", method_get_default_target, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("PresetAllUnitFiles", "sbb", "a(sss)", method_preset_all_unit_files, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("AddDependencyUnitFiles", "asssbb", "a(sss)", method_add_dependency_unit_files, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD("SetExitCode", "y", NULL, method_set_exit_code, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_SIGNAL("UnitNew", "so", 0),
SD_BUS_SIGNAL("UnitRemoved", "so", 0),
diff --git a/src/core/kill.c b/src/core/kill.c
index 2de71c6bf9..bddfa4460f 100644
--- a/src/core/kill.c
+++ b/src/core/kill.c
@@ -60,7 +60,10 @@ DEFINE_STRING_TABLE_LOOKUP(kill_mode, KillMode);
static const char* const kill_who_table[_KILL_WHO_MAX] = {
[KILL_MAIN] = "main",
[KILL_CONTROL] = "control",
- [KILL_ALL] = "all"
+ [KILL_ALL] = "all",
+ [KILL_MAIN_FAIL] = "main-fail",
+ [KILL_CONTROL_FAIL] = "control-fail",
+ [KILL_ALL_FAIL] = "all-fail"
};
DEFINE_STRING_TABLE_LOOKUP(kill_who, KillWho);
diff --git a/src/core/kill.h b/src/core/kill.h
index d5f125fa41..5d97abb104 100644
--- a/src/core/kill.h
+++ b/src/core/kill.h
@@ -50,6 +50,9 @@ typedef enum KillWho {
KILL_MAIN,
KILL_CONTROL,
KILL_ALL,
+ KILL_MAIN_FAIL,
+ KILL_CONTROL_FAIL,
+ KILL_ALL_FAIL,
_KILL_WHO_MAX,
_KILL_WHO_INVALID = -1
} KillWho;
diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c
index 1217b4651e..fcf863c5c7 100644
--- a/src/core/load-fragment.c
+++ b/src/core/load-fragment.c
@@ -3049,6 +3049,7 @@ int config_parse_runtime_directory(
void *userdata) {
char***rt = data;
+ Unit *u = userdata;
const char *word, *state;
size_t l;
int r;
@@ -3065,12 +3066,19 @@ int config_parse_runtime_directory(
}
FOREACH_WORD_QUOTED(word, l, rvalue, state) {
- _cleanup_free_ char *n;
+ _cleanup_free_ char *t = NULL, *n = NULL;
- n = strndup(word, l);
- if (!n)
+ t = strndup(word, l);
+ if (!t)
return log_oom();
+ r = unit_name_printf(u, t, &n);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, -r,
+ "Failed to resolve specifiers, ignoring: %s", strerror(-r));
+ continue;
+ }
+
if (!filename_is_valid(n)) {
log_syntax(unit, LOG_ERR, filename, line, EINVAL,
"Runtime directory is not valid, ignoring assignment: %s", rvalue);
diff --git a/src/core/main.c b/src/core/main.c
index 200fe740da..9b59648279 100644
--- a/src/core/main.c
+++ b/src/core/main.c
@@ -1254,6 +1254,7 @@ int main(int argc, char *argv[]) {
char *switch_root_dir = NULL, *switch_root_init = NULL;
struct rlimit saved_rlimit_nofile = RLIMIT_MAKE_CONST(0);
const char *error_message = NULL;
+ uint8_t shutdown_exit_code = 0;
#ifdef HAVE_SYSV_COMPAT
if (getpid() != 1 && strstr(program_invocation_short_name, "init")) {
@@ -1764,11 +1765,6 @@ int main(int argc, char *argv[]) {
switch (m->exit_code) {
- case MANAGER_EXIT:
- retval = EXIT_SUCCESS;
- log_debug("Exit.");
- goto finish;
-
case MANAGER_RELOAD:
log_info("Reloading.");
@@ -1810,11 +1806,13 @@ int main(int argc, char *argv[]) {
log_notice("Switching root.");
goto finish;
+ case MANAGER_EXIT:
case MANAGER_REBOOT:
case MANAGER_POWEROFF:
case MANAGER_HALT:
case MANAGER_KEXEC: {
static const char * const table[_MANAGER_EXIT_CODE_MAX] = {
+ [MANAGER_EXIT] = "exit",
[MANAGER_REBOOT] = "reboot",
[MANAGER_POWEROFF] = "poweroff",
[MANAGER_HALT] = "halt",
@@ -1836,8 +1834,10 @@ int main(int argc, char *argv[]) {
finish:
pager_close();
- if (m)
+ if (m) {
arg_shutdown_watchdog = m->shutdown_watchdog;
+ shutdown_exit_code = m->return_value;
+ }
m = manager_free(m);
for (j = 0; j < ELEMENTSOF(arg_default_rlimit); j++)
@@ -1978,7 +1978,8 @@ finish:
if (shutdown_verb) {
char log_level[DECIMAL_STR_MAX(int) + 1];
- const char* command_line[9] = {
+ char exit_code[DECIMAL_STR_MAX(uint8_t) + 1];
+ const char* command_line[11] = {
SYSTEMD_SHUTDOWN_BINARY_PATH,
shutdown_verb,
"--log-level", log_level,
@@ -2015,6 +2016,12 @@ finish:
if (log_get_show_location())
command_line[pos++] = "--log-location";
+ if (streq(shutdown_verb, "exit")) {
+ command_line[pos++] = "--exit-code";
+ command_line[pos++] = exit_code;
+ xsprintf(exit_code, "%d", shutdown_exit_code);
+ }
+
assert(pos < ELEMENTSOF(command_line));
if (arm_reboot_watchdog && arg_shutdown_watchdog > 0) {
diff --git a/src/core/manager.h b/src/core/manager.h
index b955982100..1384eb33a4 100644
--- a/src/core/manager.h
+++ b/src/core/manager.h
@@ -242,6 +242,11 @@ struct Manager {
bool test_run:1;
+ /* If non-zero, exit with the following value when the systemd
+ * process terminate. Useful for containers: systemd-nspawn could get
+ * the return value. */
+ uint8_t return_value;
+
ShowStatus show_status;
bool confirm_spawn;
bool no_console_output;
diff --git a/src/core/shutdown.c b/src/core/shutdown.c
index 8cc6efc5b8..5296efce1d 100644
--- a/src/core/shutdown.c
+++ b/src/core/shutdown.c
@@ -48,6 +48,7 @@
#define FINALIZE_ATTEMPTS 50
static char* arg_verb;
+static uint8_t arg_exit_code;
static int parse_argv(int argc, char *argv[]) {
enum {
@@ -55,6 +56,7 @@ static int parse_argv(int argc, char *argv[]) {
ARG_LOG_TARGET,
ARG_LOG_COLOR,
ARG_LOG_LOCATION,
+ ARG_EXIT_CODE,
};
static const struct option options[] = {
@@ -62,6 +64,7 @@ static int parse_argv(int argc, char *argv[]) {
{ "log-target", required_argument, NULL, ARG_LOG_TARGET },
{ "log-color", optional_argument, NULL, ARG_LOG_COLOR },
{ "log-location", optional_argument, NULL, ARG_LOG_LOCATION },
+ { "exit-code", required_argument, NULL, ARG_EXIT_CODE },
{}
};
@@ -110,6 +113,13 @@ static int parse_argv(int argc, char *argv[]) {
break;
+ case ARG_EXIT_CODE:
+ r = safe_atou8(optarg, &arg_exit_code);
+ if (r < 0)
+ log_error("Failed to parse exit code %s, ignoring", optarg);
+
+ break;
+
case '\001':
if (!arg_verb)
arg_verb = optarg;
@@ -183,6 +193,8 @@ int main(int argc, char *argv[]) {
cmd = RB_HALT_SYSTEM;
else if (streq(arg_verb, "kexec"))
cmd = LINUX_REBOOT_CMD_KEXEC;
+ else if (streq(arg_verb, "exit"))
+ cmd = 0; /* ignored, just checking that arg_verb is valid */
else {
r = -EINVAL;
log_error("Unknown action '%s'.", arg_verb);
@@ -339,6 +351,16 @@ int main(int argc, char *argv[]) {
if (!in_container)
sync();
+ if (streq(arg_verb, "exit")) {
+ if (in_container)
+ exit(arg_exit_code);
+ else {
+ /* We cannot exit() on the host, fallback on another
+ * method. */
+ cmd = RB_POWER_OFF;
+ }
+ }
+
switch (cmd) {
case LINUX_REBOOT_CMD_KEXEC:
diff --git a/src/core/unit.c b/src/core/unit.c
index 3356b97522..3a6313e4a2 100644
--- a/src/core/unit.c
+++ b/src/core/unit.c
@@ -3064,32 +3064,39 @@ int unit_kill_common(
sd_bus_error *error) {
int r = 0;
+ bool killed = false;
- if (who == KILL_MAIN) {
+ if (IN_SET(who, KILL_MAIN, KILL_MAIN_FAIL)) {
if (main_pid < 0)
return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_PROCESS, "%s units have no main processes", unit_type_to_string(u->type));
else if (main_pid == 0)
return sd_bus_error_set_const(error, BUS_ERROR_NO_SUCH_PROCESS, "No main process to kill");
}
- if (who == KILL_CONTROL) {
+ if (IN_SET(who, KILL_CONTROL, KILL_CONTROL_FAIL)) {
if (control_pid < 0)
return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_PROCESS, "%s units have no control processes", unit_type_to_string(u->type));
else if (control_pid == 0)
return sd_bus_error_set_const(error, BUS_ERROR_NO_SUCH_PROCESS, "No control process to kill");
}
- if (who == KILL_CONTROL || who == KILL_ALL)
- if (control_pid > 0)
+ if (IN_SET(who, KILL_CONTROL, KILL_CONTROL_FAIL, KILL_ALL, KILL_ALL_FAIL))
+ if (control_pid > 0) {
if (kill(control_pid, signo) < 0)
r = -errno;
+ else
+ killed = true;
+ }
- if (who == KILL_MAIN || who == KILL_ALL)
- if (main_pid > 0)
+ if (IN_SET(who, KILL_MAIN, KILL_MAIN_FAIL, KILL_ALL, KILL_ALL_FAIL))
+ if (main_pid > 0) {
if (kill(main_pid, signo) < 0)
r = -errno;
+ else
+ killed = true;
+ }
- if (who == KILL_ALL && u->cgroup_path) {
+ if (IN_SET(who, KILL_ALL, KILL_ALL_FAIL) && u->cgroup_path) {
_cleanup_set_free_ Set *pid_set = NULL;
int q;
@@ -3101,8 +3108,13 @@ int unit_kill_common(
q = cg_kill_recursive(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, signo, false, false, false, pid_set);
if (q < 0 && q != -EAGAIN && q != -ESRCH && q != -ENOENT)
r = q;
+ else
+ killed = true;
}
+ if (r == 0 && !killed && IN_SET(who, KILL_ALL_FAIL, KILL_CONTROL_FAIL, KILL_ALL_FAIL))
+ return -ESRCH;
+
return r;
}
diff --git a/src/libsystemd-network/arp-util.c b/src/libsystemd-network/arp-util.c
new file mode 100644
index 0000000000..2f5b9b3731
--- /dev/null
+++ b/src/libsystemd-network/arp-util.c
@@ -0,0 +1,153 @@
+/***
+ This file is part of systemd.
+
+ Copyright (C) 2014 Axis Communications AB. All rights reserved.
+ Copyright (C) 2015 Tom Gundersen
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <linux/filter.h>
+#include <arpa/inet.h>
+
+#include "util.h"
+#include "arp-util.h"
+
+int arp_network_bind_raw_socket(int ifindex, be32_t address, const struct ether_addr *eth_mac) {
+ struct sock_filter filter[] = {
+ BPF_STMT(BPF_LD + BPF_W + BPF_LEN, 0), /* A <- packet length */
+ BPF_JUMP(BPF_JMP + BPF_JGE + BPF_K, sizeof(struct ether_arp), 1, 0), /* packet >= arp packet ? */
+ BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */
+ BPF_STMT(BPF_LD + BPF_H + BPF_ABS, offsetof(struct ether_arp, ea_hdr.ar_hrd)), /* A <- header */
+ BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ARPHRD_ETHER, 1, 0), /* header == ethernet ? */
+ BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */
+ BPF_STMT(BPF_LD + BPF_H + BPF_ABS, offsetof(struct ether_arp, ea_hdr.ar_pro)), /* A <- protocol */
+ BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ETHERTYPE_IP, 1, 0), /* protocol == IP ? */
+ BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */
+ BPF_STMT(BPF_LD + BPF_B + BPF_ABS, offsetof(struct ether_arp, ea_hdr.ar_hln)), /* A <- hardware address length */
+ BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, sizeof(struct ether_addr), 1, 0), /* length == sizeof(ether_addr)? */
+ BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */
+ BPF_STMT(BPF_LD + BPF_B + BPF_ABS, offsetof(struct ether_arp, ea_hdr.ar_pln)), /* A <- protocol address length */
+ BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, sizeof(struct in_addr), 1, 0), /* length == sizeof(in_addr) ? */
+ BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */
+ BPF_STMT(BPF_LD + BPF_H + BPF_ABS, offsetof(struct ether_arp, ea_hdr.ar_op)), /* A <- operation */
+ BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ARPOP_REQUEST, 2, 0), /* protocol == request ? */
+ BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ARPOP_REPLY, 1, 0), /* protocol == reply ? */
+ BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */
+ /* Sender Hardware Address must be different from our own */
+ BPF_STMT(BPF_LD + BPF_IMM, htobe32(*((uint32_t *) eth_mac))), /* A <- 4 bytes of client's MAC */
+ BPF_STMT(BPF_MISC + BPF_TAX, 0), /* X <- A */
+ BPF_STMT(BPF_LD + BPF_W + BPF_ABS, offsetof(struct ether_arp, arp_sha)), /* A <- 4 bytes of SHA */
+ BPF_STMT(BPF_ALU + BPF_XOR + BPF_X, 0), /* A xor X */
+ BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0, 0, 6), /* A == 0 ? */
+ BPF_STMT(BPF_LD + BPF_IMM, htobe16(*((uint16_t *) (((char *) eth_mac) + 4)))), /* A <- remainder of client's MAC */
+ BPF_STMT(BPF_MISC + BPF_TAX, 0), /* X <- A */
+ BPF_STMT(BPF_LD + BPF_H + BPF_ABS, offsetof(struct ether_arp, arp_sha) + 4), /* A <- remainder of SHA */
+ BPF_STMT(BPF_ALU + BPF_XOR + BPF_X, 0), /* A xor X */
+ BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0, 0, 1), /* A == 0 ? */
+ BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */
+ /* Sender Protocol Address or Target Protocol Address must be equal to the one we care about*/
+ BPF_STMT(BPF_LD + BPF_IMM, htobe32(address)), /* A <- clients IP */
+ BPF_STMT(BPF_MISC + BPF_TAX, 0), /* X <- A */
+ BPF_STMT(BPF_LD + BPF_W + BPF_ABS, offsetof(struct ether_arp, arp_spa)), /* A <- SPA */
+ BPF_STMT(BPF_ALU + BPF_XOR + BPF_X, 0), /* X xor A */
+ BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0, 0, 1), /* A == 0 ? */
+ BPF_STMT(BPF_RET + BPF_K, 65535), /* return all */
+ BPF_STMT(BPF_LD + BPF_IMM, htobe32(address)), /* A <- clients IP */
+ BPF_STMT(BPF_MISC + BPF_TAX, 0), /* X <- A */
+ BPF_STMT(BPF_LD + BPF_W + BPF_ABS, offsetof(struct ether_arp, arp_tpa)), /* A <- TPA */
+ BPF_STMT(BPF_ALU + BPF_XOR + BPF_X, 0), /* X xor A */
+ BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0, 0, 1), /* A == 0 ? */
+ BPF_STMT(BPF_RET + BPF_K, 65535), /* return all */
+ BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */
+ };
+ struct sock_fprog fprog = {
+ .len = ELEMENTSOF(filter),
+ .filter = (struct sock_filter*) filter
+ };
+ union sockaddr_union link = {
+ .ll.sll_family = AF_PACKET,
+ .ll.sll_protocol = htons(ETH_P_ARP),
+ .ll.sll_ifindex = ifindex,
+ .ll.sll_halen = ETH_ALEN,
+ .ll.sll_addr = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff },
+ };
+ _cleanup_close_ int s = -1;
+ int r;
+
+ assert(ifindex > 0);
+
+ s = socket(PF_PACKET, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0);
+ if (s < 0)
+ return -errno;
+
+ r = setsockopt(s, SOL_SOCKET, SO_ATTACH_FILTER, &fprog, sizeof(fprog));
+ if (r < 0)
+ return -errno;
+
+ r = bind(s, &link.sa, sizeof(link.ll));
+ if (r < 0)
+ return -errno;
+
+ r = s;
+ s = -1;
+
+ return r;
+}
+
+static int arp_send_packet(int fd, int ifindex,
+ be32_t pa, const struct ether_addr *ha,
+ bool announce) {
+ union sockaddr_union link = {
+ .ll.sll_family = AF_PACKET,
+ .ll.sll_protocol = htons(ETH_P_ARP),
+ .ll.sll_ifindex = ifindex,
+ .ll.sll_halen = ETH_ALEN,
+ .ll.sll_addr = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff },
+ };
+ struct ether_arp arp = {
+ .ea_hdr.ar_hrd = htons(ARPHRD_ETHER), /* HTYPE */
+ .ea_hdr.ar_pro = htons(ETHERTYPE_IP), /* PTYPE */
+ .ea_hdr.ar_hln = ETH_ALEN, /* HLEN */
+ .ea_hdr.ar_pln = sizeof(be32_t), /* PLEN */
+ .ea_hdr.ar_op = htons(ARPOP_REQUEST), /* REQUEST */
+ };
+ int r;
+
+ assert(fd >= 0);
+ assert(pa != 0);
+ assert(ha);
+
+ memcpy(&arp.arp_sha, ha, ETH_ALEN);
+ memcpy(&arp.arp_tpa, &pa, sizeof(pa));
+
+ if (announce)
+ memcpy(&arp.arp_spa, &pa, sizeof(pa));
+
+ r = sendto(fd, &arp, sizeof(struct ether_arp), 0, &link.sa, sizeof(link.ll));
+ if (r < 0)
+ return -errno;
+
+ return 0;
+}
+
+int arp_send_probe(int fd, int ifindex,
+ be32_t pa, const struct ether_addr *ha) {
+ return arp_send_packet(fd, ifindex, pa, ha, false);
+}
+
+int arp_send_announcement(int fd, int ifindex,
+ be32_t pa, const struct ether_addr *ha) {
+ return arp_send_packet(fd, ifindex, pa, ha, true);
+}
diff --git a/src/libsystemd-network/ipv4ll-internal.h b/src/libsystemd-network/arp-util.h
index ae0ce43985..44e5c893a7 100644
--- a/src/libsystemd-network/ipv4ll-internal.h
+++ b/src/libsystemd-network/arp-util.h
@@ -26,13 +26,9 @@
#include "sparse-endian.h"
#include "socket-util.h"
-int arp_network_bind_raw_socket(int index, union sockaddr_union *link);
-int arp_network_send_raw_socket(int fd, const union sockaddr_union *link,
- const struct ether_arp *arp);
+int arp_network_bind_raw_socket(int index, be32_t address, const struct ether_addr *eth_mac);
-void arp_packet_init(struct ether_arp *arp);
-void arp_packet_probe(struct ether_arp *arp, be32_t pa, const struct ether_addr *ha);
-void arp_packet_announcement(struct ether_arp *arp, be32_t pa, const struct ether_addr *ha);
-int arp_packet_verify_headers(struct ether_arp *arp);
-
-#define log_ipv4ll(ll, fmt, ...) log_internal(LOG_DEBUG, 0, __FILE__, __LINE__, __func__, "IPv4LL: " fmt, ##__VA_ARGS__)
+int arp_send_probe(int fd, int ifindex,
+ be32_t pa, const struct ether_addr *ha);
+int arp_send_announcement(int fd, int ifindex,
+ be32_t pa, const struct ether_addr *ha);
diff --git a/src/libsystemd-network/ipv4ll-network.c b/src/libsystemd-network/ipv4ll-network.c
deleted file mode 100644
index 93ffed408f..0000000000
--- a/src/libsystemd-network/ipv4ll-network.c
+++ /dev/null
@@ -1,91 +0,0 @@
-/***
- This file is part of systemd.
-
- Copyright (C) 2014 Axis Communications AB. All rights reserved.
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <linux/filter.h>
-
-#include "util.h"
-#include "ipv4ll-internal.h"
-
-int arp_network_send_raw_socket(int fd, const union sockaddr_union *link,
- const struct ether_arp *arp) {
- int r;
-
- assert(arp);
- assert(link);
- assert(fd >= 0);
-
- r = sendto(fd, arp, sizeof(struct ether_arp), 0, &link->sa, sizeof(link->ll));
- if (r < 0)
- return -errno;
-
- return 0;
-}
-
-int arp_network_bind_raw_socket(int ifindex, union sockaddr_union *link) {
-
- static const struct sock_filter filter[] = {
- BPF_STMT(BPF_LD + BPF_W + BPF_LEN, 0), /* A <- packet length */
- BPF_JUMP(BPF_JMP + BPF_JGE + BPF_K, sizeof(struct ether_arp), 1, 0), /* packet >= arp packet ? */
- BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */
- BPF_STMT(BPF_LD + BPF_H + BPF_ABS, offsetof(struct ether_arp, ea_hdr.ar_hrd)), /* A <- header */
- BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ARPHRD_ETHER, 1, 0), /* header == ethernet ? */
- BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */
- BPF_STMT(BPF_LD + BPF_H + BPF_ABS, offsetof(struct ether_arp, ea_hdr.ar_pro)), /* A <- protocol */
- BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ETHERTYPE_IP, 1, 0), /* protocol == IP ? */
- BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */
- BPF_STMT(BPF_LD + BPF_H + BPF_ABS, offsetof(struct ether_arp, ea_hdr.ar_op)), /* A <- operation */
- BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ARPOP_REQUEST, 0, 1), /* protocol == request ? */
- BPF_STMT(BPF_RET + BPF_K, 65535), /* return all */
- BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ARPOP_REPLY, 0, 1), /* protocol == reply ? */
- BPF_STMT(BPF_RET + BPF_K, 65535), /* return all */
- BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */
- };
- struct sock_fprog fprog = {
- .len = ELEMENTSOF(filter),
- .filter = (struct sock_filter*) filter
- };
- _cleanup_close_ int s = -1;
- int r;
-
- assert(ifindex > 0);
- assert(link);
-
- s = socket(PF_PACKET, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0);
- if (s < 0)
- return -errno;
-
- r = setsockopt(s, SOL_SOCKET, SO_ATTACH_FILTER, &fprog, sizeof(fprog));
- if (r < 0)
- return -errno;
-
- link->ll.sll_family = AF_PACKET;
- link->ll.sll_protocol = htons(ETH_P_ARP);
- link->ll.sll_ifindex = ifindex;
- link->ll.sll_halen = ETH_ALEN;
- memset(link->ll.sll_addr, 0xff, ETH_ALEN);
-
- r = bind(s, &link->sa, sizeof(link->ll));
- if (r < 0)
- return -errno;
-
- r = s;
- s = -1;
-
- return r;
-}
diff --git a/src/libsystemd-network/ipv4ll-packet.c b/src/libsystemd-network/ipv4ll-packet.c
deleted file mode 100644
index 2b6c73ab4b..0000000000
--- a/src/libsystemd-network/ipv4ll-packet.c
+++ /dev/null
@@ -1,71 +0,0 @@
-/***
- This file is part of systemd.
-
- Copyright (C) 2014 Axis Communications AB. All rights reserved.
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-#include <arpa/inet.h>
-
-#include "util.h"
-#include "ipv4ll-internal.h"
-
-void arp_packet_init(struct ether_arp *arp) {
- assert(arp);
-
- memzero(arp, sizeof(struct ether_arp));
- /* Header */
- arp->ea_hdr.ar_hrd = htons(ARPHRD_ETHER); /* HTYPE */
- arp->ea_hdr.ar_pro = htons(ETHERTYPE_IP); /* PTYPE */
- arp->ea_hdr.ar_hln = ETH_ALEN; /* HLEN */
- arp->ea_hdr.ar_pln = sizeof arp->arp_spa; /* PLEN */
- arp->ea_hdr.ar_op = htons(ARPOP_REQUEST); /* REQUEST */
-}
-
-void arp_packet_probe(struct ether_arp *arp, be32_t pa, const struct ether_addr *ha) {
- assert(ha);
-
- arp_packet_init(arp);
- memcpy(arp->arp_sha, ha, ETH_ALEN);
- memcpy(arp->arp_tpa, &pa, sizeof(pa));
-}
-
-void arp_packet_announcement(struct ether_arp *arp, be32_t pa, const struct ether_addr *ha) {
- assert(ha);
-
- arp_packet_init(arp);
- memcpy(arp->arp_sha, ha, ETH_ALEN);
- memcpy(arp->arp_tpa, &pa, sizeof(pa));
- memcpy(arp->arp_spa, &pa, sizeof(pa));
-}
-
-int arp_packet_verify_headers(struct ether_arp *arp) {
- assert(arp);
-
- if (arp->ea_hdr.ar_hrd != htons(ARPHRD_ETHER)) {
- log_ipv4ll(NULL, "ignoring packet: header is not ARPHRD_ETHER");
- return -EINVAL;
- }
- if (arp->ea_hdr.ar_pro != htons(ETHERTYPE_IP)) {
- log_ipv4ll(NULL, "ignoring packet: protocol is not ETHERTYPE_IP");
- return -EINVAL;
- }
- if (arp->ea_hdr.ar_op != htons(ARPOP_REQUEST) &&
- arp->ea_hdr.ar_op != htons(ARPOP_REPLY)) {
- log_ipv4ll(NULL, "ignoring packet: operation is not ARPOP_REQUEST or ARPOP_REPLY");
- return -EINVAL;
- }
-
- return 0;
-}
diff --git a/src/libsystemd-network/sd-ipv4acd.c b/src/libsystemd-network/sd-ipv4acd.c
new file mode 100644
index 0000000000..ee5d13c030
--- /dev/null
+++ b/src/libsystemd-network/sd-ipv4acd.c
@@ -0,0 +1,529 @@
+/***
+ This file is part of systemd.
+
+ Copyright (C) 2014 Axis Communications AB. All rights reserved.
+ Copyright (C) 2015 Tom Gundersen
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <arpa/inet.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "event-util.h"
+#include "in-addr-util.h"
+#include "list.h"
+#include "refcnt.h"
+#include "random-util.h"
+#include "siphash24.h"
+#include "util.h"
+
+#include "arp-util.h"
+#include "sd-ipv4acd.h"
+
+/* Constants from the RFC */
+#define PROBE_WAIT 1
+#define PROBE_NUM 3
+#define PROBE_MIN 1
+#define PROBE_MAX 2
+#define ANNOUNCE_WAIT 2
+#define ANNOUNCE_NUM 2
+#define ANNOUNCE_INTERVAL 2
+#define MAX_CONFLICTS 10
+#define RATE_LIMIT_INTERVAL 60
+#define DEFEND_INTERVAL 10
+
+#define IPV4ACD_NETWORK 0xA9FE0000L
+#define IPV4ACD_NETMASK 0xFFFF0000L
+
+#define log_ipv4acd_full(ll, level, error, fmt, ...) log_internal(level, error, __FILE__, __LINE__, __func__, "ACD: " fmt, ##__VA_ARGS__)
+
+#define log_ipv4acd_debug(ll, ...) log_ipv4acd_full(ll, LOG_DEBUG, 0, ##__VA_ARGS__)
+#define log_ipv4acd_info(ll, ...) log_ipv4acd_full(ll, LOG_INFO, 0, ##__VA_ARGS__)
+#define log_ipv4acd_notice(ll, ...) log_ipv4acd_full(ll, LOG_NOTICE, 0, ##__VA_ARGS__)
+#define log_ipv4acd_warning(ll, ...) log_ipv4acd_full(ll, LOG_WARNING, 0, ##__VA_ARGS__)
+#define log_ipv4acd_error(ll, ...) log_ipv4acd_full(ll, LOG_ERR, 0, ##__VA_ARGS__)
+
+#define log_ipv4acd_debug_errno(ll, error, ...) log_ipv4acd_full(ll, LOG_DEBUG, error, ##__VA_ARGS__)
+#define log_ipv4acd_info_errno(ll, error, ...) log_ipv4acd_full(ll, LOG_INFO, error, ##__VA_ARGS__)
+#define log_ipv4acd_notice_errno(ll, error, ...) log_ipv4acd_full(ll, LOG_NOTICE, error, ##__VA_ARGS__)
+#define log_ipv4acd_warning_errno(ll, error, ...) log_ipv4acd_full(ll, LOG_WARNING, error, ##__VA_ARGS__)
+#define log_ipv4acd_error_errno(ll, error, ...) log_ipv4acd_full(ll, LOG_ERR, error, ##__VA_ARGS__)
+
+typedef enum IPv4ACDState {
+ IPV4ACD_STATE_INIT,
+ IPV4ACD_STATE_WAITING_PROBE,
+ IPV4ACD_STATE_PROBING,
+ IPV4ACD_STATE_WAITING_ANNOUNCE,
+ IPV4ACD_STATE_ANNOUNCING,
+ IPV4ACD_STATE_RUNNING,
+ _IPV4ACD_STATE_MAX,
+ _IPV4ACD_STATE_INVALID = -1
+} IPv4ACDState;
+
+struct sd_ipv4acd {
+ RefCount n_ref;
+
+ IPv4ACDState state;
+ int index;
+ int fd;
+ int iteration;
+ int conflict;
+ sd_event_source *receive_message;
+ sd_event_source *timer;
+ usec_t defend_window;
+ be32_t address;
+ /* External */
+ struct ether_addr mac_addr;
+ sd_event *event;
+ int event_priority;
+ sd_ipv4acd_cb_t cb;
+ void* userdata;
+};
+
+sd_ipv4acd *sd_ipv4acd_ref(sd_ipv4acd *ll) {
+ if (ll)
+ assert_se(REFCNT_INC(ll->n_ref) >= 2);
+
+ return ll;
+}
+
+sd_ipv4acd *sd_ipv4acd_unref(sd_ipv4acd *ll) {
+ if (!ll || REFCNT_DEC(ll->n_ref) > 0)
+ return NULL;
+
+ ll->receive_message = sd_event_source_unref(ll->receive_message);
+ ll->fd = safe_close(ll->fd);
+
+ ll->timer = sd_event_source_unref(ll->timer);
+
+ sd_ipv4acd_detach_event(ll);
+
+ free(ll);
+
+ return NULL;
+}
+
+DEFINE_TRIVIAL_CLEANUP_FUNC(sd_ipv4acd*, sd_ipv4acd_unref);
+#define _cleanup_ipv4acd_unref_ _cleanup_(sd_ipv4acd_unrefp)
+
+int sd_ipv4acd_new(sd_ipv4acd **ret) {
+ _cleanup_ipv4acd_unref_ sd_ipv4acd *ll = NULL;
+
+ assert_return(ret, -EINVAL);
+
+ ll = new0(sd_ipv4acd, 1);
+ if (!ll)
+ return -ENOMEM;
+
+ ll->n_ref = REFCNT_INIT;
+ ll->state = IPV4ACD_STATE_INIT;
+ ll->index = -1;
+ ll->fd = -1;
+
+ *ret = ll;
+ ll = NULL;
+
+ return 0;
+}
+
+static void ipv4acd_set_state(sd_ipv4acd *ll, IPv4ACDState st, bool reset_counter) {
+
+ assert(ll);
+ assert(st < _IPV4ACD_STATE_MAX);
+
+ if (st == ll->state && !reset_counter)
+ ll->iteration++;
+ else {
+ ll->state = st;
+ ll->iteration = 0;
+ }
+}
+
+static void ipv4acd_client_notify(sd_ipv4acd *ll, int event) {
+ assert(ll);
+
+ if (ll->cb)
+ ll->cb(ll, event, ll->userdata);
+}
+
+static void ipv4acd_stop(sd_ipv4acd *ll) {
+ assert(ll);
+
+ ll->receive_message = sd_event_source_unref(ll->receive_message);
+ ll->fd = safe_close(ll->fd);
+
+ ll->timer = sd_event_source_unref(ll->timer);
+
+ log_ipv4acd_debug(ll, "STOPPED");
+
+ ipv4acd_set_state (ll, IPV4ACD_STATE_INIT, true);
+}
+
+int sd_ipv4acd_stop(sd_ipv4acd *ll) {
+ assert_return(ll, -EINVAL);
+
+ ipv4acd_stop(ll);
+
+ ipv4acd_client_notify(ll, IPV4ACD_EVENT_STOP);
+
+ return 0;
+}
+
+static int ipv4acd_on_timeout(sd_event_source *s, uint64_t usec, void *userdata);
+
+static int ipv4acd_set_next_wakeup(sd_ipv4acd *ll, int sec, int random_sec) {
+ _cleanup_event_source_unref_ sd_event_source *timer = NULL;
+ usec_t next_timeout;
+ usec_t time_now;
+ int r;
+
+ assert(sec >= 0);
+ assert(random_sec >= 0);
+ assert(ll);
+
+ next_timeout = sec * USEC_PER_SEC;
+
+ if (random_sec)
+ next_timeout += random_u32() % (random_sec * USEC_PER_SEC);
+
+ assert_se(sd_event_now(ll->event, clock_boottime_or_monotonic(), &time_now) >= 0);
+
+ r = sd_event_add_time(ll->event, &timer, clock_boottime_or_monotonic(),
+ time_now + next_timeout, 0, ipv4acd_on_timeout, ll);
+ if (r < 0)
+ return r;
+
+ r = sd_event_source_set_priority(timer, ll->event_priority);
+ if (r < 0)
+ return r;
+
+ r = sd_event_source_set_description(timer, "ipv4acd-timer");
+ if (r < 0)
+ return r;
+
+ ll->timer = sd_event_source_unref(ll->timer);
+ ll->timer = timer;
+ timer = NULL;
+
+ return 0;
+}
+
+static bool ipv4acd_arp_conflict(sd_ipv4acd *ll, struct ether_arp *arp) {
+ assert(ll);
+ assert(arp);
+
+ /* see the BPF */
+ if (memcmp(arp->arp_spa, &ll->address, sizeof(ll->address)) == 0)
+ return true;
+
+ /* the TPA matched instead of the SPA, this is not a conflict */
+ return false;
+}
+
+static int ipv4acd_on_timeout(sd_event_source *s, uint64_t usec, void *userdata) {
+ sd_ipv4acd *ll = userdata;
+ int r = 0;
+
+ assert(ll);
+
+ switch (ll->state) {
+ case IPV4ACD_STATE_INIT:
+
+ ipv4acd_set_state(ll, IPV4ACD_STATE_WAITING_PROBE, true);
+
+ if (ll->conflict >= MAX_CONFLICTS) {
+ log_ipv4acd_notice(ll, "Max conflicts reached, delaying by %us", RATE_LIMIT_INTERVAL);
+ r = ipv4acd_set_next_wakeup(ll, RATE_LIMIT_INTERVAL, PROBE_WAIT);
+ if (r < 0)
+ goto out;
+
+ ll->conflict = 0;
+ } else {
+ r = ipv4acd_set_next_wakeup(ll, 0, PROBE_WAIT);
+ if (r < 0)
+ goto out;
+ }
+
+ break;
+ case IPV4ACD_STATE_WAITING_PROBE:
+ case IPV4ACD_STATE_PROBING:
+ /* Send a probe */
+ r = arp_send_probe(ll->fd, ll->index, ll->address, &ll->mac_addr);
+ if (r < 0) {
+ log_ipv4acd_error_errno(ll, r, "Failed to send ARP probe: %m");
+ goto out;
+ } else {
+ _cleanup_free_ char *address = NULL;
+ union in_addr_union addr = { .in.s_addr = ll->address };
+
+ r = in_addr_to_string(AF_INET, &addr, &address);
+ if (r >= 0)
+ log_ipv4acd_debug(ll, "Probing %s", address);
+ }
+
+ if (ll->iteration < PROBE_NUM - 2) {
+ ipv4acd_set_state(ll, IPV4ACD_STATE_PROBING, false);
+
+ r = ipv4acd_set_next_wakeup(ll, PROBE_MIN, (PROBE_MAX-PROBE_MIN));
+ if (r < 0)
+ goto out;
+ } else {
+ ipv4acd_set_state(ll, IPV4ACD_STATE_WAITING_ANNOUNCE, true);
+
+ r = ipv4acd_set_next_wakeup(ll, ANNOUNCE_WAIT, 0);
+ if (r < 0)
+ goto out;
+ }
+
+ break;
+
+ case IPV4ACD_STATE_ANNOUNCING:
+ if (ll->iteration >= ANNOUNCE_NUM - 1) {
+ ipv4acd_set_state(ll, IPV4ACD_STATE_RUNNING, false);
+
+ break;
+ }
+ case IPV4ACD_STATE_WAITING_ANNOUNCE:
+ /* Send announcement packet */
+ r = arp_send_announcement(ll->fd, ll->index, ll->address, &ll->mac_addr);
+ if (r < 0) {
+ log_ipv4acd_error_errno(ll, r, "Failed to send ARP announcement: %m");
+ goto out;
+ } else
+ log_ipv4acd_debug(ll, "ANNOUNCE");
+
+ ipv4acd_set_state(ll, IPV4ACD_STATE_ANNOUNCING, false);
+
+ r = ipv4acd_set_next_wakeup(ll, ANNOUNCE_INTERVAL, 0);
+ if (r < 0)
+ goto out;
+
+ if (ll->iteration == 0) {
+ ll->conflict = 0;
+ ipv4acd_client_notify(ll, IPV4ACD_EVENT_BIND);
+ }
+
+ break;
+ default:
+ assert_not_reached("Invalid state.");
+ }
+
+out:
+ if (r < 0)
+ sd_ipv4acd_stop(ll);
+
+ return 1;
+}
+
+static void ipv4acd_on_conflict(sd_ipv4acd *ll) {
+ _cleanup_free_ char *address = NULL;
+ union in_addr_union addr = { .in.s_addr = ll->address };
+ int r;
+
+ assert(ll);
+
+ ll->conflict++;
+
+ r = in_addr_to_string(AF_INET, &addr, &address);
+ if (r >= 0)
+ log_ipv4acd_debug(ll, "Conflict on %s (%u)", address, ll->conflict);
+
+ ipv4acd_stop(ll);
+
+ ipv4acd_client_notify(ll, IPV4ACD_EVENT_CONFLICT);
+}
+
+static int ipv4acd_on_packet(sd_event_source *s, int fd,
+ uint32_t revents, void *userdata) {
+ sd_ipv4acd *ll = userdata;
+ struct ether_arp packet;
+ int r;
+
+ assert(ll);
+ assert(fd >= 0);
+
+ r = read(fd, &packet, sizeof(struct ether_arp));
+ if (r < (int) sizeof(struct ether_arp))
+ goto out;
+
+ switch (ll->state) {
+ case IPV4ACD_STATE_ANNOUNCING:
+ case IPV4ACD_STATE_RUNNING:
+ if (ipv4acd_arp_conflict(ll, &packet)) {
+ usec_t ts;
+
+ assert_se(sd_event_now(ll->event, clock_boottime_or_monotonic(), &ts) >= 0);
+
+ /* Defend address */
+ if (ts > ll->defend_window) {
+ ll->defend_window = ts + DEFEND_INTERVAL * USEC_PER_SEC;
+ r = arp_send_announcement(ll->fd, ll->index, ll->address, &ll->mac_addr);
+ if (r < 0) {
+ log_ipv4acd_error_errno(ll, r, "Failed to send ARP announcement: %m");
+ goto out;
+ } else
+ log_ipv4acd_debug(ll, "DEFEND");
+
+ } else
+ ipv4acd_on_conflict(ll);
+ }
+
+ break;
+ case IPV4ACD_STATE_WAITING_PROBE:
+ case IPV4ACD_STATE_PROBING:
+ case IPV4ACD_STATE_WAITING_ANNOUNCE:
+ /* BPF ensures this packet indicates a conflict */
+ ipv4acd_on_conflict(ll);
+
+ break;
+ default:
+ assert_not_reached("Invalid state.");
+ }
+
+out:
+ if (r < 0)
+ sd_ipv4acd_stop(ll);
+
+ return 1;
+}
+
+int sd_ipv4acd_set_index(sd_ipv4acd *ll, int interface_index) {
+ assert_return(ll, -EINVAL);
+ assert_return(interface_index > 0, -EINVAL);
+ assert_return(ll->state == IPV4ACD_STATE_INIT, -EBUSY);
+
+ ll->index = interface_index;
+
+ return 0;
+}
+
+int sd_ipv4acd_set_mac(sd_ipv4acd *ll, const struct ether_addr *addr) {
+ assert_return(ll, -EINVAL);
+ assert_return(addr, -EINVAL);
+ assert_return(ll->state == IPV4ACD_STATE_INIT, -EBUSY);
+
+ memcpy(&ll->mac_addr, addr, ETH_ALEN);
+
+ return 0;
+}
+
+int sd_ipv4acd_detach_event(sd_ipv4acd *ll) {
+ assert_return(ll, -EINVAL);
+
+ ll->event = sd_event_unref(ll->event);
+
+ return 0;
+}
+
+int sd_ipv4acd_attach_event(sd_ipv4acd *ll, sd_event *event, int priority) {
+ int r;
+
+ assert_return(ll, -EINVAL);
+ assert_return(!ll->event, -EBUSY);
+
+ if (event)
+ ll->event = sd_event_ref(event);
+ else {
+ r = sd_event_default(&ll->event);
+ if (r < 0)
+ return r;
+ }
+
+ ll->event_priority = priority;
+
+ return 0;
+}
+
+int sd_ipv4acd_set_callback(sd_ipv4acd *ll, sd_ipv4acd_cb_t cb, void *userdata) {
+ assert_return(ll, -EINVAL);
+
+ ll->cb = cb;
+ ll->userdata = userdata;
+
+ return 0;
+}
+
+int sd_ipv4acd_set_address(sd_ipv4acd *ll, const struct in_addr *address){
+ assert_return(ll, -EINVAL);
+ assert_return(address, -EINVAL);
+ assert_return(ll->state == IPV4ACD_STATE_INIT, -EBUSY);
+
+ ll->address = address->s_addr;
+
+ return 0;
+}
+
+bool sd_ipv4acd_is_running(sd_ipv4acd *ll) {
+ assert_return(ll, false);
+
+ return ll->state != IPV4ACD_STATE_INIT;
+}
+
+static bool ether_addr_is_nul(const struct ether_addr *addr) {
+ const struct ether_addr nul_addr = {};
+
+ assert(addr);
+
+ return memcmp(addr, &nul_addr, sizeof(struct ether_addr)) == 0;
+}
+
+#define HASH_KEY SD_ID128_MAKE(df,04,22,98,3f,ad,14,52,f9,87,2e,d1,9c,70,e2,f2)
+
+int sd_ipv4acd_start(sd_ipv4acd *ll) {
+ int r;
+
+ assert_return(ll, -EINVAL);
+ assert_return(ll->event, -EINVAL);
+ assert_return(ll->index > 0, -EINVAL);
+ assert_return(ll->address != 0, -EINVAL);
+ assert_return(!ether_addr_is_nul(&ll->mac_addr), -EINVAL);
+ assert_return(ll->state == IPV4ACD_STATE_INIT, -EBUSY);
+
+ ll->defend_window = 0;
+
+ r = arp_network_bind_raw_socket(ll->index, ll->address, &ll->mac_addr);
+ if (r < 0)
+ goto out;
+
+ ll->fd = safe_close(ll->fd);
+ ll->fd = r;
+
+ r = sd_event_add_io(ll->event, &ll->receive_message, ll->fd,
+ EPOLLIN, ipv4acd_on_packet, ll);
+ if (r < 0)
+ goto out;
+
+ r = sd_event_source_set_priority(ll->receive_message, ll->event_priority);
+ if (r < 0)
+ goto out;
+
+ r = sd_event_source_set_description(ll->receive_message, "ipv4acd-receive-message");
+ if (r < 0)
+ goto out;
+
+ r = ipv4acd_set_next_wakeup(ll, 0, 0);
+ if (r < 0)
+ goto out;
+out:
+ if (r < 0) {
+ ipv4acd_stop(ll);
+ return r;
+ }
+
+ return 0;
+}
diff --git a/src/libsystemd-network/sd-ipv4ll.c b/src/libsystemd-network/sd-ipv4ll.c
index 14b9444dab..f0230b919c 100644
--- a/src/libsystemd-network/sd-ipv4ll.c
+++ b/src/libsystemd-network/sd-ipv4ll.c
@@ -2,6 +2,7 @@
This file is part of systemd.
Copyright (C) 2014 Axis Communications AB. All rights reserved.
+ Copyright (C) 2015 Tom Gundersen
systemd is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by
@@ -23,429 +24,153 @@
#include <stdio.h>
#include <arpa/inet.h>
-#include "util.h"
-#include "siphash24.h"
+#include "event-util.h"
#include "list.h"
#include "random-util.h"
+#include "refcnt.h"
+#include "siphash24.h"
+#include "sparse-endian.h"
+#include "util.h"
-#include "ipv4ll-internal.h"
+#include "sd-ipv4acd.h"
#include "sd-ipv4ll.h"
-/* Constants from the RFC */
-#define PROBE_WAIT 1
-#define PROBE_NUM 3
-#define PROBE_MIN 1
-#define PROBE_MAX 2
-#define ANNOUNCE_WAIT 2
-#define ANNOUNCE_NUM 2
-#define ANNOUNCE_INTERVAL 2
-#define MAX_CONFLICTS 10
-#define RATE_LIMIT_INTERVAL 60
-#define DEFEND_INTERVAL 10
-
#define IPV4LL_NETWORK 0xA9FE0000L
#define IPV4LL_NETMASK 0xFFFF0000L
-typedef enum IPv4LLTrigger{
- IPV4LL_TRIGGER_NULL,
- IPV4LL_TRIGGER_PACKET,
- IPV4LL_TRIGGER_TIMEOUT,
- _IPV4LL_TRIGGER_MAX,
- _IPV4LL_TRIGGER_INVALID = -1
-} IPv4LLTrigger;
-
-typedef enum IPv4LLState {
- IPV4LL_STATE_INIT,
- IPV4LL_STATE_WAITING_PROBE,
- IPV4LL_STATE_PROBING,
- IPV4LL_STATE_WAITING_ANNOUNCE,
- IPV4LL_STATE_ANNOUNCING,
- IPV4LL_STATE_RUNNING,
- IPV4LL_STATE_STOPPED,
- _IPV4LL_STATE_MAX,
- _IPV4LL_STATE_INVALID = -1
-} IPv4LLState;
+#define IPV4LL_DONT_DESTROY(ll) \
+ _cleanup_ipv4ll_unref_ _unused_ sd_ipv4ll *_dont_destroy_##ll = sd_ipv4ll_ref(ll)
struct sd_ipv4ll {
unsigned n_ref;
- IPv4LLState state;
- int index;
- int fd;
- union sockaddr_union link;
- int iteration;
- int conflict;
- sd_event_source *receive_message;
- sd_event_source *timer;
- usec_t next_wakeup;
- usec_t defend_window;
- int next_wakeup_valid;
- be32_t address;
+ sd_ipv4acd *acd;
+ be32_t address; /* the address pushed to ACD */
struct random_data *random_data;
char *random_data_state;
+
/* External */
be32_t claimed_address;
- struct ether_addr mac_addr;
- sd_event *event;
- int event_priority;
sd_ipv4ll_cb_t cb;
void* userdata;
};
-static void ipv4ll_run_state_machine(sd_ipv4ll *ll, IPv4LLTrigger trigger, void *trigger_data);
-
-static void ipv4ll_set_state(sd_ipv4ll *ll, IPv4LLState st, int reset_counter) {
-
- assert(ll);
- assert(st < _IPV4LL_STATE_MAX);
-
- if (st == ll->state && !reset_counter) {
- ll->iteration++;
- } else {
- ll->state = st;
- ll->iteration = 0;
- }
-}
-
-static sd_ipv4ll *ipv4ll_client_notify(sd_ipv4ll *ll, int event) {
- assert(ll);
-
- if (ll->cb) {
- ll = sd_ipv4ll_ref(ll);
- ll->cb(ll, event, ll->userdata);
- ll = sd_ipv4ll_unref(ll);
- }
-
- return ll;
-}
-
-static sd_ipv4ll *ipv4ll_stop(sd_ipv4ll *ll, int event) {
- assert(ll);
-
- ll->receive_message = sd_event_source_unref(ll->receive_message);
- ll->fd = safe_close(ll->fd);
-
- ll->timer = sd_event_source_unref(ll->timer);
-
- log_ipv4ll(ll, "STOPPED");
-
- ll = ipv4ll_client_notify(ll, event);
+sd_ipv4ll *sd_ipv4ll_ref(sd_ipv4ll *ll) {
+ if (!ll)
+ return NULL;
- if (ll) {
- ll->claimed_address = 0;
- ipv4ll_set_state (ll, IPV4LL_STATE_INIT, 1);
- }
+ assert(ll->n_ref >= 1);
+ ll->n_ref++;
return ll;
}
-static int ipv4ll_pick_address(sd_ipv4ll *ll, be32_t *address) {
- be32_t addr;
- int r;
- int32_t random;
-
- assert(ll);
- assert(address);
- assert(ll->random_data);
-
- do {
- r = random_r(ll->random_data, &random);
- if (r < 0)
- return r;
- addr = htonl((random & 0x0000FFFF) | IPV4LL_NETWORK);
- } while (addr == ll->address ||
- (ntohl(addr) & IPV4LL_NETMASK) != IPV4LL_NETWORK ||
- (ntohl(addr) & 0x0000FF00) == 0x0000 ||
- (ntohl(addr) & 0x0000FF00) == 0xFF00);
-
- *address = addr;
- return 0;
-}
-
-static int ipv4ll_timer(sd_event_source *s, uint64_t usec, void *userdata) {
- sd_ipv4ll *ll = (sd_ipv4ll*)userdata;
-
- assert(ll);
-
- ll->next_wakeup_valid = 0;
- ipv4ll_run_state_machine(ll, IPV4LL_TRIGGER_TIMEOUT, NULL);
-
- return 0;
-}
-
-static void ipv4ll_set_next_wakeup(sd_ipv4ll *ll, int sec, int random_sec) {
- usec_t next_timeout = 0;
- usec_t time_now = 0;
-
- assert(sec >= 0);
- assert(random_sec >= 0);
- assert(ll);
-
- next_timeout = sec * USEC_PER_SEC;
-
- if (random_sec)
- next_timeout += random_u32() % (random_sec * USEC_PER_SEC);
-
- assert_se(sd_event_now(ll->event, clock_boottime_or_monotonic(), &time_now) >= 0);
-
- ll->next_wakeup = time_now + next_timeout;
- ll->next_wakeup_valid = 1;
-}
-
-static bool ipv4ll_arp_conflict (sd_ipv4ll *ll, struct ether_arp *arp) {
- assert(ll);
- assert(arp);
-
- if (memcmp(arp->arp_spa, &ll->address, sizeof(ll->address)) == 0 &&
- memcmp(arp->arp_sha, &ll->mac_addr, ETH_ALEN) != 0)
- return true;
+sd_ipv4ll *sd_ipv4ll_unref(sd_ipv4ll *ll) {
+ if (!ll)
+ return NULL;
- return false;
-}
+ assert(ll->n_ref >= 1);
+ ll->n_ref--;
-static bool ipv4ll_arp_probe_conflict (sd_ipv4ll *ll, struct ether_arp *arp) {
- assert(ll);
- assert(arp);
+ if (ll->n_ref > 0)
+ return NULL;
- if (ipv4ll_arp_conflict(ll, arp))
- return true;
+ sd_ipv4acd_unref(ll->acd);
- if (memcmp(arp->arp_tpa, &ll->address, sizeof(ll->address)) == 0 &&
- memcmp(arp->arp_sha, &ll->mac_addr, ETH_ALEN))
- return true;
+ free(ll->random_data);
+ free(ll->random_data_state);
+ free(ll);
- return false;
+ return NULL;
}
-static void ipv4ll_run_state_machine(sd_ipv4ll *ll, IPv4LLTrigger trigger, void *trigger_data) {
- struct ether_arp out_packet;
- int out_packet_ready = 0;
- int r = 0;
-
- assert(ll);
- assert(trigger < _IPV4LL_TRIGGER_MAX);
-
- if (ll->state == IPV4LL_STATE_INIT) {
-
- log_ipv4ll(ll, "PROBE");
- ipv4ll_set_state(ll, IPV4LL_STATE_WAITING_PROBE, 1);
- ipv4ll_set_next_wakeup(ll, 0, PROBE_WAIT);
-
- } else if ((ll->state == IPV4LL_STATE_WAITING_PROBE && trigger == IPV4LL_TRIGGER_TIMEOUT) ||
- (ll->state == IPV4LL_STATE_PROBING && trigger == IPV4LL_TRIGGER_TIMEOUT && ll->iteration < PROBE_NUM-2)) {
-
- /* Send a probe */
- arp_packet_probe(&out_packet, ll->address, &ll->mac_addr);
- out_packet_ready = 1;
- ipv4ll_set_state(ll, IPV4LL_STATE_PROBING, 0);
-
- ipv4ll_set_next_wakeup(ll, PROBE_MIN, (PROBE_MAX-PROBE_MIN));
-
- } else if (ll->state == IPV4LL_STATE_PROBING && trigger == IPV4LL_TRIGGER_TIMEOUT && ll->iteration >= PROBE_NUM-2) {
-
- /* Send the last probe */
- arp_packet_probe(&out_packet, ll->address, &ll->mac_addr);
- out_packet_ready = 1;
- ipv4ll_set_state(ll, IPV4LL_STATE_WAITING_ANNOUNCE, 1);
-
- ipv4ll_set_next_wakeup(ll, ANNOUNCE_WAIT, 0);
-
- } else if ((ll->state == IPV4LL_STATE_WAITING_ANNOUNCE && trigger == IPV4LL_TRIGGER_TIMEOUT) ||
- (ll->state == IPV4LL_STATE_ANNOUNCING && trigger == IPV4LL_TRIGGER_TIMEOUT && ll->iteration < ANNOUNCE_NUM-1)) {
-
- /* Send announcement packet */
- arp_packet_announcement(&out_packet, ll->address, &ll->mac_addr);
- out_packet_ready = 1;
- ipv4ll_set_state(ll, IPV4LL_STATE_ANNOUNCING, 0);
-
- ipv4ll_set_next_wakeup(ll, ANNOUNCE_INTERVAL, 0);
-
- if (ll->iteration == 0) {
- log_ipv4ll(ll, "ANNOUNCE");
- ll->claimed_address = ll->address;
- ll = ipv4ll_client_notify(ll, IPV4LL_EVENT_BIND);
- if (!ll || ll->state == IPV4LL_STATE_STOPPED)
- goto out;
-
- ll->conflict = 0;
- }
-
- } else if ((ll->state == IPV4LL_STATE_ANNOUNCING && trigger == IPV4LL_TRIGGER_TIMEOUT &&
- ll->iteration >= ANNOUNCE_NUM-1)) {
-
- ipv4ll_set_state(ll, IPV4LL_STATE_RUNNING, 0);
- ll->next_wakeup_valid = 0;
-
- } else if (trigger == IPV4LL_TRIGGER_PACKET) {
-
- int conflicted = 0;
- usec_t time_now;
- struct ether_arp* in_packet = (struct ether_arp*)trigger_data;
-
- assert(in_packet);
-
- if (IN_SET(ll->state, IPV4LL_STATE_ANNOUNCING, IPV4LL_STATE_RUNNING)) {
-
- if (ipv4ll_arp_conflict(ll, in_packet)) {
-
- r = sd_event_now(ll->event, clock_boottime_or_monotonic(), &time_now);
- if (r < 0)
- goto out;
-
- /* Defend address */
- if (time_now > ll->defend_window) {
- ll->defend_window = time_now + DEFEND_INTERVAL * USEC_PER_SEC;
- arp_packet_announcement(&out_packet, ll->address, &ll->mac_addr);
- out_packet_ready = 1;
- } else
- conflicted = 1;
- }
-
- } else if (IN_SET(ll->state, IPV4LL_STATE_WAITING_PROBE,
- IPV4LL_STATE_PROBING,
- IPV4LL_STATE_WAITING_ANNOUNCE)) {
-
- conflicted = ipv4ll_arp_probe_conflict(ll, in_packet);
- }
-
- if (conflicted) {
- log_ipv4ll(ll, "CONFLICT");
- ll = ipv4ll_client_notify(ll, IPV4LL_EVENT_CONFLICT);
- if (!ll || ll->state == IPV4LL_STATE_STOPPED)
- goto out;
+DEFINE_TRIVIAL_CLEANUP_FUNC(sd_ipv4ll*, sd_ipv4ll_unref);
+#define _cleanup_ipv4ll_unref_ _cleanup_(sd_ipv4ll_unrefp)
- ll->claimed_address = 0;
+static void ipv4ll_on_acd(sd_ipv4acd *ll, int event, void *userdata);
- /* Pick a new address */
- r = ipv4ll_pick_address(ll, &ll->address);
- if (r < 0)
- goto out;
- ll->conflict++;
- ll->defend_window = 0;
- ipv4ll_set_state(ll, IPV4LL_STATE_WAITING_PROBE, 1);
+int sd_ipv4ll_new(sd_ipv4ll **ret) {
+ _cleanup_ipv4ll_unref_ sd_ipv4ll *ll = NULL;
+ int r;
- if (ll->conflict >= MAX_CONFLICTS) {
- log_ipv4ll(ll, "MAX_CONFLICTS");
- ipv4ll_set_next_wakeup(ll, RATE_LIMIT_INTERVAL, PROBE_WAIT);
- } else
- ipv4ll_set_next_wakeup(ll, 0, PROBE_WAIT);
+ assert_return(ret, -EINVAL);
- }
- }
+ ll = new0(sd_ipv4ll, 1);
+ if (!ll)
+ return -ENOMEM;
- if (out_packet_ready) {
- r = arp_network_send_raw_socket(ll->fd, &ll->link, &out_packet);
- if (r < 0) {
- log_ipv4ll(ll, "failed to send arp packet out");
- goto out;
- }
- }
+ r = sd_ipv4acd_new(&ll->acd);
+ if (r < 0)
+ return r;
- if (ll->next_wakeup_valid) {
- ll->timer = sd_event_source_unref(ll->timer);
- r = sd_event_add_time(ll->event, &ll->timer, clock_boottime_or_monotonic(),
- ll->next_wakeup, 0, ipv4ll_timer, ll);
- if (r < 0)
- goto out;
+ r = sd_ipv4acd_set_callback(ll->acd, ipv4ll_on_acd, ll);
+ if (r < 0)
+ return r;
- r = sd_event_source_set_priority(ll->timer, ll->event_priority);
- if (r < 0)
- goto out;
+ ll->n_ref = 1;
- r = sd_event_source_set_description(ll->timer, "ipv4ll-timer");
- if (r < 0)
- goto out;
- }
+ *ret = ll;
+ ll = NULL;
-out:
- if (r < 0 && ll)
- ipv4ll_stop(ll, r);
+ return 0;
}
-static int ipv4ll_receive_message(sd_event_source *s, int fd,
- uint32_t revents, void *userdata) {
+int sd_ipv4ll_stop(sd_ipv4ll *ll) {
int r;
- struct ether_arp arp;
- sd_ipv4ll *ll = (sd_ipv4ll*)userdata;
- assert(ll);
-
- r = read(fd, &arp, sizeof(struct ether_arp));
- if (r < (int) sizeof(struct ether_arp))
- return 0;
+ assert_return(ll, -EINVAL);
- r = arp_packet_verify_headers(&arp);
+ r = sd_ipv4acd_stop(ll->acd);
if (r < 0)
- return 0;
-
- ipv4ll_run_state_machine(ll, IPV4LL_TRIGGER_PACKET, &arp);
+ return r;
return 0;
}
int sd_ipv4ll_set_index(sd_ipv4ll *ll, int interface_index) {
assert_return(ll, -EINVAL);
- assert_return(interface_index > 0, -EINVAL);
- assert_return(IN_SET(ll->state, IPV4LL_STATE_INIT,
- IPV4LL_STATE_STOPPED), -EBUSY);
- ll->index = interface_index;
-
- return 0;
+ return sd_ipv4acd_set_index(ll->acd, interface_index);
}
+#define HASH_KEY SD_ID128_MAKE(df,04,22,98,3f,ad,14,52,f9,87,2e,d1,9c,70,e2,f2)
+
int sd_ipv4ll_set_mac(sd_ipv4ll *ll, const struct ether_addr *addr) {
- bool need_restart = false;
+ int r;
assert_return(ll, -EINVAL);
- assert_return(addr, -EINVAL);
-
- if (memcmp(&ll->mac_addr, addr, ETH_ALEN) == 0)
- return 0;
- if (!IN_SET(ll->state, IPV4LL_STATE_INIT, IPV4LL_STATE_STOPPED)) {
- log_ipv4ll(ll, "Changing MAC address on running IPv4LL "
- "client, restarting");
- ll = ipv4ll_stop(ll, IPV4LL_EVENT_STOP);
- need_restart = true;
- }
+ if (!ll->random_data) {
+ uint8_t seed[8];
- if (!ll)
- return 0;
+ /* If no random data is set, generate some from the MAC */
+ siphash24(seed, &addr->ether_addr_octet,
+ ETH_ALEN, HASH_KEY.bytes);
- memcpy(&ll->mac_addr, addr, ETH_ALEN);
+ assert_cc(sizeof(unsigned) <= 8);
- if (need_restart)
- sd_ipv4ll_start(ll);
+ r = sd_ipv4ll_set_address_seed(ll, *(unsigned*)seed);
+ if (r < 0)
+ return r;
+ }
- return 0;
+ return sd_ipv4acd_set_mac(ll->acd, addr);
}
int sd_ipv4ll_detach_event(sd_ipv4ll *ll) {
assert_return(ll, -EINVAL);
- ll->event = sd_event_unref(ll->event);
-
- return 0;
+ return sd_ipv4acd_detach_event(ll->acd);
}
int sd_ipv4ll_attach_event(sd_ipv4ll *ll, sd_event *event, int priority) {
int r;
assert_return(ll, -EINVAL);
- assert_return(!ll->event, -EBUSY);
-
- if (event)
- ll->event = sd_event_ref(event);
- else {
- r = sd_event_default(&ll->event);
- if (r < 0) {
- ipv4ll_stop(ll, IPV4LL_EVENT_STOP);
- return r;
- }
- }
- ll->event_priority = priority;
+ r = sd_ipv4acd_attach_event(ll->acd, event, priority);
+ if (r < 0)
+ return r;
return 0;
}
@@ -467,189 +192,147 @@ int sd_ipv4ll_get_address(sd_ipv4ll *ll, struct in_addr *address){
return -ENOENT;
address->s_addr = ll->claimed_address;
+
return 0;
}
-int sd_ipv4ll_set_address_seed (sd_ipv4ll *ll, uint8_t seed[8]) {
- unsigned int entropy;
+int sd_ipv4ll_set_address_seed(sd_ipv4ll *ll, unsigned seed) {
+ _cleanup_free_ struct random_data *random_data = NULL;
+ _cleanup_free_ char *random_data_state = NULL;
int r;
assert_return(ll, -EINVAL);
assert_return(seed, -EINVAL);
- entropy = *seed;
+ random_data = new0(struct random_data, 1);
+ if (!random_data)
+ return -ENOMEM;
- free(ll->random_data);
- free(ll->random_data_state);
+ random_data_state = new0(char, 128);
+ if (!random_data_state)
+ return -ENOMEM;
- ll->random_data = new0(struct random_data, 1);
- ll->random_data_state = new0(char, 128);
+ r = initstate_r(seed, random_data_state, 128, random_data);
+ if (r < 0)
+ return r;
- if (!ll->random_data || !ll->random_data_state) {
- r = -ENOMEM;
- goto error;
- }
+ free(ll->random_data);
+ ll->random_data = random_data;
+ random_data = NULL;
- r = initstate_r((unsigned int)entropy, ll->random_data_state, 128, ll->random_data);
- if (r < 0)
- goto error;
+ free(ll->random_data_state);
+ ll->random_data_state = random_data_state;
+ random_data_state = NULL;
-error:
- if (r < 0){
- free(ll->random_data);
- free(ll->random_data_state);
- ll->random_data = NULL;
- ll->random_data_state = NULL;
- }
- return r;
+ return 0;
}
bool sd_ipv4ll_is_running(sd_ipv4ll *ll) {
assert_return(ll, false);
- return !IN_SET(ll->state, IPV4LL_STATE_INIT, IPV4LL_STATE_STOPPED);
+ return sd_ipv4acd_is_running(ll->acd);
}
-#define HASH_KEY SD_ID128_MAKE(df,04,22,98,3f,ad,14,52,f9,87,2e,d1,9c,70,e2,f2)
-
-int sd_ipv4ll_start (sd_ipv4ll *ll) {
+static int ipv4ll_pick_address(sd_ipv4ll *ll) {
+ struct in_addr in_addr;
+ be32_t addr;
int r;
+ int32_t random;
- assert_return(ll, -EINVAL);
- assert_return(ll->event, -EINVAL);
- assert_return(ll->index > 0, -EINVAL);
- assert_return(IN_SET(ll->state, IPV4LL_STATE_INIT,
- IPV4LL_STATE_STOPPED), -EBUSY);
+ assert(ll);
+ assert(ll->random_data);
- ll->state = IPV4LL_STATE_INIT;
+ do {
+ r = random_r(ll->random_data, &random);
+ if (r < 0)
+ return r;
+ addr = htonl((random & 0x0000FFFF) | IPV4LL_NETWORK);
+ } while (addr == ll->address ||
+ (ntohl(addr) & IPV4LL_NETMASK) != IPV4LL_NETWORK ||
+ (ntohl(addr) & 0x0000FF00) == 0x0000 ||
+ (ntohl(addr) & 0x0000FF00) == 0xFF00);
- r = arp_network_bind_raw_socket(ll->index, &ll->link);
+ in_addr.s_addr = addr;
+ r = sd_ipv4acd_set_address(ll->acd, &in_addr);
if (r < 0)
- goto out;
+ return r;
- ll->fd = r;
- ll->conflict = 0;
- ll->defend_window = 0;
- ll->claimed_address = 0;
+ ll->address = addr;
- if (!ll->random_data) {
- uint8_t seed[8];
+ return 0;
+}
- /* Fallback to mac */
- siphash24(seed, &ll->mac_addr.ether_addr_octet,
- ETH_ALEN, HASH_KEY.bytes);
+int sd_ipv4ll_start(sd_ipv4ll *ll) {
+ int r;
- r = sd_ipv4ll_set_address_seed(ll, seed);
- if (r < 0)
- goto out;
- }
+ assert_return(ll, -EINVAL);
+ assert_return(ll->random_data, -EINVAL);
if (ll->address == 0) {
- r = ipv4ll_pick_address(ll, &ll->address);
+ r = ipv4ll_pick_address(ll);
if (r < 0)
- goto out;
+ return r;
}
- ipv4ll_set_state (ll, IPV4LL_STATE_INIT, 1);
-
- r = sd_event_add_io(ll->event, &ll->receive_message, ll->fd,
- EPOLLIN, ipv4ll_receive_message, ll);
+ r = sd_ipv4acd_start(ll->acd);
if (r < 0)
- goto out;
-
- r = sd_event_source_set_priority(ll->receive_message, ll->event_priority);
- if (r < 0)
- goto out;
-
- r = sd_event_source_set_description(ll->receive_message, "ipv4ll-receive-message");
- if (r < 0)
- goto out;
-
- r = sd_event_add_time(ll->event,
- &ll->timer,
- clock_boottime_or_monotonic(),
- now(clock_boottime_or_monotonic()), 0,
- ipv4ll_timer, ll);
-
- if (r < 0)
- goto out;
-
- r = sd_event_source_set_priority(ll->timer, ll->event_priority);
- if (r < 0)
- goto out;
-
- r = sd_event_source_set_description(ll->timer, "ipv4ll-timer");
-out:
- if (r < 0)
- ipv4ll_stop(ll, IPV4LL_EVENT_STOP);
+ return r;
return 0;
}
-int sd_ipv4ll_stop(sd_ipv4ll *ll) {
- ipv4ll_stop(ll, IPV4LL_EVENT_STOP);
- if (ll)
- ipv4ll_set_state(ll, IPV4LL_STATE_STOPPED, 1);
-
- return 0;
-}
-
-sd_ipv4ll *sd_ipv4ll_ref(sd_ipv4ll *ll) {
-
- if (!ll)
- return NULL;
-
- assert(ll->n_ref >= 1);
- ll->n_ref++;
+static void ipv4ll_client_notify(sd_ipv4ll *ll, int event) {
+ assert(ll);
- return ll;
+ if (ll->cb)
+ ll->cb(ll, event, ll->userdata);
}
-sd_ipv4ll *sd_ipv4ll_unref(sd_ipv4ll *ll) {
-
- if (!ll)
- return NULL;
-
- assert(ll->n_ref >= 1);
- ll->n_ref--;
-
- if (ll->n_ref > 0)
- return ll;
-
- ll->receive_message = sd_event_source_unref(ll->receive_message);
- ll->fd = safe_close(ll->fd);
-
- ll->timer = sd_event_source_unref(ll->timer);
+void ipv4ll_on_acd(sd_ipv4acd *acd, int event, void *userdata) {
+ sd_ipv4ll *ll = userdata;
+ IPV4LL_DONT_DESTROY(ll);
+ int r;
- sd_ipv4ll_detach_event(ll);
+ assert(acd);
+ assert(ll);
- free(ll->random_data);
- free(ll->random_data_state);
- free(ll);
+ switch (event) {
+ case IPV4ACD_EVENT_STOP:
+ ipv4ll_client_notify(ll, IPV4LL_EVENT_STOP);
- return NULL;
-}
+ ll->claimed_address = 0;
-DEFINE_TRIVIAL_CLEANUP_FUNC(sd_ipv4ll*, sd_ipv4ll_unref);
-#define _cleanup_ipv4ll_free_ _cleanup_(sd_ipv4ll_unrefp)
+ break;
+ case IPV4ACD_EVENT_BIND:
+ ll->claimed_address = ll->address;
+ ipv4ll_client_notify(ll, IPV4LL_EVENT_BIND);
-int sd_ipv4ll_new(sd_ipv4ll **ret) {
- _cleanup_ipv4ll_free_ sd_ipv4ll *ll = NULL;
+ break;
+ case IPV4ACD_EVENT_CONFLICT:
+ /* if an address was already bound we must call up to the
+ user to handle this, otherwise we just try again */
+ if (ll->claimed_address != 0) {
+ ipv4ll_client_notify(ll, IPV4LL_EVENT_CONFLICT);
- assert_return(ret, -EINVAL);
+ ll->claimed_address = 0;
+ } else {
+ r = ipv4ll_pick_address(ll);
+ if (r < 0)
+ goto error;
- ll = new0(sd_ipv4ll, 1);
- if (!ll)
- return -ENOMEM;
+ r = sd_ipv4acd_start(ll->acd);
+ if (r < 0)
+ goto error;
+ }
- ll->n_ref = 1;
- ll->state = IPV4LL_STATE_INIT;
- ll->index = -1;
- ll->fd = -1;
+ break;
+ default:
+ assert_not_reached("Invalid IPv4ACD event.");
+ }
- *ret = ll;
- ll = NULL;
+ return;
- return 0;
+error:
+ ipv4ll_client_notify(ll, IPV4LL_EVENT_STOP);
}
diff --git a/src/libsystemd-network/test-acd.c b/src/libsystemd-network/test-acd.c
new file mode 100644
index 0000000000..f1f14ee119
--- /dev/null
+++ b/src/libsystemd-network/test-acd.c
@@ -0,0 +1,117 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+ This file is part of systemd.
+
+ Copyright (C) 2014 Tom Gundersen <teg@jklm.no>
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+
+#include <linux/veth.h>
+#include <net/if.h>
+
+#include "sd-event.h"
+#include "sd-netlink.h"
+#include "sd-ipv4acd.h"
+
+#include "util.h"
+#include "event-util.h"
+#include "netlink-util.h"
+#include "in-addr-util.h"
+
+static void acd_handler(sd_ipv4acd *acd, int event, void *userdata) {
+ assert_se(acd);
+
+ switch (event) {
+ case IPV4ACD_EVENT_BIND:
+ log_info("bound");
+ break;
+ case IPV4ACD_EVENT_CONFLICT:
+ log_info("conflict");
+ break;
+ case IPV4ACD_EVENT_STOP:
+ log_error("the client was stopped");
+ break;
+ default:
+ assert_not_reached("invalid ACD event");
+ }
+}
+
+static int client_run(int ifindex, const struct in_addr *pa, const struct ether_addr *ha, sd_event *e) {
+ sd_ipv4acd *acd;
+
+ assert_se(sd_ipv4acd_new(&acd) >= 0);
+ assert_se(sd_ipv4acd_attach_event(acd, e, 0) >= 0);
+
+ assert_se(sd_ipv4acd_set_index(acd, ifindex) >= 0);
+ assert_se(sd_ipv4acd_set_mac(acd, ha) >= 0);
+ assert_se(sd_ipv4acd_set_address(acd, pa) >= 0);
+ assert_se(sd_ipv4acd_set_callback(acd, acd_handler, NULL) >= 0);
+
+ log_info("starting IPv4ACD client");
+
+ assert_se(sd_ipv4acd_start(acd) >= 0);
+
+ assert_se(sd_event_loop(e) >= 0);
+
+ assert_se(!sd_ipv4acd_unref(acd));
+
+ return EXIT_SUCCESS;
+}
+
+static int test_acd(const char *ifname, const char *address) {
+ _cleanup_event_unref_ sd_event *e = NULL;
+ _cleanup_netlink_unref_ sd_netlink *rtnl = NULL;
+ _cleanup_netlink_message_unref_ sd_netlink_message *m = NULL, *reply = NULL;
+ union in_addr_union pa;
+ struct ether_addr ha;
+ int ifindex;
+
+ assert_se(in_addr_from_string(AF_INET, address, &pa) >= 0);
+
+ assert_se(sd_event_new(&e) >= 0);
+
+ assert_se(sd_netlink_open(&rtnl) >= 0);
+ assert_se(sd_netlink_attach_event(rtnl, e, 0) >= 0);
+
+ assert_se(sd_rtnl_message_new_link(rtnl, &m, RTM_GETLINK, 0) >= 0);
+ assert_se(sd_netlink_message_append_string(m, IFLA_IFNAME, ifname) >= 0);
+ assert_se(sd_netlink_call(rtnl, m, 0, &reply) >= 0);
+
+ assert_se(sd_rtnl_message_link_get_ifindex(reply, &ifindex) >= 0);
+ assert_se(sd_netlink_message_read_ether_addr(reply, IFLA_ADDRESS, &ha) >= 0);
+
+ client_run(ifindex, &pa.in, &ha, e);
+
+ return EXIT_SUCCESS;
+}
+
+int main(int argc, char *argv[]) {
+ log_set_max_level(LOG_DEBUG);
+ log_parse_environment();
+ log_open();
+
+ if (argc == 3)
+ return test_acd(argv[1], argv[2]);
+ else {
+ log_error("This program takes two arguments.\n"
+ "\t %s <ifname> <IPv4 address>", program_invocation_short_name);
+ return EXIT_FAILURE;
+ }
+}
diff --git a/src/libsystemd-network/test-ipv4ll-manual.c b/src/libsystemd-network/test-ipv4ll-manual.c
new file mode 100644
index 0000000000..ad664cba51
--- /dev/null
+++ b/src/libsystemd-network/test-ipv4ll-manual.c
@@ -0,0 +1,129 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+ This file is part of systemd.
+
+ Copyright (C) 2014 Tom Gundersen <teg@jklm.no>
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+
+#include <linux/veth.h>
+#include <net/if.h>
+
+#include "sd-event.h"
+#include "sd-netlink.h"
+#include "sd-ipv4ll.h"
+
+#include "util.h"
+#include "event-util.h"
+#include "netlink-util.h"
+#include "in-addr-util.h"
+
+static void ll_handler(sd_ipv4ll *ll, int event, void *userdata) {
+ _cleanup_free_ char *address = NULL;
+ struct in_addr addr = {};
+
+ assert_se(ll);
+
+ if (sd_ipv4ll_get_address(ll, &addr) >= 0)
+ assert_se(in_addr_to_string(AF_INET, (const union in_addr_union*) &addr, &address) >= 0);
+
+ switch (event) {
+ case IPV4LL_EVENT_BIND:
+ log_info("bound %s", strna(address));
+ break;
+ case IPV4LL_EVENT_CONFLICT:
+ log_info("conflict on %s", strna(address));
+ break;
+ case IPV4LL_EVENT_STOP:
+ log_error("the client was stopped with address %s", strna(address));
+ break;
+ default:
+ assert_not_reached("invalid LL event");
+ }
+}
+
+static int client_run(int ifindex, const char *seed_str, const struct ether_addr *ha, sd_event *e) {
+ sd_ipv4ll *ll;
+
+ assert_se(sd_ipv4ll_new(&ll) >= 0);
+ assert_se(sd_ipv4ll_attach_event(ll, e, 0) >= 0);
+
+ assert_se(sd_ipv4ll_set_index(ll, ifindex) >= 0);
+ assert_se(sd_ipv4ll_set_mac(ll, ha) >= 0);
+ assert_se(sd_ipv4ll_set_callback(ll, ll_handler, NULL) >= 0);
+
+ if (seed_str) {
+ unsigned seed;
+
+ assert_se(safe_atou(seed_str, &seed) >= 0);
+
+ assert_se(sd_ipv4ll_set_address_seed(ll, seed) >= 0);
+ }
+
+ log_info("starting IPv4LL client");
+
+ assert_se(sd_ipv4ll_start(ll) >= 0);
+
+ assert_se(sd_event_loop(e) >= 0);
+
+ assert_se(!sd_ipv4ll_unref(ll));
+
+ return EXIT_SUCCESS;
+}
+
+static int test_ll(const char *ifname, const char *seed) {
+ _cleanup_event_unref_ sd_event *e = NULL;
+ _cleanup_netlink_unref_ sd_netlink *rtnl = NULL;
+ _cleanup_netlink_message_unref_ sd_netlink_message *m = NULL, *reply = NULL;
+ struct ether_addr ha;
+ int ifindex;
+
+ assert_se(sd_event_new(&e) >= 0);
+
+ assert_se(sd_netlink_open(&rtnl) >= 0);
+ assert_se(sd_netlink_attach_event(rtnl, e, 0) >= 0);
+
+ assert_se(sd_rtnl_message_new_link(rtnl, &m, RTM_GETLINK, 0) >= 0);
+ assert_se(sd_netlink_message_append_string(m, IFLA_IFNAME, ifname) >= 0);
+ assert_se(sd_netlink_call(rtnl, m, 0, &reply) >= 0);
+
+ assert_se(sd_rtnl_message_link_get_ifindex(reply, &ifindex) >= 0);
+ assert_se(sd_netlink_message_read_ether_addr(reply, IFLA_ADDRESS, &ha) >= 0);
+
+ client_run(ifindex, seed, &ha, e);
+
+ return EXIT_SUCCESS;
+}
+
+int main(int argc, char *argv[]) {
+ log_set_max_level(LOG_DEBUG);
+ log_parse_environment();
+ log_open();
+
+ if (argc == 2)
+ return test_ll(argv[1], NULL);
+ else if (argc == 3)
+ return test_ll(argv[1], argv[2]);
+ else {
+ log_error("This program takes one or two arguments.\n"
+ "\t %s <ifname> [<seed>]", program_invocation_short_name);
+ return EXIT_FAILURE;
+ }
+}
diff --git a/src/libsystemd-network/test-ipv4ll.c b/src/libsystemd-network/test-ipv4ll.c
index d60ee98b25..f0e26bda07 100644
--- a/src/libsystemd-network/test-ipv4ll.c
+++ b/src/libsystemd-network/test-ipv4ll.c
@@ -31,7 +31,7 @@
#include "event-util.h"
#include "sd-ipv4ll.h"
-#include "ipv4ll-internal.h"
+#include "arp-util.h"
static bool verbose = false;
static bool extended = false;
@@ -56,10 +56,10 @@ static void basic_request_handler(sd_ipv4ll *ll, int event, void *userdata) {
}
}
-int arp_network_send_raw_socket(int fd, const union sockaddr_union *link,
- const struct ether_arp *arp) {
+static int arp_network_send_raw_socket(int fd, int ifindex,
+ const struct ether_arp *arp) {
assert_se(arp);
- assert_se(link);
+ assert_se(ifindex > 0);
assert_se(fd >= 0);
if (send(fd, arp, sizeof(struct ether_arp), 0) < 0)
@@ -68,51 +68,35 @@ int arp_network_send_raw_socket(int fd, const union sockaddr_union *link,
return 0;
}
-int arp_network_bind_raw_socket(int index, union sockaddr_union *link) {
- if (socketpair(AF_UNIX, SOCK_DGRAM | SOCK_NONBLOCK, 0, test_fd) < 0)
- return -errno;
+int arp_send_probe(int fd, int ifindex,
+ be32_t pa, const struct ether_addr *ha) {
+ struct ether_arp ea = {};
- return test_fd[0];
-}
+ assert(fd >= 0);
+ assert(ifindex > 0);
+ assert(pa != 0);
+ assert(ha);
-static void test_arp_header(struct ether_arp *arp) {
- assert_se(arp);
- assert_se(arp->ea_hdr.ar_hrd == htons(ARPHRD_ETHER)); /* HTYPE */
- assert_se(arp->ea_hdr.ar_pro == htons(ETHERTYPE_IP)); /* PTYPE */
- assert_se(arp->ea_hdr.ar_hln == ETH_ALEN); /* HLEN */
- assert_se(arp->ea_hdr.ar_pln == sizeof arp->arp_spa); /* PLEN */
- assert_se(arp->ea_hdr.ar_op == htons(ARPOP_REQUEST)); /* REQUEST */
+ return arp_network_send_raw_socket(fd, ifindex, &ea);
}
-static void test_arp_probe(void) {
- struct ether_arp arp;
- struct ether_addr mac_addr = {
- .ether_addr_octet = {'A', 'B', 'C', '1', '2', '3'}};
- be32_t pa = 0x3030;
+int arp_send_announcement(int fd, int ifindex,
+ be32_t pa, const struct ether_addr *ha) {
+ struct ether_arp ea = {};
- if (verbose)
- printf("* %s\n", __FUNCTION__);
+ assert(fd >= 0);
+ assert(ifindex > 0);
+ assert(pa != 0);
+ assert(ha);
- arp_packet_probe(&arp, pa, &mac_addr);
- test_arp_header(&arp);
- assert_se(memcmp(arp.arp_sha, &mac_addr, ETH_ALEN) == 0);
- assert_se(memcmp(arp.arp_tpa, &pa, sizeof(pa)) == 0);
+ return arp_network_send_raw_socket(fd, ifindex, &ea);
}
-static void test_arp_announce(void) {
- struct ether_arp arp;
- struct ether_addr mac_addr = {
- .ether_addr_octet = {'A', 'B', 'C', '1', '2', '3'}};
- be32_t pa = 0x3131;
-
- if (verbose)
- printf("* %s\n", __FUNCTION__);
+int arp_network_bind_raw_socket(int index, be32_t address, const struct ether_addr *eth_mac) {
+ if (socketpair(AF_UNIX, SOCK_DGRAM | SOCK_NONBLOCK, 0, test_fd) < 0)
+ return -errno;
- arp_packet_announcement(&arp, pa, &mac_addr);
- test_arp_header(&arp);
- assert_se(memcmp(arp.arp_sha, &mac_addr, ETH_ALEN) == 0);
- assert_se(memcmp(arp.arp_tpa, &pa, sizeof(pa)) == 0);
- assert_se(memcmp(arp.arp_spa, &pa, sizeof(pa)) == 0);
+ return test_fd[0];
}
static void test_public_api_setters(sd_event *e) {
@@ -134,9 +118,8 @@ static void test_public_api_setters(sd_event *e) {
assert_se(sd_ipv4ll_set_callback(NULL, NULL, NULL) == -EINVAL);
assert_se(sd_ipv4ll_set_callback(ll, NULL, NULL) == 0);
- assert_se(sd_ipv4ll_set_address_seed(NULL, NULL) == -EINVAL);
- assert_se(sd_ipv4ll_set_address_seed(ll, NULL) == -EINVAL);
- assert_se(sd_ipv4ll_set_address_seed(ll, seed) == 0);
+ assert_se(sd_ipv4ll_set_address_seed(NULL, *(unsigned *) seed) == -EINVAL);
+ assert_se(sd_ipv4ll_set_address_seed(ll, *(unsigned *) seed) == 0);
assert_se(sd_ipv4ll_set_mac(NULL, NULL) == -EINVAL);
assert_se(sd_ipv4ll_set_mac(ll, NULL) == -EINVAL);
@@ -149,7 +132,7 @@ static void test_public_api_setters(sd_event *e) {
assert_se(sd_ipv4ll_set_index(ll, 99) == 0);
assert_se(sd_ipv4ll_ref(ll) == ll);
- assert_se(sd_ipv4ll_unref(ll) == ll);
+ assert_se(sd_ipv4ll_unref(ll) == NULL);
/* Cleanup */
assert_se(sd_ipv4ll_unref(ll) == NULL);
@@ -184,21 +167,20 @@ static void test_basic_request(sd_event *e) {
sd_event_run(e, (uint64_t) -1);
assert_se(sd_ipv4ll_start(ll) == -EBUSY);
+ assert_se(sd_ipv4ll_is_running(ll));
+
/* PROBE */
sd_event_run(e, (uint64_t) -1);
assert_se(read(test_fd[1], &arp, sizeof(struct ether_arp)) == sizeof(struct ether_arp));
- test_arp_header(&arp);
if (extended) {
/* PROBE */
sd_event_run(e, (uint64_t) -1);
assert_se(read(test_fd[1], &arp, sizeof(struct ether_arp)) == sizeof(struct ether_arp));
- test_arp_header(&arp);
/* PROBE */
sd_event_run(e, (uint64_t) -1);
assert_se(read(test_fd[1], &arp, sizeof(struct ether_arp)) == sizeof(struct ether_arp));
- test_arp_header(&arp);
sd_event_run(e, (uint64_t) -1);
assert_se(basic_request_handler_bind == 1);
@@ -215,11 +197,13 @@ static void test_basic_request(sd_event *e) {
int main(int argc, char *argv[]) {
_cleanup_event_unref_ sd_event *e = NULL;
+ log_set_max_level(LOG_DEBUG);
+ log_parse_environment();
+ log_open();
+
assert_se(sd_event_new(&e) >= 0);
test_public_api_setters(e);
- test_arp_probe();
- test_arp_announce();
test_basic_request(e);
return 0;
diff --git a/src/network/networkd-ipv4ll.c b/src/network/networkd-ipv4ll.c
index 0a27a30278..1c34f55b4b 100644
--- a/src/network/networkd-ipv4ll.c
+++ b/src/network/networkd-ipv4ll.c
@@ -195,10 +195,7 @@ static void ipv4ll_handler(sd_ipv4ll *ll, int event, void *userdata){
}
break;
default:
- if (event < 0)
- log_link_warning(link, "IPv4 link-local error: %s", strerror(-event));
- else
- log_link_warning(link, "IPv4 link-local unknown event: %d", event);
+ log_link_warning(link, "IPv4 link-local unknown event: %d", event);
break;
}
}
@@ -218,7 +215,9 @@ int ipv4ll_configure(Link *link) {
if (link->udev_device) {
r = net_get_unique_predictable_data(link->udev_device, seed);
if (r >= 0) {
- r = sd_ipv4ll_set_address_seed(link->ipv4ll, seed);
+ assert_cc(sizeof(unsigned) <= 8);
+
+ r = sd_ipv4ll_set_address_seed(link->ipv4ll, *(unsigned *)seed);
if (r < 0)
return r;
}
diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c
index d21ba9a566..e20fc1bbbb 100644
--- a/src/systemctl/systemctl.c
+++ b/src/systemctl/systemctl.c
@@ -3005,6 +3005,7 @@ static int prepare_firmware_setup(sd_bus *bus) {
}
static int start_special(sd_bus *bus, char **args) {
+ _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
enum action a;
int r;
@@ -3029,6 +3030,31 @@ static int start_special(sd_bus *bus, char **args) {
r = update_reboot_param_file(args[1]);
if (r < 0)
return r;
+ } else if (a == ACTION_EXIT && strv_length(args) > 1) {
+ /* If the exit code is not given on the command line, don't
+ * reset it to zero: just keep it as it might have been set
+ * previously. */
+ uint8_t code = 0;
+
+ r = safe_atou8(args[1], &code);
+ if (r < 0) {
+ log_error("Invalid exit code.");
+ return -EINVAL;
+ }
+
+ r = sd_bus_call_method(
+ bus,
+ "org.freedesktop.systemd1",
+ "/org/freedesktop/systemd1",
+ "org.freedesktop.systemd1.Manager",
+ "SetExitCode",
+ &error,
+ NULL,
+ "y", code);
+ if (r < 0) {
+ log_error("Failed to execute operation: %s", bus_error_message(&error, r));
+ return r;
+ }
}
if (arg_force >= 2 &&
@@ -3107,7 +3133,7 @@ static int check_unit_failed(sd_bus *bus, char **args) {
static int kill_unit(sd_bus *bus, char **args) {
_cleanup_strv_free_ char **names = NULL;
- char **name;
+ char *kill_who = NULL, **name;
int r, q;
assert(bus);
@@ -3118,6 +3144,10 @@ static int kill_unit(sd_bus *bus, char **args) {
if (!arg_kill_who)
arg_kill_who = "all";
+ /* --fail was specified */
+ if (streq(arg_job_mode, "fail"))
+ kill_who = strjoina(arg_kill_who, "-fail", NULL);
+
r = expand_names(bus, args + 1, NULL, &names);
if (r < 0)
log_error_errno(r, "Failed to expand names: %m");
@@ -3133,7 +3163,7 @@ static int kill_unit(sd_bus *bus, char **args) {
"KillUnit",
&error,
NULL,
- "ssi", *names, arg_kill_who, arg_signal);
+ "ssi", *names, kill_who ? kill_who : arg_kill_who, arg_signal);
if (q < 0) {
log_error("Failed to kill unit %s: %s", *names, bus_error_message(&error, q));
if (r == 0)
@@ -6220,7 +6250,7 @@ static void systemctl_help(void) {
" poweroff Shut down and power-off the system\n"
" reboot [ARG] Shut down and reboot the system\n"
" kexec Shut down and reboot the system with kexec\n"
- " exit Request user instance exit\n"
+ " exit [EXIT_CODE] Request user instance or container exit\n"
" switch-root ROOT [INIT] Change to a different root file system\n"
" suspend Suspend the system\n"
" hibernate Hibernate the system\n"
@@ -7207,7 +7237,7 @@ static int systemctl_main(sd_bus *bus, int argc, char *argv[], int bus_error) {
{ "default", EQUAL, 1, start_special },
{ "rescue", EQUAL, 1, start_special },
{ "emergency", EQUAL, 1, start_special },
- { "exit", EQUAL, 1, start_special },
+ { "exit", LESS, 2, start_special },
{ "reset-failed", MORE, 1, reset_failed },
{ "enable", MORE, 2, enable_unit, NOBUS },
{ "disable", MORE, 2, enable_unit, NOBUS },
diff --git a/src/systemd/sd-ipv4acd.h b/src/systemd/sd-ipv4acd.h
new file mode 100644
index 0000000000..8844ae848d
--- /dev/null
+++ b/src/systemd/sd-ipv4acd.h
@@ -0,0 +1,55 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#ifndef foosdipv4acdfoo
+#define foosdipv4acdfoo
+
+/***
+ This file is part of systemd.
+
+ Copyright (C) 2014 Axis Communications AB. All rights reserved.
+ Copyright (C) 2015 Tom Gundersen
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <stdbool.h>
+#include <netinet/in.h>
+#include <net/ethernet.h>
+
+#include "sd-event.h"
+
+enum {
+ IPV4ACD_EVENT_STOP = 0,
+ IPV4ACD_EVENT_BIND = 1,
+ IPV4ACD_EVENT_CONFLICT = 2,
+};
+
+typedef struct sd_ipv4acd sd_ipv4acd;
+typedef void (*sd_ipv4acd_cb_t)(sd_ipv4acd *ll, int event, void *userdata);
+
+int sd_ipv4acd_detach_event(sd_ipv4acd *ll);
+int sd_ipv4acd_attach_event(sd_ipv4acd *ll, sd_event *event, int priority);
+int sd_ipv4acd_get_address(sd_ipv4acd *ll, struct in_addr *address);
+int sd_ipv4acd_set_callback(sd_ipv4acd *ll, sd_ipv4acd_cb_t cb, void *userdata);
+int sd_ipv4acd_set_mac(sd_ipv4acd *ll, const struct ether_addr *addr);
+int sd_ipv4acd_set_index(sd_ipv4acd *ll, int interface_index);
+int sd_ipv4acd_set_address(sd_ipv4acd *ll, const struct in_addr *address);
+bool sd_ipv4acd_is_running(sd_ipv4acd *ll);
+int sd_ipv4acd_start(sd_ipv4acd *ll);
+int sd_ipv4acd_stop(sd_ipv4acd *ll);
+sd_ipv4acd *sd_ipv4acd_ref(sd_ipv4acd *ll);
+sd_ipv4acd *sd_ipv4acd_unref(sd_ipv4acd *ll);
+int sd_ipv4acd_new (sd_ipv4acd **ret);
+
+#endif
diff --git a/src/systemd/sd-ipv4ll.h b/src/systemd/sd-ipv4ll.h
index d017158154..9581e99d31 100644
--- a/src/systemd/sd-ipv4ll.h
+++ b/src/systemd/sd-ipv4ll.h
@@ -43,7 +43,7 @@ int sd_ipv4ll_get_address(sd_ipv4ll *ll, struct in_addr *address);
int sd_ipv4ll_set_callback(sd_ipv4ll *ll, sd_ipv4ll_cb_t cb, void *userdata);
int sd_ipv4ll_set_mac(sd_ipv4ll *ll, const struct ether_addr *addr);
int sd_ipv4ll_set_index(sd_ipv4ll *ll, int interface_index);
-int sd_ipv4ll_set_address_seed(sd_ipv4ll *ll, uint8_t seed[8]);
+int sd_ipv4ll_set_address_seed(sd_ipv4ll *ll, unsigned seed);
bool sd_ipv4ll_is_running(sd_ipv4ll *ll);
int sd_ipv4ll_start(sd_ipv4ll *ll);
int sd_ipv4ll_stop(sd_ipv4ll *ll);
diff --git a/units/.gitignore b/units/.gitignore
index d45492d06b..049371884a 100644
--- a/units/.gitignore
+++ b/units/.gitignore
@@ -30,6 +30,7 @@
/systemd-fsck@.service
/systemd-machine-id-commit.service
/systemd-halt.service
+/systemd-exit.service
/systemd-hibernate.service
/systemd-hostnamed.service
/systemd-hybrid-sleep.service
diff --git a/units/exit.target b/units/exit.target
new file mode 100644
index 0000000000..f5f953d112
--- /dev/null
+++ b/units/exit.target
@@ -0,0 +1,17 @@
+# This file is part of systemd.
+#
+# systemd is free software; you can redistribute it and/or modify it
+# under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation; either version 2.1 of the License, or
+# (at your option) any later version.
+
+[Unit]
+Description=Exit the container
+Documentation=man:systemd.special(7)
+DefaultDependencies=no
+Requires=systemd-exit.service
+After=systemd-exit.service
+AllowIsolate=yes
+
+[Install]
+Alias=ctrl-alt-del.target
diff --git a/units/systemd-exit.service.in b/units/systemd-exit.service.in
new file mode 100644
index 0000000000..2dbfb36b41
--- /dev/null
+++ b/units/systemd-exit.service.in
@@ -0,0 +1,17 @@
+# This file is part of systemd.
+#
+# systemd is free software; you can redistribute it and/or modify it
+# under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation; either version 2.1 of the License, or
+# (at your option) any later version.
+
+[Unit]
+Description=Exit the Session
+Documentation=man:systemd.special(7)
+DefaultDependencies=no
+Requires=shutdown.target
+After=shutdown.target
+
+[Service]
+Type=oneshot
+ExecStart=@SYSTEMCTL@ --force exit