diff --git a/repos/dde_linux/lib/mk/spec/arm_64/wireguard.mk b/repos/dde_linux/lib/mk/spec/arm_64/wireguard.mk
new file mode 100644
index 0000000000..5becda2d3f
--- /dev/null
+++ b/repos/dde_linux/lib/mk/spec/arm_64/wireguard.mk
@@ -0,0 +1,23 @@
+#
+# For documentation see $(REP_DIR)/lib/mk/wireguard.inc .
+#
+
+PRG_DIR := $(REP_DIR)/src/app/wireguard/spec/arm_64
+GEN_PRG_DIR := $(PRG_DIR)/../..
+
+SRC_C += arch/arm64/kernel/smp.c
+SRC_C += kernel/smp.c
+SRC_C += arch/arm64/kernel/cpufeature.c
+
+vpath arch/arm64/kernel/cpufeature.c $(GEN_PRG_DIR)/lx_emul/shadow
+vpath arch/arm64/kernel/smp.c $(REP_DIR)/src/lib/lx_emul/shadow
+vpath kernel/smp.c $(REP_DIR)/src/lib/lx_emul/shadow
+
+SRC_S += arch/arm64/crypto/poly1305-core.S
+
+arch/arm64/crypto/poly1305-core.S:
+ $(VERBOSE)perl $(LX_SRC_DIR)/arch/arm64/crypto/poly1305-armv8.pl > $@
+
+CC_OPT_arch/arm64/crypto/poly1305-core += -Dpoly1305_init=poly1305_init_arm64
+
+include $(REP_DIR)/lib/mk/wireguard.inc
diff --git a/repos/dde_linux/lib/mk/spec/x86_64/wireguard.mk b/repos/dde_linux/lib/mk/spec/x86_64/wireguard.mk
new file mode 100644
index 0000000000..e51e4e805b
--- /dev/null
+++ b/repos/dde_linux/lib/mk/spec/x86_64/wireguard.mk
@@ -0,0 +1,12 @@
+#
+# For documentation see $(REP_DIR)/lib/mk/wireguard.inc .
+#
+
+PRG_DIR := $(REP_DIR)/src/app/wireguard/spec/x86_64
+
+SRC_S += arch/x86/crypto/poly1305-x86_64-cryptogams.S
+
+arch/x86/crypto/poly1305-x86_64-cryptogams.S:
+ perl $(LX_SRC_DIR)/arch/x86/crypto/poly1305-x86_64-cryptogams.pl > $@
+
+include $(REP_DIR)/lib/mk/wireguard.inc
diff --git a/repos/dde_linux/lib/mk/wireguard.inc b/repos/dde_linux/lib/mk/wireguard.inc
new file mode 100644
index 0000000000..da0af3d3ce
--- /dev/null
+++ b/repos/dde_linux/lib/mk/wireguard.inc
@@ -0,0 +1,61 @@
+#
+# This library is for avoiding clashes between Linux and Genode includes.
+# If we were to compile all the *.c files of this library directly with the
+# Wireguard target there would be only one INC_DIR applied to *.cc files as
+# well as to *.c files. Some Genode headers, however (e.g. 'net/udp.h' or
+# 'net/dhcp.h') exist with the same include identifier in both Linux and
+# Genode, and we would have the problem that we want the Linux variant in *.c
+# files and the Genode variant in *.cc files. Therefore, we create two
+# dedicated INC_DIR settings (that of the library and that of the target).
+#
+
+GEN_PRG_DIR := $(PRG_DIR)/../..
+
+SRC_C += $(notdir $(wildcard $(PRG_DIR)/generated_dummies.c))
+SRC_C += dummies.c
+SRC_C += dummies_arch.c
+SRC_C += lx_emul.c
+SRC_C += wireguard.c
+SRC_C += genode_c_api_arch.c
+
+vpath lx_emul/alloc.cc $(GEN_PRG_DIR)
+vpath lx_kit/memory.cc $(GEN_PRG_DIR)
+vpath wireguard.c $(GEN_PRG_DIR)/genode_c_api
+vpath %.c $(PRG_DIR)
+vpath %.c $(GEN_PRG_DIR)
+
+INC_DIR += $(PRG_DIR)
+INC_DIR += $(GEN_PRG_DIR)
+
+LIBS += lx_emul virt_linux_generated
+
+CC_OPT_wireguard += -DKBUILD_MODFILE='"wireguard"' \
+ -DKBUILD_BASENAME='"wireguard"' \
+ -DKBUILD_MODNAME='"wireguard"'
+CC_OPT_lx_emul += -DKBUILD_MODFILE='"lx_emul"' \
+ -DKBUILD_BASENAME='"lx_emul"' \
+ -DKBUILD_MODNAME='"lx_emul"'
+
+#
+# The lx_emul Makefiles have a generic mechanism for defining the
+# KBUILD_MODNAME for each Linux unit to be the filename of that unit
+# (without suffix). However, some Wireguard units expect
+# KBUILD_MODNAME to be the same for all Wireguard units.
+# Therefore, we do a pattern substition on the CC_OPT_* variables of
+# those units, changing their KBUILD_MODNAME def to "wireguard".
+#
+
+OBJECTS_TO_FIX_MODNAME_DEFS_FOR := \
+ drivers/net/wireguard/device.o \
+ drivers/net/wireguard/netlink.o
+
+define FIX_MODNAME_DEF =
+CC_OPT_$(1) = $(patsubst -DKBUILD_MODNAME='"%"',-DKBUILD_MODNAME='"wireguard"',$(CC_OPT_$(1)))
+endef
+
+.PHONY: fix_modname_defs
+fix_modname_defs:
+ $(foreach file,$(OBJECTS_TO_FIX_MODNAME_DEFS_FOR), \
+ $(eval $(call FIX_MODNAME_DEF,$(file:%.o=%))))
+
+$(OBJECTS_TO_FIX_MODNAME_DEFS_FOR): fix_modname_defs
diff --git a/repos/dde_linux/run/wg_fetchurl.run b/repos/dde_linux/run/wg_fetchurl.run
new file mode 100644
index 0000000000..665e8e1490
--- /dev/null
+++ b/repos/dde_linux/run/wg_fetchurl.run
@@ -0,0 +1,419 @@
+#
+# FetchURL downloading a file from a LightTPD server through a Wireguard VPN
+#
+# By default, the file is an short inline HTML file at lighttpd and downloaded
+# into RAM in fetchurl. However, when the test is run with base-linux,
+# lighttpd uses a file created by the host filled filled with zeroes and of
+# customizable size and fetchurl downloads into the host FS, so the test can
+# then check the MD5 sum of the file.
+#
+
+if {[expr ![have_spec arm_64] && ![have_spec x86_64]]} {
+ puts "Run script is not supported on this platform."
+ exit 0
+}
+
+if {[have_spec linux]} {
+ set linux 1
+ set not_linux 0
+} else {
+ set linux 0
+ set not_linux 1
+}
+
+#
+# Note that in the not_linux case, the file size is rounded
+# down to a multiple of 100.
+#
+set file_size_in_bytes 1000000
+
+create_boot_directory
+
+import_from_depot [depot_user]/src/libc \
+ [depot_user]/src/libssh \
+ [depot_user]/src/lighttpd \
+ [depot_user]/src/openssl \
+ [depot_user]/src/posix \
+ [depot_user]/src/vfs \
+ [depot_user]/src/vfs_lwip \
+ [depot_user]/src/zlib
+
+append config {
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+
+append_if $linux config {
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+
+append config {
+
+
+
+
+
+
+
+
+ 2019-07-04 12:00
+ 01234567890123456789
+
+
+
+
+ }
+
+append_if $linux config {
+
+ }
+
+append_if $not_linux config {
+
+ }
+
+append config {
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 2000-01-01 00:00
+ 0123456789012345678901234567890123456789
+
+
+
+
+
+# lighttpd configuration
+server.port = 80
+server.document-root = "/website"
+server.event-handler = "select"
+server.network-backend = "write"
+server.upload-dirs = ( "/tmp" )
+server.modules = ("mod_openssl")
+index-file.names = (
+ "index.xhtml", "index.html", "index.htm"
+)
+mimetype.assign = (
+ ".html" => "text/html",
+ ".htm" => "text/html"
+)
+$SERVER["socket"] == ":443" {
+ ssl.engine = "enable"
+ ssl.pemfile = "/etc/lighttpd/example.pem"
+}
+
+
+-----BEGIN PRIVATE KEY-----
+MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQC4KHUZjDRew89c
+wDlYPz9XFigcMDnDlHzdg2ByrGZIOUNYC5LH1QUK0TDbPP45Xx455niA0QY85dMQ
+4DQx0Qk6+TDpVD3F2MYQgbIX6YkX9kgqX+jiHgsNzRD4KamNYmfUY+dJhlZEXWAF
+uNSnRLvg4EH72AVKLLKiruGwkisW/AYU6dNE8iFOYL8Q75bBUADiQSDdD8vkpeXg
+1NqxNyHPR6YRbA+vqcK0kbC8btKR9wG6m99OhTR4x3M87vtFFLNtJNEf54fYxi+L
+1rljSqHbaXD+XJsVKgX+UlI1ZlYW4KqlMciMemkBp0CovCxLfsbMmkXAW2RONpkm
++sdO3CXFAgMBAAECggEAIKv00nqAVAuzP0ZPJivaZe3lYdLgfKVcXcRQGSgi4U9f
+dkBfYxqU0W15mHvCspUAfM85s8jhrW4suwK739axJ4hMOCkc6Hvj78vCt+FT1C96
+cCIh4/PmjCVEjHJ/xTifKRwsTWwK5AgY4AsBl0dneabvremOTrGNY7VZDwVvpZz1
+qXkSNjQ63tZKj9cESO5ceGLzuBAG6JDDpqJM5fmdsQ36/QVz9Gogr8bXEWFM1TOo
+lWVAPB/l6nqKurfMv+5th354+owv9CGKxqLBE1fujwE2VogBz7mkR/rnABOPU5ev
+wQVLXoUkO2bI8Uvc28lChaiG6ihfdmNCmwoi56HFRQKBgQDj0WoIxiY7H42KV7Hh
+uQZv/0aoQyjXuqJ7Vq0HdxOAxZr0GpSYgo3MTZWooI2AnAstPHXo0BsQr+XVijWm
+xiDxMM4p9nrBzjEIHwyDaf62Pz/6lIPdenynLiEIOUbocJ3r0/3tCrY3U7fgjzYY
+f9PZmXKEOOKdbVPyXG0OIJ/ADwKBgQDO8GkCdVGy/YB0X7ntqcBG0xgmDnKRmYpQ
+X7Tb377AT2lzvftxaRVrx+UXtvFdy4xdrxjqHJCgOHT/fsAfjJlo7v1+KhTvE0pt
+jCdJPLbzXJRwaISaeEaMJ/N8Vv/j2/YuoS5M5vh4NlWeO16HtF7N9V9cMEZ5iRW1
+9G/eWgOo6wKBgQCY6rn3xblnuhgxogd+ccmGZ50v2FST6WyiyV0/Q4hNyVXnP+g6
+LneriPBJzertRtChvpGOghGIs+jb2veESD1YZ+Aafp2LdTGoN98YXo9gGTiCpCmX
+Al6lgOsfMAMOhnkaEKPC9ou0u3cTPk2bSEIVL1CUu/IwpW/RoIR7FR7ltQKBgQDA
+RAmsqQfhPzqL5SzALclhhFuZcC7uLDOf/WvyJW37C000pjzp3/JxE2Y8pFKZDLc7
+i6WgTi3pTssVXtRt+5nFLtcC02Jjxg6OvXr6xphMf6XC0rjxM/KH4c6Npd9V+1Y9
+eK+l76rHNeRSgWKQvvqebO3On2O7I6yyQ4t0kTl5RQKBgQCbX1cTtNmNr6HNleXL
+zfclKESSYy57uq3fQxhRrEE2ZNbemLOxEuoBCFYoMwpZEjC1GZyICrM7o5673/Ih
+I0oZerUBmt2l8noZCQoITEa97bCbp2vIdHYnCf/H3Nf2qM329fc00kAmm7vUVRgM
+4BqXnuFcAOuY68sgp9JArzK+EQ==
+-----END PRIVATE KEY-----
+-----BEGIN CERTIFICATE-----
+MIIDazCCAlOgAwIBAgIUYPOYXijLmMjjlgRCGHuZeyP0iPEwDQYJKoZIhvcNAQEL
+BQAwRTELMAkGA1UEBhMCREUxEzARBgNVBAgMClNvbWUtU3RhdGUxDTALBgNVBAoM
+BFRlc3QxEjAQBgNVBAMMCTEwLjAuMi41NTAeFw0yMDA1MTQxNDQ0MzlaFw00NzA5
+MzAxNDQ0MzlaMEUxCzAJBgNVBAYTAkRFMRMwEQYDVQQIDApTb21lLVN0YXRlMQ0w
+CwYDVQQKDARUZXN0MRIwEAYDVQQDDAkxMC4wLjIuNTUwggEiMA0GCSqGSIb3DQEB
+AQUAA4IBDwAwggEKAoIBAQC4KHUZjDRew89cwDlYPz9XFigcMDnDlHzdg2ByrGZI
+OUNYC5LH1QUK0TDbPP45Xx455niA0QY85dMQ4DQx0Qk6+TDpVD3F2MYQgbIX6YkX
+9kgqX+jiHgsNzRD4KamNYmfUY+dJhlZEXWAFuNSnRLvg4EH72AVKLLKiruGwkisW
+/AYU6dNE8iFOYL8Q75bBUADiQSDdD8vkpeXg1NqxNyHPR6YRbA+vqcK0kbC8btKR
+9wG6m99OhTR4x3M87vtFFLNtJNEf54fYxi+L1rljSqHbaXD+XJsVKgX+UlI1ZlYW
+4KqlMciMemkBp0CovCxLfsbMmkXAW2RONpkm+sdO3CXFAgMBAAGjUzBRMB0GA1Ud
+DgQWBBQvSHuosL/SDn/8sKl0dpyPeFvOfjAfBgNVHSMEGDAWgBQvSHuosL/SDn/8
+sKl0dpyPeFvOfjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQBR
+sGYEuRwIU/tmAmTbniptItN9VE0NNj9QeKh+hKQ9cHvhxmlBlf5b7Vb2JaRZdy88
+kRIFKiNkyjgQVg+5KuEIcg17mHSal7zG+jIZ3c1bIpVCM4AjUe7EXl8LM4+dJ5sX
+Bwpd34tUk2edOiT8R/dU7uesxCdeIQ2FfvKyrXca73nj+UTvFGXUk/9mWY8KAaYc
+F/PWBhiZhJD4/dkUHJnrVtjpcqW2Io8bFmrMq2vfqQv+W2FZGCsHgXkAZO2E0jyQ
+5eOrwzgWRtMc5PvoGvqQfefseaLs0fvSQdcPqfv88Eqk5NGTOCIW8/KEsBwFJuwa
+EpA5DBBklj8UE2CdONvN
+-----END CERTIFICATE-----
+
+
+
+ }
+
+append_if $linux config {
+
+ }
+
+if {$not_linux} {
+
+ append config {}
+ for {set i 0} {$i < $file_size_in_bytes} {incr i 64} {
+
+ # append 100 bytes of "0"
+ append config {0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000}
+ }
+ append config {}
+}
+
+append config {
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+}
+
+install_config $config
+
+append targets {
+ core init timer server/nic_router app/wireguard server/report_rom
+ app/fetchurl }
+
+append boot_modules {
+ core init timer nic_router wireguard fetchurl report_rom curl.lib.so
+ ld.lib.so }
+
+if $linux {
+
+ append targets { server/lx_fs }
+ append boot_modules { lx_fs }
+
+ # create the lx_fs root of fetchurl where it will store the downloaded file
+ proc lx_fs_root {} { return [run_dir]/genode }
+ exec rm -rf [lx_fs_root]/fetchurl_fs
+ exec mkdir -p [lx_fs_root]/fetchurl_fs
+
+ # create the lx_fs root of lighttpd and the downloadable file inside it
+ exec rm -rf [lx_fs_root]/lighttpd_fs
+ exec mkdir -p [lx_fs_root]/lighttpd_fs
+ exec head -c $file_size_in_bytes /dev/zero > [lx_fs_root]/lighttpd_fs/index.html
+}
+
+build $targets
+
+build_boot_image $boot_modules
+
+append qemu_args "-nographic "
+
+# run the scenario till fetchurl succeeded to download the file
+run_genode_until "fetchurl. exited with exit value 0.*\n" 60
+
+if {$linux} {
+
+ # check that the md5 sum of the downloaded file is correct
+ set lighttpd_index_md5 [exec md5sum [lx_fs_root]/lighttpd_fs/index.html]
+ set fetchurl_index_md5 [exec md5sum [lx_fs_root]/fetchurl_fs/index.html]
+
+ puts ""
+ puts $lighttpd_index_md5
+ puts $fetchurl_index_md5
+ puts "MD5SUM of transferred files is correct"
+
+ if {[string compare -length 32 $lighttpd_index_md5 $fetchurl_index_md5]} {
+ puts ""
+ puts "Error: MD5SUM of transferred files is incorrect"
+ puts ""
+ exit -1
+ }
+}
diff --git a/repos/dde_linux/run/wg_lighttpd.run b/repos/dde_linux/run/wg_lighttpd.run
new file mode 100644
index 0000000000..4310f4a88b
--- /dev/null
+++ b/repos/dde_linux/run/wg_lighttpd.run
@@ -0,0 +1,293 @@
+#
+# LightTPD server in a Wireguard VPN
+#
+# Once the scenario is running and DHCP is done, you can reach the server from
+# your host system via 10.0.9.2:80 . The traffic is going through a host
+# Wireguard device 'wg0' that puts it into an encrypted UDP tunnel towards the
+# TAP device 'tap0' where it enters Qemu and reaches the inner Genode router
+# at domain 'uplink'. The inner router port-forwards the traffic to its
+# 'downlink' domain to which the tunnel side (10.0.3.2) of the Genode Wireguard
+# component is connected . This component unpacks the original packets
+# from the tunnel. The back side of the component is connected to the inner
+# Genode router at domain 'uplink' and sends the plain packets unmodified a
+# this connection. The routers IP identity in that domain is the Wireguard
+# device IP, speak the VPN-internal IP 10.0.9.2 of the server. The inner
+# router now forwards the different ports to the corresponding peers, in
+# this case TCP port 80 to the LightTPD server (10.0.5.2) at the inner
+# router domain "downlink".
+#
+
+source ${genode_dir}/repos/dde_linux/run/wg_qemu_tap_preamble.inc
+
+create_boot_directory
+
+import_from_depot [depot_user]/src/[base_src] \
+ [depot_user]/pkg/[drivers_nic_pkg] \
+ [depot_user]/src/init \
+ [depot_user]/src/nic_router \
+ [depot_user]/src/libc \
+ [depot_user]/src/libssh \
+ [depot_user]/src/lighttpd \
+ [depot_user]/src/openssl \
+ [depot_user]/src/posix \
+ [depot_user]/src/vfs \
+ [depot_user]/src/vfs_lwip \
+ [depot_user]/src/zlib
+
+install_config {
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 2000-01-01 00:00
+ 0123456789012345678901234567890123456789
+
+
+
+
+
+# lighttpd configuration
+server.port = 80
+server.document-root = "/website"
+server.event-handler = "select"
+server.network-backend = "write"
+server.upload-dirs = ( "/tmp" )
+server.modules = ("mod_openssl")
+index-file.names = (
+ "index.xhtml", "index.html", "index.htm"
+)
+mimetype.assign = (
+ ".html" => "text/html",
+ ".htm" => "text/html"
+)
+$SERVER["socket"] == ":443" {
+ ssl.engine = "enable"
+ ssl.pemfile = "/etc/lighttpd/example.pem"
+}
+
+
+-----BEGIN PRIVATE KEY-----
+MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQC4KHUZjDRew89c
+wDlYPz9XFigcMDnDlHzdg2ByrGZIOUNYC5LH1QUK0TDbPP45Xx455niA0QY85dMQ
+4DQx0Qk6+TDpVD3F2MYQgbIX6YkX9kgqX+jiHgsNzRD4KamNYmfUY+dJhlZEXWAF
+uNSnRLvg4EH72AVKLLKiruGwkisW/AYU6dNE8iFOYL8Q75bBUADiQSDdD8vkpeXg
+1NqxNyHPR6YRbA+vqcK0kbC8btKR9wG6m99OhTR4x3M87vtFFLNtJNEf54fYxi+L
+1rljSqHbaXD+XJsVKgX+UlI1ZlYW4KqlMciMemkBp0CovCxLfsbMmkXAW2RONpkm
++sdO3CXFAgMBAAECggEAIKv00nqAVAuzP0ZPJivaZe3lYdLgfKVcXcRQGSgi4U9f
+dkBfYxqU0W15mHvCspUAfM85s8jhrW4suwK739axJ4hMOCkc6Hvj78vCt+FT1C96
+cCIh4/PmjCVEjHJ/xTifKRwsTWwK5AgY4AsBl0dneabvremOTrGNY7VZDwVvpZz1
+qXkSNjQ63tZKj9cESO5ceGLzuBAG6JDDpqJM5fmdsQ36/QVz9Gogr8bXEWFM1TOo
+lWVAPB/l6nqKurfMv+5th354+owv9CGKxqLBE1fujwE2VogBz7mkR/rnABOPU5ev
+wQVLXoUkO2bI8Uvc28lChaiG6ihfdmNCmwoi56HFRQKBgQDj0WoIxiY7H42KV7Hh
+uQZv/0aoQyjXuqJ7Vq0HdxOAxZr0GpSYgo3MTZWooI2AnAstPHXo0BsQr+XVijWm
+xiDxMM4p9nrBzjEIHwyDaf62Pz/6lIPdenynLiEIOUbocJ3r0/3tCrY3U7fgjzYY
+f9PZmXKEOOKdbVPyXG0OIJ/ADwKBgQDO8GkCdVGy/YB0X7ntqcBG0xgmDnKRmYpQ
+X7Tb377AT2lzvftxaRVrx+UXtvFdy4xdrxjqHJCgOHT/fsAfjJlo7v1+KhTvE0pt
+jCdJPLbzXJRwaISaeEaMJ/N8Vv/j2/YuoS5M5vh4NlWeO16HtF7N9V9cMEZ5iRW1
+9G/eWgOo6wKBgQCY6rn3xblnuhgxogd+ccmGZ50v2FST6WyiyV0/Q4hNyVXnP+g6
+LneriPBJzertRtChvpGOghGIs+jb2veESD1YZ+Aafp2LdTGoN98YXo9gGTiCpCmX
+Al6lgOsfMAMOhnkaEKPC9ou0u3cTPk2bSEIVL1CUu/IwpW/RoIR7FR7ltQKBgQDA
+RAmsqQfhPzqL5SzALclhhFuZcC7uLDOf/WvyJW37C000pjzp3/JxE2Y8pFKZDLc7
+i6WgTi3pTssVXtRt+5nFLtcC02Jjxg6OvXr6xphMf6XC0rjxM/KH4c6Npd9V+1Y9
+eK+l76rHNeRSgWKQvvqebO3On2O7I6yyQ4t0kTl5RQKBgQCbX1cTtNmNr6HNleXL
+zfclKESSYy57uq3fQxhRrEE2ZNbemLOxEuoBCFYoMwpZEjC1GZyICrM7o5673/Ih
+I0oZerUBmt2l8noZCQoITEa97bCbp2vIdHYnCf/H3Nf2qM329fc00kAmm7vUVRgM
+4BqXnuFcAOuY68sgp9JArzK+EQ==
+-----END PRIVATE KEY-----
+-----BEGIN CERTIFICATE-----
+MIIDazCCAlOgAwIBAgIUYPOYXijLmMjjlgRCGHuZeyP0iPEwDQYJKoZIhvcNAQEL
+BQAwRTELMAkGA1UEBhMCREUxEzARBgNVBAgMClNvbWUtU3RhdGUxDTALBgNVBAoM
+BFRlc3QxEjAQBgNVBAMMCTEwLjAuMi41NTAeFw0yMDA1MTQxNDQ0MzlaFw00NzA5
+MzAxNDQ0MzlaMEUxCzAJBgNVBAYTAkRFMRMwEQYDVQQIDApTb21lLVN0YXRlMQ0w
+CwYDVQQKDARUZXN0MRIwEAYDVQQDDAkxMC4wLjIuNTUwggEiMA0GCSqGSIb3DQEB
+AQUAA4IBDwAwggEKAoIBAQC4KHUZjDRew89cwDlYPz9XFigcMDnDlHzdg2ByrGZI
+OUNYC5LH1QUK0TDbPP45Xx455niA0QY85dMQ4DQx0Qk6+TDpVD3F2MYQgbIX6YkX
+9kgqX+jiHgsNzRD4KamNYmfUY+dJhlZEXWAFuNSnRLvg4EH72AVKLLKiruGwkisW
+/AYU6dNE8iFOYL8Q75bBUADiQSDdD8vkpeXg1NqxNyHPR6YRbA+vqcK0kbC8btKR
+9wG6m99OhTR4x3M87vtFFLNtJNEf54fYxi+L1rljSqHbaXD+XJsVKgX+UlI1ZlYW
+4KqlMciMemkBp0CovCxLfsbMmkXAW2RONpkm+sdO3CXFAgMBAAGjUzBRMB0GA1Ud
+DgQWBBQvSHuosL/SDn/8sKl0dpyPeFvOfjAfBgNVHSMEGDAWgBQvSHuosL/SDn/8
+sKl0dpyPeFvOfjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQBR
+sGYEuRwIU/tmAmTbniptItN9VE0NNj9QeKh+hKQ9cHvhxmlBlf5b7Vb2JaRZdy88
+kRIFKiNkyjgQVg+5KuEIcg17mHSal7zG+jIZ3c1bIpVCM4AjUe7EXl8LM4+dJ5sX
+Bwpd34tUk2edOiT8R/dU7uesxCdeIQ2FfvKyrXca73nj+UTvFGXUk/9mWY8KAaYc
+F/PWBhiZhJD4/dkUHJnrVtjpcqW2Io8bFmrMq2vfqQv+W2FZGCsHgXkAZO2E0jyQ
+5eOrwzgWRtMc5PvoGvqQfefseaLs0fvSQdcPqfv88Eqk5NGTOCIW8/KEsBwFJuwa
+EpA5DBBklj8UE2CdONvN
+-----END CERTIFICATE-----
+
+
+
+
+
+
+
+ Hello
+
+
+ Hello Genode!
+ I am bold ;-)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+}
+
+build { app/wireguard }
+
+build_boot_image { wireguard }
+
+run_genode_until forever
diff --git a/repos/dde_linux/run/wg_ping_inwards.run b/repos/dde_linux/run/wg_ping_inwards.run
new file mode 100644
index 0000000000..71674f2185
--- /dev/null
+++ b/repos/dde_linux/run/wg_ping_inwards.run
@@ -0,0 +1,161 @@
+#
+# Let the host Linux ping a Genode in Qemu through a Wireguard tunnel.
+#
+
+source ${genode_dir}/repos/dde_linux/run/wg_qemu_tap_preamble.inc
+
+create_boot_directory
+
+import_from_depot [depot_user]/src/[base_src] \
+ [depot_user]/pkg/[drivers_nic_pkg] \
+ [depot_user]/src/init \
+ [depot_user]/src/nic_router
+
+install_config {
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+}
+
+build { app/wireguard }
+
+build_boot_image { wireguard }
+
+run_genode_until "uplink\] dynamic IP config: interface 10.0.2.3" 10
+
+set timeout 60
+
+append wait_for_string "64 bytes from 10.0.9.2.*"
+append wait_for_string "64 bytes from 10.0.9.2.*"
+append wait_for_string "64 bytes from 10.0.9.2.*\n"
+
+eval spawn ping 10.0.9.2
+expect {
+ -re $wait_for_string { }
+ eof {
+ puts stderr "Error: Spawned process died unexpectedly";
+ exit -3
+ }
+ timeout {
+ puts stderr "Error: Test execution timed out";
+ exit -2
+ }
+}
diff --git a/repos/dde_linux/run/wg_ping_outwards.run b/repos/dde_linux/run/wg_ping_outwards.run
new file mode 100644
index 0000000000..adcc5f305c
--- /dev/null
+++ b/repos/dde_linux/run/wg_ping_outwards.run
@@ -0,0 +1,172 @@
+#
+# Let a Genode in Qemu ping the host Linux through a Wireguard tunnel.
+#
+
+source ${genode_dir}/repos/dde_linux/run/wg_qemu_tap_preamble.inc
+
+create_boot_directory
+
+import_from_depot [depot_user]/src/[base_src] \
+ [depot_user]/pkg/[drivers_nic_pkg] \
+ [depot_user]/src/init \
+ [depot_user]/src/nic_router
+
+install_config {
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+
+build { app/wireguard app/ping }
+
+build_boot_image { wireguard ping }
+
+append wait_for_string "64 bytes from 10.0.9.1.*"
+append wait_for_string "64 bytes from 10.0.9.1.*"
+append wait_for_string "64 bytes from 10.0.9.1.*\n"
+
+run_genode_until $wait_for_string 60
diff --git a/repos/dde_linux/run/wg_qemu_tap_preamble.inc b/repos/dde_linux/run/wg_qemu_tap_preamble.inc
new file mode 100644
index 0000000000..e1b6ef0344
--- /dev/null
+++ b/repos/dde_linux/run/wg_qemu_tap_preamble.inc
@@ -0,0 +1,110 @@
+#
+# Preamble for WireGuard tests that run in Qemu and use a Qemu netdev TAP
+# device to create a tunnel between the WireGuard device in the guest system
+# and a Wireguard device in the host system. This script checks that the
+# target platform is supported, installs the correct Qemu arguments, sets up
+# the host WireGuard device, and ensures that the host WireGuard setup is
+# undone whenever the test terminates.
+#
+
+if {[expr ![have_spec arm_64] && ![have_spec x86_64]]} {
+ puts "Run script is not supported on this platform."
+ exit 0
+}
+
+if {[expr [have_spec arm_64] && ![have_board virt_qemu]]} {
+ puts "Run script is not supported on this platform."
+ exit 0
+}
+
+if {[expr ![have_include power_on/qemu]]} {
+ puts "Test requires Qemu."
+ exit 0
+}
+
+append wg_board_qemu_args " -m 512 "
+append wg_board_qemu_args " -nographic "
+append wg_board_qemu_args " -netdev tap,id=net0,ifname=tap0,script=no,downscript=no "
+append wg_board_qemu_args " -smp 4 "
+
+if {[have_board virt_qemu]} {
+
+ append wg_board_qemu_args " -global virtio-mmio.force-legacy=false "
+ append wg_board_qemu_args " -device virtio-net-device,bus=virtio-mmio-bus.0,netdev=net0 "
+ append wg_board_qemu_args " -M virt,virtualization=true,gic-version=3 "
+ append wg_board_qemu_args " -cpu cortex-a53 "
+
+} elseif {[have_spec x86_64]} {
+
+ append wg_board_qemu_args " -machine q35 "
+ append wg_board_qemu_args " -net nic,model=e1000,netdev=net0 "
+
+} else {
+
+ puts "Run script is not supported on this platform."
+ exit 0
+}
+
+proc board_qemu_args { } {
+ global wg_board_qemu_args
+ return $wg_board_qemu_args
+}
+
+proc set_up_host_wg {} {
+
+ puts "Set up host WireGuard"
+
+ exec sudo rm -f udhcpd.conf udhcpd.leases
+ exec sudo ip tuntap del dev tap0 mode tap
+
+ set fd [open udhcpd.conf w]
+ puts $fd "interface tap0"
+ puts $fd "start 10.0.2.3"
+ puts $fd "end 10.0.2.4"
+ puts $fd "max_leases 2"
+ puts $fd "lease_file udhcpd.leases"
+ puts $fd "pidfile udhcpd.pid"
+ puts $fd "option dns 10.0.2.1 10.0.2.2"
+ puts $fd "option subnet 255.255.255.0"
+ puts $fd "option router 10.0.2.1"
+ close $fd
+
+ set fd [open udhcpd.leases w]
+ close $fd
+
+ exec sudo ip tuntap add dev tap0 mode tap user $::tcl_platform(user)
+ exec sudo ip address flush dev tap0
+ exec sudo ip address add 10.0.2.1/24 dev tap0
+ exec sudo ip link set tap0 up
+
+ exec sudo udhcpd udhcpd.conf
+
+ exec echo "0CtU34qsl97IGiYKSO4tMaF/SJvy04zzeQkhZEbZSk0=" > wg_private_key
+ exec chmod 700 wg_private_key
+ exec sudo ip link add wg0 type wireguard
+ exec sudo ip addr add 10.0.9.1/24 dev wg0
+ exec sudo wg set wg0 private-key wg_private_key listen-port 49001
+ exec sudo ip link set wg0 up
+ exec sudo wg set wg0 peer "GrvyALPZ3PQ2AWM+ovxJqnxSqKpmTyqUui5jH+C8I0E=" allowed-ips 10.0.9.2/32 endpoint 10.0.2.3:49002
+}
+
+proc undo_host_wg_setup {} {
+
+ puts "Undo host WireGuard setup"
+ exec sudo pkill -F udhcpd.pid
+ exec sudo ip link set wg0 down
+ exec sudo ip link delete dev wg0
+ exec sudo ip link set tap0 down
+ exec sudo ip address flush dev tap0
+ exec sudo ip link delete tap0
+ exec sudo rm -rf wg_private_key udhcpd.conf udhcpd.leases udhcpd.pid
+}
+
+rename exit run_tool_exit
+proc exit {{status 0}} {
+
+ undo_host_wg_setup
+ run_tool_exit $status
+}
+
+set_up_host_wg
diff --git a/repos/dde_linux/src/app/wireguard/README b/repos/dde_linux/src/app/wireguard/README
new file mode 100644
index 0000000000..70833f9368
--- /dev/null
+++ b/repos/dde_linux/src/app/wireguard/README
@@ -0,0 +1,8 @@
+
+:Warning:
+
+Although in principal functioning, the WireGuard port has not been exposed to a
+sufficient amount of real-world testing, so far. Therefore, we strongly
+recommend not to use it in any security-critical scenarios! There is no
+guarantee that the port meets any of the security goals pursued by the
+WireGuard protocol or other WireGuard implementations!
diff --git a/repos/dde_linux/src/app/wireguard/arp_cache.cc b/repos/dde_linux/src/app/wireguard/arp_cache.cc
new file mode 100644
index 0000000000..edafe9f94e
--- /dev/null
+++ b/repos/dde_linux/src/app/wireguard/arp_cache.cc
@@ -0,0 +1,99 @@
+/*
+* \brief Cache for received ARP information
+* \author Martin Stein
+* \date 2016-08-19
+*/
+
+/*
+* Copyright (C) 2016-2017 Genode Labs GmbH
+*
+* This file is part of the Genode OS framework, which is distributed
+* under the terms of the GNU Affero General Public License version 3.
+*/
+
+/* local includes */
+#include
+
+using namespace Net;
+using namespace Genode;
+
+
+/*********************
+ ** Arp_cache_entry **
+ *********************/
+
+Arp_cache_entry::Arp_cache_entry(Ipv4_address const &ip,
+ Mac_address const &mac)
+:
+ _ip(ip), _mac(mac)
+{ }
+
+
+bool Arp_cache_entry::_higher(Ipv4_address const &ip) const
+{
+ return memcmp(ip.addr, _ip.addr, sizeof(_ip.addr)) > 0;
+}
+
+
+Arp_cache_result Arp_cache_entry::find_by_ip(Ipv4_address const &ip) const
+{
+ if (ip == _ip) {
+ return Const_pointer { *this };
+ }
+ Arp_cache_entry const *const entry = child(_higher(ip));
+ if (!entry) {
+ return Arp_cache_result(Arp_cache_error::NO_MATCH);
+ }
+ return entry->find_by_ip(ip);
+}
+
+void Arp_cache_entry::print(Output &output) const
+{
+ Genode::print(output, _ip, " > ", _mac);
+}
+
+
+/***************
+ ** Arp_cache **
+ ***************/
+
+void Arp_cache::new_entry(Ipv4_address const &ip, Mac_address const &mac)
+{
+ if (_entries[_curr].constructed()) {
+ remove(&(*_entries[_curr]));
+ }
+ _entries[_curr].construct(ip, mac);
+ Arp_cache_entry &entry = *_entries[_curr];
+ insert(&entry);
+ if (_curr < NR_OF_ENTRIES - 1) {
+ _curr++;
+ } else {
+ _curr = 0;
+ };
+}
+
+
+Arp_cache_result Arp_cache::find_by_ip(Ipv4_address const &ip) const
+{
+ if (!first()) {
+ return Arp_cache_error::NO_MATCH;
+ }
+ return first()->find_by_ip(ip);
+}
+
+
+void Arp_cache::destroy_entries_with_mac(Mac_address const &mac)
+{
+ for (unsigned curr = 0; curr < NR_OF_ENTRIES; curr++) {
+ try {
+ Arp_cache_entry &entry = *_entries[curr];
+ if (entry.mac() != mac) {
+ continue;
+ }
+ log("destroy ARP entry ", entry);
+ remove(&entry);
+ _entries[curr].destruct();
+
+ } catch (Arp_cache_entry_slot::Deref_unconstructed_object) { }
+ }
+}
diff --git a/repos/dde_linux/src/app/wireguard/arp_cache.h b/repos/dde_linux/src/app/wireguard/arp_cache.h
new file mode 100644
index 0000000000..e97d722063
--- /dev/null
+++ b/repos/dde_linux/src/app/wireguard/arp_cache.h
@@ -0,0 +1,98 @@
+/*
+* \brief Cache for received ARP information
+* \author Martin Stein
+* \date 2016-08-19
+*/
+
+/*
+* Copyright (C) 2016-2017 Genode Labs GmbH
+*
+* This file is part of the Genode OS framework, which is distributed
+* under the terms of the GNU Affero General Public License version 3.
+*/
+
+#ifndef _ARP_CACHE_H_
+#define _ARP_CACHE_H_
+
+/* Genode includes */
+#include
+#include
+#include
+#include
+#include
+
+/* dde_linux wireguard includes */
+#include
+
+namespace Net {
+
+ enum class Arp_cache_error { NO_MATCH };
+ class Domain;
+ class Arp_cache;
+ class Arp_cache_entry;
+ using Arp_cache_entry_slot = Genode::Constructible;
+ using Arp_cache_result = Genode::Attempt, Arp_cache_error>;
+}
+
+
+class Net::Arp_cache_entry : public Genode::Avl_node
+{
+ private:
+
+ Ipv4_address const _ip;
+ Mac_address const _mac;
+
+ bool _higher(Ipv4_address const &ip) const;
+
+ public:
+
+ Arp_cache_entry(Ipv4_address const &ip, Mac_address const &mac);
+
+ Arp_cache_result find_by_ip(Ipv4_address const &ip) const;
+
+
+ /**************
+ ** Avl_node **
+ **************/
+
+ bool higher(Arp_cache_entry *entry) { return _higher(entry->_ip); }
+
+
+ /***************
+ ** Accessors **
+ ***************/
+
+ Mac_address const &mac() const { return _mac; }
+ Ipv4_address const &ip() const { return _ip; }
+
+
+ /*********
+ ** log **
+ *********/
+
+ void print(Genode::Output &output) const;
+};
+
+
+class Net::Arp_cache : public Genode::Avl_tree
+{
+ private:
+
+ enum {
+ ENTRIES_SIZE = 1024 * sizeof(Genode::addr_t),
+ NR_OF_ENTRIES = ENTRIES_SIZE / sizeof(Arp_cache_entry),
+ };
+
+ Arp_cache_entry_slot _entries[NR_OF_ENTRIES];
+ unsigned _curr = 0;
+
+ public:
+
+ void new_entry(Ipv4_address const &ip, Mac_address const &mac);
+
+ void destroy_entries_with_mac(Mac_address const &mac);
+
+ Arp_cache_result find_by_ip(Ipv4_address const &ip) const;
+};
+
+#endif /* _ARP_CACHE_H_ */
diff --git a/repos/dde_linux/src/app/wireguard/arp_waiter.cc b/repos/dde_linux/src/app/wireguard/arp_waiter.cc
new file mode 100644
index 0000000000..1f89326c20
--- /dev/null
+++ b/repos/dde_linux/src/app/wireguard/arp_waiter.cc
@@ -0,0 +1,40 @@
+/*
+ * \brief Aspect of waiting for an ARP reply
+ * \author Martin Stein
+ * \date 2016-08-19
+ */
+
+/*
+ * Copyright (C) 2016-2017 Genode Labs GmbH
+ *
+ * This file is part of the Genode OS framework, which is distributed
+ * under the terms of the GNU Affero General Public License version 3.
+ */
+
+/* local includes */
+#include
+
+using namespace Net;
+using namespace Genode;
+
+
+Arp_waiter::Arp_waiter(Arp_waiter_list &list,
+ Ipv4_address const &ip,
+ Packet_descriptor const &packet)
+:
+ _list(list), _le(this), _ip(ip), _packet(packet)
+{
+ _list.insert(&_le);
+}
+
+
+Arp_waiter::~Arp_waiter()
+{
+ _list.remove(&_le);
+}
+
+
+void Arp_waiter::print(Output &output) const
+{
+ Genode::print(output, "IP ", _ip);
+}
diff --git a/repos/dde_linux/src/app/wireguard/arp_waiter.h b/repos/dde_linux/src/app/wireguard/arp_waiter.h
new file mode 100644
index 0000000000..2645e065d4
--- /dev/null
+++ b/repos/dde_linux/src/app/wireguard/arp_waiter.h
@@ -0,0 +1,66 @@
+/*
+ * \brief Remember packets that wait for ARP replies at different interfaces
+ * \author Martin Stein
+ * \date 2016-08-19
+ */
+
+/*
+ * Copyright (C) 2016-2017 Genode Labs GmbH
+ *
+ * This file is part of the Genode OS framework, which is distributed
+ * under the terms of the GNU Affero General Public License version 3.
+ */
+
+#ifndef _ARP_WAITER_H_
+#define _ARP_WAITER_H_
+
+/* local includes */
+#include
+
+/* Genode includes */
+#include
+#include
+
+namespace Net {
+
+ using Packet_descriptor = ::Nic::Packet_descriptor;
+ class Arp_waiter;
+ using Arp_waiter_list_element = Genode::List_element;
+ using Arp_waiter_list = Net::List;
+}
+
+
+class Net::Arp_waiter
+{
+ private:
+
+ Arp_waiter_list &_list;
+ Arp_waiter_list_element _le;
+ Ipv4_address const _ip;
+ Packet_descriptor const _packet;
+
+ public:
+
+ Arp_waiter(Arp_waiter_list &list,
+ Ipv4_address const &ip,
+ Packet_descriptor const &packet);
+
+ ~Arp_waiter();
+
+
+ /*********
+ ** Log **
+ *********/
+
+ void print(Genode::Output &output) const;
+
+
+ /***************
+ ** Accessors **
+ ***************/
+
+ Ipv4_address const &ip() const { return _ip; }
+ Packet_descriptor const &packet() const { return _packet; }
+};
+
+#endif /* _ARP_WAITER_H_ */
diff --git a/repos/dde_linux/src/app/wireguard/base64.cc b/repos/dde_linux/src/app/wireguard/base64.cc
new file mode 100644
index 0000000000..9078f5d5ea
--- /dev/null
+++ b/repos/dde_linux/src/app/wireguard/base64.cc
@@ -0,0 +1,59 @@
+/***************************************************
+ ** FIXME **
+ ** Slightly adapted copy from wireguard-tools. **
+ ** Replace with contrib or Genode implementation **
+ ***************************************************/
+
+/* base includes */
+#include
+
+/* app/wireguard includes */
+#include
+
+using namespace Genode;
+
+
+int decode_base64(const char src[4])
+{
+ int val = 0;
+
+ for (unsigned int i = 0; i < 4; ++i)
+ val |= (-1
+ + ((((('A' - 1) - src[i]) & (src[i] - ('Z' + 1))) >> 8) & (src[i] - 64))
+ + ((((('a' - 1) - src[i]) & (src[i] - ('z' + 1))) >> 8) & (src[i] - 70))
+ + ((((('0' - 1) - src[i]) & (src[i] - ('9' + 1))) >> 8) & (src[i] + 5))
+ + ((((('+' - 1) - src[i]) & (src[i] - ('+' + 1))) >> 8) & 63)
+ + ((((('/' - 1) - src[i]) & (src[i] - ('/' + 1))) >> 8) & 64)
+ ) << (18 - 6 * i);
+ return val;
+}
+
+
+bool key_from_base64(uint8_t key[WG_KEY_LEN], const char *base64)
+{
+ unsigned int i;
+ volatile uint8_t ret = 0;
+ int val;
+ char tmp[4];
+
+ if (strlen(base64) != WG_KEY_LEN_BASE64 - 1 || base64[WG_KEY_LEN_BASE64 - 2] != '=')
+ return false;
+
+ for (i = 0; i < WG_KEY_LEN / 3; ++i) {
+ val = decode_base64(&base64[i * 4]);
+ ret |= (uint8_t)((uint32_t)val >> 31);
+ key[i * 3 + 0] = (uint8_t)((val >> 16) & 0xff);
+ key[i * 3 + 1] = (uint8_t)((val >> 8) & 0xff);
+ key[i * 3 + 2] = (uint8_t)(val & 0xff);
+ }
+ tmp[0] = base64[i * 4 + 0];
+ tmp[1] = base64[i * 4 + 1];
+ tmp[2] = base64[i * 4 + 2];
+ tmp[3] = 'A';
+ val = decode_base64(tmp);
+ ret |= (uint8_t)(((uint32_t)val >> 31) | (val & 0xff));
+ key[i * 3 + 0] = (uint8_t)((val >> 16) & 0xff);
+ key[i * 3 + 1] = (uint8_t)((val >> 8) & 0xff);
+
+ return 1 & ((ret - 1) >> 8);
+}
diff --git a/repos/dde_linux/src/app/wireguard/base64.h b/repos/dde_linux/src/app/wireguard/base64.h
new file mode 100644
index 0000000000..bc3e1a2380
--- /dev/null
+++ b/repos/dde_linux/src/app/wireguard/base64.h
@@ -0,0 +1,22 @@
+/***************************************************
+ ** FIXME **
+ ** Slightly adapted copy from wireguard-tools. **
+ ** Replace with contrib or Genode implementation **
+ ***************************************************/
+
+#ifndef _BASE64_H_
+#define _BASE64_H_
+
+/* base includes */
+#include
+
+enum {
+ WG_KEY_LEN = 32,
+ WG_KEY_LEN_BASE64 = ((((WG_KEY_LEN) + 2) / 3) * 4 + 1),
+};
+
+int decode_base64(const char src[4]);
+
+bool key_from_base64(Genode::uint8_t key[WG_KEY_LEN], const char *base64);
+
+#endif /* _BASE64_H_ */
diff --git a/repos/dde_linux/src/app/wireguard/config_model.cc b/repos/dde_linux/src/app/wireguard/config_model.cc
new file mode 100644
index 0000000000..9a1a42f74f
--- /dev/null
+++ b/repos/dde_linux/src/app/wireguard/config_model.cc
@@ -0,0 +1,161 @@
+/*
+ * \brief A differentially updating model of the component configuration
+ * \author Stefan Kalkowski
+ * \author Martin Stein
+ * \date 2022-01-07
+ */
+
+/*
+ * Copyright (C) 2022 Genode Labs GmbH
+ *
+ * This file is part of the Genode OS framework, which is distributed
+ * under the terms of the GNU Affero General Public License version 3.
+ */
+
+/* dde_linux wireguard includes */
+#include
+
+using namespace Genode;
+using namespace Net;
+using namespace Wireguard;
+
+
+/******************
+ ** Config_model **
+ ******************/
+
+Config_model::Config_model(Genode::Allocator &alloc)
+:
+ _alloc { alloc }
+{ }
+
+
+void Config_model::update(genode_wg_config_callbacks &callbacks,
+ Xml_node node)
+{
+ if (!_config.constructed()) {
+
+ _config.construct(
+ node.attribute_value("private_key", Key_base64 { }),
+ node.attribute_value("listen_port", (uint16_t)0U),
+ node.attribute_value("interface", Ipv4_address_prefix { }));
+
+ uint8_t private_key[WG_KEY_LEN];
+ if (!_config->private_key_b64().valid() ||
+ !key_from_base64(private_key, _config->private_key_b64().string())) {
+
+ error("Invalid private key!");
+ }
+ callbacks.add_device(_config->listen_port(), private_key);
+ }
+ Peer_update_policy policy { _alloc, callbacks, _config->listen_port() };
+ _peers.update_from_xml(policy, node);
+}
+
+
+/**************************
+ ** Config_model::Config **
+ **************************/
+
+Config_model::Config::Config(Key_base64 private_key_b64,
+ uint16_t listen_port,
+ Ipv4_address_prefix interface)
+:
+ _private_key_b64 { private_key_b64 },
+ _listen_port { listen_port },
+ _interface { interface }
+{ }
+
+
+/**************************************
+ ** Config_model::Peer_update_policy **
+ **************************************/
+
+void Config_model::Peer_update_policy::update_element(Element &,
+ Xml_node )
+{ }
+
+
+Config_model::
+Peer_update_policy::Peer_update_policy(Allocator &alloc,
+ genode_wg_config_callbacks &callbacks,
+ uint16_t listen_port)
+:
+ _alloc { alloc },
+ _callbacks { callbacks },
+ _listen_port { listen_port }
+{ }
+
+
+void Config_model::Peer_update_policy::destroy_element(Element &peer)
+{
+ _callbacks.remove_peer(
+ _listen_port, peer._endpoint_ip.addr, peer._endpoint_port);
+
+ destroy(_alloc, &peer);
+}
+
+
+Config_model::Peer_update_policy::Element &
+Config_model::Peer_update_policy::create_element(Xml_node node)
+{
+ Ipv4_address endpoint_ip { node.attribute_value("endpoint_ip", Ipv4_address { }) };
+ uint16_t endpoint_port { node.attribute_value("endpoint_port", (uint16_t)0U ) };
+ Key_base64 public_key_b64 { node.attribute_value("public_key", Key_base64 { }) };
+ Ipv4_address_prefix allowed_ip { node.attribute_value("allowed_ip", Ipv4_address_prefix { }) };
+
+ uint8_t public_key[WG_KEY_LEN];
+ if (!public_key_b64.valid() ||
+ !key_from_base64(public_key, public_key_b64.string())) {
+
+ error("Invalid public key!");
+ }
+ if (!allowed_ip.valid()) {
+ error("Invalid allowed ip!");
+ }
+ _callbacks.add_peer(
+ _listen_port, endpoint_ip.addr, endpoint_port, public_key,
+ allowed_ip.address.addr, allowed_ip.prefix);
+
+ return *(
+ new (_alloc)
+ Element(public_key_b64, endpoint_ip, endpoint_port, allowed_ip));
+}
+
+
+bool
+Config_model::
+Peer_update_policy::element_matches_xml_node(Element const &peer,
+ Xml_node node)
+{
+ Ipv4_address endpoint_ip { node.attribute_value("endpoint_ip", Ipv4_address { }) };
+ uint16_t endpoint_port { node.attribute_value("endpoint_port", (uint16_t)0U ) };
+ Key_base64 public_key_b64 { node.attribute_value("public_key", Key_base64 { }) };
+
+ return
+ (endpoint_ip == peer._endpoint_ip) &&
+ (endpoint_port == peer._endpoint_port) &&
+ (public_key_b64 == peer._public_key_b64);
+}
+
+
+bool Config_model::Peer_update_policy::node_is_element(Xml_node node)
+{
+ return node.has_type("peer");
+}
+
+
+/************************
+ ** Config_model::Peer **
+ ************************/
+
+Config_model::Peer::Peer(Key_base64 public_key_b64,
+ Ipv4_address endpoint_ip,
+ uint16_t endpoint_port,
+ Ipv4_address_prefix allowed_ip)
+:
+ _public_key_b64 { public_key_b64 },
+ _endpoint_ip { endpoint_ip },
+ _endpoint_port { endpoint_port },
+ _allowed_ip { allowed_ip }
+{ }
diff --git a/repos/dde_linux/src/app/wireguard/config_model.h b/repos/dde_linux/src/app/wireguard/config_model.h
new file mode 100644
index 0000000000..7467b61927
--- /dev/null
+++ b/repos/dde_linux/src/app/wireguard/config_model.h
@@ -0,0 +1,125 @@
+/*
+ * \brief A differentially updating model of the component configuration
+ * \author Stefan Kalkowski
+ * \author Martin Stein
+ * \date 2022-01-07
+ */
+
+/*
+ * Copyright (C) 2022 Genode Labs GmbH
+ *
+ * This file is part of the Genode OS framework, which is distributed
+ * under the terms of the GNU Affero General Public License version 3.
+ */
+
+#ifndef _CONFIG_MODEL_H_
+#define _CONFIG_MODEL_H_
+
+/* base includes */
+#include
+#include
+#include
+
+/* app/wireguard includes */
+#include
+#include
+#include
+
+namespace Wireguard {
+
+ class Config_model;
+}
+
+
+class Wireguard::Config_model
+{
+ private:
+
+ using Key_base64 = Genode::String;
+
+ class Peer;
+ class Peer_update_policy;
+
+ class Config
+ {
+ private:
+
+ Key_base64 const _private_key_b64;
+ Genode::uint16_t const _listen_port;
+ Net::Ipv4_address_prefix const _interface;
+
+ public:
+
+ Config(Key_base64 private_key_b64,
+ Genode::uint16_t listen_port,
+ Net::Ipv4_address_prefix interface);
+
+
+ Key_base64 const &private_key_b64() const { return _private_key_b64; }
+ Genode::uint16_t listen_port() const { return _listen_port; }
+ Net::Ipv4_address_prefix const &interface() const { return _interface; }
+ };
+
+ Genode::Allocator &_alloc;
+ Genode::Constructible _config { };
+ Genode::List_model _peers { };
+
+ public:
+
+ Config_model(Genode::Allocator &alloc);
+
+ void update(genode_wg_config_callbacks &callbacks,
+ Genode::Xml_node config_node);
+};
+
+
+class Wireguard::Config_model::Peer : public Genode::List_model::Element
+{
+ friend class Peer_update_policy;
+
+ private:
+
+ Key_base64 _public_key_b64;
+ Net::Ipv4_address _endpoint_ip;
+ Genode::uint16_t _endpoint_port;
+ Net::Ipv4_address_prefix _allowed_ip;
+
+ public:
+
+ Peer(Key_base64 public_key_b64,
+ Net::Ipv4_address endpoint_ip,
+ Genode::uint16_t endpoint_port,
+ Net::Ipv4_address_prefix allowed_ip);
+};
+
+
+class Wireguard::Config_model::Peer_update_policy
+:
+ public Genode::List_model::Update_policy
+{
+ private:
+
+ Genode::Allocator &_alloc;
+ genode_wg_config_callbacks &_callbacks;
+ Genode::uint16_t _listen_port;
+
+ public:
+
+ Peer_update_policy(Genode::Allocator &alloc,
+ genode_wg_config_callbacks &callbacks,
+ Genode::uint16_t listen_port);
+
+ void destroy_element(Element &peer);
+
+ Element & create_element(Genode::Xml_node node);
+
+ void update_element(Element &peer,
+ Genode::Xml_node node);
+
+ static bool element_matches_xml_node(Element const &peer,
+ Genode::Xml_node node);
+
+ static bool node_is_element(Genode::Xml_node node);
+};
+
+#endif /* _CONFIG_MODEL_H_ */
diff --git a/repos/dde_linux/src/app/wireguard/dhcp.h b/repos/dde_linux/src/app/wireguard/dhcp.h
new file mode 100644
index 0000000000..19cb0f881b
--- /dev/null
+++ b/repos/dde_linux/src/app/wireguard/dhcp.h
@@ -0,0 +1,30 @@
+/*
+ * \brief DHCP related local utilities
+ * \author Martin Stein
+ * \date 2021-02-10
+ */
+
+/*
+ * Copyright (C) 2021 Genode Labs GmbH
+ *
+ * This file is part of the Genode OS framework, which is distributed
+ * under the terms of the GNU Affero General Public License version 3.
+ */
+
+#ifndef _DHCP_H_
+#define _DHCP_H_
+
+/* os includes */
+#include
+
+namespace Net {
+
+ template
+ static Ipv4_address dhcp_ipv4_option(Dhcp_packet &dhcp)
+ {
+ try { return dhcp.option().value(); }
+ catch (Dhcp_packet::Option_not_found) { return Ipv4_address { }; }
+ }
+}
+
+#endif /* _DHCP_H_ */
diff --git a/repos/dde_linux/src/app/wireguard/dhcp_client.cc b/repos/dde_linux/src/app/wireguard/dhcp_client.cc
new file mode 100644
index 0000000000..27191bed94
--- /dev/null
+++ b/repos/dde_linux/src/app/wireguard/dhcp_client.cc
@@ -0,0 +1,285 @@
+/*
+ * \brief DHCP client state model
+ * \author Martin Stein
+ * \date 2016-08-24
+ */
+
+/*
+ * Copyright (C) 2016-2017 Genode Labs GmbH
+ *
+ * This file is part of the Genode OS framework, which is distributed
+ * under the terms of the GNU Affero General Public License version 3.
+ */
+
+/* dde_linux wireguard includes */
+#include
+#include
+
+enum { PKT_SIZE = 1024 };
+
+using namespace Genode;
+using namespace Net;
+using namespace Wireguard;
+
+using Message_type = Dhcp_packet::Message_type;
+using Dhcp_options = Dhcp_packet::Options_aggregator;
+
+
+/***************
+ ** Utilities **
+ ***************/
+
+void append_param_req_list(Dhcp_options &dhcp_opts)
+{
+ dhcp_opts.append_param_req_list([&] (Dhcp_options::Parameter_request_list_data &data) {
+ data.append_param_req();
+ data.append_param_req();
+ data.append_param_req();
+ data.append_param_req();
+ data.append_param_req();
+ data.append_param_req();
+ data.append_param_req();
+ });
+}
+
+
+/*****************
+ ** Dhcp_client **
+ *****************/
+
+Dhcp_client::Dhcp_client(Timer::Connection &timer,
+ Nic_connection &nic_connection)
+:
+ _nic_connection { nic_connection },
+ _timeout { timer, *this, &Dhcp_client::_handle_timeout }
+{ }
+
+
+void Dhcp_client::discover()
+{
+ _set_state(State::SELECT, _nic_connection.dhcp_discover_timeout());
+ _send(Message_type::DISCOVER, Ipv4_address(), Ipv4_address(),
+ Ipv4_address());
+}
+
+
+void Dhcp_client::_rerequest(State next_state)
+{
+ _set_state(next_state, _rerequest_timeout(2));
+ Ipv4_address const client_ip {
+ _nic_connection.ip_config().interface().address };
+
+ _send(Message_type::REQUEST, client_ip, Ipv4_address(), client_ip);
+}
+
+
+void Dhcp_client::_set_state(State state, Microseconds timeout)
+{
+ _state = state;
+ _timeout.schedule(timeout);
+}
+
+
+Microseconds Dhcp_client::_rerequest_timeout(unsigned lease_time_div_log2)
+{
+ /* FIXME limit the time because of shortcomings in timeout framework */
+ enum { MAX_TIMEOUT_SEC = 3600 };
+ uint64_t timeout_sec = _lease_time_sec >> lease_time_div_log2;
+
+ if (timeout_sec > MAX_TIMEOUT_SEC) {
+ timeout_sec = MAX_TIMEOUT_SEC;
+ if (_nic_connection.verbose()) {
+ log("DHCP client: prune re-request timeout");
+ }
+ }
+ return Microseconds(timeout_sec * 1000 * 1000);
+}
+
+
+void Dhcp_client::_handle_timeout(Duration)
+{
+ switch (_state) {
+ case State::BOUND:
+
+ _rerequest(State::RENEW);
+ break;
+
+ case State::RENEW:
+
+ _rerequest(State::REBIND);
+ break;
+
+ case State::REBIND:
+
+ _nic_connection.discard_ip_config();
+ discover();
+ break;
+
+ default:
+
+ discover();
+ break;
+ }
+}
+
+
+void Dhcp_client::handle_eth(Ethernet_frame ð,
+ Size_guard &size_guard)
+{
+ if (eth.dst() != _nic_connection.mac_address() &&
+ eth.dst() != Mac_address(0xff))
+ {
+ log("DHCP client: drop packet - ETH.DST does not target me");
+ return;
+ }
+ if (eth.type() != Ethernet_frame::Type::IPV4) {
+ log("DHCP client: drop packet - ETH.TYPE is not IPV4");
+ return;
+ }
+ Ipv4_packet &ip { eth.data(size_guard) };
+ if (ip.protocol() != Ipv4_packet::Protocol::UDP) {
+ log("DHCP client: drop packet - IPV4.PROTOCOL is not UDP");
+ return;
+ }
+ Udp_packet &udp { ip.data(size_guard) };
+ if (!Dhcp_packet::is_dhcp(&udp)) {
+ log("DHCP client: drop packet - UDP does not carry DHCP");
+ return;
+ }
+ Dhcp_packet &dhcp = udp.data(size_guard);
+ if (dhcp.op() != Dhcp_packet::REPLY) {
+ log("DHCP client: drop packet - DHCP.OP is not REPLY");
+ return;
+ }
+ if (dhcp.client_mac() != _nic_connection.mac_address()) {
+ log("DHCP client: drop packet - DHCP.CLIENT_MAC is not my MAC address");
+ return;
+ }
+ try {
+ Message_type const msg_type =
+ dhcp.option().value();
+
+ switch (_state) {
+ case State::SELECT:
+
+ if (msg_type != Message_type::OFFER) {
+ log("DHCP client: drop packet - DHCP.MSG_TYPE is not OFFER");
+ return;
+ }
+ _set_state(State::REQUEST, _nic_connection.dhcp_request_timeout());
+ _send(Message_type::REQUEST, Ipv4_address(),
+ dhcp.option().value(),
+ dhcp.yiaddr());
+
+ break;
+
+ case State::REQUEST:
+ {
+ if (msg_type != Message_type::ACK) {
+ log("DHCP client: drop packet - DHCP.MSG_TYPE is not ACK (state REQUEST)");
+ return;
+ }
+ _lease_time_sec = dhcp.option().value();
+ _set_state(State::BOUND, _rerequest_timeout(1));
+ _nic_connection.ip_config_from_dhcp_ack(dhcp);
+ break;
+ }
+ case State::RENEW:
+ case State::REBIND:
+
+ if (msg_type != Message_type::ACK) {
+ log("DHCP client: drop packet - DHCP.MSG_TYPE is not ACK (state RENEW/REBIND)");
+ return;
+ }
+ _set_state(State::BOUND, _rerequest_timeout(1));
+ _lease_time_sec = dhcp.option().value();
+ break;
+
+ default:
+
+ log("DHCP client: drop packet - client doesn't expect reply");
+ return;
+ }
+ }
+ catch (Dhcp_packet::Option_not_found) {
+
+ log("DHCP client: drop packet - DHCP.MSG_TYPE missing");
+ return;
+ }
+}
+
+
+void Dhcp_client::_send(Message_type msg_type,
+ Ipv4_address client_ip,
+ Ipv4_address server_ip,
+ Ipv4_address requested_ip)
+{
+ Mac_address client_mac = _nic_connection.mac_address();
+ _nic_connection.send(PKT_SIZE, [&] (void *pkt_base, Size_guard &size_guard) {
+
+ /* create ETH header of the request */
+ Ethernet_frame ð = Ethernet_frame::construct_at(pkt_base, size_guard);
+ eth.dst(Mac_address(0xff));
+ eth.src(client_mac);
+ eth.type(Ethernet_frame::Type::IPV4);
+
+ /* create IP header of the request */
+ enum { IPV4_TIME_TO_LIVE = 64 };
+ size_t const ip_off = size_guard.head_size();
+ Ipv4_packet &ip = eth.construct_at_data(size_guard);
+ ip.header_length(sizeof(Ipv4_packet) / 4);
+ ip.version(4);
+ ip.time_to_live(IPV4_TIME_TO_LIVE);
+ ip.protocol(Ipv4_packet::Protocol::UDP);
+ ip.src(client_ip);
+ ip.dst(Ipv4_address(0xff));
+
+ /* create UDP header of the request */
+ size_t const udp_off = size_guard.head_size();
+ Udp_packet &udp = ip.construct_at_data(size_guard);
+ udp.src_port(Port(Dhcp_packet::BOOTPC));
+ udp.dst_port(Port(Dhcp_packet::BOOTPS));
+
+ /* create mandatory DHCP fields of the request */
+ size_t const dhcp_off = size_guard.head_size();
+ Dhcp_packet &dhcp = udp.construct_at_data(size_guard);
+ dhcp.op(Dhcp_packet::REQUEST);
+ dhcp.htype(Dhcp_packet::Htype::ETH);
+ dhcp.hlen(sizeof(Mac_address));
+ dhcp.ciaddr(client_ip);
+ dhcp.client_mac(client_mac);
+ dhcp.default_magic_cookie();
+
+ /* append DHCP option fields to the request */
+ Dhcp_options dhcp_opts(dhcp, size_guard);
+ dhcp_opts.append_option(msg_type);
+ switch (msg_type) {
+ case Message_type::DISCOVER:
+ append_param_req_list(dhcp_opts);
+ dhcp_opts.append_option(client_mac);
+ dhcp_opts.append_option((uint16_t)(PKT_SIZE - dhcp_off));
+ break;
+
+ case Message_type::REQUEST:
+ append_param_req_list(dhcp_opts);
+ dhcp_opts.append_option(client_mac);
+ dhcp_opts.append_option((uint16_t)(PKT_SIZE - dhcp_off));
+ if (_state == State::REQUEST) {
+ dhcp_opts.append_option(requested_ip);
+ dhcp_opts.append_option(server_ip);
+ }
+ break;
+
+ default:
+ class Bad_dhcp_message_type { };
+ throw Bad_dhcp_message_type { };
+ }
+ dhcp_opts.append_option();
+
+ /* fill in header values that need the packet to be complete already */
+ udp.length((uint16_t)(size_guard.head_size() - udp_off));
+ udp.update_checksum(ip.src(), ip.dst());
+ ip.total_length(size_guard.head_size() - ip_off);
+ ip.update_checksum();
+ });
+}
diff --git a/repos/dde_linux/src/app/wireguard/dhcp_client.h b/repos/dde_linux/src/app/wireguard/dhcp_client.h
new file mode 100644
index 0000000000..2f9ff8727a
--- /dev/null
+++ b/repos/dde_linux/src/app/wireguard/dhcp_client.h
@@ -0,0 +1,72 @@
+/*
+ * \brief DHCP client state model
+ * \author Martin Stein
+ * \date 2016-08-24
+ */
+
+/*
+ * Copyright (C) 2016-2022 Genode Labs GmbH
+ *
+ * This file is part of the Genode OS framework, which is distributed
+ * under the terms of the GNU Affero General Public License version 3.
+ */
+
+#ifndef _DHCP_CLIENT_H_
+#define _DHCP_CLIENT_H_
+
+/* base includes */
+#include
+
+/* dde_linux wireguard includes */
+#include
+
+namespace Wireguard {
+
+ class Nic_connection;
+}
+
+namespace Net {
+
+ class Ethernet_frame;
+ class Dhcp_client;
+}
+
+class Net::Dhcp_client
+{
+ private:
+
+ enum class State
+ {
+ INIT = 0, SELECT = 1, REQUEST = 2, BOUND = 3, RENEW = 4, REBIND = 5
+ };
+
+ Wireguard::Nic_connection &_nic_connection;
+ State _state { State::INIT };
+ Timer::One_shot_timeout _timeout;
+ Genode::uint64_t _lease_time_sec = 0;
+
+ void _handle_timeout(Genode::Duration);
+
+ void _rerequest(State next_state);
+
+ Genode::Microseconds _rerequest_timeout(unsigned lease_time_div_log2);
+
+ void _set_state(State state, Genode::Microseconds timeout);
+
+ void _send(Dhcp_packet::Message_type msg_type,
+ Ipv4_address client_ip,
+ Ipv4_address server_ip,
+ Ipv4_address requested_ip);
+
+ public:
+
+ Dhcp_client(Timer::Connection &timer,
+ Wireguard::Nic_connection &nic_connection);
+
+ void handle_eth(Ethernet_frame ð,
+ Size_guard &size_guard);
+
+ void discover();
+};
+
+#endif /* _DHCP_CLIENT_H_ */
diff --git a/repos/dde_linux/src/app/wireguard/dummies.c b/repos/dde_linux/src/app/wireguard/dummies.c
new file mode 100644
index 0000000000..00c74a70d4
--- /dev/null
+++ b/repos/dde_linux/src/app/wireguard/dummies.c
@@ -0,0 +1,269 @@
+/**
+ * \brief Dummy definitions of Linux Kernel functions
+ * \author Stefan Kalkowski
+ * \author Martin Stein
+ * \date 2022-01-07
+ */
+
+/*
+ * Copyright (C) 2022 Genode Labs GmbH
+ *
+ * This file is distributed under the terms of the GNU General Public License
+ * version 2.
+ */
+
+#include
+
+
+#include
+
+int __cpuhp_setup_state(enum cpuhp_state state,const char * name,bool invoke,int (* startup)(unsigned int cpu),int (* teardown)(unsigned int cpu),bool multi_instance)
+{
+ lx_emul_trace(__func__);
+ return 0;
+}
+
+
+#include
+struct pt_regs * __irq_regs = NULL;
+
+
+#include
+
+int __preempt_count = 0;
+
+
+#include
+
+void account_process_tick(struct task_struct * p,int user_tick)
+{
+ lx_emul_trace(__func__);
+}
+
+
+#include
+
+int add_random_ready_callback(struct random_ready_callback * rdy)
+{
+ lx_emul_trace(__func__);
+ return 0;
+}
+
+
+extern int __init buses_init(void);
+int __init buses_init(void)
+{
+ lx_emul_trace(__func__);
+ return 0;
+}
+
+
+#include
+
+void calc_global_load(void)
+{
+ lx_emul_trace(__func__);
+}
+
+
+extern int __init classes_init(void);
+int __init classes_init(void)
+{
+ lx_emul_trace(__func__);
+ return 0;
+}
+
+
+extern int __init devices_init(void);
+int __init devices_init(void)
+{
+ lx_emul_trace(__func__);
+ return 0;
+}
+
+
+#include
+
+int __init early_irq_init(void)
+{
+ lx_emul_trace(__func__);
+ return 0;
+}
+
+
+#include
+#include
+
+int generic_handle_irq(unsigned int irq)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+const struct trace_print_flags gfpflag_names[] = { {0,NULL}};
+
+
+#include
+
+void ignore_signals(struct task_struct * t)
+{
+ lx_emul_trace(__func__);
+}
+
+
+#include
+
+const struct ipv6_stub *ipv6_stub = NULL;
+
+
+#include
+
+unsigned long net_rand_noise;
+
+
+#include
+
+const struct trace_print_flags pageflag_names[] = { {0,NULL}};
+
+
+extern int __init platform_bus_init(void);
+int __init platform_bus_init(void)
+{
+ lx_emul_trace(__func__);
+ return 0;
+}
+
+
+#include
+#include
+#include
+
+void rcu_barrier(void)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+void rcu_sched_clock_irq(int user)
+{
+ lx_emul_trace(__func__);
+}
+
+
+#include
+
+int register_netdevice(struct net_device * dev)
+{
+ lx_emul_trace(__func__);
+ return 0;
+}
+
+
+#include
+
+int register_pernet_device(struct pernet_operations * ops)
+{
+ lx_emul_trace(__func__);
+ return 0;
+}
+
+
+#include
+
+void register_syscore_ops(struct syscore_ops * ops)
+{
+ lx_emul_trace(__func__);
+}
+
+
+#include
+
+void sk_set_memalloc(struct sock * sk)
+{
+ lx_emul_trace(__func__);
+}
+
+
+#include
+
+void synchronize_net(void)
+{
+ lx_emul_trace(__func__);
+}
+
+
+#include
+
+void update_vsyscall(struct timekeeper * tk)
+{
+ lx_emul_trace(__func__);
+}
+
+
+#include
+
+const struct trace_print_flags vmaflag_names[] = { {0,NULL}};
+
+
+#include
+
+void rtnl_lock(void)
+{
+ lx_emul_trace(__func__);
+}
+
+
+#include
+
+void rtnl_unlock(void)
+{
+ lx_emul_trace(__func__);
+}
+
+
+#include
+
+void do_trace_netlink_extack(const char * msg)
+{
+ lx_emul_trace(__func__);
+}
+
+
+#include
+
+void napi_enable(struct napi_struct * n)
+{
+ lx_emul_trace(__func__);
+}
+
+
+#include
+
+struct mem_section ** mem_section = NULL;
+
+
+unsigned long phys_base = 0;
+
+
+#include
+
+DEFINE_STATIC_KEY_FALSE(bpf_stats_enabled_key);
+
+
+#include
+
+int net_ratelimit(void)
+{
+ lx_emul_trace(__func__);
+ return 0;
+}
+
+
+__wsum csum_partial(const void * buff,int len,__wsum sum)
+{
+ lx_emul_trace_and_stop(__func__);
+}
diff --git a/repos/dde_linux/src/app/wireguard/genode_c_api/wireguard.c b/repos/dde_linux/src/app/wireguard/genode_c_api/wireguard.c
new file mode 100644
index 0000000000..538250259b
--- /dev/null
+++ b/repos/dde_linux/src/app/wireguard/genode_c_api/wireguard.c
@@ -0,0 +1,468 @@
+/*
+ * \brief Glue code between Genode C++ code and Wireguard C code
+ * \author Martin Stein
+ * \date 2022-01-07
+ */
+
+/*
+ * Copyright (C) 2022 Genode Labs GmbH
+ *
+ * This file is part of the Genode OS framework, which is distributed
+ * under the terms of the GNU Affero General Public License version 3.
+ */
+
+/* app/wireguard includes */
+#include
+#include
+
+/* contrib linux includes */
+#include <../drivers/net/wireguard/device.h>
+#include <../drivers/net/wireguard/messages.h>
+#include
+#include
+#include
+
+
+/*
+ * The contrib code expects the private device data to be located directly
+ + behind the public data with a certain alignment. It does pointer arithmetic
+ * based on a pointer to the public data in order to determine the private
+ * data's base.
+ */
+struct genode_wg_net_device
+{
+ struct net_device public_data;
+ struct wg_device private_data __attribute__((aligned(NETDEV_ALIGN)));
+ int pcpu_refcnt;
+}
+__attribute__((aligned(NETDEV_ALIGN), packed));
+
+
+struct genode_wg_nlattr_ifname
+{
+ struct nlattr header;
+ genode_wg_u8_t data[1] __attribute__((aligned(NLA_ALIGNTO)));
+}
+__attribute__((aligned(NLA_ALIGNTO), packed));
+
+
+struct genode_wg_nlattr_private_key
+{
+ struct nlattr header;
+ genode_wg_u8_t data[NOISE_PUBLIC_KEY_LEN] __attribute__((aligned(NLA_ALIGNTO)));
+}
+__attribute__((aligned(NLA_ALIGNTO), packed));
+
+
+struct genode_wg_nlattr_public_key
+{
+ struct nlattr header;
+ genode_wg_u8_t data[NOISE_PUBLIC_KEY_LEN] __attribute__((aligned(NLA_ALIGNTO)));
+}
+__attribute__((aligned(NLA_ALIGNTO), packed));
+
+
+struct genode_wg_nlattr_u8
+{
+ struct nlattr header;
+ genode_wg_u8_t data __attribute__((aligned(NLA_ALIGNTO)));
+}
+__attribute__((aligned(NLA_ALIGNTO), packed));
+
+
+struct genode_wg_nlattr_u16
+{
+ struct nlattr header;
+ genode_wg_u16_t data __attribute__((aligned(NLA_ALIGNTO)));
+}
+__attribute__((aligned(NLA_ALIGNTO), packed));
+
+
+struct genode_wg_nlattr_u32
+{
+ struct nlattr header;
+ genode_wg_u32_t data __attribute__((aligned(NLA_ALIGNTO)));
+}
+__attribute__((aligned(NLA_ALIGNTO), packed));
+
+
+struct genode_wg_nlattr_in_addr
+{
+ struct nlattr header;
+ struct in_addr data __attribute__((aligned(NLA_ALIGNTO)));
+}
+__attribute__((aligned(NLA_ALIGNTO), packed));
+
+
+struct genode_wg_nlattr_sockaddr
+{
+ struct nlattr header;
+ struct sockaddr data __attribute__((aligned(NLA_ALIGNTO)));
+}
+__attribute__((aligned(NLA_ALIGNTO), packed));
+
+
+struct genode_wg_nlattr_allowedip
+{
+ struct nlattr header;
+ struct genode_wg_nlattr_u16 family __attribute__((aligned(NLA_ALIGNTO)));
+ struct genode_wg_nlattr_in_addr ipaddr __attribute__((aligned(NLA_ALIGNTO)));
+ struct genode_wg_nlattr_u8 cidr_mask __attribute__((aligned(NLA_ALIGNTO)));
+}
+__attribute__((aligned(NLA_ALIGNTO), packed));
+
+
+struct genode_wg_nlattr_allowedips
+{
+ struct nlattr header;
+ struct genode_wg_nlattr_allowedip ip_0 __attribute__((aligned(NLA_ALIGNTO)));
+}
+__attribute__((aligned(NLA_ALIGNTO), packed));
+
+
+struct genode_wg_nlattr_peer
+{
+ struct nlattr header;
+ struct genode_wg_nlattr_public_key public_key __attribute__((aligned(NLA_ALIGNTO)));
+ struct genode_wg_nlattr_sockaddr endpoint __attribute__((aligned(NLA_ALIGNTO)));
+ struct genode_wg_nlattr_u32 flags __attribute__((aligned(NLA_ALIGNTO)));
+ struct genode_wg_nlattr_allowedips allowedips __attribute__((aligned(NLA_ALIGNTO)));
+}
+__attribute__((aligned(NLA_ALIGNTO), packed));
+
+
+struct genode_wg_nlattr_peers
+{
+ struct nlattr header;
+ struct genode_wg_nlattr_peer peer_0 __attribute__((aligned(NLA_ALIGNTO)));
+}
+__attribute__((aligned(NLA_ALIGNTO), packed));
+
+
+static struct genode_wg_net_device _genode_wg_net_dev;
+static struct net _genode_wg_src_net;
+static struct nlattr *_genode_wg_tb[1];
+static struct nlattr *_genode_wg_data[1];
+static struct netlink_ext_ack _genode_wg_extack;
+static struct rtnl_link_ops *_genode_wg_rtnl_link_ops;
+static struct genl_family *_genode_wg_genl_family;
+static struct socket _genode_wg_socket;
+
+/* for the call to wg_set_device that installs listen port and private key */
+static struct sock _genode_wg_sock;
+static struct sk_buff _genode_wg_sk_buff;
+static struct udp_tunnel_sock_cfg _genode_wg_udp_tunnel_cfg;
+genode_wg_u16_t _genode_wg_listen_port;
+
+
+genode_wg_u16_t genode_wg_listen_port(void)
+{
+ return _genode_wg_listen_port;
+}
+
+
+void genode_wg_rtnl_link_ops(struct rtnl_link_ops *ops)
+{
+ _genode_wg_rtnl_link_ops = ops;
+}
+
+
+void genode_wg_genl_family(struct genl_family * family)
+{
+ _genode_wg_genl_family = family;
+}
+
+
+struct net_device * genode_wg_net_device(void)
+{
+ return &_genode_wg_net_dev.public_data;
+}
+
+void genode_wg_udp_tunnel_sock_cfg(struct udp_tunnel_sock_cfg * cfg)
+{
+ _genode_wg_udp_tunnel_cfg = *cfg;
+}
+
+
+/**
+ * Call 'wg_set_device' in the contrib code
+ */
+static void
+_genode_wg_set_device(struct genl_info *info)
+{
+ unsigned idx;
+ bool op_not_found = true;
+
+ for (idx = 0; idx < _genode_wg_genl_family->n_ops; idx++) {
+ if (_genode_wg_genl_family->ops[idx].cmd == WG_CMD_SET_DEVICE) {
+ int result = _genode_wg_genl_family->ops[idx].doit(&_genode_wg_sk_buff, info);
+ if (result != 0) {
+ printk("Error: op WG_CMD_SET_DEVICE returned %d\n", result);
+ while (1) { }
+ }
+ op_not_found = false;
+ }
+ }
+ if (op_not_found) {
+ printk("Error: cannot find op WG_CMD_SET_DEVICE\n");
+ while (1) { }
+ }
+}
+
+
+void genode_wg_arch_net_dev_init(struct net_device *net_dev,
+ int *pcpu_refcnt);
+
+
+static void
+_genode_wg_config_add_dev(genode_wg_u16_t listen_port,
+ const genode_wg_u8_t * const priv_key)
+{
+ static unsigned called = 0;
+ if (called++) {
+ printk("%s re-called. Reconfiguration not supported yet\n", __func__);
+ return;
+ }
+ _genode_wg_listen_port = listen_port;
+
+ /* prepare environment for the execution of 'wg_set_device' */
+ _genode_wg_net_dev.public_data.rtnl_link_ops = _genode_wg_rtnl_link_ops;
+ _genode_wg_net_dev.pcpu_refcnt = 0;
+ genode_wg_arch_net_dev_init(
+ &_genode_wg_net_dev.public_data, &_genode_wg_net_dev.pcpu_refcnt);
+
+ _genode_wg_sk_buff.sk = &_genode_wg_sock;
+ _genode_wg_sock.sk_user_data = &_genode_wg_net_dev.private_data;
+
+ {
+ struct genode_wg_nlattr_ifname ifname;
+ struct genode_wg_nlattr_u16 port;
+ struct genode_wg_nlattr_private_key private_key;
+ struct nlattr * attrs[__WGDEVICE_A_LAST];
+ struct genl_info info;
+
+ ifname.data[0] = '\0';
+ ifname.header.nla_len = sizeof(ifname);
+
+ port.data = listen_port;
+ port.header.nla_len = sizeof(port);
+
+ memcpy(private_key.data, priv_key, sizeof(private_key.data));
+
+ private_key.header.nla_len = sizeof(private_key);
+
+ memset(attrs, 0, sizeof(attrs));
+ attrs[WGDEVICE_A_IFNAME] = &ifname.header;
+ attrs[WGDEVICE_A_LISTEN_PORT] = &port.header;
+ attrs[WGDEVICE_A_PRIVATE_KEY] = &private_key.header;
+
+ info.attrs = attrs;
+ _genode_wg_set_device(&info);
+ }
+
+ /* prepare environment for the execution of 'wg_open' */
+ _genode_wg_socket.sk = &_genode_wg_sock;
+
+ /* trigger execution of 'wg_open' */
+ _genode_wg_net_dev.public_data.netdev_ops->ndo_open(
+ &_genode_wg_net_dev.public_data);
+}
+
+
+static void _genode_wg_config_rm_dev(genode_wg_u16_t listen_port)
+{
+ printk("%s not yet implemented\n", __func__);
+}
+
+
+static void
+_genode_wg_config_add_peer(genode_wg_u16_t listen_port,
+ genode_wg_u8_t const endpoint_ip[4],
+ genode_wg_u16_t endpoint_port,
+ genode_wg_u8_t const *const pub_key,
+ genode_wg_u8_t const allowed_ip_addr[4],
+ genode_wg_u8_t const allowed_ip_prefix_length)
+{
+ struct genode_wg_nlattr_ifname ifname;
+ struct genode_wg_nlattr_peers peers;
+ struct nlattr *attrs[__WGDEVICE_A_LAST];
+ struct genl_info info;
+ struct genode_wg_nlattr_peer *peer = &peers.peer_0;
+ struct genode_wg_nlattr_allowedip *allowedip = &peer->allowedips.ip_0;
+
+ ifname.data[0] = '\0';
+ ifname.header.nla_len = sizeof(ifname);
+
+ memset(&peers, 0, sizeof(peers));
+
+ peers.header.nla_type = WGDEVICE_A_PEERS | NLA_F_NESTED;
+ peers.header.nla_len = sizeof(peers);
+
+ peer->header.nla_len = sizeof(*peer);
+ peer->header.nla_type |= NLA_F_NESTED;
+
+ peer->public_key.header.nla_type = WGPEER_A_PUBLIC_KEY;
+ peer->public_key.header.nla_len = sizeof(peer->public_key);
+ memcpy(peer->public_key.data, pub_key, sizeof(peer->public_key.data));
+
+ peer->endpoint.header.nla_type = WGPEER_A_ENDPOINT;
+ peer->endpoint.header.nla_len = sizeof(peer->endpoint);
+ peer->endpoint.data.sa_family = AF_INET;
+ peer->endpoint.data.sa_data[0] = ((genode_wg_u8_t*)&endpoint_port)[1];
+ peer->endpoint.data.sa_data[1] = ((genode_wg_u8_t*)&endpoint_port)[0];
+ peer->endpoint.data.sa_data[2] = endpoint_ip[0];
+ peer->endpoint.data.sa_data[3] = endpoint_ip[1];
+ peer->endpoint.data.sa_data[4] = endpoint_ip[2];
+ peer->endpoint.data.sa_data[5] = endpoint_ip[3];
+
+ peer->flags.header.nla_type = WGPEER_A_FLAGS;
+ peer->flags.header.nla_len = sizeof(peer->flags);
+ peer->flags.data = 2; /* I don't know what this value means */
+
+ peer->allowedips.header.nla_len = sizeof(peer->allowedips);
+ peer->allowedips.header.nla_type = WGPEER_A_ALLOWEDIPS | NLA_F_NESTED;
+
+ allowedip->header.nla_type |= NLA_F_NESTED;
+ allowedip->header.nla_len = sizeof(*allowedip);
+
+ allowedip->family.header.nla_type = WGALLOWEDIP_A_FAMILY;
+ allowedip->family.header.nla_len = sizeof(allowedip->family.data) + NLA_HDRLEN;
+ allowedip->family.data = AF_INET;
+
+ allowedip->ipaddr.header.nla_type = WGALLOWEDIP_A_IPADDR;
+ allowedip->ipaddr.header.nla_len = sizeof(allowedip->ipaddr.data) + NLA_HDRLEN;
+ memcpy(&allowedip->ipaddr.data, allowed_ip_addr, 4);
+
+ allowedip->cidr_mask.header.nla_type = WGALLOWEDIP_A_CIDR_MASK;
+ allowedip->cidr_mask.header.nla_len = sizeof(allowedip->cidr_mask.data) + NLA_HDRLEN;
+ allowedip->cidr_mask.data = allowed_ip_prefix_length;
+
+ memset(attrs, 0, sizeof(attrs));
+ attrs[WGDEVICE_A_IFNAME] = &ifname.header;
+ attrs[WGDEVICE_A_PEERS] = &peers.header;
+
+ info.attrs = attrs;
+ _genode_wg_set_device(&info);
+}
+
+
+static void
+_genode_wg_config_rm_peer(genode_wg_u16_t listen_port,
+ genode_wg_u8_t const endpoint_ip[4],
+ genode_wg_u16_t endpoint_port)
+{
+ printk("%s not yet implemented\n", __func__);
+}
+
+
+static struct genode_wg_config_callbacks _config_callbacks = {
+ .add_device = _genode_wg_config_add_dev,
+ .remove_device = _genode_wg_config_rm_dev,
+ .add_peer = _genode_wg_config_add_peer,
+ .remove_peer = _genode_wg_config_rm_peer
+};
+
+
+static void _genode_wg_uplink_connection_receive(void *buf_base,
+ genode_wg_size_t buf_size)
+{
+ struct iphdr * ip;
+ size_t data_offset;
+ struct sk_buff *skb = alloc_skb(buf_size, GFP_KERNEL);
+ if (!skb) {
+ printk("Error: alloc_skb failed!\n");
+ return;
+ }
+
+ skb_reset_network_header(skb);
+ memcpy(skb_put(skb, buf_size), buf_base, buf_size);
+ skb->protocol = htons(ETH_P_IP);
+ skb->dev = genode_wg_net_device();
+
+ skb_pull(skb, ETH_HLEN);
+ skb_reset_network_header(skb);
+ ip = ip_hdr(skb);
+ data_offset = ip->ihl * 4;
+
+ genode_wg_net_device()->netdev_ops->ndo_start_xmit(skb, genode_wg_net_device());
+}
+
+
+static void _genode_wg_nic_connection_receive(void *buf_base,
+ genode_wg_size_t buf_size)
+{
+ struct iphdr * ip;
+ size_t data_offset;
+ struct sk_buff *skb = alloc_skb(buf_size, GFP_KERNEL);
+ if (!skb) {
+ printk("Error: alloc_skb failed!\n");
+ return;
+ }
+
+ skb_reset_network_header(skb);
+ memcpy(skb_put(skb, buf_size), buf_base, buf_size);
+ skb->protocol = htons(ETH_P_IP);
+ skb->dev = genode_wg_net_device();
+
+ skb_pull(skb, ETH_HLEN);
+ skb_reset_network_header(skb);
+ ip = ip_hdr(skb);
+ data_offset = ip->ihl * 4;
+
+ skb_pull(skb, data_offset);
+ skb_reset_transport_header(skb);
+ _genode_wg_udp_tunnel_cfg.encap_rcv(&_genode_wg_sock, skb);
+}
+
+
+static int user_task_function(void *arg)
+{
+ for (;;) {
+ genode_wg_update_config(&_config_callbacks);
+
+ genode_wg_net_receive(&_genode_wg_uplink_connection_receive,
+ &_genode_wg_nic_connection_receive);
+
+ /* block until lx_emul_task_unblock */
+ lx_emul_task_schedule(true);
+ }
+ return 0;
+}
+
+
+static struct task_struct * _user_task_struct_ptr = NULL;
+
+
+void lx_user_handle_io(void)
+{
+ if (_user_task_struct_ptr)
+ lx_emul_task_unblock(_user_task_struct_ptr);
+}
+
+
+void genode_wg_arch_lx_user_init(void);
+
+
+void lx_user_init(void)
+{
+ pid_t pid;
+
+ genode_wg_arch_lx_user_init();
+
+ skb_init();
+
+ /* trigger execution of 'wg_setup' */
+ _genode_wg_rtnl_link_ops->setup(&_genode_wg_net_dev.public_data);
+
+ /* trigger execution of 'wg_newlink' */
+ _genode_wg_rtnl_link_ops->newlink(
+ &_genode_wg_src_net,
+ &_genode_wg_net_dev.public_data,
+ _genode_wg_tb,
+ _genode_wg_data,
+ &_genode_wg_extack);
+
+ /* create user task, which handles network traffic and configuration changes */
+ pid = kernel_thread(user_task_function, NULL, CLONE_FS | CLONE_FILES);
+ _user_task_struct_ptr = find_task_by_pid_ns(pid, NULL);
+}
diff --git a/repos/dde_linux/src/app/wireguard/genode_c_api/wireguard.h b/repos/dde_linux/src/app/wireguard/genode_c_api/wireguard.h
new file mode 100644
index 0000000000..e24225af57
--- /dev/null
+++ b/repos/dde_linux/src/app/wireguard/genode_c_api/wireguard.h
@@ -0,0 +1,95 @@
+/*
+ * \brief Glue code between Genode C++ code and Wireguard C code
+ * \author Martin Stein
+ * \date 2022-01-07
+ */
+
+/*
+ * Copyright (C) 2022 Genode Labs GmbH
+ *
+ * This file is part of the Genode OS framework, which is distributed
+ * under the terms of the GNU Affero General Public License version 3.
+ */
+
+#ifndef _GENODE_C_API__WIREGUARD_H_
+#define _GENODE_C_API__WIREGUARD_H_
+
+enum { GENODE_WG_KEY_LEN = 32 };
+
+typedef unsigned char genode_wg_u8_t;
+typedef unsigned short genode_wg_u16_t;
+typedef unsigned int genode_wg_u32_t;
+typedef unsigned long genode_wg_size_t;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef void (*genode_wg_config_add_dev_t)
+ (genode_wg_u16_t listen_port, const genode_wg_u8_t * const priv_key);
+
+typedef void (*genode_wg_config_rm_dev_t) (genode_wg_u16_t listen_port);
+
+typedef void (*genode_wg_config_add_peer_t) (
+ genode_wg_u16_t listen_port,
+ genode_wg_u8_t const endpoint_ip[4],
+ genode_wg_u16_t endpoint_port,
+ genode_wg_u8_t const *const pub_key,
+ genode_wg_u8_t const allowed_ip_addr[4],
+ genode_wg_u8_t const allowed_ip_prefix
+);
+
+typedef void (*genode_wg_config_rm_peer_t)
+ (genode_wg_u16_t listen_port, genode_wg_u8_t const endpoint_ip[4],
+ genode_wg_u16_t endpoint_port);
+
+
+struct genode_wg_config_callbacks
+{
+ genode_wg_config_add_dev_t add_device;
+ genode_wg_config_rm_dev_t remove_device;
+ genode_wg_config_add_peer_t add_peer;
+ genode_wg_config_rm_peer_t remove_peer;
+};
+
+
+void genode_wg_update_config(struct genode_wg_config_callbacks * callbacks);
+
+
+typedef
+void (*genode_wg_uplink_connection_receive_t)(void *buf_base,
+ genode_wg_size_t buf_size);
+
+
+typedef void (*genode_wg_nic_connection_receive_t)(void *buf_base,
+ genode_wg_size_t buf_size);
+
+
+void
+genode_wg_net_receive(genode_wg_uplink_connection_receive_t uplink_rx_callback,
+ genode_wg_nic_connection_receive_t nic_rx_callback);
+
+
+genode_wg_u16_t genode_wg_listen_port(void);
+
+
+void genode_wg_send_wg_prot_at_nic_connection(
+ genode_wg_u8_t const *wg_prot_base,
+ genode_wg_size_t wg_prot_size,
+ genode_wg_u16_t udp_src_port_big_endian,
+ genode_wg_u16_t udp_dst_port_big_endian,
+ genode_wg_u32_t ipv4_src_addr_big_endian,
+ genode_wg_u32_t ipv4_dst_addr_big_endian,
+ genode_wg_u8_t ipv4_dscp_ecn,
+ genode_wg_u8_t ipv4_ttl);
+
+
+void genode_wg_send_ip_at_uplink_connection(
+ genode_wg_u8_t const *ip_base,
+ genode_wg_size_t ip_size);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _GENODE_C_API__WIREGUARD_H_ */
diff --git a/repos/dde_linux/src/app/wireguard/ipv4_address_prefix.cc b/repos/dde_linux/src/app/wireguard/ipv4_address_prefix.cc
new file mode 100644
index 0000000000..a6abae0065
--- /dev/null
+++ b/repos/dde_linux/src/app/wireguard/ipv4_address_prefix.cc
@@ -0,0 +1,103 @@
+/*
+ * \brief Ipv4 address combined with a subnet prefix length
+ * \author Martin Stein
+ * \date 2017-10-12
+ */
+
+/*
+ * Copyright (C) 2017 Genode Labs GmbH
+ *
+ * This file is part of the Genode OS framework, which is distributed
+ * under the terms of the GNU Affero General Public License version 3.
+ */
+
+/* local includes */
+#include
+
+using namespace Genode;
+using namespace Net;
+
+
+Ipv4_address Ipv4_address_prefix::subnet_mask() const
+{
+ Ipv4_address result;
+ if (prefix >= 8) {
+
+ result.addr[0] = 0xff;
+
+ if (prefix >= 16) {
+
+ result.addr[1] = 0xff;
+
+ if (prefix >= 24) {
+
+ result.addr[2] = 0xff;
+ result.addr[3] = 0xff << (32 - prefix);
+ } else {
+ result.addr[2] = 0xff << (24 - prefix);
+ }
+ } else {
+ result.addr[1] = 0xff << (16 - prefix);
+ }
+ } else {
+ result.addr[0] = 0xff << (8 - prefix);
+ }
+ return result;
+}
+
+
+void Ipv4_address_prefix::print(Genode::Output &output) const
+{
+ Genode::print(output, address, "/", prefix);
+}
+
+
+bool Ipv4_address_prefix::prefix_matches(Ipv4_address const &ip) const
+{
+ uint8_t prefix_left = prefix;
+ uint8_t byte = 0;
+ for (; prefix_left >= 8; prefix_left -= 8, byte++) {
+ if (ip.addr[byte] != address.addr[byte]) {
+ return false; }
+ }
+ if (prefix_left == 0) {
+ return true; }
+
+ uint8_t const mask = (uint8_t)(~(0xff >> prefix_left));
+ return !((ip.addr[byte] ^ address.addr[byte]) & mask);
+}
+
+
+Ipv4_address Ipv4_address_prefix::broadcast_address() const
+{
+ Ipv4_address result = address;
+ Ipv4_address const mask = subnet_mask();
+ for (unsigned i = 0; i < 4; i++) {
+ result.addr[i] |= (uint8_t)(~mask.addr[i]);
+ }
+ return result;
+}
+
+
+Ipv4_address_prefix::Ipv4_address_prefix(Ipv4_address address,
+ Ipv4_address subnet_mask)
+:
+ address(address), prefix(0)
+{
+ Genode::uint8_t rest;
+ if (subnet_mask.addr[0] != 0xff) {
+ rest = subnet_mask.addr[0];
+ prefix = 0;
+ } else if (subnet_mask.addr[1] != 0xff) {
+ rest = subnet_mask.addr[1];
+ prefix = 8;
+ } else if (subnet_mask.addr[2] != 0xff) {
+ rest = subnet_mask.addr[2];
+ prefix = 16;
+ } else {
+ rest = subnet_mask.addr[3];
+ prefix = 24;
+ }
+ for (Genode::uint8_t mask = 1 << 7; rest & mask; mask >>= 1)
+ prefix++;
+}
diff --git a/repos/dde_linux/src/app/wireguard/ipv4_address_prefix.h b/repos/dde_linux/src/app/wireguard/ipv4_address_prefix.h
new file mode 100644
index 0000000000..5d031c9666
--- /dev/null
+++ b/repos/dde_linux/src/app/wireguard/ipv4_address_prefix.h
@@ -0,0 +1,82 @@
+/*
+ * \brief Ipv4 address combined with a subnet prefix length
+ * \author Martin Stein
+ * \date 2017-10-12
+ */
+
+/*
+ * Copyright (C) 2017 Genode Labs GmbH
+ *
+ * This file is part of the Genode OS framework, which is distributed
+ * under the terms of the GNU Affero General Public License version 3.
+ */
+
+#ifndef _IPV4_ADDRESS_PREFIX_H_
+#define _IPV4_ADDRESS_PREFIX_H_
+
+/* Genode includes */
+#include
+
+namespace Net {
+ class Ipv4_address_prefix;
+
+ static inline Genode::size_t ascii_to(char const *, Net::Ipv4_address_prefix &);
+}
+
+
+struct Net::Ipv4_address_prefix
+{
+ Ipv4_address address { };
+ Genode::uint8_t prefix;
+
+ Ipv4_address_prefix(Ipv4_address address,
+ Ipv4_address subnet_mask);
+
+ Ipv4_address_prefix() : prefix(32) { }
+
+ bool valid() const { return address.valid() || prefix == 0; }
+
+ void print(Genode::Output &output) const;
+
+ bool prefix_matches(Ipv4_address const &ip) const;
+
+ Ipv4_address subnet_mask() const;
+
+ Ipv4_address broadcast_address() const;
+
+ bool operator != (Ipv4_address_prefix const &other) const
+ {
+ return prefix != other.prefix ||
+ address != other.address;
+ }
+};
+
+
+Genode::size_t Net::ascii_to(char const *s, Ipv4_address_prefix &result)
+{
+ using namespace Genode;
+
+ /* read the leading IPv4 address, fail if there's no address */
+ Net::Ipv4_address_prefix buf;
+ size_t read_len = ascii_to(s, buf.address);
+ if (!read_len) {
+ return 0; }
+
+ /* check for the following slash */
+ s += read_len;
+ if (*s != '/') {
+ return 0; }
+ read_len++;
+ s++;
+
+ /* read the prefix, fail if there's no prefix */
+ size_t prefix_len = ascii_to_unsigned(s, buf.prefix, 10);
+ if (!prefix_len) {
+ return 0; }
+
+ /* fill result and return read length */
+ result = buf;
+ return read_len + prefix_len;
+}
+
+#endif /* _IPV4_ADDRESS_PREFIX_H_ */
diff --git a/repos/dde_linux/src/app/wireguard/ipv4_config.cc b/repos/dde_linux/src/app/wireguard/ipv4_config.cc
new file mode 100644
index 0000000000..dbf137076b
--- /dev/null
+++ b/repos/dde_linux/src/app/wireguard/ipv4_config.cc
@@ -0,0 +1,38 @@
+/*
+ * \brief IPv4 peer configuration
+ * \author Martin Stein
+ * \date 2016-08-19
+ */
+
+/*
+ * Copyright (C) 2016-2017 Genode Labs GmbH
+ *
+ * This file is part of the Genode OS framework, which is distributed
+ * under the terms of the GNU Affero General Public License version 3.
+ */
+
+/* dde_linux wireguard includes */
+#include
+
+using namespace Genode;
+using namespace Net;
+using namespace Wireguard;
+
+
+Ipv4_config::Ipv4_config()
+:
+ _interface { }
+{ }
+
+
+Ipv4_config::Ipv4_config(Xml_node const &config_node)
+:
+ _interface { config_node.attribute_value("interface", Ipv4_address_prefix()) }
+{ }
+
+
+Ipv4_config::Ipv4_config(Dhcp_packet &dhcp_ack)
+:
+ _interface { dhcp_ack.yiaddr(),
+ dhcp_ipv4_option(dhcp_ack) }
+{ }
diff --git a/repos/dde_linux/src/app/wireguard/ipv4_config.h b/repos/dde_linux/src/app/wireguard/ipv4_config.h
new file mode 100644
index 0000000000..357009614a
--- /dev/null
+++ b/repos/dde_linux/src/app/wireguard/ipv4_config.h
@@ -0,0 +1,59 @@
+/*
+ * \brief IPv4 peer configuration
+ * \author Martin Stein
+ * \date 2016-08-19
+ */
+
+/*
+ * Copyright (C) 2016-2017 Genode Labs GmbH
+ *
+ * This file is part of the Genode OS framework, which is distributed
+ * under the terms of the GNU Affero General Public License version 3.
+ */
+
+#ifndef _IPV4_CONFIG_H_
+#define _IPV4_CONFIG_H_
+
+/* local includes */
+#include
+#include
+
+/* Genode includes */
+#include
+
+namespace Wireguard {
+
+ class Ipv4_config;
+}
+
+class Wireguard::Ipv4_config
+{
+ private:
+
+ Net::Ipv4_address_prefix const _interface;
+ bool const _interface_valid { _interface.valid() };
+ bool const _valid { _interface_valid };
+
+ public:
+
+ Ipv4_config(Net::Dhcp_packet &dhcp_ack);
+
+ Ipv4_config(Genode::Xml_node const &config_node);
+
+ Ipv4_config();
+
+ bool operator != (Ipv4_config const &other) const
+ {
+ return _interface != other._interface;
+ }
+
+
+ /***************
+ ** Accessors **
+ ***************/
+
+ bool valid() const { return _valid; }
+ Net::Ipv4_address_prefix const &interface() const { return _interface; }
+};
+
+#endif /* _IPV4_CONFIG_H_ */
diff --git a/repos/dde_linux/src/app/wireguard/irq.cc b/repos/dde_linux/src/app/wireguard/irq.cc
new file mode 100644
index 0000000000..c8cc4fcd13
--- /dev/null
+++ b/repos/dde_linux/src/app/wireguard/irq.cc
@@ -0,0 +1,18 @@
+
+#include
+#include
+
+
+extern "C" void lx_emul_irq_unmask(unsigned int ) { }
+
+
+extern "C" void lx_emul_irq_mask(unsigned int ) { }
+
+
+extern "C" void lx_emul_irq_eoi(unsigned int ) { }
+
+
+extern "C" unsigned int lx_emul_irq_last()
+{
+ return Lx_kit::env().last_irq;
+}
diff --git a/repos/dde_linux/src/app/wireguard/list.h b/repos/dde_linux/src/app/wireguard/list.h
new file mode 100644
index 0000000000..2fda07d77a
--- /dev/null
+++ b/repos/dde_linux/src/app/wireguard/list.h
@@ -0,0 +1,102 @@
+/*
+ * \brief Genode list with additional functions needed by NIC router
+ * \author Martin Stein
+ * \date 2016-08-19
+ */
+
+/*
+ * Copyright (C) 2016-2017 Genode Labs GmbH
+ *
+ * This file is part of the Genode OS framework, which is distributed
+ * under the terms of the GNU Affero General Public License version 3.
+ */
+
+#ifndef _LIST_H_
+#define _LIST_H_
+
+/* Genode includes */
+#include
+#include
+
+namespace Net { template class List; }
+
+
+template
+struct Net::List : Genode::List
+{
+ using Base = Genode::List;
+
+ template
+ void for_each(FUNC && functor)
+ {
+ for (LT *elem = Base::first(); elem; )
+ {
+ LT *const next = elem->Base::Element::next();
+ functor(*elem);
+ elem = next;
+ }
+ }
+
+ template
+ void for_each(FUNC && functor) const
+ {
+ for (LT const *elem = Base::first(); elem; )
+ {
+ LT const *const next = elem->Base::Element::next();
+ functor(*elem);
+ elem = next;
+ }
+ }
+
+ void destroy_each(Genode::Deallocator &dealloc)
+ {
+ while (LT *elem = Base::first()) {
+ Base::remove(elem);
+ destroy(dealloc, elem);
+ }
+ }
+
+ bool empty() const
+ {
+ return Base::first() == nullptr;
+ }
+
+ void insert_as_tail(LT const &le)
+ {
+ LT *elem { Base::first() };
+ if (elem) {
+ while (elem->Base::Element::next()) {
+ elem = elem->Base::Element::next();
+ }
+ }
+ Base::insert(&le, elem);
+ }
+
+ bool equal_to(List const &list) const
+ {
+ LT const *curr_elem_1 { Base::first() };
+ LT const *curr_elem_2 { list.Base::first() };
+ while (true) {
+
+ if (curr_elem_1 == nullptr) {
+ return curr_elem_2 == nullptr;
+ }
+ if (curr_elem_2 == nullptr) {
+ return false;
+ }
+ LT const *const next_elem_1 {
+ curr_elem_1->List::Element::next() };
+
+ LT const *const next_elem_2 {
+ curr_elem_2->List::Element::next() };
+
+ if (!curr_elem_1->equal_to(*curr_elem_2)) {
+ return false;
+ }
+ curr_elem_1 = next_elem_1;
+ curr_elem_2 = next_elem_2;
+ }
+ }
+};
+
+#endif /* _LIST_H_ */
diff --git a/repos/dde_linux/src/app/wireguard/lx_emul.c b/repos/dde_linux/src/app/wireguard/lx_emul.c
new file mode 100644
index 0000000000..730dc18635
--- /dev/null
+++ b/repos/dde_linux/src/app/wireguard/lx_emul.c
@@ -0,0 +1,376 @@
+/**
+ * \brief Dummy definitions of lx_emul
+ * \author Stefan Kalkowski
+ * \date 2022-01-10
+ */
+
+/*
+ * Copyright (C) 2022 Genode Labs GmbH
+ *
+ * This file is distributed under the terms of the GNU General Public License
+ * version 2.
+ */
+
+/* app/wireguard includes */
+#include
+
+#include
+#include
+
+void get_random_bytes(void * buf,int nbytes)
+{
+ lx_emul_random_bytes(buf, nbytes);
+}
+
+
+#include
+
+int wait_for_random_bytes(void)
+{
+ lx_emul_trace(__func__);
+ return 0;
+}
+
+
+#include
+
+u32 get_random_u32(void)
+{
+ u8 buf[4];
+ lx_emul_random_bytes(buf, sizeof(buf));
+ return *((u32*)&buf);
+}
+
+
+#include
+
+u32 prandom_u32(void)
+{
+ u8 buf[4];
+ lx_emul_random_bytes(buf, sizeof(buf));
+ return *((u32*)&buf);
+}
+
+
+#include
+
+int __must_check get_random_bytes_arch(void * buf,int nbytes)
+{
+ lx_emul_random_bytes(buf, nbytes);
+ return 0;
+}
+
+
+#include
+
+void * kmalloc_order(size_t size,gfp_t flags,unsigned int order)
+{
+ return kmalloc(size, flags);
+}
+
+
+#include
+
+void * kvmalloc_node(size_t size,gfp_t flags,int node)
+{
+ return kmalloc(size, flags);
+}
+
+
+#include
+
+extern void genode_wg_rtnl_link_ops(struct rtnl_link_ops * ops);
+
+int rtnl_link_register(struct rtnl_link_ops * ops)
+{
+ genode_wg_rtnl_link_ops(ops);
+ return 0;
+}
+
+
+#include
+
+extern void genode_wg_genl_family(struct genl_family * family);
+
+int genl_register_family(struct genl_family * family)
+{
+ genode_wg_genl_family(family);
+ return 0;
+}
+
+
+#include
+
+extern struct net_device * genode_wg_net_device(void);
+
+struct net_device * dev_get_by_name(struct net * net,const char * name)
+{
+ return genode_wg_net_device();
+}
+
+
+#include
+
+int udp_sock_create4(struct net * net,struct udp_port_cfg * cfg,struct socket ** sockp)
+{
+ *sockp = (struct socket*) kmalloc(sizeof(struct socket), GFP_KERNEL);
+ (*sockp)->sk = (struct sock*) kmalloc(sizeof(struct sock), GFP_KERNEL);
+ return 0;
+}
+
+
+#include
+
+extern void genode_wg_udp_tunnel_sock_cfg(struct udp_tunnel_sock_cfg * cfg);
+
+void setup_udp_tunnel_sock(struct net * net,struct socket * sock,struct udp_tunnel_sock_cfg * cfg)
+{
+ genode_wg_udp_tunnel_sock_cfg(cfg);
+}
+
+
+#include
+
+bool ipv6_mod_enabled(void)
+{
+ return false;
+}
+
+
+#include
+#include
+
+void udp_tunnel_xmit_skb(
+ struct rtable * rt,struct sock * sk,struct sk_buff * skb,
+ __be32 src,__be32 dst,__u8 tos,__u8 ttl,__be16 df,
+ __be16 src_port,__be16 dst_port,bool xnet,bool nocheck)
+{
+ /*
+ * FIXME
+ *
+ * I don't propagate these values because I found that, at the call to
+ * udp_tunnel_xmit_skb, Linux sets them hard to the values I'm checking
+ * for in the following. Furthermore, I assume that they should not be
+ * relevant for the port anyway.
+ */
+ if (xnet != false) {
+ pr_info("Error: XNET != false is not expected\n");
+ while (1) { }
+ }
+ if (nocheck != false) {
+ pr_info("Error: NOCHECK != false is not expected\n");
+ while (1) { }
+ }
+ if (df != 0) {
+ pr_info("Error: DF != 0 is not expected\n");
+ while (1) { }
+ }
+ /*
+ * FIXME
+ *
+ * Manually set TTL. In the Linux reference scenario this argument is
+ * observed to be 64. Here it is 0. Further Linux contrib code would have
+ * to be incorporated in order to make Wireguard provide a correct TTL
+ * argument. However, it is simpler to set it manually.
+ */
+ if (ttl != 0) {
+ pr_info("Error: TTL != 0 is not expected\n");
+ while (1) { }
+ }
+ ttl = 64;
+
+ /*
+ * FIXME
+ *
+ * Manually set UDP destination port. In the Linux reference scenario this
+ * argument is observed to be the listen port. Here it is som other port.
+ * Further Linux contrib code would have to be incorporated in order to
+ * make Wireguard provide a correct argument. However, it is simpler to
+ * set it manually.
+ */
+ src_port = htons(genode_wg_listen_port());
+
+ /*
+ * This is the SKB that we put into WireGuard earlier in
+ * _genode_wg_uplink_connection_receive. WireGuard modified it to become
+ * the SKB that we want to send at the NIC connection. WireGuard
+ * assumes that we free the SKB after having sent it.
+ */
+ genode_wg_send_wg_prot_at_nic_connection(
+ skb->data, skb->len, src_port, dst_port, src, dst,
+ tos, ttl);
+
+ kfree_skb(skb);
+}
+
+
+#include
+
+DEFINE_STATIC_KEY_FALSE(memalloc_socks_key);
+EXPORT_SYMBOL_GPL(memalloc_socks_key);
+
+
+#include
+
+struct kmem_cache * kmem_cache_create_usercopy(const char * name,
+ unsigned int size,
+ unsigned int align,
+ slab_flags_t flags,
+ unsigned int useroffset,
+ unsigned int usersize,
+ void (* ctor)(void *))
+{
+ return kmem_cache_create(name, size, align, flags, ctor);
+}
+
+
+#include
+
+/* Returns either the correct skb->protocol value, or 0 if invalid. */
+__be16 ip_tunnel_parse_protocol(const struct sk_buff *skb)
+{
+ //FIXME: we just assume IPv4
+ return htons(ETH_P_IP);
+}
+
+
+#include
+
+bool rng_is_initialized(void)
+{
+ return true;
+}
+
+
+#include
+
+__be32 inet_confirm_addr(struct net * net,struct in_device * in_dev,__be32 dst,__be32 local,int scope)
+{
+ lx_emul_trace(__func__);
+ return local;
+}
+
+
+#include
+
+struct rtable * ip_route_output_flow(struct net * net,struct flowi4 * flp4,const struct sock * sk)
+{
+ static bool initialized = false;
+ static struct dst_metrics dst_default_metrics;
+ static struct rtable rt;
+ if (!initialized) {
+ rt.dst.dev = genode_wg_net_device();
+ dst_init_metrics(&rt.dst, dst_default_metrics.metrics, true);
+ initialized = true;
+ }
+ return &rt;
+}
+
+
+#include
+
+int __cond_resched(void)
+{
+ if (should_resched(0)) {
+ schedule();
+ return 1;
+ }
+ return 0;
+}
+
+
+#include
+
+void call_rcu(struct rcu_head * head,rcu_callback_t func)
+{
+ func(head);
+}
+
+
+#include
+
+void kfree_sensitive(const void * p)
+{
+ kfree(p);
+}
+
+
+#include
+
+gro_result_t napi_gro_receive(struct napi_struct * napi,struct sk_buff * skb)
+{
+ /*
+ * This is the SKB that we put into WireGuard earlier in
+ * _genode_wg_nic_connection_receive. WireGuard modified it to become
+ * the SKB that we want to send at the Uplink connection. WireGuard
+ * assumes that we free the SKB after having sent it.
+ */
+ genode_wg_send_ip_at_uplink_connection(skb->data, skb->len);
+ kfree_skb(skb);
+
+ /*
+ * FIXME
+ *
+ * The Wireguard contrib code currently ignores this return value.
+ * Considering the possibility that, one day, it does otherwise, I return
+ * an invalid value here in the hope that it complains. The reason is that
+ * I don't understand GRO and its return values fully and don't want to
+ * dive into it because I hope that it will not become relevant anyway.
+ */
+ return -1;
+}
+
+
+#include
+
+void netif_napi_add(struct net_device * dev,struct napi_struct * napi,int (* poll)(struct napi_struct *,int),int weight)
+{
+ napi->dev = dev;
+ napi->poll = poll;
+ napi->weight = weight;
+}
+
+
+#include
+
+bool napi_schedule_prep(struct napi_struct * n)
+{
+ return true;
+}
+
+
+#include
+
+void __napi_schedule(struct napi_struct * n)
+{
+ int weight = n->weight;
+ if (n->poll(n, n->weight) >= weight) {
+ printk("Warning: more work to do?\n");
+ lx_emul_trace_and_stop(__func__);
+ }
+}
+
+
+#include
+
+bool napi_complete_done(struct napi_struct * n,int work_done)
+{
+ lx_emul_trace(__func__);
+ return true;
+}
+
+
+#include
+
+void __do_once_done(bool * done,struct static_key_true * once_key,unsigned long * flags,struct module * mod)
+{
+ *done = true;
+}
+
+
+#include
+
+bool __do_once_start(bool * done,unsigned long * flags)
+{
+ return !*done;
+}
diff --git a/repos/dde_linux/src/app/wireguard/lx_emul.h b/repos/dde_linux/src/app/wireguard/lx_emul.h
new file mode 100644
index 0000000000..772e5d6e52
--- /dev/null
+++ b/repos/dde_linux/src/app/wireguard/lx_emul.h
@@ -0,0 +1,23 @@
+/**
+ * \brief Dummy definitions of Linux Kernel functions
+ * \author Stefan Kalkowski
+ * \date 2022-01-07
+ */
+
+/*
+ * Copyright (C) 2021 Genode Labs GmbH
+ *
+ * This file is distributed under the terms of the GNU General Public License
+ * version 2.
+ */
+
+/* Needed to trace and stop */
+#include
+
+/* fix for missing includes in generated_dummies */
+#include
+#include
+#include
+
+
+struct rtnl_link_ops *wireguard_rtnl_link_ops(void);
diff --git a/repos/dde_linux/src/app/wireguard/lx_emul/alloc.cc b/repos/dde_linux/src/app/wireguard/lx_emul/alloc.cc
new file mode 100644
index 0000000000..1458d18fe1
--- /dev/null
+++ b/repos/dde_linux/src/app/wireguard/lx_emul/alloc.cc
@@ -0,0 +1,84 @@
+/*
+ * \brief This file shadows repos/dde_linux/src/lib/lx_emul/alloc.cc
+ * \author Martin Stein
+ * \author Stefan Kalkowski
+ * \date 2021-03-22
+ */
+
+/*
+ * Copyright (C) 2021 Genode Labs GmbH
+ *
+ * This file is distributed under the terms of the GNU General Public License
+ * version 2.
+ */
+
+#include
+#include
+#include
+#include
+#include
+
+extern "C" void * lx_emul_mem_alloc_aligned(unsigned long size, unsigned long align)
+{
+ void * const ptr = Lx_kit::env().memory.alloc(size, align);
+ return ptr;
+};
+
+
+extern "C" void * lx_emul_mem_alloc_aligned_uncached(unsigned long size,
+ unsigned long align)
+{
+ void * const ptr = Lx_kit::env().uncached_memory.alloc(size, align);
+ return ptr;
+};
+
+
+extern "C" unsigned long lx_emul_mem_dma_addr(void * addr)
+{
+ return (unsigned long)addr;
+}
+
+
+extern "C" unsigned long lx_emul_mem_virt_addr(void * dma_addr)
+{
+ return (unsigned long)dma_addr;
+}
+
+
+extern "C" void lx_emul_mem_free(const void * ptr)
+{
+ if (!ptr)
+ return;
+ if (Lx_kit::env().memory.free(ptr))
+ return;
+ if (Lx_kit::env().uncached_memory.free(ptr))
+ return;
+ Genode::error(__func__, " called with invalid ptr ", ptr);
+};
+
+
+extern "C" unsigned long lx_emul_mem_size(const void * ptr)
+{
+ unsigned long ret = 0;
+ if (!ptr)
+ return ret;
+ if ((ret = Lx_kit::env().memory.size(ptr)))
+ return ret;
+ if (!(ret = Lx_kit::env().uncached_memory.size(ptr)))
+ Genode::error(__func__, " called with invalid ptr ", ptr);
+ return ret;
+};
+
+
+extern "C" void lx_emul_mem_cache_clean_invalidate(const void * addr,
+ unsigned long size)
+{
+ Genode::cache_clean_invalidate_data((Genode::addr_t)addr, size);
+}
+
+
+extern "C" void lx_emul_mem_cache_invalidate(const void * addr,
+ unsigned long size)
+{
+ Genode::cache_invalidate_data((Genode::addr_t)addr, size);
+}
diff --git a/repos/dde_linux/src/app/wireguard/lx_emul/random.h b/repos/dde_linux/src/app/wireguard/lx_emul/random.h
new file mode 100644
index 0000000000..9ed5f1eef0
--- /dev/null
+++ b/repos/dde_linux/src/app/wireguard/lx_emul/random.h
@@ -0,0 +1,27 @@
+/**
+ * \brief Randomness generation of lx_emul
+ * \author Stefan Kalkowski
+ * \date 2022-01-12
+ */
+
+/*
+ * Copyright (C) 2022 Genode Labs GmbH
+ *
+ * This file is distributed under the terms of the GNU General Public License
+ * version 2.
+ */
+
+#ifndef _LX_EMUL__RANDOM_H_
+#define _LX_EMUL__RANDOM_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void lx_emul_random_bytes(void * buf, int bytes);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LX_EMUL__RANDOM_H_ */
diff --git a/repos/dde_linux/src/app/wireguard/lx_emul/shadow/arch/arm64/kernel/cpufeature.c b/repos/dde_linux/src/app/wireguard/lx_emul/shadow/arch/arm64/kernel/cpufeature.c
new file mode 100644
index 0000000000..efd26487a8
--- /dev/null
+++ b/repos/dde_linux/src/app/wireguard/lx_emul/shadow/arch/arm64/kernel/cpufeature.c
@@ -0,0 +1,37 @@
+/*
+ * \brief Replaces arch/arm64/kernel/cpufeature.c
+ * \author Martin Stein
+ * \date 2022-05-09
+ */
+
+/*
+ * Copyright (C) 2022 Genode Labs GmbH
+ *
+ * This file is distributed under the terms of the GNU General Public License
+ * version 2.
+ */
+
+#include
+#include
+
+/*
+ * Flag to indicate if we have computed the system wide
+ * capabilities based on the boot time active CPUs. This
+ * will be used to determine if a new booting CPU should
+ * go through the verification process to make sure that it
+ * supports the system capabilities, without using a hotplug
+ * notifier. This is also used to decide if we could use
+ * the fast path for checking constant CPU caps.
+ */
+DEFINE_STATIC_KEY_FALSE(arm64_const_caps_ready);
+EXPORT_SYMBOL(arm64_const_caps_ready);
+void finalize_system_capabilities(void)
+{
+ static_branch_enable(&arm64_const_caps_ready);
+}
+
+DEFINE_STATIC_KEY_ARRAY_FALSE(cpu_hwcap_keys, ARM64_NCAPS);
+EXPORT_SYMBOL(cpu_hwcap_keys);
+
+DECLARE_BITMAP(cpu_hwcaps, ARM64_NCAPS);
+EXPORT_SYMBOL(cpu_hwcaps);
diff --git a/repos/dde_linux/src/app/wireguard/lx_kit/device.h b/repos/dde_linux/src/app/wireguard/lx_kit/device.h
new file mode 100644
index 0000000000..9093d97c25
--- /dev/null
+++ b/repos/dde_linux/src/app/wireguard/lx_kit/device.h
@@ -0,0 +1,28 @@
+#ifndef _LX_KIT__DEVICE_H_
+#define _LX_KIT__DEVICE_H_
+
+#include
+#include
+
+namespace Platform { struct Connection; }
+namespace Lx_kit { struct Device_list; }
+
+struct Platform::Connection
+{
+ Connection(Genode::Env &) {}
+};
+
+
+struct Lx_kit::Device_list
+{
+ Device_list(Genode::Entrypoint &,
+ Genode::Heap &,
+ Platform::Connection &) {}
+
+ void update() {}
+
+ template
+ void for_each(FN const &) {}
+};
+
+#endif /* _LX_KIT__DEVICE_H_ */
diff --git a/repos/dde_linux/src/app/wireguard/lx_kit/memory.cc b/repos/dde_linux/src/app/wireguard/lx_kit/memory.cc
new file mode 100644
index 0000000000..df48c99a8f
--- /dev/null
+++ b/repos/dde_linux/src/app/wireguard/lx_kit/memory.cc
@@ -0,0 +1,171 @@
+/*
+ * \brief This file shadows repos/dde_linux/src/lib/lx_kit/memory.cc
+ * \author Martin Stein
+ * \author Stefan Kalkowski
+ * \date 2021-03-25
+ */
+
+/*
+ * Copyright (C) 2021 Genode Labs GmbH
+ *
+ * This file is distributed under the terms of the GNU General Public License
+ * version 2.
+ */
+
+/* Genode includes */
+#include
+
+/* local includes */
+#include
+#include
+#include
+#include
+
+
+void Lx_kit::Mem_allocator::free_buffer(void * addr)
+{
+ Buffer * buffer = nullptr;
+
+ _virt_to_dma.apply(Buffer_info::Query_addr(addr),
+ [&] (Buffer_info const & info) {
+ buffer = &info.buffer;
+ });
+
+ if (!buffer) {
+ warning(__func__, ": no memory buffer for addr: ", addr, " found");
+ return;
+ }
+
+ void const * virt_addr = (void const *)buffer->virt_addr();
+ void const * dma_addr = (void const *)buffer->dma_addr();
+
+ _virt_to_dma.remove(Buffer_info::Query_addr(virt_addr));
+ _dma_to_virt.remove(Buffer_info::Query_addr(dma_addr));
+
+ destroy(_heap, buffer);
+}
+
+
+Genode::Dataspace_capability Lx_kit::Mem_allocator::attached_dataspace_cap(void * addr)
+{
+ Genode::Dataspace_capability ret { };
+
+ _virt_to_dma.apply(Buffer_info::Query_addr(addr),
+ [&] (Buffer_info const & info) {
+ ret = info.buffer.cap();
+ });
+
+ return ret;
+}
+
+
+void * Lx_kit::Mem_allocator::alloc(size_t size, size_t align)
+{
+ if (!size)
+ return nullptr;
+
+ return _mem.alloc_aligned(size, (unsigned)log2(align)).convert(
+
+ [&] (void *ptr) {
+ memset(ptr, 0, size);
+ return ptr; },
+
+ [&] (Range_allocator::Alloc_error) {
+
+ /*
+ * Restrict the minimum buffer size to avoid the creation of
+ * a separate dataspaces for tiny allocations.
+ */
+ size_t const min_buffer_size = 256*1024;
+
+ /*
+ * Allocate one excess byte that is not officially registered at
+ * the '_mem' ranges. This way, two virtual consecutive ranges
+ * (that must be assumed to belong to non-contiguous physical
+ * ranges) can never be merged when freeing an allocation. Such
+ * a merge would violate the assumption that a both the virtual
+ * and physical addresses of a multi-page allocation are always
+ * contiguous.
+ */
+ Buffer & buffer = alloc_buffer(max(size + 1, min_buffer_size));
+
+ _mem.add_range(buffer.virt_addr(), buffer.size() - 1);
+
+ lx_emul_forget_pages((void*)buffer.virt_addr(), buffer.size());
+ lx_emul_virt_to_pages((void*)buffer.virt_addr(), (buffer.size() + 0xfff) >> 12);
+
+ /* re-try allocation */
+ return _mem.alloc_aligned(size, (unsigned)log2(align)).convert(
+
+ [&] (void *ptr) {
+ memset(ptr, 0, size);
+ return ptr; },
+
+ [&] (Range_allocator::Alloc_error) -> void * {
+ error("memory allocation failed for ", size, " align ", align);
+ return nullptr; }
+ );
+ }
+ );
+}
+
+
+Genode::addr_t Lx_kit::Mem_allocator::dma_addr(void * addr)
+{
+ addr_t ret = 0UL;
+
+ _virt_to_dma.apply(Buffer_info::Query_addr(addr),
+ [&] (Buffer_info const & info) {
+ addr_t const offset = (addr_t)addr - info.buffer.virt_addr();
+ ret = info.buffer.dma_addr() + offset;
+ });
+
+ return ret;
+}
+
+
+Genode::addr_t Lx_kit::Mem_allocator::virt_addr(void * dma_addr)
+{
+ addr_t ret = 0UL;
+
+ _dma_to_virt.apply(Buffer_info::Query_addr(dma_addr),
+ [&] (Buffer_info const & info) {
+ addr_t const offset = (addr_t)dma_addr - info.buffer.dma_addr();
+ ret = info.buffer.virt_addr() + offset;
+ });
+
+ return ret;
+}
+
+
+bool Lx_kit::Mem_allocator::free(const void * ptr)
+{
+ if (!_mem.valid_addr((addr_t)ptr))
+ return false;
+
+ using Size_at_error = Allocator_avl::Size_at_error;
+
+ _mem.size_at(ptr).with_result(
+ [&] (size_t) { _mem.free(const_cast(ptr)); },
+ [ ] (Size_at_error) { });
+
+ return true;
+}
+
+
+Genode::size_t Lx_kit::Mem_allocator::size(const void * ptr)
+{
+ if (!ptr) return 0;
+
+ using Size_at_error = Allocator_avl::Size_at_error;
+
+ return _mem.size_at(ptr).convert([ ] (size_t s) { return s; },
+ [ ] (Size_at_error) { return 0U; });
+}
+
+
+Lx_kit::Mem_allocator::Mem_allocator(Genode::Env & env,
+ Heap & heap,
+ Platform::Connection & platform,
+ Cache cache_attr)
+: _env(env), _heap(heap), _platform(platform), _cache_attr(cache_attr) {}
diff --git a/repos/dde_linux/src/app/wireguard/main.cc b/repos/dde_linux/src/app/wireguard/main.cc
new file mode 100644
index 0000000000..805bcc6590
--- /dev/null
+++ b/repos/dde_linux/src/app/wireguard/main.cc
@@ -0,0 +1,255 @@
+/*
+ * \brief Wireguard component
+ * \author Stefan Kalkowski
+ * \author Martin Stein
+ * \date 2022-01-07
+ */
+
+/*
+ * Copyright (C) 2022 Genode Labs GmbH
+ *
+ * This file is part of the Genode OS framework, which is distributed
+ * under the terms of the GNU Affero General Public License version 3.
+ */
+
+#include
+#include
+
+/* base includes */
+#include
+#include
+#include
+#include
+
+/* lx-kit includes */
+#include
+
+/* lx-emul includes */
+#include
+
+/* lx-user includes */
+#include
+
+/* app/wireguard includes */
+#include
+#include
+#include
+
+using namespace Genode;
+
+namespace Wireguard { class Main; }
+
+
+class Wireguard::Main : private Entrypoint::Io_progress_handler,
+ private Nic_connection_notifier
+{
+ private:
+
+ Env &_env;
+ Timer::Connection _timer { _env };
+ Heap _heap { _env.ram(), _env.rm() };
+ Attached_rom_dataspace _config_rom { _env, "config" };
+ Signal_handler _config_handler { _env.ep(), *this, &Main::_handle_config };
+ Io_signal_handler _signal_handler { _env.ep(), *this, &Main::_handle_signal };
+ Config_model _config_model { _heap };
+ Signal_handler _nic_ip_config_handler { _env.ep(), *this, &Main::_handle_nic_ip_config };
+ Nic_connection _nic_connection { _env, _heap, _signal_handler, _config_rom.xml(), _timer, *this };
+ Constructible _uplink_connection { };
+
+ void _handle_signal()
+ {
+ lx_user_handle_io();
+ Lx_kit::env().scheduler.schedule();
+ }
+
+ void _handle_config() { _config_rom.update(); }
+
+ void _handle_nic_ip_config();
+
+
+ /*****************************
+ ** Nic_connection_notifier **
+ *****************************/
+
+ void notify_about_ip_config_update() override
+ {
+ _nic_ip_config_handler.local_submit();
+ }
+
+ public:
+
+ Main(Env &env)
+ :
+ _env(env)
+ {
+ Lx_kit::initialize(_env);
+
+ /*
+ * We have to call the static constructors because otherwise the
+ * initcall list of the LX kit won't get populated.
+ */
+ _env.exec_static_constructors();
+
+ _config_rom.sigh(_config_handler);
+ _handle_config();
+
+ env.ep().register_io_progress_handler(*this);
+
+ /* trigger signal handling once after construction */
+ Signal_transmitter(_signal_handler).submit();
+ }
+
+ /**
+ * Entrypoint::Io_progress_handler
+ */
+ void handle_io_progress() override
+ {
+ if (_uplink_connection.constructed()) {
+ _uplink_connection->notify_peer();
+ }
+ _nic_connection.notify_peer();
+ }
+
+ void update(genode_wg_config_callbacks & callbacks)
+ {
+ _config_model.update(callbacks, _config_rom.xml());
+ }
+
+ void net_receive(genode_wg_uplink_connection_receive_t uplink_rcv_callback,
+ genode_wg_nic_connection_receive_t nic_rcv_callback)
+ {
+ if (_uplink_connection.constructed()) {
+ _uplink_connection->for_each_rx_packet(uplink_rcv_callback);
+ }
+ _nic_connection.for_each_rx_packet(nic_rcv_callback);
+ }
+
+ void send_wg_prot_at_nic_connection(
+ genode_wg_u8_t const *wg_prot_base,
+ genode_wg_size_t wg_prot_size,
+ genode_wg_u16_t udp_src_port_big_endian,
+ genode_wg_u16_t udp_dst_port_big_endian,
+ genode_wg_u32_t ipv4_src_addr_big_endian,
+ genode_wg_u32_t ipv4_dst_addr_big_endian,
+ genode_wg_u8_t ipv4_dscp_ecn,
+ genode_wg_u8_t ipv4_ttl);
+
+ void send_ip_at_uplink_connection(
+ genode_wg_u8_t const *ip_base,
+ genode_wg_size_t ip_size);
+};
+
+
+void Wireguard::Main::_handle_nic_ip_config()
+{
+ if (_nic_connection.ip_config().valid()) {
+ if (!_uplink_connection.constructed()) {
+ _uplink_connection.construct(_env, _heap, _signal_handler);
+ }
+ } else {
+ if (_uplink_connection.constructed()) {
+ _uplink_connection.destruct();
+ }
+ }
+}
+
+
+void Wireguard::Main::send_wg_prot_at_nic_connection(
+ genode_wg_u8_t const *wg_prot_base,
+ genode_wg_size_t wg_prot_size,
+ genode_wg_u16_t udp_src_port_big_endian,
+ genode_wg_u16_t udp_dst_port_big_endian,
+ genode_wg_u32_t ipv4_src_addr_big_endian,
+ genode_wg_u32_t ipv4_dst_addr_big_endian,
+ genode_wg_u8_t ipv4_dscp_ecn,
+ genode_wg_u8_t ipv4_ttl)
+{
+ _nic_connection.send_wg_prot(
+ wg_prot_base,
+ wg_prot_size,
+ udp_src_port_big_endian,
+ udp_dst_port_big_endian,
+ ipv4_src_addr_big_endian,
+ ipv4_dst_addr_big_endian,
+ ipv4_dscp_ecn,
+ ipv4_ttl);
+}
+
+
+void Wireguard::Main::send_ip_at_uplink_connection(
+ genode_wg_u8_t const *ip_base,
+ genode_wg_size_t ip_size)
+{
+ if (_uplink_connection.constructed()) {
+ _uplink_connection->send_ip(ip_base, ip_size);
+ } else {
+ log("Main: drop packet - uplink connection down");
+ }
+}
+
+
+static Wireguard::Main & main_object(Genode::Env & env)
+{
+ static Wireguard::Main main { env };
+ return main;
+}
+
+
+extern "C" void
+genode_wg_update_config(struct genode_wg_config_callbacks * callbacks)
+{
+ main_object(Lx_kit::env().env).update(*callbacks);
+};
+
+
+extern "C" void
+genode_wg_net_receive(genode_wg_uplink_connection_receive_t uplink_rcv_callback,
+ genode_wg_nic_connection_receive_t nic_rcv_callback)
+{
+ main_object(Lx_kit::env().env).net_receive(uplink_rcv_callback,
+ nic_rcv_callback);
+}
+
+
+void genode_wg_send_wg_prot_at_nic_connection(
+ genode_wg_u8_t const *wg_prot_base,
+ genode_wg_size_t wg_prot_size,
+ genode_wg_u16_t udp_src_port_big_endian,
+ genode_wg_u16_t udp_dst_port_big_endian,
+ genode_wg_u32_t ipv4_src_addr_big_endian,
+ genode_wg_u32_t ipv4_dst_addr_big_endian,
+ genode_wg_u8_t ipv4_dscp_ecn,
+ genode_wg_u8_t ipv4_ttl)
+{
+ main_object(Lx_kit::env().env).send_wg_prot_at_nic_connection(
+ wg_prot_base,
+ wg_prot_size,
+ udp_src_port_big_endian,
+ udp_dst_port_big_endian,
+ ipv4_src_addr_big_endian,
+ ipv4_dst_addr_big_endian,
+ ipv4_dscp_ecn,
+ ipv4_ttl);
+}
+
+
+void genode_wg_send_ip_at_uplink_connection(
+ genode_wg_u8_t const *ip_base,
+ genode_wg_size_t ip_size)
+{
+ main_object(Lx_kit::env().env).send_ip_at_uplink_connection(
+ ip_base,
+ ip_size);
+}
+
+
+void Component::construct(Env &env)
+{
+ main_object(env);
+
+ /*
+ * Main needs to be constructed before startin Linux code,
+ * because of genode_wg_* calls
+ */
+ lx_emul_start_kernel(nullptr);
+}
diff --git a/repos/dde_linux/src/app/wireguard/nic_connection.cc b/repos/dde_linux/src/app/wireguard/nic_connection.cc
new file mode 100644
index 0000000000..aad650fbfe
--- /dev/null
+++ b/repos/dde_linux/src/app/wireguard/nic_connection.cc
@@ -0,0 +1,339 @@
+/*
+ * \brief Network back-end towards public network (encrypted UDP tunnel)
+ * \author Stefan Kalkowski
+ * \author Martin Stein
+ * \date 2022-01-07
+ */
+
+/*
+ * Copyright (C) 2022 Genode Labs GmbH
+ *
+ * This file is part of the Genode OS framework, which is distributed
+ * under the terms of the GNU Affero General Public License version 3.
+ */
+
+/* dde_linux wireguard includes */
+#include
+
+/* os includes */
+#include
+
+using namespace Genode;
+using namespace Net;
+using namespace Wireguard;
+
+
+Nic_connection::Handle_pkt_result
+Nic_connection::_drop_pkt(char const *packet_type,
+ char const *reason)
+{
+ if (_verbose_pkt_drop) {
+ log("Drop ", packet_type, " - ", reason);
+ }
+ return Handle_pkt_result::DROP_PACKET;
+}
+
+
+void Nic_connection::_connection_tx_flush_acks()
+{
+ while (_connection.tx()->ack_avail()) {
+ _connection.tx()->release_packet(
+ _connection.tx()->get_acked_packet());
+ }
+}
+
+
+Nic_connection::Send_pkt_result
+Nic_connection::_finish_send_eth_ipv4_with_eth_dst_set_via_arp(Packet_descriptor pkt,
+ Mac_address const ð_dst)
+{
+ void *pkt_base { _connection.tx()->packet_content(pkt) };
+ Size_guard size_guard { pkt.size() };
+
+ Ethernet_frame ð { Ethernet_frame::cast_from(pkt_base, size_guard) };
+
+ eth.dst(eth_dst);
+ _connection_tx_flush_acks();
+ _connection.tx()->submit_packet(pkt);
+ return Send_pkt_result::SUCCEEDED;
+}
+
+
+Nic_connection::Send_pkt_result
+Nic_connection::_send_arp_reply(Ethernet_frame &request_eth,
+ Arp_packet &request_arp)
+{
+ return send(ARP_PACKET_SIZE, [&] (void *reply_base, Size_guard &reply_guard) {
+
+ Ethernet_frame &reply_eth {
+ Ethernet_frame::construct_at(reply_base, reply_guard) };
+
+ reply_eth.dst(request_eth.src());
+ reply_eth.src(_mac_address);
+ reply_eth.type(Ethernet_frame::Type::ARP);
+
+ Arp_packet &reply_arp {
+ reply_eth.construct_at_data(reply_guard) };
+
+ reply_arp.hardware_address_type(Arp_packet::ETHERNET);
+ reply_arp.protocol_address_type(Arp_packet::IPV4);
+ reply_arp.hardware_address_size(sizeof(Mac_address));
+ reply_arp.protocol_address_size(sizeof(Ipv4_address));
+ reply_arp.opcode(Arp_packet::REPLY);
+ reply_arp.src_mac(_mac_address);
+ reply_arp.src_ip(request_arp.dst_ip());
+ reply_arp.dst_mac(request_arp.src_mac());
+ reply_arp.dst_ip(request_arp.src_ip());
+ });
+}
+
+
+Nic_connection::Handle_pkt_result
+Nic_connection::_handle_arp_request(Ethernet_frame ð,
+ Arp_packet &arp)
+{
+ if (ip_config().interface().address != arp.dst_ip()) {
+ return _drop_pkt("ARP request", "Doesn't target my IP address");
+ }
+ if (_send_arp_reply(eth, arp) != Send_pkt_result::SUCCEEDED) {
+ return _drop_pkt("ARP request", "Sending reply failed");
+ }
+ return Handle_pkt_result::ACK_PACKET;
+}
+
+
+Nic_connection::Handle_pkt_result
+Nic_connection::_handle_arp(Ethernet_frame ð,
+ Size_guard &size_guard)
+{
+ Arp_packet &arp { eth.data(size_guard) };
+ if (!arp.ethernet_ipv4()) {
+ return _drop_pkt("ARP packet", "Targets unknown protocol");
+ }
+ switch (arp.opcode()) {
+ case Arp_packet::REQUEST: return _handle_arp_request(eth, arp);
+ case Arp_packet::REPLY: return _handle_arp_reply(arp);
+ default: return _drop_pkt("ARP packet", "Unexpected opcode");
+ }
+}
+
+
+void Nic_connection::_broadcast_arp_request(Ipv4_address const &src_ip,
+ Ipv4_address const &dst_ip)
+{
+ send(ARP_PACKET_SIZE, [&] (void *pkt_base, Size_guard &size_guard) {
+
+ /* write Ethernet header */
+ Ethernet_frame ð = Ethernet_frame::construct_at(pkt_base, size_guard);
+ eth.dst(Mac_address(0xff));
+ eth.src(_mac_address);
+ eth.type(Ethernet_frame::Type::ARP);
+
+ /* write ARP header */
+ Arp_packet &arp = eth.construct_at_data(size_guard);
+ arp.hardware_address_type(Arp_packet::ETHERNET);
+ arp.protocol_address_type(Arp_packet::IPV4);
+ arp.hardware_address_size(sizeof(Mac_address));
+ arp.protocol_address_size(sizeof(Ipv4_address));
+ arp.opcode(Arp_packet::REQUEST);
+ arp.src_mac(_mac_address);
+ arp.src_ip(src_ip);
+ arp.dst_mac(Mac_address(0xff));
+ arp.dst_ip(dst_ip);
+ });
+}
+
+
+Nic_connection::Handle_pkt_result
+Nic_connection::_handle_arp_reply(Arp_packet &arp)
+{
+ _arp_cache.find_by_ip(arp.src_ip()).with_result(
+ [&] (Const_pointer) { },
+ [&] (Arp_cache_error) {
+
+ /* by now, no matching ARP cache entry exists, so create one */
+ Ipv4_address const ip = arp.src_ip();
+ _arp_cache.new_entry(ip, arp.src_mac());
+
+ /* finish sending packets that waited for the entry */
+ for (Arp_waiter_list_element *waiter_le = _arp_waiters.first();
+ waiter_le; ) {
+
+ Arp_waiter &waiter = *waiter_le->object();
+ waiter_le = waiter_le->next();
+ if (ip != waiter.ip()) {
+ continue;
+ }
+ _finish_send_eth_ipv4_with_eth_dst_set_via_arp(
+ waiter.packet(), arp.src_mac());
+
+ destroy(_alloc, &waiter);
+ }
+ }
+ );
+ return Handle_pkt_result::ACK_PACKET;
+}
+
+
+Nic_connection::Nic_connection(Env &env,
+ Allocator &alloc,
+ Signal_context_capability pkt_stream_sigh,
+ Xml_node const &config_node,
+ Timer::Connection &timer,
+ Nic_connection_notifier ¬ifier)
+:
+ _alloc { alloc },
+ _notifier { notifier },
+ _dhcp_client { timer, *this },
+ _ip_config { config_node },
+ _connection { env, &_packet_alloc, BUF_SIZE, BUF_SIZE,
+ "nic_session" },
+ _link_state_handler { env.ep(), *this, &Nic_connection::_handle_link_state }
+{
+ _connection.rx_channel()->sigh_ready_to_ack(pkt_stream_sigh);
+ _connection.rx_channel()->sigh_packet_avail(pkt_stream_sigh);
+ _connection.tx_channel()->sigh_ack_avail(pkt_stream_sigh);
+ _connection.tx_channel()->sigh_ready_to_submit(pkt_stream_sigh);
+ _connection.link_state_sigh(_link_state_handler);
+
+ if (ip_config().valid()) {
+ _notifier.notify_about_ip_config_update();
+ } else {
+ _dhcp_client.discover();
+ }
+}
+
+
+void Nic_connection::_handle_link_state()
+{
+ discard_ip_config();
+ _dhcp_client.discover();
+}
+
+
+void Nic_connection::for_each_rx_packet(Handle_packet_func handle_packet)
+{
+ typename Nic::Connection::Rx::Sink & rx_sink = *_connection.rx();
+
+ for (;;) {
+
+ if (!rx_sink.packet_avail() || !rx_sink.ack_slots_free())
+ break;
+
+ Packet_descriptor const packet = rx_sink.peek_packet();
+
+ bool const packet_valid = rx_sink.packet_valid(packet)
+ && (packet.offset() >= 0);
+
+ if (packet_valid) {
+
+ void *eth_base { rx_sink.packet_content(packet) };
+ Size_guard size_guard { packet.size() };
+ Ethernet_frame ð { Ethernet_frame::cast_from(eth_base, size_guard) };
+
+ if (!ip_config().valid()) {
+
+ _dhcp_client.handle_eth(eth, size_guard);
+
+ } else {
+
+ switch (eth.type()) {
+ case Ethernet_frame::Type::ARP:
+
+ _handle_arp(eth, size_guard);
+ break;
+
+ case Ethernet_frame::Type::IPV4:
+
+ handle_packet(eth_base, packet.size());
+ _notify_peers = true;
+ break;
+
+ default:
+
+ _drop_pkt("packet", "Unknown type in Ethernet header");
+ break;
+ }
+ }
+ }
+ (void)rx_sink.try_get_packet();
+ rx_sink.try_ack_packet(packet);
+ }
+}
+
+
+void Nic_connection::notify_peer()
+{
+ if (_notify_peers) {
+ _notify_peers = false;
+ _connection.rx()->wakeup();
+ _connection.tx()->wakeup();
+ }
+}
+
+
+void Nic_connection::discard_ip_config()
+{
+ _ip_config.construct();
+ _notifier.notify_about_ip_config_update();
+}
+
+
+void Nic_connection::ip_config_from_dhcp_ack(Net::Dhcp_packet &dhcp_ack)
+{
+ _ip_config.construct(dhcp_ack);
+ _notifier.notify_about_ip_config_update();
+}
+
+
+void
+Nic_connection::send_wg_prot(uint8_t const *wg_prot_base,
+ size_t wg_prot_size,
+ uint16_t udp_src_port_big_endian,
+ uint16_t udp_dst_port_big_endian,
+ uint32_t,
+ uint32_t ipv4_dst_addr_big_endian,
+ uint8_t ipv4_dscp_ecn,
+ uint8_t ipv4_ttl)
+{
+ size_t const pkt_size {
+ sizeof(Ethernet_frame) + sizeof(Ipv4_packet) + sizeof(Udp_packet) +
+ wg_prot_size };
+
+ Ipv4_address const dst_ip {
+ Ipv4_address::from_uint32_big_endian(ipv4_dst_addr_big_endian) };
+
+ _send_eth_ipv4_with_eth_dst_set_via_arp(
+ pkt_size, dst_ip, [&] (Ethernet_frame ð, Size_guard &size_guard)
+ {
+ /* create ETH header */
+ eth.src(_mac_address);
+ eth.type(Ethernet_frame::Type::IPV4);
+
+ /* create IP header of the reply */
+ size_t const ip_off = size_guard.head_size();
+ Ipv4_packet &ip = eth.construct_at_data(size_guard);
+ ip.header_length(sizeof(Ipv4_packet) / 4);
+ ip.version(4);
+ ip.time_to_live(ipv4_ttl);
+ ip.diff_service_ecn(ipv4_dscp_ecn);
+ ip.protocol(Ipv4_packet::Protocol::UDP);
+ ip.src_big_endian(ip_config().interface().address.to_uint32_big_endian());
+ ip.dst_big_endian(ipv4_dst_addr_big_endian);
+
+ /* create UDP header of the reply */
+ size_t const udp_off = size_guard.head_size();
+ Udp_packet &udp = ip.construct_at_data(size_guard);
+ udp.src_port_big_endian(udp_src_port_big_endian);
+ udp.dst_port_big_endian(udp_dst_port_big_endian);
+
+ /* add Wireguard protocol data */
+ udp.memcpy_to_data((void *)wg_prot_base, wg_prot_size, size_guard);
+
+ /* fill in header values that need the packet to be complete already */
+ udp.length((uint16_t)(size_guard.head_size() - udp_off));
+ udp.update_checksum(ip.src(), ip.dst());
+ ip.total_length(size_guard.head_size() - ip_off);
+ ip.update_checksum();
+ });
+}
diff --git a/repos/dde_linux/src/app/wireguard/nic_connection.h b/repos/dde_linux/src/app/wireguard/nic_connection.h
new file mode 100644
index 0000000000..cda21ffc11
--- /dev/null
+++ b/repos/dde_linux/src/app/wireguard/nic_connection.h
@@ -0,0 +1,224 @@
+/*
+ * \brief Network back-end towards public network (encrypted UDP tunnel)
+ * \author Stefan Kalkowski
+ * \author Martin Stein
+ * \date 2022-01-07
+ */
+
+/*
+ * Copyright (C) 2022 Genode Labs GmbH
+ *
+ * This file is part of the Genode OS framework, which is distributed
+ * under the terms of the GNU Affero General Public License version 3.
+ */
+
+#ifndef _NIC_CONNECTION_H_
+#define _NIC_CONNECTION_H_
+
+/* base includes */
+#include
+
+/* os includes */
+#include
+#include
+#include
+#include
+
+/* dde_linux wireguard includes */
+#include
+#include
+#include
+#include
+#include
+
+namespace Timer
+{
+ class Connection;
+}
+
+namespace Net {
+
+ class Dhcp_packet;
+}
+
+namespace Wireguard {
+
+ class Nic_connection_notifier;
+ class Nic_connection;
+}
+
+
+class Wireguard::Nic_connection_notifier : Genode::Interface
+{
+ public:
+
+ virtual void notify_about_ip_config_update() = 0;
+};
+
+
+class Wireguard::Nic_connection
+{
+ private:
+
+ using Handle_packet_func = void (*)(void *buf_base,
+ Genode::size_t buf_size);
+
+ using Packet_source = Nic::Packet_stream_source<::Nic::Session::Policy>;
+
+ enum { PACKET_SIZE = Nic::Packet_allocator::DEFAULT_PACKET_SIZE };
+ enum { WG_PROT_PACKET_SIZE = Nic::Packet_allocator::OFFSET_PACKET_SIZE };
+ enum { BUF_SIZE = Nic::Connection::Session::QUEUE_SIZE * PACKET_SIZE };
+
+ enum {
+
+ ETHERNIC_CONNECTION_HEADER_SIZE = sizeof(Net::Ethernet_frame),
+
+ ETHERNIC_CONNECTION_DATA_SIZE_WITH_ARP =
+ sizeof(Net::Arp_packet) + ETHERNIC_CONNECTION_HEADER_SIZE < Net::Ethernet_frame::MIN_SIZE ?
+ Net::Ethernet_frame::MIN_SIZE - ETHERNIC_CONNECTION_HEADER_SIZE :
+ sizeof(Net::Arp_packet),
+
+ ETHERNIC_CONNECTION_CRC_SIZE = sizeof(Genode::uint32_t),
+
+ ARP_PACKET_SIZE =
+ ETHERNIC_CONNECTION_HEADER_SIZE +
+ ETHERNIC_CONNECTION_DATA_SIZE_WITH_ARP +
+ ETHERNIC_CONNECTION_CRC_SIZE,
+ };
+
+ enum Handle_pkt_result { DROP_PACKET, ACK_PACKET };
+
+ enum Send_pkt_result { SUCCEEDED, FAILED, PACKET_WAITS_FOR_ARP };
+
+ Genode::Allocator &_alloc;
+ Nic_connection_notifier &_notifier;
+ Net::Dhcp_client _dhcp_client;
+ Genode::Reconstructible _ip_config;
+ Nic::Packet_allocator _packet_alloc { &_alloc };
+ bool _notify_peers { true };
+ Net::Arp_cache _arp_cache { };
+ Net::Arp_waiter_list _arp_waiters { };
+ Nic::Connection _connection;
+ Net::Mac_address const _mac_address { _connection.mac_address() };
+ bool const _verbose { true };
+ bool const _verbose_pkt_drop { true };
+ Genode::Signal_handler _link_state_handler;
+
+ Send_pkt_result
+ _finish_send_eth_ipv4_with_eth_dst_set_via_arp(Nic::Packet_descriptor pkt,
+ Net::Mac_address const ð_dst);
+
+ void _connection_tx_flush_acks();
+
+ template
+ Send_pkt_result
+ _send_eth_ipv4_with_eth_dst_set_via_arp(Genode::size_t pkt_size,
+ Net::Ipv4_address const &dst_ip,
+ FUNC && write_to_pkt)
+ {
+ Send_pkt_result result { Send_pkt_result::FAILED };
+ try {
+ Nic::Packet_descriptor pkt { _connection.tx()->alloc_packet(pkt_size) };
+ void *pkt_base { _connection.tx()->packet_content(pkt) };
+ Net::Size_guard size_guard { pkt_size };
+ Net::Ethernet_frame ð { Net::Ethernet_frame::construct_at(pkt_base, size_guard) };
+
+ write_to_pkt(eth, size_guard);
+ _arp_cache.find_by_ip(dst_ip).with_result(
+ [&] (Net::Const_pointer entry_ref) {
+ result = _finish_send_eth_ipv4_with_eth_dst_set_via_arp(
+ pkt, entry_ref.deref().mac());
+ },
+ [&] (Net::Arp_cache_error) {
+ _broadcast_arp_request(ip_config().interface().address, dst_ip);
+ new (_alloc) Net::Arp_waiter { _arp_waiters, dst_ip, pkt };
+ result = Send_pkt_result::PACKET_WAITS_FOR_ARP;
+ }
+ );
+ }
+ catch (Packet_source::Packet_alloc_failed) {
+ if (_verbose) {
+ Genode::log("Failed sending NIC packet - Failed allocating packet");
+ }
+ }
+ return result;
+ }
+
+ Handle_pkt_result _drop_pkt(char const *packet_type,
+ char const *reason);
+
+ Send_pkt_result _send_arp_reply(Net::Ethernet_frame &request_eth,
+ Net::Arp_packet &request_arp);
+
+ Handle_pkt_result _handle_arp_request(Net::Ethernet_frame ð,
+ Net::Arp_packet &arp);
+
+ Handle_pkt_result _handle_arp(Net::Ethernet_frame ð,
+ Net::Size_guard &size_guard);
+
+ void _broadcast_arp_request(Net::Ipv4_address const &src_ip,
+ Net::Ipv4_address const &dst_ip);
+
+ Handle_pkt_result _handle_arp_reply(Net::Arp_packet &arp);
+
+ void _handle_link_state();
+
+ public:
+
+ Nic_connection(Genode::Env &env,
+ Genode::Allocator &heap,
+ Genode::Signal_context_capability pkt_stream_sigh,
+ Genode::Xml_node const &config_node,
+ Timer::Connection &timer,
+ Nic_connection_notifier ¬ifier);
+
+ void for_each_rx_packet(Handle_packet_func handle_packet);
+
+ void notify_peer();
+
+ void send_wg_prot(Genode::uint8_t const *wg_prot_base,
+ Genode::size_t wg_prot_size,
+ Genode::uint16_t udp_src_port_big_endian,
+ Genode::uint16_t udp_dst_port_big_endian,
+ Genode::uint32_t ipv4_src_addr_big_endian,
+ Genode::uint32_t ipv4_dst_addr_big_endian,
+ Genode::uint8_t ipv4_dscp_ecn,
+ Genode::uint8_t ipv4_ttl);
+
+ Genode::Microseconds dhcp_discover_timeout() const { return Genode::Microseconds { 3 * 1000 * 1000 }; }
+
+ Genode::Microseconds dhcp_request_timeout() const { return Genode::Microseconds { 10 * 1000 * 1000 }; }
+
+ Ipv4_config const &ip_config() const { return *_ip_config; }
+
+ bool verbose() const { return _verbose; }
+
+ void discard_ip_config();
+
+ void ip_config_from_dhcp_ack(Net::Dhcp_packet &dhcp_ack);
+
+ Net::Mac_address mac_address() const { return _mac_address; }
+
+ template
+ Send_pkt_result send(Genode::size_t pkt_size, FUNC && write_to_pkt)
+ {
+ try {
+ Nic::Packet_descriptor pkt { _connection.tx()->alloc_packet(pkt_size) };
+ void *pkt_base { _connection.tx()->packet_content(pkt) };
+ Net::Size_guard size_guard { pkt_size };
+
+ write_to_pkt(pkt_base, size_guard);
+ _connection_tx_flush_acks();
+ _connection.tx()->submit_packet(pkt);
+ }
+ catch (Packet_source::Packet_alloc_failed) {
+ if (_verbose) {
+ Genode::log("Failed sending NIC packet - Failed allocating packet");
+ }
+ return Send_pkt_result::FAILED;
+ }
+ return Send_pkt_result::SUCCEEDED;
+ }
+};
+
+#endif /* _NIC_CONNECTION_H_ */
diff --git a/repos/dde_linux/src/app/wireguard/pointer.h b/repos/dde_linux/src/app/wireguard/pointer.h
new file mode 100644
index 0000000000..6db321bbe5
--- /dev/null
+++ b/repos/dde_linux/src/app/wireguard/pointer.h
@@ -0,0 +1,48 @@
+/*
+ * \brief Pointer that can be dereferenced only when valid
+ * \author Martin Stein
+ * \date 2017-03-08
+ */
+
+/*
+ * Copyright (C) 2016-2017 Genode Labs GmbH
+ *
+ * This file is part of the Genode OS framework, which is distributed
+ * under the terms of the GNU Affero General Public License version 3.
+ */
+
+#ifndef _POINTER_H_
+#define _POINTER_H_
+
+/* Genode includes */
+#include
+
+namespace Net { template class Const_pointer; }
+
+template
+class Net::Const_pointer
+{
+ private:
+
+ T const *_ptr { nullptr };
+
+ public:
+
+ struct Invalid : Genode::Exception { };
+
+ Const_pointer() { }
+
+ Const_pointer(T const &ref) : _ptr(&ref) { }
+
+ T const &deref() const
+ {
+ if (_ptr == nullptr) {
+ throw Invalid();
+ }
+ return *_ptr;
+ }
+
+ bool valid() const { return _ptr != nullptr; }
+};
+
+#endif /* _POINTER_H_ */
diff --git a/repos/dde_linux/src/app/wireguard/random.cc b/repos/dde_linux/src/app/wireguard/random.cc
new file mode 100644
index 0000000000..f6e7dd8936
--- /dev/null
+++ b/repos/dde_linux/src/app/wireguard/random.cc
@@ -0,0 +1,36 @@
+/*
+ * \brief Randomness backend for lx_emul
+ * \author Stefan Kalkowski
+ * \date 2022-01-12
+ */
+
+/*
+ * Copyright (C) 2022 Genode Labs GmbH
+ *
+ * This file is part of the Genode OS framework, which is distributed
+ * under the terms of the GNU Affero General Public License version 3.
+ */
+
+#include
+#include
+#include
+#include
+
+
+extern "C" void lx_emul_random_bytes(void * buf, int bytes)
+{
+ static rand_data * jent = nullptr;
+
+ if (!jent) {
+ jitterentropy_init(Lx_kit::env().heap);
+
+ if (jent_entropy_init() != 0)
+ Genode::error("jitterentropy library could not be initialized!");
+
+ jent = jent_entropy_collector_alloc(0, 0);
+ if (!jent)
+ Genode::error("jitterentropy could not allocate entropy collector!");
+ }
+
+ jent_read_entropy(jent, (char*)buf, bytes);
+}
diff --git a/repos/dde_linux/src/app/wireguard/spec/arm_64/dummies_arch.c b/repos/dde_linux/src/app/wireguard/spec/arm_64/dummies_arch.c
new file mode 100644
index 0000000000..db645de314
--- /dev/null
+++ b/repos/dde_linux/src/app/wireguard/spec/arm_64/dummies_arch.c
@@ -0,0 +1,113 @@
+/**
+ * \brief Architecture-specific dummy definitions of Linux Kernel functions
+ * \author Martin Stein
+ * \date 2022-05-09
+ */
+
+/*
+ * Copyright (C) 2022 Genode Labs GmbH
+ *
+ * This file is distributed under the terms of the GNU General Public License
+ * version 2.
+ */
+
+#include
+#include
+
+unsigned long long sched_clock(void)
+{
+ return lx_emul_time_counter() * 1000;
+}
+
+
+#include
+
+bool cpu_have_feature(unsigned int num)
+{
+ return 0;
+}
+
+u64 vabits_actual;
+
+void rcu_read_unlock_strict(void)
+{
+ lx_emul_trace(__func__);
+}
+
+unsigned long __must_check __arch_copy_to_user(void __user *to, const void *from, unsigned long n)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+void __init unflatten_device_tree(void)
+{
+ lx_emul_trace(__func__);
+}
+
+#include
+
+bool __init early_init_dt_scan(void * params)
+{
+ lx_emul_trace(__func__);
+ return false;
+}
+
+void __init irqchip_init(void) {
+ lx_emul_trace(__func__);
+}
+
+
+#include
+
+void __init sched_clock_register(u64 (* read)(void),int bits,unsigned long rate)
+{
+ lx_emul_trace(__func__);
+}
+
+#include
+
+void __init of_clk_init(const struct of_device_id * matches)
+{
+ lx_emul_trace(__func__);
+}
+
+
+#include
+
+void __init generic_sched_clock_init(void)
+{
+ lx_emul_trace(__func__);
+}
+
+#include
+
+void do_set_cpus_allowed(struct task_struct * p,const struct cpumask * new_mask)
+{
+ lx_emul_trace(__func__);
+}
+
+
+#include
+
+void __init of_core_init(void)
+{
+ lx_emul_trace(__func__);
+}
+
+#include
+
+int stop_machine(cpu_stop_fn_t fn,void * data,const struct cpumask * cpus)
+{
+ return (*fn)(data);
+}
+
+
+#include
+
+void kvfree(const void * addr)
+{
+ lx_emul_trace_and_stop(__func__);
+}
diff --git a/repos/dde_linux/src/app/wireguard/spec/arm_64/generated_dummies.c b/repos/dde_linux/src/app/wireguard/spec/arm_64/generated_dummies.c
new file mode 100644
index 0000000000..56074c7607
--- /dev/null
+++ b/repos/dde_linux/src/app/wireguard/spec/arm_64/generated_dummies.c
@@ -0,0 +1,693 @@
+/*
+ * \brief Dummy definitions of Linux Kernel functions
+ * \author Automatically generated file - do no edit
+ * \date 2022-05-04
+ */
+
+#include
+
+
+#include
+
+int ___ratelimit(struct ratelimit_state * rs,const char * func)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+struct page * __alloc_pages(gfp_t gfp,unsigned int order,int preferred_nid,nodemask_t * nodemask)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+const char * __clk_get_name(const struct clk * clk)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+unsigned long __get_free_pages(gfp_t gfp_mask,unsigned int order)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+void __icmp_send(struct sk_buff * skb_in,int type,int code,__be32 info,const struct ip_options * opt)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+int __ipv6_addr_type(const struct in6_addr * addr)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+struct irq_domain * __irq_domain_add(struct fwnode_handle * fwnode,int size,irq_hw_number_t hwirq_max,int direct_max,const struct irq_domain_ops * ops,void * host_data)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+struct irq_desc * __irq_resolve_mapping(struct irq_domain * domain,irq_hw_number_t hwirq,unsigned int * irq)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+void __netif_napi_del(struct napi_struct * napi)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+unsigned long __per_cpu_offset[NR_CPUS] = {};
+
+
+#include
+
+void __put_page(struct page * page)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+void __put_task_struct(struct task_struct * tsk)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+struct sk_buff * __skb_gso_segment(struct sk_buff * skb,netdev_features_t features,bool tx_path)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+const unsigned char _ctype[] = {};
+
+
+#include
+
+atomic_long_t _totalram_pages;
+
+
+#include
+
+int crypto_register_shash(struct shash_alg * alg)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+struct net_device * dev_get_by_index(struct net * net,int ifindex)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+void dev_get_tstats64(struct net_device * dev,struct rtnl_link_stats64 * s)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+asmlinkage __visible void dump_stack(void)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+extern void flush_dcache_page(struct page * page);
+void flush_dcache_page(struct page * page)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+void free_netdev(struct net_device * dev)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+void free_pages(unsigned long addr,unsigned int order)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+void free_uid(struct user_struct * up)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+unsigned int fwnode_count_parents(const struct fwnode_handle * fwnode)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+const char * fwnode_get_name(const struct fwnode_handle * fwnode)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+const char * fwnode_get_name_prefix(const struct fwnode_handle * fwnode)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+struct fwnode_handle * fwnode_get_nth_parent(struct fwnode_handle * fwnode,unsigned int depth)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+void fwnode_handle_put(struct fwnode_handle * fwnode)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include