|
|
@@ -3,7 +3,11 @@
|
|
|
* All rights reserved.
|
|
|
*
|
|
|
******************************************************************************/
|
|
|
+
|
|
|
+#include <string.h>
|
|
|
+
|
|
|
#include "cipioconnection.h"
|
|
|
+
|
|
|
#include "cipconnectionmanager.h"
|
|
|
#include "cipassembly.h"
|
|
|
#include "ciptcpipinterface.h"
|
|
|
@@ -12,831 +16,767 @@
|
|
|
#include "cpf.h"
|
|
|
#include "trace.h"
|
|
|
#include "endianconv.h"
|
|
|
-#include <string.h>
|
|
|
|
|
|
/*The port to be used per default for I/O messages on UDP.*/
|
|
|
-#define OPENER_EIP_IO_UDP_PORT 0x08AE
|
|
|
+const int kOpenerEipIoUdpPort = 0x08AE;
|
|
|
|
|
|
/* producing multicast connection have to consider the rules that apply for
|
|
|
* application connection types.
|
|
|
*/
|
|
|
-EIP_STATUS
|
|
|
-openProducingMulticastConnection(S_CIP_ConnectionObject *pa_pstConnObj,
|
|
|
- S_CIP_CPF_Data *pa_CPF_data);
|
|
|
+EipStatus OpenProducingMulticastConnection(
|
|
|
+ ConnectionObject *connection_object,
|
|
|
+ CipCommonPacketFormatData *common_packet_format_data);
|
|
|
+
|
|
|
+EipStatus OpenMulticastConnection(
|
|
|
+ UdpCommuncationDirection direction, ConnectionObject *connection_object,
|
|
|
+ CipCommonPacketFormatData *common_packet_format_data);
|
|
|
|
|
|
-EIP_STATUS
|
|
|
-OpenMulticastConnection(int pa_direction, S_CIP_ConnectionObject *pa_pstConnObj,
|
|
|
- S_CIP_CPF_Data *pa_CPF_data);
|
|
|
+EipStatus OpenConsumingPointToPointConnection(
|
|
|
+ ConnectionObject *connection_object,
|
|
|
+ CipCommonPacketFormatData *common_packet_format_data);
|
|
|
|
|
|
-EIP_STATUS
|
|
|
-OpenConsumingPointToPointConnection(S_CIP_ConnectionObject *pa_pstConnObj,
|
|
|
- S_CIP_CPF_Data *pa_CPF_data);
|
|
|
+EipStatus OpenProducingPointToPointConnection(
|
|
|
+ ConnectionObject *connection_object,
|
|
|
+ CipCommonPacketFormatData *common_packet_format_data);
|
|
|
|
|
|
-int
|
|
|
-OpenProducingPointToPointConnection(S_CIP_ConnectionObject *pa_pstConnObj,
|
|
|
- S_CIP_CPF_Data *pa_CPF_data);
|
|
|
-EIP_UINT16
|
|
|
-handleConfigData(S_CIP_Class *pa_pstAssemblyClass,
|
|
|
- S_CIP_ConnectionObject *pa_pstIOConnObj);
|
|
|
+EipUint16 HandleConfigData(CipClass *assembly_class,
|
|
|
+ ConnectionObject *connection_object);
|
|
|
|
|
|
/* Regularly close the IO connection. If it is an exclusive owner or input only
|
|
|
* connection and in charge of the connection a new owner will be searched
|
|
|
*/
|
|
|
-void
|
|
|
-closeIOConnection(S_CIP_ConnectionObject *pa_pstConnObjData);
|
|
|
+void CloseIoConnection(ConnectionObject *connection_object);
|
|
|
|
|
|
-void
|
|
|
-handleIOConnectionTimeOut(S_CIP_ConnectionObject *pa_pstConn);
|
|
|
+void HandleIoConnectionTimeOut(ConnectionObject *connection_object);
|
|
|
|
|
|
-/*! Send the data from the produced CIP Object of the connection via the socket of the connection object
|
|
|
+/** @brief Send the data from the produced CIP Object of the connection via the socket of the connection object
|
|
|
* on UDP.
|
|
|
- * @param pa_pstConnection pointer to the connection object
|
|
|
+ * @param connection_object pointer to the connection object
|
|
|
* @return status EIP_OK .. success
|
|
|
* EIP_ERROR .. error
|
|
|
*/
|
|
|
-EIP_STATUS
|
|
|
-sendConnectedData(S_CIP_ConnectionObject *pa_pstConnection);
|
|
|
+EipStatus SendConnectedData(ConnectionObject *connection_object);
|
|
|
+
|
|
|
+EipStatus HandleReceivedIoConnectionData(ConnectionObject *connection_object,
|
|
|
+ EipUint8 *data, EipUint16 data_length);
|
|
|
|
|
|
-EIP_STATUS
|
|
|
-handleReceivedIOConnData(struct CIP_ConnectionObject *pa_pstConnection,
|
|
|
- EIP_UINT8 * pa_pnData, EIP_UINT16 pa_nDataLength);
|
|
|
/**** Global variables ****/
|
|
|
-/* buffers for the config data coming with a forward open request.
|
|
|
- */EIP_UINT8 *g_pnConfigDataBuffer = NULL;
|
|
|
-unsigned int g_unConfigDataLen = 0;
|
|
|
-/*! buffer for holding the run idle information. */EIP_UINT32 g_nRunIdleState;
|
|
|
+EipUint8 *g_config_data_buffer = NULL; /**< buffers for the config data coming with a forward open request. */
|
|
|
+unsigned int g_config_data_length = 0;
|
|
|
|
|
|
-/**** Implementation ****/
|
|
|
+EipUint32 g_run_idle_state; /**< buffer for holding the run idle information. */
|
|
|
|
|
|
-int
|
|
|
-establishIOConnction(struct CIP_ConnectionObject *pa_pstConnObjData,
|
|
|
- EIP_UINT16 *pa_pnExtendedError)
|
|
|
-{
|
|
|
- int O2TConnectionType, T2OConnectionType;
|
|
|
- int nRetVal = EIP_OK;
|
|
|
- S_CIP_attribute_struct *pstAttribute;
|
|
|
+/**** Implementation ****/
|
|
|
+int EstablishIoConnction(ConnectionObject *connection_object,
|
|
|
+ EipUint16 *extended_error) {
|
|
|
+ int originator_to_target_connection_type,
|
|
|
+ target_to_originator_connection_type;
|
|
|
+ int eip_status = kEipStatusOk;
|
|
|
+ CipAttributeStruct *attribute;
|
|
|
/* currently we allow I/O connections only to assembly objects */
|
|
|
- S_CIP_Class *pstAssemblyClass = getCIPClass(CIP_ASSEMBLY_CLASS_CODE); /* we don't need to check for zero as this is handled in the connection path parsing */
|
|
|
- S_CIP_Instance *pstInstance = NULL;
|
|
|
-
|
|
|
- S_CIP_ConnectionObject *pstIOConnObj = getIOConnectionForConnectionData(
|
|
|
- pa_pstConnObjData, pa_pnExtendedError);
|
|
|
-
|
|
|
- if (NULL == pstIOConnObj)
|
|
|
- {
|
|
|
- return CIP_ERROR_CONNECTION_FAILURE;
|
|
|
- }
|
|
|
-
|
|
|
- //TODO add check for transport type trigger
|
|
|
-
|
|
|
- if (CIP_CONN_CYCLIC_CONNECTION
|
|
|
- != (pstIOConnObj->TransportTypeClassTrigger
|
|
|
- & CIP_CONN_PRODUCTION_TRIGGER_MASK))
|
|
|
- {
|
|
|
- if (256 == pstIOConnObj->m_unProductionInhibitTime)
|
|
|
- {
|
|
|
- /* there was no PIT segment in the connection path set PIT to one fourth of RPI */
|
|
|
- pstIOConnObj->m_unProductionInhibitTime = ((EIP_UINT16)(
|
|
|
- pstIOConnObj->T_to_O_RPI) / 4000);
|
|
|
+ CipClass *assembly_class = GetCipClass(kCipAssemblyClassCode); /* we don't need to check for zero as this is handled in the connection path parsing */
|
|
|
+ CipInstance *instance = NULL;
|
|
|
+
|
|
|
+ ConnectionObject *io_connection_object = GetIoConnectionForConnectionData(
|
|
|
+ connection_object, extended_error);
|
|
|
+
|
|
|
+ if (NULL == io_connection_object) {
|
|
|
+ return kCipErrorConnectionFailure;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* TODO add check for transport type trigger */
|
|
|
+
|
|
|
+ if (kConnectionTriggerTypeCyclicConnection
|
|
|
+ != (io_connection_object->transport_type_class_trigger
|
|
|
+ & kConnectionTriggerTypeProductionTriggerMask)) {
|
|
|
+ if (256 == io_connection_object->production_inhibit_time) {
|
|
|
+ /* there was no PIT segment in the connection path set PIT to one fourth of RPI */
|
|
|
+ io_connection_object->production_inhibit_time =
|
|
|
+ ((EipUint16) (io_connection_object->t_to_o_requested_packet_interval)
|
|
|
+ / 4000);
|
|
|
+ } else {
|
|
|
+ /* if production inhibit time has been provided it needs to be smaller than the RPI */
|
|
|
+ if (io_connection_object->production_inhibit_time
|
|
|
+ > ((EipUint16) ((io_connection_object
|
|
|
+ ->t_to_o_requested_packet_interval) / 1000))) {
|
|
|
+ /* see section C-1.4.3.3 */
|
|
|
+ *extended_error = 0x111; /**< RPI not supported. Extended Error code deprecated */
|
|
|
+ return kCipErrorConnectionFailure;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ /* set the connection call backs */
|
|
|
+ io_connection_object->connection_close_function = CloseIoConnection;
|
|
|
+ io_connection_object->connection_timeout_function = HandleIoConnectionTimeOut;
|
|
|
+ io_connection_object->connection_send_data_function = SendConnectedData;
|
|
|
+ io_connection_object->connection_receive_data_function =
|
|
|
+ HandleReceivedIoConnectionData;
|
|
|
+
|
|
|
+ GeneralConnectionConfiguration(io_connection_object);
|
|
|
+
|
|
|
+ originator_to_target_connection_type = (io_connection_object
|
|
|
+ ->o_to_t_network_connection_parameter & 0x6000) >> 13;
|
|
|
+ target_to_originator_connection_type = (io_connection_object
|
|
|
+ ->t_to_o_network_connection_parameter & 0x6000) >> 13;
|
|
|
+
|
|
|
+ if ((originator_to_target_connection_type == 0)
|
|
|
+ && (target_to_originator_connection_type == 0)) { /* this indicates an re-configuration of the connection currently not supported and we should not come here as this is handled in the forwardopen function*/
|
|
|
+
|
|
|
+ } else {
|
|
|
+ int producing_index = 0;
|
|
|
+ int data_size;
|
|
|
+ int diff_size;
|
|
|
+ int is_heartbeat;
|
|
|
+
|
|
|
+ if ((originator_to_target_connection_type != 0)
|
|
|
+ && (target_to_originator_connection_type != 0)) { /* we have a producing and consuming connection*/
|
|
|
+ producing_index = 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ io_connection_object->consuming_instance = 0;
|
|
|
+ io_connection_object->consumed_connection_path_length = 0;
|
|
|
+ io_connection_object->producing_instance = 0;
|
|
|
+ io_connection_object->produced_connection_path_length = 0;
|
|
|
+
|
|
|
+ if (originator_to_target_connection_type != 0) { /*setup consumer side*/
|
|
|
+ if (0
|
|
|
+ != (instance = GetCipInstance(
|
|
|
+ assembly_class,
|
|
|
+ io_connection_object->connection_path.connection_point[0]))) { /* consuming Connection Point is present */
|
|
|
+ io_connection_object->consuming_instance = instance;
|
|
|
+
|
|
|
+ io_connection_object->consumed_connection_path_length = 6;
|
|
|
+ io_connection_object->consumed_connection_path.path_size = 6;
|
|
|
+ io_connection_object->consumed_connection_path.class_id =
|
|
|
+ io_connection_object->connection_path.class_id;
|
|
|
+ io_connection_object->consumed_connection_path.instance_number =
|
|
|
+ io_connection_object->connection_path.connection_point[0];
|
|
|
+ io_connection_object->consumed_connection_path.attribute_number = 3;
|
|
|
+
|
|
|
+ attribute = GetCipAttribute(instance, 3);
|
|
|
+ OPENER_ASSERT(attribute != NULL);
|
|
|
+ /* an assembly object should always have an attribute 3 */
|
|
|
+ data_size = io_connection_object->consumed_connection_size;
|
|
|
+ diff_size = 0;
|
|
|
+ is_heartbeat = (((CipByteArray *) attribute->data)->length == 0);
|
|
|
+
|
|
|
+ if ((io_connection_object->transport_type_class_trigger & 0x0F) == 1) {
|
|
|
+ /* class 1 connection */
|
|
|
+ data_size -= 2; /* remove 16-bit sequence count length */
|
|
|
+ diff_size += 2;
|
|
|
}
|
|
|
- else
|
|
|
- {
|
|
|
- /* if production inhibit time has been provided it needs to be smaller than the RPI */
|
|
|
- if (pstIOConnObj->m_unProductionInhibitTime
|
|
|
- > ((EIP_UINT16)((pstIOConnObj->T_to_O_RPI) / 1000)))
|
|
|
- {
|
|
|
- /* see section C-1.4.3.3 */
|
|
|
- *pa_pnExtendedError = 0x111;
|
|
|
- return 0x01;
|
|
|
- }
|
|
|
+ if ((kOpenerConsumedDataHasRunIdleHeader) &&(data_size > 0)
|
|
|
+ && (!is_heartbeat)) { /* we only have an run idle header if it is not an heartbeat connection */
|
|
|
+ data_size -= 4; /* remove the 4 bytes needed for run/idle header */
|
|
|
+ diff_size += 4;
|
|
|
}
|
|
|
- }
|
|
|
- /* set the connection call backs */
|
|
|
- pstIOConnObj->m_pfCloseFunc = closeIOConnection;
|
|
|
- pstIOConnObj->m_pfTimeOutFunc = handleIOConnectionTimeOut;
|
|
|
- pstIOConnObj->m_pfSendDataFunc = sendConnectedData;
|
|
|
- pstIOConnObj->m_pfReceiveDataFunc = handleReceivedIOConnData;
|
|
|
-
|
|
|
- generalConnectionConfiguration(pstIOConnObj);
|
|
|
-
|
|
|
- O2TConnectionType = (pstIOConnObj->O_to_T_NetworkConnectionParameter & 0x6000)
|
|
|
- >> 13;
|
|
|
- T2OConnectionType = (pstIOConnObj->T_to_O_NetworkConnectionParameter & 0x6000)
|
|
|
- >> 13;
|
|
|
-
|
|
|
- if ((O2TConnectionType == 0) && (T2OConnectionType == 0))
|
|
|
- { /* this indicates an re-configuration of the connection currently not supported and we should not come here as this is handled in the forwardopen function*/
|
|
|
-
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- int nProducingIndex = 0;
|
|
|
- int nDataSize;
|
|
|
- int nDiffSize;
|
|
|
- int nIsHeartbeat;
|
|
|
-
|
|
|
- if ((O2TConnectionType != 0) && (T2OConnectionType != 0))
|
|
|
- { /* we have a producing and consuming connection*/
|
|
|
- nProducingIndex = 1;
|
|
|
+ if (((CipByteArray *) attribute->data)->length != data_size) {
|
|
|
+ /*wrong connection size */
|
|
|
+ connection_object->correct_originator_to_target_size =
|
|
|
+ ((CipByteArray *) attribute->data)->length + diff_size;
|
|
|
+ *extended_error =
|
|
|
+ kConnectionManagerStatusCodeErrorInvalidOToTConnectionSize;
|
|
|
+ return kCipErrorConnectionFailure;
|
|
|
}
|
|
|
-
|
|
|
- pstIOConnObj->p_stConsumingInstance = 0;
|
|
|
- pstIOConnObj->ConsumedConnectionPathLength = 0;
|
|
|
- pstIOConnObj->p_stProducingInstance = 0;
|
|
|
- pstIOConnObj->ProducedConnectionPathLength = 0;
|
|
|
-
|
|
|
- if (O2TConnectionType != 0)
|
|
|
- { /*setup consumer side*/
|
|
|
- if (0
|
|
|
- != (pstInstance = getCIPInstance(pstAssemblyClass,
|
|
|
- pstIOConnObj->ConnectionPath.ConnectionPoint[0])))
|
|
|
- { /* consuming Connection Point is present */
|
|
|
- pstIOConnObj->p_stConsumingInstance = pstInstance;
|
|
|
-
|
|
|
- pstIOConnObj->ConsumedConnectionPathLength = 6;
|
|
|
- pstIOConnObj->ConsumedConnectionPath.PathSize = 6;
|
|
|
- pstIOConnObj->ConsumedConnectionPath.ClassID =
|
|
|
- pstIOConnObj->ConnectionPath.ClassID;
|
|
|
- pstIOConnObj->ConsumedConnectionPath.InstanceNr =
|
|
|
- pstIOConnObj->ConnectionPath.ConnectionPoint[0];
|
|
|
- pstIOConnObj->ConsumedConnectionPath.AttributNr = 3;
|
|
|
-
|
|
|
- pstAttribute = getAttribute(pstInstance, 3);
|
|
|
- OPENER_ASSERT(pstAttribute != NULL);
|
|
|
- /* an assembly object should always have an attribute 3 */
|
|
|
- nDataSize = pstIOConnObj->ConsumedConnectionSize;
|
|
|
- nDiffSize = 0;
|
|
|
- nIsHeartbeat = (((S_CIP_Byte_Array *) pstAttribute->pt2data)->len == 0);
|
|
|
-
|
|
|
- if ((pstIOConnObj->TransportTypeClassTrigger & 0x0F) == 1)
|
|
|
- {
|
|
|
- /* class 1 connection */
|
|
|
- nDataSize -= 2; /* remove 16-bit sequence count length */
|
|
|
- nDiffSize += 2;
|
|
|
- }
|
|
|
- if ((OPENER_CONSUMED_DATA_HAS_RUN_IDLE_HEADER) && (nDataSize > 0) && (!nIsHeartbeat))
|
|
|
- { /* we only have an run idle header if it is not an heartbeat connection */
|
|
|
- nDataSize -= 4; /* remove the 4 bytes needed for run/idle header */
|
|
|
- nDiffSize += 4;
|
|
|
- }
|
|
|
- if (((S_CIP_Byte_Array *) pstAttribute->pt2data)->len
|
|
|
- != nDataSize)
|
|
|
- {
|
|
|
- /*wrong connection size */
|
|
|
- pa_pstConnObjData->CorrectOTSize = ((S_CIP_Byte_Array *) pstAttribute->pt2data)->len + nDiffSize;
|
|
|
- *pa_pnExtendedError = CIP_CON_MGR_ERROR_INVALID_O_TO_T_CONNECTION_SIZE;
|
|
|
- return CIP_ERROR_CONNECTION_FAILURE;
|
|
|
- }
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- *pa_pnExtendedError =
|
|
|
- CIP_CON_MGR_INVALID_CONSUMING_APPLICATION_PATH;
|
|
|
- return CIP_ERROR_CONNECTION_FAILURE;
|
|
|
- }
|
|
|
+ } else {
|
|
|
+ *extended_error =
|
|
|
+ kConnectionManagerStatusCodeInvalidConsumingApllicationPath;
|
|
|
+ return kCipErrorConnectionFailure;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (target_to_originator_connection_type != 0) { /*setup producer side*/
|
|
|
+ if (0
|
|
|
+ != (instance =
|
|
|
+ GetCipInstance(
|
|
|
+ assembly_class,
|
|
|
+ io_connection_object->connection_path.connection_point[producing_index]))) {
|
|
|
+ io_connection_object->producing_instance = instance;
|
|
|
+
|
|
|
+ io_connection_object->produced_connection_path_length = 6;
|
|
|
+ io_connection_object->produced_connection_path.path_size = 6;
|
|
|
+ io_connection_object->produced_connection_path.class_id =
|
|
|
+ io_connection_object->connection_path.class_id;
|
|
|
+ io_connection_object->produced_connection_path.instance_number =
|
|
|
+ io_connection_object->connection_path.connection_point[producing_index];
|
|
|
+ io_connection_object->produced_connection_path.attribute_number = 3;
|
|
|
+
|
|
|
+ attribute = GetCipAttribute(instance, 3);
|
|
|
+ OPENER_ASSERT(attribute != NULL);
|
|
|
+ /* an assembly object should always have an attribute 3 */
|
|
|
+ data_size = io_connection_object->produced_connection_size;
|
|
|
+ diff_size = 0;
|
|
|
+ is_heartbeat = (((CipByteArray *) attribute->data)->length == 0);
|
|
|
+
|
|
|
+ if ((io_connection_object->transport_type_class_trigger & 0x0F) == 1) {
|
|
|
+ /* class 1 connection */
|
|
|
+ data_size -= 2; /* remove 16-bit sequence count length */
|
|
|
+ diff_size += 2;
|
|
|
}
|
|
|
-
|
|
|
- if (T2OConnectionType != 0)
|
|
|
- { /*setup producer side*/
|
|
|
- if (0
|
|
|
- != (pstInstance = getCIPInstance(pstAssemblyClass,
|
|
|
- pstIOConnObj->ConnectionPath.ConnectionPoint[nProducingIndex])))
|
|
|
- {
|
|
|
- pstIOConnObj->p_stProducingInstance = pstInstance;
|
|
|
-
|
|
|
- pstIOConnObj->ProducedConnectionPathLength = 6;
|
|
|
- pstIOConnObj->ProducedConnectionPath.PathSize = 6;
|
|
|
- pstIOConnObj->ProducedConnectionPath.ClassID =
|
|
|
- pstIOConnObj->ConnectionPath.ClassID;
|
|
|
- pstIOConnObj->ProducedConnectionPath.InstanceNr =
|
|
|
- pstIOConnObj->ConnectionPath.ConnectionPoint[nProducingIndex];
|
|
|
- pstIOConnObj->ProducedConnectionPath.AttributNr = 3;
|
|
|
-
|
|
|
- pstAttribute = getAttribute(pstInstance, 3);
|
|
|
- OPENER_ASSERT(pstAttribute != NULL);
|
|
|
- /* an assembly object should always have an attribute 3 */
|
|
|
- nDataSize = pstIOConnObj->ProducedConnectionSize;
|
|
|
- nDiffSize = 0;
|
|
|
- nIsHeartbeat = (((S_CIP_Byte_Array *) pstAttribute->pt2data)->len == 0);
|
|
|
-
|
|
|
- if ((pstIOConnObj->TransportTypeClassTrigger & 0x0F) == 1)
|
|
|
- {
|
|
|
- /* class 1 connection */
|
|
|
- nDataSize -= 2; /* remove 16-bit sequence count length */
|
|
|
- nDiffSize += 2;
|
|
|
- }
|
|
|
- if ((OPENER_PRODUCED_DATA_HAS_RUN_IDLE_HEADER) && (nDataSize > 0) && (!nIsHeartbeat))
|
|
|
- { /* we only have an run idle header if it is not an heartbeat connection */
|
|
|
- nDataSize -= 4; /* remove the 4 bytes needed for run/idle header */
|
|
|
- nDiffSize += 4;
|
|
|
- }
|
|
|
- if (((S_CIP_Byte_Array *) pstAttribute->pt2data)->len
|
|
|
- != nDataSize)
|
|
|
- {
|
|
|
- /*wrong connection size*/
|
|
|
- pa_pstConnObjData->CorrectTOSize = ((S_CIP_Byte_Array *) pstAttribute->pt2data)->len + nDiffSize;
|
|
|
- *pa_pnExtendedError = CIP_CON_MGR_ERROR_INVALID_T_TO_O_CONNECTION_SIZE;
|
|
|
- return CIP_ERROR_CONNECTION_FAILURE;
|
|
|
- }
|
|
|
-
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- *pa_pnExtendedError =
|
|
|
- CIP_CON_MGR_INVALID_PRODUCING_APPLICATION_PATH;
|
|
|
- return CIP_ERROR_CONNECTION_FAILURE;
|
|
|
- }
|
|
|
+ if ((kOpenerProducedDataHasRunIdleHeader) &&(data_size > 0)
|
|
|
+ && (!is_heartbeat)) { /* we only have an run idle header if it is not an heartbeat connection */
|
|
|
+ data_size -= 4; /* remove the 4 bytes needed for run/idle header */
|
|
|
+ diff_size += 4;
|
|
|
}
|
|
|
-
|
|
|
- if (NULL != g_pnConfigDataBuffer)
|
|
|
- { /* config data has been sent with this forward open request */
|
|
|
- *pa_pnExtendedError = handleConfigData(pstAssemblyClass,
|
|
|
- pstIOConnObj);
|
|
|
- if (0 != *pa_pnExtendedError)
|
|
|
- {
|
|
|
- return CIP_ERROR_CONNECTION_FAILURE;
|
|
|
- }
|
|
|
+ if (((CipByteArray *) attribute->data)->length != data_size) {
|
|
|
+ /*wrong connection size*/
|
|
|
+ connection_object->correct_target_to_originator_size =
|
|
|
+ ((CipByteArray *) attribute->data)->length + diff_size;
|
|
|
+ *extended_error =
|
|
|
+ kConnectionManagerStatusCodeErrorInvalidTToOConnectionSize;
|
|
|
+ return kCipErrorConnectionFailure;
|
|
|
}
|
|
|
|
|
|
- nRetVal = openCommunicationChannels(pstIOConnObj);
|
|
|
- if (EIP_OK != nRetVal)
|
|
|
- {
|
|
|
- *pa_pnExtendedError = 0; /*TODO find out the correct extended error code*/
|
|
|
- return nRetVal;
|
|
|
- }
|
|
|
+ } else {
|
|
|
+ *extended_error =
|
|
|
+ kConnectionManagerStatusCodeInvalidProducingApplicationPath;
|
|
|
+ return kCipErrorConnectionFailure;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (NULL != g_config_data_buffer) { /* config data has been sent with this forward open request */
|
|
|
+ *extended_error = HandleConfigData(assembly_class, io_connection_object);
|
|
|
+ if (0 != *extended_error) {
|
|
|
+ return kCipErrorConnectionFailure;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ eip_status = OpenCommunicationChannels(io_connection_object);
|
|
|
+ if (kEipStatusOk != eip_status) {
|
|
|
+ *extended_error = 0; /*TODO find out the correct extended error code*/
|
|
|
+ return eip_status;
|
|
|
}
|
|
|
+ }
|
|
|
|
|
|
- addNewActiveConnection(pstIOConnObj);
|
|
|
- IApp_IOConnectionEvent(pstIOConnObj->ConnectionPath.ConnectionPoint[0],
|
|
|
- pstIOConnObj->ConnectionPath.ConnectionPoint[1], enOpened);
|
|
|
- return nRetVal;
|
|
|
+ AddNewActiveConnection(io_connection_object);
|
|
|
+ IoConnectionEvent(io_connection_object->connection_path.connection_point[0],
|
|
|
+ io_connection_object->connection_path.connection_point[1],
|
|
|
+ kOpenedEvent);
|
|
|
+ return eip_status;
|
|
|
}
|
|
|
|
|
|
-/* EIP_STATUS OpenPointToPointConnection(S_CIP_CPF_Data *pa_CPF_data, S_CIP_CM_Object *pa_pstCMObject, INT8 pa_direction, int pa_index)
|
|
|
- * open a Point2Point connection dependent on pa_direction.
|
|
|
- * pa_pstCMObject pointer to registered Object in ConnectionManager.
|
|
|
- * pa_index index of the connection object
|
|
|
- * return status
|
|
|
+/* @brief Open a Point2Point connection dependent on pa_direction.
|
|
|
+ * @param connection_object Pointer to registered Object in ConnectionManager.
|
|
|
+ * @param common_packet_format_data Index of the connection object
|
|
|
+ * @return status
|
|
|
* 0 .. success
|
|
|
* -1 .. error
|
|
|
*/
|
|
|
-
|
|
|
-EIP_STATUS
|
|
|
-OpenConsumingPointToPointConnection(S_CIP_ConnectionObject *pa_pstConnObj,
|
|
|
- S_CIP_CPF_Data *pa_CPF_data)
|
|
|
-{
|
|
|
+EipStatus OpenConsumingPointToPointConnection(
|
|
|
+ ConnectionObject *connection_object,
|
|
|
+ CipCommonPacketFormatData *common_packet_format_data) {
|
|
|
/*static EIP_UINT16 nUDPPort = 2222; TODO think on improving the udp port assigment for point to point connections */
|
|
|
- int j;
|
|
|
+ int j = 0;
|
|
|
struct sockaddr_in addr;
|
|
|
- int newfd;
|
|
|
+ int socket;
|
|
|
|
|
|
- j = 0;
|
|
|
- if (pa_CPF_data->AddrInfo[0].TypeID == 0)
|
|
|
- { /* it is not used yet */
|
|
|
- j = 0;
|
|
|
- }
|
|
|
- else if (pa_CPF_data->AddrInfo[1].TypeID == 0)
|
|
|
- {
|
|
|
- j = 1;
|
|
|
- }
|
|
|
+ if (common_packet_format_data->address_info_item[0].type_id == 0) { /* it is not used yet */
|
|
|
+ j = 0;
|
|
|
+ } else if (common_packet_format_data->address_info_item[1].type_id == 0) {
|
|
|
+ j = 1;
|
|
|
+ }
|
|
|
|
|
|
addr.sin_family = AF_INET;
|
|
|
addr.sin_addr.s_addr = INADDR_ANY;
|
|
|
/*addr.in_port = htons(nUDPPort++);*/
|
|
|
- addr.sin_port = htons(OPENER_EIP_IO_UDP_PORT);
|
|
|
-
|
|
|
- newfd = IApp_CreateUDPSocket(CONSUMING, &addr); /* the address is only needed for bind used if consuming */
|
|
|
- if (newfd == EIP_INVALID_SOCKET)
|
|
|
- {
|
|
|
- OPENER_TRACE_ERR(
|
|
|
- "cannot create UDP socket in OpenPointToPointConnection\n");
|
|
|
- return EIP_ERROR;
|
|
|
- }
|
|
|
+ addr.sin_port = htons(kOpenerEipIoUdpPort);
|
|
|
|
|
|
- pa_pstConnObj->m_stOriginatorAddr = addr; /* store the address of the originator for packet scanning */
|
|
|
+ socket = CreateUdpSocket(kUdpCommuncationDirectionConsuming, &addr); /* the address is only needed for bind used if consuming */
|
|
|
+ if (socket == kEipInvalidSocket) {
|
|
|
+ OPENER_TRACE_ERR(
|
|
|
+ "cannot create UDP socket in OpenPointToPointConnection\n");
|
|
|
+ return kEipStatusError;
|
|
|
+ }
|
|
|
+
|
|
|
+ connection_object->originator_address = addr; /* store the address of the originator for packet scanning */
|
|
|
addr.sin_addr.s_addr = INADDR_ANY; /* restore the address */
|
|
|
- pa_pstConnObj->sockfd[CONSUMING] = newfd;
|
|
|
+ connection_object->socket[kUdpCommuncationDirectionConsuming] = socket;
|
|
|
|
|
|
- pa_CPF_data->AddrInfo[j].Length = 16;
|
|
|
- pa_CPF_data->AddrInfo[j].TypeID = CIP_ITEM_ID_SOCKADDRINFO_O_TO_T;
|
|
|
+ common_packet_format_data->address_info_item[j].length = 16;
|
|
|
+ common_packet_format_data->address_info_item[j].type_id =
|
|
|
+ kSocketAddressInfoOriginatorToTargetId;
|
|
|
|
|
|
- pa_CPF_data->AddrInfo[j].nsin_port = addr.sin_port;
|
|
|
+ common_packet_format_data->address_info_item[j].nsin_port = addr.sin_port;
|
|
|
/*TODO should we add our own address here? */
|
|
|
- pa_CPF_data->AddrInfo[j].nsin_addr = addr.sin_addr.s_addr;
|
|
|
- memset(pa_CPF_data->AddrInfo[j].nasin_zero, 0, 8);
|
|
|
- pa_CPF_data->AddrInfo[j].nsin_family = htons(AF_INET);
|
|
|
+ common_packet_format_data->address_info_item[j].nsin_addr = addr.sin_addr
|
|
|
+ .s_addr;
|
|
|
+ memset(common_packet_format_data->address_info_item[j].nasin_zero, 0, 8);
|
|
|
+ common_packet_format_data->address_info_item[j].nsin_family = htons(AF_INET);
|
|
|
|
|
|
- return EIP_OK;
|
|
|
+ return kEipStatusOk;
|
|
|
}
|
|
|
|
|
|
-int
|
|
|
-OpenProducingPointToPointConnection(S_CIP_ConnectionObject *pa_pstConnObj,
|
|
|
- S_CIP_CPF_Data *pa_CPF_data)
|
|
|
-{
|
|
|
- int newfd;
|
|
|
- in_port_t nPort = htons(OPENER_EIP_IO_UDP_PORT); /* the default port to be used if no port information is part of the forward open request */
|
|
|
-
|
|
|
- if (CIP_ITEM_ID_SOCKADDRINFO_T_TO_O == pa_CPF_data->AddrInfo[0].TypeID)
|
|
|
- {
|
|
|
- nPort = pa_CPF_data->AddrInfo[0].nsin_port;
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- if (CIP_ITEM_ID_SOCKADDRINFO_T_TO_O == pa_CPF_data->AddrInfo[1].TypeID)
|
|
|
- {
|
|
|
- nPort = pa_CPF_data->AddrInfo[1].nsin_port;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- pa_pstConnObj->remote_addr.sin_family = AF_INET;
|
|
|
- pa_pstConnObj->remote_addr.sin_addr.s_addr = 0; /* we don't know the address of the originate will be set in the IApp_CreateUDPSocket */
|
|
|
- pa_pstConnObj->remote_addr.sin_port = nPort;
|
|
|
-
|
|
|
- newfd = IApp_CreateUDPSocket(PRODUCING, &pa_pstConnObj->remote_addr); /* the address is only needed for bind used if consuming */
|
|
|
- if (newfd == EIP_INVALID_SOCKET)
|
|
|
- {
|
|
|
- OPENER_TRACE_ERR(
|
|
|
- "cannot create UDP socket in OpenPointToPointConnection\n");
|
|
|
- //*pa_pnExtendedError = 0x0315; /* miscellaneous*/
|
|
|
- return CIP_ERROR_CONNECTION_FAILURE;
|
|
|
- }
|
|
|
- pa_pstConnObj->sockfd[PRODUCING] = newfd;
|
|
|
-
|
|
|
- return EIP_OK;
|
|
|
+EipStatus OpenProducingPointToPointConnection(
|
|
|
+ ConnectionObject *connection_object,
|
|
|
+ CipCommonPacketFormatData *common_packet_format_data) {
|
|
|
+ int socket;
|
|
|
+ in_port_t port = htons(kOpenerEipIoUdpPort); /* the default port to be used if no port information is part of the forward open request */
|
|
|
+
|
|
|
+ if (kSocketAddressInfoTargetToOriginatorId
|
|
|
+ == common_packet_format_data->address_info_item[0].type_id) {
|
|
|
+ port = common_packet_format_data->address_info_item[0].nsin_port;
|
|
|
+ } else {
|
|
|
+ if (kSocketAddressInfoTargetToOriginatorId
|
|
|
+ == common_packet_format_data->address_info_item[1].type_id) {
|
|
|
+ port = common_packet_format_data->address_info_item[1].nsin_port;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ connection_object->remote_address.sin_family = AF_INET;
|
|
|
+ connection_object->remote_address.sin_addr.s_addr = 0; /* we don't know the address of the originate will be set in the IApp_CreateUDPSocket */
|
|
|
+ connection_object->remote_address.sin_port = port;
|
|
|
+
|
|
|
+ socket = CreateUdpSocket(kUdpCommuncationDirectionProducing,
|
|
|
+ &connection_object->remote_address); /* the address is only needed for bind used if consuming */
|
|
|
+ if (socket == kEipInvalidSocket) {
|
|
|
+ OPENER_TRACE_ERR(
|
|
|
+ "cannot create UDP socket in OpenPointToPointConnection\n");
|
|
|
+ /* *pa_pnExtendedError = 0x0315; miscellaneous*/
|
|
|
+ return kCipErrorConnectionFailure;
|
|
|
+ }
|
|
|
+ connection_object->socket[kUdpCommuncationDirectionProducing] = socket;
|
|
|
+
|
|
|
+ return kEipStatusOk;
|
|
|
}
|
|
|
|
|
|
-EIP_STATUS
|
|
|
-openProducingMulticastConnection(S_CIP_ConnectionObject *pa_pstConnObj,
|
|
|
- S_CIP_CPF_Data *pa_CPF_data)
|
|
|
-{
|
|
|
- S_CIP_ConnectionObject *pstExistingConn = getExistingProdMulticastConnection(
|
|
|
- pa_pstConnObj->ConnectionPath.ConnectionPoint[1]);
|
|
|
+EipStatus OpenProducingMulticastConnection(
|
|
|
+ ConnectionObject *connection_object,
|
|
|
+ CipCommonPacketFormatData *common_packet_format_data) {
|
|
|
+ ConnectionObject *existing_connection_object =
|
|
|
+ GetExistingProducerMulticastConnection(
|
|
|
+ connection_object->connection_path.connection_point[1]);
|
|
|
int j;
|
|
|
|
|
|
- if (NULL == pstExistingConn)
|
|
|
- { /* we are the first connection producing for the given Input Assembly */
|
|
|
- return OpenMulticastConnection(PRODUCING, pa_pstConnObj, pa_CPF_data);
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- /* we need to infrom our originator on the correct connection id */
|
|
|
- pa_pstConnObj->CIPProducedConnectionID =
|
|
|
- pstExistingConn->CIPProducedConnectionID;
|
|
|
- }
|
|
|
+ if (NULL == existing_connection_object) { /* we are the first connection producing for the given Input Assembly */
|
|
|
+ return OpenMulticastConnection(kUdpCommuncationDirectionProducing,
|
|
|
+ connection_object, common_packet_format_data);
|
|
|
+ } else {
|
|
|
+ /* we need to infrom our originator on the correct connection id */
|
|
|
+ connection_object->produced_connection_id = existing_connection_object
|
|
|
+ ->produced_connection_id;
|
|
|
+ }
|
|
|
|
|
|
/* we have a connection reuse the data and the socket */
|
|
|
|
|
|
j = 0; /* allocate an unused sockaddr struct to use */
|
|
|
- if (g_stCPFDataItem.AddrInfo[0].TypeID == 0)
|
|
|
- { /* it is not used yet */
|
|
|
- j = 0;
|
|
|
- }
|
|
|
- else if (g_stCPFDataItem.AddrInfo[1].TypeID == 0)
|
|
|
- {
|
|
|
- j = 1;
|
|
|
- }
|
|
|
-
|
|
|
- if (enConnTypeIOExclusiveOwner == pa_pstConnObj->m_eInstanceType)
|
|
|
- {
|
|
|
- /* eclusive owners take the socket and further manage the connection
|
|
|
- * especially in the case of time outs.
|
|
|
- */
|
|
|
- pa_pstConnObj->sockfd[PRODUCING] = pstExistingConn->sockfd[PRODUCING];
|
|
|
- pstExistingConn->sockfd[PRODUCING] = EIP_INVALID_SOCKET;
|
|
|
- }
|
|
|
- else
|
|
|
- { /* this connection will not produce the data */
|
|
|
- pa_pstConnObj->sockfd[PRODUCING] = EIP_INVALID_SOCKET;
|
|
|
- }
|
|
|
-
|
|
|
- pa_CPF_data->AddrInfo[j].Length = 16;
|
|
|
- pa_CPF_data->AddrInfo[j].TypeID = CIP_ITEM_ID_SOCKADDRINFO_T_TO_O;
|
|
|
- pa_pstConnObj->remote_addr.sin_family = AF_INET;
|
|
|
- pa_pstConnObj->remote_addr.sin_port = pa_CPF_data->AddrInfo[j].nsin_port =
|
|
|
- htons(OPENER_EIP_IO_UDP_PORT);
|
|
|
- pa_pstConnObj->remote_addr.sin_addr.s_addr =
|
|
|
- pa_CPF_data->AddrInfo[j].nsin_addr =
|
|
|
- g_stMultiCastconfig.m_unMcastStartAddr;
|
|
|
- memset(pa_CPF_data->AddrInfo[j].nasin_zero, 0, 8);
|
|
|
- pa_CPF_data->AddrInfo[j].nsin_family = htons(AF_INET);
|
|
|
-
|
|
|
- return EIP_OK;
|
|
|
+ if (g_common_packet_format_data_item.address_info_item[0].type_id == 0) { /* it is not used yet */
|
|
|
+ j = 0;
|
|
|
+ } else if (g_common_packet_format_data_item.address_info_item[1].type_id
|
|
|
+ == 0) {
|
|
|
+ j = 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (kConnectionTypeIoExclusiveOwner == connection_object->instance_type) {
|
|
|
+ /* exclusive owners take the socket and further manage the connection
|
|
|
+ * especially in the case of time outs.
|
|
|
+ */
|
|
|
+ connection_object->socket[kUdpCommuncationDirectionProducing] =
|
|
|
+ existing_connection_object->socket[kUdpCommuncationDirectionProducing];
|
|
|
+ existing_connection_object->socket[kUdpCommuncationDirectionProducing] =
|
|
|
+ kEipInvalidSocket;
|
|
|
+ } else { /* this connection will not produce the data */
|
|
|
+ connection_object->socket[kUdpCommuncationDirectionProducing] =
|
|
|
+ kEipInvalidSocket;
|
|
|
+ }
|
|
|
+
|
|
|
+ common_packet_format_data->address_info_item[j].length = 16;
|
|
|
+ common_packet_format_data->address_info_item[j].type_id =
|
|
|
+ kSocketAddressInfoTargetToOriginatorId;
|
|
|
+ connection_object->remote_address.sin_family = AF_INET;
|
|
|
+ connection_object->remote_address.sin_port = common_packet_format_data
|
|
|
+ ->address_info_item[j].nsin_port = htons(kOpenerEipIoUdpPort);
|
|
|
+ connection_object->remote_address.sin_addr.s_addr = common_packet_format_data
|
|
|
+ ->address_info_item[j].nsin_addr = g_multicast_configuration
|
|
|
+ .starting_multicast_address;
|
|
|
+ memset(common_packet_format_data->address_info_item[j].nasin_zero, 0, 8);
|
|
|
+ common_packet_format_data->address_info_item[j].nsin_family = htons(AF_INET);
|
|
|
+
|
|
|
+ return kEipStatusOk;
|
|
|
}
|
|
|
|
|
|
-/* INT8 OpenMulticastConnection(S_CIP_CPF_Data *pa_CPF_data, S_CIP_CM_Object *pa_pstCMObject, INT8 pa_direction, int pa_index)
|
|
|
- * open a Multicast connection dependent on pa_direction.
|
|
|
- * pa_CPF_data received CPF Data Item.
|
|
|
- * pa_pstCMObject pointer to registered Object in ConnectionManager.
|
|
|
- * pa_direction flag to indicate if consuming or producing.
|
|
|
- * pa_index index of the connection object
|
|
|
- * return status
|
|
|
+/* @brief Open a Multicast connection dependent on @var direction.
|
|
|
+ *
|
|
|
+ * @param direction Flag to indicate if consuming or producing.
|
|
|
+ * @param connection_object pointer to registered Object in ConnectionManager.
|
|
|
+ * @param common_packet_format_data received CPF Data Item.
|
|
|
+ * @return status
|
|
|
* 0 .. success
|
|
|
* -1 .. error
|
|
|
*/
|
|
|
-EIP_STATUS
|
|
|
-OpenMulticastConnection(int pa_direction, S_CIP_ConnectionObject *pa_pstConnObj,
|
|
|
- S_CIP_CPF_Data *pa_CPF_data)
|
|
|
-{
|
|
|
+EipStatus OpenMulticastConnection(
|
|
|
+ UdpCommuncationDirection direction, ConnectionObject *connection_object,
|
|
|
+ CipCommonPacketFormatData *common_packet_format_data) {
|
|
|
int j;
|
|
|
- struct sockaddr_in addr;
|
|
|
- int newfd;
|
|
|
+ struct sockaddr_in socket_address;
|
|
|
+ int socket;
|
|
|
|
|
|
j = 0; /* allocate an unused sockaddr struct to use */
|
|
|
- if (0 != g_stCPFDataItem.AddrInfo[0].TypeID)
|
|
|
- {
|
|
|
- if ((CONSUMING == pa_direction)
|
|
|
- && (CIP_ITEM_ID_SOCKADDRINFO_O_TO_T == pa_CPF_data->AddrInfo[0].TypeID))
|
|
|
- {
|
|
|
- /* for consuming connection points the originator can choos the multicast address to use
|
|
|
- * we have a given address type so use it */
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- j = 1;
|
|
|
- /* if the type is not zero (not used) or if a given tpye it has to be the correct one */
|
|
|
- if ((0 != g_stCPFDataItem.AddrInfo[1].TypeID)
|
|
|
- && (!((CONSUMING == pa_direction)
|
|
|
- && (CIP_ITEM_ID_SOCKADDRINFO_O_TO_T
|
|
|
- == pa_CPF_data->AddrInfo[0].TypeID))))
|
|
|
- {
|
|
|
- OPENER_TRACE_ERR("no suitable addr info item available\n");
|
|
|
- return EIP_ERROR;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if (0 == pa_CPF_data->AddrInfo[j].TypeID)
|
|
|
- { /* we are using an unused item initialize it with the default multicast address */
|
|
|
- pa_CPF_data->AddrInfo[j].nsin_family = htons(AF_INET);
|
|
|
- pa_CPF_data->AddrInfo[j].nsin_port = htons(OPENER_EIP_IO_UDP_PORT);
|
|
|
- pa_CPF_data->AddrInfo[j].nsin_addr =
|
|
|
- g_stMultiCastconfig.m_unMcastStartAddr;
|
|
|
- memset(pa_CPF_data->AddrInfo[j].nasin_zero, 0, 8);
|
|
|
- pa_CPF_data->AddrInfo[j].Length = 16;
|
|
|
- }
|
|
|
-
|
|
|
- if (htons(AF_INET) != pa_CPF_data->AddrInfo[j].nsin_family)
|
|
|
- {
|
|
|
- OPENER_TRACE_ERR("Sockaddr Info Item with wrong sin family value recieved\n");
|
|
|
- return EIP_ERROR;
|
|
|
- }
|
|
|
-
|
|
|
- addr.sin_family = ntohs(pa_CPF_data->AddrInfo[j].nsin_family);
|
|
|
- addr.sin_addr.s_addr = pa_CPF_data->AddrInfo[j].nsin_addr;
|
|
|
- addr.sin_port = pa_CPF_data->AddrInfo[j].nsin_port;
|
|
|
-
|
|
|
- newfd = IApp_CreateUDPSocket(pa_direction, &addr); /* the address is only needed for bind used if consuming */
|
|
|
- if (newfd == EIP_INVALID_SOCKET)
|
|
|
- {
|
|
|
- OPENER_TRACE_ERR("cannot create UDP socket in OpenMulticastConnection\n");
|
|
|
- return EIP_ERROR;
|
|
|
- }
|
|
|
- pa_pstConnObj->sockfd[pa_direction] = newfd;
|
|
|
-
|
|
|
- if (pa_direction == CONSUMING)
|
|
|
- {
|
|
|
- pa_CPF_data->AddrInfo[j].TypeID = CIP_ITEM_ID_SOCKADDRINFO_O_TO_T;
|
|
|
- pa_pstConnObj->m_stOriginatorAddr = addr;
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- pa_CPF_data->AddrInfo[j].TypeID = CIP_ITEM_ID_SOCKADDRINFO_T_TO_O;
|
|
|
- pa_pstConnObj->remote_addr = addr;
|
|
|
- }
|
|
|
-
|
|
|
- return EIP_OK;
|
|
|
+ if (0 != g_common_packet_format_data_item.address_info_item[0].type_id) {
|
|
|
+ if ((kUdpCommuncationDirectionConsuming == direction)
|
|
|
+ && (kSocketAddressInfoOriginatorToTargetId
|
|
|
+ == common_packet_format_data->address_info_item[0].type_id)) {
|
|
|
+ /* for consuming connection points the originator can choos the multicast address to use
|
|
|
+ * we have a given address type so use it */
|
|
|
+ } else {
|
|
|
+ j = 1;
|
|
|
+ /* if the type is not zero (not used) or if a given tpye it has to be the correct one */
|
|
|
+ if ((0 != g_common_packet_format_data_item.address_info_item[1].type_id)
|
|
|
+ && (!((kUdpCommuncationDirectionConsuming == direction)
|
|
|
+ && (kSocketAddressInfoOriginatorToTargetId
|
|
|
+ == common_packet_format_data->address_info_item[0].type_id)))) {
|
|
|
+ OPENER_TRACE_ERR("no suitable addr info item available\n");
|
|
|
+ return kEipStatusError;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (0 == common_packet_format_data->address_info_item[j].type_id) { /* we are using an unused item initialize it with the default multicast address */
|
|
|
+ common_packet_format_data->address_info_item[j].nsin_family = htons(
|
|
|
+ AF_INET);
|
|
|
+ common_packet_format_data->address_info_item[j].nsin_port = htons(
|
|
|
+ kOpenerEipIoUdpPort);
|
|
|
+ common_packet_format_data->address_info_item[j].nsin_addr =
|
|
|
+ g_multicast_configuration.starting_multicast_address;
|
|
|
+ memset(common_packet_format_data->address_info_item[j].nasin_zero, 0, 8);
|
|
|
+ common_packet_format_data->address_info_item[j].length = 16;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (htons(AF_INET)
|
|
|
+ != common_packet_format_data->address_info_item[j].nsin_family) {
|
|
|
+ OPENER_TRACE_ERR(
|
|
|
+ "Sockaddr Info Item with wrong sin family value recieved\n");
|
|
|
+ return kEipStatusError;
|
|
|
+ }
|
|
|
+
|
|
|
+ socket_address.sin_family = ntohs(
|
|
|
+ common_packet_format_data->address_info_item[j].nsin_family);
|
|
|
+ socket_address.sin_addr.s_addr =
|
|
|
+ common_packet_format_data->address_info_item[j].nsin_addr;
|
|
|
+ socket_address.sin_port = common_packet_format_data->address_info_item[j]
|
|
|
+ .nsin_port;
|
|
|
+
|
|
|
+ socket = CreateUdpSocket(direction, &socket_address); /* the address is only needed for bind used if consuming */
|
|
|
+ if (socket == kEipInvalidSocket) {
|
|
|
+ OPENER_TRACE_ERR("cannot create UDP socket in OpenMulticastConnection\n");
|
|
|
+ return kEipStatusError;
|
|
|
+ }
|
|
|
+ connection_object->socket[direction] = socket;
|
|
|
+
|
|
|
+ if (direction == kUdpCommuncationDirectionConsuming) {
|
|
|
+ common_packet_format_data->address_info_item[j].type_id =
|
|
|
+ kSocketAddressInfoOriginatorToTargetId;
|
|
|
+ connection_object->originator_address = socket_address;
|
|
|
+ } else {
|
|
|
+ common_packet_format_data->address_info_item[j].type_id =
|
|
|
+ kSocketAddressInfoTargetToOriginatorId;
|
|
|
+ connection_object->remote_address = socket_address;
|
|
|
+ }
|
|
|
+
|
|
|
+ return kEipStatusOk;
|
|
|
}
|
|
|
|
|
|
-EIP_UINT16
|
|
|
-handleConfigData(S_CIP_Class *pa_pstAssemblyClass,
|
|
|
- S_CIP_ConnectionObject *pa_pstIOConnObj)
|
|
|
-{
|
|
|
- EIP_UINT16 unRetVal = 0;
|
|
|
- S_CIP_Instance *pstConfigInstance = getCIPInstance(pa_pstAssemblyClass,
|
|
|
- pa_pstIOConnObj->ConnectionPath.ConnectionPoint[2]);
|
|
|
-
|
|
|
- if (0 != g_unConfigDataLen)
|
|
|
- {
|
|
|
- if (connectionWithSameConfigPointExists(
|
|
|
- pa_pstIOConnObj->ConnectionPath.ConnectionPoint[2]))
|
|
|
- { /* there is a connected connection with the same config point
|
|
|
+EipUint16 HandleConfigData(CipClass *assembly_class,
|
|
|
+ ConnectionObject *connection_object) {
|
|
|
+ EipUint16 connection_manager_status = 0;
|
|
|
+ CipInstance *config_instance = GetCipInstance(
|
|
|
+ assembly_class, connection_object->connection_path.connection_point[2]);
|
|
|
+
|
|
|
+ if (0 != g_config_data_length) {
|
|
|
+ if (ConnectionWithSameConfigPointExists(
|
|
|
+ connection_object->connection_path.connection_point[2])) { /* there is a connected connection with the same config point
|
|
|
* we have to have the same data as already present in the config point*/
|
|
|
- S_CIP_Byte_Array *p = (S_CIP_Byte_Array *) getAttribute(
|
|
|
- pstConfigInstance, 3)->pt2data;
|
|
|
- if (p->len != g_unConfigDataLen)
|
|
|
- {
|
|
|
- unRetVal = CIP_CON_MGR_ERROR_OWNERSHIP_CONFLICT;
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- /*FIXME check if this is correct */
|
|
|
- if (memcmp(p->Data, g_pnConfigDataBuffer, g_unConfigDataLen))
|
|
|
- {
|
|
|
- unRetVal = CIP_CON_MGR_ERROR_OWNERSHIP_CONFLICT;
|
|
|
- }
|
|
|
- }
|
|
|
+ CipByteArray *p = (CipByteArray *) GetCipAttribute(config_instance, 3)
|
|
|
+ ->data;
|
|
|
+ if (p->length != g_config_data_length) {
|
|
|
+ connection_manager_status =
|
|
|
+ kConnectionManagerStatusCodeErrorOwnershipConflict;
|
|
|
+ } else {
|
|
|
+ /*FIXME check if this is correct */
|
|
|
+ if (memcmp(p->data, g_config_data_buffer, g_config_data_length)) {
|
|
|
+ connection_manager_status =
|
|
|
+ kConnectionManagerStatusCodeErrorOwnershipConflict;
|
|
|
}
|
|
|
- else
|
|
|
- {
|
|
|
- /*put the data on the configuration assembly object with the current
|
|
|
- design this can be done rather efficiently */
|
|
|
- if (EIP_OK
|
|
|
- != notifyAssemblyConnectedDataReceived(pstConfigInstance,
|
|
|
- g_pnConfigDataBuffer, g_unConfigDataLen))
|
|
|
- {
|
|
|
- OPENER_TRACE_WARN("Configuration data was invalid\n");
|
|
|
- unRetVal = CIP_CON_MGR_INVALID_CONFIGURATION_APP_PATH;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- return unRetVal;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ /* put the data on the configuration assembly object with the current
|
|
|
+ design this can be done rather efficiently */
|
|
|
+ if (kEipStatusOk
|
|
|
+ != NotifyAssemblyConnectedDataReceived(config_instance,
|
|
|
+ g_config_data_buffer,
|
|
|
+ g_config_data_length)) {
|
|
|
+ OPENER_TRACE_WARN("Configuration data was invalid\n");
|
|
|
+ connection_manager_status =
|
|
|
+ kConnectionManagerStatusCodeInvalidConfigurationApplicationPath;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return connection_manager_status;
|
|
|
}
|
|
|
|
|
|
-void
|
|
|
-closeIOConnection(S_CIP_ConnectionObject *pa_pstConnObjData)
|
|
|
-{
|
|
|
- S_CIP_ConnectionObject *pstNextNonCtrlMasterCon;
|
|
|
-
|
|
|
- IApp_IOConnectionEvent(pa_pstConnObjData->ConnectionPath.ConnectionPoint[0],
|
|
|
- pa_pstConnObjData->ConnectionPath.ConnectionPoint[1], enClosed);
|
|
|
-
|
|
|
- if ((enConnTypeIOExclusiveOwner == pa_pstConnObjData->m_eInstanceType)
|
|
|
- || (enConnTypeIOInputOnly == pa_pstConnObjData->m_eInstanceType))
|
|
|
- {
|
|
|
- if ((CIP_MULTICAST_CONNECTION
|
|
|
- == (pa_pstConnObjData->T_to_O_NetworkConnectionParameter
|
|
|
- & CIP_MULTICAST_CONNECTION))
|
|
|
- && (EIP_INVALID_SOCKET != pa_pstConnObjData->sockfd[PRODUCING]))
|
|
|
- {
|
|
|
- pstNextNonCtrlMasterCon = getNextNonCtrlMasterCon(
|
|
|
- pa_pstConnObjData->ConnectionPath.ConnectionPoint[1]);
|
|
|
- if (NULL != pstNextNonCtrlMasterCon)
|
|
|
- {
|
|
|
- pstNextNonCtrlMasterCon->sockfd[PRODUCING] =
|
|
|
- pa_pstConnObjData->sockfd[PRODUCING];
|
|
|
- memcpy(&(pstNextNonCtrlMasterCon->remote_addr),
|
|
|
- &(pa_pstConnObjData->remote_addr),
|
|
|
- sizeof(pstNextNonCtrlMasterCon->remote_addr));
|
|
|
- pstNextNonCtrlMasterCon->EIPSequenceCountProducing =
|
|
|
- pa_pstConnObjData->EIPSequenceCountProducing;
|
|
|
- pstNextNonCtrlMasterCon->SequenceCountProducing =
|
|
|
- pa_pstConnObjData->SequenceCountProducing;
|
|
|
- pa_pstConnObjData->sockfd[PRODUCING] = EIP_INVALID_SOCKET;
|
|
|
- pstNextNonCtrlMasterCon->TransmissionTriggerTimer =
|
|
|
- pa_pstConnObjData->TransmissionTriggerTimer;
|
|
|
- }
|
|
|
- else
|
|
|
- { /* this was the last master connection close all listen only connections listening on the port */
|
|
|
- closeAllConnsForInputWithSameType(
|
|
|
- pa_pstConnObjData->ConnectionPath.ConnectionPoint[1],
|
|
|
- enConnTypeIOListenOnly);
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- closeCommChannelsAndRemoveFromActiveConnsList(pa_pstConnObjData);
|
|
|
+void CloseIoConnection(ConnectionObject *connection_object) {
|
|
|
+ ConnectionObject *next_non_control_master_connection;
|
|
|
+
|
|
|
+ IoConnectionEvent(connection_object->connection_path.connection_point[0],
|
|
|
+ connection_object->connection_path.connection_point[1],
|
|
|
+ kClosedEvent);
|
|
|
+
|
|
|
+ if ((kConnectionTypeIoExclusiveOwner == connection_object->instance_type)
|
|
|
+ || (kConnectionTypeIoInputOnly == connection_object->instance_type)) {
|
|
|
+ if ((kRoutingTypeMulticastConnection
|
|
|
+ == (connection_object->t_to_o_network_connection_parameter
|
|
|
+ & kRoutingTypeMulticastConnection))
|
|
|
+ && (kEipInvalidSocket
|
|
|
+ != connection_object->socket[kUdpCommuncationDirectionProducing])) {
|
|
|
+ next_non_control_master_connection = GetNextNonControlMasterConnection(
|
|
|
+ connection_object->connection_path.connection_point[1]);
|
|
|
+ if (NULL != next_non_control_master_connection) {
|
|
|
+ next_non_control_master_connection->socket[kUdpCommuncationDirectionProducing] =
|
|
|
+ connection_object->socket[kUdpCommuncationDirectionProducing];
|
|
|
+ memcpy(&(next_non_control_master_connection->remote_address),
|
|
|
+ &(connection_object->remote_address),
|
|
|
+ sizeof(next_non_control_master_connection->remote_address));
|
|
|
+ next_non_control_master_connection->eip_level_sequence_count_producing =
|
|
|
+ connection_object->eip_level_sequence_count_producing;
|
|
|
+ next_non_control_master_connection->sequence_count_producing =
|
|
|
+ connection_object->sequence_count_producing;
|
|
|
+ connection_object->socket[kUdpCommuncationDirectionProducing] =
|
|
|
+ kEipInvalidSocket;
|
|
|
+ next_non_control_master_connection->transmission_trigger_timer =
|
|
|
+ connection_object->transmission_trigger_timer;
|
|
|
+ } else { /* this was the last master connection close all listen only connections listening on the port */
|
|
|
+ CloseAllConnectionsForInputWithSameType(
|
|
|
+ connection_object->connection_path.connection_point[1],
|
|
|
+ kConnectionTypeIoListenOnly);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ CloseCommunicationChannelsAndRemoveFromActiveConnectionsList(
|
|
|
+ connection_object);
|
|
|
}
|
|
|
|
|
|
-void
|
|
|
-handleIOConnectionTimeOut(S_CIP_ConnectionObject *pa_pstConn)
|
|
|
-{
|
|
|
- S_CIP_ConnectionObject *pstNextNonCtrlMasterCon;
|
|
|
- IApp_IOConnectionEvent(pa_pstConn->ConnectionPath.ConnectionPoint[0],
|
|
|
- pa_pstConn->ConnectionPath.ConnectionPoint[1], enTimedOut);
|
|
|
-
|
|
|
- if (CIP_MULTICAST_CONNECTION
|
|
|
- == (pa_pstConn->T_to_O_NetworkConnectionParameter
|
|
|
- & CIP_MULTICAST_CONNECTION))
|
|
|
- {
|
|
|
- switch (pa_pstConn->m_eInstanceType)
|
|
|
- {
|
|
|
- case enConnTypeIOExclusiveOwner:
|
|
|
- closeAllConnsForInputWithSameType(
|
|
|
- pa_pstConn->ConnectionPath.ConnectionPoint[1],
|
|
|
- enConnTypeIOInputOnly);
|
|
|
- closeAllConnsForInputWithSameType(
|
|
|
- pa_pstConn->ConnectionPath.ConnectionPoint[1],
|
|
|
- enConnTypeIOListenOnly);
|
|
|
+void HandleIoConnectionTimeOut(ConnectionObject *connection_object) {
|
|
|
+ ConnectionObject *next_non_control_master_connection;
|
|
|
+ IoConnectionEvent(connection_object->connection_path.connection_point[0],
|
|
|
+ connection_object->connection_path.connection_point[1],
|
|
|
+ kTimedOutEvent);
|
|
|
+
|
|
|
+ if (kRoutingTypeMulticastConnection
|
|
|
+ == (connection_object->t_to_o_network_connection_parameter
|
|
|
+ & kRoutingTypeMulticastConnection)) {
|
|
|
+ switch (connection_object->instance_type) {
|
|
|
+ case kConnectionTypeIoExclusiveOwner:
|
|
|
+ CloseAllConnectionsForInputWithSameType(
|
|
|
+ connection_object->connection_path.connection_point[1],
|
|
|
+ kConnectionTypeIoInputOnly);
|
|
|
+ CloseAllConnectionsForInputWithSameType(
|
|
|
+ connection_object->connection_path.connection_point[1],
|
|
|
+ kConnectionTypeIoListenOnly);
|
|
|
break;
|
|
|
- case enConnTypeIOInputOnly:
|
|
|
- if (EIP_INVALID_SOCKET != pa_pstConn->sockfd[PRODUCING])
|
|
|
- { /* we are the controlling input only connection find a new controller*/
|
|
|
- pstNextNonCtrlMasterCon = getNextNonCtrlMasterCon(
|
|
|
- pa_pstConn->ConnectionPath.ConnectionPoint[1]);
|
|
|
- if (NULL != pstNextNonCtrlMasterCon)
|
|
|
- {
|
|
|
- pstNextNonCtrlMasterCon->sockfd[PRODUCING] =
|
|
|
- pa_pstConn->sockfd[PRODUCING];
|
|
|
- pa_pstConn->sockfd[PRODUCING] = EIP_INVALID_SOCKET;
|
|
|
- pstNextNonCtrlMasterCon->TransmissionTriggerTimer =
|
|
|
- pa_pstConn->TransmissionTriggerTimer;
|
|
|
- }
|
|
|
- else
|
|
|
- { /* this was the last master connection close all listen only connections listening on the port */
|
|
|
- closeAllConnsForInputWithSameType(
|
|
|
- pa_pstConn->ConnectionPath.ConnectionPoint[1],
|
|
|
- enConnTypeIOListenOnly);
|
|
|
- }
|
|
|
+ case kConnectionTypeIoInputOnly:
|
|
|
+ if (kEipInvalidSocket
|
|
|
+ != connection_object->socket[kUdpCommuncationDirectionProducing]) { /* we are the controlling input only connection find a new controller*/
|
|
|
+ next_non_control_master_connection =
|
|
|
+ GetNextNonControlMasterConnection(
|
|
|
+ connection_object->connection_path.connection_point[1]);
|
|
|
+ if (NULL != next_non_control_master_connection) {
|
|
|
+ next_non_control_master_connection->socket[kUdpCommuncationDirectionProducing] =
|
|
|
+ connection_object->socket[kUdpCommuncationDirectionProducing];
|
|
|
+ connection_object->socket[kUdpCommuncationDirectionProducing] =
|
|
|
+ kEipInvalidSocket;
|
|
|
+ next_non_control_master_connection->transmission_trigger_timer =
|
|
|
+ connection_object->transmission_trigger_timer;
|
|
|
+ } else { /* this was the last master connection close all listen only connections listening on the port */
|
|
|
+ CloseAllConnectionsForInputWithSameType(
|
|
|
+ connection_object->connection_path.connection_point[1],
|
|
|
+ kConnectionTypeIoListenOnly);
|
|
|
}
|
|
|
+ }
|
|
|
break;
|
|
|
default:
|
|
|
break;
|
|
|
- }
|
|
|
}
|
|
|
+ }
|
|
|
|
|
|
- OPENER_ASSERT(NULL != pa_pstConn->m_pfCloseFunc);
|
|
|
- pa_pstConn->m_pfCloseFunc(pa_pstConn);
|
|
|
+ OPENER_ASSERT(NULL != connection_object->connection_close_function);
|
|
|
+ connection_object->connection_close_function(connection_object);
|
|
|
}
|
|
|
|
|
|
-EIP_STATUS
|
|
|
-sendConnectedData(S_CIP_ConnectionObject *pa_pstConnection)
|
|
|
-{
|
|
|
- S_CIP_CPF_Data *pCPFDataItem;
|
|
|
- S_CIP_Byte_Array *p;
|
|
|
- EIP_UINT16 replylength;
|
|
|
- EIP_UINT8 *pnBuf;
|
|
|
+EipStatus SendConnectedData(ConnectionObject *connection_object) {
|
|
|
+ CipCommonPacketFormatData *common_packet_format_data;
|
|
|
+ EipUint16 reply_length;
|
|
|
+ EipUint8 *message_data_reply_buffer;
|
|
|
|
|
|
/* TODO think of adding an own send buffer to each connection object in order to preset up the whole message on connection opening and just change the variable data items e.g., sequence number */
|
|
|
|
|
|
- pCPFDataItem = &g_stCPFDataItem; /* TODO think on adding a CPF data item to the S_CIP_ConnectionObject in order to remove the code here or even better allocate memory in the connection object for storing the message to send and just change the application data*/
|
|
|
+ common_packet_format_data = &g_common_packet_format_data_item; /* TODO think on adding a CPF data item to the S_CIP_ConnectionObject in order to remove the code here or even better allocate memory in the connection object for storing the message to send and just change the application data*/
|
|
|
|
|
|
- pa_pstConnection->EIPSequenceCountProducing++;
|
|
|
+ connection_object->eip_level_sequence_count_producing++;
|
|
|
|
|
|
/* assembleCPFData */
|
|
|
- pCPFDataItem->ItemCount = 2;
|
|
|
- if ((pa_pstConnection->TransportTypeClassTrigger & 0x0F) != 0)
|
|
|
- { /* use Sequenced Address Items if not Connection Class 0 */
|
|
|
- pCPFDataItem->stAddr_Item.TypeID = CIP_ITEM_ID_SEQUENCEDADDRESS;
|
|
|
- pCPFDataItem->stAddr_Item.Length = 8;
|
|
|
- pCPFDataItem->stAddr_Item.Data.SequenceNumber =
|
|
|
- pa_pstConnection->EIPSequenceCountProducing;
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- pCPFDataItem->stAddr_Item.TypeID = CIP_ITEM_ID_CONNECTIONBASED;
|
|
|
- pCPFDataItem->stAddr_Item.Length = 4;
|
|
|
-
|
|
|
- }
|
|
|
- pCPFDataItem->stAddr_Item.Data.ConnectionIdentifier =
|
|
|
- pa_pstConnection->CIPProducedConnectionID;
|
|
|
-
|
|
|
- pCPFDataItem->stDataI_Item.TypeID = CIP_ITEM_ID_CONNECTIONTRANSPORTPACKET;
|
|
|
-
|
|
|
- p =
|
|
|
- (S_CIP_Byte_Array *) pa_pstConnection->p_stProducingInstance->pstAttributes->pt2data;
|
|
|
- pCPFDataItem->stDataI_Item.Length = 0;
|
|
|
+ common_packet_format_data->item_count = 2;
|
|
|
+ if ((connection_object->transport_type_class_trigger & 0x0F) != 0) { /* use Sequenced Address Items if not Connection Class 0 */
|
|
|
+ common_packet_format_data->address_item.type_id = kSequencedAddressItemId;
|
|
|
+ common_packet_format_data->address_item.length = 8;
|
|
|
+ common_packet_format_data->address_item.data.sequence_number =
|
|
|
+ connection_object->eip_level_sequence_count_producing;
|
|
|
+ } else {
|
|
|
+ common_packet_format_data->address_item.type_id = kConnectionBasedId;
|
|
|
+ common_packet_format_data->address_item.length = 4;
|
|
|
+
|
|
|
+ }
|
|
|
+ common_packet_format_data->address_item.data.connection_identifier =
|
|
|
+ connection_object->produced_connection_id;
|
|
|
+
|
|
|
+ common_packet_format_data->data_item.type_id = kConnectedTransportPacketId;
|
|
|
+
|
|
|
+ CipByteArray *producing_instance_attributes =
|
|
|
+ (CipByteArray *) connection_object->producing_instance->attributes->data;
|
|
|
+ common_packet_format_data->data_item.length = 0;
|
|
|
|
|
|
/* notify the application that data will be sent immediately after the call */
|
|
|
- if (IApp_BeforeAssemblyDataSend(pa_pstConnection->p_stProducingInstance))
|
|
|
- {
|
|
|
- /* the data has changed increase sequence counter */
|
|
|
- pa_pstConnection->SequenceCountProducing++;
|
|
|
- }
|
|
|
+ if (BeforeAssemblyDataSend(connection_object->producing_instance)) {
|
|
|
+ /* the data has changed increase sequence counter */
|
|
|
+ connection_object->sequence_count_producing++;
|
|
|
+ }
|
|
|
|
|
|
/* set AddressInfo Items to invalid Type */
|
|
|
- pCPFDataItem->AddrInfo[0].TypeID = 0;
|
|
|
- pCPFDataItem->AddrInfo[1].TypeID = 0;
|
|
|
-
|
|
|
- replylength = assembleLinearMsg(0, pCPFDataItem,
|
|
|
- &g_acMessageDataReplyBuffer[0]);
|
|
|
-
|
|
|
- pnBuf = &g_acMessageDataReplyBuffer[replylength - 2];
|
|
|
- pCPFDataItem->stDataI_Item.Length = p->len;
|
|
|
- if (OPENER_PRODUCED_DATA_HAS_RUN_IDLE_HEADER)
|
|
|
- {
|
|
|
- pCPFDataItem->stDataI_Item.Length += 4;
|
|
|
- }
|
|
|
-
|
|
|
- if ((pa_pstConnection->TransportTypeClassTrigger & 0x0F) == 1)
|
|
|
- {
|
|
|
- pCPFDataItem->stDataI_Item.Length += 2;
|
|
|
- htols(pCPFDataItem->stDataI_Item.Length, &pnBuf);
|
|
|
- htols(pa_pstConnection->SequenceCountProducing, &pnBuf);
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- htols(pCPFDataItem->stDataI_Item.Length, &pnBuf);
|
|
|
- }
|
|
|
-
|
|
|
- if (OPENER_PRODUCED_DATA_HAS_RUN_IDLE_HEADER)
|
|
|
- {
|
|
|
- htoll(g_nRunIdleState, &(pnBuf));
|
|
|
- }
|
|
|
-
|
|
|
- memcpy(pnBuf, p->Data, p->len);
|
|
|
-
|
|
|
- replylength += pCPFDataItem->stDataI_Item.Length;
|
|
|
-
|
|
|
- return IApp_SendUDPData(&pa_pstConnection->remote_addr,
|
|
|
- pa_pstConnection->sockfd[PRODUCING], &g_acMessageDataReplyBuffer[0],
|
|
|
- replylength);
|
|
|
+ common_packet_format_data->address_info_item[0].type_id = 0;
|
|
|
+ common_packet_format_data->address_info_item[1].type_id = 0;
|
|
|
+
|
|
|
+ reply_length = AssembleLinearMessage(0, common_packet_format_data,
|
|
|
+ &g_message_data_reply_buffer[0]);
|
|
|
+
|
|
|
+ message_data_reply_buffer = &g_message_data_reply_buffer[reply_length - 2];
|
|
|
+ common_packet_format_data->data_item.length = producing_instance_attributes
|
|
|
+ ->length;
|
|
|
+ if (kOpenerProducedDataHasRunIdleHeader) {
|
|
|
+ common_packet_format_data->data_item.length += 4;
|
|
|
+ }
|
|
|
+
|
|
|
+ if ((connection_object->transport_type_class_trigger & 0x0F) == 1) {
|
|
|
+ common_packet_format_data->data_item.length += 2;
|
|
|
+ AddIntToMessage(common_packet_format_data->data_item.length,
|
|
|
+ &message_data_reply_buffer);
|
|
|
+ AddIntToMessage(connection_object->sequence_count_producing,
|
|
|
+ &message_data_reply_buffer);
|
|
|
+ } else {
|
|
|
+ AddIntToMessage(common_packet_format_data->data_item.length,
|
|
|
+ &message_data_reply_buffer);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (kOpenerProducedDataHasRunIdleHeader) {
|
|
|
+ AddDintToMessage(g_run_idle_state, &(message_data_reply_buffer));
|
|
|
+ }
|
|
|
+
|
|
|
+ memcpy(message_data_reply_buffer, producing_instance_attributes->data,
|
|
|
+ producing_instance_attributes->length);
|
|
|
+
|
|
|
+ reply_length += common_packet_format_data->data_item.length;
|
|
|
+
|
|
|
+ return SendUdpData(
|
|
|
+ &connection_object->remote_address,
|
|
|
+ connection_object->socket[kUdpCommuncationDirectionProducing],
|
|
|
+ &g_message_data_reply_buffer[0], reply_length);
|
|
|
}
|
|
|
|
|
|
-EIP_STATUS
|
|
|
-handleReceivedIOConnData(struct CIP_ConnectionObject *pa_pstConnection,
|
|
|
- EIP_UINT8 * pa_pnData, EIP_UINT16 pa_nDataLength)
|
|
|
-{
|
|
|
+EipStatus HandleReceivedIoConnectionData(ConnectionObject *connection_object,
|
|
|
+ EipUint8 *data, EipUint16 data_length) {
|
|
|
|
|
|
/* check class 1 sequence number*/
|
|
|
- if ((pa_pstConnection->TransportTypeClassTrigger & 0x0F) == 1)
|
|
|
- {
|
|
|
- EIP_UINT16 nSequenceBuf = ltohs(&(pa_pnData));
|
|
|
- if (SEQ_LEQ16(nSequenceBuf, pa_pstConnection->SequenceCountConsuming))
|
|
|
- {
|
|
|
- return EIP_OK; /* no new data for the assembly */
|
|
|
- }
|
|
|
- pa_pstConnection->SequenceCountConsuming = nSequenceBuf;
|
|
|
- pa_nDataLength -= 2;
|
|
|
- }
|
|
|
-
|
|
|
- if (pa_nDataLength > 0)
|
|
|
- {
|
|
|
- /* we have no heartbeat connection */
|
|
|
- if (OPENER_CONSUMED_DATA_HAS_RUN_IDLE_HEADER)
|
|
|
- {
|
|
|
- EIP_UINT32 nRunIdleBuf = ltohl(&(pa_pnData));
|
|
|
- if (g_nRunIdleState != nRunIdleBuf)
|
|
|
- {
|
|
|
- IApp_RunIdleChanged(nRunIdleBuf);
|
|
|
- }
|
|
|
- g_nRunIdleState = nRunIdleBuf;
|
|
|
- pa_nDataLength -= 4;
|
|
|
- }
|
|
|
-
|
|
|
- if (notifyAssemblyConnectedDataReceived(
|
|
|
- pa_pstConnection->p_stConsumingInstance, pa_pnData, pa_nDataLength)
|
|
|
- != 0)
|
|
|
- {
|
|
|
- return EIP_ERROR;
|
|
|
- }
|
|
|
- }
|
|
|
- return EIP_OK;
|
|
|
+ if ((connection_object->transport_type_class_trigger & 0x0F) == 1) {
|
|
|
+ EipUint16 sequence_buffer = GetIntFromMessage(&(data));
|
|
|
+ if (SEQ_LEQ16(sequence_buffer,
|
|
|
+ connection_object->sequence_count_consuming)) {
|
|
|
+ return kEipStatusOk; /* no new data for the assembly */
|
|
|
+ }
|
|
|
+ connection_object->sequence_count_consuming = sequence_buffer;
|
|
|
+ data_length -= 2;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (data_length > 0) {
|
|
|
+ /* we have no heartbeat connection */
|
|
|
+ if (kOpenerConsumedDataHasRunIdleHeader) {
|
|
|
+ EipUint32 nRunIdleBuf = GetDintFromMessage(&(data));
|
|
|
+ if (g_run_idle_state != nRunIdleBuf) {
|
|
|
+ RunIdleChanged(nRunIdleBuf);
|
|
|
+ }
|
|
|
+ g_run_idle_state = nRunIdleBuf;
|
|
|
+ data_length -= 4;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (NotifyAssemblyConnectedDataReceived(
|
|
|
+ connection_object->consuming_instance, data, data_length) != 0) {
|
|
|
+ return kEipStatusError;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return kEipStatusOk;
|
|
|
}
|
|
|
|
|
|
-int
|
|
|
-openCommunicationChannels(struct CIP_ConnectionObject *pa_pstIOConnObj)
|
|
|
-{
|
|
|
- int O2TConnectionType, T2OConnectionType;
|
|
|
- int nRetVal = EIP_OK;
|
|
|
- /*get pointer to the cpf data, currently we have just one global instance of the struct. This may change in the future*/
|
|
|
- S_CIP_CPF_Data *pstCPF_data = &g_stCPFDataItem;
|
|
|
+EipStatus OpenCommunicationChannels(ConnectionObject *connection_object) {
|
|
|
+ int originator_to_target_connection_type,
|
|
|
+ target_to_originator_connection_type;
|
|
|
+ int eip_status = kEipStatusOk;
|
|
|
+ /*get pointer to the CPF data, currently we have just one global instance of the struct. This may change in the future*/
|
|
|
+ CipCommonPacketFormatData *common_packet_format_data =
|
|
|
+ &g_common_packet_format_data_item;
|
|
|
|
|
|
- O2TConnectionType = (pa_pstIOConnObj->O_to_T_NetworkConnectionParameter
|
|
|
- & 0x6000) >> 13;
|
|
|
- T2OConnectionType = (pa_pstIOConnObj->T_to_O_NetworkConnectionParameter
|
|
|
- & 0x6000) >> 13;
|
|
|
+ originator_to_target_connection_type = (connection_object
|
|
|
+ ->o_to_t_network_connection_parameter & 0x6000) >> 13;
|
|
|
+ target_to_originator_connection_type = (connection_object
|
|
|
+ ->t_to_o_network_connection_parameter & 0x6000) >> 13;
|
|
|
|
|
|
/* open a connection "point to point" or "multicast" based on the ConnectionParameter */
|
|
|
- if (O2TConnectionType == 1) /* Multicast consuming */
|
|
|
- {
|
|
|
- if (OpenMulticastConnection(CONSUMING, pa_pstIOConnObj, pstCPF_data)
|
|
|
- == EIP_ERROR)
|
|
|
- {
|
|
|
- OPENER_TRACE_ERR("error in OpenMulticast Connection\n");
|
|
|
- return CIP_ERROR_CONNECTION_FAILURE;
|
|
|
- }
|
|
|
- }
|
|
|
- else if (O2TConnectionType == 2) /* Point to Point consuming */
|
|
|
- {
|
|
|
- if (OpenConsumingPointToPointConnection(pa_pstIOConnObj, pstCPF_data)
|
|
|
- == EIP_ERROR)
|
|
|
- {
|
|
|
- OPENER_TRACE_ERR("error in PointToPoint consuming connection\n");
|
|
|
- return CIP_ERROR_CONNECTION_FAILURE;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if (T2OConnectionType == 1) /* Multicast producing */
|
|
|
- {
|
|
|
- if (openProducingMulticastConnection(pa_pstIOConnObj, pstCPF_data)
|
|
|
- == EIP_ERROR)
|
|
|
- {
|
|
|
- OPENER_TRACE_ERR("error in OpenMulticast Connection\n");
|
|
|
- return CIP_ERROR_CONNECTION_FAILURE;
|
|
|
- }
|
|
|
- }
|
|
|
- else if (T2OConnectionType == 2) /* Point to Point producing */
|
|
|
- {
|
|
|
-
|
|
|
- if (OpenProducingPointToPointConnection(pa_pstIOConnObj, pstCPF_data)
|
|
|
- != EIP_OK)
|
|
|
- {
|
|
|
- OPENER_TRACE_ERR("error in PointToPoint producing connection\n");
|
|
|
- return CIP_ERROR_CONNECTION_FAILURE;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- return nRetVal;
|
|
|
+ if (originator_to_target_connection_type == 1) /*TODO: Fix magic number; Multicast consuming */
|
|
|
+ {
|
|
|
+ if (OpenMulticastConnection(kUdpCommuncationDirectionConsuming,
|
|
|
+ connection_object, common_packet_format_data)
|
|
|
+ == kEipStatusError) {
|
|
|
+ OPENER_TRACE_ERR("error in OpenMulticast Connection\n");
|
|
|
+ return kCipErrorConnectionFailure;
|
|
|
+ }
|
|
|
+ } else if (originator_to_target_connection_type == 2) /* TODO: Fix magic number; Point to Point consuming */
|
|
|
+ {
|
|
|
+ if (OpenConsumingPointToPointConnection(connection_object,
|
|
|
+ common_packet_format_data)
|
|
|
+ == kEipStatusError) {
|
|
|
+ OPENER_TRACE_ERR("error in PointToPoint consuming connection\n");
|
|
|
+ return kCipErrorConnectionFailure;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (target_to_originator_connection_type == 1) /* TODO: Fix magic number; Multicast producing */
|
|
|
+ {
|
|
|
+ if (OpenProducingMulticastConnection(connection_object,
|
|
|
+ common_packet_format_data)
|
|
|
+ == kEipStatusError) {
|
|
|
+ OPENER_TRACE_ERR("error in OpenMulticast Connection\n");
|
|
|
+ return kCipErrorConnectionFailure;
|
|
|
+ }
|
|
|
+ } else if (target_to_originator_connection_type == 2) /* TODO: Fix magic number; Point to Point producing */
|
|
|
+ {
|
|
|
+
|
|
|
+ if (OpenProducingPointToPointConnection(connection_object,
|
|
|
+ common_packet_format_data)
|
|
|
+ != kEipStatusOk) {
|
|
|
+ OPENER_TRACE_ERR("error in PointToPoint producing connection\n");
|
|
|
+ return kCipErrorConnectionFailure;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return eip_status;
|
|
|
}
|
|
|
|
|
|
-void
|
|
|
-closeCommChannelsAndRemoveFromActiveConnsList(
|
|
|
- struct CIP_ConnectionObject *pa_pstConnObjData)
|
|
|
-{
|
|
|
- IApp_CloseSocket_udp(pa_pstConnObjData->sockfd[CONSUMING]);
|
|
|
- pa_pstConnObjData->sockfd[CONSUMING] = EIP_INVALID_SOCKET;
|
|
|
- IApp_CloseSocket_udp(pa_pstConnObjData->sockfd[PRODUCING]);
|
|
|
- pa_pstConnObjData->sockfd[PRODUCING] = EIP_INVALID_SOCKET;
|
|
|
-
|
|
|
- removeFromActiveConnections(pa_pstConnObjData);
|
|
|
+void CloseCommunicationChannelsAndRemoveFromActiveConnectionsList(
|
|
|
+ ConnectionObject *connection_object) {
|
|
|
+ IApp_CloseSocket_udp(
|
|
|
+ connection_object->socket[kUdpCommuncationDirectionConsuming]);
|
|
|
+ connection_object->socket[kUdpCommuncationDirectionConsuming] =
|
|
|
+ kEipInvalidSocket;
|
|
|
+ IApp_CloseSocket_udp(
|
|
|
+ connection_object->socket[kUdpCommuncationDirectionProducing]);
|
|
|
+ connection_object->socket[kUdpCommuncationDirectionProducing] =
|
|
|
+ kEipInvalidSocket;
|
|
|
+
|
|
|
+ RemoveFromActiveConnections(connection_object);
|
|
|
}
|