diff --git a/src/l4/pkg/shmc/include/internal.h b/src/l4/pkg/shmc/include/internal.h
index c4cb4bf..7c9758c 100644
--- a/src/l4/pkg/shmc/include/internal.h
+++ b/src/l4/pkg/shmc/include/internal.h
@@ -91,7 +91,7 @@ L4_CV L4_INLINE long
 l4shmc_chunk_ready(l4shmc_chunk_t *chunk, l4_umword_t size)
 {
   chunk->_chunk->_size = size;
-  asm volatile("" : : : "memory");
+  __sync_synchronize();
   chunk->_chunk->_status = L4SHMC_CHUNK_READY;
   return L4_EOK;
 }
@@ -128,16 +128,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 +155,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..dbee89d
--- /dev/null
+++ b/src/l4/pkg/shmc/include/shmbuf.h
@@ -0,0 +1,638 @@
+/*
+ * 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>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* sizeof(struct pkt_head) must be power of two */
+struct pkt_head {
+    unsigned long size;
+};
+
+struct shm_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 pkt_head pkg[0];
+};
+
+#if 0
+#define debug_printf(...) printf(__VA_ARGS__)
+#else
+#define debug_printf(...)
+#endif
+
+/**
+ * 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.
+ */
+static inline unsigned long shmchunk_tx_free(struct shm_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 pkt_head))
+                return 0;
+        return space - 2 * sizeof(struct pkt_head);
+}
+
+/** align v to power of 2 boundary */
+#define SHMC_ALIGN(v, boundary)                                 \
+    (((unsigned long)(v) + ((unsigned long)(boundary)-1))       \
+        & ~((unsigned long)(boundary) - 1))
+
+#define SHMC_ALIGN_PTR_PH(v)                                    \
+    ((struct pkt_head *)SHMC_ALIGN(v, sizeof(struct pkt_head)))
+
+#define SHMC_ALIGN_OFF_PH(v)    SHMC_ALIGN(v, sizeof(struct 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 shm_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.
+ */
+static inline int shmchunk_init(struct shm_chunk_head *chunk,
+                                unsigned long chunksize)
+{
+        if (chunk->pkg != SHMC_ALIGN_PTR_PH(chunk->pkg))
+            return -L4_EINVAL;
+        chunksize -= sizeof(struct shm_chunk_head);
+        if (chunksize != SHMC_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 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 shm_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.
+ */
+static inline int shmchunk_tx(struct shm_chunk_head *ch,
+                              unsigned long chunksize,
+                              const char *buf, unsigned long pkt_size)
+{
+    unsigned long offset, nextoffset, r, part_len;
+    volatile struct pkt_head *ph, *next_ph;
+    int blocked = 0;
+    if (pkt_size == 0)
+        return 0;
+    if (pkt_size > chunksize - sizeof(struct pkt_head))
+        return -L4_ENOMEM;
+
+retry:
+    __sync_synchronize();
+    offset = ch->next_offs_to_write;
+    if (offset >= chunksize || offset != SHMC_ALIGN_OFF_PH(offset))
+        return -L4_EIO;
+    ph = ch->pkg + (offset / sizeof(struct pkt_head));
+
+    nextoffset = SHMC_ALIGN_OFF_PH(offset + pkt_size + sizeof(struct 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 pkt_head.
+     */
+    if (nextoffset + sizeof(struct 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;
+
+    nextoffset %= chunksize;
+    /* For L4Linux compatibility */
+    next_ph = ch->pkg + (nextoffset / sizeof(struct pkt_head));
+    next_ph->size = 0;
+
+    offset += sizeof(struct pkt_head);
+    offset %= chunksize;
+
+    if (offset + pkt_size > chunksize)
+        part_len = chunksize - offset;
+    else
+        part_len = pkt_size;
+
+    memcpy(((unsigned char *)ch->pkg)+offset, buf, part_len);
+    if (part_len != pkt_size) {
+        memcpy((void*)ch->pkg, buf + part_len, pkt_size - part_len);
+    }
+
+    __sync_synchronize();
+    ph->size = pkt_size;
+    ch->next_offs_to_write = nextoffset;
+
+    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 shmchunk_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 shm_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.
+ */
+static inline int shmchunk_tx_part(struct shm_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 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 pkt_head))
+        return -L4_ENOMEM;
+
+retry:
+    __sync_synchronize();
+    woffset = ch->next_offs_to_write;
+    if (woffset >= chunksize || woffset != SHMC_ALIGN_OFF_PH(woffset))
+        return -L4_EIO;
+    ph = ch->pkg + (woffset / sizeof(struct pkt_head));
+
+    nextoffset = SHMC_ALIGN_OFF_PH(woffset + totallen
+                                   + sizeof(struct 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 pkt_head.
+     */
+    if (nextoffset + sizeof(struct 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 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 shmchunk_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 shm_chunk_head structure.
+ * @param pkglen The total length of the packet.
+ * @return Zero in case of success or a negative error code.
+ */
+static inline int shmchunk_tx_complete(struct shm_chunk_head *ch,
+                                       unsigned long chunksize, size_t pkglen)
+{
+    unsigned long offset, nextoffset, r;
+    volatile struct pkt_head *ph, *next_ph;
+
+    if (pkglen == 0)
+        return 0;
+    if (pkglen > chunksize - 2*sizeof(struct pkt_head))
+        return -L4_ENOMEM;
+
+    offset = ch->next_offs_to_write;
+    if (offset >= chunksize || offset != SHMC_ALIGN_OFF_PH(offset))
+        return -L4_EIO;
+    ph = ch->pkg + (offset / sizeof(struct pkt_head));
+
+    nextoffset = SHMC_ALIGN_OFF_PH(offset + pkglen + sizeof(struct 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 pkt_head.
+     */
+    if (nextoffset + sizeof(struct pkt_head) > r)
+        return  -L4_EIO;
+
+    nextoffset %= chunksize;
+    /* For L4Linux compatibility */
+    next_ph = ch->pkg + (nextoffset / sizeof(struct pkt_head));
+    next_ph->size = 0;
+
+    __sync_synchronize();
+
+    ph->size = pkglen;
+    ch->next_offs_to_write = nextoffset;
+    return 0;
+}
+
+/**
+ * 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 shm_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.
+ */
+static inline int shmchunk_rx_len(struct shm_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 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 pkt_head))
+        return -L4_EIO;
+    ph = ch->pkg + (offset / sizeof(struct pkt_head));
+    pkt_size = ph->size;
+    if (pkt_size > (unsigned long)space - sizeof(struct 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 shm_chunk_head structure.
+ * @return Zero if the packet could be dropped, a negative value in case
+ *     of an error.
+ */
+static inline int shmchunk_rx_drop(struct shm_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 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 pkt_head))
+        return -L4_EIO;
+    ph = ch->pkg + (offset / sizeof(struct pkt_head));
+    pkt_size = ph->size;
+    if (pkt_size > (unsigned long)space - sizeof(struct pkt_head))
+        return -L4_EIO;
+    offset = SHMC_ALIGN_OFF_PH(offset + sizeof(struct pkt_head) + pkt_size);
+    offset %= chunksize;
+    ch->next_offs_to_read = offset;
+    __sync_synchronize();
+
+    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 shm_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.
+ */
+static inline int shmchunk_rx_part(const struct shm_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 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 pkt_head))
+        return -L4_EIO;
+    ph = ch->pkg + (roffset / sizeof(struct pkt_head));
+    pkt_size = ph->size;
+    if (pkt_size > (unsigned long)space - sizeof(struct pkt_head))
+        return -L4_EIO;
+    /* L4Linux 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 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 shm_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.
+ */
+static inline int shmchunk_rx(struct shm_chunk_head *ch,
+                              unsigned long chunksize,
+                              char *buf, unsigned long buf_size)
+{
+    unsigned long offset = ch->next_offs_to_read;
+    unsigned long woffset = ch->next_offs_to_write;
+    long space = woffset - offset;
+    volatile struct pkt_head *ph;
+    unsigned long part_len, pkt_size;
+
+    /* It is not sufficient that we check ph->size later on, we must check that
+     * (*ph) actually contains valid data.
+     */
+    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 pkt_head))
+        return -L4_EIO;
+    ph = ch->pkg + (offset / sizeof(struct pkt_head));
+    pkt_size = ph->size;
+    if (pkt_size > (unsigned long)space)
+        return -L4_EIO;
+    /* L4Linux compatibility (pkt_size == 0 means no more packets) */
+    if (pkt_size == 0)
+        return 0;
+    if (buf_size < pkt_size)
+        return -L4_ENOMEM;
+    offset += sizeof(struct pkt_head);
+    offset %= chunksize;
+
+    if (offset + pkt_size > chunksize)
+        part_len = chunksize - offset;
+    else
+        part_len = pkt_size;
+    memcpy(buf, ((unsigned char *)ch->pkg)+offset, part_len);
+    if (part_len != pkt_size)
+        memcpy(buf + part_len, (unsigned char *)ch->pkg, pkt_size - part_len);
+
+    offset = SHMC_ALIGN_OFF_PH(offset + pkt_size);
+    offset %= chunksize;
+    ch->next_offs_to_read = offset;
+
+    __sync_synchronize();
+    return pkt_size;
+}
+
+
+/*
+ * Various wrappers for shmchunk_* functions using a single shmbuf struct
+ */
+
+struct shmbuf {
+    struct shm_chunk_head *tx_head;
+    struct shm_chunk_head *rx_head;
+    unsigned long tx_ring_size;
+    unsigned long rx_ring_size;
+};
+
+/**
+ * Initialize an shmbuf structure with pre-allocated Rx/Tx rings
+ * @param sb A pre-allocated shmbuf structure to  initialize.
+ * @param rx_chunk The receive ring for this thread.
+ * @param rx_size The size of the receive ring including the shm_chunk_head.
+ * @param tx_chunk The transmit ring for this thread.
+ * @param tx_size The size of the transmit ring including the shm_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 shmbuf_init()
+ * twice, once with rx_chunk == NULL and once with tx_chunk == NULL.
+ */
+static inline int shmbuf_init(struct shmbuf *sb, char *rx_chunk, unsigned long rx_size,
+                char *tx_chunk, unsigned long tx_size)
+{
+    if (tx_chunk) {
+         debug_printf("shmbuf_init: tx_chunk: %lu\n", tx_size);
+        if (shmchunk_init((struct shm_chunk_head *)tx_chunk, tx_size)) {
+            debug_printf("shmbuf_init: tx_chunk not aligned\n");
+            return -L4_EINVAL;
+        }
+        sb->tx_head = (struct shm_chunk_head *)tx_chunk;
+        sb->tx_ring_size = tx_size - sizeof(struct shm_chunk_head);
+    } else {
+        sb->tx_head = NULL;
+    }
+
+    if (rx_chunk) {
+         debug_printf("shmbuf_init: rx_chunk: %lu\n", rx_size);
+        if (shmchunk_init((struct shm_chunk_head *)rx_chunk, rx_size)) {
+            debug_printf("shmbuf_init: rx_chunk not aligned\n");
+            return -L4_EINVAL;
+        }
+        sb->rx_head = (struct shm_chunk_head *)rx_chunk;
+        sb->rx_ring_size = rx_size - sizeof(struct shm_chunk_head);
+    } else if (!tx_chunk) {
+        debug_printf("shmbuf_init: ERROR: tx_chunk == rx_chunk == NULL\n");
+        return -L4_EINVAL;
+    } else {
+        sb->rx_head = NULL;
+    }
+
+    return 0;
+}
+
+static inline int shmbuf_rx_len(struct shmbuf *sb)
+{
+    return shmchunk_rx_len(sb->rx_head, sb->rx_ring_size);
+}
+
+static inline int shmbuf_rx_drop(struct shmbuf *sb)
+{
+    return shmchunk_rx_drop(sb->rx_head, sb->rx_ring_size);
+}
+
+static inline int shmbuf_rx_part(struct shmbuf *sb, unsigned long poffset,
+                                 unsigned long len, char *buf)
+{
+    return shmchunk_rx_part(sb->rx_head, sb->rx_ring_size, poffset, len, buf);
+}
+
+static inline unsigned long shmbuf_tx_free(struct shmbuf *sb)
+{
+    return shmchunk_tx_free(sb->tx_head, sb->tx_ring_size);
+}
+
+static inline int shmbuf_tx(struct shmbuf *sb, const char *buf,
+                              unsigned long pkt_size)
+{
+    return shmchunk_tx(sb->tx_head, sb->tx_ring_size, buf, pkt_size);
+}
+
+static inline int shmbuf_rx(struct shmbuf *sb, char *buf,
+                              unsigned long buf_size)
+{
+    return shmchunk_rx(sb->rx_head, sb->rx_ring_size, buf, buf_size);
+}
+
+
+static inline int shmbuf_tx_part(struct shmbuf *sb, const char *buf,
+                                 unsigned long poffset, unsigned long len)
+{
+    return shmchunk_tx_part(sb->tx_head, sb->tx_ring_size, buf, poffset, len);
+}
+
+static inline int shmbuf_tx_complete(struct shmbuf *sb, size_t pktlen)
+{
+    return shmchunk_tx_complete(sb->tx_head, sb->tx_ring_size, pktlen);
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#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..0dcb807 100644
--- a/src/l4/pkg/shmc/include/types.h
+++ b/src/l4/pkg/shmc/include/types.h
@@ -33,14 +33,17 @@ enum {
 
 /* l4shmc_chunk_desc_t is shared among address spaces */
 /* private: This data structure is hidden for the clients */
+/* we don't make the whole struct volatile to avoid compiler warnings when
+ * using _name
+ */
 typedef struct {
-  l4_umword_t _magic;        // magic
-  l4_addr_t _offset;         // offset of chunk in shm-area
-  l4_umword_t _capacity;     // capacity in bytes of chunk
-  l4_umword_t _size;         // size of current payload
-  l4_umword_t _status;       // status of chunk
+  volatile l4_umword_t _magic;        // magic
+  volatile l4_addr_t _offset;         // offset of chunk in shm-area
+  volatile l4_umword_t _capacity;     // capacity in bytes of chunk
+  volatile l4_umword_t _size;         // size of current payload
+  volatile l4_umword_t _status;       // status of chunk
   char _name[L4SHMC_CHUNK_NAME_STRINGLEN]; // name of chunk
-  l4_addr_t _next;           // next chunk in shm-area, as absolute offset
+  volatile l4_addr_t _next;           // next chunk in shm-area, as absolute offset
   char payload[];
 } l4shmc_chunk_desc_t;
 
@@ -50,6 +53,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 +66,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 db713e5..5496fc7 100644
--- a/src/l4/pkg/shmc/lib/src/shmc.c
+++ b/src/l4/pkg/shmc/lib/src/shmc.c
@@ -36,6 +36,7 @@ enum {
   SHMAREA_LOCK_FREE, SHMAREA_LOCK_TAKEN,
 };
 
+#define MAX_SIZE  ((~0UL) >> 1)
 
 static inline l4shmc_chunk_desc_t *
 chunk_get(l4_addr_t o, void *shm_local_addr)
@@ -49,7 +50,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 +70,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 +95,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 +113,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 +132,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;
+  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 +193,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
+  __sync_synchronize();
+
+  if (prev)
+    prev->_next = offs;
+  else
+    shm_addr->_first_chunk = offs;
+
+  __sync_synchronize();
+  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
@@ -216,13 +302,11 @@ l4shmc_add_signal(l4shmc_area_t *shmarea,
   b[sizeof(b) - 1] = 0;
 
   tmp = l4re_get_env_cap(shmarea->_name);
+  r = -L4_ENOENT;
   if (l4_is_invalid_cap(tmp))
-    {
-      r = -L4_ENOENT;
-      goto out_free_sigcap;
-    }
+    goto out_free_sigcap;
 
-  if ((r = l4re_ns_register_obj_srv(tmp, b, signal->_sigcap, 0)) != L4_EOK)
+  if (l4re_ns_register_obj_srv(tmp, b, signal->_sigcap, 0))
     goto out_free_sigcap;
 
   return L4_EOK;
@@ -238,25 +322,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;
