diff --git a/repos/dde_linux/run/vfs_lxip.inc b/repos/dde_linux/run/vfs_lxip.inc
new file mode 100644
index 0000000000..9b6396521f
--- /dev/null
+++ b/repos/dde_linux/run/vfs_lxip.inc
@@ -0,0 +1,13 @@
+assert_spec x86
+
+proc append_socket_fs_build_components { } {
+ global build_components
+ append build_components { lib/vfs/lxip }
+}
+
+proc socket_fs_plugin {} { return lxip }
+
+proc append_socket_fs_boot_modules {} {
+ global boot_modules
+ append boot_modules { lxip.lib.so vfs_lxip.lib.so }
+}
diff --git a/repos/libports/include/lwip/arch/cc.h b/repos/libports/include/lwip/arch/cc.h
new file mode 100644
index 0000000000..5ea8477dd6
--- /dev/null
+++ b/repos/libports/include/lwip/arch/cc.h
@@ -0,0 +1,100 @@
+/*
+ * \brief Some size definitions and macros needed by LwIP.
+ * \author Stefan Kalkowski
+ * \author Emery Hemingway
+ * \date 2009-11-10
+ */
+
+/*
+ * 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.
+ */
+
+#ifndef __LWIP__ARCH__CC_H__
+#define __LWIP__ARCH__CC_H__
+
+#include
+
+
+#ifndef LWIP_RAND
+genode_uint32_t genode_rand();
+#define LWIP_RAND() genode_rand()
+#endif
+
+
+#ifndef LWIP_NO_STDDEF_H
+#define LWIP_NO_STDDEF_H 1
+typedef unsigned long size_t;
+typedef long ptrdiff_t;
+#endif /* LWIP_NO_STDDEF_H */
+
+
+#ifndef LWIP_NO_STDINT_H
+#define LWIP_NO_STDINT_H 1
+typedef genode_uint8_t u8_t;
+typedef genode_int8_t s8_t;
+typedef genode_uint16_t u16_t;
+typedef genode_int16_t s16_t;
+typedef genode_uint32_t u32_t;
+typedef genode_int32_t s32_t;
+
+typedef unsigned long mem_ptr_t;
+#endif /* LWIP_NO_STDINT_H */
+
+
+#ifndef LWIP_NO_INTTYPES_H
+#define LWIP_NO_INTTYPES_H 1
+/* Define (sn)printf formatters */
+#define U16_F "u" // we don't have hu
+#define S16_F "d" // we don't have hd
+#define X16_F "x" // we don't have hx
+#define U32_F "u"
+#define S32_F "d"
+#define X32_F "x"
+#endif /* LWIP_NO_INTTYPES_H */
+
+
+#ifndef LWIP_PLATFORM_DIAG
+void lwip_printf(const char *format, ...);
+#define LWIP_PLATFORM_DIAG(x) do { lwip_printf x; } while(0)
+#endif /* LWIP_PLATFORM_DIAG */
+
+
+#ifdef GENODE_RELEASE
+#define LWIP_PLATFORM_ASSERT(x)
+#else /* GENODE_RELEASE */
+void lwip_platform_assert(char const* msg, char const *file, int line);
+#define LWIP_PLATFORM_ASSERT(x) \
+ do { \
+ lwip_platform_assert(x, __FILE__, __LINE__); \
+ } while (0)
+#endif /* GENODE_RELEASE */
+
+
+#ifndef LWIP_NO_LIMITS_H
+#define LWIP_NO_LIMITS_H 1
+#endif
+
+
+#define LWIP_SKIP_PACKING_CHECK 1
+#define PACK_STRUCT_FIELD(x) x
+#define PACK_STRUCT_STRUCT
+#define PACK_STRUCT_BEGIN
+#define PACK_STRUCT_END
+
+#ifndef BYTE_ORDER
+#define BYTE_ORDER LITTLE_ENDIAN
+#endif /* BYTE_ORDER */
+
+
+void genode_free(void *ptr);
+void *genode_malloc(unsigned long size);
+void *genode_calloc(unsigned long number, unsigned long size);
+
+#define mem_clib_free genode_free
+#define mem_clib_malloc genode_malloc
+#define mem_clib_calloc genode_calloc
+
+#endif /* __LWIP__ARCH__CC_H__ */
diff --git a/repos/libports/include/lwip/arch/perf.h b/repos/libports/include/lwip/arch/perf.h
new file mode 100644
index 0000000000..eea977777f
--- /dev/null
+++ b/repos/libports/include/lwip/arch/perf.h
@@ -0,0 +1,20 @@
+/*
+ * \brief Header file with macros needed by LwIP.
+ * \author Stefan Kalkowski
+ * \date 2009-11-10
+ */
+
+/*
+ * 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.
+ */
+
+#ifndef __LWIP__ARCH__PERF_H__
+#define __LWIP__ARCH__PERF_H__
+
+#define PERF_START
+#define PERF_STOP(x)
+
+#endif /* __LWIP__ARCH__PERF_H__ */
diff --git a/repos/libports/include/lwip/genode_init.h b/repos/libports/include/lwip/genode_init.h
new file mode 100644
index 0000000000..531c6ac3e7
--- /dev/null
+++ b/repos/libports/include/lwip/genode_init.h
@@ -0,0 +1,22 @@
+/*
+ * \brief Genode native lwIP initalization
+ * \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 _INCLUDE__LWIP__GENODE_INIT_H_
+#define _INCLUDE__LWIP__GENODE_INIT_H_
+
+#include
+#include
+
+namespace Lwip { void genode_init(Genode::Allocator &heap, Genode::Timeout_scheduler &timer); }
+
+#endif
diff --git a/repos/libports/include/lwip/lwipopts.h b/repos/libports/include/lwip/lwipopts.h
new file mode 100644
index 0000000000..91ff881d5c
--- /dev/null
+++ b/repos/libports/include/lwip/lwipopts.h
@@ -0,0 +1,133 @@
+/*
+ * \brief Configuration file for LwIP, adapt it to your needs.
+ * \author Stefan Kalkowski
+ * \author Emery Hemingway
+ * \date 2009-11-10
+ *
+ * See lwip/src/include/lwip/opt.h for all options
+ */
+
+/*
+ * 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.
+ */
+
+#ifndef __LWIP__LWIPOPTS_H__
+#define __LWIP__LWIPOPTS_H__
+
+/* Genode includes */
+#include
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Use lwIP without OS-awareness
+ */
+#define NO_SYS 1
+#define SYS_LIGHTWEIGHT_PROT 0
+
+#define LWIP_DNS 1 /* DNS support */
+#define LWIP_DHCP 1 /* DHCP support */
+#define LWIP_SOCKET 0 /* LwIP socket API */
+#define LWIP_NETIF_LOOPBACK 1 /* Looping back to same address? */
+#define LWIP_STATS 0 /* disable stating */
+#define LWIP_TCP_TIMESTAMPS 1
+#define TCP_MSS 1460
+#define TCP_WND (32 * TCP_MSS)
+#define TCP_SND_BUF (32 * TCP_MSS)
+#define LWIP_WND_SCALE 3
+#define TCP_RCV_SCALE 2
+#define TCP_SND_QUEUELEN ((8 * (TCP_SND_BUF) + (TCP_MSS - 1))/(TCP_MSS))
+
+#define LWIP_NETIF_STATUS_CALLBACK 1 /* callback function used for interface changes */
+#define LWIP_NETIF_LINK_CALLBACK 1 /* callback function used for link-state changes */
+
+
+/***********************************
+ ** Checksum calculation settings **
+ ***********************************/
+
+/* checksum calculation for outgoing packets can be disabled if the hardware supports it */
+#define LWIP_CHECKSUM_ON_COPY 1 /* calculate checksum during memcpy */
+
+/*********************
+ ** Memory settings **
+ *********************/
+
+#define MEM_LIBC_MALLOC 1
+#define MEMP_MEM_MALLOC 1
+/* MEM_ALIGNMENT > 4 e.g. for x86_64 are not supported, see Genode issue #817 */
+#define MEM_ALIGNMENT 4
+
+#define DEFAULT_ACCEPTMBOX_SIZE 128
+#define TCPIP_MBOX_SIZE 128
+
+#define RECV_BUFSIZE_DEFAULT (512*1024)
+
+#define PBUF_POOL_SIZE 96
+
+#define MEMP_NUM_SYS_TIMEOUT 16
+#define MEMP_NUM_TCP_PCB 128
+
+void genode_memcpy(void * dst, const void *src, unsigned long size);
+#define MEMCPY(dst,src,len) genode_memcpy(dst,src,len)
+
+/********************
+ ** Debug settings **
+ ********************/
+
+/* #define LWIP_DEBUG */
+/* #define DHCP_DEBUG LWIP_DBG_ON */
+/* #define ETHARP_DEBUG LWIP_DBG_ON */
+/* #define NETIF_DEBUG LWIP_DBG_ON */
+/* #define PBUF_DEBUG LWIP_DBG_ON */
+/* #define API_LIB_DEBUG LWIP_DBG_ON */
+/* #define API_MSG_DEBUG LWIP_DBG_ON */
+/* #define SOCKETS_DEBUG LWIP_DBG_ON */
+/* #define ICMP_DEBUG LWIP_DBG_ON */
+/* #define INET_DEBUG LWIP_DBG_ON */
+/* #define IP_DEBUG LWIP_DBG_ON */
+/* #define IP_REASS_DEBUG LWIP_DBG_ON */
+/* #define RAW_DEBUG LWIP_DBG_ON */
+/* #define MEM_DEBUG LWIP_DBG_ON */
+/* #define MEMP_DEBUG LWIP_DBG_ON */
+/* #define SYS_DEBUG LWIP_DBG_ON */
+/* #define TCP_DEBUG LWIP_DBG_ON */
+
+
+/*
+ ----------------------------------
+ ---------- DHCP options ----------
+ ----------------------------------
+*/
+
+#define LWIP_DHCP_CHECK_LINK_UP 1
+
+
+/*
+ ----------------------------------------------
+ ---------- Sequential layer options ----------
+ ----------------------------------------------
+*/
+/* no Netconn API */
+#define LWIP_NETCONN 0
+
+
+/*
+ ---------------------------------------
+ ---------- IPv6 options ---------------
+ ---------------------------------------
+*/
+
+#define LWIP_IPV6 1
+#define IPV6_FRAG_COPYHEADER 1
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __LWIP__LWIPOPTS_H__ */
diff --git a/repos/libports/include/lwip/nic_netif.h b/repos/libports/include/lwip/nic_netif.h
new file mode 100644
index 0000000000..c4fb5d4d14
--- /dev/null
+++ b/repos/libports/include/lwip/nic_netif.h
@@ -0,0 +1,416 @@
+/*
+ * \brief LwIP netif for the Nic session
+ * \author Emery Hemingway
+ * \date 2016-09-28
+ *
+ * If you want to use the lwIP API in a native Genode
+ * component then this is the Nic client to use.
+ */
+
+/*
+ * 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 __LWIP__NIC_NETIF_H__
+#define __LWIP__NIC_NETIF_H__
+
+#if ETH_PAD_SIZE
+#error ETH_PAD_SIZE defined but unsupported by lwip/nic_netif.h
+#endif
+
+#ifndef __cplusplus
+#error lwip/nic_netif.h is a C++ only header
+#endif
+
+/* Genode includes */
+#include
+#include
+#include
+
+namespace Lwip {
+
+extern "C" {
+/* LwIP includes */
+#include
+#include
+#if LWIP_IPV6
+#include
+#endif
+#include
+#include
+}
+
+ class Nic_netif;
+
+ extern "C" {
+
+ /**
+ * Metadata for packet backed pbufs
+ */
+ struct nic_netif_pbuf
+ {
+ struct pbuf_custom p { };
+ Nic_netif *netif = nullptr;
+ Nic::Packet_descriptor packet { };
+ };
+
+ static void nic_netif_pbuf_free(pbuf *p);
+ static err_t nic_netif_init(struct netif *netif);
+ static err_t nic_netif_linkoutput(struct netif *netif, struct pbuf *p);
+ static void nic_netif_status_callback(struct netif *netif);
+ }
+}
+
+
+class Lwip::Nic_netif
+{
+ private:
+
+ enum {
+ PBUFS_QUEUE_SIZE = 128,
+ NIC_BUF_SIZE =
+ Nic::Packet_allocator::DEFAULT_PACKET_SIZE *
+ PBUFS_QUEUE_SIZE
+ };
+
+ nic_netif_pbuf _pbufs[PBUFS_QUEUE_SIZE];
+ unsigned _pbufs_next = 0;
+ unsigned _alloced = 0;
+
+ Nic::Packet_allocator _nic_tx_alloc;
+ Nic::Connection _nic;
+
+ struct netif _netif { };
+
+ ip_addr_t ip { };
+ ip_addr_t nm { };
+ ip_addr_t gw { };
+
+ Genode::Io_signal_handler _link_state_handler;
+ Genode::Io_signal_handler _rx_packet_handler;
+
+ public:
+
+ void free_pbuf(nic_netif_pbuf &pbuf)
+ {
+ if (!_nic.rx()->ready_to_ack()) {
+ Genode::error("Nic rx acknowledgement queue congested, blocking to free pbuf");
+ }
+
+ _nic.rx()->acknowledge_packet(pbuf.packet);
+ pbuf.packet = Nic::Packet_descriptor();
+ }
+
+
+ /*************************
+ ** Nic signal handlers **
+ *************************/
+
+ void handle_link_state()
+ {
+ /*
+ * if the application wants to know what is going
+ * on then it should use 'set_link_callback'
+ */
+
+ if (_nic.link_state()) {
+ netif_set_link_up(&_netif);
+ /* XXX: DHCP? */
+ } else {
+ netif_set_link_down(&_netif);
+ }
+ }
+
+ void handle_rx_packets()
+ {
+ auto &rx = *_nic.rx();
+
+ while (rx.packet_avail() && rx.ready_to_ack()) {
+ unsigned const initial_index = _pbufs_next;
+
+ while (_pbufs[_pbufs_next].packet.size()) {
+ _pbufs_next = (_pbufs_next+1) % PBUFS_QUEUE_SIZE;
+ if (_pbufs_next == initial_index) {
+ /* internal pbuf queue congested */
+ return;
+ }
+ }
+
+ Nic::Packet_descriptor const packet = rx.get_packet();
+
+ nic_netif_pbuf &nic_pbuf = _pbufs[_pbufs_next];
+ _pbufs_next = (_pbufs_next+1) % PBUFS_QUEUE_SIZE;
+
+ nic_pbuf.p.custom_free_function = nic_netif_pbuf_free;
+ nic_pbuf.netif = this;
+ nic_pbuf.packet = packet;
+
+ 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 (_netif.input(p, &_netif) != ERR_OK) {
+ Genode::error("error forwarding Nic packet to lwIP");
+ pbuf_free(p);
+ }
+ }
+ }
+
+ void configure(Genode::Xml_node const &config)
+ {
+ if (config.attribute_value("dhcp", false)) {
+
+ err_t err = dhcp_start(&_netif);
+ if (err == ERR_OK)
+ Genode::log("configuring lwIP interface with DHCP");
+ else
+ Genode::error("failed to configure lwIP interface with DHCP, error ", -err);
+
+ } else /* get addressing from config */ {
+ typedef Genode::String Str;
+ Str ip_str = config.attribute_value("ip_addr", Str());
+ ip_addr_t ipaddr;
+ if (!ipaddr_aton(ip_str.string(), &ipaddr)) {
+ Genode::error("lwIP configured with invalid IP address '",ip_str,"'");
+ throw ip_str;
+ }
+
+ if (IP_IS_V6_VAL(ipaddr)) {
+ netif_create_ip6_linklocal_address(&_netif, 1);
+ err_t err = netif_add_ip6_address(&_netif, ip_2_ip6(&ipaddr), NULL);
+ if (err != ERR_OK) {
+ Genode::error("failed to set lwIP IPv6 address to '",ip_str,"'");
+ throw err;
+ }
+ } else {
+ netif_set_ipaddr(&_netif, ip_2_ip4(&ipaddr));
+
+ if (config.has_attribute("netmask")) {
+ Str str = config.attribute_value("netmask", Str());
+ ip_addr_t ip;
+ ipaddr_aton(str.string(), &ip);
+ netif_set_netmask(&_netif, ip_2_ip4(&ip));
+ }
+
+ if (config.has_attribute("gateway")) {
+ Str str = config.attribute_value("gateway", Str());
+ ip_addr_t ip;
+ ipaddr_aton(str.string(), &ip);
+ netif_set_gw(&_netif, ip_2_ip4(&ip));
+ }
+
+ /* inform DHCP servers of our fixed IP address */
+ dhcp_inform(&_netif);
+ }
+ }
+ }
+
+ Nic_netif(Genode::Env &env,
+ Genode::Allocator &alloc,
+ Genode::Xml_node config)
+ :
+ _nic_tx_alloc(&alloc),
+ _nic(env, &_nic_tx_alloc, NIC_BUF_SIZE, NIC_BUF_SIZE,
+ config.attribute_value("label", Genode::String<160>("lwip")).string()),
+ _link_state_handler(env.ep(), *this, &Nic_netif::handle_link_state),
+ _rx_packet_handler( env.ep(), *this, &Nic_netif::handle_rx_packets)
+ {
+ Genode::memset(&_netif, 0x00, sizeof(_netif));
+
+ {
+ ip4_addr_t v4dummy;
+ IP4_ADDR(&v4dummy, 0, 0, 0, 0);
+
+ netif* r = netif_add(&_netif, &v4dummy, &v4dummy, &v4dummy,
+ this, nic_netif_init, ethernet_input);
+ if (r == NULL) {
+ Genode::error("failed to initialize Nic to lwIP interface");
+ throw r;
+ }
+ }
+
+ netif_set_default(&_netif);
+ netif_set_up(&_netif);
+ configure(config);
+ netif_set_status_callback(
+ &_netif, nic_netif_status_callback);
+ nic_netif_status_callback(&_netif);
+ }
+
+ virtual ~Nic_netif() { }
+
+ /**
+ * Status callback to override in subclass
+ */
+ virtual void status_callback() { }
+
+ /**
+ * Callback issued by lwIP to initialize netif struct
+ *
+ * \noapi
+ */
+ err_t init()
+ {
+ /*
+ * XXX: hostname and MTU could probably be
+ * set in the Nic client constructor
+ */
+
+#if LWIP_NETIF_HOSTNAME
+ /* Initialize interface hostname */
+ _netif.hostname = "";
+#endif /* LWIP_NETIF_HOSTNAME */
+
+ _netif.name[0] = 'e';
+ _netif.name[1] = 'n';
+
+ _netif.output = etharp_output;
+#if LWIP_IPV6
+ _netif.output_ip6 = ethip6_output;
+#endif /* LWIP_IPV6 */
+
+ _netif.linkoutput = nic_netif_linkoutput;
+
+ /* Set physical MAC address */
+ Nic::Mac_address const mac = _nic.mac_address();
+ for(int i=0; i<6; ++i)
+ _netif.hwaddr[i] = mac.addr[i];
+
+ _netif.mtu = 1500; /* XXX: just a guess */
+ _netif.hwaddr_len = ETHARP_HWADDR_LEN;
+ _netif.flags = NETIF_FLAG_BROADCAST |
+ NETIF_FLAG_ETHARP |
+ NETIF_FLAG_LINK_UP;
+
+ /* set Nic session signal handlers */
+ _nic.link_state_sigh(_link_state_handler);
+ _nic.rx_channel()->sigh_packet_avail(_rx_packet_handler);
+ _nic.rx_channel()->sigh_ready_to_ack(_rx_packet_handler);
+
+ return ERR_OK;
+ }
+
+ /**
+ * Callback issued by lwIP to write a Nic packet
+ *
+ * \noapi
+ */
+ err_t linkoutput(struct pbuf *p)
+ {
+ auto &tx = *_nic.tx();
+
+ /* flush acknowledgements */
+ while (tx.ack_avail())
+ tx.release_packet(tx.get_acked_packet());
+
+ if (!tx.ready_to_submit()) {
+ Genode::error("lwIP: Nic packet queue congested, cannot send packet");
+ return ERR_WOULDBLOCK;
+ }
+
+ Nic::Packet_descriptor packet;
+ try { packet = tx.alloc_packet(p->tot_len); }
+ catch (...) {
+ Genode::error("lwIP: Nic packet allocation failed, cannot send packet");
+ return ERR_WOULDBLOCK;
+ }
+
+ /*
+ * We iterate over the pbuf chain until we have read the entire
+ * pbuf into the packet.
+ */
+ char *dst = tx.packet_content(packet);
+ for(struct pbuf *q = p; q != 0; q = q->next) {
+ char const *src = (char*)q->payload;
+ Genode::memcpy(dst, src, q->len);
+ dst += q->len;
+ }
+
+ tx.submit_packet(packet);
+ LINK_STATS_INC(link.xmit);
+ return ERR_OK;
+ }
+
+ bool ready()
+ {
+ return netif_is_up(&_netif) &&
+ !ip_addr_isany(&_netif.ip_addr);
+ }
+};
+
+
+/**************************
+ ** LwIP netif callbacks **
+ **************************/
+
+namespace Lwip {
+ extern "C" {
+
+/**
+ * Free a packet buffer backed pbuf
+ */
+static void nic_netif_pbuf_free(pbuf *p)
+{
+ nic_netif_pbuf *nic_pbuf = (nic_netif_pbuf*)(p);
+ nic_pbuf->netif->free_pbuf(*nic_pbuf);
+}
+
+
+/**
+ * Initialize the netif
+ */
+static err_t nic_netif_init(struct netif *netif)
+{
+ Lwip::Nic_netif *nic_netif = (Lwip::Nic_netif *)netif->state;
+ return nic_netif->init();
+}
+
+
+/**
+ * Send a raw packet to the Nic session
+ */
+static err_t nic_netif_linkoutput(struct netif *netif, struct pbuf *p)
+{
+ Lwip::Nic_netif *nic_netif = (Lwip::Nic_netif *)netif->state;
+ return nic_netif->linkoutput(p);
+}
+
+
+static void nic_netif_status_callback(struct netif *netif)
+{
+ Lwip::Nic_netif *nic_netif = (Lwip::Nic_netif *)netif->state;
+
+ if (netif_is_up(netif)) {
+ if (IP_IS_V6_VAL(netif->ip_addr)) {
+ Genode::log("lwIP Nic interface up"
+ ", address=",(char const*)ip6addr_ntoa(netif_ip6_addr(netif, 0)));
+ } else if (!ip4_addr_isany(netif_ip4_addr(netif))) {
+ typedef Genode::String Str;
+ Str address((char const*)ip4addr_ntoa(netif_ip4_addr(netif)));
+ Str netmask((char const*)ip4addr_ntoa(netif_ip4_netmask(netif)));
+ Str gateway((char const*)ip4addr_ntoa(netif_ip4_gw(netif)));
+
+ Genode::log("lwIP Nic interface up"
+ " address=", address,
+ " netmask=", netmask,
+ " gateway=", gateway);
+ }
+ } else {
+ Genode::log("lwIP Nic interface down");
+ }
+
+ nic_netif->status_callback();
+}
+
+ }
+}
+
+#endif /* __LWIP__NIC_NETIF_H__ */
diff --git a/repos/libports/lib/import/import-lwip.mk b/repos/libports/lib/import/import-lwip.mk
new file mode 100644
index 0000000000..e212bb85d1
--- /dev/null
+++ b/repos/libports/lib/import/import-lwip.mk
@@ -0,0 +1,2 @@
+INC_DIR += $(call select_from_ports,lwip)/include/lwip
+INC_DIR += $(call select_from_repositories,include/lwip)
diff --git a/repos/libports/lib/mk/lwip.mk b/repos/libports/lib/mk/lwip.mk
new file mode 100644
index 0000000000..adbab414df
--- /dev/null
+++ b/repos/libports/lib/mk/lwip.mk
@@ -0,0 +1,41 @@
+#
+# lwIP TCP/IP library
+#
+# The library implements TCP and UDP as well as DNS and DHCP.
+#
+
+LWIP_PORT_DIR := $(call select_from_ports,lwip)
+LWIPDIR := $(LWIP_PORT_DIR)/src/lib/lwip/lwip-2.0.3/src
+
+-include $(LWIPDIR)/Filelists.mk
+
+# Genode platform files
+SRC_CC = printf.cc rand.cc sys_arch.cc
+
+# Core files
+SRC_C += $(notdir $(COREFILES))
+
+# IPv4 files
+SRC_C += $(notdir $(CORE4FILES))
+
+# IPv6 files
+SRC_C += $(notdir $(CORE6FILES))
+
+# Network interface files
+SRC_C += $(notdir $(NETIFFILES))
+
+INC_DIR += $(REP_DIR)/include/lwip \
+ $(LWIP_PORT_DIR)/include/lwip \
+ $(LWIPDIR)/include \
+ $(LWIPDIR)/include/ipv4 \
+ $(LWIPDIR)/include/api \
+ $(LWIPDIR)/include/netif \
+ $(REP_DIR)/src/lib/lwip/include
+
+vpath %.cc $(REP_DIR)/src/lib/lwip/platform
+vpath %.c $(LWIPDIR)/core
+vpath %.c $(LWIPDIR)/core/ipv4
+vpath %.c $(LWIPDIR)/core/ipv6
+vpath %.c $(LWIPDIR)/netif
+
+CC_CXX_WARN_STRICT =
diff --git a/repos/libports/lib/mk/vfs_lwip.mk b/repos/libports/lib/mk/vfs_lwip.mk
new file mode 100644
index 0000000000..03191da607
--- /dev/null
+++ b/repos/libports/lib/mk/vfs_lwip.mk
@@ -0,0 +1,11 @@
+SRC_CC = vfs.cc
+
+VFS_DIR = $(REP_DIR)/src/lib/vfs/lwip
+INC_DIR += $(VFS_DIR)
+LD_OPT += --version-script=$(VFS_DIR)/symbol.map
+
+LIBS += lwip
+
+vpath %.cc $(VFS_DIR)
+
+SHARED_LIB = yes
diff --git a/repos/libports/ports/lwip.hash b/repos/libports/ports/lwip.hash
new file mode 100644
index 0000000000..57f98e23ef
--- /dev/null
+++ b/repos/libports/ports/lwip.hash
@@ -0,0 +1 @@
+1ac3301a29dcf5f4fc3981fb4338578c7d5d7fe5
diff --git a/repos/libports/ports/lwip.port b/repos/libports/ports/lwip.port
new file mode 100644
index 0000000000..5c8692c451
--- /dev/null
+++ b/repos/libports/ports/lwip.port
@@ -0,0 +1,20 @@
+LICENSE := BSD
+VERSION := 2.0.3
+DOWNLOADS := lwip.archive
+
+URL(lwip) := http://download.savannah.nongnu.org/releases/lwip/lwip-$(VERSION).zip
+SHA(lwip) := 1488829ca48890cc7e5e86c5e76a74b32a1bc9ac8dc01b2177b3a937650e9730
+DIR(lwip) := src/lib/lwip
+
+UNPACKED_DIR := src/lib/lwip/lwip-$(VERSION)
+
+DIRS := \
+ include/lwip/lwip \
+ include/lwip/lwip/priv \
+ include/lwip/lwip/prot \
+ include/lwip/netif \
+
+DIR_CONTENT(include/lwip/lwip/priv) := $(UNPACKED_DIR)/src/include/lwip/priv/*.h
+DIR_CONTENT(include/lwip/lwip/prot) := $(UNPACKED_DIR)/src/include/lwip/prot/*.h
+DIR_CONTENT(include/lwip/lwip) := $(UNPACKED_DIR)/src/include/lwip/*.h
+DIR_CONTENT(include/lwip/netif) := $(UNPACKED_DIR)/src/include/netif/*.h
diff --git a/repos/libports/recipes/src/vfs_lwip/content.mk b/repos/libports/recipes/src/vfs_lwip/content.mk
new file mode 100644
index 0000000000..72b2a874a4
--- /dev/null
+++ b/repos/libports/recipes/src/vfs_lwip/content.mk
@@ -0,0 +1,22 @@
+MIRROR_FROM_REP_DIR := \
+ $(shell cd $(REP_DIR); find include/lwip src/lib/lwip src/lib/vfs/lwip -type f) \
+ lib/import/import-lwip.mk \
+ lib/mk/lwip.mk \
+ lib/mk/vfs_lwip.mk \
+ recipes/src/vfs_lwip \
+
+PORT_DIR := $(call port_dir,$(REP_DIR)/ports/lwip)
+
+MIRROR_FROM_PORT_DIR := $(shell cd $(PORT_DIR); find include src -type f)
+
+content: $(MIRROR_FROM_REP_DIR) $(MIRROR_FROM_PORT_DIR) LICENSE
+
+$(MIRROR_FROM_REP_DIR):
+ $(mirror_from_rep_dir)
+
+$(MIRROR_FROM_PORT_DIR):
+ mkdir -p $(dir $@)
+ cp -r $(PORT_DIR)/$@ $@
+
+LICENSE:
+ cp $(PORT_DIR)/src/lib/lwip/lwip-*/COPYING $@
diff --git a/repos/libports/recipes/src/vfs_lwip/hash b/repos/libports/recipes/src/vfs_lwip/hash
new file mode 100644
index 0000000000..2e1d447e87
--- /dev/null
+++ b/repos/libports/recipes/src/vfs_lwip/hash
@@ -0,0 +1 @@
+2018-02-21-c c71f513a9915a2c98a363d5818147da0857202be
diff --git a/repos/libports/recipes/src/vfs_lwip/used_apis b/repos/libports/recipes/src/vfs_lwip/used_apis
new file mode 100644
index 0000000000..baa484fb84
--- /dev/null
+++ b/repos/libports/recipes/src/vfs_lwip/used_apis
@@ -0,0 +1,7 @@
+base
+libc
+nic_session
+os
+so
+timer_session
+vfs
diff --git a/repos/libports/run/fetchurl.inc b/repos/libports/run/fetchurl.inc
new file mode 100644
index 0000000000..4d053182eb
--- /dev/null
+++ b/repos/libports/run/fetchurl.inc
@@ -0,0 +1,135 @@
+#
+# \brief Test of fetchurl
+# \author Emery Hemingway
+# \date 2016-06-05
+#
+
+if {[have_spec odroid_xu] || [have_spec linux] ||
+ [expr [have_spec imx53] && [have_spec trustzone]]} {
+ puts "Run script does not support this platform."
+ exit 0
+}
+
+set build_components {
+ app/fetchurl
+ core init
+ drivers/nic
+ drivers/timer
+ server/report_rom
+}
+
+proc gpio_drv { } { if {[have_spec rpi] && [have_spec hw]} { return hw_gpio_drv }
+ if {[have_spec rpi] && [have_spec foc]} { return foc_gpio_drv }
+ return gpio_drv }
+
+lappend_if [have_spec gpio] build_components drivers/gpio
+
+source ${genode_dir}/repos/base/run/platform_drv.inc
+
+append_platform_drv_build_components
+append_socket_fs_build_components
+
+lappend_if [expr {[nic_drv_binary] == "nic_drv"}] build_components drivers/nic
+lappend_if [expr {[nic_drv_binary] == "usb_drv"}] build_components drivers/usb
+
+build $build_components
+
+create_boot_directory
+
+append config {
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+
+append_platform_drv_config
+
+append_if [have_spec gpio] config "
+
+
+
+
+ "
+
+append config {
+
+
+
+
+
+
+
+
+ } [nic_drv_config] {
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 2000-01-01 00:00
+ 01234567890123456789
+
+ <} [socket_fs_plugin] { dhcp="yes"/>
+
+
+
+
+
+
+}
+
+install_config $config
+
+# generic modules
+set boot_modules {
+ core init ld.lib.so
+ curl.lib.so
+ fetchurl
+ libc.lib.so vfs.lib.so
+ libcrypto.lib.so
+ libssh.lib.so
+ libssl.lib.so
+ pthread.lib.so
+ timer
+ zlib.lib.so
+ report_rom
+}
+
+# platform-specific modules
+append_platform_drv_boot_modules
+
+# vfs plugin modules
+append_socket_fs_boot_modules
+
+lappend boot_modules [nic_drv_binary]
+
+lappend_if [have_spec gpio] boot_modules [gpio_drv]
+
+build_boot_image $boot_modules
+
+append_if [have_spec x86] qemu_args " -net nic,model=e1000 "
+append_if [have_spec lan9118] qemu_args " -net nic,model=lan9118 "
+append qemu_args " -nographic -net user"
+
+run_genode_until {child "fetchurl" exited with exit value 0} 120
diff --git a/repos/libports/run/fetchurl.run b/repos/libports/run/fetchurl.run
index 3b1a2de2aa..5099d79837 100644
--- a/repos/libports/run/fetchurl.run
+++ b/repos/libports/run/fetchurl.run
@@ -1,132 +1,2 @@
-#
-# \brief Test of 'fetchurl
-# \author Emery Hemingway
-# \date 2016-06-05
-#
-
-if {[have_spec odroid_xu] || [have_spec linux] ||
- [expr [have_spec imx53] && [have_spec trustzone]]} {
- puts "Run script does not support this platform."
- exit 0
-}
-
-set build_components {
- app/fetchurl
- core init
- drivers/nic
- drivers/timer
- lib/vfs/lxip
- server/report_rom
-}
-
-proc gpio_drv { } { if {[have_spec rpi] && [have_spec hw]} { return hw_gpio_drv }
- if {[have_spec rpi] && [have_spec foc]} { return foc_gpio_drv }
- return gpio_drv }
-
-lappend_if [have_spec gpio] build_components drivers/gpio
-
-source ${genode_dir}/repos/base/run/platform_drv.inc
-append_platform_drv_build_components
-
-lappend_if [expr {[nic_drv_binary] == "nic_drv"}] build_components drivers/nic
-lappend_if [expr {[nic_drv_binary] == "usb_drv"}] build_components drivers/usb
-
-build $build_components
-
-create_boot_directory
-
-append config {
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- }
-
-append_platform_drv_config
-
-append_if [have_spec gpio] config "
-
-
-
-
- "
-
-append config {
-
-
-
-
-
-
-
-
- } [nic_drv_config] {
-
-
-
-
-
-
-
-
-
-
-
-
-
- 2000-01-01 00:00
- 01234567890123456789
-
-
-
-
-
-
-
-
-}
-
-install_config $config
-
-# generic modules
-set boot_modules {
- core init ld.lib.so
- curl.lib.so
- fetchurl
- libc.lib.so vfs.lib.so
- libcrypto.lib.so
- libssh.lib.so
- libssl.lib.so
- lxip.lib.so
- pthread.lib.so
- timer
- vfs_lxip.lib.so
- zlib.lib.so
- report_rom
-}
-
-# platform-specific modules
-append_platform_drv_boot_modules
-lappend boot_modules [nic_drv_binary]
-
-lappend_if [have_spec gpio] boot_modules [gpio_drv]
-
-build_boot_image $boot_modules
-
-append_if [have_spec x86] qemu_args " -net nic,model=e1000 "
-append_if [have_spec lan9118] qemu_args " -net nic,model=lan9118 "
-append qemu_args " -nographic -net user"
-
-run_genode_until {child "fetchurl" exited with exit value 0} 120
+source ${genode_dir}/repos/ports/run/vfs_lxip.inc
+source ${genode_dir}/repos/libports/run/fetchurl.inc
diff --git a/repos/libports/run/fetchurl_lwip.run b/repos/libports/run/fetchurl_lwip.run
new file mode 100644
index 0000000000..afad0425d5
--- /dev/null
+++ b/repos/libports/run/fetchurl_lwip.run
@@ -0,0 +1,2 @@
+source ${genode_dir}/repos/libports/run/vfs_lwip.inc
+source ${genode_dir}/repos/libports/run/fetchurl.inc
diff --git a/repos/libports/run/libc_getaddrinfo.run b/repos/libports/run/libc_getaddrinfo.run
index bb6db735f1..5f433c623a 100644
--- a/repos/libports/run/libc_getaddrinfo.run
+++ b/repos/libports/run/libc_getaddrinfo.run
@@ -8,7 +8,7 @@ if {[have_spec linux]} {
set build_components {
core init
drivers/timer
- lib/vfs/lxip
+ lib/vfs/lwip
test/libc_getaddrinfo
}
@@ -49,11 +49,11 @@ append config {
-
+
-
+
@@ -70,8 +70,9 @@ install_config $config
set boot_modules {
core init ld.lib.so
libc.lib.so libm.lib.so posix.lib.so
- lxip.lib.so vfs_lxip.lib.so
+ vfs_lwip.lib.so
test-libc_getaddrinfo
+ vfs.lib.so
timer
}
@@ -81,6 +82,6 @@ lappend boot_modules [nic_drv_binary]
build_boot_image $boot_modules
-append qemu_args " -nographic -net nic,model=e1000 -net user -net dump,file=[run_dir]/dump.pcap"
+append qemu_args " -nographic -net nic,model=e1000 -net user"
run_genode_until "child .* exited with exit value 0.*\n" 20
diff --git a/repos/libports/run/netty_lwip.inc b/repos/libports/run/netty_lwip.inc
new file mode 100644
index 0000000000..b5283bb3c8
--- /dev/null
+++ b/repos/libports/run/netty_lwip.inc
@@ -0,0 +1,90 @@
+assert_spec x86
+
+proc use_dynamic_rom { } { return false }
+
+set build_components {
+ core init
+ drivers/timer
+ drivers/nic
+ server/vfs
+ lib/vfs/lwip
+ lib/vfs/audit
+}
+
+lappend_if [use_dynamic_rom] build_components server/dynamic_rom
+
+source ${genode_dir}/repos/base/run/platform_drv.inc
+append_platform_drv_build_components
+
+append config {
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+}
+
+append_platform_drv_config
+
+append config {
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+}
+
+append boot_modules {
+ core init timer } [nic_drv_binary] {
+ ld.lib.so
+ libc.lib.so
+ vfs
+ vfs_audit.lib.so
+ vfs.lib.so
+ vfs_lwip.lib.so
+}
+
+lappend_if [use_dynamic_rom] boot_modules dynamic_rom
+
+append_platform_drv_boot_modules
+
+append qemu_args " -nographic -net nic,model=e1000 -net tap,ifname=tap0,downscript=no,script=no "
+
+# vi: set ft=tcl :
diff --git a/repos/libports/run/netty_lwip_tcp.run b/repos/libports/run/netty_lwip_tcp.run
new file mode 100644
index 0000000000..fdc54e5709
--- /dev/null
+++ b/repos/libports/run/netty_lwip_tcp.run
@@ -0,0 +1,72 @@
+source ${genode_dir}/repos/libports/run/netty_lwip.inc
+
+append build_components { test/netty/tcp }
+
+build $build_components
+
+create_boot_directory
+
+append config {
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+}
+
+install_config $config
+
+append boot_modules { test-netty_tcp }
+
+build_boot_image $boot_modules
+
+run_genode_until forever
+
+# vi: set ft=tcl :
diff --git a/repos/libports/run/netty_lwip_udp.run b/repos/libports/run/netty_lwip_udp.run
new file mode 100644
index 0000000000..94752c0490
--- /dev/null
+++ b/repos/libports/run/netty_lwip_udp.run
@@ -0,0 +1,45 @@
+source ${genode_dir}/repos/libports/run/netty_lwip.inc
+
+append build_components { test/netty/udp }
+
+build $build_components
+
+create_boot_directory
+
+append config {
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+}
+
+install_config $config
+
+append boot_modules { test-netty_udp }
+
+build_boot_image $boot_modules
+
+run_genode_until forever
+
+# vi: set ft=tcl :
diff --git a/repos/libports/run/vfs_lwip.inc b/repos/libports/run/vfs_lwip.inc
new file mode 100644
index 0000000000..d3caba6fcf
--- /dev/null
+++ b/repos/libports/run/vfs_lwip.inc
@@ -0,0 +1,13 @@
+assert_spec x86
+
+proc append_socket_fs_build_components { } {
+ global build_components
+ append build_components { lib/vfs/lwip }
+}
+
+proc socket_fs_plugin {} { return lwip }
+
+proc append_socket_fs_boot_modules {} {
+ global boot_modules
+ append boot_modules { vfs_lwip.lib.so }
+}
diff --git a/repos/libports/src/lib/libc/socket_fs_plugin.cc b/repos/libports/src/lib/libc/socket_fs_plugin.cc
index 1b9b63045e..c093f488e8 100644
--- a/repos/libports/src/lib/libc/socket_fs_plugin.cc
+++ b/repos/libports/src/lib/libc/socket_fs_plugin.cc
@@ -468,7 +468,7 @@ extern "C" int socket_fs_accept(int libc_fd, sockaddr *addr, socklen_t *addrlen)
/* TODO EOPNOTSUPP - no SOCK_STREAM */
/* TODO ECONNABORTED */
- char accept_buf[8];
+ char accept_buf[MAX_CONTROL_PATH_LEN];
{
int n = 0;
/* XXX currently reading accept may return without new connection */
diff --git a/repos/libports/src/lib/lwip/include/stdlib.h b/repos/libports/src/lib/lwip/include/stdlib.h
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/repos/libports/src/lib/lwip/include/string.h b/repos/libports/src/lib/lwip/include/string.h
new file mode 100644
index 0000000000..0d4b83330f
--- /dev/null
+++ b/repos/libports/src/lib/lwip/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/libports/src/lib/lwip/platform/printf.cc b/repos/libports/src/lib/lwip/platform/printf.cc
new file mode 100644
index 0000000000..ff59dc733b
--- /dev/null
+++ b/repos/libports/src/lib/lwip/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
+#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);
+
+ Genode::vprintf(format, list);
+
+ va_end(list);
+ }
+
+}
diff --git a/repos/libports/src/lib/lwip/platform/rand.cc b/repos/libports/src/lib/lwip/platform/rand.cc
new file mode 100644
index 0000000000..f9e3fc2499
--- /dev/null
+++ b/repos/libports/src/lib/lwip/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 = ((oldstate >> 18u) ^ oldstate) >> 27u;
+ uint32_t rot = oldstate >> 59u;
+ return (xorshifted >> rot) | (xorshifted << ((-rot) & 31));
+}
diff --git a/repos/libports/src/lib/lwip/platform/sys_arch.cc b/repos/libports/src/lib/lwip/platform/sys_arch.cc
new file mode 100644
index 0000000000..b07d53deb7
--- /dev/null
+++ b/repos/libports/src/lib/lwip/platform/sys_arch.cc
@@ -0,0 +1,116 @@
+/*
+ * \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
+
+extern "C" {
+/* LwIP includes */
+#include
+#include
+#include
+#include
+
+/* our abridged copy of string.h */
+#include
+}
+
+namespace Lwip {
+
+ static Genode::Allocator *_heap;
+
+ /**
+ * XXX: can this be replaced with an alarm?
+ */
+ struct Sys_timer
+ {
+ void check_timeouts(Genode::Duration) {
+ sys_check_timeouts(); }
+
+ Genode::Timeout_scheduler &timer;
+
+ Timer::Periodic_timeout timeout {
+ timer, *this, &Sys_timer::check_timeouts,
+ Genode::Microseconds{250*1000} };
+
+ Sys_timer(Genode::Timeout_scheduler &timer) : timer(timer) { }
+ };
+
+ static Genode::Constructible _sys_timer;
+
+ void genode_init(Genode::Allocator &heap, Genode::Timeout_scheduler &timer)
+ {
+ LWIP_ASSERT("LwIP initialized with an allocator that does not track sizes",
+ !heap.need_size_for_free());
+
+ _heap = &heap;
+ _sys_timer.construct(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)
+ {
+ Lwip::_heap->free(ptr, 0);
+ }
+
+ void *genode_malloc(unsigned long size)
+ {
+ void *ptr = nullptr;
+ return Lwip::_heap->alloc(size, &ptr) ? ptr : 0;
+ }
+
+ void *genode_calloc(unsigned long number, unsigned long size)
+ {
+ void *ptr = nullptr;
+ size *= number;
+ if (Lwip::_heap->alloc(size, &ptr)) {
+ Genode::memset(ptr, 0x00, size);
+ return ptr;
+ }
+ return nullptr;
+ }
+
+ u32_t sys_now(void) {
+ return Lwip::_sys_timer->timer.curr_time().trunc_to_plain_ms().value; }
+
+ void genode_memcpy(void * dst, const void *src, unsigned long size) {
+ Genode::memcpy(dst, src, size); }
+
+ int memcmp(const void *b1, const void *b2, ::size_t len) {
+ return Genode::memcmp(b1, b2, len); }
+
+ int strcmp(const char *s1, const char *s2)
+ {
+ size_t len = Genode::min(Genode::strlen(s1), Genode::strlen(s2));
+ return Genode::strcmp(s1, s2, len);
+ }
+
+ int strncmp(const char *s1, const char *s2, size_t len) {
+ return Genode::strcmp(s1, s2, len); }
+
+}
diff --git a/repos/libports/src/lib/vfs/lwip/symbol.map b/repos/libports/src/lib/vfs/lwip/symbol.map
new file mode 100644
index 0000000000..58e4ff57a8
--- /dev/null
+++ b/repos/libports/src/lib/vfs/lwip/symbol.map
@@ -0,0 +1,9 @@
+{
+ global:
+
+ vfs_file_system_factory;
+
+ local:
+
+ *;
+};
diff --git a/repos/libports/src/lib/vfs/lwip/target.mk b/repos/libports/src/lib/vfs/lwip/target.mk
new file mode 100644
index 0000000000..3ad2c6d713
--- /dev/null
+++ b/repos/libports/src/lib/vfs/lwip/target.mk
@@ -0,0 +1,2 @@
+TARGET = dummy-vfs_lwip
+LIBS = vfs_lwip
diff --git a/repos/libports/src/lib/vfs/lwip/vfs.cc b/repos/libports/src/lib/vfs/lwip/vfs.cc
new file mode 100644
index 0000000000..c3f2a5ab67
--- /dev/null
+++ b/repos/libports/src/lib/vfs/lwip/vfs.cc
@@ -0,0 +1,1848 @@
+/*
+ * \brief LwIP VFS plugin
+ * \author Emery Hemingway
+ * \date 2016-09-27
+ */
+
+/*
+ * Copyright (C) 2016-2018 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
+#include
+#include
+#include
+#include
+#include
+
+/* LwIP includes */
+#include
+#include
+
+namespace Lwip {
+extern "C" {
+#include
+#include
+#include
+}
+
+ using namespace Vfs;
+ using Genode::warning;
+ typedef Vfs::File_io_service::Read_result Read_result;
+ typedef Vfs::File_io_service::Write_result Write_result;
+ typedef Vfs::File_io_service::Sync_result Sync_result;
+
+ typedef Genode::String<8> Socket_name;
+
+ char const *get_port(char const *s)
+ {
+ char const *p = s;
+ while (*++p) {
+ if (*p == ':')
+ return ++p;
+ }
+ return nullptr;
+ }
+
+ int remove_port(char *p)
+ {
+ long tmp = -1;
+
+ while (*++p)
+ if (*p == ':') {
+ *p++ = '\0';
+ Genode::ascii_to_unsigned(p, tmp, 10);
+ break;
+ }
+
+ return tmp;
+ }
+
+ class Socket_dir;
+ class Udp_socket_dir;
+ class Tcp_socket_dir;
+
+ #define Udp_socket_dir_list Genode::List
+ #define Tcp_socket_dir_list Genode::List
+
+ struct Protocol_dir;
+ template class Protocol_dir_impl;
+
+ enum {
+ MAX_SOCKETS = 128, /* 3 */
+ MAX_SOCKET_NAME_LEN = 3 + 1, /* + \0 */
+ MAX_FD_STR_LEN = 3 + 1 +1, /* + \n + \0 */
+ MAX_DATA_LEN = 32, /* 255.255.255.255:65536 + something */
+ };
+ struct Lwip_handle;
+ struct Lwip_nameserver_handle;
+ struct Lwip_file_handle;
+ struct Lwip_dir_handle;
+
+ typedef Genode::Registry Nameserver_registry;
+
+ #define Lwip_handle_list List
+
+ class File_system;
+
+ typedef Vfs::Directory_service::Open_result Open_result;
+ typedef Vfs::Directory_service::Opendir_result Opendir_result;
+ typedef Vfs::Directory_service::Unlink_result Unlink_result;
+
+ extern "C" {
+ static void udp_recv_callback(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr, u16_t port);
+ static err_t tcp_connect_callback(void *arg, struct tcp_pcb *tpcb, err_t err);
+ static err_t tcp_accept_callback(void *arg, struct tcp_pcb *newpcb, err_t err);
+ static err_t tcp_recv_callback(void *arg, struct tcp_pcb *tpcb,
+ struct pbuf *p, err_t err);
+ static err_t tcp_delayed_recv_callback(void *arg, struct tcp_pcb *tpcb,
+ struct pbuf *p, err_t err);
+ /* static err_t tcp_sent_callback(void *arg, struct tcp_pcb *tpcb, u16_t len); */
+ static void tcp_err_callback(void *arg, err_t err);
+ }
+
+ typedef Genode::Path<24> Path;
+
+ enum {
+ PORT_STRLEN_MAX = 6, /* :65536 */
+ ENDPOINT_STRLEN_MAX = IPADDR_STRLEN_MAX+PORT_STRLEN_MAX
+ };
+
+ struct Directory;
+}
+
+
+/**
+ * Synthetic directory interface
+ */
+struct Lwip::Directory
+{
+ virtual ~Directory() { }
+
+ virtual Read_result readdir(char *dst, file_size count,
+ file_size &out_count) = 0;
+
+ virtual bool directory(char const *path) = 0;
+};
+
+
+struct Lwip::Lwip_handle : Vfs::Vfs_handle
+{
+ Lwip_handle(Vfs::File_system &fs, Allocator &alloc, int status_flags)
+ : Vfs_handle(fs, fs, alloc, status_flags) { }
+
+ virtual Read_result read(char *dst, file_size count,
+ file_size &out_count) = 0;
+
+ virtual Write_result write(char const *, file_size,
+ file_size &) {
+ return Write_result::WRITE_ERR_INVALID; }
+};
+
+
+struct Lwip::Lwip_dir_handle final : Lwip_handle
+{
+ /*
+ * Noncopyable
+ */
+ Lwip_dir_handle(Lwip_dir_handle const &);
+ Lwip_dir_handle &operator = (Lwip_dir_handle const &);
+
+ Directory *dir;
+
+ void print(Genode::Output &output) const;
+
+ Lwip_dir_handle(Vfs::File_system &fs, Allocator &alloc, Directory &dir)
+ : Lwip_handle(fs, alloc, 0), dir(&dir) { }
+
+ Read_result read(char *dst, file_size count,
+ file_size &out_count) override
+ {
+ return (dir)
+ ? dir->readdir(dst, count, out_count)
+ : Read_result::READ_ERR_INVALID;
+ }
+};
+
+
+struct Lwip::Lwip_nameserver_handle final : Lwip_handle, private Nameserver_registry::Element
+{
+ Lwip_nameserver_handle(Vfs::File_system &fs, Allocator &alloc, Nameserver_registry ®istry)
+ : Lwip_handle(fs, alloc, Vfs::Directory_service::OPEN_MODE_RDONLY),
+ Nameserver_registry::Element(registry, *this) { }
+
+ Read_result read(char *dst, file_size count,
+ file_size &out_count) override
+ {
+ memset(dst, 0x00, min(file_size(IPADDR_STRLEN_MAX), count));
+ ipaddr_ntoa_r(dns_getserver(0), dst, count);
+
+ auto n = strlen(dst);
+ if (n < count)
+ dst[n] = '\n';
+
+ out_count = n+1;
+ return Read_result::READ_OK;
+ }
+};
+
+
+struct Lwip::Lwip_file_handle final : Lwip_handle, private Lwip_handle_list::Element
+{
+ friend class Lwip_handle_list;
+ friend class Lwip_handle_list::Element;
+ using Lwip_handle_list::Element::next;
+
+ enum Kind {
+ INVALID = 0,
+ ACCEPT = 1 << 0,
+ BIND = 1 << 1,
+ CONNECT = 1 << 2,
+ DATA = 1 << 3,
+ LISTEN = 1 << 4,
+ LOCAL = 1 << 5,
+ PEEK = 1 << 6,
+ REMOTE = 1 << 7,
+ LOCATION = 1 << 8,
+ PENDING = 1 << 9,
+ };
+
+ /*
+ * Noncopyable
+ */
+ Lwip_file_handle(Lwip_file_handle const &);
+ Lwip_file_handle &operator = (Lwip_file_handle const &);
+
+ static Kind kind_from_name(Path const &p)
+ {
+ if (p == "/accept_socket") return PENDING;
+ if (p == "/accept") return ACCEPT;
+ if (p == "/bind") return BIND;
+ if (p == "/connect") return CONNECT;
+ if (p == "/data") return DATA;
+ if (p == "/listen") return LISTEN;
+ if (p == "/local") return LOCAL;
+ if (p == "/peek") return PEEK;
+ if (p == "/remote") return REMOTE;
+ return INVALID;
+ }
+
+ Socket_dir *socket;
+
+ int in_transit = 0;
+
+ Kind kind;
+
+ bool notify = false;
+
+ void print(Genode::Output &output) const;
+
+ Lwip_file_handle(Vfs::File_system &fs, Allocator &alloc, int status_flags,
+ Socket_dir &s, Kind k);
+
+ ~Lwip_file_handle();
+
+ Read_result read(char *dst, file_size count,
+ file_size &out_count) override;
+
+ Write_result write(char const *src, file_size count,
+ file_size &out_count) override;
+};
+
+
+struct Lwip::Socket_dir : Lwip::Directory
+{
+ friend class Lwip_handle;
+ friend class Lwip_handle_list;
+ friend class Lwip_handle_list::Element;
+
+ static Socket_name name_from_num(unsigned num)
+ {
+ char buf[Socket_name::capacity()];
+ return Socket_name(Genode::Cstring(
+ buf, Genode::snprintf(buf, Socket_name::capacity(), "%x", num)));
+ }
+
+ Genode::Allocator &alloc;
+
+ Vfs::Io_response_handler &io_handler;
+
+ unsigned const _num;
+ Socket_name const _name { name_from_num(_num) };
+
+ /* lists of handles opened at this socket */
+ Lwip_handle_list handles { };
+
+ enum State {
+ NEW,
+ BOUND,
+ CONNECT,
+ LISTEN,
+ READY,
+ CLOSING,
+ CLOSED
+ };
+
+ Socket_dir(unsigned num, Genode::Allocator &alloc, Vfs::Io_response_handler &io_handler)
+ : alloc(alloc), io_handler(io_handler), _num(num) { };
+
+
+ ~Socket_dir()
+ {
+ /*
+ * Remove socket from handles
+ */
+ while (Lwip_file_handle *handle = handles.first()) {
+ handle->socket = nullptr;
+ handles.remove(handle);
+ }
+ }
+
+ Socket_name const &name() const { return _name; }
+
+ bool operator == (unsigned other) const {
+ return _num == other; }
+
+ bool operator == (char const *other) const {
+ return _name == other; }
+
+ virtual Open_result _accept_new_socket(Vfs::File_system &,
+ Genode::Allocator &,
+ Vfs::Vfs_handle **) = 0;
+
+ Open_result open(Vfs::File_system &fs,
+ Path const &name,
+ unsigned mode,
+ Vfs_handle **out_handle,
+ Allocator &alloc)
+ {
+ Lwip_file_handle::Kind kind = Lwip_file_handle::kind_from_name(name);
+ if (kind == Lwip_file_handle::INVALID)
+ return Open_result::OPEN_ERR_UNACCESSIBLE;
+
+ if (kind == Lwip_file_handle::LOCATION || kind == Lwip_file_handle::PENDING)
+ return _accept_new_socket(fs, alloc, out_handle);
+
+ *out_handle = new (alloc) Lwip_file_handle(fs, alloc, mode, *this, kind);
+ return Open_result::OPEN_OK;
+ }
+
+ Read_result readdir(char *dst, file_size count,
+ file_size &out_count) override
+ {
+ Genode::warning(__func__, " NOT_IMPLEMENTED");
+ (void)dst;
+ (void)count;
+ (void)out_count;
+ return Read_result::READ_ERR_INVALID;
+ }
+
+ bool directory(char const *path) override
+ {
+ /* empty path is this directory */
+ return (!*path);
+ }
+
+ virtual Read_result read(Lwip_file_handle&,
+ char *dst, file_size count,
+ file_size &out_count) = 0;
+
+ virtual Write_result write(Lwip_file_handle&,
+ char const *src, file_size count,
+ file_size &out_count) = 0;
+
+ virtual bool read_ready(Lwip_file_handle&) = 0;
+
+ void handle_io(int mask)
+ {
+ for (Lwip::Lwip_file_handle *h = handles.first();
+ h; h = h->next())
+ {
+ if (h->kind & mask) {
+ io_handler.handle_io_response(h->context);
+ }
+ }
+ }
+
+ virtual Sync_result complete_sync() = 0;
+};
+
+
+Lwip::Lwip_file_handle::Lwip_file_handle(Vfs::File_system &fs, Allocator &alloc,
+ int status_flags,
+ Socket_dir &s, Lwip_file_handle::Kind k)
+: Lwip_handle(fs, alloc, status_flags), socket(&s), kind(k)
+{
+ socket->handles.insert(this);
+}
+
+Lwip::Lwip_file_handle::~Lwip_file_handle()
+{
+ if (socket)
+ socket->handles.remove(this);
+}
+
+Lwip::Read_result Lwip::Lwip_file_handle::read(char *dst, file_size count,
+ file_size &out_count)
+{
+ return (socket)
+ ? socket->read(*this, dst, count, out_count)
+ : Read_result::READ_ERR_INVALID;
+}
+
+Lwip::Write_result Lwip::Lwip_file_handle::write(char const *src, file_size count,
+ file_size &out_count)
+{
+ return (socket)
+ ? socket->write(*this, src, count, out_count)
+ : Write_result::WRITE_ERR_INVALID;
+}
+
+
+void Lwip::Lwip_file_handle::print(Genode::Output &output) const
+{
+ output.out_string(socket->name().string());
+ switch (kind) {
+
+ case Lwip_file_handle::ACCEPT: output.out_string("/accept"); break;
+ case Lwip_file_handle::BIND: output.out_string("/bind"); break;
+ case Lwip_file_handle::CONNECT: output.out_string("/connect"); break;
+ case Lwip_file_handle::DATA: output.out_string("/data"); break;
+ case Lwip_file_handle::INVALID: output.out_string("/invalid"); break;
+ case Lwip_file_handle::LISTEN: output.out_string("/listen"); break;
+ case Lwip_file_handle::LOCAL: output.out_string("/local"); break;
+ case Lwip_file_handle::LOCATION: output.out_string("(location)"); break;
+ case Lwip_file_handle::PENDING: output.out_string("/accept_socket"); break;
+ case Lwip_file_handle::PEEK: output.out_string("/peek"); break;
+ case Lwip_file_handle::REMOTE: output.out_string("/remote"); break;
+}
+}
+
+
+struct Lwip::Protocol_dir : Lwip::Directory
+{
+ virtual bool leaf_path(char const *) = 0;
+
+ virtual Directory_service::Stat_result stat(char const*, Directory_service::Stat&) = 0;
+
+ virtual void adopt_socket(Socket_dir &socket) = 0;
+
+ virtual Open_result open(Vfs::File_system &fs,
+ char const *path,
+ unsigned mode,
+ Vfs_handle **out_handle,
+ Allocator &alloc) = 0;
+
+ virtual Opendir_result opendir(Vfs::File_system &fs,
+ char const *path,
+ Vfs_handle **out_handle,
+ Allocator &alloc) = 0;
+
+ virtual ~Protocol_dir() { }
+};
+
+
+template
+class Lwip::Protocol_dir_impl final : public Protocol_dir
+{
+ private:
+
+ Genode::Allocator &_alloc;
+ Vfs::Io_response_handler &_io_handler;
+ Genode::Entrypoint &_ep;
+
+ Genode::List _socket_dirs { };
+
+ public:
+
+ friend class Genode::List;
+ friend class Genode::List::Element;
+
+ friend class Tcp_socket_dir;
+ friend class Udp_socket_dir;
+
+ Protocol_dir_impl(Vfs::Env &vfs_env)
+ : _alloc(vfs_env.alloc()), _io_handler(vfs_env.io_handler()), _ep(vfs_env.env().ep()) { }
+
+ SOCKET_DIR *lookup(char const *name)
+ {
+ if (*name == '/') ++name;
+
+ /* make sure it is only a name */
+ for (char const *p = name; *p; ++p)
+ if (*p == '/')
+ return nullptr;
+
+ for (SOCKET_DIR *sd = _socket_dirs.first(); sd; sd = sd->next())
+ if (*sd == name)
+ return sd;
+
+ return nullptr;
+ }
+
+ bool leaf_path(char const *path) override
+ {
+ Path subpath(path);
+ subpath.strip_last_element();
+ if ((subpath == "/") || (subpath == "/new_socket"))
+ return true;
+
+ if (lookup(subpath.string())) {
+ subpath.import(path);
+ subpath.keep_only_last_element();
+ auto kind = Lwip_file_handle::kind_from_name(subpath);
+ return (kind != Lwip_file_handle::INVALID);
+ }
+ return false;
+ }
+
+ Directory_service::Stat_result stat(char const *path, Directory_service::Stat &st) override
+ {
+ Path subpath(path);
+
+ if (subpath == "/") {
+ st.size = 1;
+ st.mode = Directory_service::STAT_MODE_DIRECTORY;
+ st.inode = (Genode::addr_t)this;
+ return Directory_service::STAT_OK;
+ }
+
+ if (subpath == "/new_socket") {
+ st.size = 1;
+ st.mode = Directory_service::STAT_MODE_FILE | 0777;
+ st.inode = ((Genode::addr_t)this)+1;
+ return Directory_service::STAT_OK;
+ }
+
+ if (!subpath.has_single_element())
+ subpath.strip_last_element();
+ if (SOCKET_DIR *dir = lookup(subpath.string())) {
+ Path filename(path);
+ filename.keep_only_last_element();
+ if (filename == subpath.base()) {
+ st.size = Lwip_file_handle::INVALID;
+ st.mode = Directory_service::STAT_MODE_DIRECTORY;
+ st.inode = (Genode::addr_t)dir;
+ return Directory_service::STAT_OK;
+ }
+
+ Lwip_file_handle::Kind k = Lwip_file_handle::kind_from_name(filename);
+ if (k != Lwip_file_handle::INVALID) {
+ st.mode = Directory_service::STAT_MODE_CHARDEV;
+ st.inode = ((Genode::addr_t)dir)+k;
+ return Directory_service::STAT_OK;
+ }
+ }
+ return Directory_service::STAT_ERR_NO_ENTRY;
+ }
+
+ Read_result readdir(char *dst, file_size count,
+ file_size &out_count) override
+ {
+ Genode::warning(__func__, " NOT_IMPLEMENTED");
+ (void)dst;
+ (void)count;
+ (void)out_count;
+ return Read_result::READ_ERR_INVALID;
+ };
+
+ bool directory(char const *path) override
+ {
+ /* empty path is the protocol directory */
+ return *path ? (lookup(path+1) != nullptr) : true;
+ }
+
+ SOCKET_DIR &alloc_socket(Genode::Allocator &alloc, PCB *pcb = nullptr)
+ {
+ /*
+ * use the equidistribution RNG to hide the socket count,
+ * see src/lib/lwip/platform/rand.cc
+ */
+ unsigned id = LWIP_RAND();
+
+ /* check for collisions */
+ for (SOCKET_DIR *dir = _socket_dirs.first(); dir;) {
+ if (*dir == id) {
+ id = LWIP_RAND();
+ dir = _socket_dirs.first();
+ } else {
+ dir = dir->next();
+ }
+ }
+
+ SOCKET_DIR *new_socket = new (alloc)
+ SOCKET_DIR(id, *this, alloc, _io_handler, _ep, pcb);
+ _socket_dirs.insert(new_socket);
+ return *new_socket;
+ }
+
+ void adopt_socket(Socket_dir &socket) override {
+ _socket_dirs.insert(static_cast(&socket)); }
+
+ void release(SOCKET_DIR *socket) {
+ _socket_dirs.remove(socket); }
+
+ Open_result open(Vfs::File_system &fs,
+ char const *path,
+ unsigned mode,
+ Vfs_handle **out_handle,
+ Allocator &alloc) override
+ {
+ Path subpath(path);
+
+ if (subpath == "/new_socket") {
+ Socket_dir &new_dir = alloc_socket(alloc);
+ *out_handle = new (alloc) Lwip_file_handle(
+ fs, alloc, Vfs::Directory_service::OPEN_MODE_RDONLY,
+ new_dir, Lwip_file_handle::LOCATION);
+ return Open_result::OPEN_OK;
+ }
+
+ subpath.strip_last_element();
+ if (SOCKET_DIR *dir = lookup(subpath.base()+1)) {
+ subpath.import(path);
+ subpath.keep_only_last_element();
+ return dir->open(fs, subpath, mode, out_handle, alloc);
+ }
+
+ return Open_result::OPEN_ERR_UNACCESSIBLE;
+ }
+
+ Opendir_result opendir(Vfs::File_system &fs,
+ char const *path,
+ Vfs_handle **out_handle,
+ Allocator &alloc) override
+ {
+ if (!*path) {
+ *out_handle = new (alloc) Lwip_dir_handle(fs, alloc, *this);
+ return Opendir_result::OPENDIR_OK;
+ }
+ if (SOCKET_DIR *dir = lookup(path)) {
+ *out_handle = new (alloc) Lwip_dir_handle(fs, alloc, *dir);
+ return Opendir_result::OPENDIR_OK;
+ }
+
+ return Opendir_result::OPENDIR_ERR_LOOKUP_FAILED;
+ }
+
+ void notify()
+ {
+ for (SOCKET_DIR *sd = _socket_dirs.first(); sd; sd = sd->next()) {
+ sd->handle_io(~0U);
+ }
+ }
+};
+
+namespace Lwip {
+ typedef Protocol_dir_impl Udp_proto_dir;
+ typedef Protocol_dir_impl Tcp_proto_dir;
+}
+
+
+/*********
+ ** UDP **
+ *********/
+
+class Lwip::Udp_socket_dir final :
+ public Socket_dir,
+ private Udp_socket_dir_list::Element
+{
+ private:
+
+ /*
+ * Noncopyable
+ */
+ Udp_socket_dir(Udp_socket_dir const &);
+ Udp_socket_dir &operator = (Udp_socket_dir const &);
+
+ Udp_proto_dir &_proto_dir;
+
+ udp_pcb *_pcb;
+
+ /**
+ * Handle on a received UDP packet
+ */
+ class Packet : public Genode::Fifo::Element
+ {
+ public:
+
+ Packet(Packet const &);
+ Packet &operator = (Packet const &);
+
+ ip_addr_t const addr;
+ u16_t const port;
+
+ private:
+
+ u16_t offset = 0;
+ pbuf *buf;
+
+ public:
+
+ Packet(ip_addr_t const *addr, u16_t port, pbuf *buf)
+ : addr(*addr), port(port), buf(buf) { }
+
+ ~Packet() { pbuf_free(buf); }
+
+ u16_t read(void *dst, size_t count)
+ {
+ count = min((size_t)buf->tot_len, count);
+ auto n = pbuf_copy_partial(buf, dst, count, offset);
+ offset += n;
+ return n;
+ }
+
+ u16_t peek(void *dst, size_t count)
+ {
+ count = min((size_t)buf->tot_len, count);
+ return pbuf_copy_partial(buf, dst, count, offset);
+ }
+
+ bool empty() { return offset >= buf->tot_len; }
+ };
+
+ Genode::Tslab _packet_slab { &alloc };
+
+ /* Queue of received UDP packets */
+ Genode::Fifo _packet_queue { };
+
+ /* destination addressing */
+ ip_addr_t _to_addr { };
+ u16_t _to_port = 0;
+
+ /**
+ * New sockets from accept not avaiable for UDP
+ */
+ Open_result _accept_new_socket(Vfs::File_system &,
+ Genode::Allocator &,
+ Vfs::Vfs_handle **) override {
+ return Open_result::OPEN_ERR_UNACCESSIBLE; }
+
+ public:
+
+ friend class Udp_socket_dir_list;
+ friend class Udp_socket_dir_list::Element;
+ using Udp_socket_dir_list::Element::next;
+
+ Udp_socket_dir(unsigned num, Udp_proto_dir &proto_dir,
+ Genode::Allocator &alloc,
+ Vfs::Io_response_handler &io_handler,
+ Genode::Entrypoint &,
+ udp_pcb *pcb)
+ : Socket_dir(num, alloc, io_handler),
+ _proto_dir(proto_dir), _pcb(pcb ? pcb : udp_new())
+ {
+ ip_addr_set_zero(&_to_addr);
+
+ /* 'this' will be the argument to the LwIP recv callback */
+ udp_recv(_pcb, udp_recv_callback, this);
+ }
+
+ virtual ~Udp_socket_dir()
+ {
+ udp_remove(_pcb);
+ _pcb = NULL;
+
+ _proto_dir.release(this);
+ }
+
+ /**
+ * Stuff a packet in the queue and notify the handle
+ */
+ void queue(ip_addr_t const *addr, u16_t port, pbuf *buf)
+ {
+ try {
+ Packet *pkt = new (_packet_slab) Packet(addr, port, buf);
+ _packet_queue.enqueue(pkt);
+ } catch (...) {
+ Genode::warning("failed to queue UDP packet, dropping");
+ pbuf_free(buf);
+ }
+
+ handle_io(Lwip_file_handle::REMOTE|Lwip_file_handle::DATA);
+ }
+
+
+ /**************************
+ ** Socket_dir interface **
+ **************************/
+
+ bool read_ready(Lwip_file_handle &handle) override
+ {
+ switch (handle.kind) {
+ case Lwip_file_handle::DATA:
+ case Lwip_file_handle::REMOTE:
+ case Lwip_file_handle::PEEK:
+ return !_packet_queue.empty();
+ default:
+ break;
+ }
+ return true;
+ }
+
+ Read_result read(Lwip_file_handle &handle,
+ char *dst, file_size count,
+ file_size &out_count) override
+ {
+ switch(handle.kind) {
+
+ case Lwip_file_handle::DATA: {
+ if (Packet *pkt = _packet_queue.head()) {
+ out_count = pkt->read(dst, count);
+ if (pkt->empty()) {
+ destroy(_packet_slab, _packet_queue.dequeue());
+ }
+ return Read_result::READ_OK;
+ }
+ return Read_result::READ_QUEUED;
+ }
+
+ case Lwip_file_handle::PEEK: {
+ if (Packet *pkt = _packet_queue.head()) {
+ out_count = pkt->peek(dst, count);
+ }
+ return Read_result::READ_OK;
+ }
+
+ case Lwip_file_handle::LOCAL:
+ case Lwip_file_handle::BIND: {
+ if (count < ENDPOINT_STRLEN_MAX)
+ return Read_result::READ_ERR_INVALID;
+ char const *ip_str = ipaddr_ntoa(&_pcb->local_ip);
+ /* TODO: [IPv6]:port */
+ out_count = Genode::snprintf(dst, count, "%s:%d\n",
+ ip_str, _pcb->local_port);
+ return Read_result::READ_OK;
+ }
+
+ case Lwip_file_handle::CONNECT: {
+ /* check if the PCB was connected */
+ if (ip_addr_isany(&_pcb->remote_ip))
+ return Read_result::READ_OK;
+ /* otherwise fallthru to REMOTE*/
+ }
+
+ case Lwip_file_handle::REMOTE: {
+ if (count < ENDPOINT_STRLEN_MAX) {
+ Genode::error("VFS LwIP: accept file read buffer is too small");
+ return Read_result::READ_ERR_INVALID;
+ }
+ if (ip_addr_isany(&_pcb->remote_ip)) {
+ if (Packet *pkt = _packet_queue.head()) {
+ char const *ip_str = ipaddr_ntoa(&pkt->addr);
+ /* TODO: IPv6 */
+ out_count = Genode::snprintf(dst, count, "%s:%d\n",
+ ip_str, pkt->port);
+ return Read_result::READ_OK;
+ }
+ } else {
+ char const *ip_str = ipaddr_ntoa(&_pcb->remote_ip);
+ /* TODO: [IPv6]:port */
+ out_count = Genode::snprintf(dst, count, "%s:%d\n",
+ ip_str, _pcb->remote_port);
+ return Read_result::READ_OK;
+ }
+ break;
+ }
+
+ case Lwip_file_handle::LOCATION:
+ /*
+ * Print the location of this socket directory
+ */
+ out_count = Genode::snprintf(
+ dst, count, "udp/%s\n", name().string());
+ return Read_result::READ_OK;
+ break;
+
+ default: break;
+ }
+
+ return Read_result::READ_ERR_INVALID;
+ }
+
+ Write_result write(Lwip_file_handle &handle,
+ char const *src, file_size count,
+ file_size &out_count) override
+ {
+ switch(handle.kind) {
+
+ case Lwip_file_handle::DATA: {
+ if (ip_addr_isany(&_to_addr)) break;
+
+ file_size remain = count;
+ while (remain) {
+ pbuf *buf = pbuf_alloc(PBUF_RAW, remain, PBUF_RAM);
+ pbuf_take(buf, src, buf->tot_len);
+
+ char shit[ENDPOINT_STRLEN_MAX];
+ ipaddr_aton(shit, &_to_addr);
+ err_t err = udp_sendto(_pcb, buf, &_to_addr, _to_port);
+ pbuf_free(buf);
+ if (err != ERR_OK)
+ return Write_result::WRITE_ERR_IO;
+ remain -= buf->tot_len;
+ src += buf->tot_len;
+ }
+ out_count = count;
+ return Write_result::WRITE_OK;
+ }
+
+ case Lwip_file_handle::REMOTE: {
+ if (!ip_addr_isany(&_pcb->remote_ip)) {
+ return Write_result::WRITE_ERR_INVALID;
+ } else {
+ char buf[ENDPOINT_STRLEN_MAX];
+ Genode::strncpy(buf, src, min(count+1, sizeof(buf)));
+
+ _to_port = remove_port(buf);
+ out_count = count;
+ if (ipaddr_aton(buf, &_to_addr)) {
+ out_count = count;
+ return Write_result::WRITE_OK;
+ }
+ }
+ break;
+ }
+
+ case Lwip_file_handle::BIND: {
+ if (count < ENDPOINT_STRLEN_MAX) {
+ char buf[ENDPOINT_STRLEN_MAX];
+ ip_addr_t addr;
+ u16_t port;
+
+ Genode::strncpy(buf, src, min(count+1, sizeof(buf)));
+ port = remove_port(buf);
+ if (!ipaddr_aton(buf, &addr))
+ break;
+
+ err_t err = udp_bind(_pcb, &addr, port);
+ if (err == ERR_OK) {
+ out_count = count;
+ return Write_result::WRITE_OK;
+ }
+ return Write_result::WRITE_ERR_IO;
+ }
+ break;
+ }
+
+ case Lwip_file_handle::CONNECT: {
+ if (count < ENDPOINT_STRLEN_MAX) {
+ char buf[ENDPOINT_STRLEN_MAX];
+
+ Genode::strncpy(buf, src, min(count+1, sizeof(buf)));
+
+ _to_port = remove_port(buf);
+ if (!ipaddr_aton(buf, &_to_addr))
+ break;
+
+ err_t err = udp_connect(_pcb, &_to_addr, _to_port);
+ if (err != ERR_OK) {
+ Genode::error("lwIP: failed to connect UDP socket, error ", (int)-err);
+ return Write_result::WRITE_ERR_IO;
+ }
+
+ out_count = count;
+ return Write_result::WRITE_OK;
+ }
+ break;
+ }
+
+ default: break;
+ }
+
+ return Write_result::WRITE_ERR_INVALID;
+ }
+
+ Sync_result complete_sync() override { return Sync_result::SYNC_OK; };
+};
+
+
+/*********
+ ** TCP **
+ *********/
+
+class Lwip::Tcp_socket_dir final :
+ public Socket_dir,
+ private Tcp_socket_dir_list::Element
+{
+ public:
+
+ struct Pcb_pending : Genode::List::Element
+ {
+ tcp_pcb *pcb;
+ pbuf *buf = nullptr;
+
+ Pcb_pending(tcp_pcb *p) : pcb(p) { }
+ };
+
+ private:
+
+ /*
+ * Noncopyable
+ */
+ Tcp_socket_dir(Tcp_socket_dir const &);
+ Tcp_socket_dir &operator = (Tcp_socket_dir const &);
+
+ Tcp_proto_dir &_proto_dir;
+ Genode::Entrypoint &_ep;
+
+ typedef Genode::List Pcb_pending_list;
+
+ Pcb_pending_list _pcb_pending { };
+ tcp_pcb *_pcb;
+
+ /* queue of received data */
+ pbuf *_recv_pbuf = nullptr;
+ u16_t _recv_off = 0;
+
+ Open_result _accept_new_socket(Vfs::File_system &fs,
+ Genode::Allocator &alloc,
+ Vfs::Vfs_handle **out_handle) override
+ {
+ *out_handle = new (alloc) Lwip_file_handle(
+ fs, alloc, Vfs::Directory_service::OPEN_MODE_RDONLY,
+ *this, Lwip_file_handle::PENDING);
+ return Open_result::OPEN_OK;
+ }
+
+ public:
+
+ friend class Tcp_socket_dir_list;
+ friend class Tcp_socket_dir_list::Element;
+ using Tcp_socket_dir_list::Element::next;
+
+ State state;
+
+ Tcp_socket_dir(unsigned num, Tcp_proto_dir &proto_dir,
+ Genode::Allocator &alloc,
+ Vfs::Io_response_handler &io_handler,
+ Genode::Entrypoint &ep,
+ tcp_pcb *pcb)
+ : Socket_dir(num, alloc, io_handler), _proto_dir(proto_dir),
+ _ep(ep), _pcb(pcb ? pcb : tcp_new()), state(pcb ? READY : NEW)
+ {
+ /* 'this' will be the argument to LwIP callbacks */
+ tcp_arg(_pcb, this);
+
+ tcp_recv(_pcb, tcp_recv_callback);
+
+ /* Disabled, do not track acknowledgements */
+ /* tcp_sent(_pcb, tcp_sent_callback); */
+
+ tcp_err(_pcb, tcp_err_callback);
+
+ if (pcb) {
+ tcp_backlog_accepted(_pcb);
+ }
+ }
+
+ ~Tcp_socket_dir()
+ {
+ tcp_arg(_pcb, NULL);
+
+ for (Pcb_pending *p = _pcb_pending.first(); p; p->next()) {
+ destroy(alloc, p);
+ }
+
+ if (state != CLOSED && _pcb != NULL) {
+ tcp_close(_pcb);
+ }
+
+ _proto_dir.release(this);
+ }
+
+ /**
+ * Accept new connection from callback
+ */
+ err_t accept(struct tcp_pcb *newpcb, err_t)
+ {
+ Pcb_pending *elem = new (alloc) Pcb_pending(newpcb);
+ _pcb_pending.insert(elem);
+
+ tcp_arg(newpcb, elem);
+ tcp_recv(newpcb, tcp_delayed_recv_callback);
+
+ handle_io(Lwip_file_handle::ACCEPT|Lwip_file_handle::PENDING);
+ return ERR_OK;
+ }
+
+ /**
+ * chain a buffer to the queue
+ */
+ void recv(struct pbuf *buf)
+ {
+ if (_recv_pbuf && buf) {
+ pbuf_cat(_recv_pbuf, buf);
+ } else {
+ _recv_pbuf = buf;
+ }
+ }
+
+ /**
+ * Close the connection by error
+ *
+ * Triggered by error callback, usually
+ * just by an aborted connection.
+ */
+ void error()
+ {
+ state = CLOSED;
+ /* the PCB is expired now */
+ _pcb = NULL;
+
+ /* churn the application */
+ handle_io(Lwip_file_handle::REMOTE|Lwip_file_handle::DATA);
+ }
+
+ /**
+ * Close the connection
+ *
+ * Can be triggered by remote shutdown via callback
+ */
+ void shutdown()
+ {
+ state = CLOSING;
+ if (_recv_pbuf)
+ return;
+
+ tcp_close(_pcb);
+ tcp_arg(_pcb, NULL);
+ state = CLOSED;
+ /* lwIP may reuse the PCB memory for the next connection */
+ _pcb = NULL;
+ }
+
+ /**************************
+ ** Socket_dir interface **
+ **************************/
+
+ bool read_ready(Lwip_file_handle &handle) override
+ {
+ switch (handle.kind) {
+ case Lwip_file_handle::DATA:
+ case Lwip_file_handle::PEEK:
+ switch (state) {
+ case READY:
+ return _recv_pbuf != NULL;
+ case CLOSING:
+ case CLOSED:
+ /* time for the application to find out */
+ return true;
+ default: break;
+ }
+ break;
+
+ case Lwip_file_handle::ACCEPT:
+ case Lwip_file_handle::PENDING:
+ return _pcb_pending.first() != nullptr;
+
+ case Lwip_file_handle::BIND:
+ return state != NEW;
+
+ case Lwip_file_handle::REMOTE:
+ switch (state) {
+ case NEW:
+ case BOUND:
+ case LISTEN:
+ break;
+ default:
+ return true;
+ }
+ break;
+
+ case Lwip_file_handle::CONNECT:
+ return !ip_addr_isany(&_pcb->remote_ip);
+
+ case Lwip_file_handle::LOCATION:
+ case Lwip_file_handle::LOCAL:
+ return true;
+ default: break;
+ }
+
+ return false;
+ }
+
+ Read_result read(Lwip_file_handle &handle,
+ char *dst, file_size count,
+ file_size &out_count) override
+ {
+ if (_pcb == NULL)
+ return Read_result::READ_OK;
+
+ switch(handle.kind) {
+
+ case Lwip_file_handle::DATA:
+ if (state == READY || state == CLOSING) {
+ if (_recv_pbuf == nullptr) {
+ return Read_result::READ_QUEUED;
+ }
+
+ u16_t const ucount = count;
+ u16_t const n = pbuf_copy_partial(_recv_pbuf, dst, ucount, _recv_off);
+ _recv_off += n;
+ {
+ u16_t new_off;
+ pbuf *new_head = pbuf_skip(_recv_pbuf, _recv_off, &new_off);
+ if (new_head != NULL && new_head != _recv_pbuf) {
+ /* move down the buffer and deref the head */
+ pbuf_ref(new_head);
+ pbuf_realloc(new_head, _recv_pbuf->tot_len+_recv_off);
+ pbuf_free(_recv_pbuf);
+ }
+
+ if (!new_head)
+ pbuf_free(_recv_pbuf);
+ _recv_pbuf = new_head;
+ _recv_off = new_off;
+ }
+
+ /* ACK the remote */
+ tcp_recved(_pcb, n);
+
+ if (state == CLOSING)
+ shutdown();
+
+ out_count = n;
+ return Read_result::READ_OK;
+ } else if (state == CLOSED) {
+ return Read_result::READ_OK;
+ }
+ break;
+
+ case Lwip_file_handle::PEEK:
+ if (_recv_pbuf != nullptr) {
+ u16_t const ucount = count;
+ u16_t const n = pbuf_copy_partial(_recv_pbuf, dst, ucount, _recv_off);
+ out_count = n;
+ }
+ return Read_result::READ_OK;
+
+ case Lwip_file_handle::REMOTE:
+ if (state == READY) {
+ if (count < ENDPOINT_STRLEN_MAX)
+ return Read_result::READ_ERR_INVALID;
+ char const *ip_str = ipaddr_ntoa(&_pcb->remote_ip);
+ /* TODO: [IPv6]:port */
+ out_count = Genode::snprintf(dst, count, "%s:%d\n",
+ ip_str, _pcb->remote_port);
+ return Read_result::READ_OK;
+ } else if (state == CLOSED) {
+ return Read_result::READ_OK;
+ }
+ break;
+
+ case Lwip_file_handle::PENDING: {
+ if (Pcb_pending *pp = _pcb_pending.first()) {
+ Tcp_socket_dir &new_dir = _proto_dir.alloc_socket(alloc, pp->pcb);
+ new_dir._recv_pbuf = pp->buf;
+
+ handles.remove(&handle);
+ handle.socket = &new_dir;
+ new_dir.handles.insert(&handle);
+
+ _pcb_pending.remove(pp);
+ destroy(alloc, pp);
+
+ handle.kind = Lwip_file_handle::LOCATION;
+ /* read the location of the new socket directory */
+ return handle.read(dst, count, out_count);
+ }
+
+ return Read_result::READ_QUEUED;
+ }
+
+ case Lwip_file_handle::LOCATION:
+ /*
+ * Print the location of this socket directory
+ */
+ out_count = Genode::snprintf(
+ dst, count, "tcp/%s\n", name().string());
+ return Read_result::READ_OK;
+ break;
+
+ case Lwip_file_handle::ACCEPT: {
+ /*
+ * Print the number of pending connections
+ */
+ int pending_count = 0;
+ for (Pcb_pending *p = _pcb_pending.first(); p; p = p->next())
+ ++pending_count;
+
+ out_count = Genode::snprintf(
+ dst, count, "%d\n", pending_count);
+ return Read_result::READ_OK;
+ }
+
+ case Lwip_file_handle::LOCAL:
+ case Lwip_file_handle::BIND:
+ if (state != CLOSED) {
+ if (count < ENDPOINT_STRLEN_MAX)
+ return Read_result::READ_ERR_INVALID;
+ char const *ip_str = ipaddr_ntoa(&_pcb->local_ip);
+ /* TODO: [IPv6]:port */
+ out_count = Genode::snprintf(
+ dst, count, "%s:%d\n", ip_str, _pcb->local_port);
+ return Read_result::READ_OK;
+ }
+ break;
+
+ case Lwip_file_handle::CONNECT:
+ case Lwip_file_handle::LISTEN:
+ case Lwip_file_handle::INVALID: break;
+ }
+
+ return Read_result::READ_ERR_INVALID;
+ }
+
+ Write_result write(Lwip_file_handle &handle,
+ char const *src, file_size count,
+ file_size &out_count) override
+ {
+ if (_pcb == NULL) {
+ /* socket is closed */
+ return Write_result::WRITE_ERR_INVALID;
+ }
+
+ switch(handle.kind) {
+ case Lwip_file_handle::DATA:
+ if (state == READY) {
+ file_size out = 0;
+ while (count) {
+ /* check if the send buffer is exhausted */
+ if (tcp_sndbuf(_pcb) == 0) {
+ Genode::warning("TCP send buffer congested");
+ out_count = out;
+ return out
+ ? Write_result::WRITE_OK
+ : Write_result::WRITE_ERR_WOULD_BLOCK;
+ }
+
+ u16_t n = min(count, tcp_sndbuf(_pcb));
+ /* how much can we queue right now? */
+
+ count -= n;
+ /* write to outgoing TCP buffer */
+ err_t err = tcp_write(
+ _pcb, src, n, TCP_WRITE_FLAG_COPY);
+ if (err == ERR_OK)
+ /* flush the buffer */
+ err = tcp_output(_pcb);
+ if (err != ERR_OK) {
+ Genode::error("lwIP: tcp_write failed, error ", (int)-err);
+ return Write_result::WRITE_ERR_IO;
+ }
+
+ src += n;
+ out += n;
+ /* pending_ack += n; */
+ }
+
+ out_count = out;
+ return Write_result::WRITE_OK;
+ }
+ break;
+
+ case Lwip_file_handle::BIND:
+ if ((state == NEW) && (count < ENDPOINT_STRLEN_MAX)) {
+ char buf[ENDPOINT_STRLEN_MAX];
+ ip_addr_t addr;
+ u16_t port = 0;
+
+ Genode::strncpy(buf, src, min(count+1, sizeof(buf)));
+
+ port = remove_port(buf);
+ if (!ipaddr_aton(buf, &addr))
+ break;
+
+ err_t err = tcp_bind(_pcb, &addr, port);
+ if (err == ERR_OK) {
+ state = BOUND;
+ out_count = count;
+ return Write_result::WRITE_OK;
+ }
+ }
+ break;
+
+ case Lwip_file_handle::CONNECT:
+ if (((state == NEW) || (state == BOUND)) && (count < ENDPOINT_STRLEN_MAX-1)) {
+ char buf[ENDPOINT_STRLEN_MAX];
+ ip_addr_t addr;
+ u16_t port = 0;
+
+ Genode::strncpy(buf, src, min(count+1, sizeof(buf)));
+ port = remove_port(buf);
+ if (!ipaddr_aton(buf, &addr))
+ break;
+
+ err_t err = tcp_connect(_pcb, &addr, port, tcp_connect_callback);
+ if (err != ERR_OK) {
+ Genode::error("lwIP: failed to connect TCP socket, error ", (int)-err);
+ return Write_result::WRITE_ERR_IO;
+ }
+ state = CONNECT;
+ out_count = count;
+ return Write_result::WRITE_OK;
+ }
+ break;
+
+ case Lwip_file_handle::LISTEN:
+ if ((state == BOUND) && (count < 7)) {
+ unsigned long backlog = TCP_DEFAULT_LISTEN_BACKLOG;
+ char buf[8];
+
+ Genode::strncpy(buf, src, min(count+1, sizeof(buf)));
+ Genode::ascii_to_unsigned(buf, backlog, 10);
+
+ /* this replaces the PCB so set the callbacks again */
+ _pcb = tcp_listen_with_backlog(_pcb, backlog);
+ tcp_arg(_pcb, this);
+ tcp_accept(_pcb, tcp_accept_callback);
+ state = LISTEN;
+ out_count = count;
+ return Write_result::WRITE_OK;
+ }
+ break;
+
+ default: break;
+ }
+
+ return Write_result::WRITE_ERR_INVALID;
+ }
+
+ Sync_result complete_sync() override
+ {
+ /* sync will queue until the socket is connected and ready */
+ return (state == CONNECT) ?
+ Sync_result::SYNC_QUEUED : Sync_result::SYNC_OK;
+ }
+};
+
+
+/********************
+ ** LwIP callbacks **
+ ********************/
+
+namespace Lwip {
+ extern "C" {
+
+static
+void udp_recv_callback(void *arg, struct udp_pcb*, struct pbuf *p, const ip_addr_t *addr, u16_t port)
+{
+ if (!arg) return;
+
+ Lwip::Udp_socket_dir *socket_dir = static_cast(arg);
+ socket_dir->queue(addr, port, p);
+}
+
+
+static
+err_t tcp_connect_callback(void *arg, struct tcp_pcb *pcb, err_t)
+{
+ if (!arg) {
+ tcp_close(pcb);
+ return ERR_ARG;
+ }
+
+ Lwip::Tcp_socket_dir *socket_dir = static_cast(arg);
+ socket_dir->state = Lwip::Tcp_socket_dir::READY;
+
+ socket_dir->handle_io(Lwip_file_handle::CONNECT |
+ Lwip_file_handle::DATA);
+ return ERR_OK;
+}
+
+
+static
+err_t tcp_accept_callback(void *arg, struct tcp_pcb *newpcb, err_t err)
+{
+ if (!arg) {
+ tcp_close(newpcb);
+ return ERR_OK;
+ }
+
+ Lwip::Tcp_socket_dir *socket_dir = static_cast(arg);
+ err_t e = socket_dir->accept(newpcb, err);
+ return e;
+};
+
+
+static
+err_t tcp_recv_callback(void *arg, struct tcp_pcb*, struct pbuf *p, err_t)
+{
+ if (!arg) return ERR_ARG;
+
+ Lwip::Tcp_socket_dir *socket_dir = static_cast(arg);
+ if (p == NULL) {
+ socket_dir->shutdown();
+ } else {
+ socket_dir->recv(p);
+ }
+ socket_dir->handle_io(Lwip_file_handle::DATA);
+ return ERR_OK;
+}
+
+
+static
+err_t tcp_delayed_recv_callback(void *arg, struct tcp_pcb*, struct pbuf *buf, err_t)
+{
+ Lwip::Tcp_socket_dir::Pcb_pending *pending =
+ static_cast(arg);
+
+ if (pending->buf && buf) {
+ pbuf_cat(pending->buf, buf);
+ } else {
+ pending->buf = buf;
+ }
+
+ return ERR_OK;
+};
+
+
+/*
+static
+err_t tcp_sent_callback(void *arg, struct tcp_pcb*, u16_t len)
+{
+ if (!arg) return ERR_ARG;
+
+ Lwip::Tcp_socket_dir *socket_dir = static_cast(arg);
+ socket_dir->pending_ack -= len;
+ socket_dir->handle_io(Lwip_file_handle::DATA);
+ return ERR_OK;
+}
+*/
+
+
+static
+void tcp_err_callback(void *arg, err_t)
+{
+ if (!arg) return;
+
+ Lwip::Tcp_socket_dir *socket_dir = static_cast(arg);
+ socket_dir->error();
+ /* the error is ERR_ABRT or ERR_RST, both end the session */
+}
+
+ }
+}
+
+
+/*********************
+ ** VFS file-system **
+ *********************/
+
+class Lwip::File_system final : public Vfs::File_system
+{
+ private:
+
+ /**
+ * LwIP connection to Nic service
+ */
+ struct Vfs_netif : Lwip::Nic_netif
+ {
+ Vfs::Io_response_handler &io_handler;
+
+ Tcp_proto_dir tcp_dir;
+ Udp_proto_dir udp_dir;
+
+ Nameserver_registry nameserver_handles { };
+
+ /**
+ * Wake the application when the interface changes.
+ */
+ void status_callback() override
+ {
+ Genode::warning("notify that interface is up");
+ tcp_dir.notify();
+ udp_dir.notify();
+
+ nameserver_handles.for_each([&] (Lwip_nameserver_handle &h) {
+ io_handler.handle_io_response(h.context); });
+ }
+
+ Vfs_netif(Vfs::Env &vfs_env,
+ Genode::Xml_node config,
+ Vfs::Io_response_handler &io)
+ : Lwip::Nic_netif(vfs_env.env(), vfs_env.alloc(), config),
+ io_handler(io), tcp_dir(vfs_env), udp_dir(vfs_env)
+ { }
+ } _netif;
+
+ /**
+ * Walk a path to a protocol directory and apply procedure
+ */
+ template
+ void apply_walk(char const *path, PROC const proc)
+ {
+ if (*path == '/') ++path;
+
+ if (Genode::strcmp(path, "tcp", 3) == 0)
+ proc(path+3, _netif.tcp_dir);
+ else
+ if (Genode::strcmp(path, "udp", 3) == 0)
+ proc(path+3, _netif.udp_dir);
+ }
+
+ static bool match_nameserver(char const *name) {
+ return (!strcmp(name, "nameserver")); }
+
+ public:
+
+ File_system(Vfs::Env &vfs_env, Genode::Xml_node config)
+ : _netif(vfs_env, config, vfs_env.io_handler())
+ { }
+
+ /**
+ * Reconfigure the LwIP Nic interface with the VFS config hook
+ */
+ void apply_config(Genode::Xml_node const &node) override {
+ _netif.configure(node); }
+
+
+ /***********************
+ ** Directory_service **
+ ***********************/
+
+ char const *leaf_path(char const *path) override
+ {
+ if (*path == '/') ++path;
+ if (match_nameserver(path))
+ return path;
+
+ char const *r = nullptr;
+ apply_walk(path, [&] (char const *subpath, Protocol_dir &dir) {
+ if (dir.leaf_path(subpath)) r = path;
+ });
+ return r;
+ }
+
+ Stat_result stat(char const *path, Stat &st) override
+ {
+ if (*path == '/') ++path;
+ st = Stat();
+ st.device = (Genode::addr_t)this;
+
+ if (match_nameserver(path)) {
+ st.size = IPADDR_STRLEN_MAX;
+ st.mode = STAT_MODE_FILE;
+ return STAT_OK;
+ }
+
+ Stat_result r = STAT_ERR_NO_PERM;
+
+ apply_walk(path, [&] (char const *subpath, Protocol_dir &dir) {
+ r = dir.stat(subpath, st);
+ });
+ return r;
+ }
+
+ bool directory(char const *path) override
+ {
+ if (*path == '/') ++path;
+ if (*path == '\0') return true;
+
+ bool r = false;
+ apply_walk(path, [&] (char const *subpath, Protocol_dir &dir) {
+ r = dir.directory(subpath);
+ });
+ return r;
+ }
+
+ Open_result open(char const *path,
+ unsigned mode,
+ Vfs_handle **out_handle,
+ Allocator &alloc) override
+ {
+ if (*path == '/') ++path;
+
+ /**
+ * No files may be created here
+ */
+ if (mode & OPEN_MODE_CREATE) return OPEN_ERR_NO_PERM;
+
+ if (match_nameserver(path)) {
+ *out_handle = new (alloc)
+ Lwip_nameserver_handle(*this, alloc, _netif.nameserver_handles);
+ return OPEN_OK;
+ }
+
+ Open_result r = OPEN_ERR_UNACCESSIBLE;
+ apply_walk(path, [&] (char const *subpath, Protocol_dir &dir) {
+ r = dir.open(*this, subpath, mode, out_handle, alloc);
+ });
+ return r;
+ }
+
+ Opendir_result opendir(char const *path, bool create,
+ Vfs_handle **out_handle,
+ Allocator &alloc) override
+ {
+ /**
+ * No directories may be created here
+ */
+ if (create) return OPENDIR_ERR_PERMISSION_DENIED;
+
+ Opendir_result r = OPENDIR_ERR_LOOKUP_FAILED;
+ apply_walk(path, [&] (char const *subpath, Protocol_dir &dir) {
+ r = dir.opendir(*this, subpath, out_handle, alloc);
+ });
+ return r;
+ }
+
+ void close(Vfs_handle *vfs_handle) override
+ {
+ Socket_dir *socket = nullptr;
+ if (Lwip_handle *handle = dynamic_cast(vfs_handle)) {
+ if (Lwip_file_handle *file_handle = dynamic_cast(handle)) {
+ socket = file_handle->socket;
+ }
+ destroy(handle->alloc(), handle);
+ } else {
+ Genode::error("refusing to destroy strange handle");
+ }
+
+ /* destroy sockets that are not referenced by any handles */
+ if (socket && !socket->handles.first()) {
+ destroy(socket->alloc, socket);
+ }
+ }
+
+ Unlink_result unlink(char const *) override {
+ return UNLINK_ERR_NO_PERM; }
+
+
+ /********************************
+ ** File I/O service interface **
+ ********************************/
+
+ Write_result write(Vfs_handle *vfs_handle,
+ char const *src, file_size count,
+ file_size &out_count) override
+ {
+ out_count = 0;
+
+ if ((vfs_handle->status_flags() & OPEN_MODE_ACCMODE) == OPEN_MODE_RDONLY)
+ return Write_result::WRITE_ERR_INVALID;
+ if (Lwip_handle *handle = dynamic_cast(vfs_handle))
+ return handle->write(src, count, out_count);
+ return Write_result::WRITE_ERR_INVALID;
+ }
+
+ Read_result complete_read(Vfs_handle *vfs_handle,
+ char *dst, file_size count,
+ file_size &out_count) override
+ {
+ out_count = 0;
+
+ if ((!vfs_handle) ||
+ ((vfs_handle->status_flags() & OPEN_MODE_ACCMODE) == OPEN_MODE_WRONLY)) {
+ return Read_result::READ_ERR_INVALID;
+ }
+
+ if (Lwip_handle *handle = dynamic_cast(vfs_handle))
+ return handle->read(dst, count, out_count);
+ return Read_result::READ_ERR_INVALID;
+ }
+
+ bool queue_read(Vfs_handle *, file_size)
+ {
+ if (!_netif.ready())
+ Genode::warning(__func__, ": LwIP interface not ready");
+ return _netif.ready();
+ }
+
+ bool read_ready(Vfs_handle *vfs_handle) override
+ {
+ if (Lwip_file_handle *handle = dynamic_cast(vfs_handle)) {
+ if (handle->socket)
+ return handle->socket->read_ready(*handle);
+ }
+
+ /*
+ * in this case the polled file is a 'new_socket'
+ * or a file with no associated socket
+ */
+ return true;
+ }
+
+ bool notify_read_ready(Vfs_handle *vfs_handle) override
+ {
+ if (Lwip_file_handle *handle = dynamic_cast(vfs_handle)) {
+ if (handle->socket) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ bool check_unblock(Vfs_handle*, bool, bool, bool)
+ {
+ Genode::error("VFS lwIP: ",__func__," not implemented");
+ return true;
+ }
+
+ Sync_result complete_sync(Vfs_handle *vfs_handle) override
+ {
+ Lwip_file_handle *h = dynamic_cast(vfs_handle);
+ if (h) {
+ if (h->socket) {
+ return h->socket->complete_sync();
+ } else {
+ return SYNC_QUEUED;
+ }
+ }
+ return SYNC_OK;
+ }
+
+ /***********************
+ ** File system stubs **
+ ***********************/
+
+ Rename_result rename(char const *, char const *) override {
+ return RENAME_ERR_NO_PERM; }
+
+ file_size num_dirent(char const *) override {
+ return 0; }
+
+ Dataspace_capability dataspace(char const *) override {
+ return Dataspace_capability(); }
+
+ void release(char const *, Dataspace_capability) override { };
+
+ Ftruncate_result ftruncate(Vfs_handle *, file_size) override
+ {
+ /* report ok because libc always executes ftruncate() when opening rw */
+ return FTRUNCATE_OK;
+ }
+
+ char const *type() override { return "lwip"; }
+};
+
+
+extern "C" Vfs::File_system_factory *vfs_file_system_factory(void)
+{
+ struct Factory : Vfs::File_system_factory
+ {
+ Genode::Constructible timer { };
+
+ Vfs::File_system *create(Vfs::Env &vfs_env, Genode::Xml_node config) override
+ {
+ if (!timer.constructed()) {
+ timer.construct(vfs_env.env(), "vfs_lwip");
+ Lwip::genode_init(vfs_env.alloc(), *timer);
+ }
+
+ return new (vfs_env.alloc()) Lwip::File_system(vfs_env, config);
+ }
+ };
+
+ static Factory f;
+ return &f;
+}
diff --git a/repos/ports/run/netperf.inc b/repos/ports/run/netperf.inc
index a4fce3829d..e54b85c23e 100644
--- a/repos/ports/run/netperf.inc
+++ b/repos/ports/run/netperf.inc
@@ -80,12 +80,14 @@ if {$use_usb_driver} { set network_driver "usb_drv" }
if {$use_nic_driver} { set network_driver "nic_drv" }
if {$use_wifi_driver} { set network_driver "wifi_drv" }
-set build_components {
+append build_components {
core init
drivers/timer
+ app/netperf
}
-append build_components " $netperf_target "
+append_socket_fs_build_components
+
lappend_if $use_nic_driver build_components drivers/nic
lappend_if $use_usb_driver build_components drivers/usb
lappend_if $use_nic_bridge build_components server/nic_bridge
@@ -290,23 +292,27 @@ append_platform_drv_config
append config {
-}
-append config ""
-append config {
+
-
+
2018-01-01 00:01
+
+ <} [socket_fs_plugin] { }
+if {[expr [have_spec linux] && !$use_nic_router]} {
+ append config " ip_addr=\"$lx_ip_addr\" netmask=\"255.255.255.0\" gateway=\"10.0.2.1\""
+} else {
+ append config " dhcp=\"yes\""
+}
+append config {/>
+
}
append_if $use_nic_bridge config {
@@ -331,13 +337,14 @@ install_config $config
#
# generic modules
-set boot_modules {
+append boot_modules {
core init timer
ld.lib.so libc.lib.so vfs.lib.so libm.lib.so posix.lib.so
+ netserver
}
-append boot_modules " $netperf_app "
-append boot_modules " $netperf_stack "
+append_socket_fs_boot_modules
+
lappend_if $use_nic_bridge boot_modules nic_bridge
lappend_if $use_nic_router boot_modules nic_router
diff --git a/repos/ports/run/netperf_lwip.inc b/repos/ports/run/netperf_lwip.inc
deleted file mode 100644
index ffca444a21..0000000000
--- a/repos/ports/run/netperf_lwip.inc
+++ /dev/null
@@ -1,4 +0,0 @@
-set netperf_target app/netperf/lwip
-set netperf_app netserver_lwip
-set netperf_stack lwip_legacy.lib.so
-set ip_match_string "got IP address (\[0-9]{1,3}.\[0-9]{1,3}.\[0-9]{1,3}.\[0-9]{1,3}).*\n"
diff --git a/repos/ports/run/netperf_lwip.run b/repos/ports/run/netperf_lwip.run
index 7e573bc56b..61f38c517f 100644
--- a/repos/ports/run/netperf_lwip.run
+++ b/repos/ports/run/netperf_lwip.run
@@ -13,5 +13,7 @@ set use_usb_11 "no"
set use_usb_20 "yes"
set use_usb_30 "no"
-source ${genode_dir}/repos/ports/run/netperf_lwip.inc
+set ip_match_string "address=(\[0-9\]+\.\[0-9\]+\.\[0-9\]+\.\[0-9\]+).*\n"
+
+source ${genode_dir}/repos/libports/run/vfs_lwip.inc
source ${genode_dir}/repos/ports/run/netperf.inc
diff --git a/repos/ports/run/netperf_lxip.inc b/repos/ports/run/netperf_lxip.inc
deleted file mode 100644
index 56634f7956..0000000000
--- a/repos/ports/run/netperf_lxip.inc
+++ /dev/null
@@ -1,4 +0,0 @@
-set netperf_target app/netperf/lxip
-set netperf_app netserver_lxip
-set netperf_stack { lxip.lib.so }
-set ip_match_string "ipaddr=(\[0-9\]+\.\[0-9\]+\.\[0-9\]+\.\[0-9\]+).*\n"
diff --git a/repos/ports/run/netperf_lxip.run b/repos/ports/run/netperf_lxip.run
index 50481fde64..820ce98c04 100644
--- a/repos/ports/run/netperf_lxip.run
+++ b/repos/ports/run/netperf_lxip.run
@@ -13,5 +13,7 @@ set use_usb_11 "no"
set use_usb_20 "yes"
set use_usb_30 "no"
-source ${genode_dir}/repos/ports/run/netperf_lxip.inc
+set ip_match_string "ipaddr=(\[0-9\]+\.\[0-9\]+\.\[0-9\]+\.\[0-9\]+).*\n"
+
+source ${genode_dir}/repos/dde_linux/run/vfs_lxip.inc
source ${genode_dir}/repos/ports/run/netperf.inc
diff --git a/repos/ports/src/app/netperf/lwip/target.mk b/repos/ports/src/app/netperf/lwip/target.mk
deleted file mode 100644
index 1a49717d93..0000000000
--- a/repos/ports/src/app/netperf/lwip/target.mk
+++ /dev/null
@@ -1,7 +0,0 @@
-TARGET = netserver_lwip
-
-LIBS += libc_lwip_nic_dhcp
-
-include $(PRG_DIR)/../target.inc
-
-CC_CXX_WARN_STRICT =
diff --git a/repos/ports/src/app/netperf/lxip/target.mk b/repos/ports/src/app/netperf/lxip/target.mk
deleted file mode 100644
index d104be5a46..0000000000
--- a/repos/ports/src/app/netperf/lxip/target.mk
+++ /dev/null
@@ -1,7 +0,0 @@
-TARGET = netserver_lxip
-
-LIBS += libc_lxip
-
-include $(PRG_DIR)/../target.inc
-
-CC_CXX_WARN_STRICT =
diff --git a/repos/ports/src/app/netperf/target.inc b/repos/ports/src/app/netperf/target.mk
similarity index 76%
rename from repos/ports/src/app/netperf/target.inc
rename to repos/ports/src/app/netperf/target.mk
index c53b4e560c..967dfe87a7 100644
--- a/repos/ports/src/app/netperf/target.inc
+++ b/repos/ports/src/app/netperf/target.mk
@@ -1,3 +1,4 @@
+TARGET = netserver
NETPERF_DIR := $(call select_from_ports,netperf)/src/app/netperf
@@ -10,12 +11,14 @@ SRC_C += netsys_none.c netsec_none.c netdrv_none.c netrt_none.c netslot_none.c
SRC_CC += timer.cc
-INC_DIR += $(PRG_DIR)/..
+INC_DIR += $(PRG_DIR)
CC_OPT += -DHAVE_CONFIG_H -DGENODE_BUILD
CC_WARN = -Wall -Wno-unused
-vpath %.c $(NETPERF_DIR)/src
-vpath timer.cc $(PRG_DIR)/..
+CC_CXX_WARN_STRICT =
+
+vpath timer.cc $(PRG_DIR)
+vpath %.c $(NETPERF_DIR)/src
# vi: set ft=make :
diff --git a/tool/autopilot.list b/tool/autopilot.list
index 65d3b03858..af06f606ec 100644
--- a/tool/autopilot.list
+++ b/tool/autopilot.list
@@ -14,6 +14,7 @@ extract
fault_detection
fb_bench
fetchurl
+fetchurl_lwip
fpu
fs_log
fs_packet