]> git.ipfire.org Git - thirdparty/snort3.git/commitdiff
Pull request #4951: iec104: data size checks for pointer operations
authorOleksandr Stepanov -X (ostepano - SOFTSERVE INC at Cisco) <ostepano@cisco.com>
Tue, 28 Oct 2025 20:47:01 +0000 (20:47 +0000)
committerChris Sherwin (chsherwi) <chsherwi@cisco.com>
Tue, 28 Oct 2025 20:47:01 +0000 (20:47 +0000)
Merge in SNORT/snort3 from ~OSTEPANO/snort3:iec_coverity to master

Squashed commit of the following:

commit dc00f009a3007ba2d9b5d7ff33e123f49413b643
Author: Oleksandr Stepanov <ostepano@cisco.com>
Date:   Tue Oct 21 06:01:08 2025 -0400

    iec104: data size checks for pointer operations

src/service_inspectors/iec104/CMakeLists.txt
src/service_inspectors/iec104/iec104_decode.cc
src/service_inspectors/iec104/iec104_parse_apdu.cc
src/service_inspectors/iec104/iec104_parse_apdu.h
src/service_inspectors/iec104/iec104_parse_information_object_elements.cc
src/service_inspectors/iec104/iec104_parse_information_object_elements.h
src/service_inspectors/iec104/test/CMakeLists.txt [new file with mode: 0644]
src/service_inspectors/iec104/test/iec104_parse_apdu_test.cc [new file with mode: 0644]

index 76f54dcb6c40b2343dcdd861f7f4dadcf1f98aa5..6fb2d9b5f979aab3f6adce176f21994a991f5bba 100644 (file)
@@ -24,3 +24,4 @@ else (STATIC_INSPECTORS)
 
 endif (STATIC_INSPECTORS)
 
+add_subdirectory ( test )
index db91a3ea9b3834ffdea7829481b48da750234c36..60ef0a3d184665205b245290115eb6d4a9c86b68 100644 (file)
@@ -45,7 +45,7 @@ using namespace snort;
 // Function to determine the APCI type of the current message based on the
 // major and (where needed) minor codes
 // returns an ApciType enum value corresponding to the determined APCI
-static uint32_t getApciType(Packet* p)
+static uint32_t getApciType(const Packet* p)
 {
     // overlay a generic apci struct over the first three bytes of the stream
     const Iec104GenericApci* apci = (const Iec104GenericApci*) p->data;
@@ -148,7 +148,7 @@ bool Iec104Decode(Packet* p, Iec104FlowData* iec104fd)
 
             // print out the APCI
             print_debug_information(p, "Information Transfer Format APCI\n");
-            parseIec104ApciI(apci);
+            parseIec104ApciI(apci, p->dsize);
 
             break;
         }
index 9fcf16fbd8419c70580cd620000d60ff070e3998..871651d3a73bc615eb22ff73a792fb64e8fa67c3 100644 (file)
 #include "iec104_module.h"
 #include "iec104_parse_information_object_elements.h"
 
+#ifdef UNIT_TEST
+void (*genericGroupPtr)(const void* genericIOGroup) = nullptr;
+#endif
+
 using namespace snort;
 
 // perform some checks on the ASDU
-static bool checkIec104Asdu(Iec104AsduCheck curAsduCheck)
+static bool checkIec104Asdu(const Iec104AsduCheck& curAsduCheck)
 {
     // keep a flag to indicate whether we should exit after executing
     // taking this approach instead of returning directly as multiple of these
@@ -487,6 +491,19 @@ static bool checkIec104Asdu(Iec104AsduCheck curAsduCheck)
 // This should not be called directly by anything other than parseGenericAsdu
 static void parseIec104GenericIOGroup(const GenericIec104AsduIOGroup* genericIOGroup)
 {
+#ifdef UNIT_TEST
+    if (genericGroupPtr)
+    {
+        genericGroupPtr(genericIOGroup->m_sp_na_1IOSubgroup);
+    }
+#endif
+    if (!genericIOGroup->m_sp_na_1IOSubgroup)
+    {
+        // invalid subgroup pointers
+        if (genericIOGroup->asduType == IEC104_ASDU_F_SG_NA_1)
+            DetectionEngine::queue_event(GID_IEC104, IEC104_NULL_LOS_VALUE);
+        return;
+    }
     // determine which ASDU parsing logic to run based off of the passed type
     switch (genericIOGroup->asduType)
     {
@@ -1327,19 +1344,132 @@ static void parseIec104GenericIOGroup(const GenericIec104AsduIOGroup* genericIOG
     }
 }
 
-static void parseIec104GenericAsdu(uint32_t asduType, const Iec104ApciI* apci)
+#define ASDU_MAP_SIZE_ITEM 0
+#define ASDU_MAP_OFFSET_ITEM 1
+
+const std::unordered_map<uint32_t, std::tuple<int,int> > asdu_size_map =
+{
+{ IEC104_ASDU_M_SP_NA_1 , { sizeof(Iec104M_SP_NA_1_IO_Subgroup) , offsetof(Iec104ApciI, asdu.m_sp_na_1.subgroup) } },
+{ IEC104_ASDU_M_DP_NA_1 , { sizeof(Iec104M_DP_NA_1_IO_Subgroup) , offsetof(Iec104ApciI, asdu.m_dp_na_1.subgroup) } },
+{ IEC104_ASDU_M_ST_NA_1 , { sizeof(Iec104M_ST_NA_1_IO_Subgroup) , offsetof(Iec104ApciI, asdu.m_st_na_1.subgroup) } },
+{ IEC104_ASDU_M_BO_NA_1 , { sizeof(Iec104M_BO_NA_1_IO_Subgroup) , offsetof(Iec104ApciI, asdu.m_bo_na_1.subgroup) } },
+{ IEC104_ASDU_M_ME_NA_1 , { sizeof(Iec104M_ME_NA_1_IO_Subgroup) , offsetof(Iec104ApciI, asdu.m_me_na_1.subgroup) } },
+{ IEC104_ASDU_M_ME_NB_1 , { sizeof(Iec104M_ME_NB_1_IO_Subgroup) , offsetof(Iec104ApciI, asdu.m_me_nb_1.subgroup) } },
+{ IEC104_ASDU_M_ME_NC_1 , { sizeof(Iec104M_ME_NC_1_IO_Subgroup) , offsetof(Iec104ApciI, asdu.m_me_nc_1.subgroup) } },
+{ IEC104_ASDU_M_IT_NA_1 , { sizeof(Iec104M_IT_NA_1_IO_Subgroup) , offsetof(Iec104ApciI, asdu.m_it_na_1.subgroup) } },
+{ IEC104_ASDU_M_PS_NA_1 , { sizeof(Iec104M_PS_NA_1_IO_Subgroup) , offsetof(Iec104ApciI, asdu.m_ps_na_1.subgroup) } },
+{ IEC104_ASDU_M_ME_ND_1 , { sizeof(Iec104M_ME_ND_1_IO_Subgroup) , offsetof(Iec104ApciI, asdu.m_me_nd_1.subgroup) } },
+{ IEC104_ASDU_F_DR_TA_1 , { sizeof(Iec104F_DR_TA_1_IO_Subgroup) , offsetof(Iec104ApciI, asdu.f_dr_ta_1.subgroup) } },
+{ IEC104_ASDU_M_SP_NA_1 , { sizeof(Iec104M_SP_NA_1_IO_Group)    , offsetof(Iec104ApciI, asdu.m_sp_na_1) } },
+{ IEC104_ASDU_M_SP_TA_1 , { sizeof(Iec104M_SP_TA_1_IO_Group)    , offsetof(Iec104ApciI, asdu.m_sp_ta_1) } },
+{ IEC104_ASDU_M_DP_NA_1 , { sizeof(Iec104M_DP_NA_1_IO_Group)    , offsetof(Iec104ApciI, asdu.m_dp_na_1) } },
+{ IEC104_ASDU_M_DP_TA_1 , { sizeof(Iec104M_DP_TA_1_IO_Group)    , offsetof(Iec104ApciI, asdu.m_dp_ta_1) } },
+{ IEC104_ASDU_M_ST_NA_1 , { sizeof(Iec104M_ST_NA_1_IO_Group)    , offsetof(Iec104ApciI, asdu.m_st_na_1) } },
+{ IEC104_ASDU_M_ST_TA_1 , { sizeof(Iec104M_ST_TA_1_IO_Group)    , offsetof(Iec104ApciI, asdu.m_st_ta_1) } },
+{ IEC104_ASDU_M_BO_NA_1 , { sizeof(Iec104M_BO_NA_1_IO_Group)    , offsetof(Iec104ApciI, asdu.m_bo_na_1) } },
+{ IEC104_ASDU_M_BO_TA_1 , { sizeof(Iec104M_BO_TA_1_IO_Group)    , offsetof(Iec104ApciI, asdu.m_bo_ta_1) } },
+{ IEC104_ASDU_M_ME_NA_1 , { sizeof(Iec104M_ME_NA_1_IO_Group)    , offsetof(Iec104ApciI, asdu.m_me_na_1) } },
+{ IEC104_ASDU_M_ME_TA_1 , { sizeof(Iec104M_ME_TA_1_IO_Group)    , offsetof(Iec104ApciI, asdu.m_me_ta_1) } },
+{ IEC104_ASDU_M_ME_NB_1 , { sizeof(Iec104M_ME_NB_1_IO_Group)    , offsetof(Iec104ApciI, asdu.m_me_nb_1) } },
+{ IEC104_ASDU_M_ME_TB_1 , { sizeof(Iec104M_ME_TB_1_IO_Group)    , offsetof(Iec104ApciI, asdu.m_me_tb_1) } },
+{ IEC104_ASDU_M_ME_NC_1 , { sizeof(Iec104M_ME_NC_1_IO_Group)    , offsetof(Iec104ApciI, asdu.m_me_nc_1) } },
+{ IEC104_ASDU_M_ME_TC_1 , { sizeof(Iec104M_ME_TC_1_IO_Group)    , offsetof(Iec104ApciI, asdu.m_me_tc_1) } },
+{ IEC104_ASDU_M_IT_NA_1 , { sizeof(Iec104M_IT_NA_1_IO_Group)    , offsetof(Iec104ApciI, asdu.m_it_na_1) } },
+{ IEC104_ASDU_M_IT_TA_1 , { sizeof(Iec104M_IT_TA_1_IO_Group)    , offsetof(Iec104ApciI, asdu.m_it_ta_1) } },
+{ IEC104_ASDU_M_EP_TA_1 , { sizeof(Iec104M_EP_TA_1_IO_Group)    , offsetof(Iec104ApciI, asdu.m_ep_ta_1) } },
+{ IEC104_ASDU_M_EP_TB_1 , { sizeof(Iec104M_EP_TB_1_IO_Group)    , offsetof(Iec104ApciI, asdu.m_ep_tb_1) } },
+{ IEC104_ASDU_M_EP_TC_1 , { sizeof(Iec104M_EP_TC_1_IO_Group)    , offsetof(Iec104ApciI, asdu.m_ep_tc_1) } },
+{ IEC104_ASDU_M_PS_NA_1 , { sizeof(Iec104M_PS_NA_1_IO_Group)    , offsetof(Iec104ApciI, asdu.m_ps_na_1) } },
+{ IEC104_ASDU_M_ME_ND_1 , { sizeof(Iec104M_ME_ND_1_IO_Group)    , offsetof(Iec104ApciI, asdu.m_me_nd_1) } },
+{ IEC104_ASDU_M_SP_TB_1 , { sizeof(Iec104M_SP_TB_1_IO_Group)    , offsetof(Iec104ApciI, asdu.m_sp_tb_1) } },
+{ IEC104_ASDU_M_DP_TB_1 , { sizeof(Iec104M_DP_TB_1_IO_Group)    , offsetof(Iec104ApciI, asdu.m_dp_tb_1) } },
+{ IEC104_ASDU_M_ST_TB_1 , { sizeof(Iec104M_ST_TB_1_IO_Group)    , offsetof(Iec104ApciI, asdu.m_st_tb_1) } },
+{ IEC104_ASDU_M_BO_TB_1 , { sizeof(Iec104M_BO_TB_1_IO_Group)    , offsetof(Iec104ApciI, asdu.m_bo_tb_1) } },
+{ IEC104_ASDU_M_ME_TD_1 , { sizeof(Iec104M_ME_TD_1_IO_Group)    , offsetof(Iec104ApciI, asdu.m_me_td_1) } },
+{ IEC104_ASDU_M_ME_TE_1 , { sizeof(Iec104M_ME_TE_1_IO_Group)    , offsetof(Iec104ApciI, asdu.m_me_te_1) } },
+{ IEC104_ASDU_M_ME_TF_1 , { sizeof(Iec104M_ME_TF_1_IO_Group)    , offsetof(Iec104ApciI, asdu.m_me_tf_1) } },
+{ IEC104_ASDU_M_IT_TB_1 , { sizeof(Iec104M_IT_TB_1_IO_Group)    , offsetof(Iec104ApciI, asdu.m_it_tb_1) } },
+{ IEC104_ASDU_M_EP_TD_1 , { sizeof(Iec104M_EP_TD_1_IO_Group)    , offsetof(Iec104ApciI, asdu.m_ep_td_1) } },
+{ IEC104_ASDU_M_EP_TE_1 , { sizeof(Iec104M_EP_TE_1_IO_Group)    , offsetof(Iec104ApciI, asdu.m_ep_te_1) } },
+{ IEC104_ASDU_M_EP_TF_1 , { sizeof(Iec104M_EP_TF_1_IO_Group)    , offsetof(Iec104ApciI, asdu.m_ep_tf_1) } },
+{ IEC104_ASDU_C_SC_NA_1 , { sizeof(Iec104C_SC_NA_1_IO_Group)    , offsetof(Iec104ApciI, asdu.c_sc_na_1) } },
+{ IEC104_ASDU_C_DC_NA_1 , { sizeof(Iec104C_DC_NA_1_IO_Group)    , offsetof(Iec104ApciI, asdu.c_dc_na_1) } },
+{ IEC104_ASDU_C_RC_NA_1 , { sizeof(Iec104C_RC_NA_1_IO_Group)    , offsetof(Iec104ApciI, asdu.c_rc_na_1) } },
+{ IEC104_ASDU_C_SE_NA_1 , { sizeof(Iec104C_SE_NA_1_IO_Group)    , offsetof(Iec104ApciI, asdu.c_se_na_1) } },
+{ IEC104_ASDU_C_SE_NB_1 , { sizeof(Iec104C_SE_NB_1_IO_Group)    , offsetof(Iec104ApciI, asdu.c_se_nb_1) } },
+{ IEC104_ASDU_C_SE_NC_1 , { sizeof(Iec104C_SE_NC_1_IO_Group)    , offsetof(Iec104ApciI, asdu.c_se_nc_1) } },
+{ IEC104_ASDU_C_BO_NA_1 , { sizeof(Iec104C_BO_NA_1_IO_Group)    , offsetof(Iec104ApciI, asdu.c_bo_na_1) } },
+{ IEC104_ASDU_C_SC_TA_1 , { sizeof(Iec104C_SC_TA_1_IO_Group)    , offsetof(Iec104ApciI, asdu.c_sc_ta_1) } },
+{ IEC104_ASDU_C_DC_TA_1 , { sizeof(Iec104C_DC_TA_1_IO_Group)    , offsetof(Iec104ApciI, asdu.c_dc_ta_1) } },
+{ IEC104_ASDU_C_RC_TA_1 , { sizeof(Iec104C_RC_TA_1_IO_Group)    , offsetof(Iec104ApciI, asdu.c_rc_ta_1) } },
+{ IEC104_ASDU_C_SE_TA_1 , { sizeof(Iec104C_SE_TA_1_IO_Group)    , offsetof(Iec104ApciI, asdu.c_se_ta_1) } },
+{ IEC104_ASDU_C_SE_TB_1 , { sizeof(Iec104C_SE_TB_1_IO_Group)    , offsetof(Iec104ApciI, asdu.c_se_tb_1) } },
+{ IEC104_ASDU_C_SE_TC_1 , { sizeof(Iec104C_SE_TC_1_IO_Group)    , offsetof(Iec104ApciI, asdu.c_se_tc_1) } },
+{ IEC104_ASDU_C_BO_TA_1 , { sizeof(Iec104C_BO_TA_1_IO_Group)    , offsetof(Iec104ApciI, asdu.c_bo_ta_1) } },
+{ IEC104_ASDU_M_EI_NA_1 , { sizeof(Iec104M_EI_NA_1_IO_Group)    , offsetof(Iec104ApciI, asdu.m_ei_na_1) } },
+{ IEC104_ASDU_C_IC_NA_1 , { sizeof(Iec104C_IC_NA_1_IO_Group)    , offsetof(Iec104ApciI, asdu.c_ic_na_1) } },
+{ IEC104_ASDU_C_CI_NA_1 , { sizeof(Iec104C_CI_NA_1_IO_Group)    , offsetof(Iec104ApciI, asdu.c_ci_na_1) } },
+{ IEC104_ASDU_C_RD_NA_1 , { sizeof(Iec104C_RD_NA_1_IO_Group)    , offsetof(Iec104ApciI, asdu.c_rd_na_1) } },
+{ IEC104_ASDU_C_CS_NA_1 , { sizeof(Iec104C_CS_NA_1_IO_Group)    , offsetof(Iec104ApciI, asdu.c_cs_na_1) } },
+{ IEC104_ASDU_C_TS_NA_1 , { sizeof(Iec104C_TS_NA_1_IO_Group)    , offsetof(Iec104ApciI, asdu.c_ts_na_1) } },
+{ IEC104_ASDU_C_RP_NA_1 , { sizeof(Iec104C_RP_NA_1_IO_Group)    , offsetof(Iec104ApciI, asdu.c_rp_na_1) } },
+{ IEC104_ASDU_C_CD_NA_1 , { sizeof(Iec104C_CD_NA_1_IO_Group)    , offsetof(Iec104ApciI, asdu.c_cd_na_1) } },
+{ IEC104_ASDU_C_TS_TA_1 , { sizeof(Iec104C_TS_TA_1_IO_Group)    , offsetof(Iec104ApciI, asdu.c_ts_ta_1) } },
+{ IEC104_ASDU_P_ME_NA_1 , { sizeof(Iec104P_ME_NA_1_IO_Group)    , offsetof(Iec104ApciI, asdu.p_me_na_1) } },
+{ IEC104_ASDU_P_ME_NB_1 , { sizeof(Iec104P_ME_NB_1_IO_Group)    , offsetof(Iec104ApciI, asdu.p_me_nb_1) } },
+{ IEC104_ASDU_P_ME_NC_1 , { sizeof(Iec104P_ME_NC_1_IO_Group)    , offsetof(Iec104ApciI, asdu.p_me_nc_1) } },
+{ IEC104_ASDU_P_AC_NA_1 , { sizeof(Iec104P_AC_NA_1_IO_Group)    , offsetof(Iec104ApciI, asdu.p_ac_na_1) } },
+{ IEC104_ASDU_F_FR_NA_1 , { sizeof(Iec104F_FR_NA_1_IO_Group)    , offsetof(Iec104ApciI, asdu.f_fr_na_1) } },
+{ IEC104_ASDU_F_SR_NA_1 , { sizeof(Iec104F_SR_NA_1_IO_Group)    , offsetof(Iec104ApciI, asdu.f_sr_na_1) } },
+{ IEC104_ASDU_F_SC_NA_1 , { sizeof(Iec104F_SC_NA_1_IO_Group)    , offsetof(Iec104ApciI, asdu.f_sc_na_1) } },
+{ IEC104_ASDU_F_LS_NA_1 , { sizeof(Iec104F_LS_NA_1_IO_Group)    , offsetof(Iec104ApciI, asdu.f_ls_na_1) } },
+{ IEC104_ASDU_F_AF_NA_1 , { sizeof(Iec104F_AF_NA_1_IO_Group)    , offsetof(Iec104ApciI, asdu.f_af_na_1) } },
+{ IEC104_ASDU_F_SG_NA_1 , { sizeof(Iec104F_SG_NA_1_IO_Group)    , offsetof(Iec104ApciI, asdu.f_sg_na_1) } },
+{ IEC104_ASDU_F_SC_NB_1 , { sizeof(Iec104F_SC_NB_1_IO_Group)    , offsetof(Iec104ApciI, asdu.f_sc_nb_1) } }
+};
+
+static void parseIec104GenericAsdu(uint32_t asduType, const Iec104ApciI* apci, const uint16_t& data_size)
 {
-    uint32_t verifiedNumberOfElements = parseIec104Vsq(apci);
+    if (asdu_size_map.find(asduType) == asdu_size_map.end())
+    {
+        // ASDU parsing not implemented for this type
+        return;
+    }
+
+    uint32_t verifiedNumberOfElements = parseIec104Vsq(apci, data_size);
     parseIec104CauseOfTx(apci);
     parseIec104TwoOctetCommonAddress(apci);
 
     // Set up the generic group structure
     GenericIec104AsduIOGroup genericIOGroup;
+    memset(&genericIOGroup, 0, sizeof(GenericIec104AsduIOGroup));
     genericIOGroup.asduType = asduType;
     genericIOGroup.apduSize = apci->header.length;
 
     // make sure the number of elements value is acceptable
     if (verifiedNumberOfElements > 0 && verifiedNumberOfElements <= 255) {
+
+        if ((const uint8_t*)apci + std::get<ASDU_MAP_OFFSET_ITEM>(asdu_size_map.at(asduType)) + (verifiedNumberOfElements * std::get<ASDU_MAP_SIZE_ITEM>(asdu_size_map.at(asduType))) > (const uint8_t*)apci + data_size)
+        {
+            // number of elements exceeds the bounds of the data size, lowering to fit
+            if (std::get<ASDU_MAP_OFFSET_ITEM>(asdu_size_map.at(asduType)) > data_size)
+            {
+                // If the offset is already greater than the data size, we can't fit any elements
+                verifiedNumberOfElements = 0;
+            }
+            else
+            {
+                verifiedNumberOfElements = (data_size - std::get<ASDU_MAP_OFFSET_ITEM>(asdu_size_map.at(asduType))) / std::get<ASDU_MAP_SIZE_ITEM>(asdu_size_map.at(asduType));
+            }
+
+            if (verifiedNumberOfElements == 0)
+            {
+                // shortcut to parse call for DetectionEngine checks
+                parseIec104GenericIOGroup(&genericIOGroup);
+                return;
+            }
+        }
+
         // iterate over the reported number of elements overlaying the structures
         for (uint32_t i = 0; i < verifiedNumberOfElements; i++)
         {
@@ -2587,7 +2717,7 @@ void parseIec104ApciS(const Iec104ApciS* apci)
     }
 }
 
-void parseIec104ApciI(const Iec104ApciI* apci)
+void parseIec104ApciI(const Iec104ApciI* apci, const uint16_t& data_size)
 {
     // throw an alert if the start value is not 0x68
     if (apci->header.start != IEC104_START_BYTE)
@@ -2647,7 +2777,7 @@ void parseIec104ApciI(const Iec104ApciI* apci)
             if (checkIec104Asdu(curAsduCheck))
             {
                 // parse the asdu if checks pass
-                parseIec104GenericAsdu(IEC104_ASDU_M_SP_NA_1, apci);
+                parseIec104GenericAsdu(IEC104_ASDU_M_SP_NA_1, apci, data_size);
             }
             break;
         }
@@ -2666,7 +2796,7 @@ void parseIec104ApciI(const Iec104ApciI* apci)
             if (checkIec104Asdu(curAsduCheck))
             {
                 // parse the asdu if checks pass
-                parseIec104GenericAsdu(IEC104_ASDU_M_SP_TA_1, apci);
+                parseIec104GenericAsdu(IEC104_ASDU_M_SP_TA_1, apci, data_size);
             }
             break;
         }
@@ -2703,7 +2833,7 @@ void parseIec104ApciI(const Iec104ApciI* apci)
             if (checkIec104Asdu(curAsduCheck))
             {
                 // parse the asdu if checks pass
-                parseIec104GenericAsdu(IEC104_ASDU_M_DP_NA_1, apci);
+                parseIec104GenericAsdu(IEC104_ASDU_M_DP_NA_1, apci, data_size);
             }
             break;
         }
@@ -2722,7 +2852,7 @@ void parseIec104ApciI(const Iec104ApciI* apci)
             if (checkIec104Asdu(curAsduCheck))
             {
                 // parse the asdu if checks pass
-                parseIec104GenericAsdu(IEC104_ASDU_M_DP_TA_1, apci);
+                parseIec104GenericAsdu(IEC104_ASDU_M_DP_TA_1, apci, data_size);
             }
             break;
         }
@@ -2759,7 +2889,7 @@ void parseIec104ApciI(const Iec104ApciI* apci)
             if (checkIec104Asdu(curAsduCheck))
             {
                 // parse the asdu if checks pass
-                parseIec104GenericAsdu(IEC104_ASDU_M_ST_NA_1, apci);
+                parseIec104GenericAsdu(IEC104_ASDU_M_ST_NA_1, apci, data_size);
             }
             break;
         }
@@ -2778,7 +2908,7 @@ void parseIec104ApciI(const Iec104ApciI* apci)
             if (checkIec104Asdu(curAsduCheck))
             {
                 // parse the asdu if checks pass
-                parseIec104GenericAsdu(IEC104_ASDU_M_ST_TA_1, apci);
+                parseIec104GenericAsdu(IEC104_ASDU_M_ST_TA_1, apci, data_size);
             }
             break;
         }
@@ -2815,7 +2945,7 @@ void parseIec104ApciI(const Iec104ApciI* apci)
             if (checkIec104Asdu(curAsduCheck))
             {
                 // parse the asdu if checks pass
-                parseIec104GenericAsdu(IEC104_ASDU_M_BO_NA_1, apci);
+                parseIec104GenericAsdu(IEC104_ASDU_M_BO_NA_1, apci, data_size);
             }
             break;
         }
@@ -2832,7 +2962,7 @@ void parseIec104ApciI(const Iec104ApciI* apci)
             if (checkIec104Asdu(curAsduCheck))
             {
                 // parse the asdu if checks pass
-                parseIec104GenericAsdu(IEC104_ASDU_M_BO_TA_1, apci);
+                parseIec104GenericAsdu(IEC104_ASDU_M_BO_TA_1, apci, data_size);
             }
             break;
         }
@@ -2868,7 +2998,7 @@ void parseIec104ApciI(const Iec104ApciI* apci)
             if (checkIec104Asdu(curAsduCheck))
             {
                 // parse the asdu if checks pass
-                parseIec104GenericAsdu(IEC104_ASDU_M_ME_NA_1, apci);
+                parseIec104GenericAsdu(IEC104_ASDU_M_ME_NA_1, apci, data_size);
             }
             break;
         }
@@ -2885,7 +3015,7 @@ void parseIec104ApciI(const Iec104ApciI* apci)
             if (checkIec104Asdu(curAsduCheck))
             {
                 // parse the asdu if checks pass
-                parseIec104GenericAsdu(IEC104_ASDU_M_ME_TA_1, apci);
+                parseIec104GenericAsdu(IEC104_ASDU_M_ME_TA_1, apci, data_size);
             }
             break;
         }
@@ -2921,7 +3051,7 @@ void parseIec104ApciI(const Iec104ApciI* apci)
             if (checkIec104Asdu(curAsduCheck))
             {
                 // parse the asdu if checks pass
-                parseIec104GenericAsdu(IEC104_ASDU_M_ME_NB_1, apci);
+                parseIec104GenericAsdu(IEC104_ASDU_M_ME_NB_1, apci, data_size);
             }
             break;
         }
@@ -2938,7 +3068,7 @@ void parseIec104ApciI(const Iec104ApciI* apci)
             if (checkIec104Asdu(curAsduCheck))
             {
                 // parse the asdu if checks pass
-                parseIec104GenericAsdu(IEC104_ASDU_M_ME_TB_1, apci);
+                parseIec104GenericAsdu(IEC104_ASDU_M_ME_TB_1, apci, data_size);
             }
             break;
         }
@@ -2974,7 +3104,7 @@ void parseIec104ApciI(const Iec104ApciI* apci)
             if (checkIec104Asdu(curAsduCheck))
             {
                 // parse the asdu if checks pass
-                parseIec104GenericAsdu(IEC104_ASDU_M_ME_NC_1, apci);
+                parseIec104GenericAsdu(IEC104_ASDU_M_ME_NC_1, apci, data_size);
             }
             break;
         }
@@ -2991,7 +3121,7 @@ void parseIec104ApciI(const Iec104ApciI* apci)
             if (checkIec104Asdu(curAsduCheck))
             {
                 // parse the asdu if checks pass
-                parseIec104GenericAsdu(IEC104_ASDU_M_ME_TC_1, apci);
+                parseIec104GenericAsdu(IEC104_ASDU_M_ME_TC_1, apci, data_size);
             }
             break;
         }
@@ -3012,7 +3142,7 @@ void parseIec104ApciI(const Iec104ApciI* apci)
             if (checkIec104Asdu(curAsduCheck))
             {
                 // parse the asdu if checks pass
-                parseIec104GenericAsdu(IEC104_ASDU_M_IT_NA_1, apci);
+                parseIec104GenericAsdu(IEC104_ASDU_M_IT_NA_1, apci, data_size);
             }
             break;
         }
@@ -3033,7 +3163,7 @@ void parseIec104ApciI(const Iec104ApciI* apci)
             if (checkIec104Asdu(curAsduCheck))
             {
                 // parse the asdu if checks pass
-                parseIec104GenericAsdu(IEC104_ASDU_M_IT_TA_1, apci);
+                parseIec104GenericAsdu(IEC104_ASDU_M_IT_TA_1, apci, data_size);
             }
             break;
         }
@@ -3049,7 +3179,7 @@ void parseIec104ApciI(const Iec104ApciI* apci)
             if (checkIec104Asdu(curAsduCheck))
             {
                 // parse the asdu if checks pass
-                parseIec104GenericAsdu(IEC104_ASDU_M_EP_TA_1, apci);
+                parseIec104GenericAsdu(IEC104_ASDU_M_EP_TA_1, apci, data_size);
             }
             break;
         }
@@ -3065,7 +3195,7 @@ void parseIec104ApciI(const Iec104ApciI* apci)
             if (checkIec104Asdu(curAsduCheck))
             {
                 // parse the asdu if checks pass
-                parseIec104GenericAsdu(IEC104_ASDU_M_EP_TB_1, apci);
+                parseIec104GenericAsdu(IEC104_ASDU_M_EP_TB_1, apci, data_size);
             }
             break;
         }
@@ -3081,7 +3211,7 @@ void parseIec104ApciI(const Iec104ApciI* apci)
             if (checkIec104Asdu(curAsduCheck))
             {
                 // parse the asdu if checks pass
-                parseIec104GenericAsdu(IEC104_ASDU_M_EP_TC_1, apci);
+                parseIec104GenericAsdu(IEC104_ASDU_M_EP_TC_1, apci, data_size);
             }
             break;
         }
@@ -3118,7 +3248,7 @@ void parseIec104ApciI(const Iec104ApciI* apci)
             if (checkIec104Asdu(curAsduCheck))
             {
                 // parse the asdu if checks pass
-                parseIec104GenericAsdu(IEC104_ASDU_M_PS_NA_1, apci);
+                parseIec104GenericAsdu(IEC104_ASDU_M_PS_NA_1, apci, data_size);
             }
             break;
         }
@@ -3154,7 +3284,7 @@ void parseIec104ApciI(const Iec104ApciI* apci)
             if (checkIec104Asdu(curAsduCheck))
             {
                 // parse the asdu if checks pass
-                parseIec104GenericAsdu(IEC104_ASDU_M_ME_ND_1, apci);
+                parseIec104GenericAsdu(IEC104_ASDU_M_ME_ND_1, apci, data_size);
             }
             break;
         }
@@ -3173,7 +3303,7 @@ void parseIec104ApciI(const Iec104ApciI* apci)
             if (checkIec104Asdu(curAsduCheck))
             {
                 // parse the asdu if checks pass
-                parseIec104GenericAsdu(IEC104_ASDU_M_SP_TB_1, apci);
+                parseIec104GenericAsdu(IEC104_ASDU_M_SP_TB_1, apci, data_size);
             }
             break;
         }
@@ -3192,7 +3322,7 @@ void parseIec104ApciI(const Iec104ApciI* apci)
             if (checkIec104Asdu(curAsduCheck))
             {
                 // parse the asdu if checks pass
-                parseIec104GenericAsdu(IEC104_ASDU_M_DP_TB_1, apci);
+                parseIec104GenericAsdu(IEC104_ASDU_M_DP_TB_1, apci, data_size);
             }
             break;
         }
@@ -3211,7 +3341,7 @@ void parseIec104ApciI(const Iec104ApciI* apci)
             if (checkIec104Asdu(curAsduCheck))
             {
                 // parse the asdu if checks pass
-                parseIec104GenericAsdu(IEC104_ASDU_M_ST_TB_1, apci);
+                parseIec104GenericAsdu(IEC104_ASDU_M_ST_TB_1, apci, data_size);
             }
             break;
         }
@@ -3228,7 +3358,7 @@ void parseIec104ApciI(const Iec104ApciI* apci)
             if (checkIec104Asdu(curAsduCheck))
             {
                 // parse the asdu if checks pass
-                parseIec104GenericAsdu(IEC104_ASDU_M_BO_TB_1, apci);
+                parseIec104GenericAsdu(IEC104_ASDU_M_BO_TB_1, apci, data_size);
             }
             break;
         }
@@ -3245,7 +3375,7 @@ void parseIec104ApciI(const Iec104ApciI* apci)
             if (checkIec104Asdu(curAsduCheck))
             {
                 // parse the asdu if checks pass
-                parseIec104GenericAsdu(IEC104_ASDU_M_ME_TD_1, apci);
+                parseIec104GenericAsdu(IEC104_ASDU_M_ME_TD_1, apci, data_size);
             }
             break;
         }
@@ -3262,7 +3392,7 @@ void parseIec104ApciI(const Iec104ApciI* apci)
             if (checkIec104Asdu(curAsduCheck))
             {
                 // parse the asdu if checks pass
-                parseIec104GenericAsdu(IEC104_ASDU_M_ME_TE_1, apci);
+                parseIec104GenericAsdu(IEC104_ASDU_M_ME_TE_1, apci, data_size);
             }
             break;
         }
@@ -3279,7 +3409,7 @@ void parseIec104ApciI(const Iec104ApciI* apci)
             if (checkIec104Asdu(curAsduCheck))
             {
                 // parse the asdu if checks pass
-                parseIec104GenericAsdu(IEC104_ASDU_M_ME_TF_1, apci);
+                parseIec104GenericAsdu(IEC104_ASDU_M_ME_TF_1, apci, data_size);
             }
             break;
         }
@@ -3300,7 +3430,7 @@ void parseIec104ApciI(const Iec104ApciI* apci)
             if (checkIec104Asdu(curAsduCheck))
             {
                 // parse the asdu if checks pass
-                parseIec104GenericAsdu(IEC104_ASDU_M_IT_TB_1, apci);
+                parseIec104GenericAsdu(IEC104_ASDU_M_IT_TB_1, apci, data_size);
             }
             break;
         }
@@ -3316,7 +3446,7 @@ void parseIec104ApciI(const Iec104ApciI* apci)
             if (checkIec104Asdu(curAsduCheck))
             {
                 // parse the asdu if checks pass
-                parseIec104GenericAsdu(IEC104_ASDU_M_EP_TD_1, apci);
+                parseIec104GenericAsdu(IEC104_ASDU_M_EP_TD_1, apci, data_size);
             }
             break;
         }
@@ -3332,7 +3462,7 @@ void parseIec104ApciI(const Iec104ApciI* apci)
             if (checkIec104Asdu(curAsduCheck))
             {
                 // parse the asdu if checks pass
-                parseIec104GenericAsdu(IEC104_ASDU_M_EP_TE_1, apci);
+                parseIec104GenericAsdu(IEC104_ASDU_M_EP_TE_1, apci, data_size);
             }
             break;
         }
@@ -3348,7 +3478,7 @@ void parseIec104ApciI(const Iec104ApciI* apci)
             if (checkIec104Asdu(curAsduCheck))
             {
                 // parse the asdu if checks pass
-                parseIec104GenericAsdu(IEC104_ASDU_M_EP_TF_1, apci);
+                parseIec104GenericAsdu(IEC104_ASDU_M_EP_TF_1, apci, data_size);
             }
             break;
         }
@@ -3372,7 +3502,7 @@ void parseIec104ApciI(const Iec104ApciI* apci)
             if (checkIec104Asdu(curAsduCheck))
             {
                 // parse the asdu if checks pass
-                parseIec104GenericAsdu(IEC104_ASDU_C_SC_NA_1, apci);
+                parseIec104GenericAsdu(IEC104_ASDU_C_SC_NA_1, apci, data_size);
             }
             break;
         }
@@ -3396,7 +3526,7 @@ void parseIec104ApciI(const Iec104ApciI* apci)
             if (checkIec104Asdu(curAsduCheck))
             {
                 // parse the asdu if checks pass
-                parseIec104GenericAsdu(IEC104_ASDU_C_DC_NA_1, apci);
+                parseIec104GenericAsdu(IEC104_ASDU_C_DC_NA_1, apci, data_size);
             }
             break;
         }
@@ -3420,7 +3550,7 @@ void parseIec104ApciI(const Iec104ApciI* apci)
             if (checkIec104Asdu(curAsduCheck))
             {
                 // parse the asdu if checks pass
-                parseIec104GenericAsdu(IEC104_ASDU_C_RC_NA_1, apci);
+                parseIec104GenericAsdu(IEC104_ASDU_C_RC_NA_1, apci, data_size);
             }
             break;
         }
@@ -3444,7 +3574,7 @@ void parseIec104ApciI(const Iec104ApciI* apci)
             if (checkIec104Asdu(curAsduCheck))
             {
                 // parse the asdu if checks pass
-                parseIec104GenericAsdu(IEC104_ASDU_C_SE_NA_1, apci);
+                parseIec104GenericAsdu(IEC104_ASDU_C_SE_NA_1, apci, data_size);
             }
             break;
         }
@@ -3468,7 +3598,7 @@ void parseIec104ApciI(const Iec104ApciI* apci)
             if (checkIec104Asdu(curAsduCheck))
             {
                 // parse the asdu if checks pass
-                parseIec104GenericAsdu(IEC104_ASDU_C_SE_NB_1, apci);
+                parseIec104GenericAsdu(IEC104_ASDU_C_SE_NB_1, apci, data_size);
             }
             break;
         }
@@ -3492,7 +3622,7 @@ void parseIec104ApciI(const Iec104ApciI* apci)
             if (checkIec104Asdu(curAsduCheck))
             {
                 // parse the asdu if checks pass
-                parseIec104GenericAsdu(IEC104_ASDU_C_SE_NC_1, apci);
+                parseIec104GenericAsdu(IEC104_ASDU_C_SE_NC_1, apci, data_size);
             }
             break;
         }
@@ -3516,7 +3646,7 @@ void parseIec104ApciI(const Iec104ApciI* apci)
             if (checkIec104Asdu(curAsduCheck))
             {
                 // parse the asdu if checks pass
-                parseIec104GenericAsdu(IEC104_ASDU_C_BO_NA_1, apci);
+                parseIec104GenericAsdu(IEC104_ASDU_C_BO_NA_1, apci, data_size);
             }
             break;
         }
@@ -3540,7 +3670,7 @@ void parseIec104ApciI(const Iec104ApciI* apci)
             if (checkIec104Asdu(curAsduCheck))
             {
                 // parse the asdu if checks pass
-                parseIec104GenericAsdu(IEC104_ASDU_C_SC_TA_1, apci);
+                parseIec104GenericAsdu(IEC104_ASDU_C_SC_TA_1, apci, data_size);
             }
             break;
         }
@@ -3564,7 +3694,7 @@ void parseIec104ApciI(const Iec104ApciI* apci)
             if (checkIec104Asdu(curAsduCheck))
             {
                 // parse the asdu if checks pass
-                parseIec104GenericAsdu(IEC104_ASDU_C_DC_TA_1, apci);
+                parseIec104GenericAsdu(IEC104_ASDU_C_DC_TA_1, apci, data_size);
             }
             break;
         }
@@ -3588,7 +3718,7 @@ void parseIec104ApciI(const Iec104ApciI* apci)
             if (checkIec104Asdu(curAsduCheck))
             {
                 // parse the asdu if checks pass
-                parseIec104GenericAsdu(IEC104_ASDU_C_RC_TA_1, apci);
+                parseIec104GenericAsdu(IEC104_ASDU_C_RC_TA_1, apci, data_size);
             }
             break;
         }
@@ -3612,7 +3742,7 @@ void parseIec104ApciI(const Iec104ApciI* apci)
             if (checkIec104Asdu(curAsduCheck))
             {
                 // parse the asdu if checks pass
-                parseIec104GenericAsdu(IEC104_ASDU_C_SE_TA_1, apci);
+                parseIec104GenericAsdu(IEC104_ASDU_C_SE_TA_1, apci, data_size);
             }
             break;
         }
@@ -3636,7 +3766,7 @@ void parseIec104ApciI(const Iec104ApciI* apci)
             if (checkIec104Asdu(curAsduCheck))
             {
                 // parse the asdu if checks pass
-                parseIec104GenericAsdu(IEC104_ASDU_C_SE_TB_1, apci);
+                parseIec104GenericAsdu(IEC104_ASDU_C_SE_TB_1, apci, data_size);
             }
             break;
         }
@@ -3660,7 +3790,7 @@ void parseIec104ApciI(const Iec104ApciI* apci)
             if (checkIec104Asdu(curAsduCheck))
             {
                 // parse the asdu if checks pass
-                parseIec104GenericAsdu(IEC104_ASDU_C_SE_TC_1, apci);
+                parseIec104GenericAsdu(IEC104_ASDU_C_SE_TC_1, apci, data_size);
             }
             break;
         }
@@ -3682,7 +3812,7 @@ void parseIec104ApciI(const Iec104ApciI* apci)
             if (checkIec104Asdu(curAsduCheck))
             {
                 // parse the asdu if checks pass
-                parseIec104GenericAsdu(IEC104_ASDU_C_BO_TA_1, apci);
+                parseIec104GenericAsdu(IEC104_ASDU_C_BO_TA_1, apci, data_size);
             }
             break;
         }
@@ -3698,7 +3828,7 @@ void parseIec104ApciI(const Iec104ApciI* apci)
             if (checkIec104Asdu(curAsduCheck))
             {
                 // parse the asdu if checks pass
-                parseIec104GenericAsdu(IEC104_ASDU_M_EI_NA_1, apci);
+                parseIec104GenericAsdu(IEC104_ASDU_M_EI_NA_1, apci, data_size);
             }
             break;
         }
@@ -3722,7 +3852,7 @@ void parseIec104ApciI(const Iec104ApciI* apci)
             if (checkIec104Asdu(curAsduCheck))
             {
                 // parse the asdu if checks pass
-                parseIec104GenericAsdu(IEC104_ASDU_C_IC_NA_1, apci);
+                parseIec104GenericAsdu(IEC104_ASDU_C_IC_NA_1, apci, data_size);
             }
             break;
         }
@@ -3746,7 +3876,7 @@ void parseIec104ApciI(const Iec104ApciI* apci)
             if (checkIec104Asdu(curAsduCheck))
             {
                 // parse the asdu if checks pass
-                parseIec104GenericAsdu(IEC104_ASDU_C_CI_NA_1, apci);
+                parseIec104GenericAsdu(IEC104_ASDU_C_CI_NA_1, apci, data_size);
             }
             break;
         }
@@ -3766,7 +3896,7 @@ void parseIec104ApciI(const Iec104ApciI* apci)
             if (checkIec104Asdu(curAsduCheck))
             {
                 // parse the asdu if checks pass
-                parseIec104GenericAsdu(IEC104_ASDU_C_RD_NA_1, apci);
+                parseIec104GenericAsdu(IEC104_ASDU_C_RD_NA_1, apci, data_size);
             }
             break;
         }
@@ -3788,7 +3918,7 @@ void parseIec104ApciI(const Iec104ApciI* apci)
             if (checkIec104Asdu(curAsduCheck))
             {
                 // parse the asdu if checks pass
-                parseIec104GenericAsdu(IEC104_ASDU_C_CS_NA_1, apci);
+                parseIec104GenericAsdu(IEC104_ASDU_C_CS_NA_1, apci, data_size);
             }
             break;
         }
@@ -3809,7 +3939,7 @@ void parseIec104ApciI(const Iec104ApciI* apci)
             if (checkIec104Asdu(curAsduCheck))
             {
                 // parse the asdu if checks pass
-                parseIec104GenericAsdu(IEC104_ASDU_C_TS_NA_1, apci);
+                parseIec104GenericAsdu(IEC104_ASDU_C_TS_NA_1, apci, data_size);
             }
             break;
         }
@@ -3829,7 +3959,7 @@ void parseIec104ApciI(const Iec104ApciI* apci)
             if (checkIec104Asdu(curAsduCheck))
             {
                 // parse the asdu if checks pass
-                parseIec104GenericAsdu(IEC104_ASDU_C_RP_NA_1, apci);
+                parseIec104GenericAsdu(IEC104_ASDU_C_RP_NA_1, apci, data_size);
             }
             break;
         }
@@ -3851,7 +3981,7 @@ void parseIec104ApciI(const Iec104ApciI* apci)
             if (checkIec104Asdu(curAsduCheck))
             {
                 // parse the asdu if checks pass
-                parseIec104GenericAsdu(IEC104_ASDU_C_CD_NA_1, apci);
+                parseIec104GenericAsdu(IEC104_ASDU_C_CD_NA_1, apci, data_size);
             }
             break;
         }
@@ -3872,7 +4002,7 @@ void parseIec104ApciI(const Iec104ApciI* apci)
             if (checkIec104Asdu(curAsduCheck))
             {
                 // parse the asdu if checks pass
-                parseIec104GenericAsdu(IEC104_ASDU_C_TS_TA_1, apci);
+                parseIec104GenericAsdu(IEC104_ASDU_C_TS_TA_1, apci, data_size);
             }
             break;
         }
@@ -3910,7 +4040,7 @@ void parseIec104ApciI(const Iec104ApciI* apci)
             if (checkIec104Asdu(curAsduCheck))
             {
                 // parse the asdu if checks pass
-                parseIec104GenericAsdu(IEC104_ASDU_P_ME_NA_1, apci);
+                parseIec104GenericAsdu(IEC104_ASDU_P_ME_NA_1, apci, data_size);
             }
             break;
         }
@@ -3948,7 +4078,7 @@ void parseIec104ApciI(const Iec104ApciI* apci)
             if (checkIec104Asdu(curAsduCheck))
             {
                 // parse the asdu if checks pass
-                parseIec104GenericAsdu(IEC104_ASDU_P_ME_NB_1, apci);
+                parseIec104GenericAsdu(IEC104_ASDU_P_ME_NB_1, apci, data_size);
             }
             break;
         }
@@ -3986,7 +4116,7 @@ void parseIec104ApciI(const Iec104ApciI* apci)
             if (checkIec104Asdu(curAsduCheck))
             {
                 // parse the asdu if checks pass
-                parseIec104GenericAsdu(IEC104_ASDU_P_ME_NC_1, apci);
+                parseIec104GenericAsdu(IEC104_ASDU_P_ME_NC_1, apci, data_size);
             }
             break;
         }
@@ -4009,7 +4139,7 @@ void parseIec104ApciI(const Iec104ApciI* apci)
             if (checkIec104Asdu(curAsduCheck))
             {
                 // parse the asdu if checks pass
-                parseIec104GenericAsdu(IEC104_ASDU_P_AC_NA_1, apci);
+                parseIec104GenericAsdu(IEC104_ASDU_P_AC_NA_1, apci, data_size);
             }
             break;
         }
@@ -4029,7 +4159,7 @@ void parseIec104ApciI(const Iec104ApciI* apci)
             if (checkIec104Asdu(curAsduCheck))
             {
                 // parse the asdu if checks pass
-                parseIec104GenericAsdu(IEC104_ASDU_F_FR_NA_1, apci);
+                parseIec104GenericAsdu(IEC104_ASDU_F_FR_NA_1, apci, data_size);
             }
             break;
         }
@@ -4049,7 +4179,7 @@ void parseIec104ApciI(const Iec104ApciI* apci)
             if (checkIec104Asdu(curAsduCheck))
             {
                 // parse the asdu if checks pass
-                parseIec104GenericAsdu(IEC104_ASDU_F_SR_NA_1, apci);
+                parseIec104GenericAsdu(IEC104_ASDU_F_SR_NA_1, apci, data_size);
             }
             break;
         }
@@ -4070,7 +4200,7 @@ void parseIec104ApciI(const Iec104ApciI* apci)
             if (checkIec104Asdu(curAsduCheck))
             {
                 // parse the asdu if checks pass
-                parseIec104GenericAsdu(IEC104_ASDU_F_SC_NA_1, apci);
+                parseIec104GenericAsdu(IEC104_ASDU_F_SC_NA_1, apci, data_size);
             }
             break;
         }
@@ -4090,7 +4220,7 @@ void parseIec104ApciI(const Iec104ApciI* apci)
             if (checkIec104Asdu(curAsduCheck))
             {
                 // parse the asdu if checks pass
-                parseIec104GenericAsdu(IEC104_ASDU_F_LS_NA_1, apci);
+                parseIec104GenericAsdu(IEC104_ASDU_F_LS_NA_1, apci, data_size);
             }
             break;
         }
@@ -4110,7 +4240,7 @@ void parseIec104ApciI(const Iec104ApciI* apci)
             if (checkIec104Asdu(curAsduCheck))
             {
                 // parse the asdu if checks pass
-                parseIec104GenericAsdu(IEC104_ASDU_F_AF_NA_1, apci);
+                parseIec104GenericAsdu(IEC104_ASDU_F_AF_NA_1, apci, data_size);
             }
             break;
         }
@@ -4130,7 +4260,7 @@ void parseIec104ApciI(const Iec104ApciI* apci)
             if (checkIec104Asdu(curAsduCheck))
             {
                 // parse the asdu if checks pass
-                parseIec104GenericAsdu(IEC104_ASDU_F_SG_NA_1, apci);
+                parseIec104GenericAsdu(IEC104_ASDU_F_SG_NA_1, apci, data_size);
             }
             break;
         }
@@ -4147,7 +4277,7 @@ void parseIec104ApciI(const Iec104ApciI* apci)
             if (checkIec104Asdu(curAsduCheck))
             {
                 // parse the asdu if checks pass
-                parseIec104GenericAsdu(IEC104_ASDU_F_DR_TA_1, apci);
+                parseIec104GenericAsdu(IEC104_ASDU_F_DR_TA_1, apci, data_size);
             }
             break;
         }
@@ -4167,7 +4297,7 @@ void parseIec104ApciI(const Iec104ApciI* apci)
             if (checkIec104Asdu(curAsduCheck))
             {
                 // parse the asdu if checks pass
-                parseIec104GenericAsdu(IEC104_ASDU_F_SC_NB_1, apci);
+                parseIec104GenericAsdu(IEC104_ASDU_F_SC_NB_1, apci, data_size);
             }
             break;
         }
@@ -4180,4 +4310,3 @@ void parseIec104ApciI(const Iec104ApciI* apci)
         }
     }
 }
-
index 9aa35ed30bff687985a9555ad93253825d834cd7..3aba3024ca44342c9204787f4e05189febfe5641 100644 (file)
@@ -25,7 +25,7 @@
 
 void parseIec104ApciU(const struct Iec104ApciU* apci);
 void parseIec104ApciS(const struct Iec104ApciS* apci);
-void parseIec104ApciI(const struct Iec104ApciI* apci);
+void parseIec104ApciI(const struct Iec104ApciI* apci, const uint16_t& data_size);
 
 
 #define IEC104_ERROR -1
index 511ce7e6fd4d1a26062e69f34e5c4eb137555a83..2b5c1d404a0276ebdcc05ef00834e03edc745a56 100644 (file)
@@ -190,7 +190,7 @@ void parseIec104Afq(const Iec104AfqType* afq)
     }
 }
 
-uint32_t parseIec104Vsq(const Iec104ApciI* apci)
+uint32_t parseIec104Vsq(const Iec104ApciI* apci, const uint16_t& data_size)
 {
     // number of elements == 0 is caught in check apdu
 
@@ -547,7 +547,7 @@ uint32_t parseIec104Vsq(const Iec104ApciI* apci)
     if (informationObjectSubgroupSize)
     {
         uint32_t reported_msg_len = apci->header.length;
-        if (reported_msg_len >= IEC104_APCI_TYPE_I_MIN_LEN) {
+        if (reported_msg_len >= IEC104_APCI_TYPE_I_MIN_LEN and reported_msg_len <= data_size) {
             if (apci->asdu.variableStructureQualifier.sq == 0)
             {
                 uint32_t informationObjectGroupSize = informationObjectSubgroupSize + sizeof(const Iec104InformationObjectAddressThreeOctetType);
@@ -1074,6 +1074,11 @@ void parseIec104Lof(const Iec104LofType* lof)
 // LOS: Length of Segment Structure
 bool parseIec104Los(const Iec104LosType* los, uint16_t apduSize)
 {
+    if (!los)
+    {
+        DetectionEngine::queue_event(GID_IEC104, IEC104_NULL_LOS_VALUE);
+        return false;
+    }
     // flag to prevent debug parsing of the segments when an alert is thrown
     // doing this via a flag so that the debug messages for the LOS field still print
     bool losValid = true;
index 1393b31b6a60d4dc4b8f6aa7ca366beaebf5e3d9..a9b48cc6f50649a22ac8f44be9a306e65bec5439 100644 (file)
@@ -46,7 +46,7 @@ void parseIec104Srq(const Iec104SrqType* srq);
 void parseIec104Scq(const Iec104ScqType* scq);
 void parseIec104Lsq(const Iec104LsqType* lsq);
 void parseIec104Afq(const Iec104AfqType* afq);
-uint32_t parseIec104Vsq(const Iec104ApciI* apci);
+uint32_t parseIec104Vsq(const Iec104ApciI* apci, const uint16_t& data_size);
 void parseIec104CauseOfTx(const Iec104ApciI* apci);
 void parseIec104TwoOctetCommonAddress(const Iec104ApciI* apci);
 void parseIec104InformationObjectAddressWithThreeOctets(
diff --git a/src/service_inspectors/iec104/test/CMakeLists.txt b/src/service_inspectors/iec104/test/CMakeLists.txt
new file mode 100644 (file)
index 0000000..2bd86e3
--- /dev/null
@@ -0,0 +1,3 @@
+add_cpputest( iec104_parse_apdu_test
+    SOURCES
+    ../iec104_parse_information_object_elements.cc )
\ No newline at end of file
diff --git a/src/service_inspectors/iec104/test/iec104_parse_apdu_test.cc b/src/service_inspectors/iec104/test/iec104_parse_apdu_test.cc
new file mode 100644 (file)
index 0000000..dba8140
--- /dev/null
@@ -0,0 +1,60 @@
+//--------------------------------------------------------------------------
+// Copyright (C) 2024-2025 Cisco and/or its affiliates. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License Version 2 as published
+// by the Free Software Foundation.  You may not use, modify or distribute
+// this program under any other version of the GNU General Public License.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+//--------------------------------------------------------------------------
+// iec104_parse_apdu_test.cc author Oleksandr Stepanov <ostepano@cisco.com>
+
+#include <unordered_map>
+#include <vector>
+
+#include "../iec104_parse_apdu.cc"
+
+#include <CppUTest/CommandLineTestRunner.h>
+#include <CppUTest/TestHarness.h>
+#include <CppUTestExt/MockSupport.h>
+
+int snort::DetectionEngine::queue_event(unsigned int, unsigned int) { return 0; }
+
+TEST_GROUP(iec104_parse_apdu_invalid_packet_len)
+{
+};
+
+const uint8_t test_data_1[] = {0x68, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x01, 0x81, 0x03, 0x01, 0x00, 0x00};
+const uint8_t test_data_2[] = {0x68, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x03, 0x01, 0x00, 0x00};
+
+TEST(iec104_parse_apdu_invalid_packet_len, invalid_group_data)
+{
+    static bool result = true;
+    genericGroupPtr = [](const void* genericIOGroup)
+    {
+        if (result)
+        {
+            result = genericIOGroup == nullptr;
+        }
+    };
+    
+    for(uint32_t i = 0; i < 128; i++)
+    {
+        parseIec104GenericAsdu(i, (const Iec104ApciI*)test_data_1, sizeof(test_data_1));
+        parseIec104GenericAsdu(i, (const Iec104ApciI*)test_data_2, sizeof(test_data_2));
+    }
+    CHECK_EQUAL(true, result);
+}
+
+int main(int argc, char** argv)
+{
+    return CommandLineTestRunner::RunAllTests(argc, argv);
+}
\ No newline at end of file