OpENer - Open Source EtherNet/IP(TM) I/O Target Stack  2.1
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
cipconnectionmanager.c
Go to the documentation of this file.
1 /*******************************************************************************
2  * Copyright (c) 2009, Rockwell Automation, Inc.
3  * All rights reserved.
4  *
5  ******************************************************************************/
6 #include <string.h>
7 #include <stdbool.h>
8 
9 #include "cipconnectionmanager.h"
10 
11 #include "opener_user_conf.h"
12 #include "cipcommon.h"
13 #include "cipmessagerouter.h"
14 #include "ciperror.h"
15 #include "endianconv.h"
16 #include "opener_api.h"
17 #include "encap.h"
18 #include "cipidentity.h"
19 #include "trace.h"
20 #include "cipconnectionobject.h"
21 #include "cipclass3connection.h"
22 #include "cipioconnection.h"
23 #include "cipassembly.h"
24 #include "cpf.h"
25 #include "appcontype.h"
26 #include "encap.h"
27 #include "generic_networkhandler.h"
28 #include "cipepath.h"
29 #include "cipelectronickey.h"
30 #include "cipqos.h"
31 
32 /* values needed from the CIP identity object */
33 extern EipUint16 vendor_id_;
34 extern EipUint16 device_type_;
36 extern CipRevision revision_;
37 
38 const size_t g_kForwardOpenHeaderLength = 36;
40 static const int g_kNumberOfConnectableObjects = 2 +
42 
44 
45 typedef struct {
49 
50 /* global variables private */
56 ];
57 
60 
63 
64 /* private functions */
66  CipInstance *instance,
67  CipMessageRouterRequest *message_router_request,
68  CipMessageRouterResponse *message_router_response,
69  struct sockaddr *originator_address,
70  const int encapsulation_session);
71 
73  CipInstance *instance,
74  CipMessageRouterRequest *message_router_request,
75  CipMessageRouterResponse *message_router_response,
76  struct sockaddr *originator_address,
77  const int encapsulation_session);
78 
80  CipInstance *instance,
81  CipMessageRouterRequest *message_router_request,
82  CipMessageRouterResponse *message_router_response,
83  struct sockaddr *originator_address,
84  const int encapsulation_session);
85 
87  CipConnectionObject *connection_object,
88  CipMessageRouterResponse *message_router_response,
89  EipUint8 general_status,
90  EipUint16 extended_status);
91 
93  EipUint16 connection_serial_number,
94  EipUint16 originatior_vendor_id,
95  EipUint32 originator_serial_number,
96  CipMessageRouterRequest *message_router_request,
97  CipMessageRouterResponse *message_router_response,
98  EipUint16 extended_error_code);
99 
110  const CipConnectionObject *const connection_object);
111 
122  EipUint8 key_format,
123  void *key_data,
124  EipUint16 *extended_status);
125 
138  CipConnectionObject *connection_object,
139  CipMessageRouterRequest *message_router_request,
140  EipUint16 *extended_error);
141 
143  const EipUint32 class_id);
144 
146 
147 void AddNullAddressItem(
148  CipCommonPacketFormatData *common_data_packet_format_data);
149 
155 unsigned int GetPaddedLogicalPath(const EipUint8 **logical_path_segment) {
156  unsigned int padded_logical_path = *(*logical_path_segment)++;
157 
158  if ( (padded_logical_path & 3) == 0 ) {
159  padded_logical_path = *(*logical_path_segment)++;
160  } else if ( (padded_logical_path & 3) == 1 ) {
161  (*logical_path_segment)++; /* skip pad */
162  padded_logical_path = *(*logical_path_segment)++;
163  padded_logical_path |= *(*logical_path_segment)++ << 8;
164  } else {
165  OPENER_TRACE_ERR("illegal logical path segment\n");
166  }
167  return padded_logical_path;
168 }
169 
178  static CipUint connection_id = 18;
179  connection_id++;
180  return ( g_incarnation_id | (connection_id & 0x0000FFFF) );
181 }
182 
184 
185  CipClass *meta_class = class->class_instance.cip_class;
186 
187  InsertAttribute( (CipInstance *) class, 1, kCipUint,
188  (void *) &class->revision,
189  kGetableSingleAndAll ); /* revision */
190  InsertAttribute( (CipInstance *) class, 2, kCipUint,
191  (void *) &class->number_of_instances, kGetableSingleAndAll ); /* largest instance number */
192  InsertAttribute( (CipInstance *) class, 3, kCipUint,
193  (void *) &class->number_of_instances, kGetableSingle ); /* number of instances currently existing*/
194  InsertAttribute( (CipInstance *) class, 4, kCipUint, (void *) &kCipUintZero,
195  kNotSetOrGetable ); /* optional attribute list - default = 0 */
196  InsertAttribute( (CipInstance *) class, 5, kCipUint, (void *) &kCipUintZero,
197  kNotSetOrGetable ); /* optional service list - default = 0 */
198  InsertAttribute( (CipInstance *) class, 6, kCipUint,
199  (void *) &meta_class->highest_attribute_number,
200  kGetableSingleAndAll ); /* max class attribute number*/
201  InsertAttribute( (CipInstance *) class, 7, kCipUint,
202  (void *) &class->highest_attribute_number,
203  kGetableSingleAndAll ); /* max instance attribute number*/
204 
205 }
206 
209 
210  CipClass *connection_manager = CreateCipClass(
211  g_kCipConnectionManagerClassCode, /* class ID */
212  0, /* # of class attributes */
213  7, /* # highest class attribute number*/
214  2, /* # of class services */
215  0, /* # of instance attributes */
216  14, /* # highest instance attribute number*/
217  5, /* # of instance services */
218  1, /* # of instances */
219  "connection manager", /* class name */
220  1, /* revision */
221  &InitializeConnectionManager); /* # function pointer for initialization*/
222  if (connection_manager == NULL) {
223  return kEipStatusError;
224  }
226  "GetAttributeSingle");
227  InsertService(connection_manager, kGetAttributeAll, &GetAttributeAll,
228  "GetAttributeAll");
229  InsertService(connection_manager, kForwardOpen, &ForwardOpen, "ForwardOpen");
230  InsertService(connection_manager, kForwardClose, &ForwardClose,
231  "ForwardClose");
233  "GetConnectionOwner");
234 
235  g_incarnation_id = ( (EipUint32) unique_connection_id ) << 16;
236 
237  AddConnectableObject(kCipMessageRouterClassCode, EstablishClass3Connection);
238  AddConnectableObject(kCipAssemblyClassCode, EstablishIoConnection);
239 
240  return kEipStatusOk;
241 }
242 
244  const EipUint8 *const data,
245  int data_length,
246  struct sockaddr_in *from_address
247  ) {
248 
249  if ( ( CreateCommonPacketFormatStructure(data, data_length,
251  == kEipStatusError ) {
252  return kEipStatusError;
253  } else {
254  /* check if connected address item or sequenced address item received, otherwise it is no connected message and should not be here */
258  == kCipItemIdSequencedAddressItem) ) { /* found connected address item or found sequenced address item -> for now the sequence number will be ignored */
260  == kCipItemIdConnectedDataItem) { /* connected data item received */
261 
262  CipConnectionObject *connection_object = GetConnectedObject(
265  if (connection_object == NULL) {
266  return kEipStatusError;
267  }
268 
269  /* only handle the data if it is coming from the originator */
270  if (connection_object->originator_address.sin_addr.s_addr
271  == from_address->sin_addr.s_addr) {
273 
274  if ( SEQ_GT32(
276  sequence_number,
277  connection_object->eip_level_sequence_count_consuming) ) {
278  /* reset the watchdog timer */
280 
281  /* only inform assembly object if the sequence counter is greater or equal */
282  connection_object->eip_level_sequence_count_consuming =
285 
286  if (NULL != connection_object->connection_receive_data_function) {
287  return connection_object->connection_receive_data_function(
288  connection_object,
291  }
292  }
293  } else {
295  "Connected Message Data Received with wrong address information\n");
296  }
297  }
298  }
299  }
300  return kEipStatusOk;
301 }
302 
307  CipConnectionObject *connection_object,
308  CipInstance *instance,
309  CipMessageRouterRequest *message_router_request,
310  CipMessageRouterResponse *message_router_response);
311 
319  CipConnectionObject *connection_object,
320  CipInstance *instance,
321  CipMessageRouterRequest *message_router_request,
322  CipMessageRouterResponse *message_router_response);
323 
325  CipConnectionObject *connection_object,
326  CipInstance *instance,
327  CipMessageRouterRequest *message_router_request,
328  CipMessageRouterResponse *message_router_response
329  ) {
330  OPENER_TRACE_INFO("Right now we cannot handle Null requests\n");
332  connection_object,
333  message_router_response,
336 }
337 
345  CipConnectionObject *connection_object,
346  CipInstance *instance,
347  CipMessageRouterRequest *message_router_request,
348  CipMessageRouterResponse *message_router_response);
349 
351  CipConnectionObject *connection_object,
352  CipInstance *instance,
353  CipMessageRouterRequest *message_router_request,
354  CipMessageRouterResponse *message_router_response
355  ) {
356  OPENER_TRACE_INFO("Right now we cannot handle Null requests\n");
358  connection_object,
359  message_router_response,
362 }
363 
370  CipConnectionObject *connection_object,
371  CipInstance *instance,
372  CipMessageRouterRequest *message_router_request,
373  CipMessageRouterResponse *message_router_response);
374 
376  CipConnectionObject *connection_object,
377  CipInstance *instance,
378  CipMessageRouterRequest *message_router_request,
379  CipMessageRouterResponse *message_router_response
380  ) {
381  OPENER_TRACE_INFO("Right now we cannot handle reconfiguration requests\n");
383  connection_object,
384  message_router_response,
387 }
388 
394  CipConnectionObject *connection_object,
395  CipInstance *instance,
396  CipMessageRouterRequest *message_router_request,
397  CipMessageRouterResponse *message_router_response);
398 
400  CipConnectionObject *connection_object,
401  CipInstance *instance,
402  CipMessageRouterRequest *message_router_request,
403  CipMessageRouterResponse *message_router_response
404  ) {
405 
407 
408  /*check if the trigger type value is invalid or ok */
411  g_dummy_connection_object) )
412  {
414  &g_dummy_connection_object,
415  message_router_response,
418  }
419 
420  EipUint32 temp = ParseConnectionPath(&g_dummy_connection_object,
421  message_router_request,
422  &connection_status);
423  if (kEipStatusOk != temp) {
424  return AssembleForwardOpenResponse(&g_dummy_connection_object,
425  message_router_response, temp,
426  connection_status);
427  }
428 
429  /*parsing is now finished all data is available and check now establish the connection */
430  ConnectionManagementHandling *connection_management_entry =
431  GetConnectionManagementEntry( /* Gets correct open connection function for the targeted object */
432  g_dummy_connection_object.configuration_path.class_id);
433  if (NULL != connection_management_entry) {
434  temp = connection_management_entry->open_connection_function(
435  &g_dummy_connection_object, &connection_status);
436  } else {
437  temp = kEipStatusError;
438  connection_status =
440  }
441 
442  if (kEipStatusOk != temp) {
443  OPENER_TRACE_INFO("connection manager: connect failed\n");
444  /* in case of error the dummy objects holds all necessary information */
445  return AssembleForwardOpenResponse(&g_dummy_connection_object,
446  message_router_response, temp,
447  connection_status);
448  } else {
449  OPENER_TRACE_INFO("connection manager: connect succeeded\n");
450  /* in case of success the new connection is added at the head of the connection list */
451  return AssembleForwardOpenResponse(connection_list.first->data,
452  message_router_response,
453  kCipErrorSuccess, 0);
454  }
455 }
456 
464  handle_forward_open_request_functions[2][2] =
469  } };
470 
493  CipInstance *instance,
494  CipMessageRouterRequest *message_router_request,
495  CipMessageRouterResponse *message_router_response,
496  struct sockaddr *originator_address,
497  const int encapsulation_session
498  ) {
499  (void) instance; /*suppress compiler warning */
500 
501  bool is_null_request = false; /* 1 = Null Request, 0 = Non-Null Request */
502  bool is_matching_request = false; /* 1 = Matching Request, 0 = Non-Matching Request */
503 
504  /*first check if we have already a connection with the given params */
505  ConnectionObjectInitializeFromMessage(&(message_router_request->data),
506  &g_dummy_connection_object);
507  g_dummy_connection_object.associated_encapsulation_session =
508  encapsulation_session;
509 
510  memcpy( &(g_dummy_connection_object.originator_address), originator_address,
511  sizeof(g_dummy_connection_object.originator_address) );
512 
513  ConnectionObjectConnectionType o_to_t_connection_type =
514  ConnectionObjectGetOToTConnectionType(&g_dummy_connection_object);
515  ConnectionObjectConnectionType t_to_o_connection_type =
516  ConnectionObjectGetTToOConnectionType(&g_dummy_connection_object);
517 
518  /* Check if both connection types are valid, otherwise send error response */
519  if (kConnectionObjectConnectionTypeInvalid == o_to_t_connection_type) {
521  &g_dummy_connection_object, message_router_response,
524  }
525 
526  if (kConnectionObjectConnectionTypeInvalid == t_to_o_connection_type) {
528  &g_dummy_connection_object, message_router_response,
531  }
532 
533  /* Check if request is a Null request or a Non-Null request */
534  if (kConnectionObjectConnectionTypeNull == o_to_t_connection_type
535  && kConnectionObjectConnectionTypeNull == t_to_o_connection_type) {
536  is_null_request = true;
537  OPENER_TRACE_INFO("We have a Null request\n");
538  } else {
539  is_null_request = false;
540  OPENER_TRACE_INFO("We have a Non-Null request\n");
541  }
542 
543  /* Check if we have a matching or non matching request */
544  if ( NULL != CheckForExistingConnection(&g_dummy_connection_object) ) {
545  OPENER_TRACE_INFO("We have a Matching request\n");
546  is_matching_request = true;
547 
548  } else {
549  OPENER_TRACE_INFO("We have a Non-Matching request\n");
550  is_matching_request = false;
551  }
552 
553  HandleForwardOpenRequestFunction choosen_function =
554  handle_forward_open_request_functions[is_null_request][is_matching_request];
555 
556  return choosen_function(&g_dummy_connection_object, instance,
557  message_router_request, message_router_response);
558 }
559 
561  CipInstance *instance,
562  CipMessageRouterRequest *message_router_request,
563  CipMessageRouterResponse *message_router_response,
564  struct sockaddr *originator_address,
565  const int encapsulation_session) {
566  /*Suppress compiler warning*/
567  (void) instance;
568 
569  /* check connection_serial_number && originator_vendor_id && originator_serial_number if connection is established */
570  ConnectionManagerExtendedStatusCode connection_status =
572 
573  /* set AddressInfo Items to invalid TypeID to prevent assembleLinearMsg to read them */
576 
577  message_router_request->data += 2; /* ignore Priority/Time_tick and Time-out_ticks */
578 
579  EipUint16 connection_serial_number = GetIntFromMessage(
580  &message_router_request->data);
581  EipUint16 originator_vendor_id = GetIntFromMessage(
582  &message_router_request->data);
583  EipUint32 originator_serial_number = GetDintFromMessage(
584  &message_router_request->data);
585 
586  OPENER_TRACE_INFO("ForwardClose: ConnSerNo %d\n", connection_serial_number);
587 
588  DoublyLinkedListNode *node = connection_list.first;
589 
590  while (NULL != node) {
591  /* this check should not be necessary as only established connections should be in the active connection list */
592  CipConnectionObject *connection_object = node->data;
594  ConnectionObjectGetState(connection_object) )
596  ConnectionObjectGetState(connection_object) ) ) {
597  if ( (connection_object->connection_serial_number
598  == connection_serial_number)
599  && (connection_object->originator_vendor_id == originator_vendor_id)
600  && (connection_object->originator_serial_number
601  == originator_serial_number) ) {
602  /* found the corresponding connection object -> close it */
603  OPENER_ASSERT(NULL != connection_object->connection_close_function)
604  if ( ( (struct sockaddr_in *) originator_address )->sin_addr.s_addr
605  == connection_object->originator_address.sin_addr.s_addr ) {
606  connection_object->connection_close_function(connection_object);
608  } else {
610  }
611  break;
612  }
613  }
614  node = node->next;
615  }
616  if(
618  ==
619  connection_status) {
621  "Connection not found! Requested connection triad: %u, %u, %u\n",
622  connection_serial_number,
623  originator_vendor_id,
624  originator_serial_number);
625  }
626 
627  return AssembleForwardCloseResponse(connection_serial_number,
628  originator_vendor_id,
629  originator_serial_number,
630  message_router_request,
631  message_router_response,
632  connection_status);
633 }
634 
635 /* TODO: Not implemented */
637  CipInstance *instance,
638  CipMessageRouterRequest *message_router_request,
639  CipMessageRouterResponse *message_router_response,
640  struct sockaddr *originator_address,
641  const int encapsulation_session) {
642  /* suppress compiler warnings */
643  (void) instance;
644  (void) message_router_request;
645  (void) message_router_response;
646 
647  return kEipStatusOk;
648 }
649 
651  //OPENER_TRACE_INFO("Entering ManageConnections\n");
652  /*Inform application that it can execute */
654  ManageEncapsulationMessages(elapsed_time);
655 
656  DoublyLinkedListNode *node = connection_list.first;
657 
658  while (NULL != node) {
659  //OPENER_TRACE_INFO("Entering Connection Object loop\n");
660  CipConnectionObject *connection_object = node->data;
662  ConnectionObjectGetState(connection_object) ) {
663  if ( (NULL != connection_object->consuming_instance) || /* we have a consuming connection check inactivity watchdog timer */
665  ConnectionObjectGetTransportClassTriggerDirection(connection_object) ) ) /* all server connections have to maintain an inactivity watchdog timer */
666  {
667  if (elapsed_time >= connection_object->inactivity_watchdog_timer) {
668  /* we have a timed out connection perform watchdog time out action*/
669  OPENER_TRACE_INFO(">>>>>>>>>>Connection ConnNr: %u timed out\n",
670  connection_object->connection_serial_number);
671  OPENER_ASSERT(NULL != connection_object->connection_timeout_function)
672  connection_object->connection_timeout_function(connection_object);
673  } else {
674  connection_object->inactivity_watchdog_timer -= elapsed_time;
675  connection_object->last_package_watchdog_timer -= elapsed_time;
676  }
677  }
678  /* only if the connection has not timed out check if data is to be send */
680  ConnectionObjectGetState(connection_object) ) {
681  /* client connection */
682  if ( (0 != ConnectionObjectGetExpectedPacketRate(connection_object) )
683  && (kEipInvalidSocket
684  != connection_object->socket[
686  ]) ) /* only produce for the master connection */
687  {
690  connection_object) ) {
691  /* non cyclic connections have to decrement production inhibit timer */
692  if (elapsed_time <= connection_object->production_inhibit_timer) {
693  //The connection is allowed to send again
694  } else {
695  connection_object->production_inhibit_timer -= elapsed_time;
696  }
697  }
698 
699  if (connection_object->transmission_trigger_timer <= elapsed_time) { /* need to send package */
701  NULL != connection_object->connection_send_data_function)
702  EipStatus eip_status = connection_object
704  connection_object);
705  if (eip_status == kEipStatusError) {
707  "sending of UDP data in manage Connection failed\n");
708  }
709  /* reload the timer value */
710  connection_object->transmission_trigger_timer =
714  connection_object) ) {
715  /* non cyclic connections have to reload the production inhibit timer */
717  }
718  } else {
719  connection_object->transmission_trigger_timer -= elapsed_time;
720  }
721  }
722  }
723  }
724  node = node->next;
725  }
726  return kEipStatusOk;
727 }
728 
741  CipConnectionObject *connection_object,
742  CipMessageRouterResponse *message_router_response,
743  EipUint8 general_status,
744  EipUint16 extended_status
745  ) {
746  /* write reply information in CPF struct dependent of pa_status */
747  CipCommonPacketFormatData *cip_common_packet_format_data =
749  EipByte *message = message_router_response->data;
750  cip_common_packet_format_data->item_count = 2;
751  cip_common_packet_format_data->data_item.type_id =
753 
754  AddNullAddressItem(cip_common_packet_format_data);
755 
756  message_router_response->reply_service = (0x80 | kForwardOpen);
757  message_router_response->general_status = general_status;
758 
759  if (kCipErrorSuccess == general_status) {
760  OPENER_TRACE_INFO("assembleFWDOpenResponse: sending success response\n");
761  message_router_response->data_length = 26; /* if there is no application specific data */
762  message_router_response->size_of_additional_status = 0;
763 
764  if (cip_common_packet_format_data->address_info_item[0].type_id != 0) {
765  cip_common_packet_format_data->item_count = 3;
766  if (cip_common_packet_format_data->address_info_item[1].type_id != 0) {
767  cip_common_packet_format_data->item_count = 4; /* there are two sockaddrinfo items to add */
768  }
769  }
770 
771  AddDintToMessage(connection_object->cip_consumed_connection_id, &message);
772  AddDintToMessage(connection_object->cip_produced_connection_id, &message);
773  } else {
774  /* we have an connection creation error */
775  OPENER_TRACE_INFO("AssembleForwardOpenResponse: sending error response\n");
776  ConnectionObjectSetState(connection_object,
778  message_router_response->data_length = 10;
779 
780  switch (general_status) {
782  case kCipErrorTooMuchData: {
783  message_router_response->size_of_additional_status = 0;
784  break;
785  }
786 
787  default: {
788  switch (extended_status) {
789  case
791  {
792  message_router_response->size_of_additional_status = 2;
793  message_router_response->additional_status[0] = extended_status;
794  message_router_response->additional_status[1] = connection_object
795  ->
796  correct_originator_to_target_size;
797  break;
798  }
799 
800  case
802  {
803  message_router_response->size_of_additional_status = 2;
804  message_router_response->additional_status[0] = extended_status;
805  message_router_response->additional_status[1] = connection_object
806  ->
807  correct_target_to_originator_size;
808  break;
809  }
810 
811  default: {
812  message_router_response->size_of_additional_status = 1;
813  message_router_response->additional_status[0] = extended_status;
814  break;
815  }
816  }
817  break;
818  }
819  }
820  }
821 
822  AddIntToMessage(connection_object->connection_serial_number, &message);
823  AddIntToMessage(connection_object->originator_vendor_id, &message);
824  AddDintToMessage(connection_object->originator_serial_number, &message);
825 
826  if (kCipErrorSuccess == general_status) {
827  /* set the actual packet rate to requested packet rate */
829  &message);
831  &message);
832  }
833 
834  *message = 0; /* remaining path size - for routing devices relevant */
835  message++;
836  *message = 0; /* reserved */
837  message++;
838 
839  return kEipStatusOkSend; /* send reply */
840 }
841 
847  CipCommonPacketFormatData *common_data_packet_format_data) {
848  /* Precondition: Null Address Item only valid in unconnected messages */
849  assert(
850  common_data_packet_format_data->data_item.type_id
852 
853  common_data_packet_format_data->address_item.type_id = kCipItemIdNullAddress;
854  common_data_packet_format_data->address_item.length = 0;
855 }
856 
857 /* INT8 assembleFWDCloseResponse(UINT16 pa_ConnectionSerialNr, UINT16 pa_OriginatorVendorID, UINT32 pa_OriginatorSerialNr, S_CIP_MR_Request *pa_MRRequest, S_CIP_MR_Response *pa_MRResponse, S_CIP_CPF_Data *pa_CPF_data, INT8 pa_status, INT8 *pa_msg)
858  * create FWDClose response dependent on status.
859  * pa_ConnectionSerialNr requested ConnectionSerialNr
860  * pa_OriginatorVendorID requested OriginatorVendorID
861  * pa_OriginatorSerialNr requested OriginalSerialNr
862  * pa_MRRequest pointer to message router request
863  * pa_MRResponse pointer to message router response
864  * pa_CPF_data pointer to CPF Data Item
865  * pa_status status of FWDClose
866  * pa_msg pointer to memory where reply has to be stored
867  * return status
868  * 0 .. no reply need to ne sent back
869  * 1 .. need to send reply
870  * -1 .. error
871  */
873  EipUint16 connection_serial_number,
874  EipUint16 originatior_vendor_id,
875  EipUint32 originator_serial_number,
876  CipMessageRouterRequest *message_router_request,
877  CipMessageRouterResponse *message_router_response,
878  EipUint16 extended_error_code
879  ) {
880  /* write reply information in CPF struct dependent of pa_status */
881  CipCommonPacketFormatData *common_data_packet_format_data =
883  EipByte *message = message_router_response->data;
884  common_data_packet_format_data->item_count = 2;
885  common_data_packet_format_data->data_item.type_id =
887 
888  AddNullAddressItem(common_data_packet_format_data);
889 
890  AddIntToMessage(connection_serial_number, &message);
891  AddIntToMessage(originatior_vendor_id, &message);
892  AddDintToMessage(originator_serial_number, &message);
893 
894  message_router_response->reply_service = (0x80
895  | message_router_request->service);
896  message_router_response->data_length = 10; /* if there is no application specific data */
897 
898  if (kConnectionManagerExtendedStatusCodeSuccess == extended_error_code) {
899  *message = 0; /* no application data */
900  message_router_response->general_status = kCipErrorSuccess;
901  message_router_response->size_of_additional_status = 0;
902  } else {
903  *message = *message_router_request->data; /* remaining path size */
904  if (kConnectionManagerExtendedStatusWrongCloser == extended_error_code) {
905  message_router_response->general_status = kCipErrorPrivilegeViolation;
906  } else {
907  message_router_response->general_status = kCipErrorConnectionFailure;
908  message_router_response->additional_status[0] = extended_error_code;
909  message_router_response->size_of_additional_status = 1;
910  }
911  }
912 
913  message++;
914  *message = 0; /* reserved */
915  message++;
916 
917  return kEipStatusOkSend;
918 }
919 
921  DoublyLinkedListNode *iterator = connection_list.first;
922 
923  while(NULL != iterator) {
925  ConnectionObjectGetState(iterator->data) &&
926  connection_id ==
928  return iterator->data;
929  }
930  iterator = iterator->next;
931  }
932  return NULL;
933 }
934 
936  const EipUint32 output_assembly_id) {
937  DoublyLinkedListNode *iterator = connection_list.first;
938 
939  while(NULL != iterator) {
942  ConnectionObjectGetState(iterator->data)
944  ConnectionObjectGetState(iterator->data) ) &&
945  output_assembly_id ==
946  ( (CipConnectionObject *)iterator->data )->produced_path.instance_id ) {
947  return iterator->data;
948  }
949  iterator = iterator->next;
950  }
951  return NULL;
952 }
953 
955  const CipConnectionObject *const connection_object) {
956 
957  DoublyLinkedListNode *iterator = connection_list.first;
958 
959  while(NULL != iterator) {
961  ConnectionObjectGetState(iterator->data) ) {
962  if(EqualConnectionTriad(connection_object, iterator->data) ) {
963  return iterator->data;
964  }
965  }
966  iterator = iterator->next;
967  }
968 
969  return NULL;
970 }
971 
973  EipUint8 key_format,
974  void *key_data,
975  EipUint16 *extended_status
976  ) {
977  /* Default return value */
979 
980  /* Check key format */
981  if (4 != key_format) {
982  *extended_status =
984  return kEipStatusError;
985  }
986 
987  bool compatiblity_mode = ElectronicKeyFormat4GetMajorRevisionCompatibility(
988  key_data);
989 
990  /* Check VendorID and ProductCode, must match, or 0 */
991  if ( ( (ElectronicKeyFormat4GetVendorId(key_data) != vendor_id_) &&
992  (ElectronicKeyFormat4GetVendorId(key_data) != 0) )
994  && (ElectronicKeyFormat4GetProductCode(key_data) != 0) ) ) {
995  *extended_status =
997  return kEipStatusError;
998  } else {
999  /* VendorID and ProductCode are correct */
1000 
1001  /* Check DeviceType, must match or 0 */
1003  && (ElectronicKeyFormat4GetDeviceType(key_data) != 0) ) {
1004  *extended_status =
1006  return kEipStatusError;
1007  } else {
1008  /* VendorID, ProductCode and DeviceType are correct */
1009 
1010  if (false == compatiblity_mode) {
1011  /* Major = 0 is valid */
1012  if (0 == ElectronicKeyFormat4GetMajorRevision(key_data) ) {
1013  return kEipStatusOk;
1014  }
1015 
1016  /* Check Major / Minor Revision, Major must match, Minor match or 0 */
1017  if ( (ElectronicKeyFormat4GetMajorRevision(key_data) !=
1018  revision_.major_revision)
1019  || ( (ElectronicKeyFormat4GetMinorRevision(key_data) !=
1020  revision_.minor_revision)
1021  && (ElectronicKeyFormat4GetMinorRevision(key_data) != 0) ) ) {
1022  *extended_status =
1024  return kEipStatusError;
1025  }
1026  } else {
1027  /* Compatibility mode is set */
1028 
1029  /* Major must match, Minor != 0 and <= MinorRevision */
1030  if ( (ElectronicKeyFormat4GetMajorRevision(key_data) ==
1031  revision_.major_revision)
1032  && (ElectronicKeyFormat4GetMinorRevision(key_data) > 0)
1033  && (ElectronicKeyFormat4GetMinorRevision(key_data) <=
1034  revision_.minor_revision) ) {
1035  return kEipStatusOk;
1036  } else {
1037  *extended_status =
1039  return kEipStatusError;
1040  }
1041  } /* end if CompatiblityMode handling */
1042  }
1043  }
1044 
1045  return
1046  (*extended_status == kConnectionManagerExtendedStatusCodeSuccess) ?
1048 }
1049 
1051  CipConnectionObject *connection_object,
1052  CipMessageRouterRequest *message_router_request,
1053  EipUint16 *extended_error
1054  ) {
1055  const EipUint8 *message = message_router_request->data;
1056  const size_t connection_path_size = GetSintFromMessage(&message); /* length in words */
1057  size_t remaining_path = connection_path_size;
1058  CipClass *class = NULL;
1059 
1060  CipDword class_id = 0x0;
1061  CipDword instance_id = 0x0;
1062 
1063  /* with 256 we mark that we haven't got a PIT segment */
1064  ConnectionObjectSetProductionInhibitTime(connection_object, 256);
1065 
1066  if ( (g_kForwardOpenHeaderLength + remaining_path * 2)
1067  < message_router_request->request_path_size ) {
1068  /* the received packet is larger than the data in the path */
1069  *extended_error = 0;
1070  return kCipErrorTooMuchData;
1071  }
1072 
1073  if ( (g_kForwardOpenHeaderLength + remaining_path * 2)
1074  > message_router_request->request_path_size ) {
1075  /*there is not enough data in received packet */
1076  *extended_error = 0;
1077  OPENER_TRACE_INFO("Message not long enough for path\n");
1078  return kCipErrorNotEnoughData;
1079  }
1080 
1081  if (remaining_path > 0) {
1082  /* first look if there is an electronic key */
1083  if ( kSegmentTypeLogicalSegment == GetPathSegmentType(message) ) {
1085  == GetPathLogicalSegmentLogicalType(message) ) {
1090  /* Check if there is enough data for holding the electronic key segment */
1091  if (remaining_path < 5) {
1092  *extended_error = 0;
1093  OPENER_TRACE_INFO("Message not long enough for electronic key\n");
1094  return kCipErrorNotEnoughData;
1095  }
1096  /* Electronic key format 4 found */
1097  connection_object->electronic_key.key_format = 4;
1098  ElectronicKeyFormat4 *electronic_key = ElectronicKeyFormat4New();
1099  GetElectronicKeyFormat4FromMessage(&message, electronic_key);
1100  /* logical electronic key found */
1101  connection_object->electronic_key.key_data = electronic_key;
1102 
1103 
1104  remaining_path -= 5; /*length of the electronic key*/
1106  "key: ven ID %d, dev type %d, prod code %d, major %d, minor %d\n",
1108  key_data),
1109  ElectronicKeyFormat4GetDeviceType(connection_object->
1110  electronic_key.key_data),
1111  ElectronicKeyFormat4GetProductCode(connection_object->
1112  electronic_key.key_data),
1113  ElectronicKeyFormat4GetMajorRevision(connection_object->
1114  electronic_key.key_data),
1115  ElectronicKeyFormat4GetMinorRevision(connection_object->
1116  electronic_key.key_data) );
1117  if ( kEipStatusOk
1119  connection_object->electronic_key.key_format,
1120  connection_object->electronic_key.key_data,
1121  extended_error) ) {
1122  ElectronicKeyFormat4Delete(&electronic_key);
1124  }
1125  ElectronicKeyFormat4Delete(&electronic_key);
1126  }
1127 
1128  } else {
1129  OPENER_TRACE_INFO("no key\n");
1130  }
1131  }
1132  }
1133 
1134  //TODO: Refactor this afterwards
1137  connection_object) ) {
1138  /*non cyclic connections may have a production inhibit */
1139  if ( kSegmentTypeNetworkSegment == GetPathSegmentType(message) ) {
1143  == network_segment_subtype) {
1144  OPENER_TRACE_INFO("PIT segment available - value: %u\n",message[1]);
1145  connection_object->production_inhibit_time = message[1];
1146  message += 2;
1147  remaining_path -= 1;
1148  }
1149  }
1150  }
1151 
1155 
1156  class_id = CipEpathGetLogicalValue(&message);
1157  class = GetCipClass(class_id);
1158  if (NULL == class) {
1159  OPENER_TRACE_ERR("classid %" PRIx32 " not found\n",
1160  class_id);
1161 
1162  if (class_id >= 0xC8) { /*reserved range of class ids */
1163  *extended_error =
1165  } else {
1166  *extended_error =
1168  }
1170  }
1171 
1172  OPENER_TRACE_INFO("classid %" PRIx32 " (%s)\n",
1173  class_id,
1174  class->class_name);
1175  } else {
1176  *extended_error =
1179  }
1180  remaining_path -= 1; /* 1 16Bit word for the class part of the path */
1181 
1182  /* Get instance ID */
1185  GetPathLogicalSegmentLogicalType(message) ) { /* store the configuration ID for later checking in the application connection types */
1186  instance_id = CipEpathGetLogicalValue(&message);
1187 
1188  OPENER_TRACE_INFO("Configuration instance id %" PRId32 "\n",
1189  instance_id);
1190  if ( NULL == GetCipInstance(class, instance_id) ) {
1191  /*according to the test tool we should respond with this extended error code */
1192  *extended_error =
1195  }
1196  /* 1 or 2 16Bit words for the configuration instance part of the path */
1197  remaining_path -= (instance_id > 0xFF) ? 2 : 1; //TODO: 32 bit case missing
1198  } else {
1199  OPENER_TRACE_INFO("no config data\n");
1200  }
1201 
1204  connection_object) )
1205  {
1206  /*we have Class 3 connection*/
1207  if (remaining_path > 0) {
1209  "Too much data in connection path for class 3 connection\n");
1210  *extended_error =
1213  }
1214 
1215  /* connection end point has to be the message router instance 1 */
1216  if ( (class_id != kCipMessageRouterClassCode)
1217  || (1 != instance_id) ) {
1218  *extended_error =
1221  }
1222  /* Configuration connection point is producing connection point */
1223  CipConnectionPathEpath connection_epath = {
1224  .class_id = class_id,
1225  .instance_id = instance_id,
1226  .attribute_id_or_connection_point = 0
1227  };
1228 
1229  memcpy(&(connection_object->configuration_path),
1230  &connection_epath,
1231  sizeof(connection_object->configuration_path) );
1232  memcpy(&(connection_object->produced_path), &connection_epath,
1233  sizeof(connection_object->produced_path) );
1234 
1235  /* End class 3 connection handling */
1236  } else { /* we have an IO connection */
1237  CipConnectionPathEpath connection_epath = {
1238  .class_id = class_id,
1239  .instance_id = instance_id,
1240  .attribute_id_or_connection_point = 0
1241  };
1242  memcpy(&(connection_object->configuration_path),
1243  &connection_epath,
1244  sizeof(connection_object->configuration_path) );
1245  ConnectionObjectConnectionType originator_to_target_connection_type =
1247  connection_object);
1248  ConnectionObjectConnectionType target_to_originator_connection_type =
1250  connection_object);
1251 
1252  connection_object->consumed_connection_path_length = 0;
1253  connection_object->consumed_connection_path = NULL;
1254  //connection_object->connection_path.connection_point[1] = 0; /* set not available path to Invalid */
1255 
1256  size_t number_of_encoded_paths = 0;
1257  CipConnectionPathEpath *paths_to_encode[2] = { 0 };
1259  originator_to_target_connection_type) {
1261  target_to_originator_connection_type) { /* configuration only connection */
1262  number_of_encoded_paths = 0;
1263  OPENER_TRACE_WARN("assembly: type invalid\n");
1264  } else { /* 1 path -> path is for production */
1265  OPENER_TRACE_INFO("assembly: type produce\n");
1266  number_of_encoded_paths = 1;
1267  paths_to_encode[0] = &(connection_object->produced_path);
1268  }
1269  } else {
1271  target_to_originator_connection_type) { /* 1 path -> path is for consumption */
1272  OPENER_TRACE_INFO("assembly: type consume\n");
1273  number_of_encoded_paths = 1;
1274  paths_to_encode[0] = &(connection_object->consumed_path);
1275  } else { /* 2 paths -> 1st for production 2nd for consumption */
1276  OPENER_TRACE_INFO("assembly: type bidirectional\n");
1277  paths_to_encode[0] = &(connection_object->consumed_path);
1278  paths_to_encode[1] = &(connection_object->produced_path);
1279  number_of_encoded_paths = 2;
1280  }
1281  }
1282 
1283  for (size_t i = 0; i < number_of_encoded_paths; i++) /* process up to 2 encoded paths */
1284  {
1288  GetPathLogicalSegmentLogicalType(message) ) /* Connection Point interpreted as InstanceNr -> only in Assembly Objects */
1289  { /* Attribute Id or Connection Point */
1290  CipDword attribute_id = CipEpathGetLogicalValue(&message);
1291  CipConnectionPathEpath connection_epath = {
1292  .class_id = class_id,
1293  .instance_id = attribute_id,
1294  .attribute_id_or_connection_point = 0
1295  };
1296  memcpy(paths_to_encode[i], &connection_epath,
1297  sizeof(connection_object->produced_path) );
1299  "connection point %" PRIu32 "\n",
1300  attribute_id);
1301  if ( NULL
1302  == GetCipInstance(
1303  class,
1304  attribute_id) ) { /* Old code - Probably here the attribute ID marks the instance for the assembly object */
1305  *extended_error =
1308  }
1309  /* 1 or 2 16Bit word for the connection point part of the path */
1310  remaining_path -= (attribute_id > 0xFF) ? 2 : 1;
1311  } else {
1312  *extended_error =
1315  }
1316  }
1317 
1319  g_config_data_buffer = NULL;
1320 
1321  while (remaining_path > 0) { /* remaining_path_size something left in the path should be configuration data */
1322 
1324  switch (segment_type) {
1325  case kSegmentTypeDataSegment: {
1326  DataSegmentSubtype data_segment_type = GetPathDataSegmentSubtype(
1327  message);
1328  switch (data_segment_type) {
1330  g_config_data_length = message[1] * 2; /*data segments store length 16-bit word wise */
1331  g_config_data_buffer = (EipUint8 *) message + 2;
1332  remaining_path -= (g_config_data_length + 2) / 2;
1333  message += (g_config_data_length + 2);
1334  break;
1335  default:
1336  OPENER_TRACE_ERR("Not allowed in connection manager");
1337  break;
1338  }
1339  }
1340  break;
1343  message);
1344  switch (subtype) {
1346  if (
1348  !=
1350  connection_object) ) {
1351  /* only non cyclic connections may have a production inhibit */
1352  connection_object->production_inhibit_time = message[1];
1353  message += 2;
1354  remaining_path -= 2;
1355  } else {
1356  *extended_error = connection_path_size - remaining_path; /*offset in 16Bit words where within the connection path the error happend*/
1357  return kCipErrorPathSegmentError; /*status code for invalid segment type*/
1358  }
1359  break;
1360  default:
1361  OPENER_TRACE_ERR("Not allowed in connection manager");
1362  break;
1363  }
1364  }
1365  break;
1366 
1367  default:
1369  "No data segment identifier found for the configuration data\n");
1370  *extended_error = connection_path_size - remaining_path; /*offset in 16Bit words where within the connection path the error happend*/
1371  return
1373  }
1374  }
1375  }
1376  }
1377 
1378  OPENER_TRACE_INFO("Resulting PIT value: %u\n",
1379  connection_object->production_inhibit_time);
1380  /*save back the current position in the stream allowing followers to parse anything thats still there*/
1381  message_router_request->data = message;
1382  return kEipStatusOk;
1383 }
1384 
1385 void CloseConnection(CipConnectionObject *RESTRICT connection_object) {
1386 
1389  {
1390  /* only close the UDP connection for not class 3 connections */
1392  connection_object->socket[kUdpCommuncationDirectionConsuming]);
1393  connection_object->socket[kUdpCommuncationDirectionConsuming] =
1394  kEipInvalidSocket;
1396  connection_object->socket[kUdpCommuncationDirectionProducing]);
1397  connection_object->socket[kUdpCommuncationDirectionProducing] =
1398  kEipInvalidSocket;
1399  }
1400  RemoveFromActiveConnections(connection_object);
1401  ConnectionObjectInitializeEmpty(connection_object);
1402 
1403 }
1404 
1405 
1406 void AddNewActiveConnection(const CipConnectionObject *const connection_object)
1407 {
1408  DoublyLinkedListInsertAtHead(&connection_list, connection_object);
1409  ConnectionObjectSetState(connection_object,
1411 }
1412 
1413 void RemoveFromActiveConnections(CipConnectionObject *const connection_object) {
1414  for(DoublyLinkedListNode *iterator = connection_list.first; iterator != NULL;
1415  iterator = iterator->next) {
1416  if(iterator->data == connection_object) {
1417  DoublyLinkedListRemoveNode(&connection_list, &iterator);
1418  return;
1419  }
1420  }
1421  OPENER_TRACE_ERR("Connection not found in active connection list\n");
1422 }
1423 
1425  EipBool8 is_connected = false;
1426 
1427  DoublyLinkedListNode *node = connection_list.first;
1428 
1429  while (NULL != node) {
1430  CipConnectionObject *connection_object = (CipConnectionObject *)node->data;
1431  CipDword consumed_connection_point =
1432  connection_object->consumed_path.instance_id;
1433  if (instance_number == consumed_connection_point &&
1434  true == ConnectionObjectIsTypeIOConnection(connection_object) ) {
1435  is_connected = true;
1436  break;
1437  }
1438  node = node->next;
1439  }
1440  return is_connected;
1441 }
1442 
1444  const EipUint32 class_id,
1445  OpenConnectionFunction open_connection_function
1446  ) {
1447  EipStatus status = kEipStatusError;
1448 
1449  /*parsing is now finished all data is available and check now establish the connection */
1450  for (size_t i = 0; i < g_kNumberOfConnectableObjects; ++i) {
1451  if ( (0 == g_connection_management_list[i].class_id)
1452  || (class_id == g_connection_management_list[i].class_id) ) {
1453  g_connection_management_list[i].class_id = class_id;
1454  g_connection_management_list[i].open_connection_function =
1455  open_connection_function;
1456  status = kEipStatusOk;
1457  break;
1458  }
1459  }
1460 
1461  return status;
1462 }
1463 
1466 
1467  ConnectionManagementHandling *connection_management_entry = NULL;
1468 
1469  for (size_t i = 0; i < g_kNumberOfConnectableObjects; ++i) {
1470  if (class_id == g_connection_management_list[i].class_id) {
1471  connection_management_entry = &(g_connection_management_list[i]);
1472  break;
1473  }
1474  }
1475  return connection_management_entry;
1476 }
1477 
1479  unsigned int output_assembly,
1480  unsigned int input_assembly
1481  ) {
1482  EipStatus status = kEipStatusError;
1483 
1484  DoublyLinkedListNode *node = connection_list.first;
1485  while (NULL != node) {
1486  CipConnectionObject *connection_object = node->data;
1487  if ( (output_assembly == connection_object->consumed_path.instance_id)
1488  && (input_assembly ==
1489  connection_object->produced_path.instance_id) ) {
1490  if (
1493  connection_object) ) {
1494  /* produce at the next allowed occurrence */
1495  connection_object->transmission_trigger_timer = connection_object
1496  ->
1497  production_inhibit_time;
1498  status = kEipStatusOk;
1499  }
1500  break;
1501  }
1502  }
1503  return status;
1504 }
1505 
1507  const CipConnectionObject *const connection_object,
1508  CloseSessionFunction CloseSessions) {
1509 
1510  DoublyLinkedListNode *search_node = connection_list.first;
1511  bool non_timed_out_connection_found = false;
1512  while(NULL != search_node) {
1513  CipConnectionObject *search_connection = search_node->data;
1514  if(ConnectionObjectEqualOriginator(connection_object, search_connection)
1515  && connection_object != search_connection
1517  ConnectionObjectGetState(search_connection) ) {
1518  non_timed_out_connection_found = true;
1519  break;
1520  }
1521  search_node = search_node->next;
1522  }
1523  if(false == non_timed_out_connection_found) {
1524  CloseSessions(connection_object);
1525  }
1526 }
1527 
1529  memset( g_connection_management_list, 0,
1530  g_kNumberOfConnectableObjects *
1531  sizeof(ConnectionManagementHandling) );
1534 }
EipStatus EstablishClass3Connection(CipConnectionObject *RESTRICT const connection_object, EipUint16 *const extended_error)
Check if Class3 connection is available and if yes setup all data.
ConnectionObjectTransportClassTriggerDirection ConnectionObjectGetTransportClassTriggerDirection(const CipConnectionObject *const connection_object)
EipStatus CheckElectronicKeyData(EipUint8 key_format, void *key_data, EipUint16 *extended_status)
Compare the electronic key received with a forward open request with the device's data...
ConnectionManagementHandling g_connection_management_list[2+OPENER_CIP_NUM_APPLICATION_SPECIFIC_CONNECTABLE_OBJECTS]
void InsertAttribute(CipInstance *const instance, const EipUint16 attribute_number, const EipUint8 cip_type, void *const data, const EipByte cip_flags)
Insert an attribute in an instance of a CIP class.
Definition: cipcommon.c:304
ConnectionObjectConnectionType
EipUint16 product_code_
Definition: cipidentity.c:43
EipStatus ConnectionManagerInit(EipUint16 unique_connection_id)
Initialize the data of the connection manager object.
EipStatus EstablishIoConnection(CipConnectionObject *RESTRICT const connection_object, EipUint16 *const extended_error)
Establishes a new IO Type 1 Connection.
EipUint16 type_id
Definition: cpf.h:48
void DoublyLinkedListInsertAtHead(DoublyLinkedList *const list, void *data)
const CipOctet * data
Definition: ciptypes.h:191
EipStatus CreateCommonPacketFormatStructure(const EipUint8 *data, size_t data_length, CipCommonPacketFormatData *common_packet_format_data)
Creates Common Packet Format structure out of data.
Definition: cpf.c:204
EipUint16 vendor_id_
Definition: cipidentity.c:41
bool ConnectionObjectIsTypeIOConnection(const CipConnectionObject *const connection_object)
Tracing infrastructure for OpENer.
void ElectronicKeyFormat4Delete(ElectronicKeyFormat4 **electronic_key)
Destructor for the electroic key format 4 class.
EipUint16 additional_status[MAX_SIZE_OF_ADD_STATUS]
Definition: ciptypes.h:207
EipUint8 * g_config_data_buffer
network_segment_subtype
All types of network segment types for the use in all code.
Definition: cipepath.h:123
ConnectionReceiveDataFunction connection_receive_data_function
EipStatus AssembleForwardCloseResponse(EipUint16 connection_serial_number, EipUint16 originatior_vendor_id, EipUint32 originator_serial_number, CipMessageRouterRequest *message_router_request, CipMessageRouterResponse *message_router_response, EipUint16 extended_error_code)
EipStatus HandleNonNullNonMatchingForwardOpenRequest(CipConnectionObject *connection_object, CipInstance *instance, CipMessageRouterRequest *message_router_request, CipMessageRouterResponse *message_router_response)
Handles a Non Null Non Matching Forward Open Request.
DoublyLinkedList connection_list
CipConnectionObject * CheckForExistingConnection(const CipConnectionObject *const connection_object)
check if the data given in the connection object match with an already established connection ...
DoublyLinkedListNode * first
ConnectionManagerExtendedStatusCode
Connection Manager Error codes.
CIP Message Router Request.
Definition: ciptypes.h:187
CipConnectionObject * GetConnectedOutputAssembly(const EipUint32 output_assembly_id)
CipUint ConnectionObjectGetExpectedPacketRate(const CipConnectionObject *const connection_object)
void ConnectionObjectResetProductionInhibitTimer(CipConnectionObject *const connection_object)
Class is a subclass of Instance.
Definition: ciptypes.h:237
SocketAddressInfoItem address_info_item[2]
Definition: cpf.h:71
void InitializeConnectionManager(CipClass *class)
#define OPENER_ASSERT(assertion)
OpenConnectionFunction open_connection_function
EipUint16 length
Definition: cpf.h:49
CipUint ElectronicKeyFormat4GetDeviceType(const ElectronicKeyFormat4 *const electronic_key)
Gets the device type from a format 4 electronic key.
EipStatus(* OpenConnectionFunction)(CipConnectionObject *RESTRICT const connection_object, EipUint16 *const extended_error_code)
Function prototype for handling the opening of connections.
Definition: opener_api.h:310
CipConnectionObject g_dummy_connection_object
CipByte ElectronicKeyFormat4GetMajorRevision(const ElectronicKeyFormat4 *const electronic_key)
Gets the major revision from an format 4 electronic key.
DataItem data_item
Definition: cpf.h:70
CipUdint ConnectionObjectGetCipConsumedConnectionID(const CipConnectionObject *const connection_object)
ConnectionObjectConnectionType ConnectionObjectGetTToOConnectionType(const CipConnectionObject *const connection_object)
EipUint32 GetDintFromMessage(const EipUint8 **const buffer)
Reads EIP_UINT32 from *buffer and converts little endian to host.
Definition: endianconv.c:83
void RemoveFromActiveConnections(CipConnectionObject *const connection_object)
Removes connection from the list of active connections.
void ConnectionObjectSetProductionInhibitTime(CipConnectionObject *const connection_object, const CipUint production_inhibit_time)
CipCommonPacketFormatData g_common_packet_format_data_item
Data storage for the any CPF data Currently we are single threaded and need only one CPF at the time...
Definition: cpf.c:24
CipDword instance_id
Definition: cipepath.h:165
void ConnectionObjectResetInactivityWatchdogTimerValue(CipConnectionObject *const connection_object)
EipStatus AddConnectableObject(const EipUint32 class_id, OpenConnectionFunction open_connection_function)
register open functions for an specific object.
Responsible for Endianess conversion.
#define OPENER_TRACE_ERR(...)
Definition: trace.h:86
void DoublyLinkedListRemoveNode(DoublyLinkedList *const list, DoublyLinkedListNode **pointer_to_node_pointer)
EipUint8 GetSintFromMessage(const EipUint8 **const buffer)
Reads EIP_UINT8 from *buffer and converts little endian to host.
Definition: endianconv.c:29
enum data_segment_subtype DataSegmentSubtype
Data segment sub types.
void ConnectionObjectResetLastPackageInactivityTimerValue(CipConnectionObject *const connection_object)
void ManageEncapsulationMessages(const MilliSeconds elapsed_time)
Handle delayed encapsulation message responses.
Definition: encap.c:857
Public interface of the QoS Object.
AddressData data
Definition: cpf.h:44
CipUint type_id
Definition: cpf.h:57
ConnectionCloseFunction connection_close_function
void ConnectionObjectInitializeEmpty(CipConnectionObject *const connection_object)
DataSegmentSubtype GetPathDataSegmentSubtype(const unsigned char *const cip_path)
Gets the Data Segment subtype of a Data Segment EPath message.
Definition: cipepath.c:595
CIP Class 3 connection.
CipClass * CreateCipClass(const EipUint32 class_id, const int number_of_class_attributes, const EipUint32 highest_class_attribute_number, const int number_of_class_services, const int number_of_instance_attributes, const EipUint32 highest_instance_attribute_number, const int number_of_instance_services, const int number_of_instances, char *name, const EipUint16 revision, void(*InitializeCipClass)(CipClass *))
Definition: cipcommon.c:189
CipUint ElectronicKeyFormat4GetVendorId(const ElectronicKeyFormat4 *const electronic_key)
Gets the vendor ID form the electronic key.
LogicalSegmentSpecialTypeLogicalFormat GetPathLogicalSegmentSpecialTypeLogicalType(const unsigned char *const cip_path)
Gets the Special Type Logical Type of a Logical Segment EPath message.
Definition: cipepath.c:407
CipUint length
Definition: cpf.h:43
DoublyLinkedListNode * next
ElectronicKeySegmentFormat GetPathLogicalSegmentElectronicKeyFormat(const unsigned char *const cip_path)
Gets the Electronic Key format of a Logical Segment Special Type EPath message.
Definition: cipepath.c:426
int AddIntToMessage(const EipUint16 data, EipUint8 **const buffer)
converts UINT16 data from host to little endian an writes it to buffer.
Definition: endianconv.c:117
unsigned int GetPaddedLogicalPath(const EipUint8 **logical_path_segment)
gets the padded logical path TODO: enhance documentation
void AddNullAddressItem(CipCommonPacketFormatData *common_data_packet_format_data)
Adds a Null Address Item to the common data packet format data.
EipStatus
EIP stack status enum.
Definition: typedefs.h:93
uint8_t EipUint8
Definition: typedefs.h:32
bool ConnectionObjectEqualOriginator(const CipConnectionObject *const object1, const CipConnectionObject *const object2)
void InsertService(const CipClass *const class, const EipUint8 service_number, const CipServiceFunction service_function, char *const service_name)
Insert a service in an instance of a CIP object.
Definition: cipcommon.c:346
enum network_segment_subtype NetworkSegmentSubtype
All types of network segment types for the use in all code.
CipInstance class_instance
Definition: ciptypes.h:238
void HandleApplication(void)
Allow the device specific application to perform its execution.
uint32_t EipUint32
Definition: typedefs.h:34
EipStatus GetAttributeAll(CipInstance *instance, CipMessageRouterRequest *message_router_request, CipMessageRouterResponse *message_router_response, struct sockaddr *originator_address, const int encapsulation_session)
Generic implementation of the GetAttributeAll CIP service.
Definition: cipcommon.c:704
CipInstance * consuming_instance
int AddDintToMessage(const EipUint32 data, EipUint8 **const buffer)
Converts UINT32 data from host to little endian and writes it to buffer.
Definition: endianconv.c:132
#define SEQ_GT32(a, b)
enum segment_type SegmentType
Segment type Enum.
ConnectionObjectConnectionType ConnectionObjectGetOToTConnectionType(const CipConnectionObject *const connection_object)
EipStatus ManageConnections(MilliSeconds elapsed_time)
Check if any of the connection timers (TransmissionTrigger or WatchdogTimeout) have timed out...
void ConnectionObjectInitializeFromMessage(const CipOctet **message, CipConnectionObject *const connection_object)
#define OPENER_TRACE_INFO(...)
Definition: trace.h:89
void CloseUdpSocket(int socket_handle)
EipStatus TriggerConnections(unsigned int output_assembly, unsigned int input_assembly)
Trigger the production of an application triggered connection.
CipConnectionPathEpath produced_path
EipStatus ForwardClose(CipInstance *instance, CipMessageRouterRequest *message_router_request, CipMessageRouterResponse *message_router_response, struct sockaddr *originator_address, const int encapsulation_session)
NetworkSegmentSubtype GetPathNetworkSegmentSubtype(const unsigned char *const cip_path)
Return the Network Segment subtype.
Definition: cipepath.c:466
EipStatus GetAttributeSingle(CipInstance *RESTRICT const instance, CipMessageRouterRequest *const message_router_request, CipMessageRouterResponse *const message_router_response, struct sockaddr *originator_address, const int encapsulation_session)
Generic implementation of the GetAttributeSingle CIP service.
Definition: cipcommon.c:391
EipStatus ForwardOpen(CipInstance *instance, CipMessageRouterRequest *message_router_request, CipMessageRouterResponse *message_router_response, struct sockaddr *originator_address, const int encapsulation_session)
Check if resources for new connection available, generate ForwardOpen Reply message.
void CloseConnection(CipConnectionObject *RESTRICT connection_object)
Close the given connection.
CipInstance * GetCipInstance(const CipClass *RESTRICT const cip_class, EipUint32 instance_number)
Get a pointer to an instance.
EipUint32 sequence_number
Definition: cpf.h:38
EipUint16 item_count
Definition: cpf.h:68
ConnectionObjectState ConnectionObjectGetState(const CipConnectionObject *const connection_object)
CipConnectionPathEpath configuration_path
LogicalSegmentLogicalType GetPathLogicalSegmentLogicalType(const unsigned char *const cip_path)
Gets the Logical Type of an EPath Logical Segment message.
Definition: cipepath.c:213
EipStatus HandleNonNullMatchingForwardOpenRequest(CipConnectionObject *connection_object, CipInstance *instance, CipMessageRouterRequest *message_router_request, CipMessageRouterResponse *message_router_response)
Handles a Non Null Matching Forward Open Request.
EipStatus AssembleForwardOpenResponse(CipConnectionObject *connection_object, CipMessageRouterResponse *message_router_response, EipUint8 general_status, EipUint16 extended_status)
Assembles the Forward Open Response.
EipUint8 minor_revision
Definition: ciptypes.h:181
uint8_t EipByte
EIP Data type definitions.
Definition: typedefs.h:28
ConnectionTimeoutFunction connection_timeout_function
EipUint8 major_revision
Definition: ciptypes.h:180
AddressItem address_item
Definition: cpf.h:69
CipElectronicKey electronic_key
#define OPENER_TRACE_WARN(...)
Definition: trace.h:87
void InitializeClass3ConnectionData(void)
Initializes the explicit connections mechanism.
CipRevision revision_
Definition: cipidentity.c:44
uint8_t EipBool8
Definition: typedefs.h:37
unsigned int g_config_data_length
bool ElectronicKeyFormat4GetMajorRevisionCompatibility(const ElectronicKeyFormat4 *const electronic_key)
Gets the Compatibility flag from the format 4 electronic key.
This file contains the public interface of the encapsulation layer.
EipStatus HandleNullNonMatchingForwardOpenRequest(CipConnectionObject *connection_object, CipInstance *instance, CipMessageRouterRequest *message_router_request, CipMessageRouterResponse *message_router_response)
Handles a Null Non Matching Forward Open Request.
unsigned long MilliSeconds
Definition: typedefs.h:68
EipUint16 device_type_
Definition: cipidentity.c:42
void(* CloseSessionFunction)(const CipConnectionObject *const connection_object)
CipConnectionObject * GetConnectedObject(const EipUint32 connection_id)
Get a connected object dependent on requested ConnectionID.
EipUint8 * data
Definition: cpf.h:50
CipConnectionPathEpath consumed_path
EipStatus(* HandleForwardOpenRequestFunction)(CipConnectionObject *connection_object, CipInstance *instance, CipMessageRouterRequest *message_router_request, CipMessageRouterResponse *message_router_response)
Function prototype for all Forward Open handle functions.
CipUint type_id
Definition: cpf.h:42
EipUint8 ParseConnectionPath(CipConnectionObject *connection_object, CipMessageRouterRequest *message_router_request, EipUint16 *extended_error)
Parse the connection path of a forward open request.
EipUint32 eip_level_sequence_count_consuming
const CipDword CipEpathGetLogicalValue(const EipUint8 **message)
Definition: cipepath.c:332
ElectronicKeyFormat4 * ElectronicKeyFormat4New()
Constructor for the electroic key format 4 class.
uint16_t CipUint
Definition: typedefs.h:47
CipUint GetConnectionId(void)
Generate a new connection Id utilizing the Incarnation Id as described in the EIP specs...
EipUint32 connection_identifier
Definition: cpf.h:37
EipUint16 highest_attribute_number
Definition: ciptypes.h:245
EipStatus HandleReceivedConnectedData(const EipUint8 *const data, int data_length, struct sockaddr_in *from_address)
Notify the connection manager that data for a connection has been received.
EipUint16 GetIntFromMessage(const EipUint8 **const buffer)
Reads EIP_UINT16 from *buffer and converts little endian to host.
Definition: endianconv.c:57
EipStatus HandleNullMatchingForwardOpenRequest(CipConnectionObject *connection_object, CipInstance *instance, CipMessageRouterRequest *message_router_request, CipMessageRouterResponse *message_router_response)
Handles a Null Matching Forward Open request.
Struct storing the CIP revision.
Definition: ciptypes.h:179
void GetElectronicKeyFormat4FromMessage(const CipOctet **const message, ElectronicKeyFormat4 *key)
Gets the data for an Electronic Key of format 4 from the EPath message.
Definition: cipepath.c:441
ConnectionSendDataFunction connection_send_data_function
CIP Message Router Response.
Definition: ciptypes.h:199
ConnectionObjectTransportClassTriggerProductionTrigger ConnectionObjectGetTransportClassTriggerProductionTrigger(const CipConnectionObject *const connection_object)
void ConnectionObjectSetState(CipConnectionObject *const connection_object, const ConnectionObjectState state)
struct cip_class * cip_class
Definition: ciptypes.h:231
CipUint ConnectionObjectGetRequestedPacketInterval(const CipConnectionObject *const connection_object)
segment_type
Segment type Enum.
Definition: cipepath.h:59
uint32_t CipDword
Definition: typedefs.h:45
EipUint32 g_incarnation_id
Holds the connection ID's "incarnation ID" in the upper 16 bits.
CipUint ElectronicKeyFormat4GetProductCode(const ElectronicKeyFormat4 *const electronic_key)
Gets the product code from an format 4 electronic key.
A variant of a CPF packet, including item count, one address item, one data item, and two Sockaddr In...
Definition: cpf.h:67
uint16_t EipUint16
Definition: typedefs.h:33
CipUsint ElectronicKeyFormat4GetMinorRevision(const ElectronicKeyFormat4 *const electronic_key)
Gets the minor revision from an format 4 electronic key.
ConnectionObjectInstanceType ConnectionObjectGetInstanceType(const CipConnectionObject *const connection_object)
EipBool8 IsConnectedOutputAssembly(const EipUint32 instance_number)
struct sockaddr_in originator_address
void InitializeIoConnectionData(void)
Definition: appcontype.c:431
EipInt16 request_path_size
Definition: ciptypes.h:190
ConnectionManagementHandling * GetConnectionManagementEntry(const EipUint32 class_id)
SegmentType GetPathSegmentType(const CipOctet *const cip_path)
Gets the basic segment type of a CIP EPath.
Definition: cipepath.c:76
const size_t g_kForwardOpenHeaderLength
EipStatus GetConnectionOwner(CipInstance *instance, CipMessageRouterRequest *message_router_request, CipMessageRouterResponse *message_router_response, struct sockaddr *originator_address, const int encapsulation_session)
void CheckForTimedOutConnectionsAndCloseTCPConnections(const CipConnectionObject *const connection_object, CloseSessionFunction CloseSessions)
void AddNewActiveConnection(const CipConnectionObject *const connection_object)
Insert the given connection object to the list of currently active and managed connections.
#define OPENER_CIP_NUM_APPLICATION_SPECIFIC_CONNECTABLE_OBJECTS
Identity configuration of the device.
CipUsint size_of_additional_status
Definition: ciptypes.h:205
ConnectionObjectTransportClassTriggerTransportClass ConnectionObjectGetTransportClassTriggerTransportClass(const CipConnectionObject *const connection_object)
bool EqualConnectionTriad(const CipConnectionObject *const object1, const CipConnectionObject *const object2)
void InitializeConnectionManagerData(void)