diff --git a/examples/server_example_goose/server_example_goose.c b/examples/server_example_goose/server_example_goose.c index 7f0681d9..84e36b0d 100644 --- a/examples/server_example_goose/server_example_goose.c +++ b/examples/server_example_goose/server_example_goose.c @@ -59,9 +59,21 @@ int main(int argc, char** argv) { char* ethernetIfcID = argv[1]; printf("Using GOOSE interface: %s\n", ethernetIfcID); + + /* set GOOSE interface for all GOOSE publishers (GCBs) */ IedServer_setGooseInterfaceId(iedServer, ethernetIfcID); } + if (argc > 2) { + char* ethernetIfcID = argv[2]; + + printf("Using GOOSE interface for GenericIO/LLN0.gcbAnalogValues: %s\n", ethernetIfcID); + + /* set GOOSE interface for a particular GOOSE publisher (GCB) */ + IedServer_setGooseInterfaceIdEx(iedServer, IEDMODEL_GenericIO_LLN0, "gcbAnalogValues", ethernetIfcID); + } + + /* MMS server will be instructed to start listening to client connections. */ IedServer_start(iedServer, 102); diff --git a/src/goose/goose_publisher.c b/src/goose/goose_publisher.c index 7f418b02..97732268 100644 --- a/src/goose/goose_publisher.c +++ b/src/goose/goose_publisher.c @@ -36,7 +36,7 @@ #define GOOSE_MAX_MESSAGE_SIZE 1518 static void -prepareGooseBuffer(GoosePublisher self, CommParameters* parameters, const char* interfaceID); +prepareGooseBuffer(GoosePublisher self, CommParameters* parameters, const char* interfaceID, bool useVlanTags); struct sGoosePublisher { uint8_t* buffer; @@ -63,13 +63,12 @@ struct sGoosePublisher { MmsValue* timestamp; /* time when stNum is increased */ }; - GoosePublisher -GoosePublisher_create(CommParameters* parameters, const char* interfaceID) +GoosePublisher_createEx(CommParameters* parameters, const char* interfaceID, bool useVlanTag) { GoosePublisher self = (GoosePublisher) GLOBAL_CALLOC(1, sizeof(struct sGoosePublisher)); - prepareGooseBuffer(self, parameters, interfaceID); + prepareGooseBuffer(self, parameters, interfaceID, useVlanTag); self->timestamp = MmsValue_newUtcTimeByMsTime(Hal_getTimeInMs()); @@ -78,6 +77,12 @@ GoosePublisher_create(CommParameters* parameters, const char* interfaceID) return self; } +GoosePublisher +GoosePublisher_create(CommParameters* parameters, const char* interfaceID) +{ + return GoosePublisher_createEx(parameters, interfaceID, true); +} + void GoosePublisher_destroy(GoosePublisher self) { @@ -160,7 +165,7 @@ GoosePublisher_setTimeAllowedToLive(GoosePublisher self, uint32_t timeAllowedToL } static void -prepareGooseBuffer(GoosePublisher self, CommParameters* parameters, const char* interfaceID) +prepareGooseBuffer(GoosePublisher self, CommParameters* parameters, const char* interfaceID, bool useVlanTags) { uint8_t srcAddr[6]; @@ -201,19 +206,19 @@ prepareGooseBuffer(GoosePublisher self, CommParameters* parameters, const char* int bufPos = 12; -#if 1 - /* Priority tag - IEEE 802.1Q */ - self->buffer[bufPos++] = 0x81; - self->buffer[bufPos++] = 0x00; + if (useVlanTags) { + /* Priority tag - IEEE 802.1Q */ + self->buffer[bufPos++] = 0x81; + self->buffer[bufPos++] = 0x00; - uint8_t tci1 = priority << 5; - tci1 += vlanId / 256; + uint8_t tci1 = priority << 5; + tci1 += vlanId / 256; - uint8_t tci2 = vlanId % 256; + uint8_t tci2 = vlanId % 256; - self->buffer[bufPos++] = tci1; /* Priority + VLAN-ID */ - self->buffer[bufPos++] = tci2; /* VLAN-ID */ -#endif + self->buffer[bufPos++] = tci1; /* Priority + VLAN-ID */ + self->buffer[bufPos++] = tci2; /* VLAN-ID */ + } /* EtherType GOOSE */ self->buffer[bufPos++] = 0x88; diff --git a/src/goose/goose_publisher.h b/src/goose/goose_publisher.h index 9d250f8d..412a4e7b 100644 --- a/src/goose/goose_publisher.h +++ b/src/goose/goose_publisher.h @@ -49,6 +49,9 @@ typedef struct sGoosePublisher* GoosePublisher; LIB61850_API GoosePublisher GoosePublisher_create(CommParameters* parameters, const char* interfaceID); +LIB61850_API GoosePublisher +GoosePublisher_createEx(CommParameters* parameters, const char* interfaceID, bool useVlanTag); + LIB61850_API void GoosePublisher_destroy(GoosePublisher self); diff --git a/src/iec61850/inc/iec61850_server.h b/src/iec61850/inc/iec61850_server.h index 6bf9b4f5..c922eb88 100644 --- a/src/iec61850/inc/iec61850_server.h +++ b/src/iec61850/inc/iec61850_server.h @@ -459,6 +459,8 @@ IedServer_getMmsServer(IedServer self); * then configured GOOSE control blocks keep inactive until a MMS client enables * them by writing to the GOOSE control block. * + * Note: This function has no effect when CONFIG_INCLUDE_GOOSE_SUPPORT is not set. + * * \param self the instance of IedServer to operate on. */ LIB61850_API void @@ -470,6 +472,8 @@ IedServer_enableGoosePublishing(IedServer self); * This will set the GoEna attribute of all configured GOOSE control blocks * to false. This will stop GOOSE transmission. * + * Note: This function has no effect when CONFIG_INCLUDE_GOOSE_SUPPORT is not set. + * * \param self the instance of IedServer to operate on. */ LIB61850_API void @@ -482,12 +486,46 @@ IedServer_disableGoosePublishing(IedServer self); * default interface ID from stack_config.h is used. Note the interface ID is operating system * specific! * + * Note: This function has no effect when CONFIG_INCLUDE_GOOSE_SUPPORT is not set. + * * \param self the instance of IedServer to operate on. * \param interfaceId the ID of the ethernet interface to be used for GOOSE publishing */ LIB61850_API void IedServer_setGooseInterfaceId(IedServer self, const char* interfaceId); +/** + * \brief Set the Ethernet interface to be used by GOOSE publishing + * + * This function can be used to set the GOOSE interface ID forG all CBs (parameter ln = NULL) or for + * a specific GCB specified by the logical node instance and the GCB name. + * + * Note: This function has no effect when CONFIG_INCLUDE_GOOSE_SUPPORT is not set. + * + * \param self the instance of IedServer to operate on. + * \param ln the logical node that contains the GCB or NULL to enable/disable VLAN tagging for all GCBs + * \param gcbName the name (not object reference!) of the GCB + * \param interfaceId the ID of the ethernet interface to be used for GOOSE publishing + */ +LIB61850_API void +IedServer_setGooseInterfaceIdEx(IedServer self, LogicalNode* ln, const char* gcbName, const char* interfaceId); + +/** + * \brief Enable/disable the use of VLAN tags in GOOSE messages + * + * This function can be used to enable/disable VLAN tagging for all GCBs (parameter ln = NULL) or for + * a specific GCB specified by the logical node instance and the GCB name. + * + * Note: This function has no effect when CONFIG_INCLUDE_GOOSE_SUPPORT is not set. + * + * \param self the instance of IedServer to operate on + * \param ln the logical node that contains the GCB or NULL to enable/disable VLAN tagging for all GCBs + * \param gcbName the name (not object reference!) of the GCB + * \param useVlanTag true to enable VLAN tagging, false otherwise + */ +LIB61850_API void +IedServer_useGooseVlanTag(IedServer self, LogicalNode* ln, const char* gcbName, bool useVlanTag); + /**@}*/ /** diff --git a/src/iec61850/inc_private/mms_goose.h b/src/iec61850/inc_private/mms_goose.h index c26be24f..0b1a22d5 100644 --- a/src/iec61850/inc_private/mms_goose.h +++ b/src/iec61850/inc_private/mms_goose.h @@ -1,7 +1,7 @@ /* * mms_goose.h * - * Copyright 2013-2018 Michael Zillgith + * Copyright 2013-2019 Michael Zillgith * * This file is part of libIEC61850. * @@ -35,6 +35,15 @@ MmsGooseControlBlock_destroy(MmsGooseControlBlock self); LIB61850_INTERNAL MmsDomain* MmsGooseControlBlock_getDomain(MmsGooseControlBlock self); +LIB61850_INTERNAL void +MmsGooseControlBlock_useGooseVlanTag(MmsGooseControlBlock self, bool useVlanTag); + +LIB61850_INTERNAL void +MmsGooseControlBlock_setGooseInterfaceId(MmsGooseControlBlock self, const char* interfaceId); + +LIB61850_INTERNAL LogicalNode* +MmsGooseControlBlock_getLogicalNode(MmsGooseControlBlock self); + LIB61850_INTERNAL char* MmsGooseControlBlock_getLogicalNodeName(MmsGooseControlBlock self); diff --git a/src/iec61850/inc_private/mms_mapping.h b/src/iec61850/inc_private/mms_mapping.h index 7c768475..4590eb34 100644 --- a/src/iec61850/inc_private/mms_mapping.h +++ b/src/iec61850/inc_private/mms_mapping.h @@ -106,6 +106,12 @@ MmsMapping_enableGoosePublishing(MmsMapping* self); LIB61850_INTERNAL void MmsMapping_disableGoosePublishing(MmsMapping* self); +LIB61850_INTERNAL void +MmsMapping_useGooseVlanTag(MmsMapping* self, LogicalNode* ln, const char* gcbName, bool useVlanTag); + +LIB61850_INTERNAL void +MmsMapping_setGooseInterfaceId(MmsMapping* self, LogicalNode* ln, const char* gcbName, const char* interfaceId); + LIB61850_INTERNAL void MmsMapping_addControlObject(MmsMapping* self, ControlObject* controlObject); diff --git a/src/iec61850/server/impl/ied_server.c b/src/iec61850/server/impl/ied_server.c index 96c8a244..b12c71d5 100644 --- a/src/iec61850/server/impl/ied_server.c +++ b/src/iec61850/server/impl/ied_server.c @@ -1287,6 +1287,21 @@ IedServer_updateQuality(IedServer self, DataAttribute* dataAttribute, Quality qu } +void +IedServer_useGooseVlanTag(IedServer self, LogicalNode* ln, const char* gcbName, bool useVlanTag) +{ +#if (CONFIG_INCLUDE_GOOSE_SUPPORT == 1) + MmsMapping_useGooseVlanTag(self->mmsMapping, ln, gcbName, useVlanTag); +#endif /* (CONFIG_INCLUDE_GOOSE_SUPPORT == 1) */ +} + +void +IedServer_setGooseInterfaceIdEx(IedServer self, LogicalNode* ln, const char* gcbName, const char* interfaceId) +{ +#if (CONFIG_INCLUDE_GOOSE_SUPPORT == 1) + MmsMapping_setGooseInterfaceId(self->mmsMapping, ln, gcbName, interfaceId); +#endif /* (CONFIG_INCLUDE_GOOSE_SUPPORT == 1) */ +} void IedServer_enableGoosePublishing(IedServer self) diff --git a/src/iec61850/server/mms_mapping/mms_goose.c b/src/iec61850/server/mms_mapping/mms_goose.c index b6c2f517..91d8748d 100644 --- a/src/iec61850/server/mms_mapping/mms_goose.c +++ b/src/iec61850/server/mms_mapping/mms_goose.c @@ -39,7 +39,9 @@ struct sMmsGooseControlBlock { char* name; - bool goEna; + int goEna:1; + int isDynamicDataSet:1; + int useVlanTag:1; char* dstAddress; @@ -50,7 +52,6 @@ struct sMmsGooseControlBlock { GoosePublisher publisher; DataSet* dataSet; - bool isDynamicDataSet; LinkedList dataSetValues; uint64_t nextPublishTime; @@ -68,6 +69,8 @@ struct sMmsGooseControlBlock { char* goCBRef; char* goId; char* dataSetRef; + + char* gooseInterfaceId; }; MmsGooseControlBlock @@ -75,9 +78,12 @@ MmsGooseControlBlock_create() { MmsGooseControlBlock self = (MmsGooseControlBlock) GLOBAL_CALLOC(1, sizeof(struct sMmsGooseControlBlock)); + if (self) { + self->useVlanTag = true; #if (CONFIG_MMS_THREADLESS_STACK != 1) - self->publisherMutex = Semaphore_create(1); + self->publisherMutex = Semaphore_create(1); #endif + } return self; } @@ -112,11 +118,29 @@ MmsGooseControlBlock_destroy(MmsGooseControlBlock self) } } + if (self->gooseInterfaceId != NULL) + GLOBAL_FREEMEM(self->gooseInterfaceId); + MmsValue_delete(self->mmsValue); GLOBAL_FREEMEM(self); } +void +MmsGooseControlBlock_useGooseVlanTag(MmsGooseControlBlock self, bool useVlanTag) +{ + self->useVlanTag = useVlanTag; +} + +void +MmsGooseControlBlock_setGooseInterfaceId(MmsGooseControlBlock self, const char* interfaceId) +{ + if (self->gooseInterfaceId != NULL) + GLOBAL_FREEMEM(self->gooseInterfaceId); + + self->gooseInterfaceId = StringUtils_copyString(interfaceId); +} + MmsDomain* MmsGooseControlBlock_getDomain(MmsGooseControlBlock self) { @@ -129,6 +153,12 @@ MmsGooseControlBlock_getDataSet(MmsGooseControlBlock self) return self->dataSet; } +LogicalNode* +MmsGooseControlBlock_getLogicalNode(MmsGooseControlBlock self) +{ + return self->logicalNode; +} + char* MmsGooseControlBlock_getLogicalNodeName(MmsGooseControlBlock self) { @@ -222,7 +252,10 @@ MmsGooseControlBlock_enable(MmsGooseControlBlock self) memcpy(commParameters.dstAddress, MmsValue_getOctetStringBuffer(macAddress), 6); - self->publisher = GoosePublisher_create(&commParameters, self->mmsMapping->gooseInterfaceId); + if (self->gooseInterfaceId) + self->publisher = GoosePublisher_createEx(&commParameters, self->gooseInterfaceId, self->useVlanTag); + else + self->publisher = GoosePublisher_createEx(&commParameters, self->mmsMapping->gooseInterfaceId, self->useVlanTag); self->minTime = MmsValue_toUint32(MmsValue_getElement(self->mmsValue, 6)); self->maxTime = MmsValue_toUint32(MmsValue_getElement(self->mmsValue, 7)); diff --git a/src/iec61850/server/mms_mapping/mms_mapping.c b/src/iec61850/server/mms_mapping/mms_mapping.c index fdacb6ac..99644625 100644 --- a/src/iec61850/server/mms_mapping/mms_mapping.c +++ b/src/iec61850/server/mms_mapping/mms_mapping.c @@ -2914,6 +2914,44 @@ MmsMapping_enableGoosePublishing(MmsMapping* self) } +void +MmsMapping_useGooseVlanTag(MmsMapping* self, LogicalNode* ln, const char* gcbName, bool useVlanTag) +{ + LinkedList element = self->gseControls; + + while ((element = LinkedList_getNext(element)) != NULL) { + MmsGooseControlBlock gcb = (MmsGooseControlBlock) element->data; + + if (ln == NULL) { + MmsGooseControlBlock_useGooseVlanTag(gcb, useVlanTag); + } + else { + if ((MmsGooseControlBlock_getLogicalNode(gcb) == ln) && !strcmp(MmsGooseControlBlock_getName(gcb), gcbName)) { + MmsGooseControlBlock_useGooseVlanTag(gcb, useVlanTag); + } + } + } +} + +void +MmsMapping_setGooseInterfaceId(MmsMapping* self, LogicalNode* ln, const char* gcbName, const char* interfaceId) +{ + LinkedList element = self->gseControls; + + while ((element = LinkedList_getNext(element)) != NULL) { + MmsGooseControlBlock gcb = (MmsGooseControlBlock) element->data; + + if (ln == NULL) { + MmsGooseControlBlock_setGooseInterfaceId(gcb, interfaceId); + } + else { + if ((MmsGooseControlBlock_getLogicalNode(gcb) == ln) && !strcmp(MmsGooseControlBlock_getName(gcb), gcbName)) { + MmsGooseControlBlock_setGooseInterfaceId(gcb, interfaceId); + } + } + } +} + void MmsMapping_disableGoosePublishing(MmsMapping* self) {