diff --git a/Makefile.dep b/Makefile.dep
index 8f1cf4a16005d64531a869321332e21f593ca94d..5519a2da325af92249944a91cf76f5ad83bfb23a 100644
--- a/Makefile.dep
+++ b/Makefile.dep
@@ -411,6 +411,7 @@ endif
 
 ifneq (,$(filter lwip,$(USEMODULE)))
   USEPKG += lwip
+  USEMODULE += core_mbox
   USEMODULE += lwip_api
   USEMODULE += lwip_contrib
   USEMODULE += lwip_core
diff --git a/pkg/lwip/contrib/sys_arch.c b/pkg/lwip/contrib/sys_arch.c
index 767e74d7a2fdaf3fd143ffc0b54125788383b278..153ed23a4f749bb70d4d06c78aa8c88bcc1194e5 100644
--- a/pkg/lwip/contrib/sys_arch.c
+++ b/pkg/lwip/contrib/sys_arch.c
@@ -28,6 +28,9 @@
 #include "thread.h"
 #include "xtimer.h"
 
+#define _MSG_SUCCESS    (0x5cac)
+#define _MSG_TIMEOUT    (0x5cad)
+
 void sys_init(void)
 {
     return;
@@ -95,110 +98,80 @@ u32_t sys_arch_sem_wait(sys_sem_t *sem, u32_t count)
 err_t sys_mbox_new(sys_mbox_t *mbox, int size)
 {
     (void)size;
-    mbox->waiting = 0;
-    cib_init(&mbox->cib, SYS_MBOX_SIZE);
-    mutex_init(&mbox->mutex);
-    if (sema_create(&mbox->not_empty, 0) < 0) {
-        return ERR_VAL;
-    }
-    if (sema_create(&mbox->not_full, 0) < 0) {
-        return ERR_VAL;
-    }
+    mbox_init(&mbox->mbox, mbox->msgs, SYS_MBOX_SIZE);
     return ERR_OK;
 }
 
 void sys_mbox_free(sys_mbox_t *mbox)
 {
-    sema_destroy(&mbox->not_empty);
-    sema_destroy(&mbox->not_full);
+    (void)mbox;
+    return;
 }
 
 void sys_mbox_post(sys_mbox_t *mbox, void *msg)
 {
-    int idx;
+    msg_t m = { .content = { .ptr = msg }, .type = _MSG_SUCCESS };
 
     LWIP_ASSERT("invalid mbox", sys_mbox_valid(mbox));
-    mutex_lock(&mbox->mutex);
-    while ((idx = cib_put(&mbox->cib)) < 0) {
-        mbox->waiting++;
-        mutex_unlock(&mbox->mutex);
-        sema_wait_timed(&mbox->not_full, 0);
-        mutex_lock(&mbox->mutex);
-        mbox->waiting--;
-    }
-    mbox->msgs[idx] = msg;
-    if (cib_avail(&mbox->cib) == 1) {
-        sema_post(&mbox->not_empty);
-    }
-    mutex_unlock(&mbox->mutex);
+    mbox_put(&mbox->mbox, &m);
 }
 
 err_t sys_mbox_trypost(sys_mbox_t *mbox, void *msg)
 {
-    int idx;
+    msg_t m = { .content = { .ptr = msg }, .type = _MSG_SUCCESS };
 
-    LWIP_ASSERT("invalid mbox", sys_mbox_valid(mbox));
-    mutex_lock(&mbox->mutex);
-    if ((idx = cib_put(&mbox->cib)) < 0) {
-        mutex_unlock(&mbox->mutex);
-        return ERR_MEM;
+    if (mbox_try_put(&mbox->mbox, &m)) {
+        return ERR_OK;
     }
-    mbox->msgs[idx] = msg;
-    if (cib_avail(&mbox->cib) == 1) {
-        sema_post(&mbox->not_empty);
+    else {
+        return ERR_MEM;
     }
-    mutex_unlock(&mbox->mutex);
-    return ERR_OK;
+}
+
+static void _mbox_timeout(void *arg)
+{
+    msg_t m = { .type = _MSG_TIMEOUT };
+    mbox_put(arg, &m);
 }
 
 u32_t sys_arch_mbox_fetch(sys_mbox_t *mbox, void **msg, u32_t timeout)
 {
-    u32_t time_needed = 0;
-    unsigned int idx;
+    msg_t m;
+    xtimer_t timer = { .callback = _mbox_timeout, .arg = &mbox->mbox };
+    uint64_t start, stop;
 
-    LWIP_ASSERT("invalid mbox", sys_mbox_valid(mbox));
-    mutex_lock(&mbox->mutex);
-    while (cib_avail(&mbox->cib) == 0) {
-        sys_sem_t *not_empty = (sys_sem_t *)(&mbox->not_empty);
-        mutex_unlock(&mbox->mutex);
-        if (timeout != 0) {
-            time_needed = sys_arch_sem_wait(not_empty, timeout);
-            if (time_needed == SYS_ARCH_TIMEOUT) {
-                return SYS_ARCH_TIMEOUT;
-            }
-        }
-        else {
-            sys_arch_sem_wait(not_empty, 0);
-        }
-        mutex_lock(&mbox->mutex);
-    }
-    idx = cib_get(&mbox->cib);
-    if (msg != NULL) {
-        *msg = mbox->msgs[idx];
+    start = xtimer_now64();
+    if (timeout > 0) {
+        uint64_t u_timeout = (timeout * MS_IN_USEC);
+        _xtimer_set64(&timer, (uint32_t)u_timeout, (uint32_t)(u_timeout >> 32));
     }
-    if (mbox->waiting) {
-        sema_post(&mbox->not_full);
+    mbox_get(&mbox->mbox, &m);
+    stop = xtimer_now64();
+    switch (m.type) {
+        case _MSG_SUCCESS:
+            *msg = m.content.ptr;
+            return (u32_t)((stop - start) / MS_IN_USEC);
+        case _MSG_TIMEOUT:
+            break;
+        default:    /* should not happen */
+            LWIP_ASSERT("invalid message received", false);
+            break;
     }
-    mutex_unlock(&mbox->mutex);
-    return time_needed;
+    return SYS_ARCH_TIMEOUT;
 }
 
 u32_t sys_arch_mbox_tryfetch(sys_mbox_t *mbox, void **msg)
 {
-    int idx;
+    msg_t m;
 
-    LWIP_ASSERT("invalid mbox", sys_mbox_valid(mbox));
-    mutex_lock(&mbox->mutex);
-    if (cib_avail(&mbox->cib) == 0) {
-        mutex_unlock(&mbox->mutex);
-        return SYS_MBOX_EMPTY;
+    if (mbox_try_get(&mbox->mbox, &m)) {
+        LWIP_ASSERT("invalid message received", (m.type == _MSG_SUCCESS));
+        *msg = m.content.ptr;
+        return ERR_OK;
     }
-    idx = cib_get(&mbox->cib);
-    if (msg != NULL) {
-        *msg = mbox->msgs[idx];
+    else {
+        return SYS_MBOX_EMPTY;
     }
-    mutex_unlock(&mbox->mutex);
-    return 0;
 }
 
 sys_thread_t sys_thread_new(const char *name, lwip_thread_fn thread, void *arg,
diff --git a/pkg/lwip/include/arch/sys_arch.h b/pkg/lwip/include/arch/sys_arch.h
index 1b02458e2cfacec57e904b44a84fe15e89e7c98c..27c6f8192d349a197da415bc4a022b599fe1a7d9 100644
--- a/pkg/lwip/include/arch/sys_arch.h
+++ b/pkg/lwip/include/arch/sys_arch.h
@@ -25,6 +25,7 @@
 
 #include "cib.h"
 #include "kernel_types.h"
+#include "mbox.h"
 #include "mutex.h"
 #include "random.h"
 #include "sema.h"
@@ -38,12 +39,8 @@ extern "C" {
 #define SYS_MBOX_SIZE       (8)
 
 typedef struct {
-    cib_t cib;
-    void *msgs[SYS_MBOX_SIZE];
-    mutex_t mutex;
-    sema_t not_empty;
-    sema_t not_full;
-    volatile int waiting;
+    mbox_t mbox;
+    msg_t msgs[SYS_MBOX_SIZE];
 } sys_mbox_t;
 
 typedef mutex_t sys_mutex_t;
@@ -62,13 +59,13 @@ static inline bool sys_sem_valid(sys_sem_t *sem)
 
 static inline bool sys_mbox_valid(sys_mbox_t *mbox)
 {
-    return (mbox != NULL) && (mbox->cib.mask != 0);
+    return (mbox != NULL) && (mbox->mbox.cib.mask != 0);
 }
 
 static inline void sys_mbox_set_invalid(sys_mbox_t *mbox)
 {
     if (mbox != NULL) {
-        mbox->cib.mask = 0;
+        mbox->mbox.cib.mask = 0;
     }
 }