Won't get to upstream

--- a/src/core/init.c
+++ b/src/core/init.c
@@ -173,6 +173,9 @@
 #if ((LWIP_SOCKET || LWIP_NETCONN) && (NO_SYS==1))
   #error "If you want to use Sequential API, you have to define NO_SYS=0 in your lwipopts.h"
 #endif
+#if (LWIP_SOCKET_OPEN_COUNT && !MEMP_MEM_MALLOC)
+  #error "LWIP_SOCKET_OPEN_COUNT requires MEMP_MEM_MALLOC=1 in your lwipopts.h"
+#endif
 #if (LWIP_PPP_API && (NO_SYS==1))
   #error "If you want to use PPP API, you have to define NO_SYS=0 in your lwipopts.h"
 #endif
--- a/src/include/lwip/opt.h
+++ b/src/include/lwip/opt.h
@@ -1791,6 +1791,16 @@
 #endif
 
 /**
+ * LWIP_SOCKET_OPEN_COUNT==1: Number of sockets is not limited to MEMP_NUM_NETCONN.
+ * When enabled, sockets are allocated in the heap and the amount of sockets is
+ * only limited by the heap size. Handle with care regarding execution speed.
+ * To use this, MEMP_MEM_MALLOC also has to be enabled.
+ */
+#if !defined LWIP_SOCKET_OPEN_COUNT || defined __DOXYGEN__
+#define LWIP_SOCKET_OPEN_COUNT              0
+#endif
+
+/**
  * LWIP_TCP_KEEPALIVE==1: Enable TCP_KEEPIDLE, TCP_KEEPINTVL and TCP_KEEPCNT
  * options processing. Note that TCP_KEEPIDLE and TCP_KEEPINTVL have to be set
  * in seconds. (does not require sockets.c, and will affect tcp.c)
--- a/src/api/sockets.c
+++ b/src/api/sockets.c
@@ -208,6 +208,12 @@
 
 /** Contains all internal pointers and states used for a socket */
 struct lwip_sock {
+#if LWIP_SOCKET_OPEN_COUNT
+  /** Next element in the linked list */
+  struct lwip_sock *next;
+  /** Socket number*/
+  int count;
+#endif /* LWIP_SOCKET_OPEN_COUNT */
   /** sockets currently are built on netconns, each socket has one netconn */
   struct netconn *conn;
   /** data that was left from the previous read */
@@ -297,8 +303,13 @@
 static void lwip_socket_drop_registered_memberships(int s);
 #endif /* LWIP_IGMP */
 
+#if LWIP_SOCKET_OPEN_COUNT
+/** The global linked list of available sockets */
+static struct lwip_sock *sockets = NULL;
+#else /* LWIP_SOCKET_OPEN_COUNT */
 /** The global array of available sockets */
 static struct lwip_sock sockets[NUM_SOCKETS];
+#endif /* LWIP_SOCKET_OPEN_COUNT */
 /** The global list of tasks waiting for select */
 static struct lwip_select_cb *select_cb_list;
 /** This counter is increased from lwip_select when the list is changed
@@ -369,15 +380,29 @@
 
   s -= LWIP_SOCKET_OFFSET;
 
-  if ((s < 0) || (s >= NUM_SOCKETS)) {
+  if ((s < 0)
+#if !LWIP_SOCKET_OPEN_COUNT
+      || (s >= NUM_SOCKETS)
+#endif /* !LWIP_SOCKET_OPEN_COUNT */
+      ) {
     LWIP_DEBUGF(SOCKETS_DEBUG, ("get_socket(%d): invalid\n", s + LWIP_SOCKET_OFFSET));
     set_errno(EBADF);
     return NULL;
   }
 
+#if LWIP_SOCKET_OPEN_COUNT
+  SYS_ARCH_DECL_PROTECT(lev);
+  SYS_ARCH_PROTECT(lev);
+  for(sock = sockets; sock != NULL; sock = sock->next) {
+    if(sock->count == s)
+      break;
+  }
+  SYS_ARCH_UNPROTECT(lev);
+#else /* LWIP_SOCKET_OPEN_COUNT */
   sock = &sockets[s];
+#endif /* LWIP_SOCKET_OPEN_COUNT */
 
-  if (!sock->conn) {
+  if (!sock || !sock->conn) {
     LWIP_DEBUGF(SOCKETS_DEBUG, ("get_socket(%d): not active\n", s + LWIP_SOCKET_OFFSET));
     set_errno(EBADF);
     return NULL;
@@ -395,14 +420,33 @@
 static struct lwip_sock *
 tryget_socket(int s)
 {
+#if LWIP_SOCKET_OPEN_COUNT
+  struct lwip_sock *sock;
+#endif /* LWIP_SOCKET_OPEN_COUNT */
+
   s -= LWIP_SOCKET_OFFSET;
-  if ((s < 0) || (s >= NUM_SOCKETS)) {
+  if ((s < 0)
+#if !LWIP_SOCKET_OPEN_COUNT
+      || (s >= NUM_SOCKETS)
+#endif /* !LWIP_SOCKET_OPEN_COUNT */
+      ) {
     return NULL;
   }
+#if LWIP_SOCKET_OPEN_COUNT
+  SYS_ARCH_DECL_PROTECT(lev);
+  SYS_ARCH_PROTECT(lev);
+  for(sock = sockets; sock != NULL; sock = sock->next) {
+    if(sock->count == s)
+      break;
+  }
+  SYS_ARCH_UNPROTECT(lev);
+  return sock;
+#else /* LWIP_SOCKET_OPEN_COUNT */
   if (!sockets[s].conn) {
     return NULL;
   }
   return &sockets[s];
+#endif /* LWIP_SOCKET_OPEN_COUNT */
 }
 
 /**
@@ -417,30 +461,70 @@
 alloc_socket(struct netconn *newconn, int accepted)
 {
   int i;
+  struct lwip_sock *newsock = NULL;
+#if LWIP_SOCKET_OPEN_COUNT
+  struct lwip_sock **it;
+#endif /* LWIP_SOCKET_OPEN_COUNT */
+
   SYS_ARCH_DECL_PROTECT(lev);
 
+#if LWIP_SOCKET_OPEN_COUNT
+  newsock = (struct lwip_sock*)mem_malloc(sizeof(struct lwip_sock));
+  if(!newsock) {
+    return -1;
+  }
+  /* Protect socket list */
+  SYS_ARCH_PROTECT(lev);
+  it = &sockets;
+  i = LWIP_SOCKET_OFFSET;
+  while(*it) {
+    if((*it)->count != i) {
+      /* There's a gap in the list, fill it */
+      break;
+    }
+    i++;
+    it = &(*it)->next;
+  }
+  /* Add the new socket in the first gap found or in the end */
+  newsock->count = i;
+  newsock->next = (*it);
+  (*it) = newsock;
+  newsock->conn = newconn;
+  SYS_ARCH_UNPROTECT(lev);
+#else /* LWIP_SOCKET_OPEN_COUNT */
   /* allocate a new socket identifier */
   for (i = 0; i < NUM_SOCKETS; ++i) {
     /* Protect socket array */
     SYS_ARCH_PROTECT(lev);
     if (!sockets[i].conn && (sockets[i].select_waiting == 0)) {
-      sockets[i].conn       = newconn;
+      newsock = &sockets[i];
+      sockets[i].conn = newconn;
       /* The socket is not yet known to anyone, so no need to protect
          after having marked it as used. */
       SYS_ARCH_UNPROTECT(lev);
-      sockets[i].lastdata   = NULL;
-      sockets[i].lastoffset = 0;
-      sockets[i].rcvevent   = 0;
-      /* TCP sendbuf is empty, but the socket is not yet writable until connected
-       * (unless it has been created by accept()). */
-      sockets[i].sendevent  = (NETCONNTYPE_GROUP(newconn->type) == NETCONN_TCP ? (accepted != 0) : 1);
-      sockets[i].errevent   = 0;
-      sockets[i].err        = 0;
-      return i + LWIP_SOCKET_OFFSET;
+      break;
     }
     SYS_ARCH_UNPROTECT(lev);
   }
-  return -1;
+  if(!newsock) {
+    return -1;
+  }
+  i += LWIP_SOCKET_OFFSET;
+#endif /* LWIP_SOCKET_OPEN_COUNT */
+
+  LWIP_ASSERT("i >= 0", i >= 0);
+
+  newsock->lastdata   = NULL;
+  newsock->lastoffset = 0;
+  newsock->rcvevent   = 0;
+  /* TCP sendbuf is empty, but the socket is not yet writable until connected
+   * (unless it has been created by accept()). */
+  newsock->sendevent  = (NETCONNTYPE_GROUP(newconn->type) == NETCONN_TCP ? (accepted != 0) : 1);
+  newsock->errevent   = 0;
+  newsock->err        = 0;
+  newsock->select_waiting = 0;
+
+  return i;
 }
 
 /** Free a socket. The socket's netconn must have been
@@ -453,6 +537,9 @@
 free_socket(struct lwip_sock *sock, int is_tcp)
 {
   void *lastdata;
+#if LWIP_SOCKET_OPEN_COUNT
+  struct lwip_sock **it = &sockets;
+#endif /* LWIP_SOCKET_OPEN_COUNT */
 
   lastdata         = sock->lastdata;
   sock->lastdata   = NULL;
@@ -460,7 +547,15 @@
   sock->err        = 0;
 
   /* Protect socket array */
-  SYS_ARCH_SET(sock->conn, NULL);
+  SYS_ARCH_DECL_PROTECT(lev);
+  SYS_ARCH_PROTECT(lev);
+  sock->conn       = NULL;
+#if LWIP_SOCKET_OPEN_COUNT
+  while(*it != sock) it = &(*it)->next;
+  *it = (*it)->next;
+  mem_free(sock);
+#endif /* LWIP_SOCKET_OPEN_COUNT */
+  SYS_ARCH_UNPROTECT(lev);
   /* don't use 'sock' after this line, as another task might have allocated it */
 
   if (lastdata != NULL) {
@@ -522,7 +617,9 @@
     sock_set_errno(sock, ENFILE);
     return -1;
   }
+#if !LWIP_SOCKET_OPEN_COUNT
   LWIP_ASSERT("invalid socket index", (newsock >= LWIP_SOCKET_OFFSET) && (newsock < NUM_SOCKETS + LWIP_SOCKET_OFFSET));
+#endif /* !LWIP_SOCKET_OPEN_COUNT */
   LWIP_ASSERT("newconn->callback == event_callback", newconn->callback == event_callback);
   nsock = &sockets[newsock - LWIP_SOCKET_OFFSET];
 
--- a/port/include/lwipopts.h
+++ b/port/include/lwipopts.h
@@ -26,6 +26,9 @@
 /* Don't rename Sockets API functions */
 #define LWIP_COMPAT_SOCKETS   0
 
+/* Don't limit the number of sockets */
+#define LWIP_SOCKET_OPEN_COUNT  1
+
 /* We're using lwip_poll() */
 #define LWIP_POLL               1
 
