added function tcp_listen_with_backlog_and_err() to get the error reason when listening fails (bug #49861)
diff --git a/CHANGELOG b/CHANGELOG
index 4371f02..051f7ae 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -6,8 +6,12 @@
  
   ++ New features:
 
+  2016-12-31: Simon Goldschmidt
+  * tcp.h/.c: added function tcp_listen_with_backlog_and_err() to get the error
+    reason when listening fails (bug #49861)
+
   2016-12-14: Jan Breuer:
-  opt.h, ndc.h/.c: add support for RDNSS option (as per RFC 6106)
+  * opt.h, ndc.h/.c: add support for RDNSS option (as per RFC 6106)
 
   2016-12-14: David van Moolenbroek
   * opt.h, nd6.c: Added LWIP_HOOK_ND6_GET_GW()
diff --git a/src/api/api_msg.c b/src/api/api_msg.c
index 1009228..4927ee5 100644
--- a/src/api/api_msg.c
+++ b/src/api/api_msg.c
@@ -1307,6 +1307,13 @@
             /* connection is not closed, cannot listen */
             msg->err = ERR_VAL;
           } else {
+            err_t err;
+            u8_t backlog;
+#if TCP_LISTEN_BACKLOG
+            backlog = msg->msg.lb.backlog;
+#else  /* TCP_LISTEN_BACKLOG */
+            backlog = TCP_DEFAULT_LISTEN_BACKLOG;
+#endif /* TCP_LISTEN_BACKLOG */
 #if LWIP_IPV4 && LWIP_IPV6
             /* "Socket API like" dual-stack support: If IP to listen to is IP6_ADDR_ANY,
              * and NETCONN_FLAG_IPV6_V6ONLY is NOT set, use IP_ANY_TYPE to listen
@@ -1319,15 +1326,11 @@
             }
 #endif /* LWIP_IPV4 && LWIP_IPV6 */
 
-#if TCP_LISTEN_BACKLOG
-            lpcb = tcp_listen_with_backlog(msg->conn->pcb.tcp, msg->msg.lb.backlog);
-#else  /* TCP_LISTEN_BACKLOG */
-            lpcb = tcp_listen(msg->conn->pcb.tcp);
-#endif /* TCP_LISTEN_BACKLOG */
+            lpcb = tcp_listen_with_backlog_and_err(msg->conn->pcb.tcp, backlog, &err);
 
             if (lpcb == NULL) {
               /* in this case, the old pcb is still allocated */
-              msg->err = ERR_MEM;
+              msg->err = err;
             } else {
               /* delete the recvmbox and allocate the acceptmbox */
               if (sys_mbox_valid(&msg->conn->recvmbox)) {
diff --git a/src/core/tcp.c b/src/core/tcp.c
index f72597b..63e4445 100644
--- a/src/core/tcp.c
+++ b/src/core/tcp.c
@@ -636,19 +636,44 @@
  *
  * @note The original tcp_pcb is freed. This function therefore has to be
  *       called like this:
- *             tpcb = tcp_listen(tpcb);
+ *             tpcb = tcp_listen_with_backlog(tpcb, backlog);
  */
 struct tcp_pcb *
 tcp_listen_with_backlog(struct tcp_pcb *pcb, u8_t backlog)
 {
-  struct tcp_pcb_listen *lpcb;
+  return tcp_listen_with_backlog_and_err(pcb, backlog, NULL);
+}
+
+/**
+ * @ingroup tcp_raw
+ * Set the state of the connection to be LISTEN, which means that it
+ * is able to accept incoming connections. The protocol control block
+ * is reallocated in order to consume less memory. Setting the
+ * connection to LISTEN is an irreversible process.
+ *
+ * @param pcb the original tcp_pcb
+ * @param backlog the incoming connections queue limit
+ * @param err when NULL is returned, this contains the error reason
+ * @return tcp_pcb used for listening, consumes less memory.
+ *
+ * @note The original tcp_pcb is freed. This function therefore has to be
+ *       called like this:
+ *             tpcb = tcp_listen_with_backlog_and_err(tpcb, backlog, &err);
+ */
+struct tcp_pcb *
+tcp_listen_with_backlog_and_err(struct tcp_pcb *pcb, u8_t backlog, err_t *err)
+{
+  struct tcp_pcb_listen *lpcb = NULL;
+  err_t res;
 
   LWIP_UNUSED_ARG(backlog);
-  LWIP_ERROR("tcp_listen: pcb already connected", pcb->state == CLOSED, return NULL);
+  LWIP_ERROR("tcp_listen: pcb already connected", pcb->state == CLOSED, res = ERR_CLSD; goto done);
 
   /* already listening? */
   if (pcb->state == LISTEN) {
-    return pcb;
+    lpcb = (struct tcp_pcb_listen*)pcb;
+    res = ERR_ALREADY;
+    goto done;
   }
 #if SO_REUSE
   if (ip_get_option(pcb, SOF_REUSEADDR)) {
@@ -659,14 +684,16 @@
       if ((lpcb->local_port == pcb->local_port) &&
           ip_addr_cmp(&lpcb->local_ip, &pcb->local_ip)) {
         /* this address/port is already used */
-        return NULL;
+        res = ERR_USE;
+        goto done;
       }
     }
   }
 #endif /* SO_REUSE */
   lpcb = (struct tcp_pcb_listen *)memp_malloc(MEMP_TCP_PCB_LISTEN);
   if (lpcb == NULL) {
-    return NULL;
+    res = ERR_MEM;
+    goto done;
   }
   lpcb->callback_arg = pcb->callback_arg;
   lpcb->local_port = pcb->local_port;
@@ -691,6 +718,11 @@
   tcp_backlog_set(lpcb, backlog);
 #endif /* TCP_LISTEN_BACKLOG */
   TCP_REG(&tcp_listen_pcbs.pcbs, (struct tcp_pcb *)lpcb);
+  res = ERR_OK;
+done:
+  if (err != NULL) {
+    *err = res;
+  }
   return (struct tcp_pcb *)lpcb;
 }
 
diff --git a/src/include/lwip/tcp.h b/src/include/lwip/tcp.h
index 35584b4..3fd4467 100644
--- a/src/include/lwip/tcp.h
+++ b/src/include/lwip/tcp.h
@@ -387,6 +387,7 @@
 err_t            tcp_connect (struct tcp_pcb *pcb, const ip_addr_t *ipaddr,
                               u16_t port, tcp_connected_fn connected);
 
+struct tcp_pcb * tcp_listen_with_backlog_and_err(struct tcp_pcb *pcb, u8_t backlog, err_t *err);
 struct tcp_pcb * tcp_listen_with_backlog(struct tcp_pcb *pcb, u8_t backlog);
 /** @ingroup tcp_raw */
 #define          tcp_listen(pcb) tcp_listen_with_backlog(pcb, TCP_DEFAULT_LISTEN_BACKLOG)