15uint16_t dnp3_crc(
const uint8_t *data,
size_t len)
17 uint16_t crc = 0x0000;
18 for (
size_t i = 0; i < len; i++)
21 for (
int b = 0; b < 8; b++)
22 crc = (crc & 1) ? (uint16_t)((crc >> 1) ^ 0xA6BC) : (uint16_t)(crc >> 1);
24 return (uint16_t)(crc ^ 0xFFFF);
28static size_t put_crc(uint8_t *p,
const uint8_t *data,
size_t n)
30 uint16_t crc = dnp3_crc(data, n);
31 p[0] = (uint8_t)(crc & 0xFF);
32 p[1] = (uint8_t)(crc >> 8);
36size_t dnp3_build_frame(uint8_t *buf,
size_t cap, uint8_t control, uint16_t dest, uint16_t src,
37 const uint8_t *user_data,
size_t user_data_len)
39 if (!buf || (user_data_len && !user_data) || user_data_len > DNP3_MAX_USER_DATA)
41 size_t nblocks = (user_data_len + DNP3_BLOCK_LEN - 1) / DNP3_BLOCK_LEN;
42 size_t total = DNP3_HEADER_BLOCK_LEN + user_data_len + nblocks * DNP3_CRC_LEN;
47 buf[p++] = DNP3_START0;
48 buf[p++] = DNP3_START1;
49 buf[p++] = (uint8_t)(DNP3_LEN_OVERHEAD + user_data_len);
51 buf[p++] = (uint8_t)(dest & 0xFF);
52 buf[p++] = (uint8_t)(dest >> 8);
53 buf[p++] = (uint8_t)(src & 0xFF);
54 buf[p++] = (uint8_t)(src >> 8);
55 p += put_crc(buf + p, buf, DNP3_HEADER_LEN);
58 while (off < user_data_len)
60 size_t blk = user_data_len - off;
61 if (blk > DNP3_BLOCK_LEN)
63 memcpy(buf + p, user_data + off, blk);
64 put_crc(buf + p + blk, buf + p, blk);
65 p += blk + DNP3_CRC_LEN;
71bool dnp3_parse_frame(
const uint8_t *buf,
size_t len, Dnp3Frame *out, uint8_t *out_user,
size_t out_cap,
74 if (!buf || !out || len < DNP3_HEADER_BLOCK_LEN)
76 if (buf[0] != DNP3_START0 || buf[1] != DNP3_START1)
78 uint8_t length = buf[2];
79 if (length < DNP3_LEN_OVERHEAD)
81 size_t user_len = (size_t)length - DNP3_LEN_OVERHEAD;
82 if (user_len > DNP3_MAX_USER_DATA)
86 uint16_t hcrc = dnp3_crc(buf, DNP3_HEADER_LEN);
87 if ((uint16_t)(buf[DNP3_HEADER_LEN] | (buf[DNP3_HEADER_LEN + 1] << 8)) != hcrc)
90 size_t nblocks = (user_len + DNP3_BLOCK_LEN - 1) / DNP3_BLOCK_LEN;
91 size_t total = DNP3_HEADER_BLOCK_LEN + user_len + nblocks * DNP3_CRC_LEN;
95 if (user_len && (!out_user || user_len > out_cap))
98 size_t p = DNP3_HEADER_BLOCK_LEN;
100 while (off < user_len)
102 size_t blk = user_len - off;
103 if (blk > DNP3_BLOCK_LEN)
104 blk = DNP3_BLOCK_LEN;
105 uint16_t bcrc = dnp3_crc(buf + p, blk);
106 if ((uint16_t)(buf[p + blk] | (buf[p + blk + 1] << 8)) != bcrc)
108 memcpy(out_user + off, buf + p, blk);
109 p += blk + DNP3_CRC_LEN;
113 out->length = length;
114 out->control = buf[3];
115 out->dest = (uint16_t)(buf[4] | (buf[5] << 8));
116 out->src = (uint16_t)(buf[6] | (buf[7] << 8));
118 *out_user_len = user_len;
DNP3 (IEEE 1815) data-link frame codec (DETWS_ENABLE_DNP3) - zero-heap builder + CRC-validating parse...