diff --git a/net/icmpv6/Kconfig b/net/icmpv6/Kconfig index 248f0224f0..471204b981 100644 --- a/net/icmpv6/Kconfig +++ b/net/icmpv6/Kconfig @@ -200,9 +200,46 @@ endif # NET_ICMPv6_ROUTER if NET_ICMPv6_SOCKET -config NET_ICMPv6_NCONNS - int "Max ICMPv6 packet sockets" +config NET_ICMPv6_PREALLOC_CONNS + int "Preallocated ICMPv6 packet sockets" default 4 + ---help--- + Number of ICMPv6 connections (all tasks). + + This number of connections will be pre-allocated during system boot. + If dynamic connections allocation is enabled, more connections may + be allocated at a later time, as the system needs them. Else this + will be the maximum number of connections available to the system + at all times. + + Set to 0 to disable (and rely only on dynamic allocations). + +config NET_ICMPv6_ALLOC_CONNS + int "Dynamic ICMPv6 connections allocation" + default 0 + ---help--- + Dynamic memory allocations for ICMPv6. + + When set to 0 all dynamic allocations are disabled. + + When set to 1 a new connection will be allocated every time, + and it will be free'd when no longer needed. + + Setting this to 2 or more will allocate the connections in + batches (with batch size equal to this config). When a + connection is no longer needed, it will be returned to the + free connections pool, and it will never be deallocated! + +config NET_ICMPv6_MAX_CONNS + int "Maximum number of ICMPv6 connections" + default 0 + depends on NET_ICMPv6_ALLOC_CONNS > 0 + ---help--- + If dynamic connections allocation is selected (NET_ICMPv6_ALLOC_CONNS > 0) + this will limit the number of connections that can be allocated. + + This is useful in case the system is under very heavy load (or + under attack), ensuring that the heap will not be exhausted. config NET_ICMPv6_NPOLLWAITERS int "Number of ICMPv6 poll waiters" diff --git a/net/icmpv6/icmpv6_conn.c b/net/icmpv6/icmpv6_conn.c index b10e7daf3d..4299fb62ac 100644 --- a/net/icmpv6/icmpv6_conn.c +++ b/net/icmpv6/icmpv6_conn.c @@ -48,8 +48,9 @@ /* The array containing all IPPROTO_ICMP socket connections */ -#ifndef CONFIG_NET_ALLOC_CONNS -static struct icmpv6_conn_s g_icmpv6_connections[CONFIG_NET_ICMPv6_NCONNS]; +#if CONFIG_NET_ICMPv6_PREALLOC_CONNS > 0 +static struct icmpv6_conn_s + g_icmpv6_connections[CONFIG_NET_ICMPv6_PREALLOC_CONNS]; #endif /* A list of all free IPPROTO_ICMP socket connections */ @@ -76,10 +77,10 @@ static dq_queue_t g_active_icmpv6_connections; void icmpv6_sock_initialize(void) { -#ifndef CONFIG_NET_ALLOC_CONNS +#if CONFIG_NET_ICMPv6_PREALLOC_CONNS > 0 int i; - for (i = 0; i < CONFIG_NET_ICMPv6_NCONNS; i++) + for (i = 0; i < CONFIG_NET_ICMPv6_PREALLOC_CONNS; i++) { /* Move the connection structure to the free list */ @@ -109,13 +110,22 @@ FAR struct icmpv6_conn_s *icmpv6_alloc(void) ret = nxmutex_lock(&g_free_lock); if (ret >= 0) { -#ifdef CONFIG_NET_ALLOC_CONNS +#if CONFIG_NET_ICMPv6_ALLOC_CONNS > 0 if (dq_peek(&g_active_icmpv6_connections) == NULL) { - conn = kmm_zalloc(sizeof(*conn) * CONFIG_NET_ICMPv6_NCONNS); +#if CONFIG_NET_ICMPv6_MAX_CONNS > 0 + if (dq_count(&g_active_icmpv6_connections) + + CONFIG_NET_ICMPv6_ALLOC_CONNS >= CONFIG_NET_ICMPv6_MAX_CONNS) + { + nxmutex_unlock(&g_free_lock); + return NULL; + } +#endif + + conn = kmm_zalloc(sizeof(*conn) * CONFIG_NET_ICMPv6_ALLOC_CONNS); if (conn != NULL) { - for (ret = 0; ret < CONFIG_NET_ICMPv6_NCONNS; ret++) + for (ret = 0; ret < CONFIG_NET_ICMPv6_ALLOC_CONNS; ret++) { dq_addlast(&conn[ret].sconn.node, &g_free_icmpv6_connections); @@ -166,9 +176,21 @@ void icmpv6_free(FAR struct icmpv6_conn_s *conn) memset(conn, 0, sizeof(*conn)); - /* Free the connection */ + /* If this is a preallocated or a batch allocated connection store it in + * the free connections list. Else free it. + */ +#if CONFIG_NET_ICMPv6_ALLOC_CONNS == 1 + if (conn < g_icmpv6_connections || conn >= (g_icmpv6_connections + + CONFIG_NET_ICMPv6_PREALLOC_CONNS)) + { + kmm_free(conn); + } + else +#endif + { + dq_addlast(&conn->sconn.node, &g_free_icmpv6_connections); + } - dq_addlast(&conn->sconn.node, &g_free_icmpv6_connections); nxmutex_unlock(&g_free_lock); }