Description
I am enhancing and developing simulations with Frame Preemption and noticed that Wireshark flags mismatched checksums for SMD-C values that are not the final fragment of the packet.
You can reproduce this by adding a third application to the Frame Preemption showcase in the omnetpp.ini file and setting the initialProductionOffset
to delay the frames in a way that causes a packet to be split into more than two fragments.
example:
# host1
*.host1.numApps = 3
*.host1.app[*].typename = "UdpSourceApp"
*.host1.app[0].source.packetNameFormat = "background-%c"
*.host1.app[1].source.packetNameFormat = "ts-%c"
*.host1.app[*].tagger.typename = "PacketTagger"
*.host1.app[0].tagger.vlanId = 1
*.host1.app[1].tagger.vlanId = 0
*.host1.app[2].tagger.vlanId = 0
*.host1.app[*].io.destAddress = "host2"
*.host1.app[0].io.destPort = 1000
*.host1.app[1].io.destPort = 1001
*.host1.app[2].io.destPort = 1001
*.host1.app[0].source.packetLength = 1200B
*.host1.app[0].source.productionInterval = 1ms
*.host1.app[2].source.packetLength = 1200B
*.host1.app[2].source.productionInterval = 1ms
*.host1.app[2].source.initialProductionOffset = 180us
*.host1.app[1].source.packetLength = 1200B
*.host1.app[1].source.productionInterval = 1ms
*.host1.app[1].source.initialProductionOffset = 50us
Analyzing the pcap file of the host2, will show wrong mcrc of the first continuation fragment.
Looking at the implementation of EthernetFragmentFcsInserter, it correctly calculates the mcrc for the current fragment. However, the mcrc added to intermediate fragments only reflects the checksum of that individual fragment. This means that mcrc is computed solely for the current fragment and does not incorporate previously transmitted data, as specified by IEEE 802.1br 99.3.6.
This may have been necessary in older INET versions, where the packet included the entire payload, including fragments already transmitted. However, in INET 4.5.4, I would recommend returning currentFragmentFcs instead.
uint32_t EthernetFragmentFcsInserter::computeComputedFcs(const Packet *packet) const
{
auto data = packet->peekDataAsBytes();
auto bytes = data->getBytes();
auto fragmentTag = packet->getTag<FragmentTag>();
currentFragmentCompleteFcs = ethernetCRC(bytes.data(), packet->getByteLength(), fragmentTag->getFirstFragment() ? 0 : lastFragmentCompleteFcs);
if (fragmentTag->getLastFragment())
return currentFragmentCompleteFcs;
else
return currentFragmentCompleteFcs ^ 0xFFFF0000;
}
which would also require to change the EthernetFragmentFcsChecker
bool EthernetFragmentFcsChecker::checkComputedFcs(const Packet *packet, uint32_t receivedFcs) const
{
auto data = packet->peekDataAsBytes();
auto bytes = data->getBytes();
auto& fragmentTag = packet->getTag<FragmentTag>();
currentFragmentCompleteFcs = ethernetCRC(bytes.data(), packet->getByteLength() - 4, fragmentTag->getFirstFragment() ? 0 : lastFragmentCompleteFcs);
/** In effect, the function is accepting the frame if either:
→ The received FCS matches the computed FCS (last fragment)
→It matches the computed FCS after being XORed (non‐last fragment).
*/
return (receivedFcs == currentFragmentCompleteFcs) ||
(receivedFcs == (currentFragmentCompleteFcs ^ 0xFFFF0000));
}
With these changes, the mcrc appears correct in Wireshark, and the packets are no longer dropped. However, I have not yet tested this with corrupted checksums.
If I am mistaken and the current implementation is correct, I do be happy to be corrected.