diff --git a/src/l4/pkg/shmc/include/internal.h b/src/l4/pkg/shmc/include/internal.h
index c4cb4bf..6c7faeb 100644
--- a/src/l4/pkg/shmc/include/internal.h
+++ b/src/l4/pkg/shmc/include/internal.h
@@ -24,6 +24,23 @@ l4shmc_attach(const char *shmc_name, l4shmc_area_t *shmarea)
   return l4shmc_attach_to(shmc_name, 0, shmarea);
 }
 
+L4_CV L4_INLINE void l4shmc_membarrier(void)
+{
+  /*
+   * l4_barrier() is only a compiler memory barrier, but we need a hardware
+   * memory barrier (at least if Fiasco runs on SMP)
+   */
+#if defined(__ARM_ARCH_4T__) || defined(__ARM_ARCH_5TE__)
+  /*
+   * Early ARM arches don't support SMP and, depending on the version,
+   * gcc either does not have __sync_synchronize for them or it requires
+   * special kernel support.
+   */
+  l4_barrier();
+#else
+  __sync_synchronize();
+#endif
+}
 
 L4_CV L4_INLINE long
 l4shmc_wait_any(l4shmc_signal_t **p)
@@ -91,7 +108,7 @@ L4_CV L4_INLINE long
 l4shmc_chunk_ready(l4shmc_chunk_t *chunk, l4_umword_t size)
 {
   chunk->_chunk->_size = size;
-  asm volatile("" : : : "memory");
+  l4shmc_membarrier();
   chunk->_chunk->_status = L4SHMC_CHUNK_READY;
   return L4_EOK;
 }
@@ -128,16 +145,19 @@ l4shmc_signal_cap(l4shmc_signal_t *signal)
   return signal->_sigcap;
 }
 
-L4_CV L4_INLINE l4_umword_t
+L4_CV L4_INLINE long
 l4shmc_chunk_size(l4shmc_chunk_t *p)
 {
-  return p->_chunk->_size;
+  l4_umword_t s = p->_chunk->_size;
+  if (s > p->_capacity)
+    return -L4_EIO;
+  return s;
 }
 
-L4_CV L4_INLINE l4_umword_t
+L4_CV L4_INLINE long
 l4shmc_chunk_capacity(l4shmc_chunk_t *p)
 {
-  return p->_chunk->_capacity;
+  return p->_capacity;
 }
 
 L4_CV L4_INLINE long
@@ -152,7 +172,6 @@ l4shmc_chunk_try_to_take(l4shmc_chunk_t *chunk)
 L4_CV L4_INLINE long
 l4shmc_chunk_consumed(l4shmc_chunk_t *chunk)
 {
-  asm volatile("" : : : "memory");
   chunk->_chunk->_status = L4SHMC_CHUNK_CLEAR;
   return L4_EOK;
 }
diff --git a/src/l4/pkg/shmc/include/shmbuf.h b/src/l4/pkg/shmc/include/shmbuf.h
new file mode 100644
index 0000000..c1b636e
--- /dev/null
+++ b/src/l4/pkg/shmc/include/shmbuf.h
@@ -0,0 +1,546 @@
+/*
+ * Copyright (c) 2011 Stefan Fritsch <stefan_fritsch@genua.de>
+ *                    Christian Ehrhardt <christian_ehrhardt@genua.de>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#ifndef L4SHMC_SHMBUF_H
+#define L4SHMC_SHMBUF_H
+
+#include <l4/shmc/shmc.h>
+#include <l4/sys/err.h>
+#include <l4/sys/compiler.h>
+
+EXTERN_C_BEGIN
+
+/* sizeof(struct l4shm_buf_pkt_head) must be power of two */
+struct l4shm_buf_pkt_head
+{
+  unsigned long size;
+};
+
+struct l4shm_buf_chunk_head
+{
+  /** end of ring content */
+  volatile unsigned long next_offs_to_write;
+  /** start of ring content */
+  volatile unsigned long next_offs_to_read;
+  /** ring buffer full */
+  volatile unsigned long writer_blocked;
+  /** The packet buffers. */
+  volatile struct l4shm_buf_pkt_head pkg[0];
+};
+
+/**
+ * Return the size of the largest packet that currently fits into
+ * the given chunk.
+ * @param chunk The chunk.
+ * @param chunksize The size of the data area of the chunk (maintained
+ *     outside of the shared memory area).
+ * It is the callers responsibility to ensure that it is the sender of
+ * this chunk.
+ */
+L4_INLINE unsigned long l4shm_buf_chunk_tx_free(struct l4shm_buf_chunk_head *chunk,
+    unsigned long chunksize)
+{
+  unsigned long roff = chunk->next_offs_to_read;
+  unsigned long woff = chunk->next_offs_to_write;
+  unsigned long space;
+
+  if (woff >= chunksize || roff >= chunksize)
+    return 0;
+
+  if (woff < roff)
+    space = roff - woff;
+  else
+    space = chunksize - (woff - roff);
+  if (space < 2 * sizeof(struct l4shm_buf_pkt_head))
+    return 0;
+  return space - 2 * sizeof(struct l4shm_buf_pkt_head);
+}
+
+/** align v to power of 2 boundary */
+L4_INLINE l4_umword_t l4shmc_align(l4_umword_t v, l4_umword_t boundary)
+{
+  return (v + boundary - 1 ) & ~(boundary - 1);
+}
+
+L4_INLINE volatile struct l4shm_buf_pkt_head *l4shmc_align_ptr_ph(volatile struct l4shm_buf_pkt_head *v)
+{
+  return (struct l4shm_buf_pkt_head *)l4shmc_align((l4_umword_t)v, sizeof(struct l4shm_buf_pkt_head));
+}
+
+L4_INLINE l4_umword_t l4shmc_align_off_ph(l4_umword_t v)
+{
+  return l4shmc_align(v, sizeof(struct l4shm_buf_pkt_head));
+}
+
+/**
+ * Initialize a chunk.
+ * Note that the entire chunk structure lives in shared memory.
+ * @param chunk The chunk structure.
+ * @param chunksize The size of the chunk including the l4shm_buf_chunk_head
+ *     structure. This value is not maintained inside the chunk head
+ *     but used to check alignment requirements.
+ * @return True if initialization was successful, a negative error code
+ *     if initialization failed.
+ */
+L4_INLINE int l4shm_buf_chunk_init(struct l4shm_buf_chunk_head *chunk,
+				   unsigned long chunksize)
+{
+  static_assert(0 == ( sizeof(struct l4shm_buf_pkt_head) &
+		       (sizeof(struct l4shm_buf_pkt_head)-1) ),
+		"sizeof(struct l4shm_buf_pkt_head) not power of 2");
+
+  if (chunk->pkg != l4shmc_align_ptr_ph(chunk->pkg))
+    return -L4_EINVAL;
+  chunksize -= sizeof(struct l4shm_buf_chunk_head);
+  if (chunksize != l4shmc_align_off_ph(chunksize))
+    return -L4_EINVAL;
+  chunk->pkg[0].size = 0;
+  chunk->next_offs_to_write = 0,
+	 chunk->next_offs_to_read = 0;
+  chunk->writer_blocked = 0;
+  return 0;
+}
+
+/**
+ * Add part of a packet to the given chunk. The data is only copied
+ * into the area of the chunk reserved for the sender. It is not made
+ * available for the receiver. Use l4shm_buf_chunk_tx_complete for this.
+ * It is the callers responsibility to ensure that it is the sender
+ * on this chunk.
+ * @param ch The chunk.
+ * @param chunksize The size of the payload data in the chunk, i.e.
+ *     excluding the leading l4shm_buf_chunk_head structure.
+ * @param buf The packet data.
+ * @param poffset The offset of this chunk within the packet. The caller must
+ *     make sure that it only commits complete packets.
+ * @param len The length of the packet data.
+ * @return Zero if the packet was added to the chunk, a negative error
+ *     code otherwise. In particular -L4_EAGAIN means that insufficient
+ *     space was available in the ring.
+ */
+L4_INLINE int l4shm_buf_chunk_tx_part(struct l4shm_buf_chunk_head *ch,
+				      unsigned long chunksize, const char *buf,
+				      unsigned long poffset, unsigned long len)
+{
+  unsigned long woffset, nextoffset, r, part_len, totallen;
+  volatile struct l4shm_buf_pkt_head *ph;
+  int blocked = 0;
+
+  if (len == 0)
+    return 0;
+  if (poffset > chunksize || len > chunksize)
+    return -L4_ENOMEM;
+  totallen = poffset + len;
+  if (totallen > chunksize - 2*sizeof(struct l4shm_buf_pkt_head))
+    return -L4_ENOMEM;
+
+retry:
+  l4shmc_membarrier();
+  woffset = ch->next_offs_to_write;
+  if (woffset >= chunksize || woffset != l4shmc_align_off_ph(woffset))
+    return -L4_EIO;
+  ph = ch->pkg + (woffset / sizeof(struct l4shm_buf_pkt_head));
+
+  nextoffset = l4shmc_align_off_ph(woffset + totallen
+				   + sizeof(struct l4shm_buf_pkt_head));
+
+  r = ch->next_offs_to_read;
+  if (r >= chunksize)
+    return -L4_EIO;
+  if (r <= woffset)
+    r += chunksize;
+
+  /* Don't use all space, L4Linux needs an additional '0' chunk head after
+   * the chunk. Therefore we need an additional struct l4shm_buf_pkt_head.
+   */
+  if (nextoffset + sizeof(struct l4shm_buf_pkt_head) > r)
+    {
+      /*
+       * If there is insufficient space set writer_blocked and
+       * retry. This is neccessary to avoid a race where we set
+       * writer blocked after the peer emptied the buffer. We don't
+       * set writer_blocked in the first try to avoid spurious interrupts
+       * triggered by the reader due to writer_blocked.
+       */
+      if (blocked)
+	return  -L4_EAGAIN;
+      ch->writer_blocked = 1;
+      blocked = 1;
+      goto retry;
+    }
+
+  ch->writer_blocked = 0;
+
+  woffset += sizeof(struct l4shm_buf_pkt_head) + poffset;
+  woffset %= chunksize;
+
+  if (woffset + len > chunksize)
+    part_len = chunksize - woffset;
+  else
+    part_len = len;
+
+  memcpy(((unsigned char *)ch->pkg)+woffset, buf, part_len);
+  if (len != part_len)
+    memcpy((void*)ch->pkg, buf + part_len, len - part_len);
+
+  return 0;
+}
+
+/**
+ * Complete the transmission of a packet. This function fills in the
+ * packet head in the shm buffer. The packet data must already be present.
+ * Use l4shm_buf_chunk_tx_part to copy packet data.
+ * @param ch The chunk.
+ * @param chunksize The size of the payload data in the chunk, i.e.
+ *     excluding the leading l4shm_buf_chunk_head structure.
+ * @param pkglen The total length of the packet.
+ * @return Zero in case of success or a negative error code.
+ */
+L4_INLINE int l4shm_buf_chunk_tx_complete(struct l4shm_buf_chunk_head *ch,
+    unsigned long chunksize, size_t pkglen)
+{
+  unsigned long offset, nextoffset, r;
+  volatile struct l4shm_buf_pkt_head *ph, *next_ph;
+
+  if (pkglen == 0)
+    return 0;
+  if (pkglen > chunksize - 2*sizeof(struct l4shm_buf_pkt_head))
+    return -L4_ENOMEM;
+
+  offset = ch->next_offs_to_write;
+  if (offset >= chunksize || offset != l4shmc_align_off_ph(offset))
+    return -L4_EIO;
+  ph = ch->pkg + (offset / sizeof(struct l4shm_buf_pkt_head));
+
+  nextoffset = l4shmc_align_off_ph(offset + pkglen + sizeof(struct l4shm_buf_pkt_head));
+
+  r = ch->next_offs_to_read;
+  if (r >= chunksize)
+    return -L4_EIO;
+  if (r <= offset)
+    r += chunksize;
+
+  /* Don't use all space, L4Linux needs an additional '0' chunk head after
+   * the chunk. Therefore we need an additional struct l4shm_buf_pkt_head.
+   */
+  if (nextoffset + sizeof(struct l4shm_buf_pkt_head) > r)
+    return  -L4_EIO;
+
+  nextoffset %= chunksize;
+  /* For L4Linux compatibility */
+  next_ph = ch->pkg + (nextoffset / sizeof(struct l4shm_buf_pkt_head));
+  next_ph->size = 0;
+
+  l4shmc_membarrier();
+
+  ph->size = pkglen;
+  ch->next_offs_to_write = nextoffset;
+  return 0;
+}
+
+/**
+ * Add a packet to the given chunk.
+ * It is the callers responsibility to ensure that it is the sender
+ * on this chunk.
+ * @param ch The chunk.
+ * @param chunksize The size of the payload data in the chunk, i.e.
+ *     excluding the leading l4shm_buf_chunk_head structure.
+ * @param buf The packet data.
+ * @param size The length of the packet data.
+ * @return Zero if the packet was added to the chunk, a negative error
+ *     code otherwise. In particular -L4_EAGAIN means that insufficient
+ *     space was available in the ring.
+ * It is the callers responsibility to wake up the receiver after adding
+ * packets or when detecting insufficient space in the buffer.
+ */
+L4_INLINE int l4shm_buf_chunk_tx(struct l4shm_buf_chunk_head *ch,
+				 unsigned long chunksize,
+				 const char *buf, unsigned long pkt_size)
+{
+  int ret = l4shm_buf_chunk_tx_part(ch, chunksize, buf, 0, pkt_size);
+  if (ret < 0)
+    return ret;
+  return l4shm_buf_chunk_tx_complete(ch, chunksize, pkt_size);
+}
+
+
+/**
+ * Return the length of the next packet in the chunk.
+ * @param ch The chunk.
+ * @param chunksize The size of the payload data in the chunk, i.e.
+ *    excluding the leading l4shm_buf_chunk_head structure.
+ * @return Zero if the chunk is empty, the length of the first
+ *    packet in the chunk or a negative value in case of an error.
+ */
+L4_INLINE int l4shm_buf_chunk_rx_len(struct l4shm_buf_chunk_head *ch,
+				     unsigned long chunksize)
+{
+  unsigned long offset = ch->next_offs_to_read;
+  unsigned long woffset = ch->next_offs_to_write;
+  long space = woffset - offset;
+  unsigned long pkt_size;
+  volatile struct l4shm_buf_pkt_head *ph;
+
+  if (offset >= chunksize)
+    return -L4_EIO;
+  if (woffset >= chunksize)
+    return -L4_EIO;
+  if (space == 0)
+    return 0;
+  if (space < 0)
+    space += chunksize;
+  if (space < (int)sizeof(struct l4shm_buf_pkt_head))
+    return -L4_EIO;
+  ph = ch->pkg + (offset / sizeof(struct l4shm_buf_pkt_head));
+  pkt_size = ph->size;
+  if (pkt_size > (unsigned long)space - sizeof(struct l4shm_buf_pkt_head))
+    return -L4_EIO;
+  return pkt_size;
+}
+
+/**
+ * Drop the first packet in the chunk. The packet must have non-zero length.
+ * @param ch The chunk.
+ * @param chunksize The size of the payload data in the chunk, i.e.
+ *     excluding the leading l4shm_buf_chunk_head structure.
+ * @return Zero if the packet could be dropped, a negative value in case
+ *     of an error.
+ */
+L4_INLINE int l4shm_buf_chunk_rx_drop(struct l4shm_buf_chunk_head *ch,
+				      unsigned long chunksize)
+{
+  unsigned long offset = ch->next_offs_to_read;
+  unsigned long woffset = ch->next_offs_to_write;
+  long space = woffset - offset;
+  unsigned long pkt_size;
+  volatile struct l4shm_buf_pkt_head *ph;
+
+  if (offset >= chunksize)
+    return -L4_EIO;
+  if (woffset >= chunksize)
+    return -L4_EIO;
+  if (space == 0)
+    return -L4_ENOENT;
+  if (space < 0)
+    space += chunksize;
+  if (space < (int)sizeof(struct l4shm_buf_pkt_head))
+    return -L4_EIO;
+  ph = ch->pkg + (offset / sizeof(struct l4shm_buf_pkt_head));
+  pkt_size = ph->size;
+  if (pkt_size > (unsigned long)space - sizeof(struct l4shm_buf_pkt_head))
+    return -L4_EIO;
+  offset = l4shmc_align_off_ph(offset + sizeof(struct l4shm_buf_pkt_head) + pkt_size);
+  offset %= chunksize;
+  ch->next_offs_to_read = offset;
+  l4shmc_membarrier();
+
+  return 0;
+}
+
+/**
+ * Copy part of a packet from the shm chunk to a buffer. The caller
+ * must make sure that the packet contains enough data and that the
+ * buffer is long enough to receive the data.
+ * @param ch The chunk. The data in the chunk is not modified!
+ * @param chunksize The size of the payload data in the chunk, i.e.
+ *     excluding the leading l4shm_buf_chunk_head structure.
+ * @param poffset The offset of the part to copy within the packet.
+ *     It is an error if this offset is beyond the length of the packet.
+ * @param len The amount to copy. It is an error if the packet is shorter
+ *     than offset+len bytes.
+ * @param buf The target buffer. The caller must make sure that the buffer
+ *     can hold len bytes.
+ * @return Zero or a negative error code.
+ */
+L4_INLINE int l4shm_buf_chunk_rx_part(const struct l4shm_buf_chunk_head *ch,
+				      unsigned long chunksize,
+				      unsigned long poffset,
+				      unsigned long len, char *buf)
+{
+  unsigned long roffset = ch->next_offs_to_read;
+  unsigned long woffset = ch->next_offs_to_write;
+  long space = woffset - roffset;
+  volatile const struct l4shm_buf_pkt_head *ph;
+  unsigned long part_len, pkt_size;
+
+  if (roffset >= chunksize)
+    return -L4_EIO;
+  if (woffset >= chunksize)
+    return -L4_EIO;
+  if (space < 0)
+    space += chunksize;
+  if (space < (int)sizeof(struct l4shm_buf_pkt_head))
+    return -L4_EIO;
+  ph = ch->pkg + (roffset / sizeof(struct l4shm_buf_pkt_head));
+  pkt_size = ph->size;
+  if (pkt_size > (unsigned long)space - sizeof(struct l4shm_buf_pkt_head))
+    return -L4_EIO;
+  /* Backward compatibility (pkt_size == 0 means no more packets) */
+  if (pkt_size == 0)
+    return -L4_ENOENT;
+  if (poffset >= pkt_size || len > pkt_size || poffset + len > pkt_size)
+    return -L4_ENOENT;
+  roffset += poffset + sizeof(struct l4shm_buf_pkt_head);
+  roffset %= chunksize;
+
+  if (roffset + len > chunksize)
+    part_len = chunksize - roffset;
+  else
+    part_len = len;
+  memcpy(buf, ((unsigned char *)ch->pkg)+roffset, part_len);
+  if (part_len != len)
+    memcpy(buf + part_len, (unsigned char *)ch->pkg, len - part_len);
+
+  return 0;
+}
+
+/**
+ * Remove a packet from the given chunk.
+ * It is the callers responsibility to ensure that it is the receiver
+ * on this chunk.
+ * @param ch The chunk.
+ * @param chunksize The size of the payload data in the chunk, i.e.
+ *     excluding the leading l4shm_buf_chunk_head structure.
+ * @param buf The packet buffer.
+ * @param size The length of the packet buffer.
+ * @return The size of the received packet, zero if no packet was available
+ *    and a negative error code otherwise.
+ * It is the callers responsibility to wake up a potentially blocked
+ * sender after removing data from the buffer.
+ */
+L4_INLINE int l4shm_buf_chunk_rx(struct l4shm_buf_chunk_head *ch,
+				 unsigned long chunksize,
+				 char *buf, unsigned long buf_size)
+{
+  int ret = l4shm_buf_chunk_rx_len(ch, chunksize);
+  if (ret <= 0)
+    return ret;
+  if (buf_size < ret)
+    return -L4_ENOMEM;
+  ret = l4shm_buf_chunk_rx_part(ch, chunksize, 0, ret, buf);
+  if (ret < 0)
+    return ret;
+  return l4shm_buf_chunk_rx_drop(ch, chunksize);
+}
+
+/*
+ * Various wrappers for l4shm_buf_chunk_* functions using a single l4shm_buf struct
+ */
+
+struct l4shm_buf
+{
+  struct l4shm_buf_chunk_head *tx_head;
+  struct l4shm_buf_chunk_head *rx_head;
+  unsigned long tx_ring_size;
+  unsigned long rx_ring_size;
+};
+
+/**
+ * Initialize an l4shm_buf structure with pre-allocated Rx/Tx rings
+ * @param sb A pre-allocated l4shm_buf structure to  initialize.
+ * @param rx_chunk The receive ring for this thread.
+ * @param rx_size The size of the receive ring including the l4shm_buf_chunk_head.
+ * @param tx_chunk The transmit ring for this thread.
+ * @param tx_size The size of the transmit ring including the l4shm_buf_chunk_head.
+ * @return True if successful, a negative error code if initialization
+ *     failed (normally due to bad alignment).
+ * This library will ensure that this thread only adds data to the tx
+ * ring and only removes data from the rx ring.
+ * It is possible to do initialization in two steps, by calling l4shm_buf_init()
+ * twice, once with rx_chunk == NULL and once with tx_chunk == NULL.
+ */
+L4_INLINE int l4shm_buf_init(struct l4shm_buf *sb, char *rx_chunk, unsigned long rx_size,
+			     char *tx_chunk, unsigned long tx_size)
+{
+  if (tx_chunk)
+    {
+      if (l4shm_buf_chunk_init((struct l4shm_buf_chunk_head *)tx_chunk, tx_size))
+	return -L4_EINVAL;
+      sb->tx_head = (struct l4shm_buf_chunk_head *)tx_chunk;
+      sb->tx_ring_size = tx_size - sizeof(struct l4shm_buf_chunk_head);
+    }
+  else
+    {
+      sb->tx_head = NULL;
+    }
+
+  if (rx_chunk)
+    {
+      if (l4shm_buf_chunk_init((struct l4shm_buf_chunk_head *)rx_chunk, rx_size))
+	return -L4_EINVAL;
+      sb->rx_head = (struct l4shm_buf_chunk_head *)rx_chunk;
+      sb->rx_ring_size = rx_size - sizeof(struct l4shm_buf_chunk_head);
+    }
+  else if (!tx_chunk)
+    {
+      return -L4_EINVAL;
+    }
+  else
+    {
+      sb->rx_head = NULL;
+    }
+
+  return 0;
+}
+
+L4_INLINE int l4shm_buf_rx_len(struct l4shm_buf *sb)
+{
+  return l4shm_buf_chunk_rx_len(sb->rx_head, sb->rx_ring_size);
+}
+
+L4_INLINE int l4shm_buf_rx_drop(struct l4shm_buf *sb)
+{
+  return l4shm_buf_chunk_rx_drop(sb->rx_head, sb->rx_ring_size);
+}
+
+L4_INLINE int l4shm_buf_rx_part(struct l4shm_buf *sb, unsigned long poffset,
+				unsigned long len, char *buf)
+{
+  return l4shm_buf_chunk_rx_part(sb->rx_head, sb->rx_ring_size, poffset, len, buf);
+}
+
+L4_INLINE unsigned long l4shm_buf_tx_free(struct l4shm_buf *sb)
+{
+  return l4shm_buf_chunk_tx_free(sb->tx_head, sb->tx_ring_size);
+}
+
+L4_INLINE int l4shm_buf_tx(struct l4shm_buf *sb, const char *buf,
+			   unsigned long pkt_size)
+{
+  return l4shm_buf_chunk_tx(sb->tx_head, sb->tx_ring_size, buf, pkt_size);
+}
+
+L4_INLINE int l4shm_buf_rx(struct l4shm_buf *sb, char *buf,
+			   unsigned long buf_size)
+{
+  return l4shm_buf_chunk_rx(sb->rx_head, sb->rx_ring_size, buf, buf_size);
+}
+
+
+L4_INLINE int l4shm_buf_tx_part(struct l4shm_buf *sb, const char *buf,
+				unsigned long poffset, unsigned long len)
+{
+  return l4shm_buf_chunk_tx_part(sb->tx_head, sb->tx_ring_size, buf, poffset, len);
+}
+
+L4_INLINE int l4shm_buf_tx_complete(struct l4shm_buf *sb, size_t pktlen)
+{
+  return l4shm_buf_chunk_tx_complete(sb->tx_head, sb->tx_ring_size, pktlen);
+}
+
+EXTERN_C_END
+
+#endif
diff --git a/src/l4/pkg/shmc/include/shmc.h b/src/l4/pkg/shmc/include/shmc.h
index 72f224b..d90e819 100644
--- a/src/l4/pkg/shmc/include/shmc.h
+++ b/src/l4/pkg/shmc/include/shmc.h
@@ -216,6 +216,20 @@ l4shmc_get_chunk_to(l4shmc_area_t *shmarea,
                     l4shmc_chunk_t *chunk);
 
 /**
+ * \brief Iterate over names of all existing chunks
+ * \ingroup api_l4shmc_chunk
+ *
+ * \param shmarea     Shared memory area.
+ * \param chunk_name  Where the name of the current chunk will be stored
+ * \param offs        0 to start iteration, return value of previous
+ *                    call to l4shmc_iterate_chunk() to get next chunk
+ * \return <0 on error, 0 if no more chunks, >0 iterator value for next call
+ */
+L4_CV long
+l4shmc_iterate_chunk(l4shmc_area_t *shmarea, const char **chunk_name,
+                     long offs);
+
+/**
  * \brief Attach to signal.
  * \ingroup api_l4shmc_signal
  *
@@ -468,7 +482,7 @@ l4shmc_chunk_ptr(l4shmc_chunk_t *chunk);
  * \param chunk Chunk.
  * \return 0 on success, <0 on error
  */
-L4_CV L4_INLINE l4_umword_t
+L4_CV L4_INLINE long
 l4shmc_chunk_size(l4shmc_chunk_t *chunk);
 
 /**
@@ -478,7 +492,7 @@ l4shmc_chunk_size(l4shmc_chunk_t *chunk);
  * \param chunk Chunk.
  * \return 0 on success, <0 on error
  */
-L4_CV L4_INLINE l4_umword_t
+L4_CV L4_INLINE long
 l4shmc_chunk_capacity(l4shmc_chunk_t *chunk);
 
 /**
@@ -522,6 +536,37 @@ l4shmc_check_magic(l4shmc_chunk_t *chunk);
 L4_CV L4_INLINE long
 l4shmc_area_size(l4shmc_area_t *shmarea);
 
+/**
+ * \brief Get free size of shared memory area. To get the max size to
+ * pass to l4shmc_add_chunk, substract l4shmc_chunk_overhead().
+ * \ingroup api_l4shm
+ *
+ * \param shmarea Shared memory area.
+ * \return <0 on error, otherwise: free capacity in the area.
+ *
+ */
+L4_CV long
+l4shmc_area_size_free(l4shmc_area_t *shmarea);
+
+/**
+ * \brief Get memory overhead per area that is not available for chunks
+ * \ingroup api_l4shm
+ *
+ * \return size of the overhead in bytes
+ */
+L4_CV long
+l4shmc_area_overhead(void);
+
+/**
+ * \brief Get memory overhead required in addition to the chunk capacity
+ * for adding one chunk
+ * \ingroup api_l4shm
+ *
+ * \return size of the overhead in bytes
+ */
+L4_CV long
+l4shmc_chunk_overhead(void);
+
 #include <l4/shmc/internal.h>
 
 __END_DECLS
diff --git a/src/l4/pkg/shmc/include/types.h b/src/l4/pkg/shmc/include/types.h
index f042b53..70150df 100644
--- a/src/l4/pkg/shmc/include/types.h
+++ b/src/l4/pkg/shmc/include/types.h
@@ -50,6 +50,7 @@ typedef struct {
   l4re_ds_t         _shm_ds;
   void             *_local_addr;
   char              _name[L4SHMC_NAME_STRINGLEN];
+  l4_umword_t       _size;
 } l4shmc_area_t;
 
 /* l4shmc_signal_t is local to one address space */
@@ -62,4 +63,5 @@ typedef struct {
   l4shmc_chunk_desc_t  *_chunk;
   l4shmc_area_t        *_shm;
   l4shmc_signal_t      *_sig;
+  l4_umword_t           _capacity;
 } l4shmc_chunk_t;
diff --git a/src/l4/pkg/shmc/lib/src/shmc.c b/src/l4/pkg/shmc/lib/src/shmc.c
index 82451e7..0ef7b87 100644
--- a/src/l4/pkg/shmc/lib/src/shmc.c
+++ b/src/l4/pkg/shmc/lib/src/shmc.c
@@ -36,6 +36,9 @@ enum {
   SHMAREA_LOCK_FREE, SHMAREA_LOCK_TAKEN,
 };
 
+enum {
+  MAX_SIZE = (~0UL) >> 1,
+};
 
 static inline l4shmc_chunk_desc_t *
 chunk_get(l4_addr_t o, void *shm_local_addr)
@@ -49,7 +52,10 @@ l4shmc_create(const char *shm_name, l4_umword_t shm_size)
   shared_mem_t *s;
   l4re_ds_t shm_ds = L4_INVALID_CAP;
   l4re_namespace_t shm_cap;
-  long r = -L4_ENOMEM;
+  long r;
+
+  if (shm_size > MAX_SIZE)
+    return -L4_ENOMEM;
 
   shm_cap = l4re_get_env_cap(shm_name);
   if (l4_is_invalid_cap(shm_cap))
@@ -66,6 +72,7 @@ l4shmc_create(const char *shm_name, l4_umword_t shm_size)
     goto out_shm_free_mem;
 
   s->_first_chunk = 0;
+  s->lock = SHMAREA_LOCK_FREE;
 
   r = l4re_ns_register_obj_srv(shm_cap, "shm", shm_ds, L4RE_NS_REGISTER_RW);
   l4re_rm_detach_unmap((l4_addr_t)s, L4RE_THIS_TASK_CAP);
@@ -90,6 +97,7 @@ l4shmc_attach_to(const char *shm_name, l4_umword_t timeout_ms,
 
   strncpy(shmarea->_name, shm_name, sizeof(shmarea->_name));
   shmarea->_name[sizeof(shmarea->_name) - 1] = 0;
+  shmarea->_local_addr = 0;
 
   if (l4_is_invalid_cap(shmarea->_shm_ds = l4re_util_cap_alloc()))
     return -L4_ENOMEM;
@@ -107,9 +115,15 @@ l4shmc_attach_to(const char *shm_name, l4_umword_t timeout_ms,
       goto out_free_cap;
     }
 
-  shmarea->_local_addr = 0;
-  if ((r = l4re_rm_attach(&shmarea->_local_addr,
-                          l4shmc_area_size(shmarea),
+  r = l4shmc_area_size(shmarea);
+  if (r < 0)
+    {
+      r = -L4_ENOMEM;
+      goto out_free_cap;
+    }
+  shmarea->_size = r;
+
+  if ((r = l4re_rm_attach(&shmarea->_local_addr, shmarea->_size,
                           L4RE_RM_SEARCH_ADDR, shmarea->_shm_ds,
                           0, L4_PAGESHIFT)))
     goto out_free_cap;
@@ -120,6 +134,58 @@ out_free_cap:
   return r;
 }
 
+L4_CV long
+l4shmc_area_overhead(void)
+{
+  return sizeof(shared_mem_t);
+}
+
+L4_CV long
+l4shmc_chunk_overhead(void)
+{
+  return sizeof(l4shmc_chunk_desc_t);
+}
+
+static long next_chunk(l4shmc_area_t *shmarea, l4_addr_t offs)
+{
+  shared_mem_t *shm_addr = (shared_mem_t *)shmarea->_local_addr;
+  volatile l4shmc_chunk_desc_t *p;
+  l4_addr_t next;
+
+  if (offs == 0)
+    {
+      next = shm_addr->_first_chunk;
+    }
+  else
+    {
+      p = chunk_get(offs, shmarea->_local_addr);
+      next = p->_next;
+    }
+  if (next == 0)
+    return 0;
+  if (next >= shmarea->_size || next + sizeof(*p) >= shmarea->_size || next <= offs)
+    return -L4_EIO;
+  if (next % sizeof(l4_addr_t) != 0)
+    return -L4_EINVAL;
+  p = chunk_get(next, shmarea->_local_addr);
+  if (p->_magic != L4SHMC_CHUNK_MAGIC)
+    return -L4_EIO;
+  return next;
+}
+
+L4_CV long
+l4shmc_iterate_chunk(l4shmc_area_t *shmarea, const char **chunk_name, long offs)
+{
+  if (offs < 0)
+    return -L4_EINVAL;
+  offs = next_chunk(shmarea, offs);
+  if (offs > 0)
+    {
+      l4shmc_chunk_desc_t *p = chunk_get(offs, shmarea->_local_addr);
+      *chunk_name =  p->_name;
+    }
+  return offs;
+}
 
 L4_CV long
 l4shmc_add_chunk(l4shmc_area_t *shmarea,
@@ -129,69 +195,91 @@ l4shmc_add_chunk(l4shmc_area_t *shmarea,
 {
   shared_mem_t *shm_addr = (shared_mem_t *)shmarea->_local_addr;
 
-  l4shmc_chunk_desc_t *p;
+  l4shmc_chunk_desc_t *p = NULL;
   l4shmc_chunk_desc_t *prev = NULL;
+  l4_addr_t offs = 0;
+  long ret;
 
-  shm_addr->lock = 0;
+  if (chunk_capacity >> (sizeof(chunk_capacity) * 8 - 1))
+    return -L4_ENOMEM;
 
   while (!l4util_cmpxchg(&shm_addr->lock, SHMAREA_LOCK_FREE,
                          SHMAREA_LOCK_TAKEN))
     l4_sleep(1);
   asm volatile ("" : : : "memory");
-  {
-    l4_addr_t offs;
-    long shm_sz;
-    if (shm_addr->_first_chunk)
-      {
-        offs = shm_addr->_first_chunk;
-        p = chunk_get(offs, shmarea->_local_addr);
-        do
-          {
-            offs = p->_offset + p->_capacity + sizeof(*p);
-            prev = p;
-            p = chunk_get(p->_next, shmarea->_local_addr);
-          }
-        while (prev->_next);
-      }
-    else
-      // first chunk starts right after shm-header
-      offs = sizeof(shared_mem_t);
-
-    if ((shm_sz = l4shmc_area_size(shmarea)) < 0)
-      goto out_free_lock;
-
-    if (offs + chunk_capacity + sizeof(*p) >= (unsigned long)shm_sz)
-      goto out_free_lock; // no more free memory in this shm
-
-    p = chunk_get(offs, shmarea->_local_addr);
-    p->_offset = offs;
-    p->_next = 0;
-    p->_capacity = chunk_capacity;
-    // Ensure that other CPUs have correct data before inserting chunk
-    __sync_synchronize();
-
-    if (prev)
-      prev->_next = offs;
-    else
-      shm_addr->_first_chunk = offs;
-  }
-  __sync_synchronize();
-  shm_addr->lock = SHMAREA_LOCK_FREE;
+  while ((ret = next_chunk(shmarea, offs)) > 0)
+    {
+      p = chunk_get(ret, shmarea->_local_addr);
+      if (strcmp(p->_name, chunk_name) == 0)
+        {
+          ret = -L4_EEXIST;
+          goto out_free_lock;
+        }
+      offs = ret;
+    }
+  if (ret < 0)
+     goto out_free_lock;
+  if (offs == 0)
+    offs = sizeof(shared_mem_t);
+  else
+    {
+      l4_addr_t n = p->_offset + p->_capacity + sizeof(*p);
+      if (n <= offs || n >= shmarea->_size)
+        {
+          ret = -L4_EIO;
+          goto out_free_lock;
+        }
+      offs = n;
+      prev = p;
+    }
 
+  if (offs + chunk_capacity + sizeof(*p) > (unsigned long)shmarea->_size)
+    {
+      ret = -L4_ENOMEM;
+      goto out_free_lock; // no more free memory in this shm
+    }
+  p = chunk_get(offs, shmarea->_local_addr);
+  p->_offset = offs;
+  p->_next = 0;
+  p->_capacity = chunk_capacity;
   p->_size = 0;
   p->_status = L4SHMC_CHUNK_CLEAR;
   p->_magic = L4SHMC_CHUNK_MAGIC;
   strncpy(p->_name, chunk_name, sizeof(p->_name));
   p->_name[sizeof(p->_name) - 1] = 0;
+  // Ensure that other CPUs have correct data before inserting chunk
+  l4shmc_membarrier();
+
+  if (prev)
+    prev->_next = offs;
+  else
+    shm_addr->_first_chunk = offs;
+
+  l4shmc_membarrier();
+  shm_addr->lock = SHMAREA_LOCK_FREE;
 
-  chunk->_chunk = p;
-  chunk->_shm    = shmarea;
-  chunk->_sig    = NULL;
+  chunk->_chunk    = p;
+  chunk->_shm      = shmarea;
+  chunk->_sig      = NULL;
+  chunk->_capacity = chunk_capacity;
 
   return L4_EOK;
 out_free_lock:
   shm_addr->lock = SHMAREA_LOCK_FREE;
-  return -L4_ENOMEM;
+  return ret;
+}
+
+L4_CV long
+l4shmc_area_size_free(l4shmc_area_t *shmarea)
+{
+  long ret;
+  l4_addr_t offs = 0;
+  while ((ret = next_chunk(shmarea, offs)) > 0)
+    offs = ret;
+  if (ret < 0)
+    return ret;
+  ret = shmarea->_size - offs;
+  return ret > 0 ? ret : 0;
 }
 
 L4_CV long
@@ -236,25 +324,30 @@ l4shmc_get_chunk_to(l4shmc_area_t *shmarea,
                     l4shmc_chunk_t *chunk)
 {
   l4_kernel_clock_t try_until = l4re_kip()->clock + (timeout_ms * 1000);
-  shared_mem_t *shm_addr = (shared_mem_t *)shmarea->_local_addr;
+  long ret;
 
   do
     {
-      l4_addr_t offs = shm_addr->_first_chunk;
-      while (offs)
+      l4_addr_t offs = 0;
+      while ((ret = next_chunk(shmarea, offs)) > 0)
         {
           l4shmc_chunk_desc_t *p;
+          offs = ret;
           p = chunk_get(offs, shmarea->_local_addr);
-
           if (!strcmp(p->_name, chunk_name))
             { // found it!
-               chunk->_shm    = shmarea;
-               chunk->_chunk = p;
-               chunk->_sig    = NULL;
+               chunk->_shm      = shmarea;
+               chunk->_chunk    = p;
+               chunk->_sig      = NULL;
+               chunk->_capacity = p->_capacity;
+               if (chunk->_capacity > shmarea->_size ||
+                   chunk->_capacity + offs > shmarea->_size)
+                  return -L4_EIO;
                return L4_EOK;
             }
-          offs = p->_next;
         }
+      if (ret < 0)
+        return ret;
 
       if (!timeout_ms)
         break;
