Explorar o código

Merge branch 'Issue48NewForwardOpenClose'

CapXilinx %!s(int64=9) %!d(string=hai) anos
pai
achega
1c56464f44
Modificáronse 57 ficheiros con 4246 adicións e 1503 borrados
  1. 4 0
      .gitattributes
  2. 10 0
      README.md
  3. 3 2
      source/buildsupport/OpENer.cmake
  4. 2 1
      source/src/cip/CMakeLists.txt
  5. 142 99
      source/src/cip/appcontype.c
  6. 4 2
      source/src/cip/appcontype.h
  7. 44 35
      source/src/cip/cipassembly.c
  8. 7 7
      source/src/cip/cipassembly.h
  9. 15 11
      source/src/cip/cipclass3connection.c
  10. 3 2
      source/src/cip/cipclass3connection.h
  11. 142 103
      source/src/cip/cipcommon.c
  12. 7 4
      source/src/cip/cipcommon.h
  13. 516 247
      source/src/cip/cipconnectionmanager.c
  14. 193 72
      source/src/cip/cipconnectionmanager.h
  15. 93 0
      source/src/cip/cipelectronickey.c
  16. 126 0
      source/src/cip/cipelectronickey.h
  17. 527 0
      source/src/cip/cipepath.c
  18. 340 0
      source/src/cip/cipepath.h
  19. 27 24
      source/src/cip/cipidentity.c
  20. 434 301
      source/src/cip/cipioconnection.c
  21. 4 3
      source/src/cip/cipioconnection.h
  22. 80 57
      source/src/cip/cipmessagerouter.c
  23. 7 5
      source/src/cip/cipmessagerouter.h
  24. 18 12
      source/src/cip/ciptcpipinterface.c
  25. 1 1
      source/src/cip/ciptcpipinterface.h
  26. 52 97
      source/src/cip/ciptypes.h
  27. 146 119
      source/src/enet_encap/cpf.c
  28. 29 24
      source/src/enet_encap/cpf.h
  29. 125 101
      source/src/enet_encap/encap.c
  30. 64 16
      source/src/enet_encap/endianconv.c
  31. 19 5
      source/src/enet_encap/endianconv.h
  32. 63 37
      source/src/opener_api.h
  33. 6 5
      source/src/ports/POSIX/main.c
  34. 11 4
      source/src/ports/POSIX/networkhandler.c
  35. 10 0
      source/src/ports/POSIX/networkhandler.h
  36. 3 3
      source/src/ports/POSIX/opener_error.c
  37. 17 9
      source/src/ports/POSIX/sample_application/opener_user_conf.h
  38. 21 17
      source/src/ports/POSIX/sample_application/sampleapplication.c
  39. 7 2
      source/src/ports/WIN32/networkhandler.c
  40. 6 0
      source/src/ports/WIN32/networkhandler.h
  41. 13 7
      source/src/ports/WIN32/opener_error.c
  42. 28 7
      source/src/ports/generic_networkhandler.c
  43. 24 25
      source/src/typedefs.h
  44. 9 3
      source/src/utils/random.c
  45. 3 1
      source/src/utils/random.h
  46. 1 1
      source/src/utils/xorshiftrandom.h
  47. 2 0
      source/tests/CMakeLists.txt
  48. 2 0
      source/tests/OpENerTests.h
  49. 10 0
      source/tests/cip/CMakeLists.txt
  50. 162 0
      source/tests/cip/cipelectronickeytest.cpp
  51. 477 0
      source/tests/cip/cipepathtest.cpp
  52. 19 0
      source/tests/cip/connectionmanagertest.cpp
  53. 2 1
      source/tests/enet_encap/endianconvtest.cpp
  54. 2 0
      source/tests/utils/CMakeLists.txt
  55. 11 10
      source/tests/utils/randomTests.cpp
  56. 20 21
      source/tests/utils/xorshiftrandomtests.cpp
  57. 133 0
      uncrustify.cfg

+ 4 - 0
.gitattributes

@@ -0,0 +1,4 @@
+*.c filter=uncrustify
+*.cpp filter=uncrustify
+*.h filter=uncrustify
+*.hpp filter=uncrustify

+ 10 - 0
README.md

@@ -93,5 +93,15 @@ Porting OpENer:
 For porting OpENer to new platforms please see the porting section in the 
 Doxygen documentation.
 
+Contributing to OpENer:
+-----------------------
+The easiest way is to fork the repository, then create a feature/bugfix branch.
+After finishing your feature/bugfix create a pull request and explain your changes.
+Also, please update and/or add doxygen comments to the provided code sections.
+Please stick to the coding conventions, as defined in source/doc/coding_rules
+The easiest way to conform to the indenting convertion is to set uncrustify as git filter in the OpENer repository, which can be done with the following to commands:
+
+git config filter.uncrustify.clean=/path/to/uncrustify/uncrustify -c uncrustify.cfg --mtime --no-backup
+git config filter.uncrustify.smudge=cat
 
 

+ 3 - 2
source/buildsupport/OpENer.cmake

@@ -13,7 +13,7 @@ macro(opener_platform_support ARGS)
     message(FATAL_ERROR "No platform selected!")  
   endif(OpENer_PLATFORM STREQUAL "")
 
-  include( ${OpENer_BUILDSUPPORT_DIR}/${OpENer_PLATFORM}/OpENer_PLATFORM_${ARGS}.cmake)
+  include( ${OpENer_BUILDSUPPORT_DIR}/${OpENer_PLATFORM}/OpENer_PLATFORM_INCLUDES.cmake)
   opener_platform_spec()
 endmacro(opener_platform_support ARGS)
 
@@ -24,11 +24,12 @@ endmacro(opener_platform_support ARGS)
 macro(opener_common_includes)
   set( SRC_DIR "${PROJECT_SOURCE_DIR}/src" )
   set( CIP_SRC_DIR "${SRC_DIR}/cip" )
+  set( CIP_CONNETION_MANAGER_SRC_DIR "${SRC_DIR}/cip/connectionmanager" )
   set( ENET_ENCAP_SRC_DIR "${SRC_DIR}/enet_encap" )
   set( PORTS_SRC_DIR "${SRC_DIR}/ports")
   set( UTILS_SRC_DIR "${SRC_DIR}/utils")
 
-  include_directories( ${PROJECT_SOURCE_DIR} ${SRC_DIR} ${CIP_SRC_DIR} ${ENET_ENCAP_SRC_DIR} ${PORTS_SRC_DIR} ${UTILS_SRC_DIR} ${OpENer_CIP_OBJECTS_DIR} )
+  include_directories( ${PROJECT_SOURCE_DIR} ${SRC_DIR} ${CIP_SRC_DIR} ${CIP_CONNETION_MANAGER_SRC_DIR} ${ENET_ENCAP_SRC_DIR} ${PORTS_SRC_DIR} ${UTILS_SRC_DIR} ${OpENer_CIP_OBJECTS_DIR} )
 endmacro(opener_common_includes)
 
 MACRO(opener_add_cip_object NAME DESCRIPTION)

+ 2 - 1
source/src/cip/CMakeLists.txt

@@ -12,6 +12,7 @@ opener_common_includes()
 #######################################
 opener_platform_support("INCLUDES")
 
-set( CIP_SRC appcontype.c cipassembly.c cipclass3connection.c cipcommon.c cipconnectionmanager.c ciperror.h cipethernetlink.c cipidentity.c cipioconnection.c cipmessagerouter.c ciptcpipinterface.c ciptypes.h )
+set( CIP_SRC appcontype.c cipassembly.c cipclass3connection.c cipcommon.c cipconnectionmanager.c ciperror.h cipethernetlink.c cipidentity.c cipioconnection.c cipmessagerouter.c ciptcpipinterface.c ciptypes.h cipepath.h cipepath.c cipelectronickey.h cipelectronickey.c )
 
 add_library( CIP ${CIP_SRC} )
+

+ 142 - 99
source/src/cip/appcontype.c

@@ -11,6 +11,8 @@
 #include "cipconnectionmanager.h"
 #include "opener_api.h"
 #include "assert.h"
+#include "trace.h"
+
 
 /** @brief External globals needed from connectionmanager.c */
 extern ConnectionObject *g_active_connection_list;
@@ -36,35 +38,62 @@ typedef struct {
   unsigned int output_assembly; /**< the O-to-T point for the connection */
   unsigned int input_assembly; /**< the T-to-O point for the connection */
   unsigned int config_assembly; /**< the config point for the connection */
-  ConnectionObject connection_data[OPENER_CIP_NUM_LISTEN_ONLY_CONNS_PER_CON_PATH]; /**< the connection data */
+  ConnectionObject connection_data[OPENER_CIP_NUM_LISTEN_ONLY_CONNS_PER_CON_PATH
+  ];                                                                               /**< the connection data */
 } ListenOnlyConnection;
 
-ExclusiveOwnerConnection g_exlusive_owner_connections[OPENER_CIP_NUM_EXLUSIVE_OWNER_CONNS]; /**< Exclusive Owner connections */
+ExclusiveOwnerConnection g_exlusive_owner_connections[
+  OPENER_CIP_NUM_EXLUSIVE_OWNER_CONNS];                                                     /**< Exclusive Owner connections */
 
 InputOnlyConnection g_input_only_connections[OPENER_CIP_NUM_INPUT_ONLY_CONNS]; /**< Input Only connections */
 
 ListenOnlyConnection g_listen_only_connections[OPENER_CIP_NUM_LISTEN_ONLY_CONNS]; /**< Listen Only connections */
 
+/** @brief Takes an ConnectionObject and searches and returns an Exclusive Owner Connection based on the ConnectionObject,
+ * if there is non it returns NULL
+ *
+ * @param connection_object Connection Object which will be searched for in the Exclusive Owner Connections
+ * @param extended_error Pointer to the extended error variable, will be written if an error occurs
+ * @return The corresponding Exclusive Owner Connection or NULL if there is non
+ */
 ConnectionObject *GetExclusiveOwnerConnection(
-    const ConnectionObject *RESTRICT connection_object, EipUint16 *const extended_error);
-
-ConnectionObject *GetInputOnlyConnection(const ConnectionObject *const RESTRICT connection_object,
-                                         EipUint16 *const extended_error);
-
-ConnectionObject *GetListenOnlyConnection(const ConnectionObject *const RESTRICT connection_object,
-                                          EipUint16 *const extended_error);
+  const ConnectionObject *RESTRICT connection_object,
+  EipUint16 *const extended_error);
 
-void ConfigureExclusiveOwnerConnectionPoint(const unsigned int connection_number,
-                                            const unsigned int output_assembly,
-                                            const unsigned int input_assembly,
-                                            const unsigned int config_assembly) {
+/** @brief Takes an ConnectionObject and searches and returns an Input Only Connection based on the ConnectionObject,
+ * if there is non it returns NULL
+ *
+ * @param connection_object Connection Object which will be searched for in the Input Only Connections
+ * @param extended_error Pointer to the extended error variable, will be written if an error occurs
+ * @return The corresponding Exclusive Owner Connection or NULL if there is non
+ */
+ConnectionObject *GetInputOnlyConnection(
+  const ConnectionObject *const RESTRICT connection_object,
+  EipUint16 *const extended_error);
+
+/** @brief Takes an ConnectionObject and searches and returns an Listen Only Connection based on the ConnectionObject,
+ * if there is non it returns NULL
+ *
+ * @param connection_object Connection Object which will be searched for in the Listen Only Connections
+ * @param extended_error Pointer to the extended error variable, will be written if an error occurs
+ * @return The corresponding Exclusive Owner Connection or NULL if there is non
+ */
+ConnectionObject *GetListenOnlyConnection(
+  const ConnectionObject *const RESTRICT connection_object,
+  EipUint16 *const extended_error);
+
+void ConfigureExclusiveOwnerConnectionPoint(
+  const unsigned int connection_number,
+  const unsigned int output_assembly,
+  const unsigned int input_assembly,
+  const unsigned int config_assembly) {
   if (OPENER_CIP_NUM_EXLUSIVE_OWNER_CONNS > connection_number) {
     g_exlusive_owner_connections[connection_number].output_assembly =
-        output_assembly;
+      output_assembly;
     g_exlusive_owner_connections[connection_number].input_assembly =
-        input_assembly;
+      input_assembly;
     g_exlusive_owner_connections[connection_number].config_assembly =
-        config_assembly;
+      config_assembly;
   }
 }
 
@@ -74,10 +103,10 @@ void ConfigureInputOnlyConnectionPoint(const unsigned int connection_number,
                                        const unsigned int config_assembly) {
   if (OPENER_CIP_NUM_INPUT_ONLY_CONNS > connection_number) {
     g_input_only_connections[connection_number].output_assembly =
-        output_assembly;
+      output_assembly;
     g_input_only_connections[connection_number].input_assembly = input_assembly;
     g_input_only_connections[connection_number].config_assembly =
-        config_assembly;
+      config_assembly;
   }
 }
 
@@ -87,21 +116,23 @@ void ConfigureListenOnlyConnectionPoint(const unsigned int connection_number,
                                         const unsigned int config_assembly) {
   if (OPENER_CIP_NUM_LISTEN_ONLY_CONNS > connection_number) {
     g_listen_only_connections[connection_number].output_assembly =
-        output_assembly;
+      output_assembly;
     g_listen_only_connections[connection_number].input_assembly =
-        input_assembly;
+      input_assembly;
     g_listen_only_connections[connection_number].config_assembly =
-        config_assembly;
+      config_assembly;
   }
 }
 
 ConnectionObject *GetIoConnectionForConnectionData(
-    ConnectionObject *const RESTRICT connection_object, EipUint16 *const extended_error) {
-  ConnectionObject *io_connection = NULL;
+  ConnectionObject *const RESTRICT connection_object,
+  EipUint16 *const extended_error) {
+
   *extended_error = 0;
 
-  io_connection = GetExclusiveOwnerConnection(connection_object,
-                                              extended_error);
+  ConnectionObject *io_connection = GetExclusiveOwnerConnection(
+    connection_object,
+    extended_error);
   if (NULL == io_connection) {
     if (0 == *extended_error) {
       /* we found no connection and don't have an error so try input only next */
@@ -111,11 +142,11 @@ ConnectionObject *GetIoConnectionForConnectionData(
           /* we found no connection and don't have an error so try listen only next */
           io_connection = GetListenOnlyConnection(connection_object,
                                                   extended_error);
-          if ((NULL == io_connection) && (0 == *extended_error)) {
+          if ( (NULL == io_connection) && (0 == *extended_error) ) {
             /* no application connection type was found that suits the given data */
             /* TODO check error code VS */
             *extended_error =
-                kConnectionManagerStatusCodeInconsistentApplicationPathCombo;
+              kConnectionManagerExtendedStatusCodeInconsistentApplicationPathCombo;
           } else {
             connection_object->instance_type = kConnectionTypeIoListenOnly;
           }
@@ -136,34 +167,38 @@ ConnectionObject *GetIoConnectionForConnectionData(
 }
 
 ConnectionObject *GetExclusiveOwnerConnection(
-    const ConnectionObject *const RESTRICT connection_object, EipUint16 *const extended_error) {
+  const ConnectionObject *const RESTRICT connection_object,
+  EipUint16 *const extended_error) {
   ConnectionObject *exclusive_owner_connection = NULL;
 
   for (int i = 0; i < OPENER_CIP_NUM_EXLUSIVE_OWNER_CONNS; i++) {
-    if ((g_exlusive_owner_connections[i].output_assembly
-        == connection_object->connection_path.connection_point[0])
-        && (g_exlusive_owner_connections[i].input_assembly
-            == connection_object->connection_path.connection_point[1])
-        && (g_exlusive_owner_connections[i].config_assembly
-            == connection_object->connection_path.connection_point[2])) {
+    if ( (g_exlusive_owner_connections[i].output_assembly
+          == connection_object->connection_path.connection_point[0])
+         && (g_exlusive_owner_connections[i].input_assembly
+             == connection_object->connection_path.connection_point[1])
+         && (g_exlusive_owner_connections[i].config_assembly
+             == connection_object->connection_path.connection_point[2]) ) {
 
       /* check if on other connection point with the same output assembly is currently connected */
-      if (NULL
-          != GetConnectedOutputAssembly(
-              connection_object->connection_path.connection_point[0])) {
-        *extended_error = kConnectionManagerStatusCodeErrorOwnershipConflict;
+      if ( NULL
+           != GetConnectedOutputAssembly(
+             connection_object->connection_path.connection_point[0]) ) {
+        *extended_error =
+          kConnectionManagerExtendedStatusCodeErrorOwnershipConflict;
+        OPENER_TRACE_INFO("Hit an Ownership conflict in appcontype.c");
         break;
       }
       exclusive_owner_connection = &(g_exlusive_owner_connections[i]
-          .connection_data);
+                                     .connection_data);
       break;
     }
   }
   return exclusive_owner_connection;
 }
 
-ConnectionObject *GetInputOnlyConnection(const ConnectionObject *const RESTRICT connection_object,
-                                         EipUint16 *const extended_error) {
+ConnectionObject *GetInputOnlyConnection(
+  const ConnectionObject *const RESTRICT connection_object,
+  EipUint16 *const extended_error) {
   ConnectionObject *input_only_connection = NULL; //TODO: This variable has no use
 
   for (int i = 0; i < OPENER_CIP_NUM_INPUT_ONLY_CONNS; i++) {
@@ -172,13 +207,13 @@ ConnectionObject *GetInputOnlyConnection(const ConnectionObject *const RESTRICT
       if (g_input_only_connections[i].input_assembly
           != connection_object->connection_path.connection_point[1]) {
         *extended_error =
-            kConnectionManagerStatusCodeInvalidProducingApplicationPath;
+          kConnectionManagerExtendedStatusCodeInvalidProducingApplicationPath;
         break;
       }
       if (g_input_only_connections[i].config_assembly
           != connection_object->connection_path.connection_point[2]) {
         *extended_error =
-            kConnectionManagerStatusCodeInconsistentApplicationPathCombo;
+          kConnectionManagerExtendedStatusCodeInconsistentApplicationPathCombo;
         break;
       }
 
@@ -189,23 +224,24 @@ ConnectionObject *GetInputOnlyConnection(const ConnectionObject *const RESTRICT
         }
       }
       *extended_error =
-          kConnectionManagerStatusCodeTargetObjectOutOfConnections;
+        kConnectionManagerExtendedStatusCodeTargetObjectOutOfConnections;
       break;
     }
   }
   return input_only_connection;
 }
 
-ConnectionObject *GetListenOnlyConnection(const ConnectionObject *const RESTRICT connection_object,
-                                          EipUint16 *const extended_error) {
+ConnectionObject *GetListenOnlyConnection(
+  const ConnectionObject *const RESTRICT connection_object,
+  EipUint16 *const extended_error) {
   ConnectionObject *listen_only_connection = NULL; //TODO: This variable has no use
 
-  if (kRoutingTypeMulticastConnection
-      != (connection_object->t_to_o_network_connection_parameter
-          & kRoutingTypeMulticastConnection)) {
+  if ( kForwardOpenConnectionTypeMulticastConnection
+       != (connection_object->t_to_o_network_connection_parameter
+           & kForwardOpenConnectionTypeMulticastConnection) ) {
     /* a listen only connection has to be a multicast connection. */
     *extended_error =
-        kConnectionManagerStatusCodeNonListenOnlyConnectionNotOpened; /* maybe not the best error message however there is no suitable definition in the cip spec */
+      kConnectionManagerExtendedStatusCodeNonListenOnlyConnectionNotOpened;   /* maybe not the best error message however there is no suitable definition in the cip spec */
     return NULL;
   }
 
@@ -215,21 +251,21 @@ ConnectionObject *GetListenOnlyConnection(const ConnectionObject *const RESTRICT
       if (g_listen_only_connections[i].input_assembly
           != connection_object->connection_path.connection_point[1]) {
         *extended_error =
-            kConnectionManagerStatusCodeInvalidProducingApplicationPath;
+          kConnectionManagerExtendedStatusCodeInvalidProducingApplicationPath;
         break;
       }
       if (g_listen_only_connections[i].config_assembly
           != connection_object->connection_path.connection_point[2]) {
         *extended_error =
-            kConnectionManagerStatusCodeInconsistentApplicationPathCombo;
+          kConnectionManagerExtendedStatusCodeInconsistentApplicationPathCombo;
         break;
       }
 
-      if (NULL
-          == GetExistingProducerMulticastConnection(
-              connection_object->connection_path.connection_point[1])) {
+      if ( NULL
+           == GetExistingProducerMulticastConnection(
+             connection_object->connection_path.connection_point[1]) ) {
         *extended_error =
-            kConnectionManagerStatusCodeNonListenOnlyConnectionNotOpened;
+          kConnectionManagerExtendedStatusCodeNonListenOnlyConnectionNotOpened;
         break;
       }
 
@@ -240,29 +276,32 @@ ConnectionObject *GetListenOnlyConnection(const ConnectionObject *const RESTRICT
         }
       }
       *extended_error =
-          kConnectionManagerStatusCodeTargetObjectOutOfConnections;
+        kConnectionManagerExtendedStatusCodeTargetObjectOutOfConnections;
       break;
     }
   }
   return listen_only_connection;
 }
 
-ConnectionObject *GetExistingProducerMulticastConnection(const EipUint32 input_point) {
+ConnectionObject *GetExistingProducerMulticastConnection(
+  const EipUint32 input_point) {
   ConnectionObject *producer_multicast_connection = g_active_connection_list;
 
   while (NULL != producer_multicast_connection) {
-    if ((kConnectionTypeIoExclusiveOwner
-        == producer_multicast_connection->instance_type)
-        || (kConnectionTypeIoInputOnly
-            == producer_multicast_connection->instance_type)) {
-      if ((input_point
-          == producer_multicast_connection->connection_path.connection_point[1])
-          && (kRoutingTypeMulticastConnection
-              == (producer_multicast_connection
-                  ->t_to_o_network_connection_parameter
-                  & kRoutingTypeMulticastConnection))
-          && (kEipInvalidSocket
-              != producer_multicast_connection->socket[kUdpCommuncationDirectionProducing])) {
+    if ( (kConnectionTypeIoExclusiveOwner
+          == producer_multicast_connection->instance_type)
+         || (kConnectionTypeIoInputOnly
+             == producer_multicast_connection->instance_type) ) {
+      if ( (input_point
+            == producer_multicast_connection->connection_path.connection_point[
+              1])
+           && ( kForwardOpenConnectionTypeMulticastConnection
+                == (producer_multicast_connection
+                    ->t_to_o_network_connection_parameter
+                    & kForwardOpenConnectionTypeMulticastConnection) )
+           && (kEipInvalidSocket
+               != producer_multicast_connection->socket[
+                 kUdpCommuncationDirectionProducing]) ) {
         /* we have a connection that produces the same input assembly,
          * is a multicast producer and manages the connection.
          */
@@ -270,29 +309,31 @@ ConnectionObject *GetExistingProducerMulticastConnection(const EipUint32 input_p
       }
     }
     producer_multicast_connection = producer_multicast_connection
-        ->next_connection_object;
+                                    ->next_connection_object;
   }
   return producer_multicast_connection;
 }
 
-ConnectionObject *GetNextNonControlMasterConnection(const EipUint32 input_point) {
+ConnectionObject *GetNextNonControlMasterConnection(const EipUint32 input_point)
+{
   ConnectionObject *next_non_control_master_connection =
-      g_active_connection_list;
+    g_active_connection_list;
 
   while (NULL != next_non_control_master_connection) {
-    if ((kConnectionTypeIoExclusiveOwner
-        == next_non_control_master_connection->instance_type)
-        || (kConnectionTypeIoInputOnly
-            == next_non_control_master_connection->instance_type)) {
-      if ((input_point
-          == next_non_control_master_connection->connection_path
-              .connection_point[1])
-          && (kRoutingTypeMulticastConnection
-              == (next_non_control_master_connection
-                  ->t_to_o_network_connection_parameter
-                  & kRoutingTypeMulticastConnection))
-          && (kEipInvalidSocket
-              == next_non_control_master_connection->socket[kUdpCommuncationDirectionProducing])) {
+    if ( (kConnectionTypeIoExclusiveOwner
+          == next_non_control_master_connection->instance_type)
+         || (kConnectionTypeIoInputOnly
+             == next_non_control_master_connection->instance_type) ) {
+      if ( (input_point
+            == next_non_control_master_connection->connection_path
+            .connection_point[1])
+           && ( kForwardOpenConnectionTypeMulticastConnection
+                == (next_non_control_master_connection
+                    ->t_to_o_network_connection_parameter
+                    & kForwardOpenConnectionTypeMulticastConnection) )
+           && (kEipInvalidSocket
+               == next_non_control_master_connection->socket[
+                 kUdpCommuncationDirectionProducing]) ) {
         /* we have a connection that produces the same input assembly,
          * is a multicast producer and does not manages the connection.
          */
@@ -300,24 +341,25 @@ ConnectionObject *GetNextNonControlMasterConnection(const EipUint32 input_point)
       }
     }
     next_non_control_master_connection = next_non_control_master_connection
-        ->next_connection_object;
+                                         ->next_connection_object;
   }
   return next_non_control_master_connection;
 }
 
 void CloseAllConnectionsForInputWithSameType(const EipUint32 input_point,
-                                             const ConnectionType instance_type) {
+                                             const ConnectionType instance_type)
+{
   ConnectionObject *connection = g_active_connection_list;
 
   while (NULL != connection) {
-    if ((instance_type == connection->instance_type)
-        && (input_point == connection->connection_path.connection_point[1])) {
+    if ( (instance_type == connection->instance_type)
+         && (input_point == connection->connection_path.connection_point[1]) ) {
       ConnectionObject *connection_to_delete = connection;
       connection = connection->next_connection_object;
       CheckIoConnectionEvent(
-          connection_to_delete->connection_path.connection_point[0],
-          connection_to_delete->connection_path.connection_point[1],
-          kIoConnectionEventClosed);
+        connection_to_delete->connection_path.connection_point[0],
+        connection_to_delete->connection_path.connection_point[1],
+        kIoConnectionEventClosed);
 
       assert(connection_to_delete->connection_close_function != NULL);
       connection_to_delete->connection_close_function(connection_to_delete);
@@ -353,10 +395,11 @@ EipBool8 ConnectionWithSameConfigPointExists(const EipUint32 config_point) {
 }
 
 void InitializeIoConnectionData(void) {
-  memset(g_exlusive_owner_connections, 0,
-  OPENER_CIP_NUM_EXLUSIVE_OWNER_CONNS * sizeof(ExclusiveOwnerConnection));
-  memset(g_input_only_connections, 0,
-  OPENER_CIP_NUM_INPUT_ONLY_CONNS * sizeof(InputOnlyConnection));
-  memset(g_listen_only_connections, 0,
-  OPENER_CIP_NUM_LISTEN_ONLY_CONNS * sizeof(ListenOnlyConnection));
+  memset( g_exlusive_owner_connections, 0,
+          OPENER_CIP_NUM_EXLUSIVE_OWNER_CONNS *
+          sizeof(ExclusiveOwnerConnection) );
+  memset( g_input_only_connections, 0,
+          OPENER_CIP_NUM_INPUT_ONLY_CONNS * sizeof(InputOnlyConnection) );
+  memset( g_listen_only_connections, 0,
+          OPENER_CIP_NUM_LISTEN_ONLY_CONNS * sizeof(ListenOnlyConnection) );
 }

+ 4 - 2
source/src/cip/appcontype.h

@@ -24,7 +24,8 @@ void InitializeIoConnectionData(void);
  *        - on error: NULL
  */
 ConnectionObject *GetIoConnectionForConnectionData(
-    ConnectionObject *const RESTRICT connection_object, EipUint16 *const extended_error);
+  ConnectionObject *const RESTRICT connection_object,
+  EipUint16 *const extended_error);
 
 /** @brief Check if there exists already an exclusive owner or listen only connection
  *         which produces the input assembly.
@@ -32,7 +33,8 @@ ConnectionObject *GetIoConnectionForConnectionData(
  *  @param input_point the Input point to be produced
  *  @return if a connection could be found a pointer to this connection if not NULL
  */
-ConnectionObject *GetExistingProducerMulticastConnection(const EipUint32 input_point);
+ConnectionObject *GetExistingProducerMulticastConnection(
+  const EipUint32 input_point);
 
 /** @brief check if there exists an producing multicast exclusive owner or
  * listen only connection that should produce the same input but is not in charge

+ 44 - 35
source/src/cip/cipassembly.c

@@ -1,10 +1,11 @@
 /*******************************************************************************
  * Copyright (c) 2009, Rockwell Automation, Inc.
- * All rights reserved. 
+ * All rights reserved.
  *
  ******************************************************************************/
 
-#include <string.h>    /*needed for memcpy */
+#include <string.h>
+#include <stdbool.h>
 
 #include "cipassembly.h"
 
@@ -18,8 +19,10 @@
  *  Currently only supports Attribute 3 (CIP_BYTE_ARRAY) of an Assembly
  */
 EipStatus SetAssemblyAttributeSingle(
-    CipInstance *const instance, CipMessageRouterRequest *const message_router_request,
-    CipMessageRouterResponse *const message_router_response);
+  CipInstance *const instance,
+  CipMessageRouterRequest *const message_router_request,
+  CipMessageRouterResponse *const message_router_response,
+  struct sockaddr *originator_address);
 
 /** @brief Constructor for the assembly object class
  *
@@ -29,15 +32,15 @@ EipStatus SetAssemblyAttributeSingle(
 CipClass *CreateAssemblyClass(void) {
   /* create the CIP Assembly object with zero instances */
   CipClass *assembly_class = CreateCipClass(kCipAssemblyClassCode, 0, /* # class attributes*/
-                                  0, /* 0 as the assembly object should not have a get_attribute_all service*/
-                                  0, /* # class services*/
-                                  2, /* # instance attributes*/
-                                  0, /* 0 as the assembly object should not have a get_attribute_all service*/
-                                  1, /* # instance services*/
-                                  0, /* # instances*/
-                                  "assembly", /* name */
-                                  2 /* Revision, according to the CIP spec currently this has to be 2 */
-                                  );
+                                            0, /* 0 as the assembly object should not have a get_attribute_all service*/
+                                            0, /* # class services*/
+                                            2, /* # instance attributes*/
+                                            0, /* 0 as the assembly object should not have a get_attribute_all service*/
+                                            1, /* # instance services*/
+                                            0, /* # instances*/
+                                            "assembly", /* name */
+                                            2 /* Revision, according to the CIP spec currently this has to be 2 */
+                                            );
   if (NULL != assembly_class) {
     InsertService(assembly_class, kSetAttributeSingle,
                   &SetAssemblyAttributeSingle, "SetAssemblyAttributeSingle");
@@ -50,7 +53,7 @@ CipClass *CreateAssemblyClass(void) {
  *
  */
 EipStatus CipAssemblyInitialize(void) {
-  return (NULL != CreateAssemblyClass()) ? kEipStatusOk : kEipStatusError;
+  return ( NULL != CreateAssemblyClass() ) ? kEipStatusOk : kEipStatusError;
 }
 
 void ShutdownAssemblies(void) {
@@ -68,18 +71,21 @@ void ShutdownAssemblies(void) {
   }
 }
 
-CipInstance *CreateAssemblyObject(const EipUint32 instance_id, EipByte *const data,
+CipInstance *CreateAssemblyObject(const EipUint32 instance_id,
+                                  EipByte *const data,
                                   const EipUint16 data_length) {
   CipClass *assembly_class = NULL;
-  if (NULL == (assembly_class = GetCipClass(kCipAssemblyClassCode))) {
-    if (NULL == (assembly_class = CreateAssemblyClass())) {
+  if ( NULL == ( assembly_class = GetCipClass(kCipAssemblyClassCode) ) ) {
+    if ( NULL == ( assembly_class = CreateAssemblyClass() ) ) {
       return NULL;
     }
   }
 
   CipInstance *const instance = AddCIPInstance(assembly_class, instance_id); /* add instances (always succeeds (or asserts))*/
 
-  CipByteArray *const assembly_byte_array = (CipByteArray *) CipCalloc(1, sizeof(CipByteArray));
+  CipByteArray *const assembly_byte_array = (CipByteArray *) CipCalloc( 1,
+                                                                        sizeof(
+                                                                          CipByteArray) );
   if (assembly_byte_array == NULL) {
     return NULL; /*TODO remove assembly instance in case of error*/
   }
@@ -100,7 +106,8 @@ EipStatus NotifyAssemblyConnectedDataReceived(CipInstance *const instance,
                                               const EipUint16 data_length) {
   /* empty path (path size = 0) need to be checked and taken care of in future */
   /* copy received data to Attribute 3 */
-  CipByteArray *assembly_byte_array = (CipByteArray *) instance->attributes->data;
+  CipByteArray *assembly_byte_array =
+    (CipByteArray *) instance->attributes->data;
   if (assembly_byte_array->length != data_length) {
     OPENER_TRACE_ERR("wrong amount of data arrived for assembly object\n");
     return kEipStatusError; /*TODO question should we notify the application that wrong data has been received???*/
@@ -113,8 +120,10 @@ EipStatus NotifyAssemblyConnectedDataReceived(CipInstance *const instance,
 }
 
 EipStatus SetAssemblyAttributeSingle(
-    CipInstance *const instance, CipMessageRouterRequest *const message_router_request,
-    CipMessageRouterResponse *const message_router_response) {
+  CipInstance *const instance,
+  CipMessageRouterRequest *const message_router_request,
+  CipMessageRouterResponse *const message_router_response,
+  struct sockaddr *originator_address) {
   OPENER_TRACE_INFO(" setAttribute %d\n",
                     message_router_request->request_path.attribute_number);
 
@@ -122,32 +131,32 @@ EipStatus SetAssemblyAttributeSingle(
 
   message_router_response->data_length = 0;
   message_router_response->reply_service = (0x80
-      | message_router_request->service);
+                                            | message_router_request->service);
   message_router_response->general_status = kCipErrorAttributeNotSupported;
   message_router_response->size_of_additional_status = 0;
 
   CipAttributeStruct *attribute = GetCipAttribute(
-      instance, message_router_request->request_path.attribute_number);
+    instance, message_router_request->request_path.attribute_number);
 
-  if ((attribute != NULL)
-      && (3 == message_router_request->request_path.attribute_number)) {
+  if ( (attribute != NULL)
+       && (3 == message_router_request->request_path.attribute_number) ) {
     if (attribute->data != NULL) {
-      CipByteArray *data = (CipByteArray*) attribute->data;
+      CipByteArray *data = (CipByteArray *) attribute->data;
 
       /* TODO: check for ATTRIBUTE_SET/GETABLE MASK */
-      if (true == IsConnectedOutputAssembly(instance->instance_number)) {
+      if ( true == IsConnectedOutputAssembly(instance->instance_number) ) {
         OPENER_TRACE_WARN(
-            "Assembly AssemblyAttributeSingle: received data for connected output assembly\n\r");
+          "Assembly AssemblyAttributeSingle: received data for connected output assembly\n\r");
         message_router_response->general_status = kCipErrorAttributeNotSetable;
       } else {
-        if (message_router_request->data_length < data->length) {
+        if (message_router_request->request_path_size < data->length) {
           OPENER_TRACE_INFO(
-              "Assembly setAssemblyAttributeSingle: not enough data received.\r\n");
+            "Assembly setAssemblyAttributeSingle: not enough data received.\r\n");
           message_router_response->general_status = kCipErrorNotEnoughData;
         } else {
-          if (message_router_request->data_length > data->length) {
+          if (message_router_request->request_path_size > data->length) {
             OPENER_TRACE_INFO(
-                "Assembly setAssemblyAttributeSingle: too much data received.\r\n");
+              "Assembly setAssemblyAttributeSingle: too much data received.\r\n");
             message_router_response->general_status = kCipErrorTooMuchData;
           } else {
             memcpy(data->data, router_request_data, data->length);
@@ -162,7 +171,7 @@ EipStatus SetAssemblyAttributeSingle(
                * data was not ok.
                */
               message_router_response->general_status =
-                  kCipErrorInvalidAttributeValue;
+                kCipErrorInvalidAttributeValue;
             } else {
               message_router_response->general_status = kCipErrorSuccess;
             }
@@ -175,8 +184,8 @@ EipStatus SetAssemblyAttributeSingle(
     }
   }
 
-  if ((attribute != NULL)
-      && (4 == message_router_request->request_path.attribute_number)) {
+  if ( (attribute != NULL)
+       && (4 == message_router_request->request_path.attribute_number) ) {
     message_router_response->general_status = kCipErrorAttributeNotSetable;
   }
 

+ 7 - 7
source/src/cip/cipassembly.h

@@ -1,6 +1,6 @@
 /*******************************************************************************
  * Copyright (c) 2009, Rockwell Automation, Inc.
- * All rights reserved. 
+ * All rights reserved.
  *
  ******************************************************************************/
 #ifndef OPENER_CIPASSEMBLY_H_
@@ -15,7 +15,7 @@ static const int kCipAssemblyClassCode = 0x04;
 /* public functions */
 
 /** @brief Setup the Assembly object
- * 
+ *
  * Creates the Assembly Class with zero instances and sets up all services.
  *
  * @return Returns kEipStatusOk if assembly object was successfully created, otherwise kEipStatusError
@@ -32,16 +32,16 @@ EipStatus CipAssemblyInitialize(void);
 void ShutdownAssemblies(void);
 
 /** @brief notify an Assembly object that data has been received for it.
- * 
+ *
  *  The data will be copied into the assembly objects attribute 3 and
  *  the application will be informed with the IApp_after_assembly_data_received function.
- *  
+ *
  *  @param instance the assembly object instance for which the data was received
  *  @param data pointer to the data received
  *  @param data_length number of bytes received
- *  @return 
- *     - EIP_OK the received data was okay
- *     - EIP_ERROR the received data was wrong
+ *  @return
+ *     - kEipStatusOk the received data was okay
+ *     - kEipStatusError the received data was wrong
  */
 EipStatus NotifyAssemblyConnectedDataReceived(CipInstance *const instance,
                                               const EipUint8 *const data,

+ 15 - 11
source/src/cip/cipclass3connection.c

@@ -16,8 +16,9 @@ ConnectionObject *GetFreeExplicitConnection(void);
 ConnectionObject g_explicit_connections[OPENER_CIP_NUM_EXPLICIT_CONNS];
 
 /**** Implementation ****/
-EipStatus EstablishClass3Connection(ConnectionObject *RESTRICT const connection_object,
-                              EipUint16 *const extended_error) {
+EipStatus EstablishClass3Connection(
+  ConnectionObject *RESTRICT const connection_object,
+  EipUint16 *const extended_error) {
   EipStatus eip_status = kEipStatusOk;
 
   /*TODO add check for transport type trigger */
@@ -28,22 +29,24 @@ EipStatus EstablishClass3Connection(ConnectionObject *RESTRICT const connection_
   if (NULL == explicit_connection) {
     eip_status = kCipErrorConnectionFailure;
     *extended_error =
-        kConnectionManagerStatusCodeErrorNoMoreConnectionsAvailable;
+      kConnectionManagerExtendedStatusCodeErrorNoMoreConnectionsAvailable;
   } else {
     CopyConnectionData(explicit_connection, connection_object);
 
-    EipUint32 produced_connection_id_buffer = explicit_connection->produced_connection_id;
+    EipUint32 produced_connection_id_buffer =
+      explicit_connection->cip_produced_connection_id;
     GeneralConnectionConfiguration(explicit_connection);
-    explicit_connection->produced_connection_id = produced_connection_id_buffer;
+    explicit_connection->cip_produced_connection_id =
+      produced_connection_id_buffer;
     explicit_connection->instance_type = kConnectionTypeExplicit;
     explicit_connection->socket[0] = explicit_connection->socket[1] =
-        kEipInvalidSocket;
+                                       kEipInvalidSocket;
     /* set the connection call backs */
     explicit_connection->connection_close_function =
-        RemoveFromActiveConnections;
+      RemoveFromActiveConnections;
     /* explicit connection have to be closed on time out*/
     explicit_connection->connection_timeout_function =
-        RemoveFromActiveConnections;
+      RemoveFromActiveConnections;
 
     AddNewActiveConnection(explicit_connection);
   }
@@ -56,13 +59,14 @@ EipStatus EstablishClass3Connection(ConnectionObject *RESTRICT const connection_
  */
 ConnectionObject *GetFreeExplicitConnection(void) {
   for (int i = 0; i < OPENER_CIP_NUM_EXPLICIT_CONNS; i++) {
-    if (g_explicit_connections[i].state == kConnectionStateNonExistent)
+    if (g_explicit_connections[i].state == kConnectionStateNonExistent) {
       return &(g_explicit_connections[i]);
+    }
   }
   return NULL;
 }
 
 void InitializeClass3ConnectionData(void) {
-  memset(g_explicit_connections, 0,
-  OPENER_CIP_NUM_EXPLICIT_CONNS * sizeof(ConnectionObject));
+  memset( g_explicit_connections, 0,
+          OPENER_CIP_NUM_EXPLICIT_CONNS * sizeof(ConnectionObject) );
 }

+ 3 - 2
source/src/cip/cipclass3connection.h

@@ -23,8 +23,9 @@
  *    - kEipStatusOk ... on success
  *    - On an error the general status code to be put into the response
  */
-EipStatus EstablishClass3Connection(ConnectionObject *RESTRICT const connection_object,
-                              EipUint16 *const extended_error);
+EipStatus EstablishClass3Connection(
+  ConnectionObject *RESTRICT const connection_object,
+  EipUint16 *const extended_error);
 
 /** @brief Initializes the explicit connections mechanism
  *

+ 142 - 103
source/src/cip/cipcommon.c

@@ -1,6 +1,6 @@
 /*******************************************************************************
  * Copyright (c) 2009, Rockwell Automation, Inc.
- * All rights reserved. 
+ * All rights reserved.
  *
  ******************************************************************************/
 #include <string.h>
@@ -21,6 +21,7 @@
 #include "cpf.h"
 #include "trace.h"
 #include "appcontype.h"
+#include "cipepath.h"
 
 /* global public variables */
 EipUint8 g_message_data_reply_buffer[OPENER_MESSAGE_DATA_REPLY_BUFFER]; /**< Reply buffer */
@@ -48,7 +49,7 @@ void CipStackInit(const EipUint16 unique_connection_id) {
   /* the application has to be initialized at last */
   eip_status = ApplicationInitialization();
   OPENER_ASSERT(kEipStatusOk == eip_status);
-  
+
   /* Shut up compiler warning with traces disabled */
   (void)eip_status;
 }
@@ -69,11 +70,13 @@ void ShutdownCipStack(void) {
 
 EipStatus NotifyClass(const CipClass *RESTRICT const cip_class,
                       CipMessageRouterRequest *const message_router_request,
-                      CipMessageRouterResponse *const message_router_response) {
+                      CipMessageRouterResponse *const message_router_response,
+                      struct sockaddr *originator_address) {
 
   /* find the instance: if instNr==0, the class is addressed, else find the instance */
-  EipUint16 instance_number = message_router_request->request_path.instance_number; /* get the instance number */
-  CipInstance * instance = GetCipInstance(cip_class, instance_number); /* look up the instance (note that if inst==0 this will be the class itself) */
+  EipUint16 instance_number =
+    message_router_request->request_path.instance_number;                           /* get the instance number */
+  CipInstance *instance = GetCipInstance(cip_class, instance_number);  /* look up the instance (note that if inst==0 this will be the class itself) */
   if (instance) /* if instance is found */
   {
     OPENER_TRACE_INFO("notify: found instance %d%s\n", instance_number,
@@ -89,8 +92,10 @@ EipStatus NotifyClass(const CipClass *RESTRICT const cip_class,
           /* call the service, and return what it returns */
           OPENER_TRACE_INFO("notify: calling %s service\n", service->name);
           OPENER_ASSERT(NULL != service->service_function);
-          return service->service_function(instance, message_router_request,
-                                           message_router_response);
+          return service->service_function(instance,
+                                           message_router_request,
+                                           message_router_response,
+                                           originator_address);
         } else {
           service++;
         }
@@ -109,12 +114,13 @@ EipStatus NotifyClass(const CipClass *RESTRICT const cip_class,
   message_router_response->size_of_additional_status = 0; /* fill in the rest of the reply with not much of anything*/
   message_router_response->data_length = 0;
   message_router_response->reply_service = (0x80
-      | message_router_request->service); /* except the reply code is an echo of the command + the reply flag */
+                                            | message_router_request->service); /* except the reply code is an echo of the command + the reply flag */
 
   return kEipStatusOkSend;
 }
 
-CipInstance *AddCipInstances(CipClass *RESTRICT const cip_class, const int number_of_instances) {
+CipInstance *AddCipInstances(CipClass *RESTRICT const cip_class,
+                             const int number_of_instances) {
   CipInstance **next_instance = NULL;
   EipUint32 instance_number = 1; /* the first instance is number 1 */
 
@@ -129,7 +135,7 @@ CipInstance *AddCipInstances(CipClass *RESTRICT const cip_class, const int numbe
   }
 
   CipInstance *current_instance = current_instance = (CipInstance *) CipCalloc(
-        number_of_instances, sizeof(CipInstance)); /* allocate a block of memory for all created instances*/
+                                    number_of_instances, sizeof(CipInstance) ); /* allocate a block of memory for all created instances*/
   CipInstance *first_instance = current_instance; /* allocate a block of memory for all created instances*/
 
   OPENER_ASSERT(NULL != current_instance);
@@ -146,8 +152,8 @@ CipInstance *AddCipInstances(CipClass *RESTRICT const cip_class, const int numbe
 
     if (cip_class->number_of_attributes) /* if the class calls for instance attributes */
     { /* then allocate storage for the attribute array */
-      current_instance->attributes = (CipAttributeStruct*) CipCalloc(
-          cip_class->number_of_attributes, sizeof(CipAttributeStruct));
+      current_instance->attributes = (CipAttributeStruct *) CipCalloc(
+        cip_class->number_of_attributes, sizeof(CipAttributeStruct) );
     }
 
     next_instance = &current_instance->next; /* update pp to point to the next link of the current node */
@@ -158,7 +164,8 @@ CipInstance *AddCipInstances(CipClass *RESTRICT const cip_class, const int numbe
   return first_instance;
 }
 
-CipInstance *AddCIPInstance(CipClass *RESTRICT const class, const EipUint32 instance_id) {
+CipInstance *AddCIPInstance(CipClass *RESTRICT const class,
+                            const EipUint32 instance_id) {
   CipInstance *instance = GetCipInstance(class, instance_id);
 
   if (0 == instance) { /*we have no instance with given id*/
@@ -168,29 +175,31 @@ CipInstance *AddCIPInstance(CipClass *RESTRICT const class, const EipUint32 inst
   return instance;
 }
 
-CipClass *CreateCipClass(const EipUint32 class_id, const int number_of_class_attributes,
+CipClass *CreateCipClass(const EipUint32 class_id,
+                         const int number_of_class_attributes,
                          const EipUint32 get_all_class_attributes_mask,
                          const int number_of_class_services,
                          const int number_of_instance_attributes,
                          const EipUint32 get_all_instance_attributes_mask,
                          const int number_of_instance_services,
-                         const int number_of_instances, char *name,
+                         const int number_of_instances,
+                         char *name,
                          const EipUint16 revision) {
 
-  OPENER_TRACE_INFO("creating class '%s' with id: 0x%"PRIX32"\n", name,
+  OPENER_TRACE_INFO("creating class '%s' with id: 0x%" PRIX32 "\n", name,
                     class_id);
 
-  OPENER_ASSERT(NULL == GetCipClass(class_id)); /* check if an class with the ClassID already exists */
+  OPENER_ASSERT( NULL == GetCipClass(class_id) ); /* check if an class with the ClassID already exists */
   /* should never try to redefine a class*/
 
   /* a metaClass is a class that holds the class attributes and services
-   CIP can talk to an instance, therefore an instance has a pointer to its class
-   CIP can talk to a class, therefore a class struct is a subclass of the instance struct,
-   and contains a pointer to a metaclass
-   CIP never explicitly addresses a metaclass*/
+     CIP can talk to an instance, therefore an instance has a pointer to its class
+     CIP can talk to a class, therefore a class struct is a subclass of the instance struct,
+     and contains a pointer to a metaclass
+     CIP never explicitly addresses a metaclass*/
 
-  CipClass *const class = (CipClass*) CipCalloc(1, sizeof(CipClass)); /* create the class object*/
-  CipClass *const meta_class = (CipClass*) CipCalloc(1, sizeof(CipClass)); /* create the metaclass object*/
+  CipClass *const class = (CipClass *) CipCalloc( 1, sizeof(CipClass) ); /* create the class object*/
+  CipClass *const meta_class = (CipClass *) CipCalloc( 1, sizeof(CipClass) ); /* create the metaclass object*/
 
   /* initialize the class-specific fields of the Class struct*/
   class->class_id = class_id; /* the class remembers the class ID */
@@ -200,7 +209,8 @@ CipClass *CreateCipClass(const EipUint32 class_id, const int number_of_class_att
   class->number_of_attributes = number_of_instance_attributes; /* the class remembers the number of instances of that class */
   class->get_attribute_all_mask = get_all_instance_attributes_mask; /* indicate which attributes are included in instance getAttributeAll */
   class->number_of_services = number_of_instance_services
-      + ((0 == get_all_instance_attributes_mask) ? 1 : 2); /* the class manages the behavior of the instances */
+                              + ( (0 ==
+                                   get_all_instance_attributes_mask) ? 1 : 2 ); /* the class manages the behavior of the instances */
   class->services = 0;
   class->class_name = name; /* initialize the class-specific fields of the metaClass struct */
   meta_class->class_id = 0xffffffff; /* set metaclass ID (this should never be referenced) */
@@ -209,7 +219,8 @@ CipClass *CreateCipClass(const EipUint32 class_id, const int number_of_class_att
   meta_class->number_of_attributes = number_of_class_attributes + 7; /* the metaclass remembers how many class attributes exist*/
   meta_class->get_attribute_all_mask = get_all_class_attributes_mask; /* indicate which attributes are included in class getAttributeAll*/
   meta_class->number_of_services = number_of_class_services
-      + ((0 == get_all_class_attributes_mask) ? 1 : 2); /* the metaclass manages the behavior of the class itself */
+                                   + ( (0 ==
+                                        get_all_class_attributes_mask) ? 1 : 2 ); /* the metaclass manages the behavior of the class itself */
   class->services = 0;
   meta_class->class_name = (char *) CipCalloc(1, strlen(name) + 6); /* fabricate the name "meta<classname>"*/
   strcpy(meta_class->class_name, "meta-");
@@ -229,40 +240,41 @@ CipClass *CreateCipClass(const EipUint32 class_id, const int number_of_class_att
   /* further initialization of the class object*/
 
   class->class_instance.attributes = (CipAttributeStruct *) CipCalloc(
-      meta_class->number_of_attributes, sizeof(CipAttributeStruct));
+    meta_class->number_of_attributes, sizeof(CipAttributeStruct) );
   /* TODO -- check that we didn't run out of memory?*/
 
   meta_class->services = (CipServiceStruct *) CipCalloc(
-      meta_class->number_of_services, sizeof(CipServiceStruct));
+    meta_class->number_of_services, sizeof(CipServiceStruct) );
 
-  class->services = (CipServiceStruct *) CipCalloc(class->number_of_services,
-                                                   sizeof(CipServiceStruct));
+  class->services = (CipServiceStruct *) CipCalloc( class->number_of_services,
+                                                    sizeof(CipServiceStruct) );
 
   if (number_of_instances > 0) {
     AddCipInstances(class, number_of_instances); /*TODO handle return value and clean up if necessary*/
   }
 
-  if ((RegisterCipClass(class)) == kEipStatusError) { /* no memory to register class in Message Router */
+  if ( ( RegisterCipClass(class) ) == kEipStatusError ) { /* no memory to register class in Message Router */
     return 0; /*TODO handle return value and clean up if necessary*/
   }
 
   /* create the standard class attributes*/
-  InsertAttribute((CipInstance *) class, 1, kCipUint, (void *) &class->revision,
-                  kGetableSingleAndAll); /* revision */
-  InsertAttribute((CipInstance *) class, 2, kCipUint,
-                  (void *) &class->number_of_instances, kGetableSingleAndAll); /*  largest instance number */
-  InsertAttribute((CipInstance *) class, 3, kCipUint,
-                  (void *) &class->number_of_instances, kGetableSingleAndAll); /* number of instances currently existing*/
-  InsertAttribute((CipInstance *) class, 4, kCipUint, (void *) &kCipUintZero,
-                  kGetableAll); /* optional attribute list - default = 0 */
-  InsertAttribute((CipInstance *) class, 5, kCipUint, (void *) &kCipUintZero,
-                  kGetableAll); /* optional service list - default = 0 */
-  InsertAttribute((CipInstance *) class, 6, kCipUint,
-                  (void *) &meta_class->highest_attribute_number,
-                  kGetableSingleAndAll); /* max class attribute number*/
-  InsertAttribute((CipInstance *) class, 7, kCipUint,
-                  (void *) &class->highest_attribute_number,
-                  kGetableSingleAndAll); /* max instance attribute number*/
+  InsertAttribute( (CipInstance *) class, 1, kCipUint,
+                   (void *) &class->revision,
+                   kGetableSingleAndAll ); /* revision */
+  InsertAttribute( (CipInstance *) class, 2, kCipUint,
+                   (void *) &class->number_of_instances, kGetableSingleAndAll ); /*  largest instance number */
+  InsertAttribute( (CipInstance *) class, 3, kCipUint,
+                   (void *) &class->number_of_instances, kGetableSingleAndAll ); /* number of instances currently existing*/
+  InsertAttribute( (CipInstance *) class, 4, kCipUint, (void *) &kCipUintZero,
+                   kGetableAll ); /* optional attribute list - default = 0 */
+  InsertAttribute( (CipInstance *) class, 5, kCipUint, (void *) &kCipUintZero,
+                   kGetableAll ); /* optional service list - default = 0 */
+  InsertAttribute( (CipInstance *) class, 6, kCipUint,
+                   (void *) &meta_class->highest_attribute_number,
+                   kGetableSingleAndAll ); /* max class attribute number*/
+  InsertAttribute( (CipInstance *) class, 7, kCipUint,
+                   (void *) &class->highest_attribute_number,
+                   kGetableSingleAndAll ); /* max instance attribute number*/
 
   /* create the standard class services*/
   if (0 != get_all_class_attributes_mask) { /*only if the mask has values add the get_attribute_all service */
@@ -282,8 +294,11 @@ CipClass *CreateCipClass(const EipUint32 class_id, const int number_of_class_att
   return class;
 }
 
-void InsertAttribute(CipInstance *const instance, const EipUint16 attribute_number,
-                     const EipUint8 cip_type, void *const data, const EipByte cip_flags) {
+void InsertAttribute(CipInstance *const instance,
+                     const EipUint16 attribute_number,
+                     const EipUint8 cip_type,
+                     void *const data,
+                     const EipByte cip_flags) {
 
   CipAttributeStruct *attribute = instance->attributes;
   OPENER_ASSERT(NULL != attribute);
@@ -305,22 +320,25 @@ void InsertAttribute(CipInstance *const instance, const EipUint16 attribute_numb
   }
 
   OPENER_TRACE_ERR(
-      "Tried to insert to many attributes into class: %"PRIu32", instance %"PRIu32"\n",
-      instance->cip_class->class_instance.instance_number,
-      instance->instance_number);
+    "Tried to insert to many attributes into class: %" PRIu32 ", instance %" PRIu32 "\n",
+    instance->cip_class->class_instance.instance_number,
+    instance->instance_number);
   OPENER_ASSERT(0);
   /* trying to insert too many attributes*/
 }
 
-void InsertService(const CipClass *const class, const EipUint8 service_number,
-                   const CipServiceFunction service_function, char *const service_name) {
+void InsertService(const CipClass *const class,
+                   const EipUint8 service_number,
+                   const CipServiceFunction service_function,
+                   char *const service_name) {
 
   CipServiceStruct *service = class->services; /* get a pointer to the service array*/
   OPENER_ASSERT(service != 0);
   /* adding a service to a class that was not declared to have services is not allowed*/
   for (int i = 0; i < class->number_of_services; i++) /* Iterate over all service slots attached to the class */
   {
-    if (service->service_number == service_number || service->service_function == NULL) /* found undefined service slot*/
+    if (service->service_number == service_number ||
+        service->service_function == NULL)                                              /* found undefined service slot*/
     {
       service->service_number = service_number; /* fill in service number*/
       service->service_function = service_function; /* fill in function address*/
@@ -338,10 +356,12 @@ CipAttributeStruct *GetCipAttribute(const CipInstance *const instance,
 
   CipAttributeStruct *attribute = instance->attributes; /* init pointer to array of attributes*/
   for (int i = 0; i < instance->cip_class->number_of_attributes; i++) {
-    if (attribute_number == attribute->attribute_number)
+    if (attribute_number == attribute->attribute_number) {
       return attribute;
-    else
+    }
+    else{
       ++attribute;
+    }
   }
 
   OPENER_TRACE_WARN("attribute %d not defined\n", attribute_number);
@@ -352,17 +372,18 @@ CipAttributeStruct *GetCipAttribute(const CipInstance *const instance,
 /* TODO this needs to check for buffer overflow*/
 EipStatus GetAttributeSingle(CipInstance *RESTRICT const instance,
                              CipMessageRouterRequest *const message_router_request,
-                             CipMessageRouterResponse *const message_router_response) {
+                             CipMessageRouterResponse *const message_router_response,
+                             struct sockaddr *originator_address) {
   /* Mask for filtering get-ability */
   EipByte get_mask = kNotSetOrGetable;
 
   CipAttributeStruct *attribute = GetCipAttribute(
-      instance, message_router_request->request_path.attribute_number);
+    instance, message_router_request->request_path.attribute_number);
   EipByte *message = message_router_response->data;
 
   message_router_response->data_length = 0;
   message_router_response->reply_service = (0x80
-      | message_router_request->service);
+                                            | message_router_request->service);
   message_router_response->general_status = kCipErrorAttributeNotSupported;
   message_router_response->size_of_additional_status = 0;
 
@@ -374,7 +395,7 @@ EipStatus GetAttributeSingle(CipInstance *RESTRICT const instance,
     get_mask = kGetableSingle;
   }
 
-  if ((attribute != 0) && (attribute->data != 0)) {
+  if ( (attribute != 0) && (attribute->data != 0) ) {
     if (attribute->attribute_flags & get_mask) {
       OPENER_TRACE_INFO("getAttribute %d\n",
                         message_router_request->request_path.attribute_number); /* create a reply message containing the data*/
@@ -401,7 +422,9 @@ EipStatus GetAttributeSingle(CipInstance *RESTRICT const instance,
   return kEipStatusOkSend;
 }
 
-int EncodeData(const EipUint8 cip_type, const void *const cip_data, EipUint8 **cip_message) {
+int EncodeData(const EipUint8 cip_type,
+               const void *const cip_data,
+               EipUint8 **cip_message) {
   int counter = 0;
 
   switch (cip_type)
@@ -481,7 +504,7 @@ int EncodeData(const EipUint8 cip_type, const void *const cip_data, EipUint8 **c
       break;
 
     case (kCipEpath):
-      counter = EncodeEPath((CipEpath *) cip_data, cip_message);
+      counter = EncodeEPath( (CipEpath *) cip_data, cip_message );
       break;
 
     case (kCipEngUnit):
@@ -500,22 +523,26 @@ int EncodeData(const EipUint8 cip_type, const void *const cip_data, EipUint8 **c
 
     case (kCipUdintUdintUdintUdintUdintString): {
       /* TCP/IP attribute 5 */
-      CipTcpIpNetworkInterfaceConfiguration *tcp_ip_network_interface_configuration =
-          (CipTcpIpNetworkInterfaceConfiguration *) cip_data;
+      CipTcpIpNetworkInterfaceConfiguration *
+        tcp_ip_network_interface_configuration =
+        (CipTcpIpNetworkInterfaceConfiguration *) cip_data;
       counter += AddDintToMessage(
-          ntohl(tcp_ip_network_interface_configuration->ip_address), cip_message);
+        ntohl(tcp_ip_network_interface_configuration->ip_address), cip_message);
       counter += AddDintToMessage(
-          ntohl(tcp_ip_network_interface_configuration->network_mask), cip_message);
-      counter += AddDintToMessage(ntohl(tcp_ip_network_interface_configuration->gateway),
-                       cip_message);
+        ntohl(tcp_ip_network_interface_configuration->network_mask),
+        cip_message);
+      counter +=
+        AddDintToMessage(ntohl(tcp_ip_network_interface_configuration->gateway),
+                         cip_message);
       counter += AddDintToMessage(
-          ntohl(tcp_ip_network_interface_configuration->name_server), cip_message);
+        ntohl(tcp_ip_network_interface_configuration->name_server),
+        cip_message);
       counter += AddDintToMessage(
-          ntohl(tcp_ip_network_interface_configuration->name_server_2),
-          cip_message);
+        ntohl(tcp_ip_network_interface_configuration->name_server_2),
+        cip_message);
       counter += EncodeData(
-          kCipString, &(tcp_ip_network_interface_configuration->domain_name),
-          cip_message);
+        kCipString, &(tcp_ip_network_interface_configuration->domain_name),
+        cip_message);
       break;
     }
 
@@ -536,7 +563,7 @@ int EncodeData(const EipUint8 cip_type, const void *const cip_data, EipUint8 **c
       *cip_message += cip_byte_array->length;
       counter = cip_byte_array->length;
     }
-      break;
+    break;
 
     case (kInternalUint6): /* TODO for port class attribute 9, hopefully we can find a better way to do this*/
     {
@@ -559,7 +586,9 @@ int EncodeData(const EipUint8 cip_type, const void *const cip_data, EipUint8 **c
   return counter;
 }
 
-int DecodeData(const EipUint8 cip_type, void *const data, const EipUint8 **const message) {
+int DecodeData(const EipUint8 cip_type,
+               void *const data,
+               const EipUint8 **const message) {
   int number_of_decoded_bytes = -1;
 
   switch (cip_type)
@@ -577,14 +606,14 @@ int DecodeData(const EipUint8 cip_type, void *const data, const EipUint8 **const
     case (kCipInt):
     case (kCipUint):
     case (kCipWord):
-      (*(EipUint16 *) (data)) = GetIntFromMessage(message);
+      ( *(EipUint16 *) (data) ) = GetIntFromMessage(message);
       number_of_decoded_bytes = 2;
       break;
 
     case (kCipDint):
     case (kCipUdint):
     case (kCipDword):
-      (*(EipUint32 *) (data)) = GetDintFromMessage(message);
+      ( *(EipUint32 *) (data) ) = GetDintFromMessage(message);
       number_of_decoded_bytes = 4;
       break;
 
@@ -592,10 +621,10 @@ int DecodeData(const EipUint8 cip_type, void *const data, const EipUint8 **const
     case (kCipLint):
     case (kCipUlint):
     case (kCipLword): {
-      (*(EipUint64 *) (data)) = GetLintFromMessage(message);
+      ( *(EipUint64 *) (data) ) = GetLintFromMessage(message);
       number_of_decoded_bytes = 8;
     }
-      break;
+    break;
 #endif
 
     case (kCipString): {
@@ -611,7 +640,7 @@ int DecodeData(const EipUint8 cip_type, void *const data, const EipUint8 **const
         number_of_decoded_bytes++;
       }
     }
-      break;
+    break;
     case (kCipShortString): {
       CipShortString *short_string = (CipShortString *) data;
 
@@ -634,7 +663,8 @@ int DecodeData(const EipUint8 cip_type, void *const data, const EipUint8 **const
 
 EipStatus GetAttributeAll(CipInstance *instance,
                           CipMessageRouterRequest *message_router_request,
-                          CipMessageRouterResponse *message_router_response) {
+                          CipMessageRouterResponse *message_router_response,
+                          struct sockaddr *originator_address) {
 
   EipUint8 *reply = message_router_response->data; /* pointer into the reply */
   CipAttributeStruct *attribute = instance->attributes; /* pointer to list of attributes*/
@@ -651,30 +681,32 @@ EipStatus GetAttributeAll(CipInstance *instance,
       if (0 == instance->cip_class->number_of_attributes) {
         message_router_response->data_length = 0; /*there are no attributes to be sent back*/
         message_router_response->reply_service = (0x80
-            | message_router_request->service);
+                                                  | message_router_request->
+                                                  service);
         message_router_response->general_status = kCipErrorServiceNotSupported;
         message_router_response->size_of_additional_status = 0;
       } else {
         for (int j = 0; j < instance->cip_class->number_of_attributes; j++) /* for each instance attribute of this class */
         {
           int attrNum = attribute->attribute_number;
-          if (attrNum < 32
-              && (instance->cip_class->get_attribute_all_mask & 1 << attrNum)) /* only return attributes that are flagged as being part of GetAttributeALl */
-              {
+          if ( attrNum < 32
+               && (instance->cip_class->get_attribute_all_mask & 1 << attrNum) ) /* only return attributes that are flagged as being part of GetAttributeALl */
+          {
             message_router_request->request_path.attribute_number = attrNum;
-            if (kEipStatusOkSend
-                != service->service_function(instance, message_router_request,
-                                             message_router_response)) {
+            if ( kEipStatusOkSend
+                 != service->service_function(instance, message_router_request,
+                                              message_router_response,
+                                              originator_address) ) {
               message_router_response->data = reply;
               return kEipStatusError;
             }
             message_router_response->data += message_router_response
-                ->data_length;
+                                             ->data_length;
           }
           attribute++;
         }
         message_router_response->data_length = message_router_response->data
-            - reply;
+                                               - reply;
         message_router_response->data = reply;
       }
       return kEipStatusOkSend;
@@ -752,44 +784,51 @@ int DecodePaddedEPath(CipEpath *epath, const EipUint8 **message) {
   epath->attribute_number = 0;
 
   for (number_of_decoded_elements = 0;
-      number_of_decoded_elements < epath->path_size;
-      number_of_decoded_elements++) {
-    if (kSegmentTypeSegmentTypeReserved == ((*message_runner) & kSegmentTypeSegmentTypeReserved)) {
+       number_of_decoded_elements < epath->path_size;
+       number_of_decoded_elements++) {
+    if ( kSegmentTypeReserved ==
+         ( (*message_runner) & kSegmentTypeReserved ) ) {
       /* If invalid/reserved segment type, segment type greater than 0xE0 */
       return kEipStatusError;
     }
 
     switch (*message_runner) {
-      case kSegmentTypeLogicalSegment + kLogicalSegmentLogicalTypeClassId + kLogicalSegmentLogicalFormatEightBitValue:
+      case SEGMENT_TYPE_LOGICAL_SEGMENT + LOGICAL_SEGMENT_TYPE_CLASS_ID +
+        LOGICAL_SEGMENT_FORMAT_EIGHT_BIT:
         epath->class_id = *(EipUint8 *) (message_runner + 1);
         message_runner += 2;
         break;
 
-      case kSegmentTypeLogicalSegment + kLogicalSegmentLogicalTypeClassId + kLogicalSegmentLogicalFormatSixteenBitValue:
+      case SEGMENT_TYPE_LOGICAL_SEGMENT + LOGICAL_SEGMENT_TYPE_CLASS_ID +
+        LOGICAL_SEGMENT_FORMAT_SIXTEEN_BIT:
         message_runner += 2;
-        epath->class_id = GetIntFromMessage(&(message_runner));
+        epath->class_id = GetIntFromMessage( &(message_runner) );
         number_of_decoded_elements++;
         break;
 
-      case kSegmentTypeLogicalSegment + kLogicalSegmentLogicalTypeInstanceId + kLogicalSegmentLogicalFormatEightBitValue:
+      case SEGMENT_TYPE_LOGICAL_SEGMENT + LOGICAL_SEGMENT_TYPE_INSTANCE_ID +
+        LOGICAL_SEGMENT_FORMAT_EIGHT_BIT:
         epath->instance_number = *(EipUint8 *) (message_runner + 1);
         message_runner += 2;
         break;
 
-      case kSegmentTypeLogicalSegment + kLogicalSegmentLogicalTypeInstanceId + kLogicalSegmentLogicalFormatSixteenBitValue:
+      case SEGMENT_TYPE_LOGICAL_SEGMENT + LOGICAL_SEGMENT_TYPE_INSTANCE_ID +
+        LOGICAL_SEGMENT_FORMAT_SIXTEEN_BIT:
         message_runner += 2;
-        epath->instance_number = GetIntFromMessage(&(message_runner));
+        epath->instance_number = GetIntFromMessage( &(message_runner) );
         number_of_decoded_elements++;
         break;
 
-      case kSegmentTypeLogicalSegment + kLogicalSegmentLogicalTypeAttributeId + kLogicalSegmentLogicalFormatEightBitValue:
+      case SEGMENT_TYPE_LOGICAL_SEGMENT + LOGICAL_SEGMENT_TYPE_ATTRIBUTE_ID +
+        LOGICAL_SEGMENT_FORMAT_EIGHT_BIT:
         epath->attribute_number = *(EipUint8 *) (message_runner + 1);
         message_runner += 2;
         break;
 
-      case kSegmentTypeLogicalSegment + kLogicalSegmentLogicalTypeAttributeId + kLogicalSegmentLogicalFormatSixteenBitValue:
+      case SEGMENT_TYPE_LOGICAL_SEGMENT + LOGICAL_SEGMENT_TYPE_ATTRIBUTE_ID +
+        LOGICAL_SEGMENT_FORMAT_SIXTEEN_BIT:
         message_runner += 2;
-        epath->attribute_number = GetIntFromMessage(&(message_runner));
+        epath->attribute_number = GetIntFromMessage( &(message_runner) );
         number_of_decoded_elements++;
         break;
 
@@ -801,5 +840,5 @@ int DecodePaddedEPath(CipEpath *epath, const EipUint8 **message) {
   }
 
   *message = message_runner;
-  return number_of_decoded_elements * 2 + 1; /* i times 2 as every encoding uses 2 bytes */
+  return number_of_decoded_elements * 2 + 1; /* number_of_decoded_elements times 2 as every encoding uses 2 bytes */
 }

+ 7 - 4
source/src/cip/cipcommon.h

@@ -1,6 +1,6 @@
 /*******************************************************************************
  * Copyright (c) 2009, Rockwell Automation, Inc.
- * All rights reserved. 
+ * All rights reserved.
  *
  ******************************************************************************/
 #ifndef OPENER_CIPCOMMON_H_
@@ -33,7 +33,8 @@ extern EipUint8 g_message_data_reply_buffer[];
  */
 EipStatus NotifyClass(const CipClass *RESTRICT const class,
                       CipMessageRouterRequest *const message_router_request,
-                      CipMessageRouterResponse *const message_router_response);
+                      CipMessageRouterResponse *const message_router_response,
+                      struct sockaddr *originator_address);
 
 /** @brief Generic implementation of the GetAttributeSingle CIP service
  *
@@ -47,7 +48,8 @@ EipStatus NotifyClass(const CipClass *RESTRICT const class,
  */
 EipStatus GetAttributeSingle(CipInstance *RESTRICT const instance,
                              CipMessageRouterRequest *const message_router_request,
-                             CipMessageRouterResponse *const message_router_response);
+                             CipMessageRouterResponse *const message_router_response,
+                             struct sockaddr *originator_address);
 
 /** @brief Generic implementation of the GetAttributeAll CIP service
  *
@@ -60,7 +62,8 @@ EipStatus GetAttributeSingle(CipInstance *RESTRICT const instance,
  */
 EipStatus GetAttributeAll(CipInstance *instance,
                           CipMessageRouterRequest *message_router_request,
-                          CipMessageRouterResponse *message_router_response);
+                          CipMessageRouterResponse *message_router_response,
+                          struct sockaddr *originator_address);
 
 /** @brief Decodes padded EPath
  *  @param epath EPath to the receiving element

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 516 - 247
source/src/cip/cipconnectionmanager.c


+ 193 - 72
source/src/cip/cipconnectionmanager.h

@@ -12,39 +12,128 @@
 #include "ciptypes.h"
 
 /**
- * @brief Sets the routing type of a connection, either
- * - Point-to-point connections (unicast)
- * - Multicast connection
+ * @brief Connection Type constants of the Forward Open service request
+ *   Indicates either a
+ * - Null Request
+ * - Point-to-point connection request (unicast)
+ * - Multicast connection request
  */
 typedef enum {
-  kRoutingTypePointToPointConnection = 0x4000,
-  kRoutingTypeMulticastConnection = 0x2000
-} RoutingType;
+  kForwardOpenConnectionTypeNull = 0x0000,
+  kForwardOpenConnectionTypePointToPointConnection = 0x4000,
+  kForwardOpenConnectionTypeMulticastConnection = 0x2000,
+  kForwardOpenConnectionTypeReserved = 0x6000 /**< Reserved and therefore invalid type*/
+} ForwardOpenConnectionType;
 
+typedef enum {
+  kConnectionManagerGeneralStatusSuccess = 0x00, /**< General Status - Everything is ok */
+  kConnectionManagerGeneralStatusExtendedStatus = 0x01, /**< Indicates that extended status is set */
+  kConnectionManagerGeneralStatusResourceUnavailableForUnconnectedSend = 0x02,
+  kConnectionManagerGeneralStatusPathSegmentErrorInUnconnectedSend = 0x04,
+  kConnectionManagerGeneralStatusErrorInDataSegment = 0x09,
+  kConnectionManagerGeneralStatusObjectStateError = 0x0C,
+  kConnectionManagerGeneralStatusDeviceStateError = 0x10,
+  kConnectionManagerGeneralStatusNotEnoughData = 0x13,
+  kConnectionManagerGeneralStatusTooMuchData = 0x15,
+} ConnectionManagerGeneralStatus;
 /** @brief Connection Manager Error codes */
 typedef enum {
-  kConnectionManagerStatusCodeSuccess = 0x00,
-  kConnectionManagerStatusCodeErrorConnectionInUse = 0x0100,
-  kConnectionManagerStatusCodeErrorTransportTriggerNotSupported = 0x0103,
-  kConnectionManagerStatusCodeErrorOwnershipConflict = 0x0106,
-  kConnectionManagerStatusCodeErrorConnectionNotFoundAtTargetApplication = 0x0107,
-  kConnectionManagerStatusCodeErrorInvalidOToTConnectionType = 0x123,
-  kConnectionManagerStatusCodeErrorInvalidTToOConnectionType = 0x124,
-  kConnectionManagerStatusCodeErrorInvalidOToTConnectionSize = 0x127,
-  kConnectionManagerStatusCodeErrorInvalidTToOConnectionSize = 0x128,
-  kConnectionManagerStatusCodeErrorNoMoreConnectionsAvailable = 0x0113,
-  kConnectionManagerStatusCodeErrorVendorIdOrProductcodeError = 0x0114,
-  kConnectionManagerStatusCodeErrorDeviceTypeError = 0x0115,
-  kConnectionManagerStatusCodeErrorRevisionMismatch = 0x0116,
-  kConnectionManagerStatusCodeInvalidConfigurationApplicationPath = 0x0129,
-  kConnectionManagerStatusCodeInvalidConsumingApllicationPath = 0x012A,
-  kConnectionManagerStatusCodeInvalidProducingApplicationPath = 0x012B,
-  kConnectionManagerStatusCodeInconsistentApplicationPathCombo = 0x012F,
-  kConnectionManagerStatusCodeNonListenOnlyConnectionNotOpened = 0x0119,
-  kConnectionManagerStatusCodeErrorParameterErrorInUnconnectedSendService = 0x0205,
-  kConnectionManagerStatusCodeErrorInvalidSegmentTypeInPath = 0x0315,
-  kConnectionManagerStatusCodeTargetObjectOutOfConnections = 0x011A
-} ConnectionManagerStatusCode;
+  kConnectionManagerExtendedStatusCodeSuccess = 0x00, /**< Obsolete code, should be General Status - Everything is ok */
+  kConnectionManagerExtendedStatusCodeErrorConnectionInUseOrDuplicateForwardOpen
+    = 0x0100,                                                                              /**< General Status has to be 0x01, Connection is already in use, or a duplicate Forward Open was received */
+  kConnectionManagerExtendedStatusCodeErrorTransportClassAndTriggerCombinationNotSupported
+    = 0x0103,                                                                                        /**< General Status has to be 0x01, A Transport class and trigger combination has been specified, which is not supported by the target application */
+  kConnectionManagerExtendedStatusCodeErrorOwnershipConflict = 0x0106, /**< General Status has to be 0x01, Another connection has already reserved some needed resources */
+  kConnectionManagerExtendedStatusCodeErrorConnectionTargetConnectionNotFound =
+    0x0107,                                                                             /**< General Status has to be 0x01, Forward Close error message, if connection to be closed is not found at the target */
+  kConnectionManagerExtendedStatusCodeErrorTargetForConnectionNotConfigured =
+    0x0110,                                                                           /**< General Status has to be 0x01, Target application not configured and connection request does not contain data segment for configuration */
+  kConnectionManagerExtendedStatusCodeErrorRpiValuesNotAcceptable = 0x0112, /**< General Status has to be 0x01, Requested RPI parameters outside of range, needs 6 16-bit extended status words, see Vol.1 Table 3-5.33 */
+  kConnectionManagerExtendedStatusCodeErrorNoMoreConnectionsAvailable = 0x0113, /**< General Status has to be 0x01, No free connection slots available */
+  kConnectionManagerExtendedStatusCodeErrorVendorIdOrProductcodeError = 0x0114, /**< General Status has to be 0x01, The Product Code or Vendor ID in the electronic key logical segment does not match the Product Code or Vendor ID of the device, or if the compatibility bit is set and one or both are zero, or cannot be emulated. */
+  kConnectionManagerExtendedStatusCodeErrorDeviceTypeError = 0x0115, /**< General Status has to be 0x01, Device Type specified in the electronic key logical segment does not match the Device Type, or if the compatibility bit is set and Device Type is zero, or cannot be emulated. */
+  kConnectionManagerExtendedStatusCodeErrorRevisionMismatch = 0x0116, /**< General Status has to be 0x01, Major and minor revision specified in the electronic key logical segment is not a valid revision of the device, or if the compatibility bit is set and the requested Major Revision and/or Minor Revision is 0 or the device cannot emulate the specified revision. */
+  kConnectionManagerExtendedStatusCodeNonListenOnlyConnectionNotOpened = 0x0119, /**< General Status has to be 0x01, listen-only connection cannot be established, if no non-listen only connections are established  */
+  kConnectionManagerExtendedStatusCodeTargetObjectOutOfConnections = 0x011A, /**< Maximum number of connections supported by the instance of the target object exceeded */
+  kConnectionManagerExtendedStatusCodeProductionInhibitTimerGreaterThanRpi =
+    0x011B,                                                                          /**< The Production Inhibit Time is greater than the Target to Originator RPI */
+  kConnectionManagerExtendedStatusCodeTransportClassNotSupported = 0x011C, /**< The transport class requested in the Transport Type/Trigger parameter is not supported. */
+  kConnectionManagerExtendedStatusCodeProductionTriggerNotSuppoerted = 0x011D, /**< The production trigger requested in the Transport Type/Trigger parameter is not supported. */
+  kConnectionManagerExtendedStatusCodeDirectionNotSupported = 0x011E, /**< The direction requested in the Transport Type/Trigger parameter is not supported */
+  kConnectionManagerExtendedStatusCodeInvalidOToTNetworkConnectionFixVar =
+    0x011F,                                                                        /**< Shall be returned as the result of specifying an O->T fixed / variable flag that is not supported. */
+  kConnectionManagerExtendedStatusCodeInvalidTToONetworkConnectionFixVar =
+    0x0120,                                                                        /**< Shall be returned as the result of specifying an T->O fixed / variable flag that is not supported. */
+  kConnectionManagerExtendedStatusCodeInvalidOToTNetworkConnectionPriority =
+    0x0121,                                                                          /**< Shall be returned as the result of specifying an O->T priority code that is not supported. */
+  kConnectionManagerExtendedStatusCodeInvalidTToONetworkConnectionPriority =
+    0x0122,                                                                          /**< Shall be returned as the result of specifying an T->O priority code that is not supported. */
+  kConnectionManagerExtendedStatusCodeErrorInvalidOToTConnectionType = 0x0123, /**< Shall be returned as the result of specifying an O->T connection type that is not supported */
+  kConnectionManagerExtendedStatusCodeErrorInvalidTToOConnectionType = 0x0124, /**< Shall be returned as the result of specifying a T->O connection type that is not supported */
+  kConnectionManagerExtendedStatusCodeInvalidOToTNetworkConnectionRedundantOwner
+    = 0x0125,                                                                              /**< Shall be returned as the result of specifying an O->T Redundant Owner flag that is not supported. */
+  kConnectionManagerExtendedStatusCodeInvalidConfigurationSize = 0x0126, /**< The data segment provided in the Connection_Path parameter did not contain an acceptable number of 16-bit words for the the configuration application path requested. Two additional status words shall follow, the error code plus the max size in words */
+  kConnectionManagerExtendedStatusCodeErrorInvalidOToTConnectionSize = 0x0127, /**< The size of the consuming object declared in the Forward_Open request and available on the target does not match the size declared in the O->T Network Connection Parameter. Two additional status words shall follow, the error code plus the max size in words */
+  kConnectionManagerExtendedStatusCodeErrorInvalidTToOConnectionSize = 0x0128, /**< The size of the consuming object declared in the Forward_Open request and available on the target does not match the size declared in the T->O Network Connection Parameter. Two additional status words shall follow, the error code plus the max size in words  */
+  kConnectionManagerExtendedStatusCodeInvalidConfigurationApplicationPath =
+    0x0129,                                                                         /**< Configuration application path specified does not correspond to a valid configuration application path within the target application. This error could also be returned if a configuration application path was required, but not provided by a connection request. */
+  kConnectionManagerExtendedStatusCodeInvalidConsumingApplicationPath = 0x012A, /**< Consumed application path specified does not correspond to a valid consumed application path within the target application. This error could also be returned if a consumed application path was required, but not provided by a connection request. */
+  kConnectionManagerExtendedStatusCodeInvalidProducingApplicationPath = 0x012B, /**< Produced application path specified does not correspond to a valid produced application path within the target application. This error could also be returned if a produced application path was required, but not provided by a connection request. */
+  kConnectionManagerExtendedStatusCodeConfigurationSymbolDoesNotExist = 0x012C,
+  kConnectionManagerExtendedStatusCodeConsumingSymbolDoesNotExist = 0x012D,
+  kConnectionManagerExtendedStatusCodeProducingSymbolDoesNotExist = 0x012E,
+  kConnectionManagerExtendedStatusCodeInconsistentApplicationPathCombo = 0x012F, /**<  */
+  kConnectionManagerExtendedStatusCodeInconsistentConsumeDataFormat = 0x0130,
+  kConnectionManagerExtendedStatusCodeInconsistentProduceDataFormat = 0x0131,
+  kConnectionManagerExtendedStatusCodeNullForwardOpenNotSupported = 0x0132,
+  kConnectionManagerExtendedStatusCodeConnectionTimeoutMultiplierNotAcceptable =
+    0x0133,
+  kConnectionManagerExtendedStatusCodeConnectionTimedOut = 0x0203,
+  kConnectionManagerExtendedStatusCodeUnconnectedRequestTimedOut = 0x0204,
+  kConnectionManagerExtendedStatusCodeErrorParameterErrorInUnconnectedSendService
+    = 0x0205,                                                                               /**<  */
+  kConnectionManagerExtendedStatusCodeMessageToLargeForUnconnectedSendService =
+    0x0206,
+  kConnectionManagerExtendedStatusCodeUnconnectedAcknowledgeWithoutReply =
+    0x0207,
+  kConnectionManagerExtendedStatusCodeNoBufferMemoryAvailable = 0x0301,
+  kConnectionManagerExtendedStatusCodeNetworkBandwithNotAvailableForData =
+    0x0302,
+  kConnectionManagerExtendedStatusCodeNoConsumedConnectionIdFilterAvailable =
+    0x0303,
+  kConnectionManagerExtendedStatusCodeNotConfiguredToSendScheduledPriorityData =
+    0x0304,
+  kConnectionManagerExtendedStatusCodeScheduleSignatureMismatch = 0x0305,
+  kConnectionManagerExtendedStatusCodeScheduleSignatureValidationNotPossible =
+    0x0306,
+  kConnectionManagerExtendedStatusCodePortNotAvailable = 0x0311,
+  kConnectionManagerExtendedStatusCodeLinkAddressNotValid = 0x0312,
+  kConnectionManagerExtendedStatusCodeErrorInvalidSegmentTypeInPath = 0x0315, /**<  */
+  kConnectionManagerExtendedStatusCodeForwardCloseServiceConnectionPathMismatch
+    = 0x0316,
+  kConnectionManagerExtendedStatusCodeSchedulingNotSpecified = 0x0317,
+  kConnectionManagerExtendedStatusCodeLinkAddressToSelfInvalid = 0x0318,
+  kConnectionManagerExtendedStatusCodeSecondaryResourcesUnavailable = 0x0319,
+  kConnectionManagerExtendedStatusCodeRackConnectionAlreadyEstablished = 0x031A,
+  kConnectionManagerExtendedStatusCodeModuleConnectionAlreadyEstablished =
+    0x031B,
+  kConnectionManagerExtendedStatusCodeMiscellaneous = 0x031C,
+  kConnectionManagerExtendedStatusCodeRedundantConnectionMismatch = 0x031D,
+  kConnectionManagerExtendedStatusCodeNoMoreUserConfigurableLinkConsumerResourcesAvailableInTheProducingModule
+    = 0x031E,
+  kConnectionManagerExtendedStatusCodeNoUserConfigurableLinkConsumerResourcesConfiguredInTheProducingModule
+    = 0x031F,
+  kConnectionManagerExtendedStatusCodeNetworkLinkOffline = 0x0800,
+  kConnectionManagerExtendedStatusCodeNoTargetApplicationDataAvailable = 0x0810,
+  kConnectionManagerExtendedStatusCodeNoOriginatorApplicationDataAvailable =
+    0x0811,
+  kConnectionManagerExtendedStatusCodeNodeAddressHasChangedSinceTheNetworkWasScheduled
+    = 0x0812,
+  kConnectionManagerExtendedStatusCodeNotConfiguredForOffSubnetMulticast =
+    0x0813,
+  kConnectionManagerExtendedStatusCodeInvalidProduceConsumeDataFormat = 0x0814,
+  kConnectionManagerExtendedStatusWrongCloser
+} ConnectionManagerExtendedStatusCode;
 
 typedef enum {
   kConnectionTriggerTypeProductionTriggerMask = 0x70,
@@ -53,6 +142,27 @@ typedef enum {
   kConnectionTriggerTypeApplicationTriggeredConnection = 0x20
 } ConnectionTriggerType;
 
+typedef enum ProductionTrigger {
+  kProductionTriggerInvalid = -1,
+  kProductionTriggerCyclic = 0,
+  kProductionTriggerChangeOfState = 1,
+  kProductionTriggerApplicationObjectTriggered = 2
+} ProductionTrigger;
+
+ProductionTrigger GetProductionTrigger(
+  const ConnectionObject const *connection_object);
+
+void SetProductionTrigger(const ProductionTrigger production_trigger,
+                          ConnectionObject *connection_object);
+
+CipUint GetProductionInhibitTime(const ConnectionObject const *connection_object);
+
+void SetProductionInhibitTime(const EipUint16 production_inhibit_time,
+                              ConnectionObject *const connection_object);
+
+CipUdint GetTargetToOriginatorRequestedPackedInterval(
+  const ConnectionObject const *connection_object);
+
 /** @brief macros for comparing sequence numbers according to CIP spec vol
  * 2 3-4.2 for int type variables
  * @define SEQ_LEQ32(a, b) Checks if sequence number a is less or equal than b
@@ -60,17 +170,17 @@ typedef enum {
  *  b
  *  @define SEQ_GT32(a, b) Checks if sequence number a is greater than b
  */
-#define SEQ_LEQ32(a, b) ((int)((a) - (b)) <= 0)
-#define SEQ_GEQ32(a, b) ((int)((a) - (b)) >= 0)
-#define SEQ_GT32(a, b) ((int)((a) - (b)) > 0)
+#define SEQ_LEQ32(a, b) ( (int)( (a) - (b) ) <= 0 )
+#define SEQ_GEQ32(a, b) ( (int)( (a) - (b) ) >= 0 )
+#define SEQ_GT32(a, b) ( (int)( (a) - (b) ) > 0 )
 
 /** @brief similar macros for comparing 16 bit sequence numbers
  * @define SEQ_LEQ16(a, b) Checks if sequence number a is less or equal than b
  * @define SEQ_GEQ16(a, b) Checks if sequence number a is greater or equal than
  *  b
  */
-#define SEQ_LEQ16(a, b) ((short)((a) - (b)) <= 0)
-#define SEQ_GEQ16(a, b) ((short)((a) - (b)) >= 0)
+#define SEQ_LEQ16(a, b) ( (short)( (a) - (b) ) <= 0 )
+#define SEQ_GEQ16(a, b) ( (short)( (a) - (b) ) >= 0 )
 
 /** @brief States of a connection */
 typedef enum {
@@ -95,7 +205,7 @@ typedef enum {
 typedef enum {
   kWatchdogTimeoutActionTransitionToTimedOut = 0, /**< , invalid for explicit message connections */
   kWatchdogTimeoutActionAutoDelete = 1, /**< Default for explicit message connections,
-   default for I/O connections on EIP */
+                                           default for I/O connections on EIP */
   kWatchdogTimeoutActionAutoReset = 2, /**< Invalid for explicit message connections */
   kWatchdogTimeoutActionDeferredDelete = 3 /**< Only valid for DeviceNet, invalid for I/O connections */
 } WatchdogTimeoutAction;
@@ -104,7 +214,7 @@ typedef struct {
   ConnectionState state;
   EipUint16 connection_id;
 /*TODO think if this is needed anymore
- TCMReceiveDataFunc m_ptfuncReceiveData; */
+   TCMReceiveDataFunc m_ptfuncReceiveData; */
 } LinkConsumer;
 
 typedef struct {
@@ -123,29 +233,35 @@ typedef struct {
  * data can not be accessed with CIP means.
  */
 typedef struct connection_object {
-  ConnectionState state;
-  ConnectionType instance_type;
-
+  ConnectionState state; /**< state of the object */
+  ConnectionType instance_type; /**< Indicates either I/O or Messaging connection */
+  EipByte transport_type_class_trigger;
   /* conditional
-   EipUint16 DeviceNetProductedConnectionID;
-   EipUint16 DeviceNetConsumedConnectionID;
+     EipUint16 device_net_produced_connection_id;
+     EipUint16 device_net_consumed_connection_id;
+     EipByte device_net_initial_comm_characteristcs;
    */
-  EipByte device_net_initial_comm_characteristcs;
+
   EipUint16 produced_connection_size;
   EipUint16 consumed_connection_size;
   EipUint16 expected_packet_rate;
 
   /*conditional*/
-  EipUint32 produced_connection_id;
-  EipUint32 consumed_connection_id;
+  EipUint32 cip_produced_connection_id;
+  EipUint32 cip_consumed_connection_id;
   /**/
-  WatchdogTimeoutAction watchdog_timeout_action;
+  EipUint8 watchdog_timeout_action; /**< see enum WatchdogTimeoutAction */
   EipUint16 produced_connection_path_length;
-  CipEpath produced_connection_path;
+  CipEpath produced_connection_path; /**< Packed EPATH */
   EipUint16 consumed_connection_path_length;
-  CipEpath consumed_connection_path;
-  /* conditional
-   UINT16 ProductionInhibitTime;
+  CipEpath consumed_connection_path; /**< Packed EPATH */
+  /** @brief Minimal time between the production of two application triggered
+   * or change of state triggered I/O connection messages
+   */
+  EipUint16 production_inhibit_time;
+  EipUint16 connection_timeout_multiplier;
+  /* Conditional
+   * connection_binding_list < STRUCT OF UINT, Array of UINT
    */
   /* non CIP Attributes, only relevant for opened connections */
   EipByte priority_timetick;
@@ -153,12 +269,12 @@ typedef struct connection_object {
   EipUint16 connection_serial_number;
   EipUint16 originator_vendor_id;
   EipUint32 originator_serial_number;
-  EipUint16 connection_timeout_multiplier;
+
   EipUint32 o_to_t_requested_packet_interval;
   EipUint16 o_to_t_network_connection_parameter;
   EipUint32 t_to_o_requested_packet_interval;
   EipUint16 t_to_o_network_connection_parameter;
-  EipByte transport_type_class_trigger;
+
   EipUint8 connection_path_size;
   CipElectronicKey electronic_key;
   CipConnectionPath connection_path; /* padded EPATH*/
@@ -171,28 +287,25 @@ typedef struct connection_object {
   /*S_CIP_CM_Object *p_stProducingCMObject; */
 
   EipUint32 eip_level_sequence_count_producing; /* the EIP level sequence Count
-   for Class 0/1
-   Producing Connections may have a
-   different
-   value than SequenceCountProducing */
+                                                   for Class 0/1
+                                                   Producing Connections may have a
+                                                   different
+                                                   value than SequenceCountProducing */
   EipUint32 eip_level_sequence_count_consuming; /* the EIP level sequence Count
-   for Class 0/1
-   Producing Connections may have a
-   different
-   value than SequenceCountProducing */
+                                                   for Class 0/1
+                                                   Producing Connections may have a
+                                                   different
+                                                   value than SequenceCountProducing */
 
   EipUint16 sequence_count_producing; /* sequence Count for Class 1 Producing
-   Connections */
+                                         Connections */
   EipUint16 sequence_count_consuming; /* sequence Count for Class 1 Producing
-   Connections */
+                                         Connections */
 
   EipInt32 transmission_trigger_timer;
-  EipInt32 inactivity_watchdog_timer;
+  uint64_t inactivity_watchdog_timer;
+
 
-  /** @brief Minimal time between the production of two application triggered
-   * or change of state triggered I/O connection messages
-   */
-  EipUint16 production_inhibit_time;
 
   /** @brief Timer for the production inhibition of application triggered or
    * change-of-state I/O connections.
@@ -201,9 +314,9 @@ typedef struct connection_object {
 
   struct sockaddr_in remote_address; /* socket address for produce */
   struct sockaddr_in originator_address; /* the address of the originator that
-   established the connection. needed
-   for scanning if the right packet is
-   arriving */
+                                            established the connection. needed
+                                            for scanning if the right packet is
+                                            arriving */
   int socket[2]; /* socket handles, indexed by kConsuming or kProducing */
 
   /* pointers to connection handling functions */
@@ -218,6 +331,7 @@ typedef struct connection_object {
 
   EipUint16 correct_originator_to_target_size;
   EipUint16 correct_target_to_originator_size;
+  struct sockaddr_in original_opener_ip_address;
 } ConnectionObject;
 
 /** @brief Connection Manager class code */
@@ -238,7 +352,7 @@ EipStatus ConnectionManagerInit(EipUint16 unique_connection_id);
  *   @return pointer to connected Object
  *           0 .. connection not present in device
  */
-ConnectionObject* GetConnectedObject(EipUint32 connection_id);
+ConnectionObject *GetConnectedObject(EipUint32 connection_id);
 
 /**  Get a connection object for a given output assembly.
  *
@@ -254,14 +368,15 @@ ConnectionObject *GetConnectedOutputAssembly(EipUint32 output_assembly_id);
  * @param destination Destination of the copy operation
  * @param osurce Source of the copy operation
  */
-void CopyConnectionData(ConnectionObject *RESTRICT destination, const ConnectionObject *RESTRICT const source);
+void CopyConnectionData(ConnectionObject *RESTRICT destination,
+                        const ConnectionObject *RESTRICT const source);
 
 /** @brief Close the given connection
  *
  * This function will take the data form the connection and correctly closes the
- *connection (e.g., open sockets)
+ * connection (e.g., open sockets)
  * @param connection_object pointer to the connection object structure to be
- *closed
+ * closed
  */
 void CloseConnection(ConnectionObject *RESTRICT connection_object);
 
@@ -293,4 +408,10 @@ void AddNewActiveConnection(ConnectionObject *connection_object);
  */
 void RemoveFromActiveConnections(ConnectionObject *connection_object);
 
+/** @brief returns the connection type of the supplied network connection parameter
+ *
+ */
+ForwardOpenConnectionType GetConnectionType(
+  EipUint16 network_connection_parameter);
+
 #endif /* OPENER_CIPCONNECTIONMANAGER_H_ */

+ 93 - 0
source/src/cip/cipelectronickey.c

@@ -0,0 +1,93 @@
+/*******************************************************************************
+ * Copyright (c) 2016, Rockwell Automation, Inc.
+ * All rights reserved.
+ *
+ ******************************************************************************/
+
+#include <stdlib.h>
+
+#include "cipelectronickey.h"
+
+typedef struct electronic_key_format_4 {
+  CipUint vendor_id;
+  CipUint device_type;
+  CipUint product_code;
+  CipByte major_revision_compatibility;
+  CipUsint minor_revision;
+} ElectronicKeyFormat4;
+
+const size_t kElectronicKeyFormat4Size = sizeof(ElectronicKeyFormat4);
+
+ElectronicKeyFormat4 *ElectronicKeyFormat4New() {
+  return (ElectronicKeyFormat4 *)calloc( 1, sizeof(ElectronicKeyFormat4) );
+}
+
+void ElectronicKeyFormat4Delete(ElectronicKeyFormat4 **electronic_key) {
+  free(*electronic_key);
+  *electronic_key = NULL;
+}
+
+void ElectronicKeyFormat4SetVendorId(const CipUint vendor_id,
+                                     ElectronicKeyFormat4 *const electronic_key)
+{
+  electronic_key->vendor_id = vendor_id;
+}
+
+CipUint ElectronicKeyFormat4GetVendorId(
+  const ElectronicKeyFormat4 *const electronic_key) {
+  return electronic_key->vendor_id;
+}
+
+void ElectronicKeyFormat4SetDeviceType(const CipUint device_type,
+                                       ElectronicKeyFormat4 *const electronic_key)
+{
+  electronic_key->device_type = device_type;
+}
+
+CipUint ElectronicKeyFormat4GetDeviceType(
+  const ElectronicKeyFormat4 *const electronic_key) {
+  return electronic_key->device_type;
+}
+
+void ElectronicKeyFormat4SetProductCode(const CipUint product_code,
+                                        ElectronicKeyFormat4 *const electronic_key)
+{
+  electronic_key->product_code = product_code;
+}
+
+CipUint ElectronicKeyFormat4GetProductCode(
+  const ElectronicKeyFormat4 *const electronic_key) {
+  return electronic_key->product_code;
+}
+
+void ElectronicKeyFormat4SetMajorRevisionCompatibility(
+  const CipByte major_revision_compatibility,
+  ElectronicKeyFormat4 *const electronic_key) {
+  electronic_key->major_revision_compatibility = major_revision_compatibility;
+}
+
+CipByte ElectronicKeyFormat4GetMajorRevision(
+  const ElectronicKeyFormat4 *const electronic_key) {
+  const CipByte kMajorRevisionMask = 0x7F;
+  return (electronic_key->major_revision_compatibility & kMajorRevisionMask);
+}
+
+bool ElectronicKeyFormat4GetMajorRevisionCompatibility(
+  const ElectronicKeyFormat4 *const electronic_key) {
+  const CipByte kCompatibilityMask = 0x80;
+  if( kCompatibilityMask ==
+      (electronic_key->major_revision_compatibility & kCompatibilityMask) ) {
+    return true;
+  }
+  return false;
+}
+
+void ElectronicKeyFormat4SetMinorRevision(const CipUsint minor_revision,
+                                          ElectronicKeyFormat4 *const electronic_key)
+{
+  electronic_key->minor_revision = minor_revision;
+}
+CipUsint ElectronicKeyFormat4GetMinorRevision(
+  const ElectronicKeyFormat4 *const electronic_key) {
+  return electronic_key->minor_revision;
+}

+ 126 - 0
source/src/cip/cipelectronickey.h

@@ -0,0 +1,126 @@
+/*******************************************************************************
+ * Copyright (c) 2016, Rockwell Automation, Inc.
+ * All rights reserved.
+ *
+ ******************************************************************************/
+
+#ifndef SRC_CIP_CIPELECTRONICKEY_H_
+#define SRC_CIP_CIPELECTRONICKEY_H_
+
+#include <stdbool.h>
+
+#include "typedefs.h"
+
+/** @brief Declaration of the electronic key format 4 data struct for the class
+ *
+ */
+typedef struct electronic_key_format_4 ElectronicKeyFormat4;
+
+extern const size_t kElectronicKeyFormat4Size;
+
+/** @brief Constructor for the electroic key format 4 class
+ *
+ *	@return A new unset electronic key
+ */
+ElectronicKeyFormat4 *ElectronicKeyFormat4New();
+
+/** @brief Destructor for the electroic key format 4 class
+ *
+ *  Safe destructor/free, nulls the pointer after freeing it
+ *  @param electronic_key A format 4 electronic key
+ */
+void ElectronicKeyFormat4Delete(ElectronicKeyFormat4 **electronic_key);
+
+/** @brief Sets vendor ID in the electronic key
+ *
+ *	@param vendor_id The vendor ID to be set into the electronic key
+ *	@param electronic_key The electronic key to be set - will be modified
+ */
+void ElectronicKeyFormat4SetVendorId(const CipUint vendor_id,
+                                     ElectronicKeyFormat4 *const electronic_key);
+
+/** @brief Gets the vendor ID form the electronic key
+ *
+ *      @param electronic_key The format 4 electronic key from which the vendor ID will be extracted
+ *      @return The vendor ID
+ */
+CipUint ElectronicKeyFormat4GetVendorId(
+  const ElectronicKeyFormat4 *const electronic_key);
+
+/** @brief Sets the device type in the electronic key
+ *
+ *	@param device_type The device type which shall be inserted into the electronic key
+ *	@param electronic_key A format 4 electronic key
+ */
+void ElectronicKeyFormat4SetDeviceType(
+  const CipUint device_type,ElectronicKeyFormat4 *const
+  electronic_key);
+
+/** @brief Gets the device type from a format 4 electronic key
+ *
+ *      @param The format 4 electronic key from which the device type will be extracted
+ *      @return The device type
+ */
+CipUint ElectronicKeyFormat4GetDeviceType(
+  const ElectronicKeyFormat4 *const electronic_key);
+
+/** @brief Set product code in the electronic key
+ *
+ *      @param product_code The product code to be inserted
+ *      @param electronic_key The electronic key to be modified
+ */
+void ElectronicKeyFormat4SetProductCode(
+  const CipUint product_code,ElectronicKeyFormat4 *const
+  electronic_key);
+
+/** @brief Gets the product code from an format 4 electronic key
+ *
+ *      @param electronic_key The format 4 electronic key to be read
+ *      @return The product code
+ */
+CipUint ElectronicKeyFormat4GetProductCode(
+  const ElectronicKeyFormat4 *const electronic_key);
+
+/** @brief Sets the major revision byte including the compatibility flag
+ *
+ *      @param major_revision_compatibility The major revision byte including the compatibility flag
+ *      @param electronic_key The electronic key to be modified
+ */
+void ElectronicKeyFormat4SetMajorRevisionCompatibility(
+  const CipByte major_revision_compatibility,
+  ElectronicKeyFormat4 *const electronic_key);
+
+/** @brief Gets the major revision from an format 4 electronic key
+ *
+ *      @param electronic_key An format 4 electronic key
+ *      @return The device's major revision
+ */
+CipByte ElectronicKeyFormat4GetMajorRevision(
+  const ElectronicKeyFormat4 *const electronic_key);
+
+/** @brief Gets the Compatibility flag from the format 4 electronic key
+ *
+ *      @param electronic_key The format 4 electronic key to be read
+ *      @return True if compatibility bit is set, false if otherwise
+ */
+bool ElectronicKeyFormat4GetMajorRevisionCompatibility(
+  const ElectronicKeyFormat4 *const electronic_key);
+
+/** @brief Sets the devices minor revision in an format 4 electronic key
+ *
+ *      @param minor_revision The minor revision to be set in the electronic key
+ *      @param electronic_key The electronic key to be modified
+ */
+void ElectronicKeyFormat4SetMinorRevision(
+  const CipUsint minor_revision,ElectronicKeyFormat4 *const
+  electronic_key);
+
+/** @brief Gets the minor revision from an format 4 electronic key
+ *
+ *      @param electronic_key The format 4 electronic key to be read
+ *      @return The device's minor revision
+ */
+CipUsint ElectronicKeyFormat4GetMinorRevision(
+  const ElectronicKeyFormat4 *const electronic_key);
+
+#endif /* SRC_CIP_CIPELECTRONICKEY_H_ */

+ 527 - 0
source/src/cip/cipepath.c

@@ -0,0 +1,527 @@
+/*******************************************************************************
+ * Copyright (c) 2009, Rockwell Automation, Inc.
+ * All rights reserved.
+ *
+ ******************************************************************************/
+
+#include <stdbool.h>
+#include <stdlib.h>
+
+#include "cipepath.h"
+
+#include "endianconv.h"
+#include "cipelectronickey.h"
+#include "trace.h"
+
+const unsigned int kPortSegmentExtendedPort = 15; /**< Reserved port segment port value, indicating the use of the extended port field */
+
+/* Segments */
+#define SEGMENT_TYPE_PORT_SEGMENT 0x00 /**< Message value of the Port segment */
+#define SEGMENT_TYPE_LOGICAL_SEGMENT 0x20 /**< Message value of the Logical segment */
+#define SEGMENT_TYPE_NETWORK_SEGMENT 0x40 /**< Message value of the Network segment */
+#define SEGMENT_TYPE_SYMBOLIC_SEGMENT 0x60 /**< Message value of the Symbolic segment */
+#define SEGMENT_TYPE_DATA_SEGMENT 0x80 /**< Message value of the Data segment */
+#define SEGMENT_TYPE_DATA_TYPE_CONSTRUCTED 0xA0 /**< Message value of the Data type constructed */
+#define SEGMENT_TYPE_DATA_TYPE_ELEMENTARTY 0xC0 /**< Message value of the Data type elementary */
+#define SEGMENT_TYPE_SEGMENT_RESERVED 0xE0 /**< Reserved value */
+
+#define LOGICAL_SEGMENT_TYPE_CLASS_ID 0x00 /**< Message value of the logical segment/logical type Class ID */
+#define LOGICAL_SEGMENT_TYPE_INSTANCE_ID 0x04 /**< Message value of the logical segment/logical type Instance ID */
+#define LOGICAL_SEGMENT_TYPE_MEMBER_ID 0x08 /**< Message value of the logical segment/logical type Member ID */
+#define LOGICAL_SEGMENT_TYPE_CONNECTION_POINT 0x0C /**< Message value of the logical segment/logical type Connection Point */
+#define LOGICAL_SEGMENT_TYPE_ATTRIBUTE_ID 0x10 /**< Message value of the logical segment/logical type Attribute ID */
+#define LOGICAL_SEGMENT_TYPE_SPECIAL 0x14 /**< Message value of the logical segment/logical type Special */
+#define LOGICAL_SEGMENT_TYPE_SERVICE_ID 0x18 /**< Message value of the logical segment/logical type Service ID */
+#define LOGICAL_SEGMENT_TYPE_EXTENDED_LOGICAL 0x1C /**< Message value of the logical segment/logical type Extended Logical */
+
+#define LOGICAL_SEGMENT_FORMAT_EIGHT_BIT 0x00
+#define LOGICAL_SEGMENT_FORMAT_SIXTEEN_BIT 0x01
+#define LOGICAL_SEGMENT_FORMAT_THIRTY_TWO_BIT 0x02
+
+#define LOGICAL_SEGMENT_EXTENDED_TYPE_RESERVED 0x00
+#define LOGICAL_SEGMENT_EXTENDED_TYPE_ARRAY_INDEX 0x01
+#define LOGICAL_SEGMENT_EXTENDED_TYPE_INDIRECT_ARRAY_INDEX 0x02
+#define LOGICAL_SEGMENT_EXTENDED_TYPE_BIT_INDEX 0x03
+#define LOGICAL_SEGMENT_EXTENDED_TYPE_INDIRECT_BIT_INDEX 0x04
+#define LOGICAL_SEGMENT_EXTENDED_TYPE_STRUCTURE_MEMBER_NUMBER 0x05
+#define LOGICAL_SEGMENT_EXTENDED_TYPE_STRUCTURE_MEMBER_HANDLE 0x06
+
+#define LOGICAL_SEGMENT_SPECIAL_TYPE_FORMAT_ELECTRONIC_KEY 0x00
+#define ELECTRONIC_KEY_SEGMENT_KEY_FORMAT_4 0x04
+
+#define NETWORK_SEGMENT_SCHEDULE 0x01
+#define NETWORK_SEGMENT_FIXED_TAG 0x02
+#define NETWORK_SEGMENT_PRODUCTION_INHIBIT_TIME_IN_MILLISECONDS 0x03
+#define NETWORK_SEGMENT_SAFETY 0x04
+#define NETWORK_SEGMENT_PRODUCTION_INHIBIT_TIME_IN_MICROSECONDS 0x10
+#define NETWORK_SEGMENT_EXTENDED_NETWORK 0x1F
+
+#define SYMBOLIC_SEGMENT_FORMAT_EXTENDED_STRING 0x00
+
+#define SYMBOLIC_SEGMENT_EXTENDED_FORMAT_DOUBLE_CHAR 0x20
+#define SYMBOLIC_SEGMENT_EXTENDED_FORMAT_TRIPLE_CHAR 0x40
+#define SYMBOLIC_SEGMENT_EXTENDED_FORMAT_NUMERIC 0xC0
+
+#define SYMBOLIC_SEGMENT_EXTENDED_FORMAT_NUMERIC_USINT_TYPE 0x06
+#define SYMBOLIC_SEGMENT_EXTENDED_FORMAT_NUMERIC_UINT_TYPE 0x07
+#define SYMBOLIC_SEGMENT_EXTENDED_FORMAT_NUMERIC_UDINT_TYPE 0x08
+
+#define DATA_SEGMENT_SUBTYPE_SIMPLE_DATA 0x00
+#define DATA_SEGMENT_SUBTYPE_ANSI_EXTENDED_SYMBOL 0x11
+
+
+
+/*** Path Segment ***/
+SegmentType GetPathSegmentType(const unsigned char *const cip_path) {
+  const unsigned int kSegmentTypeMask = 0xE0;
+  const unsigned int segment_type = *cip_path & kSegmentTypeMask;
+  SegmentType result = kSegmentTypeReserved;
+  switch (segment_type) {
+    case SEGMENT_TYPE_PORT_SEGMENT:
+      result = kSegmentTypePortSegment;
+      break;
+    case SEGMENT_TYPE_LOGICAL_SEGMENT:
+      result = kSegmentTypeLogicalSegment;
+      break;
+    case SEGMENT_TYPE_NETWORK_SEGMENT:
+      result = kSegmentTypeNetworkSegment;
+      break;
+    case SEGMENT_TYPE_SYMBOLIC_SEGMENT:
+      result = kSegmentTypeSymbolicSegment;
+      break;
+    case SEGMENT_TYPE_DATA_SEGMENT:
+      result = kSegmentTypeDataSegment;
+      break;
+    case SEGMENT_TYPE_DATA_TYPE_CONSTRUCTED:
+      result = kSegmentTypeDataTypeConstructed;
+      break;
+    case SEGMENT_TYPE_DATA_TYPE_ELEMENTARTY:
+      result = kSegmentTypeDataTypeElementary;
+      break;
+    case SEGMENT_TYPE_SEGMENT_RESERVED:
+      result = kSegmentTypeReserved;
+      break;
+    default:
+      OPENER_ASSERT(
+        "Invalid Segment type in the message! We should never come here!\n");
+      break;
+  }
+  return result;
+}
+
+void SetPathSegmentType(SegmentType segment_type,
+                        unsigned char *const cip_path) {
+  switch (segment_type) {
+    case kSegmentTypePortSegment:
+      *cip_path |= SEGMENT_TYPE_PORT_SEGMENT;
+      break;
+    case kSegmentTypeLogicalSegment:
+      *cip_path |= SEGMENT_TYPE_LOGICAL_SEGMENT;
+      break;
+    case kSegmentTypeNetworkSegment:
+      *cip_path |= SEGMENT_TYPE_NETWORK_SEGMENT;
+      break;
+    case kSegmentTypeSymbolicSegment:
+      *cip_path |= SEGMENT_TYPE_SYMBOLIC_SEGMENT;
+      break;
+    case kSegmentTypeDataSegment:
+      *cip_path |= SEGMENT_TYPE_DATA_SEGMENT;
+      break;
+    case kSegmentTypeDataTypeConstructed:
+      *cip_path |= SEGMENT_TYPE_DATA_TYPE_CONSTRUCTED;
+      break;
+    case kSegmentTypeDataTypeElementary:
+      *cip_path |= SEGMENT_TYPE_DATA_TYPE_ELEMENTARTY;
+      break;
+    case kSegmentTypeReserved:
+      *cip_path |= SEGMENT_TYPE_SEGMENT_RESERVED;
+      break;
+    default:
+      OPENER_ASSERT(
+        "Invalid Segment type chosen! We should never come here!\n");
+  }
+}
+
+/*** Port Segment ***/
+bool GetPathPortSegmentExtendedLinkAddressSizeBit(
+  const unsigned char *const cip_path) {
+  const unsigned int kExtendedLinkAddressSizeMask = 0x10;
+  if ( kExtendedLinkAddressSizeMask ==
+       (*cip_path & kExtendedLinkAddressSizeMask) ) {
+    return true;
+  }
+  return false;
+}
+
+unsigned int GetPathPortSegmentPortIdentifier(
+  const unsigned char *const cip_path) {
+  const unsigned int kPortIdentifierMask = 0x0F;
+  unsigned int port_identifier = *cip_path & kPortIdentifierMask;
+//  OPENER_ASSERT(0 != port_identifier, "Use of reserved port identifier 0\n");
+  OPENER_ASSERT( kSegmentTypePortSegment == GetPathSegmentType(cip_path) );
+  OPENER_ASSERT(0 != port_identifier);
+  return port_identifier;
+}
+
+void SetPathPortSegmentPortIdentifier(const unsigned int port_identifier,
+                                      unsigned char *const cip_path) {
+//  OPENER_ASSERT(
+//      port_identifier < 16,
+//      "Port identifier too large for standard port identifier field\n");
+  OPENER_ASSERT(port_identifier < 16);
+  (*cip_path) |= port_identifier;
+}
+
+unsigned int GetPathPortSegmentLinkAddressSize(
+  const unsigned char *const cip_path) {
+//  OPENER_ASSERT(false == GetPathPortSegmentExtendedLinkAddressSizeBit(cip_path),
+//                "Call to non existent extended link address size\n");
+  OPENER_ASSERT( true ==
+                 GetPathPortSegmentExtendedLinkAddressSizeBit(cip_path) );
+  return *(cip_path + 1);
+}
+
+unsigned int GetPathPortSegmentExtendedPortNumber(
+  const unsigned char *const cip_path) {
+//  OPENER_ASSERT(kPortSegmentExtendedPort == GetPathPortSegmentPortIdentifier(cip_path),
+//                "There is no extended port available!\n");
+  OPENER_ASSERT( kPortSegmentExtendedPort ==
+                 GetPathPortSegmentPortIdentifier(cip_path) );
+  const unsigned int kExtendedPortSegmentPosition =
+    GetPathPortSegmentExtendedLinkAddressSizeBit(cip_path) == true ? 2 : 1;
+  return cip_path[kExtendedPortSegmentPosition]
+         + (cip_path[kExtendedPortSegmentPosition + 1] << 8);
+}
+
+void SetPathPortSegmentExtendedPortIdentifier(
+  const unsigned int extended_port_identifier, unsigned char *const cip_path) {
+  SetPathPortSegmentPortIdentifier(kPortSegmentExtendedPort, cip_path);
+  const unsigned int kExtendedPortSegmentPosition =
+    GetPathPortSegmentExtendedLinkAddressSizeBit(cip_path) == true ? 2 : 1;
+  cip_path[kExtendedPortSegmentPosition] = (char) (extended_port_identifier
+                                                   & 0x00FF);
+  cip_path[kExtendedPortSegmentPosition + 1] =
+    (char) ( (extended_port_identifier & 0xFF00) >> 8 );
+}
+/*** Port Segment ***/
+
+/*** Logical Segment ***/
+
+LogicalSegmentLogicalType GetPathLogicalSegmentLogicalType(
+  const unsigned char *const cip_path) {
+  OPENER_ASSERT( kSegmentTypeLogicalSegment == GetPathSegmentType(cip_path) );
+  const unsigned int kLogicalTypeMask = 0x1C;
+  const unsigned int logical_type = (*cip_path) & kLogicalTypeMask;
+  LogicalSegmentLogicalType result = kLogicalSegmentLogicalTypeExtendedLogical;
+  switch (logical_type) {
+    case LOGICAL_SEGMENT_TYPE_CLASS_ID:
+      result = kLogicalSegmentLogicalTypeClassId;
+      break;
+    case LOGICAL_SEGMENT_TYPE_INSTANCE_ID:
+      result = kLogicalSegmentLogicalTypeInstanceId;
+      break;
+    case LOGICAL_SEGMENT_TYPE_MEMBER_ID:
+      result = kLogicalSegmentLogicalTypeMemberId;
+      break;
+    case LOGICAL_SEGMENT_TYPE_CONNECTION_POINT:
+      result = kLogicalSegmentLogicalTypeConnectionPoint;
+      break;
+    case LOGICAL_SEGMENT_TYPE_ATTRIBUTE_ID:
+      result = kLogicalSegmentLogicalTypeAttributeId;
+      break;
+    case LOGICAL_SEGMENT_TYPE_SPECIAL:
+      result = kLogicalSegmentLogicalTypeSpecial;
+      break;
+    case LOGICAL_SEGMENT_TYPE_SERVICE_ID:
+      result = kLogicalSegmentLogicalTypeServiceId;
+      break;
+    case LOGICAL_SEGMENT_TYPE_EXTENDED_LOGICAL:
+      result = kLogicalSegmentLogicalTypeExtendedLogical;
+      break;
+    default:
+      OPENER_ASSERT(
+        "Logical segment/logical type: It is not possible to reach this point!\n");
+      break;
+  }
+  return result;
+}
+
+LogicalSegmentLogicalFormat GetPathLogicalSegmentLogicalFormat(
+  const unsigned char *const cip_path) {
+  OPENER_ASSERT( kSegmentTypeLogicalSegment == GetPathSegmentType(cip_path) );
+  const unsigned int kLogicalFormatMask = 0x03;
+  const unsigned int logical_format = (*cip_path) & kLogicalFormatMask;
+  LogicalSegmentLogicalFormat result = kLogicalSegmentLogicalFormatEightBit;
+  switch (logical_format) {
+    case LOGICAL_SEGMENT_FORMAT_EIGHT_BIT:
+      result = kLogicalSegmentLogicalFormatEightBit;
+      break;
+    case LOGICAL_SEGMENT_FORMAT_SIXTEEN_BIT:
+      result = kLogicalSegmentLogicalFormatSixteenBit;
+      break;
+    case LOGICAL_SEGMENT_FORMAT_THIRTY_TWO_BIT:
+      result = kLogicalSegmentLogicalFormatThirtyTwoBit;
+      break;
+    default:
+      OPENER_ASSERT(
+        "Logical segment/logical type: Invalid logical type detected!\n");
+      break;
+  }
+  return result;
+}
+
+LogicalSegmentExtendedLogicalType GetPathLogicalSegmentExtendedLogicalType(
+  const unsigned char *const cip_path) {
+//  OPENER_ASSERT(LOGICAL_SEGMENT_TYPE_EXTENDED_kLogicalSegmentLogicalTypeExtendedLogicalMessageValue == GetPathLogicalSegmentLogicalType(cip_path),
+//                "Trying to extract non-existent extended logical type");
+  OPENER_ASSERT( kLogicalSegmentLogicalTypeExtendedLogical == GetPathLogicalSegmentLogicalType(
+                   cip_path) );
+  const unsigned int extended_logical_type = *(cip_path + 1);
+  LogicalSegmentExtendedLogicalType result =
+    kLogicalSegmentExtendedLogicalTypeReserved;
+  switch(extended_logical_type) {
+    case LOGICAL_SEGMENT_EXTENDED_TYPE_ARRAY_INDEX: result =
+      kLogicalSegmentExtendedLogicalTypeArrayIndex; break;
+    case LOGICAL_SEGMENT_EXTENDED_TYPE_INDIRECT_ARRAY_INDEX: result =
+      kLogicalSegmentExtendedLogicalTypeIndirectArrayIndex; break;
+    case LOGICAL_SEGMENT_EXTENDED_TYPE_BIT_INDEX: result =
+      kLogicalSegmentExtendedLogicalTypeBitIndex; break;
+    case LOGICAL_SEGMENT_EXTENDED_TYPE_INDIRECT_BIT_INDEX: result =
+      kLogicalSegmentExtendedLogicalTypeIndirectBitIndex; break;
+    case LOGICAL_SEGMENT_EXTENDED_TYPE_STRUCTURE_MEMBER_NUMBER: result =
+      kLogicalSegmentExtendedLogicalTypeStructureMemberNumber; break;
+    case LOGICAL_SEGMENT_EXTENDED_TYPE_STRUCTURE_MEMBER_HANDLE: result =
+      kLogicalSegmentExtendedLogicalTypeStructureMemberHandle; break;
+    default: result = kLogicalSegmentExtendedLogicalTypeReserved;
+  }
+  return result;
+}
+
+LogicalSegmentSpecialTypeLogicalFormat
+GetPathLogicalSegmentSpecialTypeLogicalType(const unsigned char *const cip_path)
+{
+//  OPENER_ASSERT(kSegmentTypeLogicalSegment == GetPathSegmentType(cip_path), "Not a logical segment!\n");
+  OPENER_ASSERT( kSegmentTypeLogicalSegment == GetPathSegmentType(cip_path) );
+  OPENER_ASSERT( kLogicalSegmentLogicalTypeSpecial == GetPathLogicalSegmentLogicalType(
+                   cip_path) );
+  const unsigned int kLogicalFormatMask = 0x03;
+  const unsigned int logical_format = (*cip_path) & kLogicalFormatMask;
+
+  LogicalSegmentSpecialTypeLogicalFormat result =
+    kLogicalSegmentSpecialTypeLogicalFormatReserved;
+  switch(logical_format) {
+    case LOGICAL_SEGMENT_SPECIAL_TYPE_FORMAT_ELECTRONIC_KEY:
+      result = kLogicalSegmentSpecialTypeLogicalFormatElectronicKey; break;
+    default: result = kLogicalSegmentSpecialTypeLogicalFormatReserved; break;
+  }
+
+  return result;
+}
+
+ElectronicKeySegmentFormat GetPathLogicalSegmentElectronicKeyFormat(
+  const unsigned char *const cip_path) {
+//  OPENER_ASSERT(kLogicalSegmentSpecialTypeLogicalFormatElectronicKey ==
+//      GetPathLogicalSegmentSpecialTypeLogicalType(cip_path), "Not an electronic key!\n");
+  OPENER_ASSERT( kLogicalSegmentSpecialTypeLogicalFormatElectronicKey ==
+                 GetPathLogicalSegmentSpecialTypeLogicalType(cip_path) );
+  ElectronicKeySegmentFormat result = kElectronicKeySegmentFormatReserved;
+  switch( *(cip_path + 1) ) {
+    case ELECTRONIC_KEY_SEGMENT_KEY_FORMAT_4: result =
+      kElectronicKeySegmentFormatKeyFormat4; break;
+    default: result = kElectronicKeySegmentFormatReserved; break;
+  }
+  return result;
+}
+
+void GetPathLogicalSegmentElectronicKeyFormat4(
+  const unsigned char *const cip_path, ElectronicKeyFormat4 *key) {
+//  OPENER_ASSERT(kElectronicKeySegmentFormatKeyFormat4 ==
+//      GetPathLogicalSegmentElectronicKeyFormat(cip_path), "Not electronic key format 4!\n");
+  OPENER_ASSERT( kElectronicKeySegmentFormatKeyFormat4 ==
+                 GetPathLogicalSegmentElectronicKeyFormat(cip_path) );
+
+  const EipUint8 *message_runner = (const EipUint8 *)(cip_path + 2);
+  ElectronicKeyFormat4SetVendorId(GetIntFromMessage(&message_runner), key);
+  ElectronicKeyFormat4SetDeviceType(GetIntFromMessage(&message_runner), key);
+  ElectronicKeyFormat4SetProductCode(GetIntFromMessage(&message_runner), key);
+  ElectronicKeyFormat4SetMajorRevisionCompatibility(GetSintFromMessage(&
+                                                                       message_runner),
+                                                    key);
+  ElectronicKeyFormat4SetMinorRevision(GetSintFromMessage(&message_runner),
+                                       key);
+}
+
+/*** Logical Segment ***/
+
+
+/*** Network Segment ***/
+
+/** @brief Return the Network Segment subtype
+ *
+ *  @param cip_path Pointer to the start of the EPath message
+ *  @return The Network Segment subtype of the EPath
+ */
+NetworkSegmentSubtype GetPathNetworkSegmentSubtype(
+  const unsigned char *const cip_path) {
+  OPENER_ASSERT( kSegmentTypeNetworkSegment == GetPathSegmentType(cip_path) );
+  const unsigned int kSubtypeMask = 0x1F;
+  const unsigned int subtype = (*cip_path) & kSubtypeMask;
+  NetworkSegmentSubtype result = kNetworkSegmentSubtypeReserved;
+  switch(subtype) {
+    case NETWORK_SEGMENT_SCHEDULE:
+      result = kNetworkSegmentSubtypeScheduleSegment; break;
+    case NETWORK_SEGMENT_FIXED_TAG:
+      result = kNetworkSegmentSubtypeFixedTagSegment; break;
+    case NETWORK_SEGMENT_PRODUCTION_INHIBIT_TIME_IN_MILLISECONDS:
+      result = kNetworkSegmentSubtypeProductionInhibitTimeInMilliseconds; break;
+    case NETWORK_SEGMENT_SAFETY:
+      result = kNetworkSegmentSubtypeSafetySegment; break;
+    case NETWORK_SEGMENT_PRODUCTION_INHIBIT_TIME_IN_MICROSECONDS:
+      result = kNetworkSegmentSubtypeProductionInhibitTimeInMicroseconds; break;
+    case NETWORK_SEGMENT_EXTENDED_NETWORK:
+      result = kNetworkSegmentSubtypeExtendedNetworkSegment; break;
+    default: result = kNetworkSegmentSubtypeReserved; break;
+  }
+
+  return result;
+}
+
+/**
+ * @brief Return the Production Inhibit Time in milliseconds from an EPath
+ *
+ * @param cip_path Pointer to the start of the EPath message
+ * @return the Production Inhibit Time in milliseconds ranging from 0 to 255
+ */
+CipUsint GetPathNetworkSegmentProductionInhibitTimeInMilliseconds(
+  const unsigned char *const cip_path) {
+//  OPENER_ASSERT(kSegmentTypeNetworkSegment == GetPathSegmentType(cip_path),"Not a network segment!\n");
+//  OPENER_ASSERT(kNetworkSegmentSubtypeProductionInhibitTimeInMilliseconds == GetPathNetworkSegmentSubtype(cip_path),
+//                "Not a Production Inhibit Time milliseconds segment!\n");
+  OPENER_ASSERT( kSegmentTypeNetworkSegment == GetPathSegmentType(cip_path) );
+  OPENER_ASSERT( kNetworkSegmentSubtypeProductionInhibitTimeInMilliseconds == GetPathNetworkSegmentSubtype(
+                   cip_path) );
+  return *(cip_path + 1);
+}
+
+/**
+ * @brief Return the Production Inhibit Time in microseconds from an EPath
+ *
+ * @param cip_path Pointer to the start of the EPath message
+ * @return the Production Inhibit Time in microseconds ranging from 0 to 4294967295
+ */
+CipUdint GetPathNetworkSegmentProductionInhibitTimeInMicroseconds(
+  const unsigned char *const cip_path) {
+//  OPENER_ASSERT(kSegmentTypeNetworkSegment == GetPathSegmentType(cip_path),"Not a network segment!\n");
+//  OPENER_ASSERT(kNetworkSegmentSubtypeProductionInhibitTimeInMicroseconds == GetPathNetworkSegmentSubtype(cip_path),
+//                  "Not a Production Inhibit Time microseconds segment!\n");
+//  OPENER_ASSERT(2 == *(cip_path + 1), "Data Words length is incorrect! See CIP Spec Vol.1 C-1.4.3.3.2\n");
+
+  OPENER_ASSERT( kSegmentTypeNetworkSegment == GetPathSegmentType(cip_path) );
+  OPENER_ASSERT( kNetworkSegmentSubtypeProductionInhibitTimeInMicroseconds == GetPathNetworkSegmentSubtype(
+                   cip_path) );
+  OPENER_ASSERT( 2 == *(cip_path + 1) );
+
+  const unsigned char *message_runner = cip_path + 2;
+  return GetDintFromMessage(&message_runner);
+}
+
+/*** Network Segment ***/
+
+/*** Symbolic Segment ***/
+
+SymbolicSegmentFormat GetPathSymbolicSegmentFormat(
+  const unsigned char *const cip_path) {
+  const unsigned int kSymbolicSegmentFormatMask = 0x1F;
+  if( SYMBOLIC_SEGMENT_FORMAT_EXTENDED_STRING ==
+      (*cip_path & kSymbolicSegmentFormatMask) ) {
+    return kSymbolicSegmentFormatExtendedString;
+  }
+  return kSymbolicSegmentFormatASCII;
+}
+
+unsigned int GetPathSymbolicSegmentASCIIFormatLength(
+  const unsigned char *const cip_path) {
+  const unsigned int kSymbolicSegmentASCIIFormatLength = 0x1F;
+  const unsigned int length = *cip_path & kSymbolicSegmentASCIIFormatLength;
+  OPENER_ASSERT(0 != length);
+  return length;
+}
+
+SymbolicSegmentExtendedFormat GetPathSymbolicSegmentNumericType(
+  const unsigned char *const cip_path) {
+  const unsigned int kSymbolicSegmentExtendedFormatNumericTypeMask = 0x1F;
+  const unsigned int numeric_subtype = *(cip_path + 1) &
+                                       kSymbolicSegmentExtendedFormatNumericTypeMask;
+  SymbolicSegmentExtendedFormat result = kSymbolicSegmentExtendedFormatReserved;
+  switch(numeric_subtype) {
+    case SYMBOLIC_SEGMENT_EXTENDED_FORMAT_NUMERIC_USINT_TYPE: result =
+      kSymbolicSegmentExtendedFormatNumericSymbolUSINT; break;
+    case SYMBOLIC_SEGMENT_EXTENDED_FORMAT_NUMERIC_UINT_TYPE: result =
+      kSymbolicSegmentExtendedFormatNumericSymbolUINT; break;
+    case SYMBOLIC_SEGMENT_EXTENDED_FORMAT_NUMERIC_UDINT_TYPE: result =
+      kSymbolicSegmentExtendedFormatNumericSymbolUDINT; break;
+    default: result = kSymbolicSegmentExtendedFormatReserved; break;
+  }
+  return result;
+}
+
+SymbolicSegmentExtendedFormat GetPathSymbolicSegmentExtendedFormat(
+  const unsigned char *const cip_path) {
+  OPENER_ASSERT( kSegmentTypeSymbolicSegment == GetPathSegmentType(cip_path) );
+  OPENER_ASSERT( kSymbolicSegmentFormatExtendedString == GetPathSymbolicSegmentFormat(
+                   cip_path) );
+  const unsigned int kSymbolicSegmentExtendedFormatMask = 0xE0;
+  const unsigned int extended_type = *(cip_path + 1) &
+                                     kSymbolicSegmentExtendedFormatMask;
+  SymbolicSegmentExtendedFormat result = kSymbolicSegmentExtendedFormatReserved;
+  switch(extended_type) {
+    case SYMBOLIC_SEGMENT_EXTENDED_FORMAT_DOUBLE_CHAR: result =
+      kSymbolicSegmentExtendedFormatDoubleByteChars; break;
+    case SYMBOLIC_SEGMENT_EXTENDED_FORMAT_TRIPLE_CHAR: result =
+      kSymbolicSegmentExtendedFormatTripleByteChars; break;
+    case SYMBOLIC_SEGMENT_EXTENDED_FORMAT_NUMERIC: result =
+      GetPathSymbolicSegmentNumericType(cip_path); break;
+    default: result = kSymbolicSegmentExtendedFormatReserved; break;
+  }
+  return result;
+}
+
+/*** Symbolic Segment ***/
+
+/*** Data Segment ***/
+
+DataSegmentSubtype GetPathDataSegmentSubtype(const unsigned char *const cip_path)
+{
+  const unsigned int kDataSegmentSubtypeMask = 0x1F;
+  const unsigned int data_subtype = (*cip_path) & kDataSegmentSubtypeMask;
+
+  DataSegmentSubtype result = kDataSegmentSubtypeReserved;
+  switch(data_subtype) {
+    case DATA_SEGMENT_SUBTYPE_SIMPLE_DATA:
+      result = kDataSegmentSubtypeSimpleData; break;
+    case DATA_SEGMENT_SUBTYPE_ANSI_EXTENDED_SYMBOL:
+      result = kDataSegmentSubtypeANSIExtendedSymbol; break;
+    default: result = kDataSegmentSubtypeReserved; break;
+  }
+  return result;
+}
+
+/** @brief Returns the amount of 16-bit data words in the Simple Data EPath
+ *
+ * @param cip_path Pointer to the start of the EPath message
+ * @return The amount of 16-bit words of data in the EPath
+ */
+CipUsint GetPathDataSegmentSimpleDataWordLength(
+  const unsigned char *const cip_path) {
+//  OPENER_ASSERT(kSegmentTypeDataSegment == GetPathSegmentType(cip_path),"Not a data segment!\n");
+//  OPENER_ASSERT(kDataSegmentSubtypeSimpleData == GetPathDataSegmentSubtype(cip_path), "Not a simple data segment!\n");
+  OPENER_ASSERT( kSegmentTypeDataSegment == GetPathSegmentType(cip_path) );
+  OPENER_ASSERT( kDataSegmentSubtypeSimpleData ==
+                 GetPathDataSegmentSubtype(cip_path) );
+
+  const unsigned char *message_runner = cip_path + 1;
+  return GetSintFromMessage(&message_runner);
+}
+
+/*** Data Segment ***/
+

+ 340 - 0
source/src/cip/cipepath.h

@@ -0,0 +1,340 @@
+/*******************************************************************************
+ * Copyright (c) 2016, Rockwell Automation, Inc.
+ * All rights reserved.
+ *
+ ******************************************************************************/
+
+#ifndef SRC_CIP_CIPEPATH_H_
+#define SRC_CIP_CIPEPATH_H_
+
+#include <stdbool.h>
+
+#include "ciptypes.h"
+#include "cipelectronickey.h"
+
+#define SEGMENT_TYPE_PORT_SEGMENT 0x00 /**< Message value of the Port segment */
+#define SEGMENT_TYPE_LOGICAL_SEGMENT 0x20 /**< Message value of the Logical segment */
+#define SEGMENT_TYPE_NETWORK_SEGMENT 0x40 /**< Message value of the Network segment */
+#define SEGMENT_TYPE_SYMBOLIC_SEGMENT 0x60 /**< Message value of the Symbolic segment */
+#define SEGMENT_TYPE_DATA_SEGMENT 0x80 /**< Message value of the Data segment */
+#define SEGMENT_TYPE_DATA_TYPE_CONSTRUCTED 0xA0 /**< Message value of the Data type constructed */
+#define SEGMENT_TYPE_DATA_TYPE_ELEMENTARTY 0xC0 /**< Message value of the Data type elementary */
+#define SEGMENT_TYPE_SEGMENT_RESERVED 0xE0 /**< Reserved value */
+
+#define LOGICAL_SEGMENT_TYPE_CLASS_ID 0x00 /**< Message value of the logical segment/logical type Class ID */
+#define LOGICAL_SEGMENT_TYPE_INSTANCE_ID 0x04 /**< Message value of the logical segment/logical type Instance ID */
+#define LOGICAL_SEGMENT_TYPE_MEMBER_ID 0x08 /**< Message value of the logical segment/logical type Member ID */
+#define LOGICAL_SEGMENT_TYPE_CONNECTION_POINT 0x0C /**< Message value of the logical segment/logical type Connection Point */
+#define LOGICAL_SEGMENT_TYPE_ATTRIBUTE_ID 0x10 /**< Message value of the logical segment/logical type Attribute ID */
+#define LOGICAL_SEGMENT_TYPE_SPECIAL 0x14 /**< Message value of the logical segment/logical type Special */
+#define LOGICAL_SEGMENT_TYPE_SERVICE_ID 0x18 /**< Message value of the logical segment/logical type Service ID */
+#define LOGICAL_SEGMENT_TYPE_EXTENDED_LOGICAL 0x1C /**< Message value of the logical segment/logical type Extended Logical */
+
+#define LOGICAL_SEGMENT_FORMAT_EIGHT_BIT 0x00 /**< Message value indicating an 8 bit value */
+#define LOGICAL_SEGMENT_FORMAT_SIXTEEN_BIT 0x01 /**< Message value indicating an 16 bit value */
+#define LOGICAL_SEGMENT_FORMAT_THIRTY_TWO_BIT 0x02 /**< Message value indicating an 32 bit value */
+
+#define LOGICAL_SEGMENT_EXTENDED_TYPE_RESERVED 0x00 /**< Message value indicating an reserved/unused Extended Logical Segment type */
+#define LOGICAL_SEGMENT_EXTENDED_TYPE_ARRAY_INDEX 0x01 /**< Message value indicating the Array Index Extended Logical Segment type */
+#define LOGICAL_SEGMENT_EXTENDED_TYPE_INDIRECT_ARRAY_INDEX 0x02 /**< Message value indicating the Indirect Array Index Extended Logical Segment type */
+#define LOGICAL_SEGMENT_EXTENDED_TYPE_BIT_INDEX 0x03 /**< Message value indicating the Bit Index Extended Logical Segment type */
+#define LOGICAL_SEGMENT_EXTENDED_TYPE_INDIRECT_BIT_INDEX 0x04 /**< Message value indicating the Indirect Bit Index Extended Logical Segment type */
+#define LOGICAL_SEGMENT_EXTENDED_TYPE_STRUCTURE_MEMBER_NUMBER 0x05 /**< Message value indicating the Structured Member Number Extended Logical Segment type */
+#define LOGICAL_SEGMENT_EXTENDED_TYPE_STRUCTURE_MEMBER_HANDLE 0x06 /**< Message value indicating the Structured Member Handler Extended Logical Segment type */
+
+#define LOGICAL_SEGMENT_SPECIAL_TYPE_FORMAT_ELECTRONIC_KEY 0x00 /**< Message value indicating an electronic key */
+
+#define NETWORK_SEGMENT_SUBTYPE_SCHEDULE 0x01 /**< Message value indicating a network segment schedule message */
+#define NETWORK_SEGMENT_SUBTYPE_FIXED_TAG 0x02 /**< Message value indicating a network segment fixed tag message */
+#define NETWORK_SEGMENT_SUBTYPE_PRODUCTION_INHIBIT_TIME_IN_MILLISECONDS 0x03 /**< Message value indicating a network segment PIT in milliseconds message */
+#define NETWORK_SEGMENT_SUBTYPE_SAFETY 0x04 /**< Message value indicating a network segment safety message */
+#define NETWORK_SEGMENT_SUBTYPE_PRODUCTION_INHIBIT_TIME_IN_MICROSECONDS 0x10 /**< Message value indicating a network segment PIT in microseconds message */
+#define NETWORK_SEGMENT_SUBTYPE_EXTENDED_NETWORK 0x1F /**< Message indicating a network message extended network message */
+
+/** @brief Segment type Enum
+ *
+ * Bits 7-5 in the Segment Type/Format byte
+ *
+ */
+typedef enum segment_type {
+  /* Segments */
+  kSegmentTypePortSegment, /**< Port segment */
+  kSegmentTypeLogicalSegment, /**< Logical segment */
+  kSegmentTypeNetworkSegment, /**< Network segment */
+  kSegmentTypeSymbolicSegment, /**< Symbolic segment */
+  kSegmentTypeDataSegment, /**< Data segment */
+  kSegmentTypeDataTypeConstructed, /**< Data type constructed */
+  kSegmentTypeDataTypeElementary, /**< Data type elementary */
+  kSegmentTypeReserved /**< Reserved segment type */
+} SegmentType;
+
+/** @brief Port Segment flags */
+typedef enum port_segment_type {
+  kPortSegmentFlagExtendedLinkAddressSize = 0x10 /**< Extended Link Address Size flag, Port segment */
+} PortSegmentFlag;
+
+/** @brief Enum containing values which kind of logical segment is encoded */
+typedef enum logical_segment_type {
+  kLogicalSegmentLogicalTypeClassId, /**< Class ID */
+  kLogicalSegmentLogicalTypeInstanceId, /**< Instance ID */
+  kLogicalSegmentLogicalTypeMemberId, /**< Member ID */
+  kLogicalSegmentLogicalTypeConnectionPoint, /**< Connection Point */
+  kLogicalSegmentLogicalTypeAttributeId, /**< Attribute ID */
+  kLogicalSegmentLogicalTypeSpecial, /**< Special */
+  kLogicalSegmentLogicalTypeServiceId, /**< Service ID */
+  kLogicalSegmentLogicalTypeExtendedLogical /**< Extended Logical */
+} LogicalSegmentLogicalType;
+
+typedef enum logical_segment_extended_logical_type {
+  kLogicalSegmentExtendedLogicalTypeReserved,
+  kLogicalSegmentExtendedLogicalTypeArrayIndex,
+  kLogicalSegmentExtendedLogicalTypeIndirectArrayIndex,
+  kLogicalSegmentExtendedLogicalTypeBitIndex,
+  kLogicalSegmentExtendedLogicalTypeIndirectBitIndex,
+  kLogicalSegmentExtendedLogicalTypeStructureMemberNumber,
+  kLogicalSegmentExtendedLogicalTypeStructureMemberHandle
+} LogicalSegmentExtendedLogicalType;
+
+/** @brief Enum containing values how long the encoded value will be (8, 16, or
+ * 32 bit) */
+typedef enum logical_segment_logical_format {
+  kLogicalSegmentLogicalFormatEightBit,
+  kLogicalSegmentLogicalFormatSixteenBit,
+  kLogicalSegmentLogicalFormatThirtyTwoBit
+} LogicalSegmentLogicalFormat;
+
+typedef enum logical_segment_special_type_logical_format {
+  kLogicalSegmentSpecialTypeLogicalFormatReserved,
+  kLogicalSegmentSpecialTypeLogicalFormatElectronicKey
+} LogicalSegmentSpecialTypeLogicalFormat;
+
+/** @brief Electronic key formats
+ *
+ */
+typedef enum electronic_key_segment_format {
+  kElectronicKeySegmentFormatReserved, /**< Reserved */
+  kElectronicKeySegmentFormatKeyFormat4 /**< Electronic key format 4 key */
+} ElectronicKeySegmentFormat;
+
+/** @brief All types of network segment types for the use in all code
+ *
+ *  Enum constants for the different network segment subtypes to decouple code from the actual needed message values
+ */
+typedef enum network_segment_subtype {
+  kNetworkSegmentSubtypeReserved, /**< Reserverd */
+  kNetworkSegmentSubtypeScheduleSegment, /**< Schedule segment */
+  kNetworkSegmentSubtypeFixedTagSegment, /**< Fixed tag segment */
+  kNetworkSegmentSubtypeProductionInhibitTimeInMilliseconds, /**< Production Inhibit Time in milliseconds segment */
+  kNetworkSegmentSubtypeSafetySegment, /**< Safety segment */
+  kNetworkSegmentSubtypeProductionInhibitTimeInMicroseconds, /**< Production Inhibit Time in microseconds segment */
+  kNetworkSegmentSubtypeExtendedNetworkSegment /**< Extended network segment */
+} NetworkSegmentSubtype;
+
+/** @brief Data segment sub types
+ *
+ */
+typedef enum data_segment_subtype {
+  kDataSegmentSubtypeReserved, /**< Reserved */
+  kDataSegmentSubtypeSimpleData, /**< Simple Data segment */
+  kDataSegmentSubtypeANSIExtendedSymbol /**< ANSI extended symbol segment */
+} DataSegmentSubtype;
+
+/** @brief Symbolic segment formats
+ *
+ */
+typedef enum symbolic_segment_format {
+  kSymbolicSegmentFormatASCII, /**< ASCII format */
+  kSymbolicSegmentFormatExtendedString /**< Extended String format */
+} SymbolicSegmentFormat;
+
+/** @brief Extended symbolic symbol formats
+ *
+ */
+typedef enum symbolic_segment_extended_format {
+  kSymbolicSegmentExtendedFormatDoubleByteChars, /**< Double byte character encoding */
+  kSymbolicSegmentExtendedFormatTripleByteChars, /**< Triple byte character encoding */
+  kSymbolicSegmentExtendedFormatNumericSymbolUSINT, /**< Numeric USINT symbol */
+  kSymbolicSegmentExtendedFormatNumericSymbolUINT, /**< Numeric UINT symbol */
+  kSymbolicSegmentExtendedFormatNumericSymbolUDINT, /**< Numeric UDINT symbol */
+  kSymbolicSegmentExtendedFormatReserved /**< Reserved */
+} SymbolicSegmentExtendedFormat;
+
+/** @brief Gets the basic segment type of a CIP EPath
+ *
+ * @param cip_path The start of the EPath message
+ * @return The basic segment type
+ */
+SegmentType GetPathSegmentType(const unsigned char *const cip_path);
+
+/** @brief Sets the basic segment type of an CIP EPath to be sent
+ *
+ * @param segment_type The segment type
+ * @param cip_path A message buffer - Will be written on!
+ */
+void SetPathSegmentType(SegmentType segment_type,unsigned char *const cip_path);
+
+/*********************************************************
+* Port Segment functions
+*********************************************************/
+
+/** @brief Only to be used on Port Segments. Returns if the Port Segment has the extended link address size bit set
+ *
+ * @param cip_path The start of the EPath message
+ * @return True if extended link addres size bit set, false otherwise
+ */
+bool GetPathPortSegmentExtendedLinkAddressSizeBit(
+  const unsigned char *const cip_path);
+
+/** @brief Only to be used on Port Segments. Returns the Port Identifier
+ *
+ * @param cip_path The start of the EPath message
+ * @return The Port Identifier
+ */
+unsigned int GetPathPortSegmentPortIdentifier(
+  const unsigned char *const cip_path);
+
+/** @brief Sets the Port Identifier form an Port Segment EPath to be sent.
+ *
+ * @param port_identifier The port identifier
+ * @param cip_path A message buffer - Will be written on!
+ */
+void SetPathPortSegmentPortIdentifier(const unsigned int port_identifier,
+                                      unsigned char *const cip_path);
+
+/** @brief Only to be used on Port Segments. Gets the Link Address Size
+ *
+ * @param cip_path The start of the EPath message
+ * @return The Link Address Size
+ */
+unsigned int GetPathPortSegmentLinkAddressSize(
+  const unsigned char *const cip_path);
+
+/** @brief Only to be used on Port Segments with Extended Port Number. Gets the Extended Port Number
+ *
+ * @param cip_path The start of the EPath message
+ * @return The Link Address Size
+ */
+unsigned int GetPathPortSegmentExtendedPortNumber(
+  const unsigned char *const cip_path);
+
+/** @brief Sets the Extended Port Identifier in a EPath Port Segment message
+ *
+ * @param extended_port_identifier The extended port identifier to be encoded into the message
+ * @param cip_path The start for the EPatch message
+ */
+void SetPathPortSegmentExtendedPortIdentifier(
+  const unsigned int extended_port_identifier, unsigned char *const cip_path);
+
+/** @brief Gets the Logical Type of an EPath Logical Segment message
+ *
+ * @param cip_path The start of the EPath message
+ * @return The logical type of the logical segment
+ */
+LogicalSegmentLogicalType GetPathLogicalSegmentLogicalType(
+  const unsigned char *const cip_path);
+
+/** @brief Gets the Logical Format of a Logical Segment EPath message
+ *
+ * @param cip_path The start of the EPath message
+ * @return The logical format of the logical format
+ */
+LogicalSegmentLogicalFormat GetPathLogicalSegmentLogicalFormat(
+  const unsigned char *const cip_path);
+
+/** @brief  Gets the Extended Logical Type of a Logical Segment EPath message
+ *
+ * @param cip_path The start of the EPath message
+ * @return The extended logical type of the logical segment
+ */
+LogicalSegmentExtendedLogicalType GetPathLogicalSegmentExtendedLogicalType(
+  const unsigned char *const cip_path);
+
+/** @brief Gets the Special Type Logical Type of a Logical Segment EPath message
+ *
+ * @param cip_path The start of the EPath message
+ * @return The Special Type Logical Format subtype of a Logical Segment EPath message
+ */
+LogicalSegmentSpecialTypeLogicalFormat
+GetPathLogicalSegmentSpecialTypeLogicalType(const unsigned char *const cip_path);
+
+/** @brief Gets the Electronic Key format of a Logical Segment Special Type EPath message
+ *
+ * @param cip_path The start of the EPath message
+ * @return The Electronic Key Format used in the EPath
+ */
+ElectronicKeySegmentFormat GetPathLogicalSegmentElectronicKeyFormat(
+  const unsigned char *const cip_path);
+
+/** @brief Gets the data for an Electronic Key of format 4 from the EPath message
+ *
+ * @param cip_path The start of the EPath message
+ * @param Writes the data on the user provided data electronic key struct
+ */
+void GetPathLogicalSegmentElectronicKeyFormat4(
+  const unsigned char *const cip_path, ElectronicKeyFormat4 *key);
+
+/** @brief Gets the Network Segment Subtype of a EPatch Network Segement EPath message
+ *
+ * @param cip_path The start of the EPath message
+ * @return Network Segment subtype
+ */
+NetworkSegmentSubtype GetPathNetworkSegmentSubtype(
+  const unsigned char *const cip_path);
+
+/** @brief Gets the Production Inhibit Time in Milliseconds
+ *
+ * @param cip_path The start of the EPath message
+ * @return The production Inhibit Time in Milliseconds
+ */
+CipUsint GetPathNetworkSegmentProductionInhibitTimeInMilliseconds(
+  const unsigned char *const cip_path);
+
+/** @brief Gets the Production Inhibit Time in Microseconds
+ *
+ * @param cip_path The start of the EPath message
+ * @return The production Inhibit Time in Microseconds
+ */
+CipUdint GetPathNetworkSegmentProductionInhibitTimeInMicroseconds(
+  const unsigned char *const cip_path);
+
+/** @brief Gets the Data Segment subtype of a Data Segment EPath message
+ *
+ * @param cip_path The start of the EPath message
+ * @return The Data Segment subtype
+ */
+DataSegmentSubtype GetPathDataSegmentSubtype(
+  const unsigned char *const cip_path);
+
+/** @brief Gets the data word length of a Simple Data segment
+ *
+ * @param cip_path The start of the EPath message
+ * @return The length in words of the Simple Data segment
+ */
+CipUsint GetPathDataSegmentSimpleDataWordLength(
+  const unsigned char *const cip_path);
+
+/** @brief Gets the Symbolic Segment Format of the Symbolic Segment EPath message
+ *
+ * @param cip_path The start of the EPath message
+ * @return The Symbolic Segment Format
+ */
+SymbolicSegmentFormat GetPathSymbolicSegmentFormat(
+  const unsigned char *const cip_path);
+
+/** @brief Gets the Numeric subtype of a Symbolic Segment Extended Format EPath message
+ *
+ * @param cip_path The start of the EPath message
+ * @return The Numeric Extended Format subtype
+ */
+SymbolicSegmentExtendedFormat GetPathSymbolicSegmentNumericType(
+  const unsigned char *const cip_path);
+
+/** @brief Gets the Extended Format subtype of a Symbolic Segment EPath message
+ *
+ * @param cip_path The start of the EPath message
+ * @return Symbolic Segment Extended Format
+ */
+SymbolicSegmentExtendedFormat GetPathSymbolicSegmentExtendedFormat(
+  const unsigned char *const cip_path);
+
+#endif /* SRC_CIP_CIPEPATH_H_ */

+ 27 - 24
source/src/cip/cipidentity.c

@@ -1,6 +1,6 @@
 /*******************************************************************************
  * Copyright (c) 2009, Rockwell Automation, Inc.
- * All rights reserved. 
+ * All rights reserved.
  *
  ******************************************************************************/
 
@@ -41,11 +41,11 @@ EipUint16 vendor_id_ = OPENER_DEVICE_VENDOR_ID; /**< Attribute 1: Vendor ID */
 EipUint16 device_type_ = OPENER_DEVICE_TYPE; /**< Attribute 2: Device Type */
 EipUint16 product_code_ = OPENER_DEVICE_PRODUCT_CODE; /**< Attribute 3: Product Code */
 CipRevision revision_ = { OPENER_DEVICE_MAJOR_REVISION,
-    OPENER_DEVICE_MINOR_REVISION }; /**< Attribute 4: Revision / USINT Major, USINT Minor */
+                          OPENER_DEVICE_MINOR_REVISION }; /**< Attribute 4: Revision / USINT Major, USINT Minor */
 EipUint16 status_ = 0; /**< Attribute 5: Status */
 EipUint32 serial_number_ = 0; /**< Attribute 6: Serial Number, has to be set prior to OpENer initialization */
 CipShortString product_name_ = { sizeof(OPENER_DEVICE_NAME) - 1,
-    OPENER_DEVICE_NAME }; /**< Attribute 7: Product Name */
+                                 OPENER_DEVICE_NAME }; /**< Attribute 7: Product Name */
 
 /** Private functions, sets the devices serial number
  * @param serial_number The serial number of the device
@@ -68,34 +68,36 @@ void SetDeviceStatus(const EipUint16 status) {
  * @param message_router_response
  * @returns Currently always kEipOkSend is returned
  */
-static EipStatus Reset(CipInstance *instance, /* pointer to instance*/
-                       CipMessageRouterRequest *message_router_request, /* pointer to message router request*/
-                       CipMessageRouterResponse *message_router_response) /* pointer to message router response*/
-{
+static EipStatus Reset(CipInstance *instance,
+                       /* pointer to instance*/
+                       CipMessageRouterRequest *message_router_request,
+                       /* pointer to message router request*/
+                       CipMessageRouterResponse *message_router_response,
+                       struct sockaddr_in *originator_address) {                      /* pointer to message router response*/
   (void) instance;
 
   EipStatus eip_status = kEipStatusOkSend;
 
   message_router_response->reply_service = (0x80
-      | message_router_request->service);
+                                            | message_router_request->service);
   message_router_response->size_of_additional_status = 0;
   message_router_response->general_status = kCipErrorSuccess;
 
-  if (message_router_request->data_length == 1) {
+  if (message_router_request->request_path_size == 1) {
     switch (message_router_request->data[0]) {
       case 0: /* Reset type 0 -> emulate device reset / Power cycle */
-        if (kEipStatusError == ResetDevice()) {
+        if ( kEipStatusError == ResetDevice() ) {
           message_router_response->general_status = kCipErrorInvalidParameter;
         }
         break;
 
       case 1: /* Reset type 1 -> reset to device settings */
-        if (kEipStatusError == ResetDeviceToInitialConfiguration()) {
+        if ( kEipStatusError == ResetDeviceToInitialConfiguration() ) {
           message_router_response->general_status = kCipErrorInvalidParameter;
         }
         break;
 
-        /* case 2: Not supported Reset type 2 -> Return to factory defaults except communications parameters */
+      /* case 2: Not supported Reset type 2 -> Return to factory defaults except communications parameters */
 
       default:
         message_router_response->general_status = kCipErrorInvalidParameter;
@@ -104,9 +106,9 @@ static EipStatus Reset(CipInstance *instance, /* pointer to instance*/
   } else  /*TODO: Should be if (pa_stMRRequest->DataLength == 0)*/
   {
     /* The same behavior as if the data value given would be 0
-     emulate device reset */
+       emulate device reset */
 
-    if (kEipStatusError == ResetDevice()) {
+    if ( kEipStatusError == ResetDevice() ) {
       message_router_response->general_status = kCipErrorInvalidParameter;
     } else {
       /* eip_status = EIP_OK; */
@@ -119,17 +121,18 @@ static EipStatus Reset(CipInstance *instance, /* pointer to instance*/
 EipStatus CipIdentityInit() {
 
   CipClass *class = CreateCipClass(kIdentityClassCode, 0, /* # of non-default class attributes */
-                         MASK4(1, 2, 6, 7), /* class getAttributeAll mask		CIP spec 5-2.3.2 */
-                         0, /* # of class services*/
-                         7, /* # of instance attributes*/
-                         MASK7(1, 2, 3, 4, 5, 6, 7), /* instance getAttributeAll mask	CIP spec 5-2.3.2 */
-                         1, /* # of instance services*/
-                         1, /* # of instances*/
-                         "identity", /* class name (for debug)*/
-                         1); /* class revision*/
-
-  if (class == 0)
+                                   MASK4(1, 2, 6, 7), /* class getAttributeAll mask		CIP spec 5-2.3.2 */
+                                   0, /* # of class services*/
+                                   7, /* # of instance attributes*/
+                                   MASK7(1, 2, 3, 4, 5, 6, 7), /* instance getAttributeAll mask	CIP spec 5-2.3.2 */
+                                   1, /* # of instance services*/
+                                   1, /* # of instances*/
+                                   "identity", /* class name (for debug)*/
+                                   1); /* class revision*/
+
+  if (class == 0) {
     return kEipStatusError;
+  }
 
   CipInstance *instance = GetCipInstance(class, 1);
 

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 434 - 301
source/src/cip/cipioconnection.c


+ 4 - 3
source/src/cip/cipioconnection.h

@@ -52,8 +52,9 @@
  *    - EIP_OK ... on success
  *    - On an error the general status code to be put into the response
  */
-EipStatus EstablishIoConnction(ConnectionObject *RESTRICT const connection_object,
-                         EipUint16 *const extended_error);
+EipStatus EstablishIoConnection(
+  ConnectionObject *RESTRICT const connection_object,
+  EipUint16 *const extended_error);
 
 /** @brief Take the data given in the connection object structure and open the necessary communication channels
  *
@@ -71,7 +72,7 @@ EipStatus OpenCommunicationChannels(ConnectionObject *connection_object);
  * @param connection_object pointer to the connection object data
  */
 void CloseCommunicationChannelsAndRemoveFromActiveConnectionsList(
-    ConnectionObject *connection_object);
+  ConnectionObject *connection_object);
 
 extern EipUint8 *g_config_data_buffer;
 extern unsigned int g_config_data_length;

+ 80 - 57
source/src/cip/cipmessagerouter.c

@@ -1,6 +1,6 @@
 /*******************************************************************************
  * Copyright (c) 2009, Rockwell Automation, Inc.
- * All rights reserved. 
+ * All rights reserved.
  *
  ******************************************************************************/
 #include "opener_api.h"
@@ -17,7 +17,7 @@ CipMessageRouterResponse g_message_router_response;
  *
  * A linked list of this  object is the registry of classes known to the message router
  * for small devices with very limited memory it could make sense to change this list into an
- * array with a given max size for removing the need for having to dynamically allocate 
+ * array with a given max size for removing the need for having to dynamically allocate
  * memory. The size of the array could be a parameter in the platform config file.
  */
 typedef struct cip_message_router_object {
@@ -36,7 +36,7 @@ CipMessageRouterObject *g_first_object = NULL;
 EipStatus RegisterCipClass(CipClass *cip_class);
 
 /** @brief Create Message Router Request structure out of the received data.
- * 
+ *
  * Parses the UCMM header consisting of: service, IOI size, IOI, data into a request structure
  * @param data pointer to the message data received
  * @param data_length number of bytes in the message
@@ -44,23 +44,25 @@ EipStatus RegisterCipClass(CipClass *cip_class);
  * @return kEipStatusOk on success. otherwise kEipStatusError
  */
 CipError CreateMessageRouterRequestStructure(
-    const EipUint8 *data, EipInt16 data_length,
-    CipMessageRouterRequest *message_router_request);
+  const EipUint8 *data,
+  EipInt16 data_length,
+  CipMessageRouterRequest *message_router_request);
 
 EipStatus CipMessageRouterInit() {
 
   CipClass *message_router = CreateCipClass(kCipMessageRouterClassCode, /* class ID*/
-                                  0, /* # of class attributes */
-                                  0xffffffff, /* class getAttributeAll mask*/
-                                  0, /* # of class services*/
-                                  0, /* # of instance attributes*/
-                                  0xffffffff, /* instance getAttributeAll mask*/
-                                  0, /* # of instance services*/
-                                  1, /* # of instances*/
-                                  "message router", /* class name*/
-                                  1); /* revision */
-  if (message_router == NULL)
+                                            0, /* # of class attributes */
+                                            0xffffffff, /* class getAttributeAll mask*/
+                                            0, /* # of class services*/
+                                            0, /* # of instance attributes*/
+                                            0xffffffff, /* instance getAttributeAll mask*/
+                                            0, /* # of instance services*/
+                                            1, /* # of instances*/
+                                            "message router", /* class name*/
+                                            1); /* revision */
+  if (NULL == message_router) {
     return kEipStatusError;
+  }
 
   /* reserved for future use -> set to zero */
   g_message_router_response.reserved = 0;
@@ -82,8 +84,9 @@ CipMessageRouterObject *GetRegisteredObject(EipUint32 class_id) {
   while (NULL != object) /* for each entry in list*/
   {
     OPENER_ASSERT(object->cip_class != NULL);
-    if (object->cip_class->class_id == class_id)
+    if (object->cip_class->class_id == class_id) {
       return object; /* return registration node if it matches class ID*/
+    }
     object = object->next;
   }
   return NULL;
@@ -92,22 +95,28 @@ CipMessageRouterObject *GetRegisteredObject(EipUint32 class_id) {
 CipClass *GetCipClass(const EipUint32 class_id) {
   CipMessageRouterObject *message_router_object = GetRegisteredObject(class_id);
 
-  if (message_router_object)
+  if (message_router_object) {
     return message_router_object->cip_class;
-  else
+  }
+  else{
     return NULL;
+  }
 }
 
-CipInstance *GetCipInstance(const CipClass *RESTRICT const cip_class, EipUint32 instance_number) {
+CipInstance *GetCipInstance(const CipClass *RESTRICT const cip_class,
+                            EipUint32 instance_number) {
 
-  if (instance_number == 0)
+  if (instance_number == 0) {
     return (CipInstance *) cip_class; /* if the instance number is zero, return the class object itself*/
 
+  }
   /* pointer to linked list of instances from the class object*/
-  for (CipInstance *instance = cip_class->instances; instance; instance = instance->next) /* follow the list*/
+  for (CipInstance *instance = cip_class->instances; instance;
+       instance = instance->next)                                                         /* follow the list*/
   {
-    if (instance->instance_number == instance_number)
+    if (instance->instance_number == instance_number) {
       return instance; /* if the number matches, return the instance*/
+    }
   }
 
   return NULL;
@@ -116,76 +125,85 @@ CipInstance *GetCipInstance(const CipClass *RESTRICT const cip_class, EipUint32
 EipStatus RegisterCipClass(CipClass *cip_class) {
   CipMessageRouterObject **message_router_object = &g_first_object;
 
-  while (*message_router_object)
+  while (*message_router_object) {
     message_router_object = &(*message_router_object)->next; /* follow the list until p points to an empty link (list end)*/
 
+  }
   *message_router_object = (CipMessageRouterObject *) CipCalloc(
-      1, sizeof(CipMessageRouterObject)); /* create a new node at the end of the list*/
-  if (*message_router_object == 0)
+    1, sizeof(CipMessageRouterObject) );  /* create a new node at the end of the list*/
+  if (*message_router_object == 0) {
     return kEipStatusError; /* check for memory error*/
 
+  }
   (*message_router_object)->cip_class = cip_class; /* fill in the new node*/
   (*message_router_object)->next = NULL;
 
   return kEipStatusOk;
 }
 
-EipStatus NotifyMessageRouter(EipUint8 *data, int data_length) {
+EipStatus NotifyMessageRouter(EipUint8 *data,
+                              int data_length,
+                              struct sockaddr *originator_address) {
   EipStatus eip_status = kEipStatusOkSend;
   EipByte status = kCipErrorSuccess;
 
   g_message_router_response.data = g_message_data_reply_buffer; /* set reply buffer, using a fixed buffer (about 100 bytes) */
 
   OPENER_TRACE_INFO("NotifyMessageRouter: routing unconnected message\n");
-  if (kCipErrorSuccess
-      != (status = CreateMessageRouterRequestStructure(
-          data, data_length, &g_message_router_request))) { /* error from create MR structure*/
-    OPENER_TRACE_ERR("NotifyMessageRouter: error from createMRRequeststructure\n");
+  if ( kCipErrorSuccess
+       != ( status = CreateMessageRouterRequestStructure(
+              data, data_length, &g_message_router_request) ) ) { /* error from create MR structure*/
+    OPENER_TRACE_ERR(
+      "NotifyMessageRouter: error from createMRRequeststructure\n");
     g_message_router_response.general_status = status;
     g_message_router_response.size_of_additional_status = 0;
     g_message_router_response.reserved = 0;
     g_message_router_response.data_length = 0;
     g_message_router_response.reply_service = (0x80
-        | g_message_router_request.service);
+                                               | g_message_router_request.
+                                               service);
   } else {
     /* forward request to appropriate Object if it is registered*/
     CipMessageRouterObject *registered_object = GetRegisteredObject(
-        g_message_router_request.request_path.class_id);
+      g_message_router_request.request_path.class_id);
     if (registered_object == 0) {
       OPENER_TRACE_ERR(
-          "NotifyMessageRouter: sending CIP_ERROR_OBJECT_DOES_NOT_EXIST reply, class id 0x%x is not registered\n",
-          (unsigned ) g_message_router_request.request_path.class_id);
+        "NotifyMessageRouter: sending CIP_ERROR_OBJECT_DOES_NOT_EXIST reply, class id 0x%x is not registered\n",
+        (unsigned ) g_message_router_request.request_path.class_id);
       g_message_router_response.general_status =
-          kCipErrorPathDestinationUnknown; /*according to the test tool this should be the correct error flag instead of CIP_ERROR_OBJECT_DOES_NOT_EXIST;*/
+        kCipErrorPathDestinationUnknown;   /*according to the test tool this should be the correct error flag instead of CIP_ERROR_OBJECT_DOES_NOT_EXIST;*/
       g_message_router_response.size_of_additional_status = 0;
       g_message_router_response.reserved = 0;
       g_message_router_response.data_length = 0;
       g_message_router_response.reply_service = (0x80
-          | g_message_router_request.service);
+                                                 | g_message_router_request.
+                                                 service);
     } else {
       /* call notify function from Object with ClassID (gMRRequest.RequestPath.ClassID)
-       object will or will not make an reply into gMRResponse*/
+         object will or will not make an reply into gMRResponse*/
       g_message_router_response.reserved = 0;
       OPENER_ASSERT(NULL != registered_object->cip_class);
-      OPENER_TRACE_INFO("NotifyMessageRouter: calling notify function of class '%s'\n",
-                        registered_object->cip_class->class_name);
+      OPENER_TRACE_INFO(
+        "NotifyMessageRouter: calling notify function of class '%s'\n",
+        registered_object->cip_class->class_name);
       eip_status = NotifyClass(registered_object->cip_class,
                                &g_message_router_request,
-                               &g_message_router_response);
+                               &g_message_router_response,
+                               originator_address);
 
 #ifdef OPENER_TRACE_ENABLED
       if (eip_status == kEipStatusError) {
         OPENER_TRACE_ERR(
-            "notifyMR: notify function of class '%s' returned an error\n",
-            registered_object->cip_class->class_name);
+          "notifyMR: notify function of class '%s' returned an error\n",
+          registered_object->cip_class->class_name);
       } else if (eip_status == kEipStatusOk) {
         OPENER_TRACE_INFO(
-            "notifyMR: notify function of class '%s' returned no reply\n",
-            registered_object->cip_class->class_name);
+          "notifyMR: notify function of class '%s' returned no reply\n",
+          registered_object->cip_class->class_name);
       } else {
         OPENER_TRACE_INFO(
-            "notifyMR: notify function of class '%s' returned a reply\n",
-            registered_object->cip_class->class_name);
+          "notifyMR: notify function of class '%s' returned a reply\n",
+          registered_object->cip_class->class_name);
       }
 #endif
     }
@@ -194,26 +212,30 @@ EipStatus NotifyMessageRouter(EipUint8 *data, int data_length) {
 }
 
 CipError CreateMessageRouterRequestStructure(
-    const EipUint8 *data, EipInt16 data_length,
-    CipMessageRouterRequest *message_router_request) {
+  const EipUint8 *data,
+  EipInt16 data_length,
+  CipMessageRouterRequest *message_router_request) {
 
   message_router_request->service = *data;
   data++;  /*TODO: Fix for 16 bit path lengths (+1 */
   data_length--;
 
   int number_of_decoded_bytes = DecodePaddedEPath(
-      &(message_router_request->request_path), &data);
+    &(message_router_request->request_path), &data);
   if (number_of_decoded_bytes < 0) {
     return kCipErrorPathSegmentError;
   }
 
   message_router_request->data = data;
-  message_router_request->data_length = data_length - number_of_decoded_bytes;
+  message_router_request->request_path_size = data_length -
+                                              number_of_decoded_bytes;
 
-  if (message_router_request->data_length < 0)
+  if (message_router_request->request_path_size < 0) {
     return kCipErrorPathSizeInvalid;
-  else
+  }
+  else{
     return kCipErrorSuccess;
+  }
 }
 
 void DeleteAllClasses(void) {
@@ -239,14 +261,15 @@ void DeleteAllClasses(void) {
 
     /*clear meta class data*/
     CipFree(
-        message_router_object_to_delete->cip_class->class_instance.cip_class
-            ->class_name);
+      message_router_object_to_delete->cip_class->class_instance.cip_class
+      ->class_name);
     CipFree(
-        message_router_object_to_delete->cip_class->class_instance.cip_class
-            ->services);
+      message_router_object_to_delete->cip_class->class_instance.cip_class
+      ->services);
     CipFree(message_router_object_to_delete->cip_class->class_instance.cip_class);
     /*clear class data*/
-    CipFree(message_router_object_to_delete->cip_class->class_instance.attributes);
+    CipFree(
+      message_router_object_to_delete->cip_class->class_instance.attributes);
     CipFree(message_router_object_to_delete->cip_class->services);
     CipFree(message_router_object_to_delete->cip_class);
     CipFree(message_router_object_to_delete);

+ 7 - 5
source/src/cip/cipmessagerouter.h

@@ -1,6 +1,6 @@
 /*******************************************************************************
  * Copyright (c) 2009, Rockwell Automation, Inc.
- * All rights reserved. 
+ * All rights reserved.
  *
  ******************************************************************************/
 #ifndef OPENER_CIPMESSAGEROUTER_H_
@@ -12,9 +12,9 @@
 static const int kCipMessageRouterClassCode = 0x02;
 
 /** @brief Structure for storing the Response generated by an explict message.
- * 
+ *
  *  This buffer will be used for storing the result. The response message will be generated
- *  by assembleLinearMsg. 
+ *  by assembleLinearMsg.
  */
 extern CipMessageRouterResponse g_message_router_response;
 
@@ -36,9 +36,11 @@ void DeleteAllClasses(void);
  *  @param data pointer to the data buffer of the message directly at the beginning of the CIP part.
  *  @param data_length number of bytes in the data buffer
  *  @return  EIP_ERROR on fault
- *           EIP_OK on success           
+ *           EIP_OK on success
  */
-EipStatus NotifyMessageRouter(EipUint8 *data, int data_length);
+EipStatus NotifyMessageRouter(EipUint8 *data,
+                              int data_length,
+                              struct sockaddr *originator_address);
 
 /*! Register a class at the message router.
  *  In order that the message router can deliver

+ 18 - 12
source/src/cip/ciptcpipinterface.c

@@ -1,6 +1,6 @@
 /*******************************************************************************
  * Copyright (c) 2009, Rockwell Automation, Inc.
- * All rights reserved. 
+ * All rights reserved.
  *
  ******************************************************************************/
 #include <string.h>
@@ -65,12 +65,14 @@ EipUint16 g_encapsulation_inactivity_timeout = 0x78;
 EipStatus GetAttributeSingleTcpIpInterface(
   CipInstance *instance,
   CipMessageRouterRequest *message_router_request,
-  CipMessageRouterResponse *message_router_response);
+  CipMessageRouterResponse *message_router_response,
+  struct sockaddr *originator_address);
 
 EipStatus GetAttributeAllTcpIpInterface(
   CipInstance *instance,
   CipMessageRouterRequest *message_router_request,
-  CipMessageRouterResponse *message_router_response);
+  CipMessageRouterResponse *message_router_response,
+  struct sockaddr *originator_address);
 
 EipStatus ConfigureNetworkInterface(const char *ip_address,
                                     const char *subnet_mask,
@@ -109,7 +111,7 @@ void ConfigureDomainName(const char *domain_name) {
   }
 }
 
-void ConfigureHostName(const char *hostname) {
+void ConfigureHostName(const char *const RESTRICT hostname) {
   if (NULL != hostname_.string) {
     /* if the string is already set to a value we have to free the resources
      * before we can set the new value in order to avoid memory leaks.
@@ -129,7 +131,8 @@ void ConfigureHostName(const char *hostname) {
 EipStatus SetAttributeSingleTcp(
   CipInstance *instance,
   CipMessageRouterRequest *message_router_request,
-  CipMessageRouterResponse *message_router_response) {
+  CipMessageRouterResponse *message_router_response,
+  struct sockaddr *originator_address) {
   CipAttributeStruct *attribute = GetCipAttribute(
     instance, message_router_request->request_path.attribute_number);
   (void) instance; /*Suppress compiler warning */
@@ -263,9 +266,10 @@ void ShutdownTcpIpInterface(void) {
 }
 
 EipStatus GetAttributeSingleTcpIpInterface(
-  CipInstance *instance,
-  CipMessageRouterRequest *message_router_request,
-  CipMessageRouterResponse *message_router_response) {
+  CipInstance *const RESTRICT instance,
+  CipMessageRouterRequest *RESTRICT const message_router_request,
+  CipMessageRouterResponse *RESTRICT const message_router_response,
+  struct sockaddr *originator_address) {
 
   EipStatus status = kEipStatusOkSend;
   EipByte *message = message_router_response->data;
@@ -295,7 +299,7 @@ EipStatus GetAttributeSingleTcpIpInterface(
                                                        &message);
   } else {
     status = GetAttributeSingle(instance, message_router_request,
-                                message_router_response);
+                                message_router_response, originator_address);
   }
   return status;
 }
@@ -303,7 +307,8 @@ EipStatus GetAttributeSingleTcpIpInterface(
 EipStatus GetAttributeAllTcpIpInterface(
   CipInstance *instance,
   CipMessageRouterRequest *message_router_request,
-  CipMessageRouterResponse *message_router_response) {
+  CipMessageRouterResponse *message_router_response,
+  struct sockaddr *originator_address) {
 
   EipUint8 *response = message_router_response->data; /* pointer into the reply */
   CipAttributeStruct *attribute = instance->attributes;
@@ -313,7 +318,7 @@ EipStatus GetAttributeAllTcpIpInterface(
     int attribute_number = attribute->attribute_number;
     if ( attribute_number < 32
          && (instance->cip_class->get_attribute_all_mask & 1 <<
-      attribute_number) )                                                         /* only return attributes that are flagged as being part of GetAttributeALl */
+             attribute_number) )                                                  /* only return attributes that are flagged as being part of GetAttributeALl */
     {
       message_router_request->request_path.attribute_number = attribute_number;
 
@@ -324,7 +329,8 @@ EipStatus GetAttributeAllTcpIpInterface(
 
       if ( kEipStatusOkSend
            != GetAttributeSingleTcpIpInterface(instance, message_router_request,
-                                               message_router_response) ) {
+                                               message_router_response,
+                                               originator_address) ) {
         message_router_response->data = response;
         return kEipStatusError;
       }

+ 1 - 1
source/src/cip/ciptcpipinterface.h

@@ -1,6 +1,6 @@
 /*******************************************************************************
  * Copyright (c) 2009, Rockwell Automation, Inc.
- * All rights reserved. 
+ * All rights reserved.
  *
  ******************************************************************************/
 #ifndef OPENER_CIPTCPIPINTERFACE_H_

+ 52 - 97
source/src/cip/ciptypes.h

@@ -7,57 +7,7 @@
 #define OPENER_CIPTYPES_H_
 
 #include "typedefs.h"
-
-/** @brief Segment type Enum
- *
- * Bits 7-5 in the Segment Type/Format byte
- *
- */
-typedef enum {
-  /* Segments */
-  kSegmentTypePortSegment = 0x00, /**< Port segment */
-  kSegmentTypeLogicalSegment = 0x20, /**< Logical segment */
-  kSegmentTypeNetworkSegment = 0x40, /**< Network segment */
-  kSegmentTypeSymbolicSegment = 0x60, /**< Symbolic segment */
-  kSegmentTypeDataSegment = 0x80, /**< Data segment */
-  kSegmentTypeDataTypeConstructed = 0xA0, /**< Data type constructed */
-  kSegmentTypeDataTypeElementary = 0xC0, /**< Data type elementary */
-  kSegmentTypeSegmentTypeReserved = 0xE0
-} SegmentType;
-
-/** @brief Port Segment flags */
-typedef enum {
-  kPortSegmentFlagExtendedLinkAddressSize = 0x10 /**< Extended Link Address Size flag, Port segment */
-} PortSegmentFlag;
-
-/** @brief Enum containing values which kind of logical segment is encoded */
-typedef enum {
-  kLogicalSegmentLogicalTypeClassId = 0x00, /**< Class ID */
-  kLogicalSegmentLogicalTypeInstanceId = 0x04, /**< Instance ID */
-  kLogicalSegmentLogicalTypeMemberId = 0x08, /**< Member ID */
-  kLogicalSegmentLogicalTypeConnectionPoint = 0x0C, /**< Connection Point */
-  kLogicalSegmentLogicalTypeAttributeId = 0x10, /**< Attribute ID */
-  kLogicalSegmentLogicalTypeSpecial = 0x14, /**< Special */
-  kLogicalSegmentLogicalTypeService = 0x18, /**< Service ID */
-  kLogicalSegmentLogicalTypeExtendedLogical = 0x1C /**< Extended Logical */
-} LogicalSegmentLogicalType;
-
-/** @brief Enum containing values how long the encoded value will be (8, 16, or
- * 32 bit) */
-typedef enum {
-  kLogicalSegmentLogicalFormatEightBitValue = 0x00,
-  kLogicalSegmentLogicalFormatSixteenBitValue = 0x01,
-  kLogicalSegmentLogicalFormatThirtyTwoBitValue = 0x02
-} LogicalSegmentLogicalFormat;
-
-typedef enum {
-  kProductionTimeInhibitTimeNetworkSegment = 0x43 /**< identifier indicating a production inhibit time network segment */
-} NetworkSegmentSubType;
-
-typedef enum {
-  kDataSegmentTypeSimpleDataMessage = kSegmentTypeDataSegment + 0x00,
-  kDataSegmentTypeAnsiExtendedSymbolMessage = kSegmentTypeDataSegment + 0x11
-} DataSegmentType;
+#include "networkhandler.h"
 
 /** @brief Enum containing the encoding values for CIP data types for CIP
  * Messages */
@@ -89,7 +39,7 @@ typedef enum cip_data_types {
   kCipItime = 0xD8, /**< Duration in milli-seconds, short; range of INT*/
   kCipStringN = 0xD9, /**< Character string, N byte per character */
   kCipShortString = 0xDA, /**< Character string, 1 byte per character, 1 byte
-   length indicator */
+                             length indicator */
   kCipTime = 0xDB, /**< Duration in milli-seconds; range of DINT */
   kCipEpath = 0xDC, /**< CIP path segments*/
   kCipEngUnit = 0xDD, /**< Engineering Units*/
@@ -98,18 +48,18 @@ typedef enum cip_data_types {
   /* TODO: Check these codes */
   kCipUsintUsint = 0xA0, /**< Used for CIP Identity attribute 4 Revision*/
   kCipUdintUdintUdintUdintUdintString = 0xA1, /**< TCP/IP attribute 5 - IP address, subnet mask, gateway, IP name
-   server 1, IP name server 2, domain name*/
+                                                 server 1, IP name server 2, domain name*/
   kCip6Usint = 0xA2, /**< Struct for MAC Address (six USINTs)*/
   kCipMemberList = 0xA3, /**< */
   kCipByteArray = 0xA4, /**< */
   kInternalUint6 = 0xF0 /**< bogus hack, for port class attribute 9, TODO
-   figure out the right way to handle it */
+                           figure out the right way to handle it */
 } CipDataType;
 
 /** @brief Definition of CIP service codes
  *
  * An Enum with all CIP service codes. Common services codes range from 0x01 to
- *0x1C
+ **0x1C
  *
  */
 typedef enum {
@@ -191,23 +141,26 @@ typedef struct {
  *
  */
 typedef struct {
-  EipUint8 path_size;
-  /**< Size of the Path in 16-bit words *//* TODO: Fix, should be UINT
-   (EIP_UINT16) */
+  EipUint8 path_size;/**< Path size in 16 bit words (path_size * 16 bit) */
   EipUint16 class_id; /**< Class ID of the linked object */
   EipUint16 instance_number; /**< Requested Instance Number of the linked object */
   EipUint16 attribute_number; /**< Requested Attribute Number of the linked object */
 } CipEpath;
 
+typedef enum connection_point_type {
+  kConnectionPointTypeProducing = 0,
+  kConnectionPointTypeConsuming,
+  kConnectionPointTypeConfig,
+  kConnectionPointTypeMaxValue
+} ConnectionPointType;
+
 /** @brief CIP Connection Path
  *
  */
 typedef struct {
-  EipUint8 path_size;
-  /**< Size of the Path in 16-bit words *//* TODO: Fix, should be UINT
-   (EIP_UINT16) */
+  EipUint8 path_size; /**< Path size in 16 bit words (path_size * 16 bit) */
   EipUint32 class_id; /**< Class ID of the linked object */
-  EipUint32 connection_point[3]; /* TODO:  Why array length 3? */
+  EipUint32 connection_point[kConnectionPointTypeMaxValue];
   EipUint8 data_segment;
   EipUint8 *segment_data;
 } CipConnectionPath;
@@ -220,7 +173,7 @@ typedef struct {
   CipUint device_type; /**< Device Type */
   CipUint product_code; /**< Product Code */
   CipByte major_revision; /**< Major Revision and Compatibility (Bit 0-6 = Major
-   Revision) Bit 7 = Compatibility */
+                             Revision) Bit 7 = Compatibility */
   CipUsint minor_revision; /**< Minor Revision */
 } CipKeyData;
 
@@ -236,9 +189,9 @@ typedef struct {
 typedef struct {
   CipUsint segment_type; /**< Specifies the Segment Type */
   CipUsint key_format; /**< Key Format 0-3 reserved, 4 = see Key Format Table,
-   5-255 = Reserved */
+                          5-255 = Reserved */
   CipKeyData key_data; /**< Depends on key format used, usually Key Format 4 as
-   specified in CIP Specification, Volume 1*/
+                          specified in CIP Specification, Volume 1*/
 } CipElectronicKey;
 
 /** @brief CIP Message Router Request
@@ -247,7 +200,7 @@ typedef struct {
 typedef struct {
   CipUsint service;
   CipEpath request_path;
-  EipInt16 data_length;
+  EipInt16 request_path_size;
   const CipOctet *data;
 } CipMessageRouterRequest;
 
@@ -258,26 +211,26 @@ typedef struct {
  */
 typedef struct {
   CipUsint reply_service; /**< Reply service code, the requested service code +
-   0x80 */
+                             0x80 */
   CipOctet reserved; /**< Reserved; Shall be zero */
   CipUsint general_status; /**< One of the General Status codes listed in CIP
-   Specification Volume 1, Appendix B */
+                              Specification Volume 1, Appendix B */
   CipUsint size_of_additional_status; /**< Number of additional 16 bit words in
-   Additional Status Array */
+                                         Additional Status Array */
   EipUint16 additional_status[MAX_SIZE_OF_ADD_STATUS]; /**< Array of 16 bit words; Additional status;
-   If SizeOfAdditionalStatus is 0. there is no
-   Additional Status */
+                                                          If SizeOfAdditionalStatus is 0. there is no
+                                                          Additional Status */
   EipInt16 data_length; /**< Supportative non-CIP variable, gives length of data segment */
   CipOctet *data; /**< Array of octet; Response data per object definition from
-   request */
+                     request */
 } CipMessageRouterResponse;
 
 typedef struct {
   EipUint16 attribute_number;
   EipUint8 type;
   CIPAttributeFlag attribute_flags; /*< 0 => getable_all, 1 => getable_single; 2 =>
-   setable_single; 3 => get and setable; all other
-   values reserved */
+                                       setable_single; 3 => get and setable; all other
+                                       values reserved */
   void *data;
 } CipAttributeStruct;
 
@@ -287,10 +240,10 @@ typedef struct {
 typedef struct cip_instance {
   EipUint32 instance_number; /**< this instance's number (unique within the class) */
   CipAttributeStruct *attributes; /**< pointer to an array of attributes which
-   is unique to this instance */
+                                     is unique to this instance */
   struct cip_class *cip_class; /**< class the instance belongs to */
   struct cip_instance *next; /**< next instance, all instances of a class live
-   in a linked list */
+                                in a linked list */
 } CipInstance;
 
 /** @brief Class is a subclass of Instance */
@@ -300,13 +253,13 @@ typedef struct cip_class {
   EipUint32 class_id; /**< class ID */
   EipUint16 revision; /**< class revision*/
   EipUint16 number_of_instances; /**< number of instances in the class (not
-   including instance 0)*/
+                                    including instance 0)*/
   EipUint16 number_of_attributes; /**< number of attributes of each instance*/
   EipUint16 highest_attribute_number; /**< highest defined attribute number
-   (attribute numbers are not necessarily
-   consecutive)*/
+                                         (attribute numbers are not necessarily
+                                         consecutive)*/
   EipUint32 get_attribute_all_mask; /**< mask indicating which attributes are
-   returned by getAttributeAll*/
+                                       returned by getAttributeAll*/
   EipUint16 number_of_services; /**< number of services supported*/
   CipInstance *instances; /**< pointer to the list of instances*/
   struct cip_service_struct *services; /**< pointer to the array of services*/
@@ -315,22 +268,24 @@ typedef struct cip_class {
 
 /** @ingroup CIP_API
  *  @typedef  EIP_STATUS (*TCIPServiceFunc)(S_CIP_Instance *pa_pstInstance,
- *S_CIP_MR_Request *pa_MRRequest, S_CIP_MR_Response *pa_MRResponse)
+ **S_CIP_MR_Request *pa_MRRequest, S_CIP_MR_Response *pa_MRResponse)
  *  @brief Signature definition for the implementation of CIP services.
  *
  *  CIP services have to follow this signature in order to be handled correctly
- *by the stack.
+ **by the stack.
  *  @param pa_pstInstance the instance which was referenced in the service
- *request
+ **request
  *  @param pa_MRRequest request data
  *  @param pa_MRResponse storage for the response data, including a buffer for
- *extended data
+ **extended data
  *  @return EIP_OK_SEND if service could be executed successfully and a response
- *should be sent
+ **should be sent
  */
 typedef EipStatus (*CipServiceFunction)(
-    CipInstance *const instance, CipMessageRouterRequest *const message_router_request,
-    CipMessageRouterResponse *const message_router_response);
+  CipInstance *const instance,
+  CipMessageRouterRequest *const message_router_request,
+  CipMessageRouterResponse *const message_router_response,
+  struct sockaddr *originator_address);
 
 /** @brief Service descriptor. These are stored in an array */
 typedef struct cip_service_struct {
@@ -369,19 +324,19 @@ typedef struct {
 } CipUnconnectedSendParameter;
 
 /* these are used for creating the getAttributeAll masks
- TODO there might be a way simplifying this using __VARARGS__ in #define */
-#define MASK1(a) (1 << (a))
-#define MASK2(a, b) (1 << (a) | 1 << (b))
-#define MASK3(a, b, c) (1 << (a) | 1 << (b) | 1 << (c))
-#define MASK4(a, b, c, d) (1 << (a) | 1 << (b) | 1 << (c) | 1 << (d))
+   TODO there might be a way simplifying this using __VARARGS__ in #define */
+#define MASK1(a) ( 1 << (a) )
+#define MASK2(a, b) ( 1 << (a) | 1 << (b) )
+#define MASK3(a, b, c) ( 1 << (a) | 1 << (b) | 1 << (c) )
+#define MASK4(a, b, c, d) ( 1 << (a) | 1 << (b) | 1 << (c) | 1 << (d) )
 #define MASK5(a, b, c, d, e) \
-  (1 << (a) | 1 << (b) | 1 << (c) | 1 << (d) | 1 << (e))
+  ( 1 << (a) | 1 << (b) | 1 << (c) | 1 << (d) | 1 << (e) )
 #define MASK6(a, b, c, d, e, f) \
-  (1 << (a) | 1 << (b) | 1 << (c) | 1 << (d) | 1 << (e) | 1 << (f))
+  ( 1 << (a) | 1 << (b) | 1 << (c) | 1 << (d) | 1 << (e) | 1 << (f) )
 #define MASK7(a, b, c, d, e, f, g) \
-  (1 << (a) | 1 << (b) | 1 << (c) | 1 << (d) | 1 << (e) | 1 << (f) | 1 << (g))
+  ( 1 << (a) | 1 << (b) | 1 << (c) | 1 << (d) | 1 << (e) | 1 << (f) | 1 << (g) )
 #define MASK8(a, b, c, d, e, f, g, h)                                \
-  (1 << (a) | 1 << (b) | 1 << (c) | 1 << (d) | 1 << (e) | 1 << (f) | \
-   1 << (g) | 1 << (h))
+  ( 1 << (a) | 1 << (b) | 1 << (c) | 1 << (d) | 1 << (e) | 1 << (f) | \
+    1 << (g) | 1 << (h) )
 
 #endif /* OPENER_CIPTYPES_H_ */

+ 146 - 119
source/src/enet_encap/cpf.c

@@ -1,6 +1,6 @@
 /*******************************************************************************
  * Copyright (c) 2009, Rockwell Automation, Inc.
- * All rights reserved. 
+ * All rights reserved.
  *
  ******************************************************************************/
 #include <string.h>
@@ -23,38 +23,40 @@ const size_t sequenced_address_item_length = 8;
 CipCommonPacketFormatData g_common_packet_format_data_item; /**< CPF global data items */
 
 int NotifyCommonPacketFormat(EncapsulationData *const receive_data,
-                             EipUint8 *reply_buffer) {
+                             EipUint8 *reply_buffer,
+                             struct sockaddr *originator_address) {
   int return_value = kEipStatusError;
 
-  if ((return_value = CreateCommonPacketFormatStructure(
-      receive_data->current_communication_buffer_position,
-      receive_data->data_length, &g_common_packet_format_data_item))
-      == kEipStatusError) {
+  if ( ( return_value = CreateCommonPacketFormatStructure(
+           receive_data->current_communication_buffer_position,
+           receive_data->data_length, &g_common_packet_format_data_item) )
+       == kEipStatusError ) {
     OPENER_TRACE_ERR("notifyCPF: error from createCPFstructure\n");
   } else {
     return_value = kEipStatusOk; /* In cases of errors we normally need to send an error response */
     if (g_common_packet_format_data_item.address_item.type_id
         == kCipItemIdNullAddress) /* check if NullAddressItem received, otherwise it is no unconnected message and should not be here*/
-        { /* found null address item*/
+    {     /* found null address item*/
       if (g_common_packet_format_data_item.data_item.type_id
           == kCipItemIdUnconnectedDataItem) { /* unconnected data item received*/
         return_value = NotifyMessageRouter(
-            g_common_packet_format_data_item.data_item.data,
-            g_common_packet_format_data_item.data_item.length);
+          g_common_packet_format_data_item.data_item.data,
+          g_common_packet_format_data_item.data_item.length,
+          originator_address);
         if (return_value != kEipStatusError) {
           return_value = AssembleLinearMessage(
-              &g_message_router_response, &g_common_packet_format_data_item,
-              reply_buffer);
+            &g_message_router_response, &g_common_packet_format_data_item,
+            reply_buffer);
         }
       } else {
         /* wrong data item detected*/
         OPENER_TRACE_ERR(
-            "notifyCPF: got something besides the expected CIP_ITEM_ID_UNCONNECTEDMESSAGE\n");
+          "notifyCPF: got something besides the expected CIP_ITEM_ID_UNCONNECTEDMESSAGE\n");
         receive_data->status = kEncapsulationProtocolIncorrectData;
       }
     } else {
       OPENER_TRACE_ERR(
-          "notifyCPF: got something besides the expected CIP_ITEM_ID_NULL\n");
+        "notifyCPF: got something besides the expected CIP_ITEM_ID_NULL\n");
       receive_data->status = kEncapsulationProtocolIncorrectData;
     }
   }
@@ -62,11 +64,12 @@ int NotifyCommonPacketFormat(EncapsulationData *const receive_data,
 }
 
 int NotifyConnectedCommonPacketFormat(EncapsulationData *received_data,
-                                      EipUint8 *reply_buffer) {
+                                      EipUint8 *reply_buffer,
+                                      struct sockaddr *originator_address) {
 
   int return_value = CreateCommonPacketFormatStructure(
-      received_data->current_communication_buffer_position,
-      received_data->data_length, &g_common_packet_format_data_item);
+    received_data->current_communication_buffer_position,
+    received_data->data_length, &g_common_packet_format_data_item);
 
   if (kEipStatusError == return_value) {
     OPENER_TRACE_ERR("notifyConnectedCPF: error from createCPFstructure\n");
@@ -74,45 +77,51 @@ int NotifyConnectedCommonPacketFormat(EncapsulationData *received_data,
     return_value = kEipStatusError; /* For connected explicit messages status always has to be 0*/
     if (g_common_packet_format_data_item.address_item.type_id
         == kCipItemIdConnectionAddress) /* check if ConnectedAddressItem received, otherwise it is no connected message and should not be here*/
-        { /* ConnectedAddressItem item */
+    {     /* ConnectedAddressItem item */
       ConnectionObject *connection_object = GetConnectedObject(
-          g_common_packet_format_data_item.address_item.data
-              .connection_identifier);
+        g_common_packet_format_data_item.address_item.data
+        .connection_identifier);
       if (NULL != connection_object) {
         /* reset the watchdog timer */
         connection_object->inactivity_watchdog_timer = (connection_object
-            ->o_to_t_requested_packet_interval / 1000)
-            << (2 + connection_object->connection_timeout_multiplier);
+                                                        ->
+                                                        o_to_t_requested_packet_interval
+                                                        / 1000)
+                                                       << (2 +
+                                                           connection_object->
+                                                           connection_timeout_multiplier);
 
         /*TODO check connection id  and sequence count    */
         if (g_common_packet_format_data_item.data_item.type_id
             == kCipItemIdConnectedDataItem) { /* connected data item received*/
           EipUint8 *buffer = g_common_packet_format_data_item.data_item.data;
           g_common_packet_format_data_item.address_item.data.sequence_number =
-              (EipUint32) GetIntFromMessage((const EipUint8 ** const)&buffer);
+            (EipUint32) GetIntFromMessage( (const EipUint8 **const)&buffer );
           return_value = NotifyMessageRouter(
-              buffer, g_common_packet_format_data_item.data_item.length - 2);
+            buffer,
+            g_common_packet_format_data_item.data_item.length - 2,
+            originator_address);
 
           if (return_value != kEipStatusError) {
             g_common_packet_format_data_item.address_item.data
-                .connection_identifier = connection_object
-                ->produced_connection_id;
+            .connection_identifier = connection_object
+                                     ->cip_produced_connection_id;
             return_value = AssembleLinearMessage(
-                &g_message_router_response, &g_common_packet_format_data_item,
-                reply_buffer);
+              &g_message_router_response, &g_common_packet_format_data_item,
+              reply_buffer);
           }
         } else {
           /* wrong data item detected*/
           OPENER_TRACE_ERR(
-              "notifyConnectedCPF: got something besides the expected CIP_ITEM_ID_UNCONNECTEDMESSAGE\n");
+            "notifyConnectedCPF: got something besides the expected CIP_ITEM_ID_UNCONNECTEDMESSAGE\n");
         }
       } else {
         OPENER_TRACE_ERR(
-            "notifyConnectedCPF: connection with given ID could not be found\n");
+          "notifyConnectedCPF: connection with given ID could not be found\n");
       }
     } else {
       OPENER_TRACE_ERR(
-          "notifyConnectedCPF: got something besides the expected CIP_ITEM_ID_NULL\n");
+        "notifyConnectedCPF: got something besides the expected CIP_ITEM_ID_NULL\n");
     }
   }
   return return_value;
@@ -125,11 +134,12 @@ int NotifyConnectedCommonPacketFormat(EncapsulationData *received_data,
  * @param common_packet_format_data	Pointer to structure of CPF data item.
  *
  *   @return kEipStatusOk .. success
- * 	       kEipStatusError .. error
+ *             kEipStatusError .. error
  */
 EipStatus CreateCommonPacketFormatStructure(
-    const EipUint8 *data, int data_length,
-    CipCommonPacketFormatData *common_packet_format_data) {
+  const EipUint8 *data,
+  int data_length,
+  CipCommonPacketFormatData *common_packet_format_data) {
 
   common_packet_format_data->address_info_item[0].type_id = 0;
   common_packet_format_data->address_info_item[1].type_id = 0;
@@ -143,12 +153,12 @@ EipStatus CreateCommonPacketFormatStructure(
     length_count += 4;
     if (common_packet_format_data->address_item.length >= 4) {
       common_packet_format_data->address_item.data.connection_identifier =
-          GetDintFromMessage(&data);
+        GetDintFromMessage(&data);
       length_count += 4;
     }
     if (common_packet_format_data->address_item.length == 8) {
       common_packet_format_data->address_item.data.sequence_number =
-          GetDintFromMessage(&data);
+        GetDintFromMessage(&data);
       length_count += 4;
     }
   }
@@ -162,20 +172,22 @@ EipStatus CreateCommonPacketFormatStructure(
   for (int j = 0; j < (common_packet_format_data->item_count - 2); j++) /* TODO there needs to be a limit check here???*/
   {
     common_packet_format_data->address_info_item[j].type_id = GetIntFromMessage(
-        &data);
+      &data);
+    OPENER_TRACE_INFO("Sockaddr type id: %x\n",
+                      common_packet_format_data->address_info_item[j].type_id);
     length_count += 2;
-    if ((common_packet_format_data->address_info_item[j].type_id
-        == kCipItemIdSocketAddressInfoOriginatorToTarget)
-        || (common_packet_format_data->address_info_item[j].type_id
-            == kCipItemIdSocketAddressInfoTargetToOriginator)) {
+    if ( (common_packet_format_data->address_info_item[j].type_id
+          == kCipItemIdSocketAddressInfoOriginatorToTarget)
+         || (common_packet_format_data->address_info_item[j].type_id
+             == kCipItemIdSocketAddressInfoTargetToOriginator) ) {
       common_packet_format_data->address_info_item[j].length =
-          GetIntFromMessage(&data);
+        GetIntFromMessage(&data);
       common_packet_format_data->address_info_item[j].sin_family =
-          GetIntFromMessage(&data);
+        GetIntFromMessage(&data);
       common_packet_format_data->address_info_item[j].sin_port =
-          GetIntFromMessage(&data);
+        GetIntFromMessage(&data);
       common_packet_format_data->address_info_item[j].sin_addr =
-          GetDintFromMessage(&data);
+        GetDintFromMessage(&data);
       for (int i = 0; i < 8; i++) {
         common_packet_format_data->address_info_item[j].nasin_zero[i] = *data;
         data++;
@@ -197,7 +209,7 @@ EipStatus CreateCommonPacketFormatStructure(
     return kEipStatusOk;
   } else {
     OPENER_TRACE_WARN(
-        "something is wrong with the length in Message Router @ CreateCommonPacketFormatStructure\n");
+      "something is wrong with the length in Message Router @ CreateCommonPacketFormatStructure\n");
     if (common_packet_format_data->item_count > 2) {
       /* there is an optional packet in data stream which is not sockaddr item */
       return kEipStatusOk;
@@ -214,7 +226,7 @@ EipStatus CreateCommonPacketFormatStructure(
  *
  * @return The new size of the message frame after encoding
  */
-int EncodeNullAddressItem(EipUint8** message, int size) {
+int EncodeNullAddressItem(EipUint8 **message, int size) {
   size += AddIntToMessage(kCipItemIdNullAddress, message);
   /* null address item -> address length set to 0 */
   size += AddIntToMessage(0, message);
@@ -230,14 +242,15 @@ int EncodeNullAddressItem(EipUint8** message, int size) {
  * @return The new size of the message frame after encoding
  */
 int EncodeConnectedAddressItem(
-    EipUint8** message,
-    CipCommonPacketFormatData* common_packet_format_data_item, int size) {
+  EipUint8 **message,
+  CipCommonPacketFormatData *common_packet_format_data_item,
+  int size) {
   /* connected data item -> address length set to 4 and copy ConnectionIdentifier */
   size += AddIntToMessage(kCipItemIdConnectionAddress, message);
   size += AddIntToMessage(4, message);
   size += AddDintToMessage(
-      common_packet_format_data_item->address_item.data.connection_identifier,
-      message);
+    common_packet_format_data_item->address_item.data.connection_identifier,
+    message);
   return size;
 }
 
@@ -251,17 +264,18 @@ int EncodeConnectedAddressItem(
  * @return New message size after encoding
  */
 int EncodeSequencedAddressItem(
-    EipUint8** message,
-    CipCommonPacketFormatData* common_packet_format_data_item, int size) {
+  EipUint8 **message,
+  CipCommonPacketFormatData *common_packet_format_data_item,
+  int size) {
   /* sequenced address item -> address length set to 8 and copy ConnectionIdentifier and SequenceNumber */
   size += AddIntToMessage(kCipItemIdSequencedAddressItem, message);
   size += AddIntToMessage(sequenced_address_item_length, message);
   size += AddDintToMessage(
-      common_packet_format_data_item->address_item.data.connection_identifier,
-      message);
+    common_packet_format_data_item->address_item.data.connection_identifier,
+    message);
   size += AddDintToMessage(
-      common_packet_format_data_item->address_item.data.sequence_number,
-      message);
+    common_packet_format_data_item->address_item.data.sequence_number,
+    message);
   return size;
 }
 
@@ -274,8 +288,9 @@ int EncodeSequencedAddressItem(
  *
  * @return The new size of the message frame after encoding
  */
-int EncodeItemCount(CipCommonPacketFormatData* common_packet_format_data_item,
-                    EipUint8** message, int size) {
+int EncodeItemCount(CipCommonPacketFormatData *common_packet_format_data_item,
+                    EipUint8 **message,
+                    int size) {
   size += AddIntToMessage(common_packet_format_data_item->item_count, message); /* item count */
   return size;
 }
@@ -290,8 +305,9 @@ int EncodeItemCount(CipCommonPacketFormatData* common_packet_format_data_item,
  * @return The new size of the message frame after encoding
  */
 int EncodeDataItemType(
-    CipCommonPacketFormatData* common_packet_format_data_item,
-    EipUint8** message, int size) {
+  CipCommonPacketFormatData *common_packet_format_data_item,
+  EipUint8 **message,
+  int size) {
   size += AddIntToMessage(common_packet_format_data_item->data_item.type_id,
                           message);
   return size;
@@ -307,8 +323,9 @@ int EncodeDataItemType(
  * @return The new size of the message frame after encoding
  */
 int EncodeDataItemLength(
-    CipCommonPacketFormatData* common_packet_format_data_item,
-    EipUint8** message, int size) {
+  CipCommonPacketFormatData *common_packet_format_data_item,
+  EipUint8 **message,
+  int size) {
   size += AddIntToMessage(common_packet_format_data_item->data_item.length,
                           message);
   return size;
@@ -324,11 +341,12 @@ int EncodeDataItemLength(
  * @return The new size of the message frame after encoding
  */
 int EncodeDataItemData(
-    CipCommonPacketFormatData* common_packet_format_data_item,
-    EipUint8** message, int size) {
+  CipCommonPacketFormatData *common_packet_format_data_item,
+  EipUint8 **message,
+  int size) {
   for (int i = 0; i < common_packet_format_data_item->data_item.length; i++) {
     size += AddSintToMessage(
-        *(common_packet_format_data_item->data_item.data + i), message);
+      *(common_packet_format_data_item->data_item.data + i), message);
   }
   return size;
 }
@@ -344,12 +362,12 @@ int EncodeDataItemData(
  */
 
 int EncodeConnectedDataItemLength(
-    CipMessageRouterResponse* message_router_response, EipUint8** message,
-    int size) {
+  CipMessageRouterResponse *message_router_response, EipUint8 **message,
+  int size) {
   size += AddIntToMessage(
-      (EipUint16) (message_router_response->data_length + 4 + 2 /* TODO: Magic numbers */
-          + (2 * message_router_response->size_of_additional_status)),
-      message);
+    (EipUint16) ( message_router_response->data_length + 4 + 2  /* TODO: Magic numbers */
+                  + (2 * message_router_response->size_of_additional_status) ),
+    message);
   return size;
 }
 
@@ -364,12 +382,13 @@ int EncodeConnectedDataItemLength(
  *
  */
 int EncodeSequenceNumber(
-    int size, const CipCommonPacketFormatData* common_packet_format_data_item,
-    EipUint8** message) {
+  int size,
+  const CipCommonPacketFormatData *common_packet_format_data_item,
+  EipUint8 **message) {
   size += AddIntToMessage(
-      (EipUint16) common_packet_format_data_item->address_item.data
-          .sequence_number,
-      message);
+    (EipUint16) common_packet_format_data_item->address_item.data
+    .sequence_number,
+    message);
   return size;
 }
 
@@ -382,8 +401,9 @@ int EncodeSequenceNumber(
  *
  * @return The new size of the message buffer
  */
-int EncodeReplyService(int size, EipUint8** message,
-                       CipMessageRouterResponse* message_router_response) {
+int EncodeReplyService(int size,
+                       EipUint8 **message,
+                       CipMessageRouterResponse *message_router_response) {
   size += AddSintToMessage(message_router_response->reply_service, message);
   return size;
 }
@@ -398,8 +418,8 @@ int EncodeReplyService(int size, EipUint8** message,
  * @return New size of the message buffer
  */
 int EncodeReservedFieldOfLengthByte(
-    int size, EipUint8** message,
-    CipMessageRouterResponse* message_router_response) {
+  int size, EipUint8 **message,
+  CipMessageRouterResponse *message_router_response) {
   size += AddSintToMessage(message_router_response->reserved, message);
   return size;
 }
@@ -413,8 +433,9 @@ int EncodeReservedFieldOfLengthByte(
  *
  * @return New size of the message buffer
  */
-int EncodeGeneralStatus(int size, EipUint8** message,
-                        CipMessageRouterResponse* message_router_response) {
+int EncodeGeneralStatus(int size,
+                        EipUint8 **message,
+                        CipMessageRouterResponse *message_router_response) {
   size += AddSintToMessage(message_router_response->general_status, message);
   return size;
 }
@@ -430,8 +451,8 @@ int EncodeGeneralStatus(int size, EipUint8** message,
  */
 
 int EncodeExtendedStatusLength(
-    int size, EipUint8** message,
-    CipMessageRouterResponse* message_router_response) {
+  int size, EipUint8 **message,
+  CipMessageRouterResponse *message_router_response) {
   size += AddSintToMessage(message_router_response->size_of_additional_status,
                            message);
   return size;
@@ -447,11 +468,12 @@ int EncodeExtendedStatusLength(
  * @return New size of the message buffer
  */
 int EncodeExtendedStatusDataItems(
-    int size, CipMessageRouterResponse* message_router_response,
-    EipUint8** message) {
-  for (int i = 0; i < message_router_response->size_of_additional_status; i++)
+  int size, CipMessageRouterResponse *message_router_response,
+  EipUint8 **message) {
+  for (int i = 0; i < message_router_response->size_of_additional_status; i++) {
     size += AddIntToMessage(message_router_response->additional_status[i],
                             message);
+  }
 
   return size;
 }
@@ -469,8 +491,9 @@ int EncodeExtendedStatusDataItems(
  * @return New size of the message buffer
  */
 
-int EncodeExtendedStatus(int size, EipUint8** message,
-                         CipMessageRouterResponse* message_router_response) {
+int EncodeExtendedStatus(int size,
+                         EipUint8 **message,
+                         CipMessageRouterResponse *message_router_response) {
   size = EncodeExtendedStatusLength(size, message, message_router_response);
   size = EncodeExtendedStatusDataItems(size, message_router_response, message);
 
@@ -487,12 +510,12 @@ int EncodeExtendedStatus(int size, EipUint8** message,
  * @return New size of the message buffer
  */
 int EncodeUnconnectedDataItemLength(
-    int size, CipMessageRouterResponse* message_router_response,
-    EipUint8** message) {
+  int size, CipMessageRouterResponse *message_router_response,
+  EipUint8 **message) {
   size += AddIntToMessage(
-      (EipUint16) (message_router_response->data_length + 4 /* TODO: Magic number */
-          + (2 * message_router_response->size_of_additional_status)),
-      message);
+    (EipUint16) ( message_router_response->data_length + 4  /* TODO: Magic number */
+                  + (2 * message_router_response->size_of_additional_status) ),
+    message);
   return size;
 }
 
@@ -504,10 +527,10 @@ int EncodeUnconnectedDataItemLength(
  * @param message Message frame to which the data is added
  */
 int EncodeMessageRouterResponseData(
-    int size, CipMessageRouterResponse* message_router_response,
-    EipUint8** message) {
+  int size, CipMessageRouterResponse *message_router_response,
+  EipUint8 **message) {
   for (int i = 0; i < message_router_response->data_length; i++) {
-    size += AddSintToMessage((message_router_response->data)[i], &*message);
+    size += AddSintToMessage( (message_router_response->data)[i], &*message );
   }
   return size;
 }
@@ -523,13 +546,14 @@ int EncodeMessageRouterResponseData(
  * @return New size of the message buffer
  */
 int EncodeSockaddrInfoItemTypeId(
-    int size, int item_type,
-    CipCommonPacketFormatData* common_packet_format_data_item,
-    EipUint8** message) {
+  int size,
+  int item_type,
+  CipCommonPacketFormatData *common_packet_format_data_item,
+  EipUint8 **message) {
   OPENER_ASSERT(item_type == 0 || item_type == 1);
   size += AddIntToMessage(
-      common_packet_format_data_item->address_info_item[item_type].type_id,
-      message);
+    common_packet_format_data_item->address_info_item[item_type].type_id,
+    message);
 
   return size;
 }
@@ -545,10 +569,13 @@ int EncodeSockaddrInfoItemTypeId(
  * @return New size of the message buffer
  */
 int EncodeSockaddrInfoLength(
-    int size, int item_type, CipCommonPacketFormatData* common_packet_format_data_item,
-    EipUint8** message) {
+  int size,
+  int item_type,
+  CipCommonPacketFormatData *common_packet_format_data_item,
+  EipUint8 **message) {
   size += AddIntToMessage(
-      common_packet_format_data_item->address_info_item[item_type].length, message);
+    common_packet_format_data_item->address_info_item[item_type].length,
+    message);
   return size;
 }
 
@@ -559,12 +586,12 @@ int EncodeSockaddrInfoLength(
  * @param common_packet_format_data_item pointer to CPF structure which has to be aligned into linear memory.
  * @param message		pointer to linear memory.
  *  @return length of reply in message in bytes
- * 			-1 .. error
+ *                      -1 .. error
  */
 int AssembleLinearMessage(
-    CipMessageRouterResponse *message_router_response,
-    CipCommonPacketFormatData *common_packet_format_data_item,
-    EipUint8 *message) {
+  CipMessageRouterResponse *message_router_response,
+  CipCommonPacketFormatData *common_packet_format_data_item,
+  EipUint8 *message) {
 
   size_t message_size = 0;
 
@@ -599,14 +626,14 @@ int AssembleLinearMessage(
   }
 
   /* process Data Item */
-  if ((common_packet_format_data_item->data_item.type_id
-      == kCipItemIdUnconnectedDataItem)
-      || (common_packet_format_data_item->data_item.type_id
-          == kCipItemIdConnectedDataItem)) {
+  if ( (common_packet_format_data_item->data_item.type_id
+        == kCipItemIdUnconnectedDataItem)
+       || (common_packet_format_data_item->data_item.type_id
+           == kCipItemIdConnectedDataItem) ) {
 
     if (message_router_response) {
       message_size = EncodeDataItemType(common_packet_format_data_item,
-                                         &message, message_size);
+                                        &message, message_size);
 
       if (common_packet_format_data_item->data_item.type_id
           == kCipItemIdConnectedDataItem) { /* Connected Item */
@@ -652,24 +679,24 @@ int AssembleLinearMessage(
    * devices which depend on CPF items to appear in the order of their
    * ID number */
   for (int type = kCipItemIdSocketAddressInfoOriginatorToTarget;
-      type <= kCipItemIdSocketAddressInfoTargetToOriginator; type++) {
+       type <= kCipItemIdSocketAddressInfoTargetToOriginator; type++) {
     for (int j = 0; j < 2; j++) {
       if (common_packet_format_data_item->address_info_item[j].type_id
           == type) {
         message_size = EncodeSockaddrInfoItemTypeId(
-            message_size, j, common_packet_format_data_item, &message);
+          message_size, j, common_packet_format_data_item, &message);
 
         message_size = EncodeSockaddrInfoLength(message_size, j,
                                                 common_packet_format_data_item,
                                                 &message);
 
         message_size += EncapsulateIpAddress(
-            common_packet_format_data_item->address_info_item[j].sin_port,
-            common_packet_format_data_item->address_info_item[j].sin_addr,
-            &message);
+          common_packet_format_data_item->address_info_item[j].sin_port,
+          common_packet_format_data_item->address_info_item[j].sin_addr,
+          &message);
 
         message_size += FillNextNMessageOctetsWithValueAndMoveToNextPosition(
-            0, 8, &message);
+          0, 8, &message);
         break;
       }
     }

+ 29 - 24
source/src/enet_encap/cpf.h

@@ -1,6 +1,6 @@
 /*******************************************************************************
  * Copyright (c) 2009, Rockwell Automation, Inc.
- * All rights reserved. 
+ * All rights reserved.
  *
  ******************************************************************************/
 #ifndef OPENER_CPF_H_
@@ -50,19 +50,22 @@ typedef struct {
   EipUint8 *data;
 } DataItem;
 
+/** @brief CPF Sockaddr Item
+ *
+ */
 typedef struct {
-  CipUint type_id;
-  CipUint length;
-  CipInt sin_family;
-  CipUint sin_port;
-  CipUdint sin_addr;
-  CipUsint nasin_zero[8];
+  CipUint type_id; /**< Either 0x8000 for O->T or 0x8001 for T->O */
+  CipUint length; /**< Length shall be 16 bytes */
+  CipInt sin_family; /**< Shall be AF_INET = 2 in big endian order */
+  CipUint sin_port; /**< For point-to-point connection this shall be set to the used UDP port (recommended port = 0x08AE). For multicast this shall be set to 0x08AE and treated by the receiver as don't care. Big endian order */
+  CipUdint sin_addr; /**< For multicast connections shall be set to the multicast address. For point-to-point shall be treated as don't care, recommended value 0. Big endian order. */
+  CipUsint nasin_zero[8]; /**< Length of 8, Recommended value zero */
 } SocketAddressInfoItem;
 
 /* this one case of a CPF packet is supported:*/
-
+/** @brief A variant of a CPF packet, including item count, one address item, one data item, and two Sockaddr Info items */
 typedef struct {
-  EipUint16 item_count;
+  EipUint16 item_count; /**< Up to four for this structure allowed */
   AddressItem address_item;
   DataItem data_item;
   SocketAddressInfoItem address_info_item[2];
@@ -70,26 +73,28 @@ typedef struct {
 
 /** @ingroup ENCAP
  * Parse the CPF data from a received unconnected explicit message and
- * hand the data on to the message router 
+ * hand the data on to the message router
  *
  * @param  received_data pointer to the encapsulation structure with the received message
  * @param  reply_buffer reply buffer
  * @return number of bytes to be sent back. < 0 if nothing should be sent
  */
 int NotifyCommonPacketFormat(EncapsulationData *const received_data,
-                             EipUint8 *const reply_buffer);
+                             EipUint8 *const reply_buffer,
+                             struct sockaddr *originator_address);
 
 /** @ingroup ENCAP
  * Parse the CPF data from a received connected explicit message, check
- * the connection status, update any timers, and hand the data on to 
- * the message router 
+ * the connection status, update any timers, and hand the data on to
+ * the message router
  *
  * @param  received_data pointer to the encapsulation structure with the received message
  * @param  reply_buffer reply buffer
  * @return number of bytes to be sent back. < 0 if nothing should be sent
  */
 int NotifyConnectedCommonPacketFormat(EncapsulationData *received_data,
-                                      EipUint8 *reply_buffer);
+                                      EipUint8 *reply_buffer,
+                                      struct sockaddr *originator_address);
 
 /** @ingroup ENCAP
  *  Create CPF structure out of the received data.
@@ -97,12 +102,13 @@ int NotifyConnectedCommonPacketFormat(EncapsulationData *received_data,
  *  @param  data_length	length of data in pa_Data.
  *  @param  common_packet_format_data	pointer to structure of CPF data item.
  *  @return status
- * 	       EIP_OK .. success
- * 	       EIP_ERROR .. error
+ *             EIP_OK .. success
+ *             EIP_ERROR .. error
  */
 EipStatus CreateCommonPacketFormatStructure(
-    const EipUint8 *data, int data_length,
-    CipCommonPacketFormatData *common_packet_format_data);
+  const EipUint8 *data,
+  int data_length,
+  CipCommonPacketFormatData *common_packet_format_data);
 
 /** @ingroup ENCAP
  * Copy data from CPFDataItem into linear memory in message for transmission over in encapsulation.
@@ -113,8 +119,7 @@ EipStatus CreateCommonPacketFormatStructure(
  *     EIP_ERROR .. error
  */
 int AssembleIOMessage(
-    CipCommonPacketFormatData *common_packet_format_data_item,
-    EipUint8 *message);
+  CipCommonPacketFormatData *common_packet_format_data_item,EipUint8 *message);
 
 
 /** @ingroup ENCAP
@@ -123,12 +128,12 @@ int AssembleIOMessage(
  * @param  common_packet_format_data_item	pointer to CPF structure which has to be aligned into linear memory.
  * @param  message		pointer to linear memory.
  * @return length of reply in pa_msg in bytes
- * 	   EIP_ERROR .. error
+ *         EIP_ERROR .. error
  */
 int AssembleLinearMessage(
-    CipMessageRouterResponse *message_router_response,
-    CipCommonPacketFormatData *common_packet_format_data_item,
-    EipUint8 *message);
+  CipMessageRouterResponse *message_router_response,
+  CipCommonPacketFormatData *common_packet_format_data_item,
+  EipUint8 *message);
 
 /** @ingroup ENCAP
  * @brief Data storage for the any CPF data

+ 125 - 101
source/src/enet_encap/encap.c

@@ -1,10 +1,11 @@
 /*******************************************************************************
  * Copyright (c) 2009, Rockwell Automation, Inc.
- * All rights reserved. 
+ * All rights reserved.
  *
  ******************************************************************************/
 #include <string.h>
 #include <stdlib.h>
+#include <stdbool.h>
 
 #include "encap.h"
 
@@ -65,7 +66,8 @@ typedef enum {
 
 #define ENCAP_NUMBER_OF_SUPPORTED_DELAYED_ENCAP_MESSAGES 2 /**< According to EIP spec at least 2 delayed message requests should be supported */
 
-#define ENCAP_MAX_DELAYED_ENCAP_MESSAGE_SIZE (ENCAPSULATION_HEADER_LENGTH + 39 + sizeof(OPENER_DEVICE_NAME)) /* currently we only have the size of an encapsulation message */
+#define ENCAP_MAX_DELAYED_ENCAP_MESSAGE_SIZE ( ENCAPSULATION_HEADER_LENGTH + \
+                                               39 + sizeof(OPENER_DEVICE_NAME) )                             /* currently we only have the size of an encapsulation message */
 
 /* Encapsulation layer data  */
 
@@ -82,7 +84,8 @@ EncapsulationInterfaceInformation g_interface_information;
 
 int g_registered_sessions[OPENER_NUMBER_OF_SUPPORTED_SESSIONS];
 
-DelayedEncapsulationMessage g_delayed_encapsulation_messages[ENCAP_NUMBER_OF_SUPPORTED_DELAYED_ENCAP_MESSAGES];
+DelayedEncapsulationMessage g_delayed_encapsulation_messages[
+  ENCAP_NUMBER_OF_SUPPORTED_DELAYED_ENCAP_MESSAGES];
 
 /*** private functions ***/
 void HandleReceivedListServicesCommand(EncapsulationData *receive_data);
@@ -99,12 +102,13 @@ void HandleReceivedRegisterSessionCommand(int socket,
                                           EncapsulationData *receive_data);
 
 EipStatus HandleReceivedUnregisterSessionCommand(
-    EncapsulationData *receive_data);
+  EncapsulationData *receive_data);
 
-EipStatus HandleReceivedSendUnitDataCommand(EncapsulationData *receive_data);
+EipStatus HandleReceivedSendUnitDataCommand(EncapsulationData *receive_data,
+                                            struct sockaddr *originator_address);
 
 EipStatus HandleReceivedSendRequestResponseDataCommand(
-    EncapsulationData *receive_data);
+  EncapsulationData *receive_data, struct sockaddr *originator_address);
 
 int GetFreeSessionIndex(void);
 
@@ -135,7 +139,8 @@ void EncapsulationInit(void) {
     g_registered_sessions[i] = kEipInvalidSocket;
   }
 
-  for (unsigned int i = 0; i < ENCAP_NUMBER_OF_SUPPORTED_DELAYED_ENCAP_MESSAGES; i++) {
+  for (unsigned int i = 0; i < ENCAP_NUMBER_OF_SUPPORTED_DELAYED_ENCAP_MESSAGES;
+       i++) {
     g_delayed_encapsulation_messages[i].socket = -1;
   }
 
@@ -145,14 +150,16 @@ void EncapsulationInit(void) {
   g_interface_information.length = sizeof(g_interface_information);
   g_interface_information.encapsulation_protocol_version = 1;
   g_interface_information.capability_flags = kCapabilityFlagsCipTcp
-      | kCapabilityFlagsCipUdpClass0or1;
-  strcpy((char *) g_interface_information.name_of_service, "Communications");
+                                             | kCapabilityFlagsCipUdpClass0or1;
+  strcpy( (char *) g_interface_information.name_of_service, "Communications" );
 }
 
-int HandleReceivedExplictTcpData(int socket, EipUint8 *buffer,
-                                 unsigned int length, int *remaining_bytes) {
-  int return_value = 0;
-  EipStatus status = kEipStatusOk;
+int HandleReceivedExplictTcpData(int socket,
+                                 EipUint8 *buffer,
+                                 unsigned int length,
+                                 int *remaining_bytes,
+                                 struct sockaddr *originator_address) {
+  EipStatus return_value = kEipStatusOk;
   EncapsulationData encapsulation_data;
   /* eat the encapsulation header*/
   /* the structure contains a pointer to the encapsulated data*/
@@ -166,12 +173,12 @@ int HandleReceivedExplictTcpData(int socket, EipUint8 *buffer,
     {
       /* full package or more received */
       encapsulation_data.status = kEncapsulationProtocolSuccess;
-	  status = kEipStatusOkSend;
+      return_value = kEipStatusOkSend;
       /* most of these functions need a reply to be send */
       switch (encapsulation_data.command_code) {
         case (kEncapsulationCommandNoOperation):
           /* NOP needs no reply and does nothing */
-          status = kEipStatusOk;
+          return_value = kEipStatusOk;
           break;
 
         case (kEncapsulationCommandListServices):
@@ -191,17 +198,18 @@ int HandleReceivedExplictTcpData(int socket, EipUint8 *buffer,
           break;
 
         case (kEncapsulationCommandUnregisterSession):
-          status = HandleReceivedUnregisterSessionCommand(
-              &encapsulation_data);
+          return_value = HandleReceivedUnregisterSessionCommand(
+            &encapsulation_data);
           break;
 
         case (kEncapsulationCommandSendRequestReplyData):
-          status = HandleReceivedSendRequestResponseDataCommand(
-              &encapsulation_data);
+          return_value = HandleReceivedSendRequestResponseDataCommand(
+            &encapsulation_data, originator_address);
           break;
 
         case (kEncapsulationCommandSendUnitData):
-          status = HandleReceivedSendUnitDataCommand(&encapsulation_data);
+          return_value = HandleReceivedSendUnitDataCommand(&encapsulation_data,
+                                                           originator_address);
           break;
 
         default:
@@ -209,13 +217,9 @@ int HandleReceivedExplictTcpData(int socket, EipUint8 *buffer,
           encapsulation_data.data_length = 0;
           break;
       }
-      
-      if (kEipStatusOk < status) {
-        /* if status is greater than 0 data has to be sent */
+      /* if nRetVal is greater than 0 data has to be sent */
+      if (kEipStatusOk < return_value) {
         return_value = EncapsulateData(&encapsulation_data);
-      } else if (kEipStatusError == status) {
-        /* Report error state with negative return value */
-        return_value = -1;
       }
     }
   }
@@ -223,17 +227,19 @@ int HandleReceivedExplictTcpData(int socket, EipUint8 *buffer,
   return return_value;
 }
 
-int HandleReceivedExplictUdpData(int socket, struct sockaddr_in *from_address,
-                                 EipUint8 *buffer, unsigned int buffer_length,
-                                 int *number_of_remaining_bytes, int unicast) {
-  int return_value = 0;
+int HandleReceivedExplictUdpData(int socket,
+                                 struct sockaddr_in *from_address,
+                                 EipUint8 *buffer,
+                                 unsigned int buffer_length,
+                                 int *number_of_remaining_bytes,
+                                 int unicast) {
   EipStatus status = kEipStatusOk;
   EncapsulationData encapsulation_data;
   /* eat the encapsulation header*/
   /* the structure contains a pointer to the encapsulated data*/
   /* returns how many bytes are left after the encapsulated data*/
   *number_of_remaining_bytes = CreateEncapsulationStructure(
-      buffer, buffer_length, &encapsulation_data);
+    buffer, buffer_length, &encapsulation_data);
 
   if (kEncapsulationHeaderOptionsFlag == encapsulation_data.options) /*TODO generate appropriate error response*/
   {
@@ -249,21 +255,21 @@ int HandleReceivedExplictUdpData(int socket, struct sockaddr_in *from_address,
           break;
 
         case (kEncapsulationCommandListIdentity):
-            if(unicast == true) {
-              HandleReceivedListIdentityCommandTcp(&encapsulation_data);
-            }
-            else {
-              HandleReceivedListIdentityCommandUdp(socket, from_address,
-                                               &encapsulation_data);
-              status = kEipStatusOk;
-            }/* as the response has to be delayed do not send it now */
+          if(unicast == true) {
+            HandleReceivedListIdentityCommandTcp(&encapsulation_data);
+          }
+          else {
+            HandleReceivedListIdentityCommandUdp(socket, from_address,
+                                                 &encapsulation_data);
+            status = kEipStatusOk;
+          }  /* as the response has to be delayed do not send it now */
           break;
 
         case (kEncapsulationCommandListInterfaces):
           HandleReceivedListInterfacesCommand(&encapsulation_data);
           break;
 
-          /* The following commands are not to be sent via UDP */
+        /* The following commands are not to be sent via UDP */
         case (kEncapsulationCommandNoOperation):
         case (kEncapsulationCommandRegisterSession):
         case (kEncapsulationCommandUnregisterSession):
@@ -274,17 +280,17 @@ int HandleReceivedExplictUdpData(int socket, struct sockaddr_in *from_address,
           encapsulation_data.data_length = 0;
           break;
       }
-      
+
       if (kEipStatusOk < status) {
         /* if status is greater than 0 data has to be sent */
-        return_value = EncapsulateData(&encapsulation_data);
+        status = EncapsulateData(&encapsulation_data);
       } else if (kEipStatusError == status) {
         /* Report error state with negative return value */
-        return_value = -1;  
+        status = -1;
       }
     }
   }
-  return return_value;
+  return status;
 }
 
 int EncapsulateData(const EncapsulationData *const send_data) {
@@ -304,33 +310,33 @@ int EncapsulateData(const EncapsulationData *const send_data) {
  */
 void HandleReceivedListServicesCommand(EncapsulationData *receive_data) {
   EipUint8 *communication_buffer = receive_data
-      ->current_communication_buffer_position;
+                                   ->current_communication_buffer_position;
 
   receive_data->data_length = g_interface_information.length + 2;
 
   /* copy Interface data to msg for sending */
   AddIntToMessage(1, &communication_buffer);
   AddIntToMessage(g_interface_information.type_code, &communication_buffer);
-  AddIntToMessage((EipUint16) (g_interface_information.length - 4),
-                  &communication_buffer);
+  AddIntToMessage( (EipUint16) (g_interface_information.length - 4),
+                   &communication_buffer );
   AddIntToMessage(g_interface_information.encapsulation_protocol_version,
                   &communication_buffer);
   AddIntToMessage(g_interface_information.capability_flags,
                   &communication_buffer);
-  memcpy(communication_buffer, g_interface_information.name_of_service,
-         sizeof(g_interface_information.name_of_service));
+  memcpy( communication_buffer, g_interface_information.name_of_service,
+          sizeof(g_interface_information.name_of_service) );
 }
 
 void HandleReceivedListInterfacesCommand(EncapsulationData *receive_data) {
   EipUint8 *communication_buffer = receive_data
-      ->current_communication_buffer_position;
+                                   ->current_communication_buffer_position;
   receive_data->data_length = 2;
   AddIntToMessage(0x0000, &communication_buffer); /* copy Interface data to msg for sending */
 }
 
-void HandleReceivedListIdentityCommandTcp(EncapsulationData * receive_data) {
+void HandleReceivedListIdentityCommandTcp(EncapsulationData *receive_data) {
   receive_data->data_length = EncapsulateListIdentyResponseMessage(
-      receive_data->current_communication_buffer_position);
+    receive_data->current_communication_buffer_position);
 }
 
 void HandleReceivedListIdentityCommandUdp(int socket,
@@ -338,7 +344,8 @@ void HandleReceivedListIdentityCommandUdp(int socket,
                                           EncapsulationData *receive_data) {
   DelayedEncapsulationMessage *delayed_message_buffer = NULL;
 
-  for (unsigned int i = 0; i < ENCAP_NUMBER_OF_SUPPORTED_DELAYED_ENCAP_MESSAGES; i++) {
+  for (unsigned int i = 0; i < ENCAP_NUMBER_OF_SUPPORTED_DELAYED_ENCAP_MESSAGES;
+       i++) {
     if (kEipInvalidSocket == g_delayed_encapsulation_messages[i].socket) {
       delayed_message_buffer = &(g_delayed_encapsulation_messages[i]);
       break;
@@ -347,8 +354,8 @@ void HandleReceivedListIdentityCommandUdp(int socket,
 
   if (NULL != delayed_message_buffer) {
     delayed_message_buffer->socket = socket;
-    memcpy((&delayed_message_buffer->receiver), from_address,
-           sizeof(struct sockaddr_in));
+    memcpy( (&delayed_message_buffer->receiver), from_address,
+            sizeof(struct sockaddr_in) );
 
     DetermineDelayTime(receive_data->communication_buffer_start,
                        delayed_message_buffer);
@@ -358,7 +365,7 @@ void HandleReceivedListIdentityCommandUdp(int socket,
            ENCAPSULATION_HEADER_LENGTH);
 
     delayed_message_buffer->message_size = EncapsulateListIdentyResponseMessage(
-        &(delayed_message_buffer->message[ENCAPSULATION_HEADER_LENGTH]));
+      &(delayed_message_buffer->message[ENCAPSULATION_HEADER_LENGTH]) );
 
     EipUint8 *communication_buffer = delayed_message_buffer->message + 2;
     AddIntToMessage(delayed_message_buffer->message_size,
@@ -370,7 +377,7 @@ void HandleReceivedListIdentityCommandUdp(int socket,
 int EncapsulateListIdentyResponseMessage(EipByte *const communication_buffer) {
   EipUint8 *communication_buffer_runner = communication_buffer;
 
-  AddIntToMessage(1, &(communication_buffer_runner)); /* Item count: one item */
+  AddIntToMessage( 1, &(communication_buffer_runner) ); /* Item count: one item */
   AddIntToMessage(kCipItemIdListIdentityResponse, &communication_buffer_runner);
 
   EipByte *id_length_buffer = communication_buffer_runner;
@@ -408,14 +415,15 @@ void DetermineDelayTime(EipByte *buffer_start,
                         DelayedEncapsulationMessage *delayed_message_buffer) {
 
   buffer_start += 12; /* start of the sender context */
-  EipUint16 maximum_delay_time = GetIntFromMessage((const EipUint8 **const)&buffer_start);
+  EipUint16 maximum_delay_time = GetIntFromMessage(
+    (const EipUint8 **const)&buffer_start );
 
   if (0 == maximum_delay_time) {
     maximum_delay_time = kListIdentityDefaultDelayTime;
   } else if (kListIdentityMinimumDelayTime > maximum_delay_time) { /* if maximum_delay_time is between 1 and 500ms set it to 500ms */
     maximum_delay_time = kListIdentityMinimumDelayTime;
   }
-  delayed_message_buffer->time_out = (maximum_delay_time * rand()) / RAND_MAX; /* Sets delay time between 0 and maximum_delay_time */
+  delayed_message_buffer->time_out = ( maximum_delay_time * rand() ) / RAND_MAX; /* Sets delay time between 0 and maximum_delay_time */
 }
 
 /* @brief Check supported protocol, generate session handle, send replay back to originator.
@@ -427,13 +435,13 @@ void HandleReceivedRegisterSessionCommand(int socket,
   int session_index = 0;
   const EipUint8 *receive_data_buffer = NULL;
   EipUint16 protocol_version = GetIntFromMessage(
-      (const EipUint8 **const)&receive_data->current_communication_buffer_position);
+    (const EipUint8 **const)&receive_data->current_communication_buffer_position);
   EipUint16 nOptionFlag = GetIntFromMessage(
-      (const EipUint8 **const)&receive_data->current_communication_buffer_position);
+    (const EipUint8 **const)&receive_data->current_communication_buffer_position);
 
   /* check if requested protocol version is supported and the register session option flag is zero*/
-  if ((0 < protocol_version) && (protocol_version <= kSupportedProtocolVersion)
-      && (0 == nOptionFlag)) { /*Option field should be zero*/
+  if ( (0 < protocol_version) && (protocol_version <= kSupportedProtocolVersion)
+       && (0 == nOptionFlag) ) { /*Option field should be zero*/
     /* check if the socket has already a session open */
     for (int i = 0; i < OPENER_NUMBER_OF_SUPPORTED_SESSIONS; ++i) {
       if (g_registered_sessions[i] == socket) {
@@ -442,8 +450,10 @@ void HandleReceivedRegisterSessionCommand(int socket,
         receive_data->status = kEncapsulationProtocolInvalidCommand;
         session_index = kSessionStatusInvalid;
         receive_data_buffer =
-            &receive_data->communication_buffer_start[kEncapsulationHeaderSessionHandlePosition];
-        AddDintToMessage(receive_data->session_handle, (EipUint8 **const)&receive_data_buffer); /*EncapsulateData will not update the session handle so we have to do it here by hand*/
+          &receive_data->communication_buffer_start[
+            kEncapsulationHeaderSessionHandlePosition];
+        AddDintToMessage(receive_data->session_handle,
+                         (EipUint8 **const)&receive_data_buffer);                               /*EncapsulateData will not update the session handle so we have to do it here by hand*/
         break;
       }
     }
@@ -458,8 +468,10 @@ void HandleReceivedRegisterSessionCommand(int socket,
         receive_data->session_handle = session_index + 1;
         receive_data->status = kEncapsulationProtocolSuccess;
         receive_data_buffer =
-            &receive_data->communication_buffer_start[kEncapsulationHeaderSessionHandlePosition];
-        AddDintToMessage(receive_data->session_handle, (EipUint8 **const)&receive_data_buffer); /*EncapsulateData will not update the session handle so we have to do it here by hand*/
+          &receive_data->communication_buffer_start[
+            kEncapsulationHeaderSessionHandlePosition];
+        AddDintToMessage(receive_data->session_handle,
+                         (EipUint8 **const)&receive_data_buffer);                               /*EncapsulateData will not update the session handle so we have to do it here by hand*/
       }
     }
   } else { /* protocol not supported */
@@ -474,12 +486,12 @@ void HandleReceivedRegisterSessionCommand(int socket,
  *      pa_S_ReceiveData pointer to unregister session request with corresponding socket handle.
  */
 EipStatus HandleReceivedUnregisterSessionCommand(
-    EncapsulationData *receive_data) {
-  int i;
+  EncapsulationData *receive_data) {
 
-  if ((0 < receive_data->session_handle)
-      && (receive_data->session_handle <= OPENER_NUMBER_OF_SUPPORTED_SESSIONS)) {
-    i = receive_data->session_handle - 1;
+  if ( (0 < receive_data->session_handle)
+       && (receive_data->session_handle <=
+           OPENER_NUMBER_OF_SUPPORTED_SESSIONS) ) {
+    int i = receive_data->session_handle - 1;
     if (kEipInvalidSocket != g_registered_sessions[i]) {
       IApp_CloseSocket_tcp(g_registered_sessions[i]);
       g_registered_sessions[i] = kEipInvalidSocket;
@@ -496,23 +508,28 @@ EipStatus HandleReceivedUnregisterSessionCommand(
 /** @brief Call Connection Manager.
  *  @param receive_data Pointer to structure with data and header information.
  */
-EipStatus HandleReceivedSendUnitDataCommand(EncapsulationData *receive_data) {
+EipStatus HandleReceivedSendUnitDataCommand(EncapsulationData *receive_data,
+                                            struct sockaddr *originator_address)
+{
   EipInt16 send_size;
   EipStatus return_value = kEipStatusOkSend;
 
   if (receive_data->data_length >= 6) {
     /* Command specific data UDINT .. Interface Handle, UINT .. Timeout, CPF packets */
     /* don't use the data yet */
-    GetDintFromMessage((const EipUint8 **const)&receive_data->current_communication_buffer_position); /* skip over null interface handle*/
-    GetIntFromMessage((const EipUint8 **const)&receive_data->current_communication_buffer_position); /* skip over unused timeout value*/
+    GetDintFromMessage(
+      (const EipUint8 **const)&receive_data->current_communication_buffer_position );                 /* skip over null interface handle*/
+    GetIntFromMessage(
+      (const EipUint8 **const)&receive_data->current_communication_buffer_position );                /* skip over unused timeout value*/
     receive_data->data_length -= 6; /* the rest is in CPF format*/
 
-    if (kSessionStatusValid == CheckRegisteredSessions(receive_data)) /* see if the EIP session is registered*/
+    if ( kSessionStatusValid == CheckRegisteredSessions(receive_data) ) /* see if the EIP session is registered*/
     {
       send_size =
-          NotifyConnectedCommonPacketFormat(
-              receive_data,
-              &receive_data->communication_buffer_start[ENCAPSULATION_HEADER_LENGTH]);
+        NotifyConnectedCommonPacketFormat(
+          receive_data,
+          &receive_data->communication_buffer_start[ENCAPSULATION_HEADER_LENGTH],
+          originator_address);
 
       if (0 < send_size) { /* need to send reply */
         receive_data->data_length = send_size;
@@ -529,27 +546,30 @@ EipStatus HandleReceivedSendUnitDataCommand(EncapsulationData *receive_data) {
 
 /** @brief Call UCMM or Message Router if UCMM not implemented.
  *  @param receive_data Pointer to structure with data and header information.
- *  @return status 	0 .. success.
- * 					-1 .. error
+ *  @return status      0 .. success.
+ *                                      -1 .. error
  */
 EipStatus HandleReceivedSendRequestResponseDataCommand(
-    EncapsulationData *receive_data) {
+  EncapsulationData *receive_data, struct sockaddr *originator_address) {
   EipInt16 send_size = 0;
   EipStatus return_value = kEipStatusOkSend;
 
   if (receive_data->data_length >= 6) {
     /* Command specific data UDINT .. Interface Handle, UINT .. Timeout, CPF packets */
     /* don't use the data yet */
-    GetDintFromMessage((const EipUint8 **const)&receive_data->current_communication_buffer_position); /* skip over null interface handle*/
-    GetIntFromMessage((const EipUint8 **const)&receive_data->current_communication_buffer_position); /* skip over unused timeout value*/
+    GetDintFromMessage(
+      (const EipUint8 **const)&receive_data->current_communication_buffer_position );                 /* skip over null interface handle*/
+    GetIntFromMessage(
+      (const EipUint8 **const)&receive_data->current_communication_buffer_position );                /* skip over unused timeout value*/
     receive_data->data_length -= 6; /* the rest is in CPF format*/
 
-    if (kSessionStatusValid == CheckRegisteredSessions(receive_data)) /* see if the EIP session is registered*/
+    if ( kSessionStatusValid == CheckRegisteredSessions(receive_data) ) /* see if the EIP session is registered*/
     {
       send_size =
-          NotifyCommonPacketFormat(
-              receive_data,
-              &receive_data->communication_buffer_start[ENCAPSULATION_HEADER_LENGTH]);
+        NotifyCommonPacketFormat(
+          receive_data,
+          &receive_data->communication_buffer_start[ENCAPSULATION_HEADER_LENGTH],
+          originator_address);
 
       if (send_size >= 0) { /* need to send reply */
         receive_data->data_length = send_size;
@@ -566,10 +586,11 @@ EipStatus HandleReceivedSendRequestResponseDataCommand(
 
 /** @brief search for available sessions an return index.
  *  @return return index of free session in anRegisteredSessions.
- * 			kInvalidSession .. no free session available
+ *                      kInvalidSession .. no free session available
  */
 int GetFreeSessionIndex(void) {
-  for (int session_index = 0; session_index < OPENER_NUMBER_OF_SUPPORTED_SESSIONS; session_index++) {
+  for (int session_index = 0;
+       session_index < OPENER_NUMBER_OF_SUPPORTED_SESSIONS; session_index++) {
     if (kEipInvalidSocket == g_registered_sessions[session_index]) {
       return session_index;
     }
@@ -582,9 +603,9 @@ int GetFreeSessionIndex(void) {
  * @param length Length of the data in receive_buffer. Might be more than one message
  * @param encapsulation_data	structure to which data shall be copied
  * @return return difference between bytes in pa_buf an data_length
- *  		0 .. full package received
- * 			>0 .. more than one packet received
- * 			<0 .. only fragment of data portion received
+ *              0 .. full package received
+ *                      >0 .. more than one packet received
+ *                      <0 .. only fragment of data portion received
  */
 EipInt16 CreateEncapsulationStructure(const EipUint8 *receive_buffer,
                                       int receive_buffer_length,
@@ -597,19 +618,21 @@ EipInt16 CreateEncapsulationStructure(const EipUint8 *receive_buffer,
 
   receive_buffer += kSenderContextSize;
   encapsulation_data->options = GetDintFromMessage(&receive_buffer);
-  encapsulation_data->current_communication_buffer_position = (EipUint8 *)receive_buffer;
+  encapsulation_data->current_communication_buffer_position =
+    (EipUint8 *)receive_buffer;
   return (receive_buffer_length - ENCAPSULATION_HEADER_LENGTH
-      - encapsulation_data->data_length);
+          - encapsulation_data->data_length);
 }
 
 /** @brief Check if received package belongs to registered session.
  *  @param receive_data Received data.
  *  @return 0 .. Session registered
- *  		kInvalidSession .. invalid session -> return unsupported command received
+ *              kInvalidSession .. invalid session -> return unsupported command received
  */
 SessionStatus CheckRegisteredSessions(EncapsulationData *receive_data) {
-  if ((0 < receive_data->session_handle)
-      && (receive_data->session_handle <= OPENER_NUMBER_OF_SUPPORTED_SESSIONS)) {
+  if ( (0 < receive_data->session_handle)
+       && (receive_data->session_handle <=
+           OPENER_NUMBER_OF_SUPPORTED_SESSIONS) ) {
     if (kEipInvalidSocket
         != g_registered_sessions[receive_data->session_handle - 1]) {
       return kSessionStatusValid;
@@ -639,11 +662,12 @@ void EncapsulationShutDown(void) {
 }
 
 void ManageEncapsulationMessages(const MilliSeconds elapsed_time) {
-  for (unsigned int i = 0; i < ENCAP_NUMBER_OF_SUPPORTED_DELAYED_ENCAP_MESSAGES; i++) {
+  for (unsigned int i = 0; i < ENCAP_NUMBER_OF_SUPPORTED_DELAYED_ENCAP_MESSAGES;
+       i++) {
     if (kEipInvalidSocket != g_delayed_encapsulation_messages[i].socket) {
       g_delayed_encapsulation_messages[i].time_out -=
-          elapsed_time;
-      if (0 > g_delayed_encapsulation_messages[i].time_out) {
+        elapsed_time;
+      if (0 >= g_delayed_encapsulation_messages[i].time_out) {
         /* If delay is reached or passed, send the UDP message */
         SendUdpData(&(g_delayed_encapsulation_messages[i].receiver),
                     g_delayed_encapsulation_messages[i].socket,

+ 64 - 16
source/src/enet_encap/endianconv.c

@@ -1,6 +1,6 @@
 /*******************************************************************************
  * Copyright (c) 2009, Rockwell Automation, Inc.
- * All rights reserved. 
+ * All rights reserved.
  *
  ******************************************************************************/
 
@@ -26,13 +26,27 @@ OpenerEndianess g_opener_platform_endianess = kOpenerEndianessUnknown;
  *   @param buffer pointer where data should be reed.
  *   @return EIP_UINT8 data value
  */
-EipUint8 GetSintFromMessage(const EipUint8 **const  buffer) {
+EipUint8 GetSintFromMessage(const EipUint8 **const buffer) {
   const unsigned char *const buffer_address = (unsigned char *) *buffer;
   EipUint16 data = buffer_address[0];
   *buffer += 1;
   return data;
 }
 
+CipByte GetByteFromMessage(const CipOctet **const buffer_address) {
+  const CipOctet *buffer = *buffer_address;
+  CipByte data = buffer[0];
+  *buffer_address += 1;
+  return data;
+}
+
+CipUsint GetUsintFromMessage(const CipOctet **const buffer_address) {
+  const CipOctet *buffer = *buffer_address;
+  CipUsint data = buffer[0];
+  *buffer_address += 1;
+  return data;
+}
+
 /* little-endian-to-host unsigned 16 bit*/
 
 /**
@@ -47,6 +61,20 @@ EipUint16 GetIntFromMessage(const EipUint8 **const buffer) {
   return data;
 }
 
+CipUint GetUintFromMessage(const CipOctet **const buffer_address) {
+  const CipOctet *buffer = *buffer_address;
+  EipUint16 data = buffer[0] | buffer[1] << 8;
+  *buffer_address += 2;
+  return data;
+}
+
+CipWord GetWordFromMessage(const CipOctet **const buffer_address) {
+  const CipOctet *buffer = *buffer_address;
+  EipUint16 data = buffer[0] | buffer[1] << 8;
+  *buffer_address += 2;
+  return data;
+}
+
 /**
  *   @brief Reads EIP_UINT32 from *buffer and converts little endian to host.
  *   @param buffer pointer where data should be reed.
@@ -59,6 +87,14 @@ EipUint32 GetDintFromMessage(const EipUint8 **const buffer) {
   return data;
 }
 
+CipUdint GetUdintFromMessage(const CipOctet **const buffer_address) {
+  const CipOctet *buffer = *buffer_address;
+  CipUdint data = buffer[0] | buffer[1] << 8 | buffer[2] << 16 | buffer[3] <<
+                  24;
+  *buffer_address += 4;
+  return data;
+}
+
 /**
  * @brief converts UINT8 data from host to little endian an writes it to buffer.
  * @param data value to be written
@@ -112,15 +148,21 @@ int AddDintToMessage(const EipUint32 data, EipUint8 **const buffer) {
  */
 EipUint64 GetLintFromMessage(const EipUint8 **const buffer) {
   const EipUint8 *buffer_address = *buffer;
-  EipUint64 data = ((((EipUint64) buffer_address[0]) << 56)
-      & 0xFF00000000000000LL)
-      + ((((EipUint64) buffer_address[1]) << 48) & 0x00FF000000000000LL)
-      + ((((EipUint64) buffer_address[2]) << 40) & 0x0000FF0000000000LL)
-      + ((((EipUint64) buffer_address[3]) << 32) & 0x000000FF00000000LL)
-      + ((((EipUint64) buffer_address[4]) << 24) & 0x00000000FF000000)
-      + ((((EipUint64) buffer_address[5]) << 16) & 0x0000000000FF0000)
-      + ((((EipUint64) buffer_address[6]) << 8) & 0x000000000000FF00)
-      + (((EipUint64) buffer_address[7]) & 0x00000000000000FF);
+  EipUint64 data = ( ( ( (EipUint64) buffer_address[0] ) << 56 )
+                     & 0xFF00000000000000LL )
+                   + ( ( ( (EipUint64) buffer_address[1] ) << 48 ) &
+                       0x00FF000000000000LL )
+                   + ( ( ( (EipUint64) buffer_address[2] ) << 40 ) &
+                       0x0000FF0000000000LL )
+                   + ( ( ( (EipUint64) buffer_address[3] ) << 32 ) &
+                       0x000000FF00000000LL )
+                   + ( ( ( (EipUint64) buffer_address[4] ) << 24 ) &
+                       0x00000000FF000000 )
+                   + ( ( ( (EipUint64) buffer_address[5] ) << 16 ) &
+                       0x0000000000FF0000 )
+                   + ( ( ( (EipUint64) buffer_address[6] ) << 8 ) &
+                       0x000000000000FF00 )
+                   + ( ( (EipUint64) buffer_address[7] ) & 0x00000000000000FF );
   *buffer += 8;
   return data;
 }
@@ -148,8 +190,9 @@ int AddLintToMessage(const EipUint64 data, EipUint8 **const buffer) {
 #endif
 
 
-int EncapsulateIpAddress(EipUint16 port, EipUint32 address,
-                                           EipByte **communication_buffer) {
+int EncapsulateIpAddress(EipUint16 port,
+                         EipUint32 address,
+                         EipByte **communication_buffer) {
   int size = 0;
   if (kOpENerEndianessLittle == g_opener_platform_endianess) {
     size += AddIntToMessage(htons(AF_INET), communication_buffer);
@@ -175,7 +218,8 @@ int EncapsulateIpAddress(EipUint16 port, EipUint32 address,
       *communication_buffer += 4;
       size += 4;
     } else {
-      fprintf(stderr, "No endianess detected! Probably the DetermineEndianess function was not executed!");
+      fprintf(stderr,
+              "No endianess detected! Probably the DetermineEndianess function was not executed!");
       exit (EXIT_FAILURE);
     }
   }
@@ -211,12 +255,16 @@ void MoveMessageNOctets(int amount_of_bytes_moved, CipOctet **message_runner) {
   (*message_runner) += amount_of_bytes_moved;
 }
 
-int FillNextNMessageOctetsWith(CipOctet value, unsigned int amount_of_bytes_written, CipOctet **message) {
+int FillNextNMessageOctetsWith(CipOctet value,
+                               unsigned int amount_of_bytes_written,
+                               CipOctet **message) {
   memset(*message, value, amount_of_bytes_written);
   return amount_of_bytes_written;
 }
 
-int FillNextNMessageOctetsWithValueAndMoveToNextPosition(CipOctet value, unsigned int amount_of_filled_bytes, CipOctet **message) {
+int FillNextNMessageOctetsWithValueAndMoveToNextPosition(CipOctet value,
+                                                         unsigned int amount_of_filled_bytes,
+                                                         CipOctet **message) {
   FillNextNMessageOctetsWith(value, amount_of_filled_bytes, message);
   MoveMessageNOctets(amount_of_filled_bytes, message);
   return amount_of_filled_bytes;

+ 19 - 5
source/src/enet_encap/endianconv.h

@@ -1,6 +1,6 @@
 /*******************************************************************************
  * Copyright (c) 2009, Rockwell Automation, Inc.
- * All rights reserved. 
+ * All rights reserved.
  *
  ******************************************************************************/
 #ifndef OPENER_ENDIANCONV_H_
@@ -25,6 +25,10 @@ typedef enum {
  */
 EipUint8 GetSintFromMessage(const EipUint8 **const buffer);
 
+CipByte GetByteFromMessage(const CipOctet **const buffer_address);
+
+CipUsint GetUsintFromMessage(const CipOctet **const buffer_address);
+
 /** @ingroup ENCAP
  *
  * @brief Get an 16Bit integer from the network buffer, and moves pointer beyond the 16 bit value
@@ -33,6 +37,10 @@ EipUint8 GetSintFromMessage(const EipUint8 **const buffer);
  */
 EipUint16 GetIntFromMessage(const EipUint8 **const buffer);
 
+CipUint GetUintFromMessage(const CipOctet **const buffer_address);
+
+CipWord GetWordFromMessage(const CipOctet **const buffer_address);
+
 /** @ingroup ENCAP
  *
  * @brief Get an 32Bit integer from the network buffer.
@@ -41,6 +49,8 @@ EipUint16 GetIntFromMessage(const EipUint8 **const buffer);
  */
 EipUint32 GetDintFromMessage(const EipUint8 **const buffer);
 
+CipUdint GetUdintFromMessage(const CipOctet **const buffer_address);
+
 /** @ingroup ENCAP
  *
  * @brief converts UINT8 data from host to little endian an writes it to buffer.
@@ -93,8 +103,9 @@ int AddLintToMessage(const EipUint64 pa_unData, EipUint8 **const buffer);
  * @param address IP address of the socket, has to be provided in big-endian
  * @param communcation_buffer The message buffer for sending the message
  */
-int EncapsulateIpAddress(EipUint16 port, EipUint32 address,
-                                           EipByte **communication_buffer);
+int EncapsulateIpAddress(EipUint16 port,
+                         EipUint32 address,
+                         EipByte **communication_buffer);
 
 /** Identify if we are running on a big or little endian system and set
  * variable.
@@ -111,7 +122,10 @@ int GetEndianess(void);
 
 void MoveMessageNOctets(int n, CipOctet **message_runner);
 
-int FillNextNMessageOctetsWith(CipOctet value, unsigned int n, CipOctet **message);
+int FillNextNMessageOctetsWith(CipOctet value,unsigned int n,
+                               CipOctet **message);
 
-int FillNextNMessageOctetsWithValueAndMoveToNextPosition(CipOctet value, unsigned int n, CipOctet **message);
+int FillNextNMessageOctetsWithValueAndMoveToNextPosition(CipOctet value,
+                                                         unsigned int n,
+                                                         CipOctet **message);
 #endif /* OPENER_ENDIANCONV_H_ */

+ 63 - 37
source/src/opener_api.h

@@ -27,10 +27,11 @@
  *  @param ip_address    the current IP address of the device
  *  @param subnet_mask  the subnet mask to be used
  *  @param gateway_address     the gateway address
- *  @return EIP_OK if the configuring worked otherwise EIP_ERROR
+ *  @return kEipStatusOk if the configuring worked otherwise kEipStatusError
  */
 EipStatus
-ConfigureNetworkInterface(const char *const ip_address, const char *const subnet_mask,
+ConfigureNetworkInterface(const char *const ip_address,
+                          const char *const subnet_mask,
                           const char *const gateway_address);
 
 /** @ingroup CIP_API
@@ -104,7 +105,8 @@ CipClass *GetCipClass(const EipUint32 class_id);
  * @return pointer to CIP Instance
  *          0 if instance is not in the object
  */
-CipInstance *GetCipInstance(const CipClass *RESTRICT const cip_object, const EipUint32 instance_number);
+CipInstance *GetCipInstance(const CipClass *RESTRICT const cip_object,
+                            const EipUint32 instance_number);
 
 /** @ingroup CIP_API
  * @brief Get a pointer to an instance's attribute
@@ -144,13 +146,15 @@ CipAttributeStruct *GetCipAttribute(const CipInstance *const cip_instance,
  *  @return pointer to new class object
  *      0 on error
  */
-CipClass *CreateCipClass(const EipUint32 class_id, const int number_of_class_attributes,
+CipClass *CreateCipClass(const EipUint32 class_id,
+                         const int number_of_class_attributes,
                          const EipUint32 class_attributes_get_attribute_all_mask,
                          const int number_of_class_services,
                          const int number_of_instance_attributes,
                          const EipUint32 instance_attributes_get_attributes_all_mask,
                          const int number_of_instance_services,
-                         const int number_of_instances, char *class_name,
+                         const int number_of_instances,
+                         char *class_name,
                          const EipUint16 class_revision);
 
 /** @ingroup CIP_API
@@ -171,8 +175,9 @@ CipClass *CreateCipClass(const EipUint32 class_id, const int number_of_class_att
  * @return pointer to the first of the new instances
  *              0 on error
  */
-CipInstance *AddCipInstances(CipClass *RESTRICT const cip_object_to_add_instances,
-                             const int number_of_instances);
+CipInstance *AddCipInstances(
+  CipClass *RESTRICT const cip_object_to_add_instances,
+  const int number_of_instances);
 
 /** @ingroup CIP_API
  * @brief Create one instance of a given class with a certain instance number
@@ -200,8 +205,11 @@ CipInstance *AddCIPInstance(CipClass *RESTRICT const cip_class_to_add_instance,
  *  @param cip_data pointer to data of attribute.
  *  @param cip_flags flags to indicate set-ability and get-ability of attribute.
  */
-void InsertAttribute(CipInstance *const cip_instance, const EipUint16 attribute_number,
-                     const EipUint8 cip_data_type, void *const cip_data, const EipByte cip_flags);
+void InsertAttribute(CipInstance *const cip_instance,
+                     const EipUint16 attribute_number,
+                     const EipUint8 cip_data_type,
+                     void *const cip_data,
+                     const EipByte cip_flags);
 
 /** @ingroup CIP_API
  * @brief Insert a service in an instance of a CIP object
@@ -216,8 +224,10 @@ void InsertAttribute(CipInstance *const cip_instance, const EipUint16 attribute_
  * @param service_function pointer to function which represents the service.
  * @param service_name name of the service
  */
-void InsertService(const CipClass *const cip_class_to_add_service, const EipUint8 service_code,
-                   const CipServiceFunction service_function, char *const service_name);
+void InsertService(const CipClass *const cip_class_to_add_service,
+                   const EipUint8 service_code,
+                   const CipServiceFunction service_function,
+                   char *const service_name);
 
 /** @ingroup CIP_API
  * @brief Produce the data according to CIP encoding onto the message buffer.
@@ -230,7 +240,9 @@ void InsertService(const CipClass *const cip_class_to_add_service, const EipUint
  *  @return length of attribute in bytes
  *          -1 .. error
  */
-int EncodeData(const EipUint8 cip_data_type, const void *const cip_data, EipUint8 **cip_message);
+int EncodeData(const EipUint8 cip_data_type,
+               const void *const cip_data,
+               EipUint8 **cip_message);
 
 /** @ingroup CIP_API
  * @brief Retrieve the given data according to CIP encoding from the message
@@ -244,7 +256,9 @@ int EncodeData(const EipUint8 cip_data_type, const void *const cip_data, EipUint
  *  @return length of taken bytes
  *          -1 .. error
  */
-int DecodeData(const EipUint8 cip_type, void *const data, const EipUint8 **const message);
+int DecodeData(const EipUint8 cip_type,
+               void *const data,
+               const EipUint8 **const message);
 
 /** @ingroup CIP_API
  * @brief Create an instance of an assembly object
@@ -263,7 +277,8 @@ int DecodeData(const EipUint8 cip_type, void *const data, const EipUint8 **const
  * The notification on received configuration data is handled with the
  * IApp_after_receive function.
  */
-CipInstance *CreateAssemblyObject(const EipUint32 instance_number, EipByte *const data,
+CipInstance *CreateAssemblyObject(const EipUint32 instance_number,
+                                  EipByte *const data,
                                   const EipUint16 data_length);
 
 typedef struct connection_object ConnectionObject;
@@ -278,7 +293,8 @@ typedef struct connection_object ConnectionObject;
  * @return CIP error code
  */
 typedef EipStatus (*OpenConnectionFunction)(
-    ConnectionObject *RESTRICT const connection_object, EipUint16 *const extended_error_code);
+  ConnectionObject *RESTRICT const connection_object,
+  EipUint16 *const extended_error_code);
 
 /** @ingroup CIP_API
  * @brief Function prototype for handling the closing of connections
@@ -287,7 +303,7 @@ typedef EipStatus (*OpenConnectionFunction)(
  * connection
  */
 typedef void (*ConnectionCloseFunction)(
-    struct connection_object *connection_object);
+  struct connection_object *connection_object);
 
 /** @ingroup CIP_API
  * @brief Function prototype for handling the timeout of connections
@@ -295,7 +311,7 @@ typedef void (*ConnectionCloseFunction)(
  * @param connection_object The connection object which connection timed out
  */
 typedef void (*ConnectionTimeoutFunction)(
-    struct connection_object *connection_object);
+  struct connection_object *connection_object);
 
 /** @ingroup CIP_API
  * @brief Function prototype for sending data via a connection
@@ -305,7 +321,7 @@ typedef void (*ConnectionTimeoutFunction)(
  * @return EIP stack status
  */
 typedef EipStatus (*ConnectionSendDataFunction)(
-    struct connection_object *connection_object);
+  struct connection_object *connection_object);
 
 /** @ingroup CIP_API
  * @brief Function prototype for receiving data via a connection
@@ -317,8 +333,8 @@ typedef EipStatus (*ConnectionSendDataFunction)(
  * @return Stack status
  */
 typedef EipStatus (*ConnectionReceiveDataFunction)(
-    struct connection_object *connection_object, const EipUint8 *data,
-    const EipUint16 data_length);
+  struct connection_object *connection_object, const EipUint8 *data,
+  const EipUint16 data_length);
 
 /** @ingroup CIP_API
  * @brief register open functions for an specific object.
@@ -326,7 +342,7 @@ typedef EipStatus (*ConnectionReceiveDataFunction)(
  * With this function any object can be enabled to be a target for forward
  * open/close request.
  * @param class_id The class ID
- * @param open_connection_function   pointer to the function handling the open
+ * @param open_connection_function Pointer to the function handling the open
  * process
  * @return EIP_OK on success
  */
@@ -348,8 +364,10 @@ AddConnectableObject(EipUint32 class_id,
  * this connection
  */
 void ConfigureExclusiveOwnerConnectionPoint(
-    const unsigned int connection_number, const unsigned int output_assembly_id,
-    const unsigned int input_assembly_id, const unsigned int configuration_assembly_id);
+  const unsigned int connection_number,
+  const unsigned int output_assembly_id,
+  const unsigned int input_assembly_id,
+  const unsigned int configuration_assembly_id);
 
 /** @ingroup CIP_API
  * @brief Configures the connection point for an input only connection.
@@ -362,7 +380,7 @@ void ConfigureExclusiveOwnerConnectionPoint(
  * @param input_assembly_id ID of the T-to-O point to be used for this
  * connection
  * @param configuration_assembly_id ID of the configuration point to be used for
- *this connection
+ * this connection
  */
 void ConfigureInputOnlyConnectionPoint(const unsigned int connection_number,
                                        const unsigned int output_assembly_id,
@@ -399,9 +417,11 @@ void ConfigureListenOnlyConnectionPoint(const unsigned int connection_number,
  * over after we're done here
  * @return length of reply that need to be sent back
  */
-int HandleReceivedExplictTcpData(int socket, EipUint8 *buffer,
+int HandleReceivedExplictTcpData(int socket,
+                                 EipUint8 *buffer,
                                  unsigned int buffer_length,
-                                 int *number_of_remaining_bytes);
+                                 int *number_of_remaining_bytes,
+                                 struct sockaddr *originator_address);
 
 /** @ingroup CIP_API
  * @brief Notify the encapsulation layer that an explicit message has been
@@ -416,9 +436,12 @@ int HandleReceivedExplictTcpData(int socket, EipUint8 *buffer,
  * over after we're done here
  * @return length of reply that need to be sent back
  */
-int HandleReceivedExplictUdpData(int socket, struct sockaddr_in *from_address,
-                                 EipUint8 *buffer, unsigned int buffer_length,
-                                 int *number_of_remaining_bytes, int unicast);
+int HandleReceivedExplictUdpData(int socket,
+                                 struct sockaddr_in *from_address,
+                                 EipUint8 *buffer,
+                                 unsigned int buffer_length,
+                                 int *number_of_remaining_bytes,
+                                 int unicast);
 
 /** @ingroup CIP_API
  *  @brief Notify the connection manager that data for a connection has been
@@ -433,7 +456,8 @@ int HandleReceivedExplictUdpData(int socket, struct sockaddr_in *from_address,
  *  @return EIP_OK on success
  */
 EipStatus
-HandleReceivedConnectedData(EipUint8 *received_data, int received_data_length,
+HandleReceivedConnectedData(EipUint8 *received_data,
+                            int received_data_length,
                             struct sockaddr_in *from_address);
 
 /** @ingroup CIP_API
@@ -525,8 +549,8 @@ void HandleApplication(void);
  * @param io_connection_event information on the change occurred
  */
 void CheckIoConnectionEvent(unsigned int output_assembly_id,
-                       unsigned int input_assembly_id,
-                       IoConnectionEvent io_connection_event);
+                            unsigned int input_assembly_id,
+                            IoConnectionEvent io_connection_event);
 
 /** @ingroup CIP_CALLBACK_API
  * @brief Call back function to inform application on received data for an
@@ -592,13 +616,13 @@ ResetDeviceToInitialConfiguration(void);
  * @param size_of_element size in bytes of one element
  * @return pointer to the allocated memory, 0 on error
  */
-void *CipCalloc(unsigned int number_of_elements, unsigned int size_of_element);
+void *CipCalloc(size_t number_of_elements, size_t size_of_element);
 
 /** @ingroup CIP_CALLBACK_API
  * @brief Free memory allocated by the OpENer
  *
  * emulate the common c-library function free
- * @param pa_poData pointer to the allocated memory
+ * @param data pointer to the allocated memory
  */
 void CipFree(void *data);
 
@@ -640,7 +664,9 @@ int CreateUdpSocket(UdpCommuncationDirection communication_direction,
  * @return  EIP_SUCCESS on success
  */
 EipStatus
-SendUdpData(struct sockaddr_in *socket_data, int socket, EipUint8 *data,
+SendUdpData(struct sockaddr_in *socket_data,
+            int socket,
+            EipUint8 *data,
             EipUint16 data_length);
 
 /** @ingroup CIP_CALLBACK_API
@@ -651,7 +677,7 @@ SendUdpData(struct sockaddr_in *socket_data, int socket, EipUint8 *data,
 void CloseSocket(int socket);
 
 /** @mainpage OpENer - Open Source EtherNet/IP(TM) Communication Stack
- *Documentation
+ * Documentation
  *
  * EtherNet/IP stack for adapter devices (connection target); supports multiple
  * I/O and explicit connections; includes features and objects required by the
@@ -785,7 +811,7 @@ void CloseSocket(int socket);
  * CloseSocket(int socket_handle)
  *      -# For TCP connection when the peer closed the connection OpENer needs
  *         to be informed to clean up internal data structures. This is done
- *with
+ * with
  *         the function void CloseSession(int socket_handle).
  *      .
  *   - Cyclically update the connection status:\n

+ 6 - 5
source/src/ports/POSIX/main.c

@@ -1,6 +1,6 @@
 /*******************************************************************************
  * Copyright (c) 2009, Rockwell Automation, Inc.
- * All rights reserved. 
+ * All rights reserved.
  *
  ******************************************************************************/
 #include <stdio.h>
@@ -33,9 +33,9 @@ int main(int argc, char *arg[]) {
     printf("Wrong number of command line parameters!\n");
     printf("The correct command line parameters are:\n");
     printf(
-        "./OpENer ipaddress subnetmask gateway domainname hostaddress macaddress\n");
+      "./OpENer ipaddress subnetmask gateway domainname hostaddress macaddress\n");
     printf(
-        "    e.g. ./OpENer 192.168.0.2 255.255.255.0 192.168.0.1 test.com testdevice 00 15 C5 BF D0 87\n");
+      "    e.g. ./OpENer 192.168.0.2 255.255.255.0 192.168.0.1 test.com testdevice 00 15 C5 BF D0 87\n");
     exit(0);
   } else {
     /* fetch Internet address info from the platform */
@@ -64,7 +64,7 @@ int main(int argc, char *arg[]) {
   CipStackInit(unique_connection_id);
 
   /* Setup Network Handles */
-  if (kEipStatusOk == NetworkHandlerInitialize()) {
+  if ( kEipStatusOk == NetworkHandlerInitialize() ) {
     g_end_stack = 0;
 #ifndef WIN32
     /* register for closing signals so that we can trigger the stack to end */
@@ -73,7 +73,8 @@ int main(int argc, char *arg[]) {
 
     /* The event loop. Put other processing you need done continually in here */
     while (1 != g_end_stack) {
-      if (kEipStatusOk != NetworkHandlerProcessOnce()) {
+      if ( kEipStatusOk != NetworkHandlerProcessOnce() ) {
+        OPENER_TRACE_ERR("Error in NetworkHandler loop! Exiting OpENer!\n");
         break;
       }
     }

+ 11 - 4
source/src/ports/POSIX/networkhandler.c

@@ -6,6 +6,7 @@
 #include <unistd.h>
 #include <sys/time.h>
 #include <time.h>
+#include <fcntl.h>
 
 #include "networkhandler.h"
 
@@ -15,7 +16,8 @@ MicroSeconds GetMicroSeconds(void) {
   struct timespec now;
 
   clock_gettime( CLOCK_MONOTONIC, &now );
-  MicroSeconds micro_seconds =  (MicroSeconds)now.tv_nsec / 1000ULL + now.tv_sec * 1000000ULL;
+  MicroSeconds micro_seconds =  (MicroSeconds)now.tv_nsec / 1000ULL +
+                               now.tv_sec * 1000000ULL;
   return micro_seconds;
 }
 
@@ -28,8 +30,13 @@ EipStatus NetworkHandlerInitializePlatform(void) {
   return kEipStatusOk;
 }
 
-
 void CloseSocketPlatform(int socket_handle) {
-    shutdown(socket_handle, SHUT_RDWR);
-    close(socket_handle);
+  shutdown(socket_handle, SHUT_RDWR);
+  close(socket_handle);
+}
+
+int SetSocketToNonBlocking(int socket_handle) {
+  return fcntl(socket_handle, F_SETFL, fcntl(socket_handle,
+                                             F_GETFL,
+                                             0) | O_NONBLOCK);
 }

+ 10 - 0
source/src/ports/POSIX/networkhandler.h

@@ -11,10 +11,20 @@
 
 #include "typedefs.h"
 
+/** @brief Executes platform dependent network handler initialization code
+ *
+ *      @return EipStatusOk if initialization was successful, otherwise EipStatusError
+ */
 EipStatus NetworkHandlerInitializePlatform(void);
 
+/** @brief Platform dependent code to close a socket
+ *
+ *  @param socket_handle The socket handle to be closed
+ */
 void CloseSocketPlatform(int socket_handle);
 
+int SetSocketToNonBlocking(int socket_handle);
+
 /** @brief This function shall return the current time in microseconds relative to epoch, and shall be implemented in a port specific networkhandler
  *
  *  @return Current time relative to epoch as MicroSeconds

+ 3 - 3
source/src/ports/POSIX/opener_error.c

@@ -17,15 +17,15 @@
 
 #include "opener_error.h"
 
-const int error_message_buffer_size = 255;
+const int kErrorMessageBufferSize = 255;
 
 int GetSocketErrorNumber() {
   return errno;
 }
 
 char *GetErrorMessage(int error_number) {
-  char *error_message = malloc(error_message_buffer_size);
-  strerror_r(error_number, error_message, error_message_buffer_size);
+  char *error_message = malloc(kErrorMessageBufferSize);
+  strerror_r(error_number, error_message, kErrorMessageBufferSize);
   return error_message;
 }
 

+ 17 - 9
source/src/ports/POSIX/sample_application/opener_user_conf.h

@@ -1,6 +1,6 @@
 /*******************************************************************************
  * Copyright (c) 2009, Rockwell Automation, Inc.
- * All rights reserved. 
+ * All rights reserved.
  *
  ******************************************************************************/
 #ifndef OPENER_USER_CONF_H_
@@ -8,9 +8,9 @@
 
 /** @file opener_user_conf.h
  * @brief OpENer configuration setup
- * 
+ *
  * This file contains the general application specific configuration for OpENer.
- * 
+ *
  * Furthermore you have to specific platform specific network include files.
  * OpENer needs definitions for the following data-types
  * and functions:
@@ -25,6 +25,7 @@
 #include <sys/socket.h>
 #include <arpa/inet.h>
 #include <sys/select.h>
+#include <assert.h>
 
 #include "typedefs.h"
 
@@ -116,19 +117,26 @@ static const int kOpenerProducedDataHasRunIdleHeader = 0;
 /** @brief A specialized assertion command that will log the assertion and block
  *  further execution in an while(1) loop.
  */
+#ifdef IDLING_ASSERT
 #define OPENER_ASSERT(assertion) \
-    do { \
-      if(!(assertion)) { \
-        LOG_TRACE("Assertion \"%s\" failed: file \"%s\", line %d\n", #assertion, __FILE__, __LINE__); \
-        while(1){;} \
-      } \
-    } while(0)
+  do { \
+    if( !(assertion) ) { \
+      LOG_TRACE("Assertion \"%s\" failed: file \"%s\", line %d\n", \
+                # assertion, \
+                __FILE__, \
+                __LINE__); \
+      while(1) {; } \
+    } \
+  } while(0)
 
 /* else use standard assert() */
 //#include <assert.h>
 //#include <stdio.h>
 //#define OPENER_ASSERT(assertion) assert(assertion)
 #else
+#define OPENER_ASSERT(assertion) assert(assertion)
+#endif
+#else
 
 /* for release builds execute the assertion, but don't test it */
 #define OPENER_ASSERT(assertion) (assertion)

+ 21 - 17
source/src/ports/POSIX/sample_application/sampleapplication.c

@@ -4,9 +4,12 @@
  *
  ******************************************************************************/
 
-#include "opener_api.h"
 #include <string.h>
 #include <stdlib.h>
+#include <stdbool.h>
+
+#include "opener_api.h"
+#include "appcontype.h"
 
 #define DEMO_APP_INPUT_ASSEMBLY_NUM                100 //0x064
 #define DEMO_APP_OUTPUT_ASSEMBLY_NUM               150 //0x096
@@ -25,16 +28,16 @@ EipUint8 g_assembly_data09A[32]; /* Explicit */
 EipStatus ApplicationInitialization(void) {
   /* create 3 assembly object instances*/
   /*INPUT*/
-  CreateAssemblyObject(DEMO_APP_INPUT_ASSEMBLY_NUM, g_assembly_data064,
-                       sizeof(g_assembly_data064));
+  CreateAssemblyObject( DEMO_APP_INPUT_ASSEMBLY_NUM, g_assembly_data064,
+                        sizeof(g_assembly_data064) );
 
   /*OUTPUT*/
-  CreateAssemblyObject(DEMO_APP_OUTPUT_ASSEMBLY_NUM, g_assembly_data096,
-                       sizeof(g_assembly_data096));
+  CreateAssemblyObject( DEMO_APP_OUTPUT_ASSEMBLY_NUM, g_assembly_data096,
+                        sizeof(g_assembly_data096) );
 
   /*CONFIG*/
-  CreateAssemblyObject(DEMO_APP_CONFIG_ASSEMBLY_NUM, g_assembly_data097,
-                       sizeof(g_assembly_data097));
+  CreateAssemblyObject( DEMO_APP_CONFIG_ASSEMBLY_NUM, g_assembly_data097,
+                        sizeof(g_assembly_data097) );
 
   /*Heart-beat output assembly for Input only connections */
   CreateAssemblyObject(DEMO_APP_HEARTBEAT_INPUT_ONLY_ASSEMBLY_NUM, NULL, 0);
@@ -43,18 +46,18 @@ EipStatus ApplicationInitialization(void) {
   CreateAssemblyObject(DEMO_APP_HEARTBEAT_LISTEN_ONLY_ASSEMBLY_NUM, NULL, 0);
 
   /* assembly for explicit messaging */
-  CreateAssemblyObject(DEMO_APP_EXPLICT_ASSEMBLY_NUM, g_assembly_data09A,
-                       sizeof(g_assembly_data09A));
+  CreateAssemblyObject( DEMO_APP_EXPLICT_ASSEMBLY_NUM, g_assembly_data09A,
+                        sizeof(g_assembly_data09A) );
 
   ConfigureExclusiveOwnerConnectionPoint(0, DEMO_APP_OUTPUT_ASSEMBLY_NUM,
-  DEMO_APP_INPUT_ASSEMBLY_NUM,
+                                         DEMO_APP_INPUT_ASSEMBLY_NUM,
                                          DEMO_APP_CONFIG_ASSEMBLY_NUM);
   ConfigureInputOnlyConnectionPoint(0,
-  DEMO_APP_HEARTBEAT_INPUT_ONLY_ASSEMBLY_NUM,
+                                    DEMO_APP_HEARTBEAT_INPUT_ONLY_ASSEMBLY_NUM,
                                     DEMO_APP_INPUT_ASSEMBLY_NUM,
                                     DEMO_APP_CONFIG_ASSEMBLY_NUM);
   ConfigureListenOnlyConnectionPoint(0,
-  DEMO_APP_HEARTBEAT_LISTEN_ONLY_ASSEMBLY_NUM,
+                                     DEMO_APP_HEARTBEAT_LISTEN_ONLY_ASSEMBLY_NUM,
                                      DEMO_APP_INPUT_ASSEMBLY_NUM,
                                      DEMO_APP_CONFIG_ASSEMBLY_NUM);
 
@@ -66,8 +69,8 @@ void HandleApplication(void) {
 }
 
 void CheckIoConnectionEvent(unsigned int output_assembly_id,
-                       unsigned int input_assembly_id,
-                       IoConnectionEvent io_connection_event) {
+                            unsigned int input_assembly_id,
+                            IoConnectionEvent io_connection_event) {
   /* maintain a correct output state according to the connection state*/
 
   (void) output_assembly_id; /* suppress compiler warning */
@@ -83,8 +86,8 @@ EipStatus AfterAssemblyDataReceived(CipInstance *instance) {
     case DEMO_APP_OUTPUT_ASSEMBLY_NUM:
       /* Data for the output assembly has been received.
        * Mirror it to the inputs */
-      memcpy(&g_assembly_data064[0], &g_assembly_data096[0],
-             sizeof(g_assembly_data064));
+      memcpy( &g_assembly_data064[0], &g_assembly_data096[0],
+              sizeof(g_assembly_data064) );
       break;
     case DEMO_APP_EXPLICT_ASSEMBLY_NUM:
       /* do something interesting with the new data from
@@ -118,6 +121,7 @@ EipBool8 BeforeAssemblyDataSend(CipInstance *pa_pstInstance) {
 
 EipStatus ResetDevice(void) {
   /* add reset code here*/
+  CloseAllConnections();
   return kEipStatusOk;
 }
 
@@ -130,7 +134,7 @@ EipStatus ResetDeviceToInitialConfiguration(void) {
 }
 
 void *
-CipCalloc(unsigned int number_of_elements, unsigned size_of_element) {
+CipCalloc(size_t number_of_elements, size_t size_of_element) {
   return calloc(number_of_elements, size_of_element);
 }
 

+ 7 - 2
source/src/ports/WIN32/networkhandler.c

@@ -24,7 +24,7 @@ MicroSeconds getMicroSeconds() {
   QueryPerformanceFrequency(&performance_frequency);
 
   return (MicroSeconds) (performance_counter.QuadPart * 1000000LL
-      / performance_frequency.QuadPart);
+                         / performance_frequency.QuadPart);
 }
 
 MilliSeconds GetMilliSeconds(void) {
@@ -42,5 +42,10 @@ EipStatus NetworkHandlerInitializePlatform(void) {
 }
 
 void CloseSocketPlatform(int socket_handle) {
-    closesocket(socket_handle);
+  closesocket(socket_handle);
+}
+
+int SetSocketToNonBlocking(int socket_handle) {
+  u_long iMode = 0;
+  ioctlsocket(m_socket, FIONBIO, &iMode);
 }

+ 6 - 0
source/src/ports/WIN32/networkhandler.h

@@ -12,8 +12,14 @@ typedef unsigned long socklen_t;
 
 EipStatus NetworkHandlerInitializePlatform(void);
 
+/** @brief Platform dependent code to close a socket
+ *
+ *  @param socket_handle The socket handle to be closed
+ */
 void CloseSocketPlatform(int socket_handle);
 
+int SetSocketToNonBlocking(int socket_handle);
+
 /** @brief This function shall return the current time in microseconds relative to epoch, and shall be implemented in a port specific networkhandler
  *
  *  @return Current time relative to epoch as MicroSeconds

+ 13 - 7
source/src/ports/WIN32/opener_error.c

@@ -15,16 +15,22 @@
  #include "opener_error.h"
 
 int GetSocketErrorNumber() {
-	return WSAGetLastError();
+  return WSAGetLastError();
 }
 
 char *GetErrorMessage(int error_number) {
-  	char *error_message = NULL;
-  	FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, error_number, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
-               &error_message, 0, NULL);
-  	return error_message;
+  char *error_message = NULL;
+  FormatMessage(
+    FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
+    NULL,
+    error_number,
+    MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+    &error_message,
+    0,
+    NULL);
+  return error_message;
 }
 
 void FreeErrorMessage(char *error_message) {
-	LocalFree(error_message);
-}
+  LocalFree(error_message);
+}

+ 28 - 7
source/src/ports/generic_networkhandler.c

@@ -12,6 +12,8 @@
  */
 
 #include <assert.h>
+#include <stdbool.h>
+#include <unistd.h>
 
 #include "generic_networkhandler.h"
 
@@ -51,8 +53,8 @@ EipStatus HandleDataOnTcpSocket(int socket);
 void CheckEncapsulationInactivity(int socket_handle);
 
 /*************************************************
- * Function implementations from now on
- *************************************************/
+* Function implementations from now on
+*************************************************/
 
 EipStatus NetworkHandlerInitialize(void) {
 
@@ -87,6 +89,8 @@ EipStatus NetworkHandlerInitialize(void) {
     return kEipStatusError;
   }
 
+  int status = SetSocketToNonBlocking(g_network_status.tcp_listener);
+
   /* create a new UDP socket */
   if ( ( g_network_status.udp_global_broadcast_listener = socket(AF_INET,
                                                                  SOCK_DGRAM,
@@ -122,6 +126,9 @@ EipStatus NetworkHandlerInitialize(void) {
     return kEipStatusError;
   }
 
+  status =
+    SetSocketToNonBlocking(g_network_status.udp_global_broadcast_listener);
+
   /* Activates address reuse */
   if (setsockopt( g_network_status.udp_unicast_listener, SOL_SOCKET,
                   SO_REUSEADDR, (char *) &set_socket_option_value,
@@ -131,6 +138,8 @@ EipStatus NetworkHandlerInitialize(void) {
     return kEipStatusError;
   }
 
+  status = SetSocketToNonBlocking(g_network_status.udp_unicast_listener);
+
   struct sockaddr_in my_address = { .sin_family = AF_INET, .sin_port = htons(
                                       kOpenerEthernetPort),
                                     .sin_addr.s_addr = interface_configuration_
@@ -251,7 +260,7 @@ EipBool8 CheckSocketSet(int socket) {
 }
 
 void CheckAndHandleTcpListenerSocket(void) {
-  int new_socket;
+  int new_socket = kEipInvalidSocket;
   /* see if this is a connection request to the TCP listener*/
   if ( true == CheckSocketSet(g_network_status.tcp_listener) ) {
     OPENER_TRACE_INFO("networkhandler: new TCP connection\n");
@@ -335,7 +344,7 @@ EipStatus NetworkHandlerProcessOnce(void) {
    * This should compensate the jitter of the windows timer
    */
   if (g_network_status.elapsed_time >= kOpenerTimerTickInMilliSeconds) {
-    /* call manage_connections() in connection manager every OPENER_TIMER_TICK ms */
+    /* call manage_connections() in connection manager every kOpenerTimerTickInMilliSeconds ms */
     ManageConnections(g_network_status.elapsed_time);
     g_network_status.elapsed_time = 0;
   }
@@ -532,7 +541,7 @@ EipStatus HandleDataOnTcpSocket(int socket) {
     return kEipStatusError;
   }
 
-  EipUint8 *read_buffer = &g_ethernet_communication_buffer[2]; /* at this place EIP stores the data length */
+  const EipUint8 *read_buffer = &g_ethernet_communication_buffer[2]; /* at this place EIP stores the data length */
   size_t data_size = GetIntFromMessage(&read_buffer)
                      + ENCAPSULATION_HEADER_LENGTH - 4; /* -4 is for the 4 bytes we have already read*/
   /* (NOTE this advances the buffer pointer) */
@@ -542,6 +551,9 @@ EipStatus HandleDataOnTcpSocket(int socket) {
     /* Currently we will drop the whole packet */
 
     do {
+      OPENER_TRACE_INFO(
+        "Entering consumption loop, remaining data to receive: %zu\n",
+        data_sent);
       number_of_read_bytes = recv(socket, &g_ethernet_communication_buffer[0],
                                   data_sent, 0);
       g_timestamps[socket] = g_actual_time;
@@ -597,7 +609,7 @@ EipStatus HandleDataOnTcpSocket(int socket) {
     return kEipStatusError;
   }
 
-  if ((unsigned) number_of_read_bytes == data_size) {
+  if ( (unsigned) number_of_read_bytes == data_size ) {
     /*we got the right amount of data */
     data_size += 4;
     /*TODO handle partial packets*/
@@ -605,8 +617,14 @@ EipStatus HandleDataOnTcpSocket(int socket) {
 
     g_current_active_tcp_socket = socket;
 
+    struct sockaddr sender_address;
+    memset( &sender_address, 0, sizeof(sender_address) );
+    socklen_t fromlen = sizeof(sender_address);
+    getpeername(socket, (struct sockaddr *)&sender_address, &fromlen);
+
     number_of_read_bytes = HandleReceivedExplictTcpData(
-      socket, g_ethernet_communication_buffer, data_size, &remaining_bytes);
+      socket, g_ethernet_communication_buffer, data_size, &remaining_bytes,
+      &sender_address);
     g_timestamps[socket] = g_actual_time;
 
     g_current_active_tcp_socket = -1;
@@ -665,6 +683,9 @@ int CreateUdpSocket(UdpCommuncationDirection communication_direction,
     return kEipInvalidSocket;
   }
 
+  int status = SetSocketToNonBlocking(new_socket);
+
+
   OPENER_TRACE_INFO("networkhandler: UDP socket %d\n", new_socket);
 
   /* check if it is sending or receiving */

+ 24 - 25
source/src/typedefs.h

@@ -8,18 +8,19 @@
 
 #include <inttypes.h>
 #include <stddef.h>
+#include <stdbool.h>
 
 /** @file typedefs.h
- Do not use interface types for internal variables, such as "int i;", which is
- commonly used for loop counters or counting things.
+   Do not use interface types for internal variables, such as "int i;", which is
+   commonly used for loop counters or counting things.
 
- Do not over-constrain data types. Prefer the use of the native "int" and
- "unsigned" types.
+   Do not over-constrain data types. Prefer the use of the native "int" and
+   "unsigned" types.
 
- Use char for native character strings.
+   Use char for native character strings.
 
- Do not use "char" for data buffers - use "unsigned char" instead. Using char
- for data buffers can occasionally blow up in your face rather nastily.
+   Do not use "char" for data buffers - use "unsigned char" instead. Using char
+   for data buffers can occasionally blow up in your face rather nastily.
  */
 
 /** @brief EIP Data type definitions
@@ -69,20 +70,20 @@ typedef unsigned long long MicroSeconds;
 
 /**
 
- The following are generally true regarding return status:
- -1 ... an error occurred
- 0 ... success
+   The following are generally true regarding return status:
+   -1 ... an error occurred
+   0 ... success
 
- Occasionally there is a variation on this:
- -1 ... an error occurred
- 0 ..  success and there is no reply to send
- 1 ... success and there is a reply to send
+   Occasionally there is a variation on this:
+   -1 ... an error occurred
+   0 ..  success and there is no reply to send
+   1 ... success and there is a reply to send
 
- For both of these cases EIP_STATUS is the return type.
+   For both of these cases EIP_STATUS is the return type.
 
- Other return type are:
- -- return pointer to thing, 0 if error (return type is "pointer to thing")
- -- return count of something, -1 if error, (return type is int)
+   Other return type are:
+   -- return pointer to thing, 0 if error (return type is "pointer to thing")
+   -- return count of something, -1 if error, (return type is int)
 
  */
 
@@ -106,14 +107,12 @@ typedef enum {
 } UdpCommuncationDirection;
 
 #ifndef __cplusplus
-#if !defined(__bool_true_false_are_defined)
-/** @brief If not yet done (through C++ or stdbool.h (C99)), define "true" and "false" keywords
+/** @brief If we don't have C++ define a C++ -like "bool" keyword defines
  */
-typedef enum {
-  false = 0, /**< defines "false" as 0 */
-  true = 1 /**< defines "true" as 1 */
-} BoolKeywords;
-#endif /* __bool_true_false_are_defined */
+//typedef enum {
+//  false = 0, /**< defines "false" as 0 */
+//  true = 1 /**< defines "true" as 1 */
+//} BoolKeywords;
 #endif /* __cplusplus */
 
 #endif /* OPENER_TYPEDEFS_H_ */

+ 9 - 3
source/src/utils/random.c

@@ -10,7 +10,13 @@
 #include <stdlib.h>
 
 Random *RandomNew(SetSeed set_seed, GetNextUInt32 get_next_uint32) {
-  Random *out = malloc(sizeof(Random));
-  *out = (Random ) { .set_seed = set_seed, .get_next_uint32 = get_next_uint32 };
-  return out;
+  Random *random = malloc( sizeof(Random) );
+  *random =
+    (Random ) { .set_seed = set_seed, .get_next_uint32 = get_next_uint32 };
+  return random;
+}
+
+void RandomDelete(Random **random) {
+  free(*random);
+  *random = NULL;
 }

+ 3 - 1
source/src/utils/random.h

@@ -19,6 +19,8 @@ typedef struct {
   GetNextUInt32 get_next_uint32; /**< Function pointer to GetNextUInt32 function */
 } Random;
 
-Random* RandomNew(SetSeed, GetNextUInt32);
+Random *RandomNew(SetSeed, GetNextUInt32);
+
+void RandomDelete(Random **random);
 
 #endif /* OPENER_RANDOM_H_ */

+ 1 - 1
source/src/utils/xorshiftrandom.h

@@ -17,7 +17,7 @@
 
 /**
  * @brief Sets the initial seed for the XOR shift pseudo-random algorithm
- * @param pa_nSeed The initial seed value
+ * @param seed The initial seed value
  */
 void SetXorShiftSeed(uint32_t seed);
 

+ 2 - 0
source/tests/CMakeLists.txt

@@ -13,6 +13,7 @@ add_test_includes()
 ###################################################
 #configure_file( CTestCustom.cmake ${PROJECT_BINARY_DIR}/CTestCustom.cmake )
 
+add_subdirectory( cip )
 add_subdirectory( utils )
 add_subdirectory( enet_encap )
 add_executable( OpENer_Tests OpENerTests.cpp )
@@ -23,6 +24,7 @@ find_library ( CPPUTESTEXT_LIBRARY CppUTestExt ${CPPUTEST_HOME}/cpputest_build/l
 target_link_libraries( OpENer_Tests gcov ${CPPUTEST_LIBRARY} ${CPPUTESTEXT_LIBRARY} )
 target_link_libraries( OpENer_Tests UtilsTest Utils ) 
 target_link_libraries( OpENer_Tests EthernetEncapsulationTest ENET_ENCAP )
+target_link_libraries( OpENer_Tests CipTest CIP )
 
 ########################################
 # Adds test to CTest environment       #

+ 2 - 0
source/tests/OpENerTests.h

@@ -3,3 +3,5 @@
 IMPORT_TEST_GROUP(RandomClass);
 IMPORT_TEST_GROUP(XorShiftRandom);
 IMPORT_TEST_GROUP(EndianConversion);
+IMPORT_TEST_GROUP(CipEpath);
+IMPORT_TEST_GROUP(CipElectronicKey);

+ 10 - 0
source/tests/cip/CMakeLists.txt

@@ -0,0 +1,10 @@
+
+opener_common_includes()
+
+set( CipTestSrc cipepathtest.cpp cipelectronickeytest.cpp )
+
+include_directories( ${SRC_DIR}/cip )
+
+add_library( CipTest ${CipTestSrc} )
+
+target_link_libraries( CipTest gcov ${CPPUTEST_LIBRARY} ${CPPUTESTEXT_LIBRARY} )

+ 162 - 0
source/tests/cip/cipelectronickeytest.cpp

@@ -0,0 +1,162 @@
+/*******************************************************************************
+ * Copyright (c) 2016, Rockwell Automation, Inc.
+ * All rights reserved.
+ *
+ ******************************************************************************/
+
+#include <CppUTest/TestHarness.h>
+#include <stdint.h>
+#include <string.h>
+
+extern "C" {
+
+#include "cipepath.h"
+#include "cipelectronickey.h"
+
+}
+
+TEST_GROUP(CipElectronicKey) {
+  ElectronicKeyFormat4 *key = NULL;
+
+  void setup() {
+    key = ElectronicKeyFormat4New();
+  }
+
+  void teardown() {
+    ElectronicKeyFormat4Delete(&key);
+  }
+
+};
+
+TEST(CipElectronicKey, CreateElectronicKey) {
+  char dummyArea[kElectronicKeyFormat4Size] = {0};
+  MEMCMP_EQUAL(dummyArea, key, kElectronicKeyFormat4Size);
+};
+
+TEST(CipElectronicKey, DeleteElectronicKey) {
+  ElectronicKeyFormat4Delete(&key);
+  POINTERS_EQUAL(NULL, key);
+}
+
+TEST(CipElectronicKey, SetVendorID) {
+  char demoArea[kElectronicKeyFormat4Size] = {0};
+  CipUint *vendor_id = (CipUint *)demoArea;
+  *vendor_id = 1;
+  ElectronicKeyFormat4SetVendorId(1, key);
+
+  MEMCMP_EQUAL(demoArea, key, kElectronicKeyFormat4Size);
+}
+
+TEST(CipElectronicKey, GetVendorID) {
+  CipUint expected_vendor_id = 1;
+
+  CipUint *vendor_id_data = (CipUint *)key;
+  *vendor_id_data = expected_vendor_id;
+
+  CipUint vendor_id = ElectronicKeyFormat4GetVendorId(key);
+  CHECK_EQUAL(expected_vendor_id, vendor_id);
+}
+
+TEST(CipElectronicKey, SetDeviceType) {
+  char demoArea[kElectronicKeyFormat4Size] = {0};
+  CipUint *device_type = (CipUint *)demoArea + 1;
+  *device_type = 1;
+
+  ElectronicKeyFormat4SetDeviceType(1, key);
+  MEMCMP_EQUAL(demoArea, key, kElectronicKeyFormat4Size);
+}
+
+TEST(CipElectronicKey, GetDeviceType) {
+  CipUint expected_device_type = 1;
+
+  CipUint *device_type_data = (CipUint *)key + 1;
+  *device_type_data = expected_device_type;
+
+  CipUint device_type = ElectronicKeyFormat4GetDeviceType(key);
+  CHECK_EQUAL(expected_device_type, device_type);
+}
+
+TEST(CipElectronicKey, SetProductCode) {
+  char demoArea[kElectronicKeyFormat4Size] = {0};
+  CipUint *product_code = (CipUint *)demoArea + 2;
+  *product_code = 1;
+
+  ElectronicKeyFormat4SetProductCode(1, key);
+  MEMCMP_EQUAL(demoArea, key, kElectronicKeyFormat4Size);
+}
+
+TEST(CipElectronicKey, GetProductCode) {
+  CipUint expected_product_code = 1;
+
+  CipUint *product_code_data = (CipUint *)key + 2;
+  *product_code_data = expected_product_code;
+
+  CipUint product_code = ElectronicKeyFormat4GetProductCode(key);
+  CHECK_EQUAL(expected_product_code, product_code);
+}
+
+TEST(CipElectronicKey, SetMajorRevisionCompatibility) {
+  char demoArea[kElectronicKeyFormat4Size] = {0};
+  CipByte *major_revision_compatiblitiy = (CipByte *)demoArea + 6;
+  *major_revision_compatiblitiy = 0x81;
+
+  ElectronicKeyFormat4SetMajorRevisionCompatibility(0x81, key);
+  MEMCMP_EQUAL(demoArea, key, kElectronicKeyFormat4Size);
+}
+
+TEST(CipElectronicKey, GetMajorRevision) {
+  CipUint expected_major_revision = 0x1;
+
+  CipUint set_major_revision = 0x1;
+  CipByte *expected_major_data = (CipByte *)key + 6;
+  *expected_major_data = set_major_revision;
+
+  CipUint product_code = ElectronicKeyFormat4GetMajorRevision(key);
+  CHECK_EQUAL(expected_major_revision, product_code);
+}
+
+TEST(CipElectronicKey, GetMajorRevisionCompatibility) {
+  CipUint expected_major_revision = 0x81;
+
+  CipByte *expected_major_data = (CipByte *)key + 6;
+  *expected_major_data = expected_major_revision;
+
+  bool compatibility = ElectronicKeyFormat4GetMajorRevisionCompatibility(key);
+  CHECK_TEXT(compatibility, "Compatibility flag not working");
+}
+
+TEST(CipElectronicKey, SetMinorRevision) {
+  char demoArea[kElectronicKeyFormat4Size] = {0};
+  CipByte *minor_revision_compatiblitiy = (CipByte *)demoArea + 7;
+  *minor_revision_compatiblitiy = 0x81;
+
+  ElectronicKeyFormat4SetMinorRevision(0x81, key);
+  MEMCMP_EQUAL(demoArea, key, kElectronicKeyFormat4Size);
+}
+
+TEST(CipElectronicKey, GetMinorRevision) {
+  CipUint expected_minor_revision = 0x1;
+
+  CipByte *expected_minor_data = (CipByte *)key + 7;
+  *expected_minor_data = expected_minor_revision;
+
+  CipUint product_code = ElectronicKeyFormat4GetMinorRevision(key);
+  CHECK_EQUAL(expected_minor_revision, product_code);
+}
+
+TEST(CipElectronicKey, ParseElectronicKeyTest) {
+  /* Size of an electronic key is 1 + 1 + 8 (Segment, Key format, Key) */
+  const unsigned char message[] =
+  {0x34, 0x04, 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x84, 0x05};
+  GetPathLogicalSegmentElectronicKeyFormat4(message, key);
+
+  CHECK_EQUAL( 256, ElectronicKeyFormat4GetVendorId(key) );
+  CHECK_EQUAL( 512, ElectronicKeyFormat4GetDeviceType(key) );
+  CHECK_EQUAL( 768, ElectronicKeyFormat4GetProductCode(key) );
+  CHECK_TRUE( ElectronicKeyFormat4GetMajorRevisionCompatibility(key) );
+  CHECK_EQUAL( 0x04, ElectronicKeyFormat4GetMajorRevision(key) );
+  CHECK_EQUAL( 0x05, ElectronicKeyFormat4GetMinorRevision(key) );
+
+  MEMCMP_EQUAL(message + 2, key, 8);
+
+}

+ 477 - 0
source/tests/cip/cipepathtest.cpp

@@ -0,0 +1,477 @@
+/*******************************************************************************
+ * Copyright (c) 2016, Rockwell Automation, Inc.
+ * All rights reserved.
+ *
+ ******************************************************************************/
+
+#include <CppUTest/TestHarness.h>
+#include <stdint.h>
+#include <string.h>
+
+extern "C" {
+
+#include "cipepath.h"
+
+}
+
+TEST_GROUP(CipEpath) {
+
+};
+
+/** Segment type tests **/
+TEST(CipEpath, GetSegmentTypePortSegment) {
+  const unsigned char message[] = {0x00};
+  SegmentType segment_type = GetPathSegmentType(message);
+  CHECK_EQUAL(kSegmentTypePortSegment, segment_type);
+}
+
+TEST(CipEpath, GetSegmentTypeLogicalSegment) {
+  const unsigned char message[] = {0x20};
+  SegmentType segment_type = GetPathSegmentType(message);
+  CHECK_EQUAL(kSegmentTypeLogicalSegment, segment_type);
+}
+
+TEST(CipEpath, GetSegmentTypeNetworkSegment) {
+  const unsigned char message[] = {0x40};
+  SegmentType segment_type = GetPathSegmentType(message);
+  CHECK_EQUAL(kSegmentTypeNetworkSegment, segment_type);
+}
+
+TEST(CipEpath, GetSegmentTypeSymbolicSegment) {
+  const unsigned char message[] = {0x60};
+  SegmentType segment_type = GetPathSegmentType(message);
+  CHECK_EQUAL(kSegmentTypeSymbolicSegment, segment_type);
+}
+
+TEST(CipEpath, GetSegmentTypeDataSegment) {
+  const unsigned char message[] = {0x80};
+  SegmentType segment_type = GetPathSegmentType(message);
+  CHECK_EQUAL(kSegmentTypeDataSegment, segment_type);
+}
+
+TEST(CipEpath, GetSegmentTypeDataTypeConstructed) {
+  const unsigned char message[] = {0xA0};
+  SegmentType segment_type = GetPathSegmentType(message);
+  CHECK_EQUAL(kSegmentTypeDataTypeConstructed, segment_type);
+}
+
+TEST(CipEpath, GetSegmentTypeDataTypeElementary) {
+  const unsigned char message[] = {0xC0};
+  SegmentType segment_type = GetPathSegmentType(message);
+  CHECK_EQUAL(kSegmentTypeDataTypeElementary, segment_type);
+}
+
+TEST(CipEpath, GetSegmentTypeReserved) {
+  const unsigned char message[] = {0xE0};
+  SegmentType segment_type = GetPathSegmentType(message);
+  CHECK_EQUAL(kSegmentTypeReserved, segment_type);
+}
+
+/** Port segment tests **/
+TEST(CipEpath, GetPortSegmentExtendedAddressSizeTrue) {
+  const unsigned char message[] = {0x10};
+  bool extended_address = GetPathPortSegmentExtendedLinkAddressSizeBit(message);
+  CHECK_EQUAL(true, extended_address);
+}
+
+TEST(CipEpath, GetPortSegmentExtendedAddressSizeFalse) {
+  const unsigned char message[] = {0x00};
+  bool extended_address = GetPathPortSegmentExtendedLinkAddressSizeBit(message);
+  CHECK_EQUAL(false, extended_address);
+}
+
+TEST(CipEpath, GetPortSegmentPortIdentifier) {
+  const unsigned char message[] = {0x0F};
+  unsigned int port = GetPathPortSegmentPortIdentifier(message);
+  unsigned int mes = (unsigned int)(message[0]);
+  CHECK_EQUAL(15, mes);
+}
+
+TEST(CipEpath, SetPortSegmentPortIdentifier) {
+  unsigned char message[] = {0x00};
+  SetPathPortSegmentPortIdentifier(15, message);
+  CHECK_EQUAL( 15, (unsigned int)(message[0]) );
+}
+
+TEST(CipEpath, GetPortSegmentLinkAddressSize) {
+  const unsigned char message[] = {0x10,0x04};
+  unsigned int size = GetPathPortSegmentLinkAddressSize(message);
+  CHECK_EQUAL(4, size);
+}
+
+TEST(CipEpath, GetPortSegmentExtendedPortNumberNoExtendedAddress) {
+  const unsigned char message[] = {0x0F, 0x22, 0x64};
+  unsigned int extended_port = GetPathPortSegmentExtendedPortNumber(message);
+  CHECK_EQUAL(25634, extended_port);
+}
+
+TEST(CipEpath, GetPortSegmentExtendedPortNumberWithExtendedAddress) {
+  const unsigned char message[] = {0x1F, 0x00, 0x22, 0x64};
+  unsigned int extended_port = GetPathPortSegmentExtendedPortNumber(message);
+  CHECK_EQUAL(25634, extended_port);
+}
+
+TEST(CipEpath, SetPortSegmentExtendedPortNoExtendedAddress) {
+  unsigned char message[] = {0x00, 0x00, 0x00};
+  const char expected_message[] = {0x0F, 0x22, 0x64};
+  SetPathPortSegmentExtendedPortIdentifier( (unsigned int)25634, message );
+  MEMCMP_EQUAL(expected_message, message, 3);
+}
+
+TEST(CipEpath, SetPortSegmentExtendedPortWithExtendedAddress) {
+  unsigned char message[] = {0x10, 0x00, 0x00, 0x00};
+  const char expected_message[] = {0x1F, 0x00, 0x22, 0x64};
+  SetPathPortSegmentExtendedPortIdentifier( (unsigned int)25634, message );
+  MEMCMP_EQUAL(expected_message, message, 4);
+}
+
+TEST(CipEpath, GetLogicalSegmentLogicalTypeClassId) {
+  const unsigned char message[] = {0x20};
+  const LogicalSegmentLogicalType type = GetPathLogicalSegmentLogicalType(
+    message);
+  CHECK_EQUAL(kLogicalSegmentLogicalTypeClassId, type);
+}
+
+TEST(CipEpath, GetLogicalSegmentLogicalTypeInstanceId) {
+  const unsigned char message[] = {0x24};
+  const LogicalSegmentLogicalType type = GetPathLogicalSegmentLogicalType(
+    message);
+  CHECK_EQUAL(kLogicalSegmentLogicalTypeInstanceId, type);
+}
+
+TEST(CipEpath, GetLogicalSegmentLogicalTypeMemberId) {
+  const unsigned char message[] = {0x28};
+  const LogicalSegmentLogicalType type = GetPathLogicalSegmentLogicalType(
+    message);
+  CHECK_EQUAL(kLogicalSegmentLogicalTypeMemberId, type);
+}
+
+TEST(CipEpath, GetLogicalSegmentLogicalTypeConnectionPoint) {
+  const unsigned char message[] = {0x2C};
+  const LogicalSegmentLogicalType type = GetPathLogicalSegmentLogicalType(
+    message);
+  CHECK_EQUAL(kLogicalSegmentLogicalTypeConnectionPoint, type);
+}
+
+TEST(CipEpath, GetLogicalSegmentLogicalTypeAttributeId) {
+  const unsigned char message[] = {0x30};
+  const LogicalSegmentLogicalType type = GetPathLogicalSegmentLogicalType(
+    message);
+  CHECK_EQUAL(kLogicalSegmentLogicalTypeAttributeId, type);
+}
+
+TEST(CipEpath, GetLogicalSegmentLogicalTypeSpecial) {
+  const unsigned char message[] = {0x34};
+  const LogicalSegmentLogicalType type = GetPathLogicalSegmentLogicalType(
+    message);
+  CHECK_EQUAL(kLogicalSegmentLogicalTypeSpecial, type);
+}
+
+TEST(CipEpath, GetLogicalSegmentLogicalTypeServiceId) {
+  const unsigned char message[] = {0x38};
+  const LogicalSegmentLogicalType type = GetPathLogicalSegmentLogicalType(
+    message);
+  CHECK_EQUAL(kLogicalSegmentLogicalTypeServiceId, type);
+}
+
+TEST(CipEpath, GetLogicalSegmentLogicalTypeExtendedLogical) {
+  const unsigned char message[] = {0x3C};
+  const LogicalSegmentLogicalType type = GetPathLogicalSegmentLogicalType(
+    message);
+  CHECK_EQUAL(kLogicalSegmentLogicalTypeExtendedLogical, type);
+}
+
+TEST(CipEpath, GetLogicalSegmentLogicalFormatEightBits) {
+  const unsigned char message[] = {0x20};
+  const LogicalSegmentLogicalFormat format = GetPathLogicalSegmentLogicalFormat(
+    message);
+  CHECK_EQUAL(kLogicalSegmentLogicalFormatEightBit, format);
+}
+
+TEST(CipEpath, GetLogicalSegmentLogicalFormatSixteenBits) {
+  const unsigned char message[] = {0x21};
+  const LogicalSegmentLogicalFormat format = GetPathLogicalSegmentLogicalFormat(
+    message);
+  CHECK_EQUAL(kLogicalSegmentLogicalFormatSixteenBit, format);
+}
+
+TEST(CipEpath, GetLogicalSegmentLogicalFormatThirtyTwoBits) {
+  const unsigned char message[] = {0x22};
+  const LogicalSegmentLogicalFormat format = GetPathLogicalSegmentLogicalFormat(
+    message);
+  CHECK_EQUAL(kLogicalSegmentLogicalFormatThirtyTwoBit, format);
+}
+
+TEST(CipEpath, GetLogicalSegmentExtendedLogicalTypeReserved) {
+  const unsigned char message[] = {0x3C, 0x00};
+  const LogicalSegmentExtendedLogicalType extended_type =
+    GetPathLogicalSegmentExtendedLogicalType(message);
+  CHECK_EQUAL(kLogicalSegmentExtendedLogicalTypeReserved, extended_type);
+}
+
+TEST(CipEpath, GetLogicalSegmentExtendedLogicalTypeArrayIndex) {
+  const unsigned char message[] = {0x3C, 0x01};
+  const LogicalSegmentExtendedLogicalType extended_type =
+    GetPathLogicalSegmentExtendedLogicalType(message);
+  CHECK_EQUAL(kLogicalSegmentExtendedLogicalTypeArrayIndex, extended_type);
+}
+
+TEST(CipEpath, GetLogicalSegmentExtendedLogicalTypeIndirectArrayIndex) {
+  const unsigned char message[] = {0x3C, 0x02};
+  const LogicalSegmentExtendedLogicalType extended_type =
+    GetPathLogicalSegmentExtendedLogicalType(message);
+  CHECK_EQUAL(kLogicalSegmentExtendedLogicalTypeIndirectArrayIndex,
+              extended_type);
+}
+
+TEST(CipEpath, GetLogicalSegmentExtendedLogicalTypeBitIndex) {
+  const unsigned char message[] = {0x3C, 0x03};
+  const LogicalSegmentExtendedLogicalType extended_type =
+    GetPathLogicalSegmentExtendedLogicalType(message);
+  CHECK_EQUAL(kLogicalSegmentExtendedLogicalTypeBitIndex, extended_type);
+}
+
+TEST(CipEpath, GetLogicalSegmentExtendedLogicalTypeIndirectBitIndex) {
+  const unsigned char message[] = {0x3C, 0x04};
+  const LogicalSegmentExtendedLogicalType extended_type =
+    GetPathLogicalSegmentExtendedLogicalType(message);
+  CHECK_EQUAL(kLogicalSegmentExtendedLogicalTypeIndirectBitIndex,
+              extended_type);
+}
+
+TEST(CipEpath, GetLogicalSegmentExtendedLogicalTypeStructureMemberNumber) {
+  const unsigned char message[] = {0x3C, 0x05};
+  const LogicalSegmentExtendedLogicalType extended_type =
+    GetPathLogicalSegmentExtendedLogicalType(message);
+  CHECK_EQUAL(kLogicalSegmentExtendedLogicalTypeStructureMemberNumber,
+              extended_type);
+}
+
+TEST(CipEpath, GetLogicalSegmentExtendedLogicalTypeStructureMemberHandle) {
+  const unsigned char message[] = {0x3C, 0x06};
+  const LogicalSegmentExtendedLogicalType extended_type =
+    GetPathLogicalSegmentExtendedLogicalType(message);
+  CHECK_EQUAL(kLogicalSegmentExtendedLogicalTypeStructureMemberHandle,
+              extended_type);
+}
+
+TEST(CipEpath, GetLogicalSegmentSpecialTypeLogicalTypeReserved) {
+  const unsigned char message[] = {0x35};
+  LogicalSegmentSpecialTypeLogicalFormat special_type =
+    GetPathLogicalSegmentSpecialTypeLogicalType(message);
+  CHECK_EQUAL(kLogicalSegmentSpecialTypeLogicalFormatReserved, special_type);
+}
+
+TEST(CipEpath, GetLogicalSegmentSpecialTypeLogicalTypeElectronicKey) {
+  const unsigned char message[] = {0x34};
+  LogicalSegmentSpecialTypeLogicalFormat special_type =
+    GetPathLogicalSegmentSpecialTypeLogicalType(message);
+  CHECK_EQUAL(kLogicalSegmentSpecialTypeLogicalFormatElectronicKey,
+              special_type);
+}
+
+TEST(CipEpath, GetPathLogicalSegmentElectronicKeyFormatReserved) {
+  const unsigned char message[] = {0x34, 0x00};
+  ElectronicKeySegmentFormat key_format =
+    GetPathLogicalSegmentElectronicKeyFormat(message);
+  CHECK_EQUAL(kElectronicKeySegmentFormatReserved, key_format);
+}
+
+TEST(CipEpath, GetPathLogicalSegmentElectronicKeyFormat4) {
+  const unsigned char message[] = {0x34, 0x04};
+  ElectronicKeySegmentFormat key_format =
+    GetPathLogicalSegmentElectronicKeyFormat(message);
+  CHECK_EQUAL(kElectronicKeySegmentFormatKeyFormat4, key_format);
+}
+
+TEST(CipEpath, GetLogicalSegmentElectronicKeyFormat4) {
+  /* Size of an electronic key is 1 + 1 + 8 (Segment, Key format, Key) */
+  const unsigned char message[] =
+  {0x34, 0x04, 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x04, 0x05};
+  ElectronicKeyFormat4 *electronic_key = ElectronicKeyFormat4New();
+  GetPathLogicalSegmentElectronicKeyFormat4(message, electronic_key);
+
+  MEMCMP_EQUAL(message + 2, electronic_key, 8);
+
+  ElectronicKeyFormat4Delete(&electronic_key);
+}
+
+TEST(CipEpath, GetPathNetworkSegmentSubtypeReserved) {
+  const unsigned char message[] = {0x40};
+  NetworkSegmentSubtype sub_type = GetPathNetworkSegmentSubtype(message);
+  CHECK_EQUAL(kNetworkSegmentSubtypeReserved, sub_type);
+}
+
+TEST(CipEpath, GetPathNetworkSegmentSubtypeScheduled) {
+  const unsigned char message[] = {0x41};
+  NetworkSegmentSubtype sub_type = GetPathNetworkSegmentSubtype(message);
+  CHECK_EQUAL(kNetworkSegmentSubtypeScheduleSegment, sub_type);
+}
+
+TEST(CipEpath, GetPathNetworkSegmentSubtypeFixedTag) {
+  const unsigned char message[] = {0x42};
+  NetworkSegmentSubtype sub_type = GetPathNetworkSegmentSubtype(message);
+  CHECK_EQUAL(kNetworkSegmentSubtypeFixedTagSegment, sub_type);
+}
+
+TEST(CipEpath,
+     GetPathNetworkSegmentSubtypeProductionInhibitTimerInMilliseconds) {
+  const unsigned char message[] = {0x43};
+  NetworkSegmentSubtype sub_type = GetPathNetworkSegmentSubtype(message);
+  CHECK_EQUAL(kNetworkSegmentSubtypeProductionInhibitTimeInMilliseconds,
+              sub_type);
+}
+
+TEST(CipEpath, GetPathNetworkSegmentSubtypeSafety) {
+  const unsigned char message[] = {0x44};
+  NetworkSegmentSubtype sub_type = GetPathNetworkSegmentSubtype(message);
+  CHECK_EQUAL(kNetworkSegmentSubtypeSafetySegment, sub_type);
+}
+
+TEST(CipEpath,
+     GetPathNetworkSegmentSubtypeProductionInhibitTimerInMicroseconds) {
+  const unsigned char message[] = {0x50};
+  NetworkSegmentSubtype sub_type = GetPathNetworkSegmentSubtype(message);
+  CHECK_EQUAL(kNetworkSegmentSubtypeProductionInhibitTimeInMicroseconds,
+              sub_type);
+}
+
+TEST(CipEpath, GetPathNetworkSegmentSubtypeExtendedNetwork) {
+  const unsigned char message[] = {0x5F};
+  NetworkSegmentSubtype sub_type = GetPathNetworkSegmentSubtype(message);
+  CHECK_EQUAL(kNetworkSegmentSubtypeExtendedNetworkSegment, sub_type);
+}
+
+TEST(CipEpath, GetPathNetworkSegmentProductionInhibitTimeInMilliseconds) {
+  const unsigned char message[] = {0x43, 0xFF};
+  CipUsint time_im_milliseconds =
+    GetPathNetworkSegmentProductionInhibitTimeInMilliseconds(message);
+  CHECK_EQUAL(255, time_im_milliseconds);
+}
+
+TEST(CipEpath, GetPathNetworkSegmentProductionInhibitTimeInMicroseconds) {
+  const unsigned char message[] = {0x50, 0x02, 0x00, 0x00, 0x00, 0xFF};
+  CipUdint time_in_microseconds =
+    GetPathNetworkSegmentProductionInhibitTimeInMicroseconds(message);
+  CHECK_EQUAL(4278190080, time_in_microseconds);
+}
+
+TEST(CipEpath, GetPathDataSegmentSubtypeReserverd) {
+  const unsigned char message[] = {0x81};
+  DataSegmentSubtype type = GetPathDataSegmentSubtype(message);
+  CHECK_EQUAL(kDataSegmentSubtypeReserved, type);
+}
+
+TEST(CipEpath, GetPathDataSegmentSubtypeSimpleData) {
+  const unsigned char message[] = {0x80};
+  DataSegmentSubtype type = GetPathDataSegmentSubtype(message);
+  CHECK_EQUAL(kDataSegmentSubtypeSimpleData, type);
+}
+
+TEST(CipEpath, GetPathDataSegmentSubtypeANSIExtendedSymbol) {
+  const unsigned char message[] = {0x91};
+  DataSegmentSubtype type = GetPathDataSegmentSubtype(message);
+  CHECK_EQUAL(kDataSegmentSubtypeANSIExtendedSymbol, type);
+}
+
+TEST(CipEpath, GetPathDataSegmentSimpleDataWordLength) {
+  const unsigned char message[] = {0x80, 0x25};
+  CipUsint length = GetPathDataSegmentSimpleDataWordLength(message);
+  CHECK_EQUAL(37, length);
+}
+
+
+TEST(CipEpath, GetPathSymbolicSegmentFormatASCII) {
+  const unsigned char message[] = {0x61};
+  SymbolicSegmentFormat format = GetPathSymbolicSegmentFormat(message);
+  CHECK_EQUAL(kSymbolicSegmentFormatASCII, format);
+}
+
+TEST(CipEpath, GetPathSymbolicSegmentFormatExtendedFormat) {
+  const unsigned char message[] = {0x60};
+  SymbolicSegmentFormat format = GetPathSymbolicSegmentFormat(message);
+  CHECK_EQUAL(kSymbolicSegmentFormatExtendedString, format);
+}
+
+TEST(CipEpath, GetPathSymbolicSegmentASCIIFormatLength) {
+  const unsigned char message[] = {0x61};
+  SymbolicSegmentFormat format = GetPathSymbolicSegmentFormat(message);
+  CHECK_EQUAL(kSymbolicSegmentFormatASCII, format);
+}
+
+TEST(CipEpath, GetPathSymbolicSegmentNumericTypeReserved) {
+  const unsigned char message[] = {0x60, 0xC0};
+  SymbolicSegmentExtendedFormat format = GetPathSymbolicSegmentNumericType(
+    message);
+  CHECK_EQUAL(kSymbolicSegmentExtendedFormatReserved, format);
+}
+
+TEST(CipEpath, GetPathSymbolicSegmentNumericTypeUSINT) {
+  const unsigned char message[] = {0x60, 0xC6};
+  SymbolicSegmentExtendedFormat format = GetPathSymbolicSegmentNumericType(
+    message);
+  CHECK_EQUAL(kSymbolicSegmentExtendedFormatNumericSymbolUSINT, format);
+}
+
+TEST(CipEpath, GetPathSymbolicSegmentNumericTypeUINT) {
+  const unsigned char message[] = {0x60, 0xC7};
+  SymbolicSegmentExtendedFormat format = GetPathSymbolicSegmentNumericType(
+    message);
+  CHECK_EQUAL(kSymbolicSegmentExtendedFormatNumericSymbolUINT, format);
+}
+
+TEST(CipEpath, GetPathSymbolicSegmentNumericTypeUDINT) {
+  const unsigned char message[] = {0x60, 0xC8};
+  SymbolicSegmentExtendedFormat format = GetPathSymbolicSegmentNumericType(
+    message);
+  CHECK_EQUAL(kSymbolicSegmentExtendedFormatNumericSymbolUDINT, format);
+}
+
+TEST(CipEpath, GetPathSymbolicSegmentExtendedFormatReserverd) {
+  const unsigned char message[] = {0x60, 0x00};
+  SymbolicSegmentExtendedFormat format = GetPathSymbolicSegmentExtendedFormat(
+    message);
+  CHECK_EQUAL(kSymbolicSegmentExtendedFormatReserved, format);
+}
+
+TEST(CipEpath, GetPathSymbolicSegmentExtendedFormatDoubleChars) {
+  const unsigned char message[] = {0x60, 0x20};
+  SymbolicSegmentExtendedFormat format = GetPathSymbolicSegmentExtendedFormat(
+    message);
+  CHECK_EQUAL(kSymbolicSegmentExtendedFormatDoubleByteChars, format);
+}
+
+TEST(CipEpath, GetPathSymbolicSegmentExtendedFormatTripleChars) {
+  const unsigned char message[] = {0x60, 0x40};
+  SymbolicSegmentExtendedFormat format = GetPathSymbolicSegmentExtendedFormat(
+    message);
+  CHECK_EQUAL(kSymbolicSegmentExtendedFormatTripleByteChars, format);
+}
+
+TEST(CipEpath, GetPathSymbolicSegmentExtendedFormatUSINT) {
+  const unsigned char message[] = {0x60, 0xC6};
+  SymbolicSegmentExtendedFormat format = GetPathSymbolicSegmentExtendedFormat(
+    message);
+  CHECK_EQUAL(kSymbolicSegmentExtendedFormatNumericSymbolUSINT, format);
+}
+
+TEST(CipEpath, GetPathSymbolicSegmentExtendedFormatUINT) {
+  const unsigned char message[] = {0x60, 0xC7};
+  SymbolicSegmentExtendedFormat format = GetPathSymbolicSegmentExtendedFormat(
+    message);
+  CHECK_EQUAL(kSymbolicSegmentExtendedFormatNumericSymbolUINT, format);
+}
+
+TEST(CipEpath, GetPathSymbolicSegmentExtendedFormatUDINT) {
+  const unsigned char message[] = {0x60, 0xC8};
+  SymbolicSegmentExtendedFormat format = GetPathSymbolicSegmentExtendedFormat(
+    message);
+  CHECK_EQUAL(kSymbolicSegmentExtendedFormatNumericSymbolUDINT, format);
+}
+
+TEST(CipEpath, GetPathSymbolicSegmentExtendedFormatNumericReserved) {
+  const unsigned char message[] = {0x60, 0xC9};
+  SymbolicSegmentExtendedFormat format = GetPathSymbolicSegmentExtendedFormat(
+    message);
+  CHECK_EQUAL(kSymbolicSegmentExtendedFormatReserved, format);
+}

+ 19 - 0
source/tests/cip/connectionmanagertest.cpp

@@ -0,0 +1,19 @@
+/*******************************************************************************
+ * Copyright (c) 2016, Rockwell Automation, Inc.
+ * All rights reserved.
+ *
+ ******************************************************************************/
+
+#include <CppUTest/TestHarness.h>
+#include <stdint.h>
+#include <string.h>
+
+extern "C" {
+
+#include "cipconnectionmanager.h"
+
+}
+
+TEST_GROUP(CipConnectionManager) {
+
+};

+ 2 - 1
source/tests/enet_encap/endianconvtest.cpp

@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2009, Rockwell Automation, Inc.
+ * Copyright (c) 2016, Rockwell Automation, Inc.
  * All rights reserved.
  *
  ******************************************************************************/
@@ -16,6 +16,7 @@ extern "C" {
 #include "endianconv.h"
 
 #include "ciptypes.h"
+
 }
 
 TEST_GROUP(EndianConversion) {

+ 2 - 0
source/tests/utils/CMakeLists.txt

@@ -6,3 +6,5 @@ set( UtilsTestSrc randomTests.cpp xorshiftrandomtests.cpp)
 include_directories( ${SRC_DIR}/utils )
 
 add_library( UtilsTest ${UtilsTestSrc} )
+
+target_link_libraries( UtilsTest gcov ${CPPUTEST_LIBRARY} ${CPPUTESTEXT_LIBRARY} )

+ 11 - 10
source/tests/utils/randomTests.cpp

@@ -1,9 +1,9 @@
-/*
- * randomTests.cpp
+/*******************************************************************************
+ * Copyright (c) 2015, Rockwell Automation, Inc.
+ * All rights reserved.
  *
- *  Created on: Dec 16, 2013
- *      Author: mmm
- */
+ ******************************************************************************/
+
 
 #include <CppUTest/TestHarness.h>
 #include <stdint.h>
@@ -20,9 +20,10 @@ TEST_GROUP(RandomClass)
 
 TEST(RandomClass, CreateXOrShiftObject)
 {
-	Random* pRandom;
-	uint32_t nResult = 0;
-	pRandom = RandomNew(SetXorShiftSeed, NextXorShiftUint32);
-	POINTERS_EQUAL(SetXorShiftSeed, pRandom->set_seed);
-	POINTERS_EQUAL(NextXorShiftUint32, pRandom->get_next_uint32);
+  Random *pRandom = NULL;
+  uint32_t nResult = 0;
+  pRandom = RandomNew(SetXorShiftSeed, NextXorShiftUint32);
+  POINTERS_EQUAL(SetXorShiftSeed, pRandom->set_seed);
+  POINTERS_EQUAL(NextXorShiftUint32, pRandom->get_next_uint32);
+  RandomDelete(&pRandom);
 }

+ 20 - 21
source/tests/utils/xorshiftrandomtests.cpp

@@ -1,9 +1,8 @@
-/*
- * xorshiftrandomtests.c
+/*******************************************************************************
+ * Copyright (c) 2015, Rockwell Automation, Inc.
+ * All rights reserved.
  *
- *  Created on: Dec 1, 2013
- *      Author: mmm
- */
+ ******************************************************************************/
 
 #include <CppUTest/TestHarness.h>
 #include <stdint.h>
@@ -17,27 +16,27 @@ TEST_GROUP(XorShiftRandom)
 
 };
 
-/*This test should always return 0 as the next random number (see XorShift algorithm*/
+/* This test should always return 0 as the next random number (see XorShift algorithm) */
 TEST(XorShiftRandom, SeedZeroInitResult)
 {
-	uint32_t nResult;
-	nResult = 1;
-	SetXorShiftSeed(0);
-	nResult = NextXorShiftUint32();
-	LONGS_EQUAL(0, nResult);
+  uint32_t nResult;
+  nResult = 1;
+  SetXorShiftSeed(0);
+  nResult = NextXorShiftUint32();
+  LONGS_EQUAL(0, nResult);
 }
 
 /*Characterization test*/
 TEST(XorShiftRandom, SeedOneCharacterization)
 {
-	uint32_t nResult;
-	SetXorShiftSeed(1);
-	nResult = NextXorShiftUint32();
-	LONGS_EQUAL(270369, nResult);
-	nResult = NextXorShiftUint32();
-	LONGS_EQUAL(67634689, nResult);
-	nResult = NextXorShiftUint32();
-	LONGS_EQUAL(2647435461, nResult);
-	nResult = NextXorShiftUint32();
-	LONGS_EQUAL(307599695, nResult);
+  uint32_t nResult;
+  SetXorShiftSeed(1);
+  nResult = NextXorShiftUint32();
+  LONGS_EQUAL(270369, nResult);
+  nResult = NextXorShiftUint32();
+  LONGS_EQUAL(67634689, nResult);
+  nResult = NextXorShiftUint32();
+  LONGS_EQUAL(2647435461, nResult);
+  nResult = NextXorShiftUint32();
+  LONGS_EQUAL(307599695, nResult);
 }

+ 133 - 0
uncrustify.cfg

@@ -0,0 +1,133 @@
+tok_split_gte=false
+utf8_byte=false
+utf8_force=false
+indent_cmt_with_tabs=false
+indent_align_string=false
+indent_braces=false
+indent_braces_no_func=false
+indent_braces_no_class=false
+indent_braces_no_struct=false
+indent_brace_parent=false
+indent_namespace=false
+indent_extern=false
+indent_class=true
+indent_class_colon=false
+indent_else_if=false
+indent_var_def_cont=false
+indent_func_call_param=false
+indent_func_def_param=false
+indent_func_proto_param=false
+indent_func_class_param=false
+indent_func_ctor_var_param=false
+indent_template_param=false
+indent_func_param_double=false
+indent_relative_single_line_comments=false
+indent_col1_comment=false
+indent_access_spec_body=false
+indent_paren_nl=false
+indent_comma_paren=false
+indent_bool_paren=false
+indent_first_bool_expr=false
+indent_square_nl=false
+indent_preserve_sql=false
+indent_align_assign=true
+sp_balance_nested_parens=true
+align_keep_tabs=false
+align_with_tabs=false
+align_on_tabstop=false
+align_number_left=false
+align_func_params=false
+align_same_func_call_params=false
+align_var_def_colon=false
+align_var_def_attribute=false
+align_var_def_inline=false
+align_right_cmt_mix=false
+align_on_operator=false
+align_mix_var_proto=false
+align_single_line_func=false
+align_single_line_brace=false
+align_nl_cont=false
+align_left_shift=true
+align_oc_decl_colon=false
+nl_collapse_empty_body=false
+nl_assign_leave_one_liners=false
+nl_class_leave_one_liners=false
+nl_enum_leave_one_liners=false
+nl_getset_leave_one_liners=false
+nl_func_leave_one_liners=false
+nl_if_leave_one_liners=false
+nl_multi_line_cond=false
+nl_multi_line_define=false
+nl_before_case=false
+nl_after_case=false
+nl_after_return=false
+nl_after_semicolon=false
+nl_after_brace_open=false
+nl_after_brace_open_cmt=false
+nl_after_vbrace_open=false
+nl_after_vbrace_open_empty=false
+nl_after_brace_close=false
+nl_after_vbrace_close=false
+nl_define_macro=false
+nl_squeeze_ifdef=false
+nl_ds_struct_enum_cmt=false
+nl_ds_struct_enum_close_brace=false
+nl_create_if_one_liner=false
+nl_create_for_one_liner=false
+nl_create_while_one_liner=false
+ls_for_split_full=false
+ls_func_split_full=true
+nl_after_multiline_comment=false
+eat_blanks_after_open_brace=false
+eat_blanks_before_close_brace=false
+mod_full_brace_if_chain=false
+mod_pawn_semicolon=false
+mod_full_paren_if_bool=false
+mod_remove_extra_semicolon=true
+mod_sort_import=false
+mod_sort_using=false
+mod_sort_include=false
+mod_move_case_break=false
+mod_remove_empty_return=false
+cmt_indent_multi=true
+cmt_c_group=false
+cmt_c_nl_start=false
+cmt_c_nl_end=false
+cmt_cpp_group=false
+cmt_cpp_nl_start=false
+cmt_cpp_nl_end=false
+cmt_cpp_to_c=false
+cmt_star_cont=false
+cmt_multi_check_last=true
+cmt_insert_before_preproc=false
+pp_indent_at_level=false
+pp_region_indent_code=false
+pp_if_indent_code=false
+pp_define_at_level=false
+indent_columns=2
+indent_switch_case=2
+code_width=80
+utf8_bom=remove
+indent_with_tabs=0
+sp_arith=add
+sp_assign=add
+sp_assign_default=add
+sp_before_assign=ignore
+sp_enum_assign=add
+sp_pp_concat=add
+sp_pp_stringify=add
+sp_before_ptr_star=add
+sp_between_ptr_star=remove
+sp_after_ptr_star=remove
+sp_after_ptr_star_func=remove
+sp_fparen_brace=add
+nl_case_colon_brace=remove
+nl_class_brace=remove
+nl_func_decl_args=remove
+nl_func_def_args=remove
+nl_fdef_brace=remove
+mod_full_brace_do=add
+mod_full_brace_for=add
+mod_full_brace_function=add
+mod_full_brace_if=add
+mod_full_brace_while=add

Algúns arquivos non se mostraron porque demasiados arquivos cambiaron neste cambio