emelianov / modbus-esp8266

Most complete Modbus library for Arduino. A library that allows your Arduino board to communicate via Modbus protocol, acting as a master, slave or both. Supports network transport (Modbus TCP) and Serial line/RS-485 (Modbus RTU). Supports Modbus TCP Security for ESP8266/ESP32.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Bug: Slave answers with malformed packet

qdlmcfresh opened this issue · comments

Lets say the Slave receives a packet like this, with a faulty length field

packet = (
    #Request - modbus_read_coil
    #Block - modbus_head
    b'\x01\x00'  # Word - transId
    b'\x00\x00'  # Word - protoId
    + b'\x00' * 2 + #  Word -length
    b'\xff'  # Byte - unit Identifier
    #Block - pdu
    b'\x01'  # Byte - funcCode read coil memory
    b'\x00\x01'  # Word - start_address
    b'\x00\x00'  # Word - quantity
)

After correcty registering that the request is faulty, the slave will response with a malformed modbus packet with only
8 bytes length, since:
_len first gets set to 2 here:

void Modbus::exceptionResponse(FunctionCode fn, ResultCode excode) {
free(_frame);
_len = 2;
_frame = (uint8_t*) malloc(_len);

then substracted by 1 here:
if (_len > MODBUSIP_MAXFRAME) { // Length is over MODBUSIP_MAXFRAME
exceptionResponse((FunctionCode)tcpclient[n]->read(), EX_SLAVE_FAILURE);
_len--; // Subtract for read byte
for (uint8_t i = 0; tcpclient[n]->available() && i < _len; i++) // Drop rest of packet
tcpclient[n]->read();

and reused for calculating the size of the response packet:
if (_reply != REPLY_OFF) {
_MBAP.length = __swap_16(_len+1); // _len+1 for last byte from MBAP
size_t send_len = (uint16_t)_len + sizeof(_MBAP.raw);
uint8_t sbuf[send_len];
memcpy(sbuf, _MBAP.raw, sizeof(_MBAP.raw));
memcpy(sbuf + sizeof(_MBAP.raw), _frame, _len);
tcpclient[n]->write(sbuf, send_len);
//tcpclient[n]->flush();

The exception code gets lost in that process.

Also

for (uint8_t i = 0; tcpclient[n]->available() && i < _len; i++) // Drop rest of packet

is only dropping 1 byte because of _len always being 1 at this point