From d9a47731943b8b17948c26d7adfb504c98c27927 Mon Sep 17 00:00:00 2001 From: Emery Hemingway Date: Sun, 18 Sep 2016 19:46:54 +0200 Subject: [PATCH] LwIP VFS plugin This patch reintroduces the LwIP stack to libc as a VFS plugin implementing the socket_fs interface. Rather than use LwIP's socket emulation layer this plugin interfaces directly to LwIP raw API and is single threaded. The internal TCP parameters of the stack are untuned. Fix #2050 Fix #2335 --- repos/dde_linux/run/vfs_lxip.inc | 13 + repos/libports/include/lwip/arch/cc.h | 100 + repos/libports/include/lwip/arch/perf.h | 20 + repos/libports/include/lwip/genode_init.h | 22 + repos/libports/include/lwip/lwipopts.h | 133 ++ repos/libports/include/lwip/nic_netif.h | 416 ++++ repos/libports/lib/import/import-lwip.mk | 2 + repos/libports/lib/mk/lwip.mk | 41 + repos/libports/lib/mk/vfs_lwip.mk | 11 + repos/libports/ports/lwip.hash | 1 + repos/libports/ports/lwip.port | 20 + .../libports/recipes/src/vfs_lwip/content.mk | 22 + repos/libports/recipes/src/vfs_lwip/hash | 1 + repos/libports/recipes/src/vfs_lwip/used_apis | 7 + repos/libports/run/fetchurl.inc | 135 ++ repos/libports/run/fetchurl.run | 134 +- repos/libports/run/fetchurl_lwip.run | 2 + repos/libports/run/libc_getaddrinfo.run | 11 +- repos/libports/run/netty_lwip.inc | 90 + repos/libports/run/netty_lwip_tcp.run | 72 + repos/libports/run/netty_lwip_udp.run | 45 + repos/libports/run/vfs_lwip.inc | 13 + .../libports/src/lib/libc/socket_fs_plugin.cc | 2 +- repos/libports/src/lib/lwip/include/stdlib.h | 0 repos/libports/src/lib/lwip/include/string.h | 34 + .../libports/src/lib/lwip/platform/printf.cc | 36 + repos/libports/src/lib/lwip/platform/rand.cc | 30 + .../src/lib/lwip/platform/sys_arch.cc | 116 ++ repos/libports/src/lib/vfs/lwip/symbol.map | 9 + repos/libports/src/lib/vfs/lwip/target.mk | 2 + repos/libports/src/lib/vfs/lwip/vfs.cc | 1848 +++++++++++++++++ repos/ports/run/netperf.inc | 31 +- repos/ports/run/netperf_lwip.inc | 4 - repos/ports/run/netperf_lwip.run | 4 +- repos/ports/run/netperf_lxip.inc | 4 - repos/ports/run/netperf_lxip.run | 4 +- repos/ports/src/app/netperf/lwip/target.mk | 7 - repos/ports/src/app/netperf/lxip/target.mk | 7 - .../src/app/netperf/{target.inc => target.mk} | 9 +- tool/autopilot.list | 1 + 40 files changed, 3282 insertions(+), 177 deletions(-) create mode 100644 repos/dde_linux/run/vfs_lxip.inc create mode 100644 repos/libports/include/lwip/arch/cc.h create mode 100644 repos/libports/include/lwip/arch/perf.h create mode 100644 repos/libports/include/lwip/genode_init.h create mode 100644 repos/libports/include/lwip/lwipopts.h create mode 100644 repos/libports/include/lwip/nic_netif.h create mode 100644 repos/libports/lib/import/import-lwip.mk create mode 100644 repos/libports/lib/mk/lwip.mk create mode 100644 repos/libports/lib/mk/vfs_lwip.mk create mode 100644 repos/libports/ports/lwip.hash create mode 100644 repos/libports/ports/lwip.port create mode 100644 repos/libports/recipes/src/vfs_lwip/content.mk create mode 100644 repos/libports/recipes/src/vfs_lwip/hash create mode 100644 repos/libports/recipes/src/vfs_lwip/used_apis create mode 100644 repos/libports/run/fetchurl.inc create mode 100644 repos/libports/run/fetchurl_lwip.run create mode 100644 repos/libports/run/netty_lwip.inc create mode 100644 repos/libports/run/netty_lwip_tcp.run create mode 100644 repos/libports/run/netty_lwip_udp.run create mode 100644 repos/libports/run/vfs_lwip.inc create mode 100644 repos/libports/src/lib/lwip/include/stdlib.h create mode 100644 repos/libports/src/lib/lwip/include/string.h create mode 100644 repos/libports/src/lib/lwip/platform/printf.cc create mode 100644 repos/libports/src/lib/lwip/platform/rand.cc create mode 100644 repos/libports/src/lib/lwip/platform/sys_arch.cc create mode 100644 repos/libports/src/lib/vfs/lwip/symbol.map create mode 100644 repos/libports/src/lib/vfs/lwip/target.mk create mode 100644 repos/libports/src/lib/vfs/lwip/vfs.cc delete mode 100644 repos/ports/run/netperf_lwip.inc delete mode 100644 repos/ports/run/netperf_lxip.inc delete mode 100644 repos/ports/src/app/netperf/lwip/target.mk delete mode 100644 repos/ports/src/app/netperf/lxip/target.mk rename repos/ports/src/app/netperf/{target.inc => target.mk} (76%) 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