diff --git a/repos/os/include/uplink_session/capability.h b/repos/os/include/uplink_session/capability.h
new file mode 100644
index 0000000000..d2ba45c4ad
--- /dev/null
+++ b/repos/os/include/uplink_session/capability.h
@@ -0,0 +1,26 @@
+/*
+ * \brief Uplink session capability type
+ * \author Martin Stein
+ * \date 2020-11-30
+ */
+
+/*
+ * Copyright (C) 2020 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 _UPLINK_SESSION__CAPABILITY_H_
+#define _UPLINK_SESSION__CAPABILITY_H_
+
+/* Genode includes */
+#include
+#include
+
+namespace Uplink {
+
+ typedef Genode::Capability Session_capability;
+}
+
+#endif /* _UPLINK_SESSION__CAPABILITY_H_ */
diff --git a/repos/os/include/uplink_session/client.h b/repos/os/include/uplink_session/client.h
new file mode 100644
index 0000000000..6248ea3cc9
--- /dev/null
+++ b/repos/os/include/uplink_session/client.h
@@ -0,0 +1,61 @@
+/*
+ * \brief Client-side Uplink session interface
+ * \author Martin Stein
+ * \date 2020-11-30
+ */
+
+/*
+ * Copyright (C) 2020 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 _UPLINK_SESSION__CLIENT_H_
+#define _UPLINK_SESSION__CLIENT_H_
+
+/* Genode includes */
+#include
+#include
+#include
+#include
+
+namespace Uplink { class Session_client; }
+
+
+class Uplink::Session_client : public Genode::Rpc_client
+{
+ private:
+
+ Packet_stream_tx::Client _tx;
+ Packet_stream_rx::Client _rx;
+
+ public:
+
+ /**
+ * Constructor
+ *
+ * \param tx_buffer_alloc allocator used for managing the
+ * transmission buffer
+ */
+ Session_client(Session_capability session,
+ Genode::Range_allocator &tx_buffer_alloc,
+ Genode::Region_map &rm)
+ :
+ Genode::Rpc_client(session),
+ _tx(call(), rm, tx_buffer_alloc),
+ _rx(call(),rm )
+ { }
+
+
+ /******************************
+ ** Uplink session interface **
+ ******************************/
+
+ Tx *tx_channel() override { return &_tx; }
+ Rx *rx_channel() override { return &_rx; }
+ Tx::Source *tx() override { return _tx.source(); }
+ Rx::Sink *rx() override { return _rx.sink(); }
+};
+
+#endif /* _UPLINK_SESSION__CLIENT_H_ */
diff --git a/repos/os/include/uplink_session/connection.h b/repos/os/include/uplink_session/connection.h
new file mode 100644
index 0000000000..6165cb162a
--- /dev/null
+++ b/repos/os/include/uplink_session/connection.h
@@ -0,0 +1,60 @@
+/*
+ * \brief Connection to Uplink service
+ * \author Martin Stein
+ * \date 2020-11-30
+ */
+
+/*
+ * Copyright (C) 2020 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 _UPLINK_SESSION__CONNECTION_H_
+#define _UPLINK_SESSION__CONNECTION_H_
+
+/* Genode includes */
+#include
+#include
+#include
+#include
+
+namespace Uplink { struct Connection; }
+
+
+struct Uplink::Connection : Genode::Connection, Session_client
+{
+ /**
+ * Constructor
+ *
+ * \param tx_buffer_alloc allocator used for managing the
+ * transmission buffer
+ * \param tx_buf_size size of transmission buffer in bytes
+ * \param rx_buf_size size of reception buffer in bytes
+ */
+ Connection(Genode::Env &env,
+ Genode::Range_allocator *tx_block_alloc,
+ Genode::size_t tx_buf_size,
+ Genode::size_t rx_buf_size,
+ Net::Mac_address const &mac_address,
+ char const *label = "")
+ :
+ Genode::Connection(
+ env,
+ session(
+ env.parent(),
+ "ram_quota=%ld, cap_quota=%ld, mac_address=\"%s\", "
+ "tx_buf_size=%ld, rx_buf_size=%ld, label=\"%s\"",
+ 32 * 1024 * sizeof(long) + tx_buf_size + rx_buf_size,
+ CAP_QUOTA,
+ Genode::String<18>(mac_address).string(),
+ tx_buf_size,
+ rx_buf_size,
+ label)),
+
+ Session_client(cap(), *tx_block_alloc, env.rm())
+ { }
+};
+
+#endif /* _UPLINK_SESSION__CONNECTION_H_ */
diff --git a/repos/os/include/uplink_session/rpc_object.h b/repos/os/include/uplink_session/rpc_object.h
new file mode 100644
index 0000000000..3bd61683cf
--- /dev/null
+++ b/repos/os/include/uplink_session/rpc_object.h
@@ -0,0 +1,59 @@
+/*
+ * \brief Server-side Uplink session interface
+ * \author Martin Stein
+ * \date 2020-11-30
+ */
+
+/*
+ * Copyright (C) 2020 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 _UPLINK_SESSION__RPC_OBJECT_H_
+#define _UPLINK_SESSION__RPC_OBJECT_H_
+
+/* Genode includes */
+#include
+#include
+#include
+
+namespace Uplink { class Session_rpc_object; }
+
+
+class Uplink::Session_rpc_object : public Genode::Rpc_object
+{
+ protected:
+
+ Packet_stream_tx::Rpc_object _tx;
+ Packet_stream_rx::Rpc_object _rx;
+
+ public:
+
+ /**
+ * Constructor
+ *
+ * \param tx_ds dataspace used as communication buffer
+ * for the tx packet stream
+ * \param rx_ds dataspace used as communication buffer
+ * for the rx packet stream
+ * \param rx_buffer_alloc allocator used for managing the communication
+ * buffer of the rx packet stream
+ * \param ep entry point used for packet-stream channels
+ */
+ Session_rpc_object(Genode::Region_map &rm,
+ Genode::Dataspace_capability tx_ds,
+ Genode::Dataspace_capability rx_ds,
+ Genode::Range_allocator *rx_buffer_alloc,
+ Genode::Rpc_entrypoint &ep)
+ :
+ _tx(tx_ds, rm, ep),
+ _rx(rx_ds, rm, *rx_buffer_alloc, ep)
+ { }
+
+ Genode::Capability _tx_cap() { return _tx.cap(); }
+ Genode::Capability _rx_cap() { return _rx.cap(); }
+};
+
+#endif /* _UPLINK_SESSION__RPC_OBJECT_H_ */
diff --git a/repos/os/include/uplink_session/uplink_session.h b/repos/os/include/uplink_session/uplink_session.h
new file mode 100644
index 0000000000..0a813c8878
--- /dev/null
+++ b/repos/os/include/uplink_session/uplink_session.h
@@ -0,0 +1,110 @@
+/*
+ * \brief Uplink session interface
+ * \author Martin Stein
+ * \date 2020-11-30
+ */
+
+/*
+ * Copyright (C) 2020 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 _UPLINK_SESSION__UPLINK_SESSION_H_
+#define _UPLINK_SESSION__UPLINK_SESSION_H_
+
+/* Genode includes */
+#include
+#include
+#include
+
+namespace Uplink {
+
+ struct Session;
+
+ using Genode::Packet_stream_sink;
+ using Genode::Packet_stream_source;
+
+ typedef Genode::Packet_descriptor Packet_descriptor;
+}
+
+
+/*
+ * Uplink session interface
+ *
+ * An Uplink session corresponds to a network adaptor, which can be used to
+ * transmit and receive network packets. Payload is communicated over the
+ * packet-stream interface set up between 'Session_client' and
+ * 'Session_server'.
+ *
+ * Even though the methods 'tx', 'tx_channel', 'rx', and 'rx_channel' are
+ * specific for the client side of the Uplink session interface, they are part of
+ * the abstract 'Session' class to enable the client-side use of the Uplink
+ * interface via a pointer to the abstract 'Session' class. This way, we can
+ * transparently co-locate the packet-stream server with the client in same
+ * program.
+ */
+struct Uplink::Session : Genode::Session
+{
+ enum { QUEUE_SIZE = 1024 };
+
+ /*
+ * Types used by the client stub code and server implementation
+ *
+ * The acknowledgement queue has always the same size as the submit
+ * queue. We access the packet content as a char pointer.
+ */
+ typedef Genode::Packet_stream_policy Policy;
+
+ typedef Packet_stream_tx::Channel Tx;
+ typedef Packet_stream_rx::Channel Rx;
+
+ /**
+ * \noapi
+ */
+ static const char *service_name() { return "Uplink"; }
+
+ /*
+ * An Uplink session consumes a dataspace capability for the server-side
+ * session object, a session capability, two packet-stream dataspaces for
+ * rx and tx, and four signal context capabilities for the data-flow
+ * signals.
+ */
+ enum { CAP_QUOTA = 8 };
+
+ virtual ~Session() { }
+
+ /**
+ * Request packet-transmission channel
+ */
+ virtual Tx *tx_channel() { return 0; }
+
+ /**
+ * Request packet-reception channel
+ */
+ virtual Rx *rx_channel() { return 0; }
+
+ /**
+ * Request client-side packet-stream interface of tx channel
+ */
+ virtual Tx::Source *tx() { return 0; }
+
+ /**
+ * Request client-side packet-stream interface of rx channel
+ */
+ virtual Rx::Sink *rx() { return 0; }
+
+
+ /*******************
+ ** RPC interface **
+ *******************/
+
+ GENODE_RPC(Rpc_tx_cap, Genode::Capability, _tx_cap);
+ GENODE_RPC(Rpc_rx_cap, Genode::Capability, _rx_cap);
+
+ GENODE_RPC_INTERFACE(Rpc_tx_cap, Rpc_rx_cap);
+};
+
+#endif /* _UPLINK_SESSION__UPLINK_SESSION_H_ */
diff --git a/repos/os/recipes/api/uplink_session/content.mk b/repos/os/recipes/api/uplink_session/content.mk
new file mode 100644
index 0000000000..5c4ab41847
--- /dev/null
+++ b/repos/os/recipes/api/uplink_session/content.mk
@@ -0,0 +1,2 @@
+MIRRORED_FROM_REP_DIR := include/uplink_session include/net
+include $(REP_DIR)/recipes/api/session.inc
diff --git a/repos/os/recipes/api/uplink_session/hash b/repos/os/recipes/api/uplink_session/hash
new file mode 100644
index 0000000000..48e860ccec
--- /dev/null
+++ b/repos/os/recipes/api/uplink_session/hash
@@ -0,0 +1 @@
+2020-12-09 42290160000ae6dd05f74b8f26541c3ebdfc2118