diff --git a/lib60870-C/src/iec60870/cs101/cs101_asdu.c b/lib60870-C/src/iec60870/cs101/cs101_asdu.c index eba6060c..aa1a6a54 100644 --- a/lib60870-C/src/iec60870/cs101/cs101_asdu.c +++ b/lib60870-C/src/iec60870/cs101/cs101_asdu.c @@ -1,5 +1,5 @@ /* - * Copyright 2016, 2017 MZ Automation GmbH + * Copyright 2016-2019 MZ Automation GmbH * * This file is part of lib60870-C * @@ -233,16 +233,21 @@ CS101_ASDU_addInformationObject(CS101_ASDU self, InformationObject io) } else if (numberOfElements < 0x7f) { - if (CS101_ASDU_isSequence(self)) { + /* Check if type of information object is matching ASDU type */ - /* check that new information object has correct IOA */ - if (InformationObject_getObjectAddress(io) == (getFirstIOA(self) + CS101_ASDU_getNumberOfElements(self))) - encoded = InformationObject_encode(io, (Frame) &asduFrame, self->parameters, true); - else - encoded = false; - } - else { - encoded = InformationObject_encode(io, (Frame) &asduFrame, self->parameters, false);; + if (self->asdu[0] == (uint8_t) InformationObject_getType(io)) { + + if (CS101_ASDU_isSequence(self)) { + + /* check that new information object has correct IOA */ + if (InformationObject_getObjectAddress(io) == (getFirstIOA(self) + CS101_ASDU_getNumberOfElements(self))) + encoded = InformationObject_encode(io, (Frame) &asduFrame, self->parameters, true); + else + encoded = false; + } + else { + encoded = InformationObject_encode(io, (Frame) &asduFrame, self->parameters, false);; + } } } diff --git a/lib60870-C/src/inc/api/iec60870_common.h b/lib60870-C/src/inc/api/iec60870_common.h index 4bf426f4..045a3409 100644 --- a/lib60870-C/src/inc/api/iec60870_common.h +++ b/lib60870-C/src/inc/api/iec60870_common.h @@ -465,10 +465,12 @@ CS101_ASDU_destroy(CS101_ASDU self); /** * \brief add an information object to the ASDU * + * NOTE: Only information objects of the exact same type can be added to a single ASDU! + * * \param self ASDU object instance * \param io information object to be added * - * \return true when added, false when there not enough space left in the ASDU or IO cannot be added to the sequence because of wrong IOA. + * \return true when added, false when there not enough space left in the ASDU or IO cannot be added to the sequence because of wrong IOA, or wrong type. */ bool CS101_ASDU_addInformationObject(CS101_ASDU self, InformationObject io); diff --git a/lib60870-C/tests/all_tests.c b/lib60870-C/tests/all_tests.c index 7f95a6c6..bf398f01 100644 --- a/lib60870-C/tests/all_tests.c +++ b/lib60870-C/tests/all_tests.c @@ -5016,6 +5016,125 @@ test_CS104_Connection_ConnectTimeout(void) CS104_Connection_destroy(con); } +void +test_CS104_Connection_UseAfterClose(void) +{ + CS104_Slave slave = NULL; + CS104_Connection con = NULL; + + slave = CS104_Slave_create(100, 100); + + TEST_ASSERT_NOT_NULL(slave); + + CS104_Slave_setLocalPort(slave, 20004); + CS104_Slave_start(slave); + + con = CS104_Connection_create("127.0.0.1", 20004); + + TEST_ASSERT_NOT_NULL(con); + + bool result = CS104_Connection_connect(con); + + TEST_ASSERT_TRUE(result); + + CS104_Connection_close(con); + + result = CS104_Connection_sendInterrogationCommand(con, CS101_COT_ACTIVATION, 1, IEC60870_QOI_STATION); + + TEST_ASSERT_FALSE(result); + + CS104_Slave_destroy(slave); + + CS104_Connection_destroy(con); +} + +void +test_CS104_Connection_UseAfterServerClosedConnection(void) +{ + CS104_Slave slave = NULL; + CS104_Connection con = NULL; + + slave = CS104_Slave_create(100, 100); + + TEST_ASSERT_NOT_NULL(slave); + + CS104_Slave_setLocalPort(slave, 20004); + CS104_Slave_start(slave); + + con = CS104_Connection_create("127.0.0.1", 20004); + + TEST_ASSERT_NOT_NULL(con); + + bool result = CS104_Connection_connect(con); + + TEST_ASSERT_TRUE(result); + + CS104_Slave_destroy(slave); + + /* wait to allow client side to detect connection loss */ + Thread_sleep(500); + + result = CS104_Connection_sendInterrogationCommand(con, CS101_COT_ACTIVATION, 1, IEC60870_QOI_STATION); + + TEST_ASSERT_FALSE(result); + + CS104_Connection_destroy(con); +} + +void +test_CS101_ASDU_addObjectOfWrongType(void) +{ + CS101_ASDU asdu = CS101_ASDU_create(&defaultAppLayerParameters, false, CS101_COT_PERIODIC, 0, 1, false, false); + + InformationObject io1 = (InformationObject) SinglePointInformation_create(NULL, 101, true, IEC60870_QUALITY_GOOD); + + bool added = CS101_ASDU_addInformationObject(asdu, io1); + + TEST_ASSERT_TRUE(added); + + InformationObject_destroy(io1); + + InformationObject io2 = (InformationObject) DoublePointInformation_create(NULL, 102, IEC60870_DOUBLE_POINT_OFF, IEC60870_QUALITY_GOOD); + + added = CS101_ASDU_addInformationObject(asdu, io2); + + TEST_ASSERT_FALSE(added); + + InformationObject_destroy(io2); + + CS101_ASDU_destroy(asdu); +} + +void +test_CS101_ASDU_addUntilOverflow(void) +{ + CS101_ASDU asdu = CS101_ASDU_create(&defaultAppLayerParameters, false, CS101_COT_PERIODIC, 0, 1, false, false); + + int i = 0; + + for (i = 0; i < 60; i++) { + InformationObject io = (InformationObject) SinglePointInformation_create(NULL, 100 + i, true, IEC60870_QUALITY_GOOD); + + bool added = CS101_ASDU_addInformationObject(asdu, io); + + TEST_ASSERT_TRUE(added); + + InformationObject_destroy(io); + + TEST_ASSERT_EQUAL_INT(i + 1, CS101_ASDU_getNumberOfElements(asdu)); + } + + InformationObject io = (InformationObject) SinglePointInformation_create(NULL, 100 + i, true, IEC60870_QUALITY_GOOD); + + bool added = CS101_ASDU_addInformationObject(asdu, io); + + TEST_ASSERT_FALSE(added); + + InformationObject_destroy(io); + + CS101_ASDU_destroy(asdu); +} + int main(int argc, char** argv) { @@ -5103,5 +5222,10 @@ main(int argc, char** argv) RUN_TEST(test_CS104_Connection_ConnectTimeout); + RUN_TEST(test_CS104_Connection_UseAfterClose); + RUN_TEST(test_CS104_Connection_UseAfterServerClosedConnection); + RUN_TEST(test_CS101_ASDU_addObjectOfWrongType); + RUN_TEST(test_CS101_ASDU_addUntilOverflow); + return UNITY_END(); }