diff --git a/repos/mml/src/lib/mxip/include/stdlib.h b/repos/mml/src/lib/mxip/include/stdlib.h
new file mode 100644
index 0000000000..2641481f45
--- /dev/null
+++ b/repos/mml/src/lib/mxip/include/stdlib.h
@@ -0,0 +1,15 @@
+#ifndef _LWIP__INCLUDE__STDLIB_H_
+#define _LWIP__INCLUDE__STDLIB_H_
+
+/**
+ * Simple atoi for LwIP purposes
+ */
+static inline int atoi(char const *s)
+{
+ int n = 0;
+ while ('0' <= *s && *s <= '9')
+ n = 10*n - (*s++ - '0');
+ return n;
+}
+
+#endif
diff --git a/repos/mml/src/lib/mxip/include/string.h b/repos/mml/src/lib/mxip/include/string.h
new file mode 100644
index 0000000000..0d4b83330f
--- /dev/null
+++ b/repos/mml/src/lib/mxip/include/string.h
@@ -0,0 +1,34 @@
+/*
+ * \brief Memory manipulation utilities
+ * \author Emery Hemingway
+ * \date 2017-08-21
+ */
+
+/*
+ * 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 __LWIP__INCLUDE__STRING_H__
+#define __LWIP__INCLUDE__STRING_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void *memcpy(void *dst, const void *src, size_t len);
+void *memset(void *b, int c, size_t len);
+
+size_t strlen(const char *s);
+
+int memcmp(const void *b1, const void *b2, size_t len);
+int strcmp(const char *s1, const char *s2);
+int strncmp(const char *s1, const char *s2, size_t len);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __LWIP__INCLUDE__STRING_H__ */
\ No newline at end of file
diff --git a/repos/mml/src/lib/mxip/memmove.patch b/repos/mml/src/lib/mxip/memmove.patch
new file mode 100644
index 0000000000..681805f15d
--- /dev/null
+++ b/repos/mml/src/lib/mxip/memmove.patch
@@ -0,0 +1,12 @@
+diff --git a/src/core/def.c b/src/core/def.c
+index 9da36fee..58edce6f 100644
+--- a/src/core/def.c
++++ b/src/core/def.c
+@@ -235,6 +235,6 @@ lwip_itoa(char *result, size_t bufsize, int number)
+ return;
+ }
+ /* move from temporary buffer to output buffer (sign is not moved) */
+- memmove(res, tmp, (size_t)((result + bufsize) - tmp));
++ MEMMOVE(res, tmp, (size_t)((result + bufsize) - tmp));
+ }
+ #endif
diff --git a/repos/mml/src/lib/mxip/platform/mxnic_netif.cc b/repos/mml/src/lib/mxip/platform/mxnic_netif.cc
new file mode 100644
index 0000000000..b70363e46d
--- /dev/null
+++ b/repos/mml/src/lib/mxip/platform/mxnic_netif.cc
@@ -0,0 +1,80 @@
+#include "mxnic_netif.h"
+#include
+
+void Lwip::Nic_netif::handle_rx_packets()
+{
+
+ Nic::Session::Rx::Sink *rx = _nic.rx();
+
+ bool progress = false;
+
+ while (rx->packet_avail() && rx->ready_to_ack()) {
+
+ try
+ {
+ Nic::Packet_descriptor packet = rx->try_get_packet();
+ progress = true;
+
+ Nic_netif_pbuf *nic_pbuf = new (this->_pbuf_alloc) Nic_netif_pbuf(*this, packet);
+
+ if (!nic_pbuf) {
+ Genode::warning("Could not allocate pbuf ");
+ return;
+ }
+ pbuf* p = pbuf_alloced_custom(
+ PBUF_RAW,
+ packet.size(),
+ PBUF_REF,
+ &nic_pbuf->p,
+ rx->packet_content(packet),
+ packet.size());
+ LINK_STATS_INC(link.recv);
+
+ if (!p) {
+ Genode::warning("Initialization of pbuf failed.");
+ return;
+ }
+
+ Lwip::Receive_task *task = new (_handler_allocator->allocate(0, 64, sizeof(Lwip::Receive_task))) Lwip::Receive_task(p, _netif, *this, nic_pbuf);
+ if (task == nullptr)
+ {
+ Genode::warning("Could not allocate task object.");
+ return;
+ }
+ task->annotate(static_cast(0));
+ mx::tasking::runtime::spawn(*task);
+
+ if (progress)
+ wake_up_nic_server();
+ }
+ catch (Genode::Exception)
+ {
+ Genode::warning("Got signal without actual packet in queue");
+ }
+ }
+}
+
+void Lwip::Nic_netif::handle_tx_ready()
+{
+ Lwip::Tx_ready_task *task = new (_handler_allocator->allocate(0, 64, sizeof(Lwip::Tx_ready_task))) Lwip::Tx_ready_task(_nic, *this);
+ if (task == nullptr)
+ {
+ Genode::warning("Could not allocate tx_ready task object.");
+ return;
+ }
+ task->annotate(static_cast(0));
+ mx::tasking::runtime::spawn(*task);
+
+
+}
+
+void Lwip::Nic_netif::handle_link_state()
+{
+ Lwip::Link_state_task *task = new (_handler_allocator->allocate(0, 64, sizeof(Lwip::Link_state_task))) Lwip::Link_state_task(_nic, _netif, *this, _dhcp); // mx::tasking::runtime::new_task(0, _nic, _netif, _dhcp);
+ if (task == nullptr) {
+ Genode::warning("Could not allocate link state task object.");
+ return;
+ }
+ task->annotate(static_cast(0));
+ mx::tasking::runtime::spawn(*task);
+}
\ No newline at end of file
diff --git a/repos/mml/src/lib/mxip/platform/printf.cc b/repos/mml/src/lib/mxip/platform/printf.cc
new file mode 100644
index 0000000000..38d93d694b
--- /dev/null
+++ b/repos/mml/src/lib/mxip/platform/printf.cc
@@ -0,0 +1,36 @@
+/*
+ * \brief Print function for debugging functionality of lwIP.
+ * \author Stefan Kalkowski
+ * \date 2009-10-26
+ */
+
+/*
+ * Copyright (C) 2009-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.
+ */
+
+/* Genode includes */
+#include
+#include
+
+extern "C" {
+
+/* LwIP includes */
+#include
+
+ /* Simply map to Genode's printf implementation */
+ void lwip_printf(const char *format, ...)
+ {
+ va_list list;
+ va_start(list, format);
+
+ char buf[128] { };
+ Genode::String_console(buf, sizeof(buf)).vprintf(format, list);
+ Genode::log(Genode::Cstring(buf));
+
+ va_end(list);
+ }
+
+}
diff --git a/repos/mml/src/lib/mxip/platform/rand.cc b/repos/mml/src/lib/mxip/platform/rand.cc
new file mode 100644
index 0000000000..0472c619cf
--- /dev/null
+++ b/repos/mml/src/lib/mxip/platform/rand.cc
@@ -0,0 +1,30 @@
+/*
+ * \brief Simple random number generator for lwIP
+ * \author Emery Hemingway
+ * \date 2016-07-30
+ */
+
+// *Really* minimal PCG32 code / (c) 2014 M.E. O'Neill / pcg-random.org
+// Licensed under Apache License 2.0 (NO WARRANTY, etc. see website)
+
+/* Genode includes */
+#include
+#include
+
+extern "C"
+genode_uint32_t genode_rand()
+{
+ using namespace Genode;
+
+ static uint64_t const inc = Trace::timestamp()|1;
+ static uint64_t state = Trace::timestamp();
+ uint64_t oldstate = state;
+
+ // Advance internal state
+ state = oldstate * 6364136223846793005ULL + inc;
+
+ // Calculate output function (XSH RR), uses old state for max ILP
+ uint32_t xorshifted = (uint32_t)(((oldstate >> 18u) ^ oldstate) >> 27u);
+ uint32_t rot = (uint32_t)(oldstate >> 59u);
+ return (xorshifted >> rot) | (xorshifted << ((-rot) & 31));
+}
diff --git a/repos/mml/src/lib/mxip/platform/sys_arch.cc b/repos/mml/src/lib/mxip/platform/sys_arch.cc
new file mode 100644
index 0000000000..26125d990f
--- /dev/null
+++ b/repos/mml/src/lib/mxip/platform/sys_arch.cc
@@ -0,0 +1,145 @@
+/*
+ * \brief lwIP platform support
+ * \author Stefan Kalkowski
+ * \author Emery Hemingway
+ * \date 2016-12-01
+ */
+
+/*
+ * 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.
+ */
+
+/* Genode includes */
+#include
+#include
+#include
+#include
+
+#include
+
+/* MxTasking includes */
+#include
+#include
+#include
+
+extern "C" {
+/* LwIP includes */
+#include
+#include
+#include
+
+/* our abridged copy of string.h */
+#include
+}
+
+namespace Mxip {
+
+ static mx::memory::dynamic::Allocator *_heap;
+ class Timeout_task : public mx::tasking::TaskInterface
+ {
+ public:
+ Timeout_task() {}
+
+ mx::tasking::TaskResult execute(std::uint16_t, std::uint16_t) override
+ {
+ //GENODE_LOG_TSC_NAMED(1, "sys_check_timeouts");
+ sys_check_timeouts();
+ _heap->free(static_cast(this));
+ return mx::tasking::TaskResult::make_null();
+ }
+ };
+
+ struct Mx_timer
+ {
+ void check_timeouts(Genode::Duration)
+ {
+ Timeout_task *task = new (_heap->allocate(0, 64, sizeof(Timeout_task))) Timeout_task(); // mx::tasking::runtime::new_task(0);
+ if (task == nullptr) {
+ Genode::error("Failed to allocate timeout task");
+ return;
+ }
+ task->annotate(static_cast(0));
+ mx::tasking::runtime::spawn(*task);
+ }
+
+ ::Timer::Connection &timer;
+
+ Timer::Periodic_timeout timeout{
+ timer, *this, &Mx_timer::check_timeouts, Genode::Microseconds{250 * 1000}};
+
+ Mx_timer(::Timer::Connection &timer) : timer(timer) {}
+ };
+
+ static Mx_timer *sys_timer_ptr;
+
+ void mxip_init(mx::memory::dynamic::Allocator &heap, ::Timer::Connection &timer)
+ {
+ _heap = &heap;
+
+ static Mx_timer sys_timer(timer);
+ sys_timer_ptr = &sys_timer;
+
+ lwip_init();
+ }
+
+}
+
+
+extern "C" {
+
+ void lwip_platform_assert(char const* msg, char const *file, int line)
+ {
+ Genode::error("Assertion \"", msg, "\" ", file, ":", line);
+ Genode::sleep_forever();
+ }
+
+ void genode_free(void *ptr)
+ {
+ Mxip::_heap->free(ptr);
+ }
+
+ void *genode_malloc(unsigned long size)
+ {
+ return Mxip::_heap->allocate(0, 64, size);
+ }
+
+ void *genode_calloc(unsigned long number, unsigned long size)
+ {
+ size *= number;
+
+ void * const ptr = genode_malloc(size);
+ if (ptr)
+ Genode::memset(ptr, 0x00, size);
+
+ return ptr;
+ }
+
+ u32_t sys_now(void) {
+ /* TODO: Use actual CPU frequency */
+ //return (u32_t)Mxip::sys_timer_ptr->timer.curr_time().trunc_to_plain_ms().value;
+ return __builtin_ia32_rdtsc() / 2000000;
+ }
+
+ void genode_memcpy(void *dst, const void *src, size_t len)
+ {
+ std::memcpy(dst, src, len); }
+
+ void *genode_memmove(void *dst, const void *src, size_t len) {
+ return std::memmove(dst, src, len); }
+
+ int memcmp(const void *b1, const void *b2, ::size_t len) {
+ return std::memcmp(b1, b2, len); }
+
+ int strcmp(const char *s1, const char *s2)
+ {
+ size_t len = std::min(Genode::strlen(s1), Genode::strlen(s2));
+ return std::strncmp(s1, s2, len);
+ }
+
+ int strncmp(const char *s1, const char *s2, size_t len) {
+ return std::strncmp(s1, s2, len); }
+
+}