diff --git a/boards/arm/stm32h7/nucleo-h743zi2/configs/socketcan/defconfig b/boards/arm/stm32h7/nucleo-h743zi2/configs/socketcan/defconfig index 5101756e2a..798bc06cea 100644 --- a/boards/arm/stm32h7/nucleo-h743zi2/configs/socketcan/defconfig +++ b/boards/arm/stm32h7/nucleo-h743zi2/configs/socketcan/defconfig @@ -25,7 +25,7 @@ CONFIG_BOARD_LOOPSPERMSEC=43103 CONFIG_BUILTIN=y CONFIG_CANUTILS_CANDUMP=y CONFIG_CANUTILS_CANSEND=y -CONFIG_CAN_CONNS=2 +CONFIG_CAN_PREALLOC_CONNS=2 CONFIG_DEBUG_ERROR=y CONFIG_DEBUG_FEATURES=y CONFIG_DEBUG_INFO=y diff --git a/net/can/Kconfig b/net/can/Kconfig index 10cffb0024..3f053e7f38 100644 --- a/net/can/Kconfig +++ b/net/can/Kconfig @@ -30,11 +30,46 @@ config NET_CAN_HAVE_ERRORS bool default n -config CAN_CONNS - int "Max number of CAN socket connections" +config CAN_PREALLOC_CONNS + int "Preallocated CAN socket connections" default 4 ---help--- - Maximum number of CAN connections (all tasks). + Number of CAN 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 CAN_ALLOC_CONNS + int "Dynamic CAN connections allocation" + default 0 + ---help--- + Dynamic memory allocations for CAN. + + 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 CAN_MAX_CONNS + int "Maximum number of CAN connections" + default 0 + depends on CAN_ALLOC_CONNS > 0 + ---help--- + If dynamic connections allocation is selected (CAN_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_CAN_EXTID bool "Enable CAN extended IDs" diff --git a/net/can/can_conn.c b/net/can/can_conn.c index b12683427b..4310bc81bb 100644 --- a/net/can/can_conn.c +++ b/net/can/can_conn.c @@ -49,8 +49,8 @@ /* The array containing all NetLink connections. */ -#ifndef CONFIG_NET_ALLOC_CONNS -static struct can_conn_s g_can_connections[CONFIG_CAN_CONNS]; +#if CONFIG_CAN_PREALLOC_CONNS > 0 +static struct can_conn_s g_can_connections[CONFIG_CAN_PREALLOC_CONNS]; #endif /* A list of all free NetLink connections */ @@ -77,10 +77,10 @@ static dq_queue_t g_active_can_connections; void can_initialize(void) { -#ifndef CONFIG_NET_ALLOC_CONNS +#if CONFIG_CAN_PREALLOC_CONNS > 0 int i; - for (i = 0; i < CONFIG_CAN_CONNS; i++) + for (i = 0; i < CONFIG_CAN_PREALLOC_CONNS; i++) { /* Mark the connection closed and move it to the free list */ @@ -101,20 +101,29 @@ void can_initialize(void) FAR struct can_conn_s *can_alloc(void) { FAR struct can_conn_s *conn; -#ifdef CONFIG_NET_ALLOC_CONNS +#if CONFIG_CAN_ALLOC_CONNS > 0 int i; #endif /* The free list is protected by a a mutex. */ nxmutex_lock(&g_free_lock); -#ifdef CONFIG_NET_ALLOC_CONNS +#if CONFIG_CAN_ALLOC_CONNS > 0 if (dq_peek(&g_free_can_connections) == NULL) { - conn = kmm_zalloc(sizeof(*conn) * CONFIG_CAN_CONNS); +#if CONFIG_CAN_MAX_CONNS > 0 + if (dq_count(&g_active_can_connections) + CONFIG_CAN_ALLOC_CONNS + >= CONFIG_CAN_MAX_CONNS) + { + nxmutex_unlock(&g_free_lock); + return NULL; + } +#endif + + conn = kmm_zalloc(sizeof(*conn) * CONFIG_CAN_ALLOC_CONNS); if (conn != NULL) { - for (i = 0; i < CONFIG_CAN_CONNS; i++) + for (i = 0; i < CONFIG_CAN_ALLOC_CONNS; i++) { dq_addlast(&conn[i].sconn.node, &g_free_can_connections); } @@ -177,9 +186,22 @@ void can_free(FAR struct can_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_CAN_ALLOC_CONNS == 1 + if (conn < g_can_connections || conn >= (g_can_connections + + CONFIG_CAN_PREALLOC_CONNS)) + { + kmm_free(conn); + } + else +#endif + { + dq_addlast(&conn->sconn.node, &g_free_can_connections); + } - dq_addlast(&conn->sconn.node, &g_free_can_connections); nxmutex_unlock(&g_free_lock); }