[modbus] Hub and helpers cleanup; tighten queue_pdu validation (#18847)

This commit is contained in:
Bonne Eggleston
2026-08-28 13:16:41 -05:00
committed by GitHub
parent 8db07d0de5
commit 768ab5b672
9 changed files with 207 additions and 275 deletions
+7 -6
View File
@@ -30,9 +30,11 @@ uint16_t server_pdu_length(const uint8_t *frame, size_t size) {
switch (static_cast<FunctionCode>(frame[0])) {
case FunctionCode::READ_COILS:
case FunctionCode::READ_DISCRETE_INPUTS:
// function(1) + byte count(1) + packed coil bytes
return 2 + (size > 1 ? std::min(frame[1], uint8_t(packed_bit_bytes(MAX_NUM_OF_COILS_TO_READ))) : 0);
case FunctionCode::READ_HOLDING_REGISTERS:
case FunctionCode::READ_INPUT_REGISTERS:
// function(1) + byte count(1) + data
// function(1) + byte count(1) + register data
return 2 + (size > 1 ? std::min(frame[1], uint8_t(MAX_NUM_OF_REGISTERS_TO_READ * 2)) : 0);
case FunctionCode::WRITE_SINGLE_COIL:
case FunctionCode::WRITE_SINGLE_REGISTER:
@@ -60,6 +62,9 @@ uint16_t server_pdu_length(const uint8_t *frame, size_t size) {
uint16_t client_pdu_length(const uint8_t *frame, size_t size) {
if (size < MIN_PDU_SIZE)
return MIN_PDU_SIZE;
if (is_function_code_exception(frame[0])) {
return 2; // never a valid request; sized like the exception reply so the CRC fails at once
}
switch (static_cast<FunctionCode>(frame[0])) {
case FunctionCode::READ_COILS:
case FunctionCode::READ_DISCRETE_INPUTS:
@@ -381,8 +386,6 @@ ReadPdu create_read_pdu(FunctionCode function_code, uint16_t start_address, uint
PduBuffer create_client_pdu(FunctionCode function_code, uint16_t start_address, uint16_t number_of_entities,
const uint8_t *values, size_t values_len) {
PduBuffer pdu; // declared before every return so NRVO fires (all paths return the same object)
// Generic entry point; prefer the direction- and type-specific builders (create_read_pdu(),
// create_write_registers_pdu(), etc.) which bound their inputs per spec.
if (is_function_code_read_only(static_cast<uint8_t>(function_code))) {
if (values != nullptr || values_len > 0) {
ESP_LOGW(TAG, "Values provided for read function code %02X, but will be ignored",
@@ -445,9 +448,7 @@ PduBuffer create_client_pdu(FunctionCode function_code, uint16_t start_address,
return pdu;
}
// The quantity is spec-bounded above, so the data length just has to agree with it exactly
// (registers are 2 bytes each, coils pack 8 per byte). This is the same consistency the response
// dispatch enforces via is_client_pdu_standard(), so a frame built here can never be classified
// non-standard on reply, and the spec bound keeps the PDU within capacity by construction.
// (registers are 2 bytes each, coils pack 8 per byte).
// Checked before the header append: a failed check must return an empty PDU, not a 5-byte partial one.
const bool bits = function_code == FunctionCode::WRITE_MULTIPLE_COILS;
const size_t expected_len = bits ? packed_bit_bytes(number_of_entities) : static_cast<size_t>(number_of_entities) * 2;