From: Graeme Foot <graeme.foot@touchcut.com>
Date: Thu, 06 May 2021 13:23:22 +1200

Overlapped PDOs not fitting into max datagram size fix.

If a slave has two overlapped PDOs and the first one fits into
the domain datagram, but the second doesn't the datagrams are
not created correctly.

This patch test's all FMMUs as to whether they fit in the current
datagram, but only updates the last valid FMMU and data start point
at aligned FMMUs (or non-overlapped FMMUs) to avoid trying to split
an FMMU between two datagrams.

Extra checks are added to ensure the combined length of overlapped
FMMUs do not exceed the maximum datagram size.


diff -r 99c8482513f3 master/domain.c
--- a/master/domain.c	Tue Apr 06 13:11:21 2021 +1200
+++ b/master/domain.c	Thu May 06 13:20:41 2021 +1200
@@ -355,19 +355,35 @@
             // All FMMUs prior to this point approved for next datagram
             valid_fmmu = fmmu;
             valid_start = candidate_start;
-            if (fmmu->logical_domain_offset + fmmu->data_size - datagram_offset
-                    > EC_MAX_DATA_SIZE) {
-                // yet the new candidate exceeds the datagram size, so we
-                // use the last known valid candidate to create the datagram
-                ret = emplace_datagram(domain, datagram_offset, valid_start,
-                    datagram_first_fmmu, valid_fmmu);
-                if (ret < 0)
-                    return ret;
+        }
+        if (fmmu->logical_domain_offset + fmmu->data_size - datagram_offset
+                > EC_MAX_DATA_SIZE) {
+            // check that previous overlapped FMMU's size is not too large
+            if (unlikely(valid_start - datagram_offset > EC_MAX_DATA_SIZE)) {
+                EC_MASTER_ERR(domain->master, "Overlapped FMMU's size "
+                    "%u bytes exceeds maximum data size %u",
+                    valid_start - datagram_offset, EC_MAX_DATA_SIZE);
+                return -EINVAL;
+            }
+            // check that current overlapped FMMU's size is not too large
+            if (unlikely(valid_start == datagram_offset)) {
+                EC_MASTER_ERR(domain->master, "Overlapped FMMU's size "
+                    ">= %u bytes exceeds maximum data size %u",
+                    logical_domain_offset + fmmu->data_size - 
+                    datagram_offset, EC_MAX_DATA_SIZE);
+                return -EINVAL;
+            }
+            
+            // yet the new candidate exceeds the datagram size, so we
+            // use the last known valid candidate to create the datagram
+            ret = emplace_datagram(domain, datagram_offset, valid_start,
+                datagram_first_fmmu, valid_fmmu);
+            if (ret < 0)
+                return ret;
 
-                datagram_offset = valid_start;
-                datagram_count++;
-                datagram_first_fmmu = fmmu;
-            }
+            datagram_offset = valid_start;
+            datagram_first_fmmu = valid_fmmu;
+            datagram_count++;
         }
         if (fmmu->logical_domain_offset + fmmu->data_size > candidate_start) {
             candidate_start = fmmu->logical_domain_offset + fmmu->data_size;
@@ -377,6 +393,14 @@
     /* Allocate last datagram pair, if data are left (this is also the case if
      * the process data fit into a single datagram) */
     if (domain->data_size > datagram_offset) {
+        // check that remaining overlapped FMMU's size is not too large
+        if (unlikely(domain->data_size - datagram_offset > EC_MAX_DATA_SIZE)) {
+            EC_MASTER_ERR(domain->master, "Overlapped FMMU's size "
+                "%u bytes exceeds maximum data size %u",
+                domain->data_size - datagram_offset, EC_MAX_DATA_SIZE);
+            return -EINVAL;
+        }
+        
         ret = emplace_datagram(domain, datagram_offset, domain->data_size,
             datagram_first_fmmu, fmmu);
         if (ret < 0)
