diff --git a/CHANGES b/CHANGES index e7c9a1c..61c76fc 100644 --- a/CHANGES +++ b/CHANGES @@ -1,4 +1,12 @@ +Now any DLL crcs (frame A or B) are removed automatically +when telegrams are read from a simulation_... file or +passed as hex on the command line. If the DLL crc do not +check out (usually because they are not there), then the +telegram is kept as is. If the crcs are broken because +of a bad data, then the telegram will be passed on as is, +probably causing a bad parse later on. + Added multical602 heat meter. Version 1.5.0: 2021-11-06 diff --git a/README.md b/README.md index 6eba07d..f763381 100644 --- a/README.md +++ b/README.md @@ -303,6 +303,7 @@ These telegrams are expected to have the data link layer crc bytes removed alrea `simulation_abc.txt`, to read telegrams from the file (the file must have a name beginning with simulation_....) expecting the same format that is the output from `--logtelegrams`. This format also supports replay with timing. +The telegrams are allowed to have valid dll crcs, which will be automatically stripped. As meter quadruples you specify: @@ -604,8 +605,11 @@ echo 234433300602010014007a8e0000002f2f0efd3a1147000000008e40fd3a341200000000 | or read hex data from a a file, `wmbusmeters myfile.txt:hex` -Any non-hex characters are ignored when using the suffix `:hex`. The hex string must be proper -with no spaces nor bad characters, when supplied on the command line. +Any non-hex characters are ignored when using the suffix `:hex`. However when the hex string is +supplied on the command line it must be a proper hex string with no spaces. + +When a telegram is supplied on the command line, then any valid dll crcs will be automatically removed, +like when the telegram is suppled in a simulation file. # Additional tools diff --git a/simulations/simulation_broken.txt b/simulations/simulation_broken.txt index 3e53fc8..f549d75 100644 --- a/simulations/simulation_broken.txt +++ b/simulations/simulation_broken.txt @@ -1,3 +1,3 @@ -# This telegram is not really broken, but the current dvparser fails, in particular the end triggers a varlen with -# not enough bytes in the telegram. When the protocol/dvparser is improved, a replacement telegram should be placed here. -telegram=|3444EE4D813929271608|811D|7A51000000|046D1912A62B036E000000|5170426CE1F1436E00000002FF2C00000259D6D0D4090265FC0902FD66A00044C4| +# The last byte C4 has been removed. This means that the dll crcs will not check out. +# Since the simulation will not remove the crcs unless they all check out, this will result in a broken telegram. +telegram=|3444EE4D813929271608|811D|7A51000000|046D1912A62B036E000000|5170426CE1F1436E00000002FF2C00000259D6D0D4090265FC0902FD66A00044| diff --git a/simulations/simulation_dll_crcs.txt b/simulations/simulation_dll_crcs.txt new file mode 100644 index 0000000..d4cf1ea --- /dev/null +++ b/simulations/simulation_dll_crcs.txt @@ -0,0 +1,3 @@ +# These telegrams have their dll crc:s still inside. +telegram=|734414867CC30B0003030D58A00EDF0700DC41343CEA390306FF0A0D44EADF07000DDF07000DDF07000DDF07000E44F9DF07000EDF07000EDF07000EDF07000E931EDF07000DDF07000DDF07000DDF0700035A4500000000374F0B20000000000000243412B31C07050C12280000000000002C002302062F19080F2F000000000000DCF5| +telegram=|3444EE4D813929271608|811D|7A51000000|046D1912A62B036E000000|5170426CE1F1436E00000002FF2C00000259D6D0D4090265FC0902FD66A00044C4| diff --git a/src/wmbus.cc b/src/wmbus.cc index e10901c..c9a9380 100644 --- a/src/wmbus.cc +++ b/src/wmbus.cc @@ -4060,14 +4060,20 @@ LIST_OF_AFL_AUTH_TYPES return AFLAuthenticationType::Reserved1; } -bool trimCRCsFrameFormatA(std::vector &payload) +bool trimCRCsFrameFormatAInternal(std::vector &payload, bool fail_is_ok) { if (payload.size() < 12) { - debug("(wmbus) not enough bytes! expected at least 12 but got (%zu)!\n", payload.size()); + if (!fail_is_ok) + { + debug("(wmbus) not enough bytes! expected at least 12 but got (%zu)!\n", payload.size()); + } return false; } size_t len = payload.size(); - debugPayload("(wmbus) trimming frame A", payload); + if (!fail_is_ok) + { + debugPayload("(wmbus) trimming frame A", payload); + } vector out; @@ -4080,7 +4086,10 @@ bool trimCRCsFrameFormatA(std::vector &payload) return false; } out.insert(out.end(), payload.begin(), payload.begin()+10); - debug("(wmbus) ff a dll crc 0-%zu %04x ok\n", 10-1, calc_crc); + if (!fail_is_ok) + { + debug("(wmbus) ff a dll crc 0-%zu %04x ok\n", 10-1, calc_crc); + } size_t pos = 12; for (pos = 12; pos+18 <= len; pos += 18) @@ -4090,12 +4099,18 @@ bool trimCRCsFrameFormatA(std::vector &payload) check_crc = payload[to] << 8 | payload[to+1]; if (calc_crc != check_crc && !FUZZING) { - debug("(wmbus) ff a dll crc mid (calculated %04x) did not match (expected %04x) for bytes %zu-%zu!\n", - calc_crc, check_crc, pos, to-1); + if (!fail_is_ok) + { + debug("(wmbus) ff a dll crc mid (calculated %04x) did not match (expected %04x) for bytes %zu-%zu!\n", + calc_crc, check_crc, pos, to-1); + } return false; } out.insert(out.end(), payload.begin()+pos, payload.begin()+pos+16); - debug("(wmbus) ff a dll crc mid %zu-%zu %04x ok\n", pos, to-1, calc_crc); + if (!fail_is_ok) + { + debug("(wmbus) ff a dll crc mid %zu-%zu %04x ok\n", pos, to-1, calc_crc); + } } if (pos < len-2) @@ -4106,12 +4121,23 @@ bool trimCRCsFrameFormatA(std::vector &payload) check_crc = payload[tto] << 8 | payload[tto+1]; if (calc_crc != check_crc && !FUZZING) { - debug("(wmbus) ff a dll crc final (calculated %04x) did not match (expected %04x) for bytes %zu-%zu!\n", - calc_crc, check_crc, pos, tto-1); + if (!fail_is_ok) + { + debug("(wmbus) ff a dll crc final (calculated %04x) did not match (expected %04x) for bytes %zu-%zu!\n", + calc_crc, check_crc, pos, tto-1); + } return false; } out.insert(out.end(), payload.begin()+pos, payload.begin()+tto); - debug("(wmbus) ff a dll crc final %zu-%zu %04x ok\n", pos, tto-1, calc_crc); + if (!fail_is_ok) + { + debug("(wmbus) ff a dll crc final %zu-%zu %04x ok\n", pos, tto-1, calc_crc); + } + } + + if (fail_is_ok) + { + debugPayload("(wmbus) trimming frame A", payload); } out[0] = out.size()-1; @@ -4120,20 +4146,26 @@ bool trimCRCsFrameFormatA(std::vector &payload) payload = out; size_t new_size = payload.size(); - debug("(wmbus) trimmed %zu crc bytes from frame a and ignored %zu suffix bytes.\n", (len-new_len), (old_size-new_size)-(len-new_len)); - debugPayload("(wmbus) trimmed frame A", payload); + debug("(wmbus) trimmed %zu dll crc bytes from frame a and ignored %zu suffix bytes.\n", (len-new_len), (old_size-new_size)-(len-new_len)); + debugPayload("(wmbus) trimmed frame A", payload); return true; } -bool trimCRCsFrameFormatB(std::vector &payload) +bool trimCRCsFrameFormatBInternal(std::vector &payload, bool fail_is_ok) { if (payload.size() < 12) { - debug("(wmbus) not enough bytes! expected at least 12 but got (%zu)!\n", payload.size()); + if (!fail_is_ok) + { + debug("(wmbus) not enough bytes! expected at least 12 but got (%zu)!\n", payload.size()); + } return false; } size_t len = payload.size(); - debugPayload("(wmbus) trimming frame B", payload); + if (!fail_is_ok) + { + debugPayload("(wmbus) trimming frame B", payload); + } vector out; size_t crc1_pos, crc2_pos; @@ -4153,12 +4185,18 @@ bool trimCRCsFrameFormatB(std::vector &payload) if (calc_crc != check_crc && !FUZZING) { - debug("(wmbus) ff b dll crc (calculated %04x) did not match (expected %04x) for bytes 0-%zu!\n", calc_crc, check_crc, crc1_pos); + if (!fail_is_ok) + { + debug("(wmbus) ff b dll crc (calculated %04x) did not match (expected %04x) for bytes 0-%zu!\n", calc_crc, check_crc, crc1_pos); + } return false; } out.insert(out.end(), payload.begin(), payload.begin()+crc1_pos); - debug("(wmbus) ff b dll crc first 0-%zu %04x ok\n", crc1_pos, calc_crc); + if (!fail_is_ok) + { + debug("(wmbus) ff b dll crc first 0-%zu %04x ok\n", crc1_pos, calc_crc); + } if (crc2_pos > 0) { @@ -4167,13 +4205,24 @@ bool trimCRCsFrameFormatB(std::vector &payload) if (calc_crc != check_crc && !FUZZING) { - debug("(wmbus) ff b dll crc (calculated %04x) did not match (expected %04x) for bytes %zu-%zu!\n", - calc_crc, check_crc, crc1_pos+2, crc2_pos); + if (!fail_is_ok) + { + debug("(wmbus) ff b dll crc (calculated %04x) did not match (expected %04x) for bytes %zu-%zu!\n", + calc_crc, check_crc, crc1_pos+2, crc2_pos); + } return false; } out.insert(out.end(), payload.begin()+crc1_pos+2, payload.begin()+crc2_pos); - debug("(wmbus) ff b dll crc final %zu-%zu %04x ok\n", crc1_pos+2, crc2_pos, calc_crc); + if (!fail_is_ok) + { + debug("(wmbus) ff b dll crc final %zu-%zu %04x ok\n", crc1_pos+2, crc2_pos, calc_crc); + } + } + + if (fail_is_ok) + { + debugPayload("(wmbus) trimming frame B", payload); } out[0] = out.size()-1; @@ -4182,12 +4231,28 @@ bool trimCRCsFrameFormatB(std::vector &payload) payload = out; size_t new_size = payload.size(); - debug("(wmbus) trimmed %zu crc bytes from frame b and ignored %zu suffix bytes.\n", (len-new_len), (old_size-new_size)-(len-new_len)); - debugPayload("(wmbus) trimmed frame B", payload); + debug("(wmbus) trimmed %zu dll crc bytes from frame b and ignored %zu suffix bytes.\n", (len-new_len), (old_size-new_size)-(len-new_len)); + debugPayload("(wmbus) trimmed frame B", payload); return true; } +void removeAnyDLLCRCs(std::vector &payload) +{ + bool trimmed = trimCRCsFrameFormatAInternal(payload, true); + if (!trimmed) trimCRCsFrameFormatBInternal(payload, true); +} + +bool trimCRCsFrameFormatA(std::vector &payload) +{ + return trimCRCsFrameFormatAInternal(payload, false); +} + +bool trimCRCsFrameFormatB(std::vector &payload) +{ + return trimCRCsFrameFormatBInternal(payload, false); +} + FrameStatus checkWMBusFrame(vector &data, size_t *frame_length, int *payload_len_out, diff --git a/src/wmbus.h b/src/wmbus.h index d020d9c..6c2433f 100644 --- a/src/wmbus.h +++ b/src/wmbus.h @@ -27,6 +27,7 @@ // Check and remove the data link layer CRCs from a wmbus telegram. // If the CRCs do not pass the test, return false. +void removeAnyDLLCRCs(std::vector &payload); bool trimCRCsFrameFormatA(std::vector &payload); bool trimCRCsFrameFormatB(std::vector &payload); diff --git a/src/wmbus_simulator.cc b/src/wmbus_simulator.cc index 4c770b7..48b7942 100644 --- a/src/wmbus_simulator.cc +++ b/src/wmbus_simulator.cc @@ -175,6 +175,13 @@ void WMBusSimulator::simulate() error("Not a valid string of hex bytes! \"%s\"\n", l.c_str()); } AboutTelegram about("", 0, FrameType::WMBUS); + // Since this is a simulation, try to remove any frame format A or B + // data link layer crcs. These might remain if we have received the telegram + // to be simulated, from a CUL device or some other devices that does not remove the crcs. + // Normally the dongle (im871a/amb8465/rc1180/rtlwmbus/rtl443) removes the dll-crcs. + // Removing dll-crcs are also done explicitly in the wmbus_cul.cc driver. + removeAnyDLLCRCs(payload); + handleTelegram(about, payload); } manager_->stop(); diff --git a/test.sh b/test.sh index f8fbc79..452a6e9 100755 --- a/test.sh +++ b/test.sh @@ -114,6 +114,9 @@ if [ "$?" != "0" ]; then RC="1"; fi ./tests/test_hex_cmdline.sh $PROG if [ "$?" != "0" ]; then RC="1"; fi +./tests/test_removing_dll_crcs.sh $PROG +if [ "$?" != "0" ]; then RC="1"; fi + ./tests/test_broken.sh $PROG if [ "$?" != "0" ]; then RC="1"; fi diff --git a/tests/test_removing_dll_crcs.sh b/tests/test_removing_dll_crcs.sh new file mode 100755 index 0000000..1434d8e --- /dev/null +++ b/tests/test_removing_dll_crcs.sh @@ -0,0 +1,37 @@ +#!/bin/sh + +PROG="$1" +TEST=testoutput +mkdir -p $TEST + +TESTNAME="Test auto removal of dll crcs in simulated telegrams" +TESTRESULT="ERROR" + +cat > $TEST/test_expected.txt < $TEST/test_output.txt 2>&1 + +if [ "$?" = "0" ] +then + diff $TEST/test_expected.txt $TEST/test_output.txt + if [ "$?" = "0" ] + then + echo OK: $TESTNAME + TESTRESULT="OK" + fi +else + echo "wmbusmeters returned error code: $?" + cat $TEST/test_output.txt +fi