From 34aebebf87e5411db1acd6ab9762a1ea8120f01a Mon Sep 17 00:00:00 2001 From: Thomas Lykkeberg <62430938+Lykkeberg@users.noreply.github.com> Date: Wed, 7 Aug 2024 12:47:10 +0200 Subject: [PATCH 01/24] service: peek/poke v2 with 64 bit memory support --- include/csp/csp.h | 4 ++- include/csp/csp_cmp.h | 52 +++++++++++++++++++++++++++++++++++++++ include/csp/csp_types.h | 4 +++ src/csp_service_handler.c | 50 +++++++++++++++++++++++++++++++++++++ 4 files changed, 109 insertions(+), 1 deletion(-) diff --git a/include/csp/csp.h b/include/csp/csp.h index 398654897..fe20d2929 100644 --- a/include/csp/csp.h +++ b/include/csp/csp.h @@ -481,9 +481,11 @@ void csp_rdp_get_opt(unsigned int *window_size, unsigned int *conn_timeout_ms, unsigned int *ack_timeout, unsigned int *ack_delay_count); /** - * Set platform specific memory copy function. + * Set platform specific memory copy functions. */ void csp_cmp_set_memcpy(csp_memcpy_fnc_t fnc); +void csp_cmp_set_memread64(csp_memread64_fnc_t fnc); +void csp_cmp_set_memwrite64(csp_memwrite64_fnc_t fnc); #if (CSP_ENABLE_CSP_PRINT) diff --git a/include/csp/csp_cmp.h b/include/csp/csp_cmp.h index 96f5132ad..e82367d20 100644 --- a/include/csp/csp_cmp.h +++ b/include/csp/csp_cmp.h @@ -62,6 +62,14 @@ extern "C" { * Set/configure routing. */ #define CSP_CMP_ROUTE_SET_V2 7 +/** + * Peek/read data from memory - 64-bit version. + */ +#define CSP_CMP_PEEK_V2 8 +/** + * Poke/write data from memory - 64-bit version. + */ +#define CSP_CMP_POKE_V2 9 /**@}*/ /** @@ -92,6 +100,16 @@ extern "C" { */ #define CSP_CMP_POKE_MAX_LEN 200 +/** + * CMP peek/read memory - max read length - 64-bit. + */ +#define CSP_CMP_PEEK_V2_MAX_LEN 196 + +/** + * CMP poke/write memory - max write length - 64-bit. + */ +#define CSP_CMP_POKE_V2_MAX_LEN 196 + /** * CSP management protocol description. */ @@ -142,6 +160,16 @@ struct csp_cmp_message { uint8_t len; char data[CSP_CMP_POKE_MAX_LEN]; } poke; + struct { + uint64_t vaddr; /* Virtual 64-bit address on the target system */ + uint8_t len; + char data[CSP_CMP_PEEK_V2_MAX_LEN]; + } peek_v2; + struct { + uint64_t vaddr; /* Virtual 64-bit address on the target system */ + uint8_t len; + char data[CSP_CMP_POKE_V2_MAX_LEN]; + } poke_v2; csp_timestamp_t clock; }; } __attribute__((__packed__)); @@ -201,6 +229,30 @@ static inline int csp_cmp_poke(uint16_t node, uint32_t timeout, struct csp_cmp_m return csp_cmp(node, timeout, CSP_CMP_POKE, CMP_SIZE(poke) - sizeof(msg->poke.data) + msg->poke.len, msg); } +/** + * Peek (read) memory on remote node - 64-bit version. + * + * @param[in] node address of subsystem. + * @param[in] timeout timeout in mS to wait for reply.. + * @param[in/out] msg memory address and number of bytes to peek. (msg peeked/read memory) + * @return #CSP_ERR_NONE on success, otherwise an error code. + */ +static inline int csp_cmp_peek_v2(uint16_t node, uint32_t timeout, struct csp_cmp_message *msg) { + return csp_cmp(node, timeout, CSP_CMP_PEEK_V2, CMP_SIZE(peek_v2) - sizeof(msg->peek_v2.data) + msg->peek_v2.len, msg); +} + +/** + * Poke (write) memory on remote node - 64-bit version. + * + * @param[in] node address of subsystem. + * @param[in] timeout timeout in mS to wait for reply.. + * @param[in] msg memory address, number of bytes and the actual bytes to poke/write. + * @return #CSP_ERR_NONE on success, otherwise an error code. + */ +static inline int csp_cmp_poke_v2(uint16_t node, uint32_t timeout, struct csp_cmp_message *msg) { + return csp_cmp(node, timeout, CSP_CMP_POKE_V2, CMP_SIZE(poke_v2) - sizeof(msg->poke_v2.data) + msg->poke_v2.len, msg); +} + #ifdef __cplusplus } #endif diff --git a/include/csp/csp_types.h b/include/csp/csp_types.h index a26a4dc23..ad64c3d5e 100644 --- a/include/csp/csp_types.h +++ b/include/csp/csp_types.h @@ -204,12 +204,16 @@ typedef const uint32_t csp_const_memptr_t; typedef void * csp_memptr_t; /** Const memory pointer */ typedef const void * csp_const_memptr_t; +/** Memory pointer 64-bit */ +typedef uint64_t csp_memptr64_t; #endif /** * Platform specific memory copy function. */ typedef csp_memptr_t (*csp_memcpy_fnc_t)(csp_memptr_t, csp_const_memptr_t, size_t); +typedef csp_memptr64_t (*csp_memread64_fnc_t)(csp_const_memptr_t, csp_memptr64_t, size_t); +typedef csp_memptr64_t (*csp_memwrite64_fnc_t)(csp_memptr64_t, csp_memptr_t, size_t); /** * Compile check/asserts. diff --git a/src/csp_service_handler.c b/src/csp_service_handler.c index a9eb05c20..7600e567c 100644 --- a/src/csp_service_handler.c +++ b/src/csp_service_handler.c @@ -22,12 +22,22 @@ static uint32_t wrap_32bit_memcpy(uint32_t to, const uint32_t from, size_t size) static csp_memcpy_fnc_t csp_cmp_memcpy_fnc = wrap_32bit_memcpy; #else static csp_memcpy_fnc_t csp_cmp_memcpy_fnc = (csp_memcpy_fnc_t)memcpy; +static csp_memread64_fnc_t csp_cmp_memread64_fnc = (csp_memread64_fnc_t)NULL; +static csp_memwrite64_fnc_t csp_cmp_memwrite64_fnc = (csp_memwrite64_fnc_t)NULL; #endif void csp_cmp_set_memcpy(csp_memcpy_fnc_t fnc) { csp_cmp_memcpy_fnc = fnc; } +void csp_cmp_set_memread64(csp_memread64_fnc_t fnc) { + csp_cmp_memread64_fnc = fnc; +} + +void csp_cmp_set_memwrite64(csp_memwrite64_fnc_t fnc) { + csp_cmp_memwrite64_fnc = fnc; +} + static int do_cmp_ident(struct csp_cmp_message * cmp) { /* Copy revision */ @@ -130,6 +140,38 @@ static int do_cmp_poke(struct csp_cmp_message * cmp) { return CSP_ERR_NONE; } +static int do_cmp_peek_v2(struct csp_cmp_message * cmp) { + + cmp->peek_v2.vaddr = htobe64(cmp->peek_v2.vaddr); + if (cmp->peek_v2.len > CSP_CMP_PEEK_MAX_LEN) + return CSP_ERR_INVAL; + + if (!csp_cmp_memread64_fnc) { + return CSP_ERR_DRIVER; + } + + /* Dangerous, you better know what you are doing */ + csp_cmp_memread64_fnc(cmp->peek_v2.data, cmp->peek_v2.vaddr, cmp->peek_v2.len); + + return CSP_ERR_NONE; +} + +static int do_cmp_poke_v2(struct csp_cmp_message * cmp) { + + cmp->poke_v2.vaddr = htobe64(cmp->poke_v2.vaddr); + if (cmp->poke_v2.len > CSP_CMP_POKE_MAX_LEN) + return CSP_ERR_INVAL; + + if (!csp_cmp_memwrite64_fnc) { + return CSP_ERR_DRIVER; + } + + /* Extremely dangerous, you better know what you are doing */ + csp_cmp_memwrite64_fnc(cmp->poke_v2.vaddr, cmp->poke_v2.data, cmp->poke_v2.len); + + return CSP_ERR_NONE; +} + static int do_cmp_clock(struct csp_cmp_message * cmp) { csp_timestamp_t clock; @@ -192,6 +234,14 @@ static int csp_cmp_handler(csp_packet_t * packet) { ret = do_cmp_poke(cmp); break; + case CSP_CMP_PEEK_V2: + ret = do_cmp_peek_v2(cmp); + break; + + case CSP_CMP_POKE_V2: + ret = do_cmp_poke_v2(cmp); + break; + case CSP_CMP_CLOCK: ret = do_cmp_clock(cmp); break; From bb8110ce9b297c879e7805684514b32908bfa712 Mon Sep 17 00:00:00 2001 From: edvard Date: Tue, 8 Oct 2024 17:56:52 +0200 Subject: [PATCH 02/24] cmp: correct poke/peek length check for v2 --- src/csp_service_handler.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/csp_service_handler.c b/src/csp_service_handler.c index 7600e567c..1947d5631 100644 --- a/src/csp_service_handler.c +++ b/src/csp_service_handler.c @@ -143,7 +143,7 @@ static int do_cmp_poke(struct csp_cmp_message * cmp) { static int do_cmp_peek_v2(struct csp_cmp_message * cmp) { cmp->peek_v2.vaddr = htobe64(cmp->peek_v2.vaddr); - if (cmp->peek_v2.len > CSP_CMP_PEEK_MAX_LEN) + if (cmp->peek_v2.len > CSP_CMP_PEEK_V2_MAX_LEN) return CSP_ERR_INVAL; if (!csp_cmp_memread64_fnc) { @@ -159,7 +159,7 @@ static int do_cmp_peek_v2(struct csp_cmp_message * cmp) { static int do_cmp_poke_v2(struct csp_cmp_message * cmp) { cmp->poke_v2.vaddr = htobe64(cmp->poke_v2.vaddr); - if (cmp->poke_v2.len > CSP_CMP_POKE_MAX_LEN) + if (cmp->poke_v2.len > CSP_CMP_POKE_V2_MAX_LEN) return CSP_ERR_INVAL; if (!csp_cmp_memwrite64_fnc) { From 794b2573addc3ec2dfb105b59093012527ea0508 Mon Sep 17 00:00:00 2001 From: kivkiv12345 Date: Tue, 10 Dec 2024 15:33:31 +0100 Subject: [PATCH 03/24] Use struct initializer to avoid "unintialized value" Valgrind warning --- src/drivers/can/can_socketcan.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/drivers/can/can_socketcan.c b/src/drivers/can/can_socketcan.c index b90233d92..ca674289f 100644 --- a/src/drivers/can/can_socketcan.c +++ b/src/drivers/can/can_socketcan.c @@ -46,8 +46,9 @@ static void * socketcan_rx_thread(void * arg) { fd_set input; FD_ZERO(&input); FD_SET(ctx->socket, &input); - struct timeval timeout; - timeout.tv_sec = 10; + struct timeval timeout = { + .tv_sec = 10, + }; int n = select(ctx->socket + 1, &input, NULL, NULL, &timeout); if (n == -1) { csp_print("CAN read error\n"); From 7ba36fb06ec21a5ade61672c2a55e3917619f58f Mon Sep 17 00:00:00 2001 From: kivkiv12345 Date: Wed, 11 Dec 2024 08:49:54 +0100 Subject: [PATCH 04/24] Fix a couple more sources of unitialized values Although I dont know how exactly csp_connect() leaves fields on csp_id_t unitialized, but Valgrind certainly seems to think that they are. --- src/csp_conn.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/csp_conn.c b/src/csp_conn.c index 6cc497613..c4422561e 100644 --- a/src/csp_conn.c +++ b/src/csp_conn.c @@ -252,13 +252,13 @@ csp_conn_t * csp_connect(uint8_t prio, uint16_t dest, uint8_t dport, uint32_t ti opts |= csp_conf.conn_dfl_so; /* Generate identifier */ - csp_id_t incoming_id, outgoing_id; + csp_id_t incoming_id = {0}, outgoing_id = {0}; /* Use 0 as incoming id (this disables the input filter on destination node) * This means that for this outgoing connection, we accept the answer coming to whatever address * the outgoing interface has. CSP does not support "source address" on outgoing connections * so the outgoing source address will be automatically applied after outgoing routing - * selects which interface the packet will leavve from */ + * selects which interface the packet will leave from */ incoming_id.dst = 0; outgoing_id.src = 0; From 67cf50e42d47ba48b6790f716fedd0caa5245a0d Mon Sep 17 00:00:00 2001 From: william Date: Wed, 15 Jan 2025 13:31:14 +0100 Subject: [PATCH 05/24] Fixed compilantion in release mode --- src/interfaces/csp_if_zmqhub.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/interfaces/csp_if_zmqhub.c b/src/interfaces/csp_if_zmqhub.c index 7976d1803..75d629075 100644 --- a/src/interfaces/csp_if_zmqhub.c +++ b/src/interfaces/csp_if_zmqhub.c @@ -207,7 +207,7 @@ int csp_zmqhub_init_w_name_endpoints_rxfilter(const char * ifname, uint16_t addr assert(ret == 0); ret = pthread_create(&drv->rx_thread, &attributes, csp_zmqhub_task, drv); assert(ret == 0); - + (void)ret; /* Register interface */ csp_iflist_add(&drv->iface); @@ -293,7 +293,7 @@ int csp_zmqhub_init_filter2(const char * ifname, const char * host, uint16_t add assert(ret == 0); ret = zmq_connect(drv->subscriber, sub); assert(ret == 0); - + (void)ret; if (promisc) { From f0835bff94d44a70adb0e0dcd003c16870ba104e Mon Sep 17 00:00:00 2001 From: Troels Jessen Date: Tue, 8 Apr 2025 14:04:44 +0200 Subject: [PATCH 06/24] Allow CAN broadcast reception when not configuring interface to promisc Previously, posix instances using CAN did not accept L2 and L3 broadcast due to HW filtering --- src/drivers/can/can_socketcan.c | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/src/drivers/can/can_socketcan.c b/src/drivers/can/can_socketcan.c index ca674289f..2aab679d2 100644 --- a/src/drivers/can/can_socketcan.c +++ b/src/drivers/can/can_socketcan.c @@ -17,6 +17,7 @@ #include #include +#include // CAN interface data, state, etc. typedef struct { @@ -153,26 +154,34 @@ static int csp_can_tx_frame(void * driver_data, uint32_t id, const uint8_t * dat int csp_can_socketcan_set_promisc(const bool promisc, can_context_t * ctx) { - struct can_filter filter = { + + struct can_filter filter[3] = { { .can_id = CFP_MAKE_DST(ctx->iface.addr), .can_mask = 0x0000, /* receive anything */ - }; + } }; if (ctx->socket == 0) { return CSP_ERR_INVAL; } + int num_filters = 1; if (!promisc) { if (csp_conf.version == 1) { - filter.can_id = CFP_MAKE_DST(ctx->iface.addr); - filter.can_mask = CFP_MAKE_DST((1 << CFP_HOST_SIZE) - 1); + num_filters = 1; + filter[0].can_id = CFP_MAKE_DST(ctx->iface.addr); + filter[0].can_mask = CFP_MAKE_DST((1 << CFP_HOST_SIZE) - 1); } else { - filter.can_id = ctx->iface.addr << CFP2_DST_OFFSET; - filter.can_mask = CFP2_DST_MASK << CFP2_DST_OFFSET; + num_filters = 3; + filter[0].can_id = ctx->iface.addr << CFP2_DST_OFFSET; + filter[0].can_mask = CFP2_DST_MASK << CFP2_DST_OFFSET; + filter[1].can_id = ((1 << (csp_id_get_host_bits() - ctx->iface.netmask)) - 1) << CFP2_DST_OFFSET; + filter[1].can_mask = CFP2_DST_MASK << CFP2_DST_OFFSET; + filter[2].can_id = 0x3FFF << CFP2_DST_OFFSET; + filter[2].can_mask = CFP2_DST_MASK << CFP2_DST_OFFSET; } } - if (setsockopt(ctx->socket, SOL_CAN_RAW, CAN_RAW_FILTER, &filter, sizeof(filter)) < 0) { + if (setsockopt(ctx->socket, SOL_CAN_RAW, CAN_RAW_FILTER, &filter, num_filters * sizeof(struct can_filter)) < 0) { csp_print("%s: setsockopt() failed, error: %s\n", __func__, strerror(errno)); return CSP_ERR_INVAL; } From 92067a4524d91c567be60ea224cdbcaa9072ae98 Mon Sep 17 00:00:00 2001 From: Troels Jessen Date: Tue, 13 May 2025 15:01:15 +0200 Subject: [PATCH 07/24] Fix CSP v1 over CAN The issue originates in the fact that L3 data is overriding L2 data in the csp_packet header. This is resolved on the libcsp/libcsp/develop branch already, by removing the union. --- src/interfaces/csp_if_can.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/interfaces/csp_if_can.c b/src/interfaces/csp_if_can.c index 880f31acc..617abeca2 100644 --- a/src/interfaces/csp_if_can.c +++ b/src/interfaces/csp_if_can.c @@ -87,8 +87,6 @@ int csp_can1_rx(csp_iface_t * iface, uint32_t id, const uint8_t * data, uint8_t memcpy(packet->frame_begin, data, sizeof(uint32_t)); packet->frame_length += sizeof(uint32_t); - csp_id_strip(packet); - /* Copy CSP length (of data) */ memcpy(&(packet->length), data + sizeof(uint32_t), sizeof(packet->length)); packet->length = be16toh(packet->length); @@ -140,6 +138,11 @@ int csp_can1_rx(csp_iface_t * iface, uint32_t id, const uint8_t * data, uint8_t if (packet->rx_count != packet->length) break; + /* Length information is packed differently for CAN */ + uint16_t length = packet->length; + csp_id_strip(packet); + packet->length = length; + /* Rewrite incoming L2 broadcast to local node */ if (packet->id.dst == 0x1F) { packet->id.dst = iface->addr; @@ -148,9 +151,6 @@ int csp_can1_rx(csp_iface_t * iface, uint32_t id, const uint8_t * data, uint8_t /* Free packet buffer */ csp_can_pbuf_free(ifdata, packet, 0, task_woken); - /* Clear timestamp_rx for L3 as L2 last_used is not needed anymore */ - packet->timestamp_rx = 0; - /* Data is available */ csp_qfifo_write(packet, iface, task_woken); From f0d70fa92d95214d11189ff54c87943f974c43b2 Mon Sep 17 00:00:00 2001 From: Mitchell Erdbruegger <214373439+MErdbruegger@users.noreply.github.com> Date: Sun, 1 Jun 2025 15:03:23 -0500 Subject: [PATCH 08/24] WIP: NOCOMMIT remove clone of unnecessary bytes in csp_buffer_clone --- src/csp_buffer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/csp_buffer.c b/src/csp_buffer.c index 4b3790a97..3aea0bbb1 100644 --- a/src/csp_buffer.c +++ b/src/csp_buffer.c @@ -139,7 +139,7 @@ void * csp_buffer_clone(void * buffer) { csp_packet_t * clone = csp_buffer_get(packet->length); if (clone) { - size_t size = sizeof(csp_packet_t) - CSP_BUFFER_SIZE + CSP_PACKET_PADDING_BYTES + packet->length; + size_t size = sizeof(csp_packet_t) - CSP_BUFFER_SIZE + packet->length; memcpy(clone, packet, size > sizeof(csp_packet_t) ? sizeof(csp_packet_t) : size); } From 9306f2b7df6c4d3ade26f8068aafd3a818510512 Mon Sep 17 00:00:00 2001 From: edvard Date: Mon, 2 Jun 2025 12:04:18 +0200 Subject: [PATCH 09/24] check timeout even if userspace --- src/csp_rdp.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/csp_rdp.c b/src/csp_rdp.c index 497d8c772..c113d3190 100644 --- a/src/csp_rdp.c +++ b/src/csp_rdp.c @@ -409,6 +409,12 @@ void csp_rdp_check_timeouts(csp_conn_t * conn) { if (conn->rdp.state == RDP_OPEN) { + if (csp_rdp_time_after(time_now, conn->timestamp + conn->rdp.conn_timeout)) { + csp_conn_close(conn, CSP_RDP_CLOSED_BY_PROTOCOL | CSP_RDP_CLOSED_BY_TIMEOUT); + csp_bin_sem_post(&conn->rdp.tx_wait); + return; + } + /* Check if we have unacknowledged segments */ if (conn->rdp.delayed_acks) { csp_rdp_check_ack(conn); From 699ac522a9616fbdf6c0b1ca2e9418e6f5ea51c1 Mon Sep 17 00:00:00 2001 From: edvard Date: Fri, 6 Jun 2025 12:44:36 +0200 Subject: [PATCH 10/24] csp_buffer: Fix pointers in csp_buffer_clone Commit inspired by @moonlight83340 https://github.com/libcsp/libcsp/pull/834 --- src/csp_buffer.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/csp_buffer.c b/src/csp_buffer.c index 3aea0bbb1..b814f3070 100644 --- a/src/csp_buffer.c +++ b/src/csp_buffer.c @@ -141,6 +141,7 @@ void * csp_buffer_clone(void * buffer) { if (clone) { size_t size = sizeof(csp_packet_t) - CSP_BUFFER_SIZE + packet->length; memcpy(clone, packet, size > sizeof(csp_packet_t) ? sizeof(csp_packet_t) : size); + clone->frame_begin = (clone->header + CSP_PACKET_PADDING_BYTES) - (packet->data - packet->frame_begin); } return clone; From 42855ef19121655733d2063ea51d9cdfbbf51fe6 Mon Sep 17 00:00:00 2001 From: edvard Date: Fri, 6 Jun 2025 13:08:41 +0200 Subject: [PATCH 11/24] buffer: Ensure buffer allocation respect the reserve Commit inspired by @moonlight83340 https://github.com/libcsp/libcsp/pull/856 --- src/csp_buffer.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/csp_buffer.c b/src/csp_buffer.c index b814f3070..ab6060130 100644 --- a/src/csp_buffer.c +++ b/src/csp_buffer.c @@ -45,8 +45,8 @@ static csp_packet_t * csp_buffer_get_actual(int reserve, int isr) { } else { remain = csp_queue_size(csp_buffers); } - /* Respect if remaining is lower than the reserve requested */ - if (remain < reserve) { + /* Respect the requested reserve */ + if (remain <= reserve) { return NULL; } From 983ee9eeca334170b381e11d44ed67c50f9a466e Mon Sep 17 00:00:00 2001 From: kevin Date: Thu, 31 Jul 2025 10:22:33 +0200 Subject: [PATCH 12/24] Fix off-by-one in `csp_rtable_set()` We should consider actually returning an error. Instead we still just override the last available route, which seems to have been the previous intention. Co-authored-by: edvard --- src/csp_rtable_cidr.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/csp_rtable_cidr.c b/src/csp_rtable_cidr.c index 8dc9ed42b..8134e4ccd 100644 --- a/src/csp_rtable_cidr.c +++ b/src/csp_rtable_cidr.c @@ -81,8 +81,8 @@ int csp_rtable_set_internal(uint16_t address, uint16_t netmask, csp_iface_t * if /* If not, create a new one */ if (!entry) { entry = &rtable[rtable_inptr++]; - if (rtable_inptr > CSP_RTABLE_SIZE) { - rtable_inptr = CSP_RTABLE_SIZE; + if (rtable_inptr >= CSP_RTABLE_SIZE) { + rtable_inptr = CSP_RTABLE_SIZE-1; } } From 2cde83b65ed584cef13bf3a61d55662adda32ba5 Mon Sep 17 00:00:00 2001 From: kivkiv12345 Date: Sat, 9 Aug 2025 20:16:12 +0200 Subject: [PATCH 13/24] Fix `sec_key` valgrind warning in `csp_zmqhub_init_filter2()` When it isn't exactly 40 characters long --- src/interfaces/csp_if_zmqhub.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/interfaces/csp_if_zmqhub.c b/src/interfaces/csp_if_zmqhub.c index 75d629075..815faba28 100644 --- a/src/interfaces/csp_if_zmqhub.c +++ b/src/interfaces/csp_if_zmqhub.c @@ -220,6 +220,15 @@ int csp_zmqhub_init_w_name_endpoints_rxfilter(const char * ifname, uint16_t addr int csp_zmqhub_init_filter2(const char * ifname, const char * host, uint16_t addr, uint16_t netmask, int promisc, csp_iface_t ** return_interface, char * sec_key, uint16_t subport, uint16_t pubport) { + /* ZMQ will cause valgrind errors if `sec_key` isn't exactly 40 characters long. + For now we deliberately parse an empty string as if no sec_key was specified. */ + const ssize_t sec_key_len = sec_key ? strnlen(sec_key, CURVE_KEYLEN-1) : 0; + if (sec_key_len && sec_key_len != CURVE_KEYLEN-1) { + /* Is it bad to expose the detected length of the ZMQ key here? */ + fprintf(stderr, "ZMQ secret key must be exactly 40 characters long (got %ld)\n", sec_key_len); + return CSP_ERR_INVAL; + } + char pub[100]; csp_zmqhub_make_endpoint(host, subport, pub, sizeof(pub)); @@ -254,8 +263,8 @@ int csp_zmqhub_init_filter2(const char * ifname, const char * host, uint16_t add assert(drv->subscriber != NULL); /* If shared secret key provided */ - if (sec_key) { - char pub_key[41]; + if (sec_key_len) { + char pub_key[CURVE_KEYLEN]; zmq_curve_public(pub_key, sec_key); /* Publisher (TX) */ From d4196988af5b4fbd34c4c873e5c01b840f967504 Mon Sep 17 00:00:00 2001 From: kivkiv12345 Date: Sun, 10 Aug 2025 11:07:12 +0200 Subject: [PATCH 14/24] Use `CSP_IFLIST_NAME_MAX` for iface name len in `csp_rtable_parse()` --- src/csp_rtable_stdio.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/csp_rtable_stdio.c b/src/csp_rtable_stdio.c index 6401007d1..49c4c0084 100644 --- a/src/csp_rtable_stdio.c +++ b/src/csp_rtable_stdio.c @@ -24,13 +24,13 @@ static int csp_rtable_parse(const char * rtable, int dry_run) { while ((str) && (strlen(str) > 1)) { unsigned int address, via; int netmask; - char name[15]; - if (sscanf(str, "%u/%d %14s %u", &address, &netmask, name, &via) == 4) { - } else if (sscanf(str, "%u/%d %14s", &address, &netmask, name) == 3) { + char name[CSP_IFLIST_NAME_MAX] = {0}; + if (sscanf(str, "%u/%d %9s %u", &address, &netmask, name, &via) == 4) { + } else if (sscanf(str, "%u/%d %9s", &address, &netmask, name) == 3) { via = CSP_NO_VIA_ADDRESS; - } else if (sscanf(str, "%u %14s %u", &address, name, &via) == 3) { + } else if (sscanf(str, "%u %9s %u", &address, name, &via) == 3) { netmask = csp_id_get_host_bits(); - } else if (sscanf(str, "%u %14s", &address, name) == 2) { + } else if (sscanf(str, "%u %9s", &address, name) == 2) { netmask = csp_id_get_host_bits(); via = CSP_NO_VIA_ADDRESS; } else { From a8e72cd84bfe5adb68cabe7c08aa351d58d423e6 Mon Sep 17 00:00:00 2001 From: kivkiv12345 <57446369+kivkiv12345@users.noreply.github.com> Date: Wed, 13 Aug 2025 12:36:35 +0000 Subject: [PATCH 15/24] Post init promisc config (#30) Added `csp_zmqhub__filters()` to change promisc settings after init --- include/csp/interfaces/csp_if_zmqhub.h | 4 ++ src/interfaces/csp_if_zmqhub.c | 80 +++++++++++++++++++------- 2 files changed, 62 insertions(+), 22 deletions(-) diff --git a/include/csp/interfaces/csp_if_zmqhub.h b/include/csp/interfaces/csp_if_zmqhub.h index 17d972442..893d39a4a 100644 --- a/include/csp/interfaces/csp_if_zmqhub.h +++ b/include/csp/interfaces/csp_if_zmqhub.h @@ -123,6 +123,10 @@ int csp_zmqhub_init_w_name_endpoints_rxfilter(const char * ifname, uint16_t addr int csp_zmqhub_init_filter2(const char * ifname, const char * host, uint16_t addr, uint16_t netmask, int promisc, csp_iface_t ** return_interface, char * sec_key, uint16_t subport, uint16_t pubport); +void csp_zmqhub_remove_filters(csp_iface_t * zmq_iface); +void csp_zmqhub_add_filters(csp_iface_t * zmq_iface); + + #ifdef __cplusplus } #endif diff --git a/src/interfaces/csp_if_zmqhub.c b/src/interfaces/csp_if_zmqhub.c index 815faba28..1c4c9fad6 100644 --- a/src/interfaces/csp_if_zmqhub.c +++ b/src/interfaces/csp_if_zmqhub.c @@ -18,6 +18,9 @@ typedef struct { void * context; void * publisher; void * subscriber; + /* We must allocate filters per interface, as ZMQ does not copy the filter value to the + outgoing packet for each setsockopt call. */ + uint16_t filt[4][3]; char name[CSP_IFLIST_NAME_MAX + 1]; csp_iface_t iface; } zmq_driver_t; @@ -218,6 +221,55 @@ int csp_zmqhub_init_w_name_endpoints_rxfilter(const char * ifname, uint16_t addr return CSP_ERR_NONE; } +void csp_zmqhub_remove_filters(csp_iface_t * zmq_iface) { + + int ret = 0; + zmq_driver_t * drv = zmq_iface->driver_data; + const uint16_t addr = zmq_iface->addr; + const uint16_t hostmask = (1 << (csp_id_get_host_bits() - zmq_iface->netmask)) - 1; + + /* Unsubscribe from any current filters */ + for (int i = 0; i < 4; i++) { + //int i = CSP_PRIO_NORM; + drv->filt[i][0] = __builtin_bswap16((i << 14) | addr); + drv->filt[i][1] = __builtin_bswap16((i << 14) | addr | hostmask); + drv->filt[i][2] = __builtin_bswap16((i << 14) | 16383); + ret = zmq_setsockopt(drv->subscriber, ZMQ_UNSUBSCRIBE, &drv->filt[i][0], 2); + ret = zmq_setsockopt(drv->subscriber, ZMQ_UNSUBSCRIBE, &drv->filt[i][1], 2); + ret = zmq_setsockopt(drv->subscriber, ZMQ_UNSUBSCRIBE, &drv->filt[i][2], 2); + } + + /* subscribe to all packets - no filter */ + ret = zmq_setsockopt(drv->subscriber, ZMQ_SUBSCRIBE, NULL, 0); + assert(ret == 0); + (void)ret; +} + +void csp_zmqhub_add_filters(csp_iface_t * zmq_iface) { + + int ret = 0; + zmq_driver_t * drv = zmq_iface->driver_data; + const uint16_t addr = zmq_iface->addr; + const uint16_t hostmask = (1 << (csp_id_get_host_bits() - zmq_iface->netmask)) - 1; + + /* Subscribe to all packets - no filter */ + ret = zmq_setsockopt(drv->subscriber, ZMQ_UNSUBSCRIBE, NULL, 0); + assert(ret == 0); + + /* Subscribe to unpromiscuous filters */ + for (int i = 0; i < 4; i++) { + //int i = CSP_PRIO_NORM; + drv->filt[i][0] = __builtin_bswap16((i << 14) | addr); + drv->filt[i][1] = __builtin_bswap16((i << 14) | addr | hostmask); + drv->filt[i][2] = __builtin_bswap16((i << 14) | 16383); + ret = zmq_setsockopt(drv->subscriber, ZMQ_SUBSCRIBE, &drv->filt[i][0], 2); + ret = zmq_setsockopt(drv->subscriber, ZMQ_SUBSCRIBE, &drv->filt[i][1], 2); + ret = zmq_setsockopt(drv->subscriber, ZMQ_SUBSCRIBE, &drv->filt[i][2], 2); + } + assert(ret == 0); + (void)ret; +} + int csp_zmqhub_init_filter2(const char * ifname, const char * host, uint16_t addr, uint16_t netmask, int promisc, csp_iface_t ** return_interface, char * sec_key, uint16_t subport, uint16_t pubport) { /* ZMQ will cause valgrind errors if `sec_key` isn't exactly 40 characters long. @@ -249,6 +301,9 @@ int csp_zmqhub_init_filter2(const char * ifname, const char * host, uint16_t add drv->iface.driver_data = drv; drv->iface.nexthop = csp_zmqhub_tx; + drv->iface.addr = addr; + drv->iface.netmask = netmask; + drv->context = zmq_ctx_new(); assert(drv->context != NULL); @@ -293,9 +348,6 @@ int csp_zmqhub_init_filter2(const char * ifname, const char * host, uint16_t add zmq_setsockopt(drv->subscriber, ZMQ_TCP_KEEPALIVE_IDLE, &idle, sizeof(idle)); zmq_setsockopt(drv->subscriber, ZMQ_TCP_KEEPALIVE_CNT, &cnt, sizeof(cnt)); zmq_setsockopt(drv->subscriber, ZMQ_TCP_KEEPALIVE_INTVL, &intvl, sizeof(intvl)); - - /* Generate filters */ - uint16_t hostmask = (1 << (csp_id_get_host_bits() - netmask)) - 1; /* Connect to server */ ret = zmq_connect(drv->publisher, pub); @@ -305,28 +357,12 @@ int csp_zmqhub_init_filter2(const char * ifname, const char * host, uint16_t add (void)ret; if (promisc) { - // subscribe to all packets - no filter - ret = zmq_setsockopt(drv->subscriber, ZMQ_SUBSCRIBE, NULL, 0); - assert(ret == 0); + csp_zmqhub_remove_filters(&drv->iface); } else { - - /* This needs to be static, because ZMQ does not copy the filter value to the - * outgoing packet for each setsockopt call */ - static uint16_t filt[4][3]; - - for (int i = 0; i < 4; i++) { - //int i = CSP_PRIO_NORM; - filt[i][0] = __builtin_bswap16((i << 14) | addr); - filt[i][1] = __builtin_bswap16((i << 14) | addr | hostmask); - filt[i][2] = __builtin_bswap16((i << 14) | 16383); - ret = zmq_setsockopt(drv->subscriber, ZMQ_SUBSCRIBE, &filt[i][0], 2); - ret = zmq_setsockopt(drv->subscriber, ZMQ_SUBSCRIBE, &filt[i][1], 2); - ret = zmq_setsockopt(drv->subscriber, ZMQ_SUBSCRIBE, &filt[i][2], 2); - } - - } + csp_zmqhub_add_filters(&drv->iface); + } /* Start RX thread */ From 60e4804ea8451e6202ce2c5c5abc0342ad3b55a4 Mon Sep 17 00:00:00 2001 From: kevin Date: Mon, 8 Sep 2025 12:48:06 +0200 Subject: [PATCH 16/24] Improve some comments for `csp_zmqhub__filters()` --- include/csp/interfaces/csp_if_zmqhub.h | 11 +++++++++++ src/interfaces/csp_if_zmqhub.c | 2 +- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/include/csp/interfaces/csp_if_zmqhub.h b/include/csp/interfaces/csp_if_zmqhub.h index 893d39a4a..8cc793c8b 100644 --- a/include/csp/interfaces/csp_if_zmqhub.h +++ b/include/csp/interfaces/csp_if_zmqhub.h @@ -123,7 +123,18 @@ int csp_zmqhub_init_w_name_endpoints_rxfilter(const char * ifname, uint16_t addr int csp_zmqhub_init_filter2(const char * ifname, const char * host, uint16_t addr, uint16_t netmask, int promisc, csp_iface_t ** return_interface, char * sec_key, uint16_t subport, uint16_t pubport); +/** + * Make `zmq_iface` promiscuous (parse all packets) + * + * Safe to call after `csp_zmqhub_init_filter2()` to change promiscuity. + */ void csp_zmqhub_remove_filters(csp_iface_t * zmq_iface); + +/** + * Make `zmq_iface` unpromiscuous, only parse matching unicast and broadcast addresses. + * + * Safe to call after `csp_zmqhub_init_filter2()` to change promiscuity. + */ void csp_zmqhub_add_filters(csp_iface_t * zmq_iface); diff --git a/src/interfaces/csp_if_zmqhub.c b/src/interfaces/csp_if_zmqhub.c index 1c4c9fad6..f7b1889a2 100644 --- a/src/interfaces/csp_if_zmqhub.c +++ b/src/interfaces/csp_if_zmqhub.c @@ -252,7 +252,7 @@ void csp_zmqhub_add_filters(csp_iface_t * zmq_iface) { const uint16_t addr = zmq_iface->addr; const uint16_t hostmask = (1 << (csp_id_get_host_bits() - zmq_iface->netmask)) - 1; - /* Subscribe to all packets - no filter */ + /* Unsubscribe to all packets */ ret = zmq_setsockopt(drv->subscriber, ZMQ_UNSUBSCRIBE, NULL, 0); assert(ret == 0); From 8cc13c663c6db1d333bd1af6546d1f7fc2599770 Mon Sep 17 00:00:00 2001 From: Troels Jessen Date: Sat, 18 Oct 2025 13:47:31 +0200 Subject: [PATCH 17/24] Add function to get iface from broadcast node --- include/csp/csp_iflist.h | 1 + src/csp_iflist.c | 12 ++++++++++++ 2 files changed, 13 insertions(+) diff --git a/include/csp/csp_iflist.h b/include/csp/csp_iflist.h index 4e23b7ec0..62f4f3d9f 100644 --- a/include/csp/csp_iflist.h +++ b/include/csp/csp_iflist.h @@ -27,6 +27,7 @@ void csp_iflist_remove(csp_iface_t * ifc); csp_iface_t * csp_iflist_get_by_name(const char * name); csp_iface_t * csp_iflist_get_by_addr(uint16_t addr); +csp_iface_t * csp_iflist_get_by_broadcast(uint16_t addr); csp_iface_t * csp_iflist_get_by_subnet(uint16_t addr, csp_iface_t * from); csp_iface_t * csp_iflist_get_by_isdfl(csp_iface_t * ifc); csp_iface_t * csp_iflist_get_by_index(int idx); diff --git a/src/csp_iflist.c b/src/csp_iflist.c index 3ad071f6b..7e0272b9b 100644 --- a/src/csp_iflist.c +++ b/src/csp_iflist.c @@ -133,6 +133,18 @@ csp_iface_t * csp_iflist_get_by_addr(uint16_t addr) { } +csp_iface_t * csp_iflist_get_by_broadcast(uint16_t addr) { + + csp_iface_t * ifc = interfaces; + while (ifc) { + if (csp_id_is_broadcast(addr, ifc)) { + return ifc; + } + ifc = ifc->next; + } + return NULL; +} + csp_iface_t * csp_iflist_get_by_name(const char * name) { csp_iface_t * ifc = interfaces; while (ifc) { From aed45767f658fc6d4e489c9c9a2216616035b9cc Mon Sep 17 00:00:00 2001 From: Troels Jessen Date: Thu, 23 Oct 2025 19:29:48 +0200 Subject: [PATCH 18/24] Support for CSP alias This is used for multicast-like operations, similar to the original concept of CAN --- include/csp/csp_iflist.h | 3 +++ include/csp/csp_interface.h | 14 ++++++++++ src/csp_iflist.c | 46 ++++++++++++++++++++++++++++++++- src/csp_route.c | 4 ++- src/drivers/can/can_socketcan.c | 34 ++++++++++++++++++++++++ src/interfaces/csp_if_can.c | 2 +- 6 files changed, 100 insertions(+), 3 deletions(-) diff --git a/include/csp/csp_iflist.h b/include/csp/csp_iflist.h index 62f4f3d9f..07194a07d 100644 --- a/include/csp/csp_iflist.h +++ b/include/csp/csp_iflist.h @@ -35,6 +35,9 @@ int csp_iflist_is_within_subnet(uint16_t addr, csp_iface_t * ifc); csp_iface_t * csp_iflist_get(void); +int csp_addr_is_alias(uint16_t addr); +int csp_alias_add(csp_alias_t * addr); + /** * Convert bytes to readable string */ diff --git a/include/csp/csp_interface.h b/include/csp/csp_interface.h index 33a9f4748..b8daac3b6 100644 --- a/include/csp/csp_interface.h +++ b/include/csp/csp_interface.h @@ -19,6 +19,7 @@ extern "C" { * @return #CSP_ERR_NONE on success, otherwise an error code. */ typedef int (*nexthop_t)(csp_iface_t * iface, uint16_t via, csp_packet_t * packet, int from_me); +typedef int (*csp_alias_add_t)(void * driver_data, uint16_t addr); /** * This struct is referenced in documentation. @@ -33,6 +34,7 @@ struct csp_iface_s { void * interface_data; /**< Interface data, only known/used by the interface layer, e.g. state information. */ void * driver_data; /**< Driver data, only known/used by the driver layer, e.g. device/channel references. */ nexthop_t nexthop; /**< Next hop (Tx) function */ + csp_alias_add_t add_alias; /**< Add receive address to interface (could be multicast receptions) */ uint8_t is_default; /**< Set default IF flag (CSP supports multiple defaults) */ /* Stats */ @@ -52,6 +54,18 @@ struct csp_iface_s { }; +/** + * Used to represent an alias reception address, bound to a particular interface + */ +typedef struct csp_alias_s { + uint16_t addr; + csp_iface_t * iface; + + /* For linked lists*/ + struct csp_alias_s * next; + +} csp_alias_t; + /** * Inputs a new packet into the system. * diff --git a/src/csp_iflist.c b/src/csp_iflist.c index 7e0272b9b..ad14def6a 100644 --- a/src/csp_iflist.c +++ b/src/csp_iflist.c @@ -9,8 +9,9 @@ #include #include -/* Interfaces are stored in a linked list */ +/* Interfaces and alias receive addresses are stored in linked lists */ static csp_iface_t * interfaces = NULL; +static csp_alias_t * aliass = NULL; int csp_iflist_is_within_subnet(uint16_t addr, csp_iface_t * ifc) { @@ -101,6 +102,49 @@ csp_iface_t * csp_iflist_iterate(csp_iface_t * ifc) { } +int csp_alias_add(csp_alias_t * addr) { + + if (addr == NULL || addr->iface == NULL) { + return -1; + } + + /* Register interface for L2 filtering, if interface supports */ + if (addr->iface->add_alias) { + int result = addr->iface->add_alias(addr->iface->driver_data, addr->addr); + if (result < 0) { + return result; + } + } + + /* Add to list */ + addr->next = aliass; + aliass = addr; + + return 0; +} + +csp_alias_t * csp_alias_iterate(csp_alias_t * addr) { + + if (addr == NULL) { + addr = aliass; + } else { + addr = addr->next; + } + + return addr; +} + +int csp_addr_is_alias(uint16_t addr) { + + csp_alias_t * alias = NULL; + while ((alias = csp_alias_iterate(alias)) != NULL) { + if (addr == alias->addr) { + return 1; + } + } + return 0; +} + void csp_iflist_check_dfl(void) { csp_iface_t * iface = csp_iflist_get_by_isdfl(NULL); diff --git a/src/csp_route.c b/src/csp_route.c index 18c5f7cd2..cc79379d8 100644 --- a/src/csp_route.c +++ b/src/csp_route.c @@ -136,7 +136,9 @@ int csp_route_work(void) { /* The packet is to me, if the address matches that of any interface, * or the address matches the broadcast address of the incoming interface */ - int is_to_me = (csp_iflist_get_by_addr(packet->id.dst) != NULL || (csp_id_is_broadcast(packet->id.dst, input.iface))); + int is_to_me = ((csp_iflist_get_by_addr(packet->id.dst) != NULL || + (csp_id_is_broadcast(packet->id.dst, input.iface))) || + (csp_addr_is_alias(packet->id.dst))); /* Deduplication */ if ((csp_conf.dedup == CSP_DEDUP_ALL) || diff --git a/src/drivers/can/can_socketcan.c b/src/drivers/can/can_socketcan.c index 2aab679d2..93ae261bf 100644 --- a/src/drivers/can/can_socketcan.c +++ b/src/drivers/can/can_socketcan.c @@ -189,6 +189,39 @@ int csp_can_socketcan_set_promisc(const bool promisc, can_context_t * ctx) { return CSP_ERR_NONE; } +int csp_can_socketcan_add_alias(void * driver_data, uint16_t addr) { + + if (csp_conf.version == 1) { + return -1; + } + + can_context_t * ctx = driver_data; + + struct can_filter filter[10]; + socklen_t len = sizeof(filter); + + getsockopt(ctx->socket, SOL_CAN_RAW, CAN_RAW_FILTER, &filter, &len); + + /* Current implementation has a defined maximum of filters available */ + if (len == sizeof(filter)) { + return -2; + } + + /* If only 1 filter exist for CSP v2, interface is promisc */ + if (len == sizeof(struct can_filter)) { + return 0; + } + + /* Add filter for specific additional receive address */ + filter[len/sizeof(struct can_filter)].can_id = addr << CFP2_DST_OFFSET; + filter[len/sizeof(struct can_filter)].can_mask = CFP2_DST_MASK << CFP2_DST_OFFSET;; + + if (setsockopt(ctx->socket, SOL_CAN_RAW, CAN_RAW_FILTER, &filter, len + sizeof(struct can_filter)) < 0) { + return -2; + } + + return 0; +} int csp_can_socketcan_open_and_add_interface(const char * device, const char * ifname, unsigned int node_id, int bitrate, bool promisc, csp_iface_t ** return_iface) { if (ifname == NULL) { @@ -217,6 +250,7 @@ int csp_can_socketcan_open_and_add_interface(const char * device, const char * i ctx->iface.interface_data = &ctx->ifdata; ctx->iface.driver_data = ctx; ctx->ifdata.tx_func = csp_can_tx_frame; + ctx->iface.add_alias = csp_can_socketcan_add_alias; ctx->ifdata.pbufs = NULL; /* Create socket */ diff --git a/src/interfaces/csp_if_can.c b/src/interfaces/csp_if_can.c index 617abeca2..133e2a734 100644 --- a/src/interfaces/csp_if_can.c +++ b/src/interfaces/csp_if_can.c @@ -368,7 +368,7 @@ int csp_can2_rx(csp_iface_t * iface, uint32_t id, const uint8_t * data, uint8_t int csp_can2_tx(csp_iface_t * iface, uint16_t via, csp_packet_t * packet, int from_me) { /* Loopback */ - if (packet->id.dst == iface->addr) { + if (packet->id.dst == iface->addr || csp_addr_is_alias(packet->id.dst)) { csp_qfifo_write(packet, iface, NULL); return CSP_ERR_NONE; } From 5a95e5c48826c3602bf4a34aa5d60e2af9e4a004 Mon Sep 17 00:00:00 2001 From: Troels Jessen Date: Mon, 3 Nov 2025 18:11:18 +0100 Subject: [PATCH 19/24] Add alias support to ZMQ --- src/interfaces/csp_if_zmqhub.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/interfaces/csp_if_zmqhub.c b/src/interfaces/csp_if_zmqhub.c index f7b1889a2..56ed65eba 100644 --- a/src/interfaces/csp_if_zmqhub.c +++ b/src/interfaces/csp_if_zmqhub.c @@ -245,6 +245,20 @@ void csp_zmqhub_remove_filters(csp_iface_t * zmq_iface) { (void)ret; } +int csp_zmqhub_add_filter(void * driver_data, uint16_t addr) { + + int ret = 0; + zmq_driver_t * drv = (zmq_driver_t*)driver_data; + + /* Subscribe to an extra address, typically registered by alias address */ + for (int i = 0; i < 4; i++) { + uint16_t filter = __builtin_bswap16((i << 14) | addr); + ret = zmq_setsockopt(drv->subscriber, ZMQ_SUBSCRIBE, &filter, 2); + assert(ret == 0); + } + return ret; +} + void csp_zmqhub_add_filters(csp_iface_t * zmq_iface) { int ret = 0; @@ -300,6 +314,7 @@ int csp_zmqhub_init_filter2(const char * ifname, const char * host, uint16_t add drv->iface.name = drv->name; drv->iface.driver_data = drv; drv->iface.nexthop = csp_zmqhub_tx; + drv->iface.add_alias = csp_zmqhub_add_filter; drv->iface.addr = addr; drv->iface.netmask = netmask; From 3bc0c2d18a9f17969f7703af481693c1b94aba73 Mon Sep 17 00:00:00 2001 From: Troels Jessen Date: Thu, 13 Nov 2025 16:47:58 +0100 Subject: [PATCH 20/24] Strip default options not read until meson 1.8 --- meson.build | 2 -- 1 file changed, 2 deletions(-) diff --git a/meson.build b/meson.build index 055a87d38..c5b60a1c1 100644 --- a/meson.build +++ b/meson.build @@ -1,6 +1,4 @@ project('csp', 'c', version: '2.1', license: 'LGPL', meson_version : '>=0.53.2', default_options : [ - 'c_std=gnu11', - 'optimization=s', 'warning_level=2', 'werror=true']) From 289cbcddaa2fe47974b495a258b6d7f6fa1a44b4 Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Lab Date: Thu, 4 Dec 2025 09:38:32 +0100 Subject: [PATCH 21/24] Update meson build to generate pkg-config files when installing Currently, installing CSP through meson does not allow other modules to use the installed version as it does not generate the required pkg-config files. --- meson.build | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/meson.build b/meson.build index c5b60a1c1..e46d1b36e 100644 --- a/meson.build +++ b/meson.build @@ -67,18 +67,12 @@ csp_c_args = ['-Wshadow', subdir('src') subdir('include/csp') -if not meson.is_subproject() - install_subdir('include', install_dir : '.') - install_headers(csp_config_h, install_dir : 'include/csp') -endif - - csp_lib = library('csp', sources: [csp_sources, csp_config_h], include_directories : csp_inc, dependencies : csp_deps, c_args : csp_c_args, - install : false, + install : true, pic:true, ) @@ -90,6 +84,10 @@ csp_dep = declare_dependency( dependencies : csp_deps, ) +install_subdir('include', install_dir : '.', exclude_files: ['csp/meson.build']) +pkg = import('pkgconfig') +pkg.generate(csp_lib) + subdir('examples') if get_option('enable_python3_bindings') From fb9d552d7b2f205589e1d52a747ad1eb86ab20b1 Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Lab Date: Thu, 4 Dec 2025 10:30:11 +0100 Subject: [PATCH 22/24] Update to use meson installation tags "runtime" will install the shared library only, "devel" will install the static library, headers and pkg-config files --- include/csp/meson.build | 2 +- meson.build | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/include/csp/meson.build b/include/csp/meson.build index ecf86b5a5..9511c2864 100644 --- a/include/csp/meson.build +++ b/include/csp/meson.build @@ -1 +1 @@ -csp_config_h = configure_file(output: 'autoconfig.h', configuration: conf, install_dir: 'include/csp/') +csp_config_h = configure_file(output: 'autoconfig.h', configuration: conf, install_dir: 'include/csp/', install_tag: 'devel') diff --git a/meson.build b/meson.build index e46d1b36e..2df8ea11b 100644 --- a/meson.build +++ b/meson.build @@ -83,8 +83,7 @@ csp_dep = declare_dependency( link_with : csp_lib, dependencies : csp_deps, ) - -install_subdir('include', install_dir : '.', exclude_files: ['csp/meson.build']) +install_subdir('include', install_dir : '.', exclude_files: ['csp/meson.build'], install_tag: 'devel') pkg = import('pkgconfig') pkg.generate(csp_lib) From 52c9da1c1caad6d4829bfea6398e8d9bca24fb72 Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Lab Date: Fri, 19 Dec 2025 14:00:21 +0100 Subject: [PATCH 23/24] Compile cleanly on both ARM and x86 --- src/interfaces/csp_if_zmqhub.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/interfaces/csp_if_zmqhub.c b/src/interfaces/csp_if_zmqhub.c index 56ed65eba..0a8bcdc7d 100644 --- a/src/interfaces/csp_if_zmqhub.c +++ b/src/interfaces/csp_if_zmqhub.c @@ -291,7 +291,7 @@ int csp_zmqhub_init_filter2(const char * ifname, const char * host, uint16_t add const ssize_t sec_key_len = sec_key ? strnlen(sec_key, CURVE_KEYLEN-1) : 0; if (sec_key_len && sec_key_len != CURVE_KEYLEN-1) { /* Is it bad to expose the detected length of the ZMQ key here? */ - fprintf(stderr, "ZMQ secret key must be exactly 40 characters long (got %ld)\n", sec_key_len); + fprintf(stderr, "ZMQ secret key must be exactly 40 characters long (got %ld)\n", (signed long)sec_key_len); return CSP_ERR_INVAL; } From f3089f4811e750f0b3d0af91fbe4af1e04f3a158 Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Lab Date: Fri, 19 Dec 2025 14:01:04 +0100 Subject: [PATCH 24/24] Use soname meson feature --- meson.build | 1 + 1 file changed, 1 insertion(+) diff --git a/meson.build b/meson.build index 2df8ea11b..1b811aef2 100644 --- a/meson.build +++ b/meson.build @@ -74,6 +74,7 @@ csp_lib = library('csp', c_args : csp_c_args, install : true, pic:true, + soversion: meson.project_version() ) # The following dependency variable is for parent projects to link