diff --git a/CMakeLists.txt b/CMakeLists.txt index 45a1c20a..a538fb97 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -49,6 +49,9 @@ option(CONFIG_IEC61850_SERVICE_TRACKING "Build with support for IEC 61850 servic option(CONFIG_IEC61850_SETTING_GROUPS "Build with support for IEC 61850 setting group services" ON) option(CONFIG_IEC61850_SUPPORT_USER_READ_ACCESS_CONTROL "Allow user provided callback to control read access" ON) option(CONFIG_IEC61850_RCB_ALLOW_ONLY_PRECONFIGURED_CLIENT "allow only configured clients (when pre-configured by ClientLN)" OFF) +option(CONFIG_IEC61850_R_GOOSE "Build with support for R-GOOSE (mbedtls required)" ON) +option(CONFIG_IEC61850_R_SMV "Build with support for R-SMV (mbedtls required)" ON) +option(CONFIG_IEC61850_SNTP_CLIENT "Build with SNTP client code" ON) set(CONFIG_REPORTING_DEFAULT_REPORT_BUFFER_SIZE "65536" CACHE STRING "Default buffer size for buffered reports in byte" ) @@ -93,6 +96,7 @@ set(API_HEADERS hal/inc/tls_config.h src/common/inc/libiec61850_common_api.h src/common/inc/linked_list.h + src/common/inc/sntp_client.h src/iec61850/inc/iec61850_client.h src/iec61850/inc/iec61850_common.h src/iec61850/inc/iec61850_server.h @@ -137,6 +141,18 @@ if(WITH_MBEDTLS) add_definitions(-DCONFIG_MMS_SUPPORT_TLS=1) +if (CONFIG_IEC61850_R_GOOSE) +set(BUILD_R_GOOSE_EXAMPLES 1) +endif (CONFIG_IEC61850_R_GOOSE) + +if (CONFIG_IEC61850_R_SMV) +set(BUILD_R_SMV_EXAMPLES 1) +endif (CONFIG_IEC61850_R_SMV) + +if (CONFIG_IEC61850_SNTP_CLIENT) +set(BUILD_SNTP_CLIENT_EXAMPLES 1) +endif (CONFIG_IEC61850_SNTP_CLIENT) + endif(WITH_MBEDTLS) include(CheckCCompilerFlag) diff --git a/config/stack_config.h b/config/stack_config.h index 8a71f0c3..5518b9f0 100644 --- a/config/stack_config.h +++ b/config/stack_config.h @@ -173,6 +173,15 @@ /* Force memory alignment - required for some platforms (required more memory for buffered reporting) */ #define CONFIG_IEC61850_FORCE_MEMORY_ALIGNMENT 1 +/* compile with support for R-GOOSE (mbedtls requried) */ +#define CONFIG_IEC61850_R_GOOSE 0 + +/* compile with support for R-SMV (mbedtls required) */ +#define CONFIG_IEC61850_R_SMV 0 + +/* compile SNTP client code */ +#define CONFIG_IEC61850_SNTP_CLIENT 0 + /* overwrite default results for MMS identify service */ /* #define CONFIG_DEFAULT_MMS_VENDOR_NAME "libiec61850.com" */ /* #define CONFIG_DEFAULT_MMS_MODEL_NAME "LIBIEC61850" */ diff --git a/config/stack_config.h.cmake b/config/stack_config.h.cmake index d3ef67b5..2901316d 100644 --- a/config/stack_config.h.cmake +++ b/config/stack_config.h.cmake @@ -74,6 +74,15 @@ /* Set to 1 to include Sampled Values support in the build. Otherwise set to 0 */ #define CONFIG_IEC61850_SAMPLED_VALUES_SUPPORT 1 +/* compile with support for R-GOOSE (mbedtls requried) */ +#cmakedefine01 CONFIG_IEC61850_R_GOOSE + +/* compile with support for R-SMV (mbedtls required) */ +#cmakedefine01 CONFIG_IEC61850_R_SMV + +/* compile SNTP client code */ +#cmakedefine01 CONFIG_IEC61850_SNTP_CLIENT + /* Set to 1 to compile for edition 1 server - default is 0 to compile for edition 2 */ #define CONFIG_IEC61850_EDITION_1 0 diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 23e9d3aa..ac08165a 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -26,12 +26,20 @@ add_subdirectory(iec61850_client_example_array) add_subdirectory(iec61850_client_example_files) add_subdirectory(iec61850_client_example_async) add_subdirectory(iec61850_client_file_async) + +if (${BUILD_SNTP_CLIENT_EXAMPLES}) add_subdirectory(sntp_example) +endif() +if(${BUILD_R_SMV_EXAMPLES}) add_subdirectory(rsv_publisher_example) add_subdirectory(rsv_subscriber_example) +endif() + +if(${BUILD_R_GOOSE_EXAMPLES}) add_subdirectory(r_goose_publisher_example) add_subdirectory(r_goose_receiver_example) +endif() if (NOT WIN32) add_subdirectory(mms_utility) diff --git a/examples/sntp_example/sntp_example.c b/examples/sntp_example/sntp_example.c index b395a60d..cb66d1b4 100644 --- a/examples/sntp_example/sntp_example.c +++ b/examples/sntp_example/sntp_example.c @@ -29,7 +29,6 @@ main(int argc, char** argv) { SNTPClient client = SNTPClient_create(); - //SNTPClient_addServer(client, "127.0.0.1", 1236); SNTPClient_addServer(client, "192.168.178.74", 123); SNTPClient_setUserCallback(client, sntpUserCallback, NULL); diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index e8f8a3fb..65b3ca1a 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -83,7 +83,6 @@ set (lib_common_SRCS ./iec61850/server/mms_mapping/mms_sv.c ./iec61850/server/mms_mapping/logging.c ./logging/log_storage.c -./sntp/sntp_client.c ) set (lib_asn1c_SRCS @@ -190,10 +189,24 @@ set (lib_sv_SRCS ./sampled_values/sv_publisher.c ) +if(WITH_MBEDTLS AND (CONFIG_IEC61850_R_GOOSE OR CONFIG_IEC61850_R_SMV)) set (lib_rsession_SRCS ./r_session/r_session.c ./r_session/r_session_crypto_mbedtls.c ) +else() +set (lib_rsession_SRCS +) +endif() + +if(CONFIG_IEC61850_SNTP_CLIENT) +set (lib_sntp_SRCS +./sntp/sntp_client.c +) +else() +set (lib_sntp_SRCS +) +endif() set (lib_linux_SRCS ) @@ -245,6 +258,7 @@ set (library_SRCS ${lib_sv_SRCS} ${lib_rsession_SRCS} ${lib_windows_SRCS} + ${lib_sntp_SRCS} ) ELSE() @@ -253,6 +267,7 @@ set (library_SRCS ${lib_asn1c_SRCS} ${lib_windows_SRCS} ${lib_rsession_SRCS} + ${lib_sntp_SRCS} ) ENDIF(WITH_WPCAP) @@ -265,6 +280,7 @@ set (library_SRCS ${lib_goose_SRCS} ${lib_sv_SRCS} ${lib_rsession_SRCS} + ${lib_sntp_SRCS} ${lib_bsd_SRCS} ) ELSEIF(${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD") @@ -274,6 +290,7 @@ set (library_SRCS ${lib_goose_SRCS} ${lib_sv_SRCS} ${lib_rsession_SRCS} + ${lib_sntp_SRCS} ${lib_bsd_SRCS} ) ELSE() @@ -283,6 +300,7 @@ set (library_SRCS ${lib_goose_SRCS} ${lib_sv_SRCS} ${lib_rsession_SRCS} + ${lib_sntp_SRCS} ${lib_linux_SRCS} ) ENDIF(APPLE) diff --git a/src/goose/goose_publisher.c b/src/goose/goose_publisher.c index 85182d7a..7409bd21 100644 --- a/src/goose/goose_publisher.c +++ b/src/goose/goose_publisher.c @@ -43,9 +43,11 @@ prepareGooseBuffer(GoosePublisher self, CommParameters* parameters, const char* struct sGoosePublisher { uint8_t* buffer; +#if (CONFIG_IEC61850_R_GOOSE == 1) /* only for R-GOOSE */ RSession remoteSession; uint16_t appId; +#endif /* (CONFIG_IEC61850_R_GOOSE == 1) */ /* only for Ethernet based GOOSE */ EthernetSocket ethernetSocket; @@ -68,6 +70,7 @@ struct sGoosePublisher { MmsValue* timestamp; /* time when stNum is increased */ }; +#if (CONFIG_IEC61850_R_GOOSE == 1) GoosePublisher GoosePublisher_createRemote(RSession session, uint16_t appId) { @@ -94,6 +97,7 @@ GoosePublisher_createRemote(RSession session, uint16_t appId) return self; } +#endif /* (CONFIG_IEC61850_R_GOOSE == 1) */ GoosePublisher GoosePublisher_createEx(CommParameters* parameters, const char* interfaceID, bool useVlanTag) @@ -471,6 +475,7 @@ GoosePublisher_publish(GoosePublisher self, LinkedList dataSet) if (DEBUG_GOOSE_PUBLISHER) printf("GOOSE_PUBLISHER: send GOOSE message\n"); } +#if (CONFIG_IEC61850_R_GOOSE == 1) else if (self->remoteSession) { RSession_sendMessage(self->remoteSession, RSESSION_SPDU_ID_GOOSE, self->simulation, self->appId, buffer, self->payloadLength); @@ -478,6 +483,7 @@ GoosePublisher_publish(GoosePublisher self, LinkedList dataSet) if (DEBUG_GOOSE_PUBLISHER) printf("GOOSE_PUBLISHER: send R-GOOSE message\n"); } +#endif /* (CONFIG_IEC61850_R_GOOSE == 1) */ return 0; } diff --git a/src/goose/goose_receiver.c b/src/goose/goose_receiver.c index 78b7a690..11b172c2 100644 --- a/src/goose/goose_receiver.c +++ b/src/goose/goose_receiver.c @@ -57,8 +57,10 @@ struct sGooseReceiver /* for Ethernet GOOSE only */ EthernetSocket ethSocket; +#if (CONFIG_IEC61850_R_GOOSE == 1) /* for R-GOOSE only */ RSession session; +#endif /* (CONFIG_IEC61850_R_GOOSE == 1) */ LinkedList subscriberList; #if (CONFIG_MMS_THREADLESS_STACK == 0) @@ -98,6 +100,7 @@ GooseReceiver_create() return self; } +#if (CONFIG_IEC61850_R_GOOSE == 1) GooseReceiver GooseReceiver_createRemote(RSession session) { @@ -109,6 +112,7 @@ GooseReceiver_createRemote(RSession session) return self; } +#endif /* (CONFIG_IEC61850_R_GOOSE == 1) */ void GooseReceiver_addSubscriber(GooseReceiver self, GooseSubscriber subscriber) @@ -1038,6 +1042,7 @@ gooseReceiverLoop(void *threadParameter) EthernetHandleSet_destroy(handleSet); } +#if (CONFIG_IEC61850_R_GOOSE == 1) else if (self->session) { HandleSet handleSet = Handleset_new(); @@ -1064,6 +1069,7 @@ gooseReceiverLoop(void *threadParameter) Handleset_destroy(handleSet); } +#endif /* (CONFIG_IEC61850_R_GOOSE == 1) */ return NULL; } @@ -1085,12 +1091,14 @@ GooseReceiver_start(GooseReceiver self) Thread_start(self->thread); } +#if (CONFIG_IEC61850_R_GOOSE == 1) else if (self->session) { if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: R-GOOSE receiver started\n"); Thread_start(self->thread); } +#endif /* (CONFIG_IEC61850_R_GOOSE == 1) */ else { if (DEBUG_GOOSE_SUBSCRIBER) printf("GOOSE_SUBSCRIBER: ERROR - No link/transport layer specified -> cannot start!\n"); @@ -1153,6 +1161,7 @@ GooseReceiver_destroy(GooseReceiver self) EthernetSocket GooseReceiver_startThreadless(GooseReceiver self) { +#if (CONFIG_IEC61850_R_GOOSE == 1) if (self->session) { if (RSession_startListening(self->session) == R_SESSION_ERROR_OK) { self->running = true; @@ -1166,6 +1175,8 @@ GooseReceiver_startThreadless(GooseReceiver self) } } else { +#endif /* (CONFIG_IEC61850_R_GOOSE == 1) */ + if (self->interfaceId == NULL) self->ethSocket = Ethernet_createSocket(CONFIG_ETHERNET_INTERFACE_ID, NULL); else @@ -1198,7 +1209,10 @@ GooseReceiver_startThreadless(GooseReceiver self) else { self->running = false; } + +#if (CONFIG_IEC61850_R_GOOSE == 1) } +#endif /* (CONFIG_IEC61850_R_GOOSE == 1) */ return self->ethSocket; } @@ -1225,6 +1239,7 @@ handleSessionPayloadElement(void* parameter, uint16_t appId, uint8_t* payloadDat bool GooseReceiver_tick(GooseReceiver self) { +#if (CONFIG_IEC61850_R_GOOSE == 1) if (self->session) { if (RSession_receiveMessage(self->session, handleSessionPayloadElement, (void*) self) == R_SESSION_ERROR_OK) return true; @@ -1232,6 +1247,8 @@ GooseReceiver_tick(GooseReceiver self) return false; } else { +#endif /* (CONFIG_IEC61850_R_GOOSE == 1) */ + int packetSize = Ethernet_receivePacket(self->ethSocket, self->buffer, ETH_BUFFER_LENGTH); if (packetSize > 0) { @@ -1240,7 +1257,10 @@ GooseReceiver_tick(GooseReceiver self) } else return false; + +#if (CONFIG_IEC61850_R_GOOSE == 1) } +#endif /* (CONFIG_IEC61850_R_GOOSE == 1) */ } void diff --git a/src/r_session/r_session.c b/src/r_session/r_session.c index 7e6677a7..704aba19 100644 --- a/src/r_session/r_session.c +++ b/src/r_session/r_session.c @@ -30,9 +30,11 @@ #include "r_session_crypto.h" #include "r_session_internal.h" -#define DEBUG_RSESSION +#ifndef DEBUG_RSESSION +#define DEBUG_RSESSION 0 +#endif -#ifdef DEBUG_RSESSION +#if (DEBUG_RSESSION == 1) #include #define DEBUG_PRINTF(...) printf("RSESSION:"__VA_ARGS__);printf("\n"); #else @@ -98,7 +100,7 @@ printBuffer(uint8_t* buffer, int bufSize) printf(" (%i)\n", i + 1); } } -#endif +#endif /* DEBUG_RSESSION */ RSessionKeyMaterial RSessionKeyMaterial_create(uint32_t keyId, uint8_t* key, int keyLength, RSecurityAlgorithm secAlgo, RSignatureAlgorithm sigAlgo) @@ -1020,7 +1022,7 @@ RSession_receiveMessage(RSession self, RSessionPayloadElementHandler handler, vo Semaphore_post(self->socketLock); if (msgSize < 1) { - printf("RESSSION: Failed to receive message\n"); + DEBUG_PRINTF("RESSSION: Failed to receive message"); return R_SESSION_ERROR_FAILED_TO_RECEIVE; diff --git a/src/sampled_values/sv_publisher.c b/src/sampled_values/sv_publisher.c index eb67db4c..d14b788d 100644 --- a/src/sampled_values/sv_publisher.c +++ b/src/sampled_values/sv_publisher.c @@ -79,8 +79,10 @@ struct sSVPublisher { /* only for Ethernet based SV */ EthernetSocket ethernetSocket; +#if (CONFIG_IEC61850_R_SMV == 1) /* only for R-SV */ RSession remoteSession; +#endif /* (CONFIG_IEC61850_R_SMV == 1) */ int lengthField; /* can probably be removed since packets have fixed size! */ int payloadStart; @@ -273,6 +275,7 @@ encodeInt64FixedSize(int64_t value, uint8_t* buffer, int bufPos) return bufPos; } +#if (CONFIG_IEC61850_R_SMV == 1) SVPublisher SVPublisher_createRemote(RSession session, uint16_t appId) { @@ -293,6 +296,7 @@ SVPublisher_createRemote(RSession session, uint16_t appId) return self; } +#endif /* (CONFIG_IEC61850_R_SMV == 1) */ SVPublisher SVPublisher_createEx(CommParameters* parameters, const char* interfaceId, bool useVlanTag) @@ -515,9 +519,11 @@ SVPublisher_publish(SVPublisher self) if (self->ethernetSocket) { Ethernet_sendPacket(self->ethernetSocket, self->buffer, self->payloadStart + self->payloadLength); } +#if (CONFIG_IEC61850_R_SMV == 1) else if (self->remoteSession) { RSession_sendMessage(self->remoteSession, RSESSION_SPDU_ID_SV, self->simulation, self->appId, self->buffer, self->payloadLength); } +#endif /* (CONFIG_IEC61850_R_SMV == 1) */ else { if (DEBUG_SV_PUBLISHER) printf("SV_PUBLISHER: no network layer!\n"); diff --git a/src/sampled_values/sv_subscriber.c b/src/sampled_values/sv_subscriber.c index d9ff72a4..82833056 100644 --- a/src/sampled_values/sv_subscriber.c +++ b/src/sampled_values/sv_subscriber.c @@ -56,7 +56,9 @@ struct sSVReceiver { uint8_t* buffer; EthernetSocket ethSocket; +#if (CONFIG_IEC61850_R_SMV == 1) RSession session; +#endif /* (CONFIG_IEC61850_R_SMV == 1) */ LinkedList subscriberList; @@ -67,8 +69,6 @@ struct sSVReceiver { }; struct sSVSubscriber { - RSession session; - uint8_t ethAddr[6]; uint16_t appId; @@ -93,7 +93,6 @@ struct sSVSubscriber_ASDU { uint8_t* dataBuffer; }; - SVReceiver SVReceiver_create(void) { @@ -113,6 +112,7 @@ SVReceiver_create(void) return self; } +#if (CONFIG_IEC61850_R_SMV == 1) SVReceiver SVReceiver_createRemote(RSession session) { @@ -133,6 +133,7 @@ SVReceiver_createRemote(RSession session) return self; } +#endif /* (CONFIG_IEC61850_R_SMV == 1) */ void SVReceiver_setInterfaceId(SVReceiver self, const char* interfaceId) @@ -210,6 +211,7 @@ svReceiverLoop(void* threadParameter) EthernetHandleSet_destroy(handleSet); } +#if (CONFIG_IEC61850_R_SMV == 1) else if (self->session) { self->stopped = false; @@ -233,6 +235,7 @@ svReceiverLoop(void* threadParameter) Handleset_destroy(handleSet); } +#endif /* (CONFIG_IEC61850_R_SMV == 1) */ self->stopped = true; @@ -307,6 +310,7 @@ SVReceiver_destroy(SVReceiver self) bool SVReceiver_startThreadless(SVReceiver self) { +#if (CONFIG_IEC61850_R_SMV == 1) if (self->session) { if (RSession_startListening(self->session) == R_SESSION_ERROR_OK) { self->running = true; @@ -318,6 +322,7 @@ SVReceiver_startThreadless(SVReceiver self) } } else { +#endif /* (CONFIG_IEC61850_R_SMV == 1) */ if (self->interfaceId == NULL) self->ethSocket = Ethernet_createSocket(CONFIG_ETHERNET_INTERFACE_ID, NULL); else @@ -334,7 +339,9 @@ SVReceiver_startThreadless(SVReceiver self) return true; else return false; +#if (CONFIG_IEC61850_R_SMV == 1) } +#endif /* (CONFIG_IEC61850_R_SMV == 1) */ } void @@ -343,9 +350,11 @@ SVReceiver_stopThreadless(SVReceiver self) if (self->ethSocket) Ethernet_destroySocket(self->ethSocket); +#if (CONFIG_IEC61850_R_SMV == 1) if (self->session) { RSession_stopListening(self->session); } +#endif /* (CONFIG_IEC61850_R_SMV == 1) */ self->running = false; } @@ -674,10 +683,12 @@ SVReceiver_tick(SVReceiver self) return true; } } +#if (CONFIG_IEC61850_R_SMV == 1) else if (self->session) { if (RSession_receiveMessage(self->session, handleSessionPayloadElement, (void*) self) == R_SESSION_ERROR_OK) return true; } +#endif /* (CONFIG_IEC61850_R_SMV == 1) */ return false; }