diff --git a/run/log_udp.run b/run/log_udp.run
new file mode 100644
index 0000000..ebf7b60
--- /dev/null
+++ b/run/log_udp.run
@@ -0,0 +1,73 @@
+proc nic_drv_opt {} {
+ if {[have_spec linux]} {
+ return "ld=\"no\""
+ }
+ return ""
+}
+
+#
+# Test logging to file system
+#
+
+set build_components {
+ core init timer
+ proxy/log_udp
+ test/bomb
+ drivers/nic
+}
+
+source ${genode_dir}/repos/base/run/platform_drv.inc
+append_platform_drv_build_components
+
+build $build_components
+
+create_boot_directory
+
+
+install_config {
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+}
+
+append boot_modules {
+ core init ld.lib.so bomb timer log_udp
+ } [nic_drv_binary] {
+}
+
+append_platform_drv_boot_modules
+build_boot_image $boot_modules
+
+append qemu_args " -nographic"
+append qemu_args " -net tap,ifname=tap1 "
+
+run_genode_until forever
diff --git a/src/proxy/log_udp/README b/src/proxy/log_udp/README
new file mode 100644
index 0000000..d96458f
--- /dev/null
+++ b/src/proxy/log_udp/README
@@ -0,0 +1,13 @@
+log_udp is a LOG client that receives log messages as UDP
+packets and forwards the messages to a local LOG session.
+
+By default, this component listens on UDP port 9 and
+forwards every message (irrespective of IP addresses).
+It also responds to ARP messages that are directed to
+its IP address.
+
+!
+!
+!
+!
+!
diff --git a/src/proxy/log_udp/main.cc b/src/proxy/log_udp/main.cc
new file mode 100644
index 0000000..7e48402
--- /dev/null
+++ b/src/proxy/log_udp/main.cc
@@ -0,0 +1,54 @@
+/*
+ * \brief Receive LOG messages via UDP and forward to LOG session.
+ * \author Johannes Schlatow
+ * \date 2018-11-02
+ */
+
+/*
+ * Copyright (C) 2018 Genode Labs GmbH
+ *
+ * This file is part of the Genode OS framework, which is distributed
+ * under the terms of the GNU General Public License version 2.
+ */
+
+#include
+#include
+#include
+
+#include "receiver.h"
+
+#include
+#include
+
+
+using namespace Net;
+
+namespace Log_udp {
+ using Genode::size_t;
+ using Genode::Attached_rom_dataspace;
+ using Genode::Xml_node;
+
+ struct Main;
+};
+
+struct Log_udp::Main
+{
+ Genode::Env &env;
+ Genode::Heap heap { &env.ram(), &env.rm() };
+ Attached_rom_dataspace config { env, "config" };
+ Receiver receiver { env, heap, config.xml() };
+
+
+ Main(Genode::Env &env) : env(env)
+ { }
+
+};
+
+namespace Component {
+ Genode::size_t stack_size() { return 2*1024*sizeof(long); }
+ void construct(Genode::Env &env)
+ {
+ env.exec_static_constructors();
+ static Log_udp::Main main(env);
+ }
+}
diff --git a/src/proxy/log_udp/receiver.h b/src/proxy/log_udp/receiver.h
new file mode 100644
index 0000000..987e555
--- /dev/null
+++ b/src/proxy/log_udp/receiver.h
@@ -0,0 +1,270 @@
+/*
+ * \brief UDP log receiver
+ * \author Johannes Schlatow
+ * \date 2018-11-02
+ */
+
+/*
+ * Copyright (C) 2018 Genode Labs GmbH
+ *
+ * This file is part of the Genode OS framework, which is distributed
+ * under the terms of the GNU General Public License version 2.
+ */
+
+#include
+#include
+
+#include
+#include
+
+#include
+#include
+
+using namespace Net;
+
+namespace Log_udp {
+ using Genode::size_t;
+ using Genode::Xml_node;
+ using Nic::Packet_stream_sink;
+ using Nic::Packet_stream_source;
+ using Nic::Packet_descriptor;
+
+ class Receiver;
+};
+
+class Log_udp::Receiver
+{
+ private:
+ enum {
+ PACKET_SIZE = 512,
+ BUF_SIZE = Nic::Session::QUEUE_SIZE * PACKET_SIZE,
+ };
+
+ Nic::Packet_allocator _tx_block_alloc;
+ Nic::Connection _nic;
+
+ Mac_address const _mac { _nic.mac_address() };
+ Ipv4_address const _default_ip { (Genode::uint8_t)0x00 };
+ Ipv4_address const _ip;
+ Port const _default_port { 9 };
+ Port const _port;
+ bool _verbose { false };
+
+ Genode::Signal_handler _sink_ack;
+ Genode::Signal_handler _sink_submit;
+ Genode::Signal_handler _source_ack;
+ Genode::Signal_handler _source_submit;
+
+ /**
+ * submit queue not empty anymore
+ */
+ void _ready_to_submit();
+
+ /**
+ * acknowledgement queue not full anymore
+ *
+ * we assume ACK and SUBMIT queue to be equally
+ * dimensioned so that this signal can be ignored.
+ */
+ void _ack_avail() { }
+
+ /**
+ * acknowledgement queue not empty anymore
+ */
+ void _ready_to_ack()
+ {
+ /* check for acknowledgements */
+ while (source()->ack_avail())
+ source()->release_packet(source()->get_acked_packet());
+ }
+
+ /**
+ * submit queue not full anymore
+ *
+ * by now, packets are dropped if submit queue is full
+ */
+ void _packet_avail() { }
+
+
+ Packet_stream_sink< ::Nic::Session::Policy> * sink() {
+ return _nic.rx(); }
+
+ Packet_stream_source< ::Nic::Session::Policy> * source() {
+ return _nic.tx(); }
+
+ public:
+ Receiver(Genode::Env &env, Genode::Allocator &alloc, Xml_node config)
+ :
+ _tx_block_alloc(&alloc),
+ _nic(env, &_tx_block_alloc, BUF_SIZE, BUF_SIZE),
+ _ip (config.attribute_value("ip", _default_ip)),
+ _port (config.attribute_value("port", _default_port)),
+ _verbose(config.attribute_value("verbose", _verbose)),
+ _sink_ack (env.ep(), *this, &Receiver::_ack_avail),
+ _sink_submit (env.ep(), *this, &Receiver::_ready_to_submit),
+ _source_ack (env.ep(), *this, &Receiver::_ready_to_ack),
+ _source_submit(env.ep(), *this, &Receiver::_packet_avail)
+ {
+ _nic.rx_channel()->sigh_ready_to_ack(_sink_ack);
+ _nic.rx_channel()->sigh_packet_avail(_sink_submit);
+ _nic.tx_channel()->sigh_ack_avail(_source_ack);
+ _nic.tx_channel()->sigh_ready_to_submit(_source_submit);
+ }
+
+ /**
+ * Handle an ethernet packet
+ *
+ * \param src ethernet frame's address
+ * \param size ethernet frame's size.
+ */
+ void handle_ethernet(void* src, Genode::size_t size);
+
+ /*
+ * Handle an ARP packet
+ *
+ * \param eth ethernet frame containing the ARP packet.
+ * \param size size guard
+ */
+ void handle_arp(Ethernet_frame ð,
+ Size_guard &size_guard);
+
+ /*
+ * Handle an IP packet
+ *
+ * \param eth ethernet frame containing the IP packet.
+ * \param size size guard
+ */
+ void handle_ip(Ethernet_frame ð,
+ Size_guard &size_guard);
+
+ /*
+ * Handle a LOG message packet
+ *
+ * \param udp UDP packet containing the LOG message.
+ * \param size size guard
+ */
+ void handle_message(Udp_packet &udp,
+ Size_guard &size_guard);
+
+ /**
+ * Send ethernet frame
+ *
+ * \param eth ethernet frame to send.
+ * \param size ethernet frame's size.
+ */
+ void send(Ethernet_frame *eth, Genode::size_t size);
+
+};
+
+void Log_udp::Receiver::_ready_to_submit()
+{
+ Packet_descriptor _packet { };
+
+ /* as long as packets are available, and we can ack them */
+ while (sink()->packet_avail()) {
+ _packet = sink()->get_packet();
+ if (_packet.size()) {
+ handle_ethernet(sink()->packet_content(_packet), _packet.size());
+ }
+
+ if (!sink()->ready_to_ack()) {
+ Genode::warning("ack state FULL");
+ return;
+ }
+
+ sink()->acknowledge_packet(_packet);
+ }
+}
+
+void Log_udp::Receiver::handle_ethernet(void* src, Genode::size_t size)
+{
+ try {
+ /* parse ethernet frame header */
+ Size_guard size_guard(size);
+ Ethernet_frame ð = Ethernet_frame::cast_from(src, size_guard);
+ switch (eth.type()) {
+ case Ethernet_frame::Type::ARP:
+ handle_arp(eth, size_guard);
+ break;
+ case Ethernet_frame::Type::IPV4:
+ handle_ip(eth, size_guard);
+ break;
+ default:
+ ;
+ }
+ } catch(Size_guard::Exceeded) {
+ Genode::warning("Packet size guard exceeded!");
+ }
+}
+
+void Log_udp::Receiver::handle_arp(Ethernet_frame ð,
+ Size_guard &size_guard)
+{
+ /* ignore broken packets */
+ Arp_packet &arp = eth.data(size_guard);
+ if (!arp.ethernet_ipv4())
+ return;
+
+ /* look whether the IP address is our's */
+ if (arp.dst_ip() == _ip) {
+ if (arp.opcode() == Arp_packet::REQUEST) {
+ /*
+ * The ARP packet gets re-written, we interchange source
+ * and destination MAC and IP addresses, and set the opcode
+ * to reply, and then push the packet back to the NIC driver.
+ */
+ Ipv4_address old_src_ip = arp.src_ip();
+ arp.opcode(Arp_packet::REPLY);
+ arp.dst_mac(arp.src_mac());
+ arp.src_mac(_mac);
+ arp.src_ip(arp.dst_ip());
+ arp.dst_ip(old_src_ip);
+ eth.dst(arp.dst_mac());
+
+ /* set our MAC as sender */
+ eth.src(_mac);
+ send(ð, size_guard.total_size());
+ }
+ }
+}
+
+void Log_udp::Receiver::handle_ip(Ethernet_frame ð,
+ Size_guard &size_guard)
+{
+ Ipv4_packet &ip = eth.data(size_guard);
+ if (ip.protocol() == Ipv4_packet::Protocol::UDP) {
+
+ Udp_packet &udp = ip.data(size_guard);
+ if (udp.dst_port() == Port(9))
+ handle_message(udp, size_guard);
+ }
+}
+
+void Log_udp::Receiver::handle_message(Udp_packet &udp,
+ Size_guard &size_guard)
+{
+ char *msg = &udp.data(size_guard);
+
+ /* consume until '\0' */
+ size_t len = 0;
+ for (char* s=msg; s && *s; s++, len++) {
+ if (len)
+ size_guard.consume_head(1);
+ }
+
+ if (len)
+ Genode::log(Genode::Cstring(msg, len-1));
+}
+
+void Log_udp::Receiver::send(Ethernet_frame *eth, Genode::size_t size)
+{
+ try {
+ /* copy and submit packet */
+ Packet_descriptor packet = source()->alloc_packet(size);
+ char *content = source()->packet_content(packet);
+ Genode::memcpy((void*)content, (void*)eth, size);
+ source()->submit_packet(packet);
+ } catch(Packet_stream_source< ::Nic::Session::Policy>::Packet_alloc_failed) {
+ Genode::warning("Packet dropped");
+ }
+}
diff --git a/src/proxy/log_udp/target.mk b/src/proxy/log_udp/target.mk
new file mode 100644
index 0000000..4b49f1b
--- /dev/null
+++ b/src/proxy/log_udp/target.mk
@@ -0,0 +1,3 @@
+TARGET = log_udp
+SRC_CC = main.cc
+LIBS = base net