diff options
| author | Peter Marko <peter.marko@siemens.com> | 2025-03-06 22:28:47 +0100 |
|---|---|---|
| committer | Armin Kuster <akuster808@gmail.com> | 2025-03-20 09:56:59 -0400 |
| commit | d5fb81cbfb9c4f0893daf8fca5d5a471768a5172 (patch) | |
| tree | 1572bd5978c65a93a86e8e6cfb37c9ff92829613 /meta-oe | |
| parent | 7e18b3fc774b7efabf9a20ae3cd6abd0e0715b59 (diff) | |
| download | meta-openembedded-d5fb81cbfb9c4f0893daf8fca5d5a471768a5172.tar.gz | |
libmodbus: patch CVE-2024-10918
Pick commit mentioning the bug and two follow-up commits mentioning the
first commit.
Tested by running the test-suite (test starter scripts were copied from
scarthgap version which has them working).
Signed-off-by: Peter Marko <peter.marko@siemens.com>
Signed-off-by: Armin Kuster <akuster808@gmail.com>
Diffstat (limited to 'meta-oe')
4 files changed, 518 insertions, 1 deletions
diff --git a/meta-oe/recipes-extended/libmodbus/libmodbus.inc b/meta-oe/recipes-extended/libmodbus/libmodbus.inc index 0857cc455b..62252a39d2 100644 --- a/meta-oe/recipes-extended/libmodbus/libmodbus.inc +++ b/meta-oe/recipes-extended/libmodbus/libmodbus.inc | |||
| @@ -8,7 +8,12 @@ SECTION = "libs" | |||
| 8 | LICENSE = "LGPL-2.1-or-later" | 8 | LICENSE = "LGPL-2.1-or-later" |
| 9 | LIC_FILES_CHKSUM = "file://COPYING.LESSER;md5=4fbd65380cdd255951079008b364516c" | 9 | LIC_FILES_CHKSUM = "file://COPYING.LESSER;md5=4fbd65380cdd255951079008b364516c" |
| 10 | 10 | ||
| 11 | SRC_URI = "http://libmodbus.org/releases/${BP}.tar.gz" | 11 | SRC_URI = " \ |
| 12 | http://libmodbus.org/releases/${BP}.tar.gz \ | ||
| 13 | file://CVE-2024-10918-01.patch \ | ||
| 14 | file://CVE-2024-10918-02.patch \ | ||
| 15 | file://CVE-2024-10918-03.patch \ | ||
| 16 | " | ||
| 12 | 17 | ||
| 13 | PACKAGECONFIG ??= "" | 18 | PACKAGECONFIG ??= "" |
| 14 | PACKAGECONFIG[documentation] = "--with-documentation,--without-documentation,asciidoc-native xmlto-native" | 19 | PACKAGECONFIG[documentation] = "--with-documentation,--without-documentation,asciidoc-native xmlto-native" |
diff --git a/meta-oe/recipes-extended/libmodbus/libmodbus/CVE-2024-10918-01.patch b/meta-oe/recipes-extended/libmodbus/libmodbus/CVE-2024-10918-01.patch new file mode 100644 index 0000000000..ae7c920525 --- /dev/null +++ b/meta-oe/recipes-extended/libmodbus/libmodbus/CVE-2024-10918-01.patch | |||
| @@ -0,0 +1,159 @@ | |||
| 1 | From df79a02feb253c0a9a009bcdbb21e47581315111 Mon Sep 17 00:00:00 2001 | ||
| 2 | From: =?UTF-8?q?St=C3=A9phane=20Raimbault?= <stephane.raimbault@gmail.com> | ||
| 3 | Date: Fri, 18 Oct 2024 10:47:14 +0200 | ||
| 4 | Subject: [PATCH] Check length passed to modbus_reply (write_bit) | ||
| 5 | |||
| 6 | The modbus_reply function is designed to receive arguments | ||
| 7 | from modbus_receive. This patch avoid a wrong use of memcpy if | ||
| 8 | the user chooses to inject a bad length argument. | ||
| 9 | |||
| 10 | Thank you Nozomi Networks Labs Advisory for the report. | ||
| 11 | |||
| 12 | CVE: CVE-2024-10918 | ||
| 13 | Upstream-Status: Backport [https://github.com/stephane/libmodbus/commit/df79a02feb253c0a9a009bcdbb21e47581315111] | ||
| 14 | Signed-off-by: Peter Marko <peter.marko@siemens.com> | ||
| 15 | --- | ||
| 16 | src/modbus.c | 42 ++++++++++++++++++++++++++-------------- | ||
| 17 | tests/unit-test-client.c | 9 +++++++-- | ||
| 18 | tests/unit-test-server.c | 16 ++++++++++++--- | ||
| 19 | tests/unit-test.h.in | 1 + | ||
| 20 | 4 files changed, 49 insertions(+), 19 deletions(-) | ||
| 21 | |||
| 22 | diff --git a/src/modbus.c b/src/modbus.c | ||
| 23 | index 5a9b867..33086ec 100644 | ||
| 24 | --- a/src/modbus.c | ||
| 25 | +++ b/src/modbus.c | ||
| 26 | @@ -802,20 +802,33 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req, | ||
| 27 | ctx, &sft, MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS, rsp, FALSE, | ||
| 28 | "Illegal data address 0x%0X in write_bit\n", | ||
| 29 | address); | ||
| 30 | + break; | ||
| 31 | + } | ||
| 32 | + | ||
| 33 | + /* This check is only done here to ensure using memcpy is safe. */ | ||
| 34 | + rsp_length = compute_response_length_from_request(ctx, (uint8_t *) req); | ||
| 35 | + if (rsp_length != req_length) { | ||
| 36 | + /* Bad use of modbus_reply */ | ||
| 37 | + rsp_length = response_exception(ctx, | ||
| 38 | + &sft, | ||
| 39 | + MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE, | ||
| 40 | + rsp, | ||
| 41 | + FALSE, | ||
| 42 | + "Invalid request length (%d)\n", | ||
| 43 | + req_length); | ||
| 44 | + break; | ||
| 45 | + } | ||
| 46 | + | ||
| 47 | + int data = (req[offset + 3] << 8) + req[offset + 4]; | ||
| 48 | + if (data == 0xFF00 || data == 0x0) { | ||
| 49 | + mb_mapping->tab_bits[mapping_address] = data ? ON : OFF; | ||
| 50 | + memcpy(rsp, req, rsp_length); | ||
| 51 | } else { | ||
| 52 | - int data = (req[offset + 3] << 8) + req[offset + 4]; | ||
| 53 | - | ||
| 54 | - if (data == 0xFF00 || data == 0x0) { | ||
| 55 | - mb_mapping->tab_bits[mapping_address] = data ? ON : OFF; | ||
| 56 | - memcpy(rsp, req, req_length); | ||
| 57 | - rsp_length = req_length; | ||
| 58 | - } else { | ||
| 59 | - rsp_length = response_exception( | ||
| 60 | - ctx, &sft, | ||
| 61 | - MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE, rsp, FALSE, | ||
| 62 | - "Illegal data value 0x%0X in write_bit request at address %0X\n", | ||
| 63 | - data, address); | ||
| 64 | - } | ||
| 65 | + rsp_length = response_exception( | ||
| 66 | + ctx, &sft, | ||
| 67 | + MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE, rsp, FALSE, | ||
| 68 | + "Illegal data value 0x%0X in write_bit request at address %0X\n", | ||
| 69 | + data, address); | ||
| 70 | } | ||
| 71 | } | ||
| 72 | break; | ||
| 73 | @@ -1687,7 +1700,8 @@ int modbus_set_byte_timeout(modbus_t *ctx, uint32_t to_sec, uint32_t to_usec) | ||
| 74 | return 0; | ||
| 75 | } | ||
| 76 | |||
| 77 | -/* Get the timeout interval used by the server to wait for an indication from a client */ | ||
| 78 | +/* Get the timeout interval used by the server to wait for an indication from a client | ||
| 79 | + */ | ||
| 80 | int modbus_get_indication_timeout(modbus_t *ctx, uint32_t *to_sec, uint32_t *to_usec) | ||
| 81 | { | ||
| 82 | if (ctx == NULL) { | ||
| 83 | diff --git a/tests/unit-test-client.c b/tests/unit-test-client.c | ||
| 84 | index a441766..50859f8 100644 | ||
| 85 | --- a/tests/unit-test-client.c | ||
| 86 | +++ b/tests/unit-test-client.c | ||
| 87 | @@ -362,12 +362,12 @@ int main(int argc, char *argv[]) | ||
| 88 | ASSERT_TRUE(rc == -1 && errno == EMBXILADD, ""); | ||
| 89 | |||
| 90 | rc = modbus_write_bits(ctx, 0, 1, tab_rp_bits); | ||
| 91 | - printf("* modbus_write_coils (0): "); | ||
| 92 | + printf("* modbus_write_bits (0): "); | ||
| 93 | ASSERT_TRUE(rc == -1 && errno == EMBXILADD, ""); | ||
| 94 | |||
| 95 | rc = modbus_write_bits(ctx, UT_BITS_ADDRESS + UT_BITS_NB, | ||
| 96 | UT_BITS_NB, tab_rp_bits); | ||
| 97 | - printf("* modbus_write_coils (max): "); | ||
| 98 | + printf("* modbus_write_bits (max): "); | ||
| 99 | ASSERT_TRUE(rc == -1 && errno == EMBXILADD, ""); | ||
| 100 | |||
| 101 | rc = modbus_write_register(ctx, 0, tab_rp_registers[0]); | ||
| 102 | @@ -445,6 +445,11 @@ int main(int argc, char *argv[]) | ||
| 103 | printf("* modbus_write_registers: "); | ||
| 104 | ASSERT_TRUE(rc == -1 && errno == EMBMDATA, ""); | ||
| 105 | |||
| 106 | + | ||
| 107 | + /** BAD USE OF REPLY FUNCTION **/ | ||
| 108 | + rc = modbus_write_bit(ctx, UT_BITS_ADDRESS_INVALID_REQUEST_LENGTH, ON); | ||
| 109 | + printf("* modbus_write_bit (triggers invalid reply): "); | ||
| 110 | + ASSERT_TRUE(rc == -1 && errno == EMBXILVAL, ""); | ||
| 111 | /** SLAVE REPLY **/ | ||
| 112 | old_slave = modbus_get_slave(ctx); | ||
| 113 | |||
| 114 | diff --git a/tests/unit-test-server.c b/tests/unit-test-server.c | ||
| 115 | index 561d64d..8e28124 100644 | ||
| 116 | --- a/tests/unit-test-server.c | ||
| 117 | +++ b/tests/unit-test-server.c | ||
| 118 | @@ -123,9 +123,8 @@ int main(int argc, char*argv[]) | ||
| 119 | break; | ||
| 120 | } | ||
| 121 | |||
| 122 | - /* Special server behavior to test client */ | ||
| 123 | - if (query[header_length] == 0x03) { | ||
| 124 | - /* Read holding registers */ | ||
| 125 | + /** Special server behavior to test client **/ | ||
| 126 | + if (query[header_length] == MODBUS_FC_READ_HOLDING_REGISTERS) { | ||
| 127 | |||
| 128 | if (MODBUS_GET_INT16_FROM_INT8(query, header_length + 3) | ||
| 129 | == UT_REGISTERS_NB_SPECIAL) { | ||
| 130 | @@ -178,6 +177,17 @@ int main(int argc, char*argv[]) | ||
| 131 | } | ||
| 132 | continue; | ||
| 133 | } | ||
| 134 | + | ||
| 135 | + } else if (query[header_length] == MODBUS_FC_WRITE_SINGLE_COIL) { | ||
| 136 | + if (MODBUS_GET_INT16_FROM_INT8(query, header_length + 1) == | ||
| 137 | + UT_BITS_ADDRESS_INVALID_REQUEST_LENGTH) { | ||
| 138 | + // The valid length is lengths of header + checkum + FC + address + value | ||
| 139 | + // (max 12) | ||
| 140 | + rc = 34; | ||
| 141 | + printf("Special modbus_write_bit detected. Inject a wrong rc value (%d) " | ||
| 142 | + "in modbus_reply\n", | ||
| 143 | + rc); | ||
| 144 | + } | ||
| 145 | } | ||
| 146 | |||
| 147 | rc = modbus_reply(ctx, query, rc, mb_mapping); | ||
| 148 | diff --git a/tests/unit-test.h.in b/tests/unit-test.h.in | ||
| 149 | index 5e379bb..21d09e3 100644 | ||
| 150 | --- a/tests/unit-test.h.in | ||
| 151 | +++ b/tests/unit-test.h.in | ||
| 152 | @@ -28,6 +28,7 @@ | ||
| 153 | const uint16_t UT_BITS_ADDRESS = 0x130; | ||
| 154 | const uint16_t UT_BITS_NB = 0x25; | ||
| 155 | const uint8_t UT_BITS_TAB[] = { 0xCD, 0x6B, 0xB2, 0x0E, 0x1B }; | ||
| 156 | +const uint16_t UT_BITS_ADDRESS_INVALID_REQUEST_LENGTH = UT_BITS_ADDRESS + 2; | ||
| 157 | |||
| 158 | const uint16_t UT_INPUT_BITS_ADDRESS = 0x1C4; | ||
| 159 | const uint16_t UT_INPUT_BITS_NB = 0x16; | ||
diff --git a/meta-oe/recipes-extended/libmodbus/libmodbus/CVE-2024-10918-02.patch b/meta-oe/recipes-extended/libmodbus/libmodbus/CVE-2024-10918-02.patch new file mode 100644 index 0000000000..6f304a337a --- /dev/null +++ b/meta-oe/recipes-extended/libmodbus/libmodbus/CVE-2024-10918-02.patch | |||
| @@ -0,0 +1,113 @@ | |||
| 1 | From d8a971e04d52be16bf405b51d934a30b8aa3f2c3 Mon Sep 17 00:00:00 2001 | ||
| 2 | From: =?UTF-8?q?St=C3=A9phane=20Raimbault?= <stephane.raimbault@gmail.com> | ||
| 3 | Date: Sun, 20 Oct 2024 18:02:22 +0200 | ||
| 4 | Subject: [PATCH] Check length passed to modbus_reply (write_register) | ||
| 5 | |||
| 6 | Related to df79a02feb253c. | ||
| 7 | |||
| 8 | CVE: CVE-2024-10918 | ||
| 9 | Upstream-Status: Backport [https://github.com/stephane/libmodbus/commit/d8a971e04d52be16bf405b51d934a30b8aa3f2c3] | ||
| 10 | Signed-off-by: Peter Marko <peter.marko@siemens.com> | ||
| 11 | --- | ||
| 12 | src/modbus.c | 38 ++++++++++++++++++++++++++------------ | ||
| 13 | tests/unit-test-client.c | 4 ++++ | ||
| 14 | tests/unit-test-server.c | 13 +++++++++++-- | ||
| 15 | 3 files changed, 41 insertions(+), 14 deletions(-) | ||
| 16 | |||
| 17 | diff --git a/src/modbus.c b/src/modbus.c | ||
| 18 | index 33086ec..fe192a7 100644 | ||
| 19 | --- a/src/modbus.c | ||
| 20 | +++ b/src/modbus.c | ||
| 21 | @@ -809,13 +809,14 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req, | ||
| 22 | rsp_length = compute_response_length_from_request(ctx, (uint8_t *) req); | ||
| 23 | if (rsp_length != req_length) { | ||
| 24 | /* Bad use of modbus_reply */ | ||
| 25 | - rsp_length = response_exception(ctx, | ||
| 26 | - &sft, | ||
| 27 | - MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE, | ||
| 28 | - rsp, | ||
| 29 | - FALSE, | ||
| 30 | - "Invalid request length (%d)\n", | ||
| 31 | - req_length); | ||
| 32 | + rsp_length = | ||
| 33 | + response_exception(ctx, | ||
| 34 | + &sft, | ||
| 35 | + MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE, | ||
| 36 | + rsp, | ||
| 37 | + FALSE, | ||
| 38 | + "Invalid request length used in modbus_reply (%d)\n", | ||
| 39 | + req_length); | ||
| 40 | break; | ||
| 41 | } | ||
| 42 | |||
| 43 | @@ -841,13 +842,26 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req, | ||
| 44 | MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS, rsp, FALSE, | ||
| 45 | "Illegal data address 0x%0X in write_register\n", | ||
| 46 | address); | ||
| 47 | - } else { | ||
| 48 | - int data = (req[offset + 3] << 8) + req[offset + 4]; | ||
| 49 | + break; | ||
| 50 | + } | ||
| 51 | |||
| 52 | - mb_mapping->tab_registers[mapping_address] = data; | ||
| 53 | - memcpy(rsp, req, req_length); | ||
| 54 | - rsp_length = req_length; | ||
| 55 | + rsp_length = compute_response_length_from_request(ctx, (uint8_t *) req); | ||
| 56 | + if (rsp_length != req_length) { | ||
| 57 | + /* Bad use of modbus_reply */ | ||
| 58 | + rsp_length = | ||
| 59 | + response_exception(ctx, | ||
| 60 | + &sft, | ||
| 61 | + MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE, | ||
| 62 | + rsp, | ||
| 63 | + FALSE, | ||
| 64 | + "Invalid request length used in modbus_reply (%d)\n", | ||
| 65 | + req_length); | ||
| 66 | + break; | ||
| 67 | } | ||
| 68 | + int data = (req[offset + 3] << 8) + req[offset + 4]; | ||
| 69 | + | ||
| 70 | + mb_mapping->tab_registers[mapping_address] = data; | ||
| 71 | + memcpy(rsp, req, rsp_length); | ||
| 72 | } | ||
| 73 | break; | ||
| 74 | case MODBUS_FC_WRITE_MULTIPLE_COILS: { | ||
| 75 | diff --git a/tests/unit-test-client.c b/tests/unit-test-client.c | ||
| 76 | index 50859f8..84d5840 100644 | ||
| 77 | --- a/tests/unit-test-client.c | ||
| 78 | +++ b/tests/unit-test-client.c | ||
| 79 | @@ -450,6 +450,10 @@ int main(int argc, char *argv[]) | ||
| 80 | rc = modbus_write_bit(ctx, UT_BITS_ADDRESS_INVALID_REQUEST_LENGTH, ON); | ||
| 81 | printf("* modbus_write_bit (triggers invalid reply): "); | ||
| 82 | ASSERT_TRUE(rc == -1 && errno == EMBXILVAL, ""); | ||
| 83 | + | ||
| 84 | + rc = modbus_write_register(ctx, UT_REGISTERS_ADDRESS_SPECIAL, 0x42); | ||
| 85 | + printf("* modbus_write_register (triggers invalid reply): "); | ||
| 86 | + ASSERT_TRUE(rc == -1 && errno == EMBXILVAL, ""); | ||
| 87 | /** SLAVE REPLY **/ | ||
| 88 | old_slave = modbus_get_slave(ctx); | ||
| 89 | |||
| 90 | diff --git a/tests/unit-test-server.c b/tests/unit-test-server.c | ||
| 91 | index 8e28124..fc7ceb3 100644 | ||
| 92 | --- a/tests/unit-test-server.c | ||
| 93 | +++ b/tests/unit-test-server.c | ||
| 94 | @@ -184,8 +184,17 @@ int main(int argc, char*argv[]) | ||
| 95 | // The valid length is lengths of header + checkum + FC + address + value | ||
| 96 | // (max 12) | ||
| 97 | rc = 34; | ||
| 98 | - printf("Special modbus_write_bit detected. Inject a wrong rc value (%d) " | ||
| 99 | - "in modbus_reply\n", | ||
| 100 | + printf( | ||
| 101 | + "Special modbus_write_bit detected. Inject a wrong length value (%d) " | ||
| 102 | + "in modbus_reply\n", | ||
| 103 | + rc); | ||
| 104 | + } | ||
| 105 | + } else if (query[header_length] == MODBUS_FC_WRITE_SINGLE_REGISTER) { | ||
| 106 | + if (MODBUS_GET_INT16_FROM_INT8(query, header_length + 1) == | ||
| 107 | + UT_REGISTERS_ADDRESS_SPECIAL) { | ||
| 108 | + rc = 45; | ||
| 109 | + printf("Special modbus_write_register detected. Inject a wrong length " | ||
| 110 | + "value (%d) in modbus_reply\n", | ||
| 111 | rc); | ||
| 112 | } | ||
| 113 | } | ||
diff --git a/meta-oe/recipes-extended/libmodbus/libmodbus/CVE-2024-10918-03.patch b/meta-oe/recipes-extended/libmodbus/libmodbus/CVE-2024-10918-03.patch new file mode 100644 index 0000000000..ccc9cfa379 --- /dev/null +++ b/meta-oe/recipes-extended/libmodbus/libmodbus/CVE-2024-10918-03.patch | |||
| @@ -0,0 +1,240 @@ | |||
| 1 | From 81bf713cf029bfa5b5da87b945c1e8817b4398f9 Mon Sep 17 00:00:00 2001 | ||
| 2 | From: =?UTF-8?q?St=C3=A9phane=20Raimbault?= <stephane.raimbault@gmail.com> | ||
| 3 | Date: Mon, 21 Oct 2024 17:32:39 +0200 | ||
| 4 | Subject: [PATCH] Fix request length check in modbus_reply in RTU | ||
| 5 | |||
| 6 | - rename internal *_prepare_response_tid to *_get_response_tid | ||
| 7 | - change signature, don't need req length anymore | ||
| 8 | - remove misleading modification of req_length | ||
| 9 | - check of req length before use in memcpy for mask write register | ||
| 10 | |||
| 11 | Related to df79a02feb253c0a9a009bcdbb21e47581315111 | ||
| 12 | |||
| 13 | CVE: CVE-2024-10918 | ||
| 14 | Upstream-Status: Backport [https://github.com/stephane/libmodbus/commit/81bf713cf029bfa5b5da87b945c1e8817b4398f9] | ||
| 15 | Signed-off-by: Peter Marko <peter.marko@siemens.com> | ||
| 16 | --- | ||
| 17 | src/modbus-private.h | 2 +- | ||
| 18 | src/modbus-rtu.c | 5 ++-- | ||
| 19 | src/modbus-tcp.c | 7 ++--- | ||
| 20 | src/modbus.c | 71 ++++++++++++++++++++++++++++---------------- | ||
| 21 | 4 files changed, 52 insertions(+), 33 deletions(-) | ||
| 22 | |||
| 23 | diff --git a/src/modbus-private.h b/src/modbus-private.h | ||
| 24 | index 6cd3424..ea83187 100644 | ||
| 25 | --- a/src/modbus-private.h | ||
| 26 | +++ b/src/modbus-private.h | ||
| 27 | @@ -73,7 +73,7 @@ typedef struct _modbus_backend { | ||
| 28 | int (*build_request_basis) (modbus_t *ctx, int function, int addr, | ||
| 29 | int nb, uint8_t *req); | ||
| 30 | int (*build_response_basis) (sft_t *sft, uint8_t *rsp); | ||
| 31 | - int (*prepare_response_tid) (const uint8_t *req, int *req_length); | ||
| 32 | + int (*get_response_tid)(const uint8_t *req); | ||
| 33 | int (*send_msg_pre) (uint8_t *req, int req_length); | ||
| 34 | ssize_t (*send) (modbus_t *ctx, const uint8_t *req, int req_length); | ||
| 35 | int (*receive) (modbus_t *ctx, uint8_t *req); | ||
| 36 | diff --git a/src/modbus-rtu.c b/src/modbus-rtu.c | ||
| 37 | index b774923..8b5ee08 100644 | ||
| 38 | --- a/src/modbus-rtu.c | ||
| 39 | +++ b/src/modbus-rtu.c | ||
| 40 | @@ -145,9 +145,8 @@ static uint16_t crc16(uint8_t *buffer, uint16_t buffer_length) | ||
| 41 | return (crc_hi << 8 | crc_lo); | ||
| 42 | } | ||
| 43 | |||
| 44 | -static int _modbus_rtu_prepare_response_tid(const uint8_t *req, int *req_length) | ||
| 45 | +static int _modbus_rtu_get_response_tid(const uint8_t *req) | ||
| 46 | { | ||
| 47 | - (*req_length) -= _MODBUS_RTU_CHECKSUM_LENGTH; | ||
| 48 | /* No TID */ | ||
| 49 | return 0; | ||
| 50 | } | ||
| 51 | @@ -1204,7 +1203,7 @@ const modbus_backend_t _modbus_rtu_backend = { | ||
| 52 | _modbus_set_slave, | ||
| 53 | _modbus_rtu_build_request_basis, | ||
| 54 | _modbus_rtu_build_response_basis, | ||
| 55 | - _modbus_rtu_prepare_response_tid, | ||
| 56 | + _modbus_rtu_get_response_tid, | ||
| 57 | _modbus_rtu_send_msg_pre, | ||
| 58 | _modbus_rtu_send, | ||
| 59 | _modbus_rtu_receive, | ||
| 60 | diff --git a/src/modbus-tcp.c b/src/modbus-tcp.c | ||
| 61 | index f8ef4e8..4ee82a7 100644 | ||
| 62 | --- a/src/modbus-tcp.c | ||
| 63 | +++ b/src/modbus-tcp.c | ||
| 64 | @@ -146,8 +146,7 @@ static int _modbus_tcp_build_response_basis(sft_t *sft, uint8_t *rsp) | ||
| 65 | return _MODBUS_TCP_PRESET_RSP_LENGTH; | ||
| 66 | } | ||
| 67 | |||
| 68 | - | ||
| 69 | -static int _modbus_tcp_prepare_response_tid(const uint8_t *req, int *req_length) | ||
| 70 | +static int _modbus_tcp_get_response_tid(const uint8_t *req) | ||
| 71 | { | ||
| 72 | return (req[0] << 8) + req[1]; | ||
| 73 | } | ||
| 74 | @@ -752,7 +751,7 @@ const modbus_backend_t _modbus_tcp_backend = { | ||
| 75 | _modbus_set_slave, | ||
| 76 | _modbus_tcp_build_request_basis, | ||
| 77 | _modbus_tcp_build_response_basis, | ||
| 78 | - _modbus_tcp_prepare_response_tid, | ||
| 79 | + _modbus_tcp_get_response_tid, | ||
| 80 | _modbus_tcp_send_msg_pre, | ||
| 81 | _modbus_tcp_send, | ||
| 82 | _modbus_tcp_receive, | ||
| 83 | @@ -775,7 +774,7 @@ const modbus_backend_t _modbus_tcp_pi_backend = { | ||
| 84 | _modbus_set_slave, | ||
| 85 | _modbus_tcp_build_request_basis, | ||
| 86 | _modbus_tcp_build_response_basis, | ||
| 87 | - _modbus_tcp_prepare_response_tid, | ||
| 88 | + _modbus_tcp_get_response_tid, | ||
| 89 | _modbus_tcp_send_msg_pre, | ||
| 90 | _modbus_tcp_send, | ||
| 91 | _modbus_tcp_receive, | ||
| 92 | diff --git a/src/modbus.c b/src/modbus.c | ||
| 93 | index fe192a7..e3737bb 100644 | ||
| 94 | --- a/src/modbus.c | ||
| 95 | +++ b/src/modbus.c | ||
| 96 | @@ -125,7 +125,7 @@ int modbus_flush(modbus_t *ctx) | ||
| 97 | return rc; | ||
| 98 | } | ||
| 99 | |||
| 100 | -/* Computes the length of the expected response */ | ||
| 101 | +/* Computes the length of the expected response including checksum */ | ||
| 102 | static unsigned int compute_response_length_from_request(modbus_t *ctx, uint8_t *req) | ||
| 103 | { | ||
| 104 | int length; | ||
| 105 | @@ -366,8 +366,7 @@ int _modbus_receive_msg(modbus_t *ctx, uint8_t *msg, msg_type_t msg_type) | ||
| 106 | length_to_read = ctx->backend->header_length + 1; | ||
| 107 | |||
| 108 | if (msg_type == MSG_INDICATION) { | ||
| 109 | - /* Wait for a message, we don't know when the message will be | ||
| 110 | - * received */ | ||
| 111 | + /* Wait for a message, we don't know when the message will be received */ | ||
| 112 | if (ctx->indication_timeout.tv_sec == 0 && ctx->indication_timeout.tv_usec == 0) { | ||
| 113 | /* By default, the indication timeout isn't set */ | ||
| 114 | p_tv = NULL; | ||
| 115 | @@ -725,7 +724,7 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req, | ||
| 116 | |||
| 117 | sft.slave = slave; | ||
| 118 | sft.function = function; | ||
| 119 | - sft.t_id = ctx->backend->prepare_response_tid(req, &req_length); | ||
| 120 | + sft.t_id = ctx->backend->get_response_tid(req); | ||
| 121 | |||
| 122 | /* Data are flushed on illegal number of values errors. */ | ||
| 123 | switch (function) { | ||
| 124 | @@ -800,7 +799,7 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req, | ||
| 125 | if (mapping_address < 0 || mapping_address >= mb_mapping->nb_bits) { | ||
| 126 | rsp_length = response_exception( | ||
| 127 | ctx, &sft, MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS, rsp, FALSE, | ||
| 128 | - "Illegal data address 0x%0X in write_bit\n", | ||
| 129 | + "Illegal data address 0x%0X in write bit\n", | ||
| 130 | address); | ||
| 131 | break; | ||
| 132 | } | ||
| 133 | @@ -809,20 +808,26 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req, | ||
| 134 | rsp_length = compute_response_length_from_request(ctx, (uint8_t *) req); | ||
| 135 | if (rsp_length != req_length) { | ||
| 136 | /* Bad use of modbus_reply */ | ||
| 137 | - rsp_length = | ||
| 138 | - response_exception(ctx, | ||
| 139 | - &sft, | ||
| 140 | - MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE, | ||
| 141 | - rsp, | ||
| 142 | - FALSE, | ||
| 143 | - "Invalid request length used in modbus_reply (%d)\n", | ||
| 144 | - req_length); | ||
| 145 | + rsp_length = response_exception( | ||
| 146 | + ctx, | ||
| 147 | + &sft, | ||
| 148 | + MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE, | ||
| 149 | + rsp, | ||
| 150 | + FALSE, | ||
| 151 | + "Invalid request length in modbus_reply to write bit (%d)\n", | ||
| 152 | + req_length); | ||
| 153 | break; | ||
| 154 | } | ||
| 155 | |||
| 156 | + /* Don't copy the CRC, if any, it will be computed later (even if identical to the | ||
| 157 | + * request) */ | ||
| 158 | + rsp_length -= ctx->backend->checksum_length; | ||
| 159 | + | ||
| 160 | int data = (req[offset + 3] << 8) + req[offset + 4]; | ||
| 161 | if (data == 0xFF00 || data == 0x0) { | ||
| 162 | + /* Apply the change to mapping */ | ||
| 163 | mb_mapping->tab_bits[mapping_address] = data ? ON : OFF; | ||
| 164 | + /* Prepare response */ | ||
| 165 | memcpy(rsp, req, rsp_length); | ||
| 166 | } else { | ||
| 167 | rsp_length = response_exception( | ||
| 168 | @@ -848,19 +853,21 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req, | ||
| 169 | rsp_length = compute_response_length_from_request(ctx, (uint8_t *) req); | ||
| 170 | if (rsp_length != req_length) { | ||
| 171 | /* Bad use of modbus_reply */ | ||
| 172 | - rsp_length = | ||
| 173 | - response_exception(ctx, | ||
| 174 | - &sft, | ||
| 175 | - MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE, | ||
| 176 | - rsp, | ||
| 177 | - FALSE, | ||
| 178 | - "Invalid request length used in modbus_reply (%d)\n", | ||
| 179 | - req_length); | ||
| 180 | + rsp_length = response_exception( | ||
| 181 | + ctx, | ||
| 182 | + &sft, | ||
| 183 | + MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE, | ||
| 184 | + rsp, | ||
| 185 | + FALSE, | ||
| 186 | + "Invalid request length in modbus_reply to write register (%d)\n", | ||
| 187 | + req_length); | ||
| 188 | break; | ||
| 189 | } | ||
| 190 | int data = (req[offset + 3] << 8) + req[offset + 4]; | ||
| 191 | |||
| 192 | mb_mapping->tab_registers[mapping_address] = data; | ||
| 193 | + | ||
| 194 | + rsp_length -= ctx->backend->checksum_length; | ||
| 195 | memcpy(rsp, req, rsp_length); | ||
| 196 | } | ||
| 197 | break; | ||
| 198 | @@ -966,8 +973,23 @@ int modbus_reply(modbus_t *ctx, const uint8_t *req, | ||
| 199 | |||
| 200 | data = (data & and) | (or & (~and)); | ||
| 201 | mb_mapping->tab_registers[mapping_address] = data; | ||
| 202 | - memcpy(rsp, req, req_length); | ||
| 203 | - rsp_length = req_length; | ||
| 204 | + | ||
| 205 | + rsp_length = compute_response_length_from_request(ctx, (uint8_t *) req); | ||
| 206 | + if (rsp_length != req_length) { | ||
| 207 | + /* Bad use of modbus_reply */ | ||
| 208 | + rsp_length = response_exception(ctx, | ||
| 209 | + &sft, | ||
| 210 | + MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE, | ||
| 211 | + rsp, | ||
| 212 | + FALSE, | ||
| 213 | + "Invalid request length in modbus_reply " | ||
| 214 | + "to mask write register (%d)\n", | ||
| 215 | + req_length); | ||
| 216 | + break; | ||
| 217 | + } | ||
| 218 | + | ||
| 219 | + rsp_length -= ctx->backend->checksum_length; | ||
| 220 | + memcpy(rsp, req, rsp_length); | ||
| 221 | } | ||
| 222 | } | ||
| 223 | break; | ||
| 224 | @@ -1037,7 +1059,6 @@ int modbus_reply_exception(modbus_t *ctx, const uint8_t *req, | ||
| 225 | int function; | ||
| 226 | uint8_t rsp[MAX_MESSAGE_LENGTH]; | ||
| 227 | int rsp_length; | ||
| 228 | - int dummy_length = 99; | ||
| 229 | sft_t sft; | ||
| 230 | |||
| 231 | if (ctx == NULL) { | ||
| 232 | @@ -1051,7 +1072,7 @@ int modbus_reply_exception(modbus_t *ctx, const uint8_t *req, | ||
| 233 | |||
| 234 | sft.slave = slave; | ||
| 235 | sft.function = function + 0x80; | ||
| 236 | - sft.t_id = ctx->backend->prepare_response_tid(req, &dummy_length); | ||
| 237 | + sft.t_id = ctx->backend->get_response_tid(req); | ||
| 238 | rsp_length = ctx->backend->build_response_basis(&sft, rsp); | ||
| 239 | |||
| 240 | /* Positive exception code */ | ||
