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