OpENer - Open Source EtherNet/IP(TM) I/O Target Stack  2.1
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
cipcommon.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 <stdio.h>
8 
9 #include "cipcommon.h"
10 
11 #include "opener_user_conf.h"
12 #include "opener_api.h"
13 #include "cipidentity.h"
14 #include "ciptcpipinterface.h"
15 #include "cipethernetlink.h"
16 #include "cipconnectionmanager.h"
17 #include "endianconv.h"
18 #include "encap.h"
19 #include "ciperror.h"
20 #include "cipassembly.h"
21 #include "cipmessagerouter.h"
22 #include "cipqos.h"
23 #include "cpf.h"
24 #include "trace.h"
25 #include "appcontype.h"
26 #include "cipepath.h"
27 #include "stdlib.h"
28 
29 /* global public variables */
32 /* private functions*/
33 int EncodeEPath(CipEpath *epath,
34  EipUint8 **message);
35 
36 void CipStackInit(const EipUint16 unique_connection_id) {
38  /* The message router is the first CIP object be initialized!!! */
39  EipStatus eip_status = CipMessageRouterInit();
40  OPENER_ASSERT(kEipStatusOk == eip_status)
41  eip_status = CipIdentityInit();
42  OPENER_ASSERT(kEipStatusOk == eip_status)
43  eip_status = CipTcpIpInterfaceInit();
44  OPENER_ASSERT(kEipStatusOk == eip_status)
45  eip_status = CipEthernetLinkInit();
46  OPENER_ASSERT(kEipStatusOk == eip_status)
47  eip_status = ConnectionManagerInit(unique_connection_id);
48  OPENER_ASSERT(kEipStatusOk == eip_status)
49  eip_status = CipAssemblyInitialize();
50  OPENER_ASSERT(kEipStatusOk == eip_status)
51  eip_status = CipQoSInit();
52  OPENER_ASSERT(kEipStatusOk == eip_status)
53  /* the application has to be initialized at last */
54  eip_status = ApplicationInitialization();
55  OPENER_ASSERT(kEipStatusOk == eip_status)
56 
57  /* Shut up compiler warning with traces disabled */
58  (void) eip_status;
59 }
60 
61 void ShutdownCipStack(void) {
62  /* First close all connections */
64  /* Than free the sockets of currently active encapsulation sessions */
66  /*clean the data needed for the assembly object's attribute 3*/
68 
70 
71  /*no clear all the instances and classes */
73 }
74 
75 EipStatus NotifyClass(const CipClass *RESTRICT const cip_class,
76  CipMessageRouterRequest *const message_router_request,
77  CipMessageRouterResponse *const message_router_response,
78  struct sockaddr *originator_address,
79  const int encapsulation_session) {
80 
81  /* find the instance: if instNr==0, the class is addressed, else find the instance */
82  EipUint16 instance_number =
83  message_router_request->request_path.instance_number; /* get the instance number */
84  CipInstance *instance = GetCipInstance(cip_class, instance_number); /* look up the instance (note that if inst==0 this will be the class itself) */
85  if (instance) /* if instance is found */
86  {
87  OPENER_TRACE_INFO("notify: found instance %d%s\n", instance_number,
88  instance_number == 0 ? " (class object)" : "");
89 
90  CipServiceStruct *service = instance->cip_class->services; /* get pointer to array of services */
91  if (NULL != service) /* if services are defined */
92  {
93  for (size_t i = 0; i < instance->cip_class->number_of_services; i++) /* seach the services list */
94  {
95  if (message_router_request->service == service->service_number) /* if match is found */
96  {
97  /* call the service, and return what it returns */
98  OPENER_TRACE_INFO("notify: calling %s service\n",
99  service->name);
100  OPENER_ASSERT(NULL != service->service_function)
101  return service->service_function(instance,
102  message_router_request,
103  message_router_response,
104  originator_address,
105  encapsulation_session);
106  } else {
107  service++;
108  }
109  }
110  }
111  OPENER_TRACE_WARN("notify: service 0x%x not supported\n",
112  message_router_request->service);
113  message_router_response->general_status = kCipErrorServiceNotSupported; /* if no services or service not found, return an error reply*/
114  } else {
115  OPENER_TRACE_WARN("notify: instance number %d unknown\n",
116  instance_number);
117  /* if instance not found, return an error reply */
118  message_router_response->general_status =
120  /* according to the test tool this is the correct error flag instead of CIP_ERROR_OBJECT_DOES_NOT_EXIST */
121  }
122 
123  /* handle error replies*/
124  message_router_response->size_of_additional_status = 0; /* fill in the rest of the reply with not much of anything*/
125  message_router_response->data_length = 0;
126  message_router_response->reply_service = (0x80
127  | message_router_request->service); /* except the reply code is an echo of the command + the reply flag */
128 
129  return kEipStatusOkSend;
130 }
131 
133  const int number_of_instances) {
134  CipInstance **next_instance = NULL;
135  EipUint32 instance_number = 1; /* the first instance is number 1 */
136 
137  OPENER_TRACE_INFO("adding %d instances to class %s\n", number_of_instances,
138  cip_class->class_name);
139 
140  next_instance = &cip_class->instances; /* get address of pointer to head of chain */
141  while (*next_instance) /* as long as what pp points to is not zero */
142  {
143  next_instance = &(*next_instance)->next; /* follow the chain until pp points to pointer that contains a zero */
144  instance_number++; /* keep track of what the first new instance number will be */
145  }
146 
147  CipInstance *current_instance = (CipInstance *) CipCalloc(
148  number_of_instances, sizeof(CipInstance) ); /* allocate a block of memory for all created instances*/
149  CipInstance *first_instance = current_instance; /* allocate a block of memory for all created instances*/
150 
151  OPENER_ASSERT(NULL != current_instance)
152  /* fail if run out of memory */
153 
154  cip_class->number_of_instances += number_of_instances; /* add the number of instances just created to the total recorded by the class */
155 
156  for (size_t i = 0; i < number_of_instances; i++) /* initialize all the new instances */
157  {
158  *next_instance = current_instance; /* link the previous pointer to this new node */
159 
160  current_instance->instance_number = instance_number; /* assign the next sequential instance number */
161  current_instance->cip_class = cip_class; /* point each instance to its class */
162 
163  if (cip_class->number_of_attributes) /* if the class calls for instance attributes */
164  { /* then allocate storage for the attribute array */
165  current_instance->attributes = (CipAttributeStruct *) CipCalloc(
166  cip_class->number_of_attributes,
167  sizeof(CipAttributeStruct) );
168  }
169 
170  next_instance = &current_instance->next; /* update pp to point to the next link of the current node */
171  instance_number++; /* update to the number of the next node*/
172  current_instance++; /* point to the next node in the calloc'ed array*/
173  }
174 
175  return first_instance;
176 }
177 
178 CipInstance *AddCIPInstance(CipClass *RESTRICT const class,
179  const EipUint32 instance_id) {
180  CipInstance *instance = GetCipInstance(class, instance_id);
181 
182  if (NULL == instance) { /*we have no instance with given id*/
183  instance = AddCipInstances(class, 1);
184  instance->instance_number = instance_id;
185  }
186  return instance;
187 }
188 
190  const int number_of_class_attributes,
191  const EipUint32 highest_class_attribute_number,
192  const int number_of_class_services,
193  const int number_of_instance_attributes,
194  const EipUint32 highest_instance_attribute_number,
195  const int number_of_instance_services,
196  const int number_of_instances,
197  char *name,
198  const EipUint16 revision,
199  void (*InitializeCipClass)(CipClass *) ) {
200 
201  OPENER_TRACE_INFO("creating class '%s' with id: 0x%" PRIX32 "\n", name,
202  class_id);
203 
204  OPENER_ASSERT(NULL == GetCipClass(class_id) ) /* check if an class with the ClassID already exists */
205  /* should never try to redefine a class*/
206 
207  /* a metaClass is a class that holds the class attributes and services
208  CIP can talk to an instance, therefore an instance has a pointer to its class
209  CIP can talk to a class, therefore a class struct is a subclass of the instance struct,
210  and contains a pointer to a metaclass
211  CIP never explicitly addresses a metaclass*/
212 
213  CipClass * const class = (CipClass *) CipCalloc(1, sizeof(CipClass) ); /* create the class object*/
214  CipClass *const meta_class = (CipClass *) CipCalloc(1, sizeof(CipClass) ); /* create the metaclass object*/
215 
216  /* initialize the class-specific fields of the Class struct*/
217  class->class_id = class_id; /* the class remembers the class ID */
218  class->revision = revision; /* the class remembers the class ID */
219  class->number_of_instances = 0; /* the number of instances initially zero (more created below) */
220  class->instances = 0;
221  class->number_of_attributes = number_of_instance_attributes; /* the class remembers the number of instances of that class */
222  class->highest_attribute_number = highest_instance_attribute_number; /* indicate which attributes are included in instance getAttributeAll */
223  class->number_of_services = number_of_instance_services; /* the class manages the behavior of the instances */
224  class->services = 0;
225  class->class_name = name; /* initialize the class-specific fields of the metaClass struct */
226  meta_class->class_id = 0xffffffff; /* set metaclass ID (this should never be referenced) */
227  meta_class->number_of_instances = 1; /* the class object is the only instance of the metaclass */
228  meta_class->instances = (CipInstance *) class;
229  meta_class->number_of_attributes = number_of_class_attributes + 7; /* the metaclass remembers how many class attributes exist*/
230  meta_class->highest_attribute_number = highest_class_attribute_number; /* indicate which attributes are included in class getAttributeAll*/
231  meta_class->number_of_services = number_of_class_services; /* the metaclass manages the behavior of the class itself */
232  meta_class->class_name = (char *) CipCalloc(1, strlen(name) + 6); /* fabricate the name "meta<classname>"*/
233  snprintf(meta_class->class_name, strlen(name) + 6, "meta-%s", name);
234 
235  /* initialize the instance-specific fields of the Class struct*/
236  class->class_instance.instance_number = 0; /* the class object is instance zero of the class it describes (weird, but that's the spec)*/
237  class->class_instance.attributes = 0; /* this will later point to the class attibutes*/
238  class->class_instance.cip_class = meta_class; /* the class's class is the metaclass (like SmallTalk)*/
239  class->class_instance.next = 0; /* the next link will always be zero, sinc there is only one instance of any particular class object */
240 
241  meta_class->class_instance.instance_number = 0xffffffff; /*the metaclass object does not really have a valid instance number*/
242  meta_class->class_instance.attributes = 0; /* the metaclass has no attributes*/
243  meta_class->class_instance.cip_class = 0; /* the metaclass has no class*/
244  meta_class->class_instance.next = 0; /* the next link will always be zero, since there is only one instance of any particular metaclass object*/
245 
246  /* further initialization of the class object*/
247 
248  class->class_instance.attributes = (CipAttributeStruct *) CipCalloc(
249  meta_class->number_of_attributes, sizeof(CipAttributeStruct) );
250  /* TODO -- check that we didn't run out of memory?*/
251 
252  meta_class->services = (CipServiceStruct *) CipCalloc(
253  meta_class->number_of_services, sizeof(CipServiceStruct) );
254 
255  class->services = (CipServiceStruct *) CipCalloc(class->number_of_services,
256  sizeof(CipServiceStruct) );
257 
258  if (number_of_instances > 0) {
259  AddCipInstances(class, number_of_instances); /*TODO handle return value and clean up if necessary*/
260  }
261 
262  if ( (RegisterCipClass(class) ) == kEipStatusError ) { /* no memory to register class in Message Router */
263  return 0; /*TODO handle return value and clean up if necessary*/
264  }
265 
266  AllocateAttributeMasks(meta_class); /* Allocation of bitmasks for Class Attributes */
267  AllocateAttributeMasks(class); /* Allocation of bitmasks for Instance Attributes */
268 
269  if (InitializeCipClass == NULL) {
270  InsertAttribute( (CipInstance *) class, 1, kCipUint,
271  (void *) &class->revision, kGetableSingleAndAll ); /* revision */
272  InsertAttribute( (CipInstance *) class, 2, kCipUint,
273  (void *) &class->number_of_instances,
274  kGetableSingleAndAll ); /* largest instance number */
275  InsertAttribute( (CipInstance *) class, 3, kCipUint,
276  (void *) &class->number_of_instances,
277  kGetableSingleAndAll ); /* number of instances currently existing*/
278  InsertAttribute( (CipInstance *) class, 4, kCipUint,
279  (void *) &kCipUintZero, kGetableAll ); /* optional attribute list - default = 0 */
280  InsertAttribute( (CipInstance *) class, 5, kCipUint,
281  (void *) &kCipUintZero, kNotSetOrGetable ); /* optional service list - default = 0 */
282  InsertAttribute( (CipInstance *) class, 6, kCipUint,
283  (void *) &meta_class->highest_attribute_number,
284  kGetableSingle ); /* max class attribute number*/
285  InsertAttribute( (CipInstance *) class, 7, kCipUint,
286  (void *) &class->highest_attribute_number,
287  kGetableSingle ); /* max instance attribute number*/
288  } else {
289  InitializeCipClass(class);
290  }
291 
292  /* create the standard class services*/
293  if (number_of_class_services > 0) {
294  if (number_of_class_services > 1) { /*only if the mask has values add the get_attribute_all service */
296  "GetAttributeAll"); /* bind instance services to the metaclass*/
297  }
299  "GetAttributeSingle");
300  }
301  return class;
302 }
303 
304 void InsertAttribute(CipInstance *const instance,
305  const EipUint16 attribute_number,
306  const EipUint8 cip_type,
307  void *const data,
308  const EipByte cip_flags) {
309 
310  CipAttributeStruct *attribute = instance->attributes;
311  CipClass *class = instance->cip_class;
312 
313  OPENER_ASSERT(NULL != attribute)
314  /* adding a attribute to a class that was not declared to have any attributes is not allowed */
315  for (int i = 0; i < instance->cip_class->number_of_attributes; i++) {
316  if (attribute->data == NULL) { /* found non set attribute */
317  attribute->attribute_number = attribute_number;
318  attribute->type = cip_type;
319  attribute->attribute_flags = cip_flags;
320  attribute->data = data;
321 
322  OPENER_ASSERT(attribute_number <= class->highest_attribute_number)
323 
324  size_t index = CalculateIndex(attribute_number);
325 
326  class->get_single_bit_mask[index] |=
327  (cip_flags & kGetableSingle) ?
328  1 << (attribute_number) % 8 : 0;
329  class->get_all_bit_mask[index] |=
330  (cip_flags & kGetableAll) ? 1 << (attribute_number) % 8 : 0;
331  class->set_bit_mask[index] |= ( (cip_flags & kSetable) ? 1 : 0 )
332  << ( (attribute_number) % 8 );
333 
334  return;
335  }
336  attribute++;
337  }
339  "Tried to insert to many attributes into class: %" PRIu32 ", instance %" PRIu32 "\n",
341  instance->instance_number);
342  OPENER_ASSERT(0)
343  /* trying to insert too many attributes*/
344 }
345 
346 void InsertService(const CipClass *const class,
347  const EipUint8 service_number,
348  const CipServiceFunction service_function,
349  char *const service_name) {
350 
351  CipServiceStruct *service = class->services; /* get a pointer to the service array*/
352  OPENER_TRACE_INFO("%s, number of services:%d, service number:%d\n",
353  class->class_name, class->number_of_services,
354  service_number);
355  OPENER_ASSERT(service != NULL)
356  /* adding a service to a class that was not declared to have services is not allowed*/
357  for (int i = 0; i < class->number_of_services; i++) /* Iterate over all service slots attached to the class */
358  {
359  if (service->service_number == service_number||
360  service->service_function == NULL) /* found undefined service slot*/
361  {
362  service->service_number = service_number; /* fill in service number*/
363  service->service_function = service_function; /* fill in function address*/
364  service->name = service_name;
365  return;
366  }
367  ++service;
368  }
369  OPENER_ASSERT(0)
370  /* adding more services than were declared is a no-no*/
371 }
372 
374  const EipUint16 attribute_number) {
375 
376  CipAttributeStruct *attribute = instance->attributes; /* init pointer to array of attributes*/
377  for (int i = 0; i < instance->cip_class->number_of_attributes; i++) {
378  if (attribute_number == attribute->attribute_number) {
379  return attribute;
380  } else {
381  ++attribute;
382  }
383  }
384 
385  OPENER_TRACE_WARN("attribute %d not defined\n", attribute_number);
386 
387  return NULL;
388 }
389 
390 /* TODO this needs to check for buffer overflow*/
391 EipStatus GetAttributeSingle(CipInstance *RESTRICT const instance,
392  CipMessageRouterRequest *const message_router_request,
393  CipMessageRouterResponse *const message_router_response,
394  struct sockaddr *originator_address,
395  const int encapsulation_session) {
396  /* Mask for filtering get-ability */
397 
398  CipAttributeStruct *attribute = GetCipAttribute(instance,
399  message_router_request->request_path.attribute_number);
400  EipByte *message = message_router_response->data;
401 
402  message_router_response->data_length = 0;
403  message_router_response->reply_service = (0x80
404  | message_router_request->service);
405  message_router_response->general_status = kCipErrorAttributeNotSupported;
406  message_router_response->size_of_additional_status = 0;
407 
408  EipUint16 attribute_number =
409  message_router_request->request_path.attribute_number;
410 
411  if ( (NULL != attribute) && (NULL != attribute->data) ) {
412  uint8_t get_bit_mask = 0;
413  if (kGetAttributeAll == message_router_request->service) {
414  get_bit_mask =
415  (instance->cip_class->get_all_bit_mask[CalculateIndex(
416  attribute_number)]);
417  message_router_response->general_status = kCipErrorSuccess;
418  } else {
419  get_bit_mask =
420  (instance->cip_class->get_single_bit_mask[CalculateIndex(
421  attribute_number)]);
422  }
423  if (0 != (get_bit_mask & (1 << (attribute_number % 8) ) ) ) {
424  OPENER_TRACE_INFO("getAttribute %d\n",
425  message_router_request->request_path.attribute_number); /* create a reply message containing the data*/
426 
427  /*TODO think if it is better to put this code in an own
428  * getAssemblyAttributeSingle functions which will call get attribute
429  * single.
430  */
431 
432  if (attribute->type == kCipByteArray
433  && instance->cip_class->class_id == kCipAssemblyClassCode) {
434  /* we are getting a byte array of a assembly object, kick out to the app callback */
435  OPENER_TRACE_INFO(" -> getAttributeSingle CIP_BYTE_ARRAY\r\n");
436  BeforeAssemblyDataSend(instance);
437  }
438 
439  OPENER_ASSERT(NULL != attribute)
440  message_router_response->data_length = EncodeData(attribute->type,
441  attribute->data,
442  &message);
443  message_router_response->general_status = kCipErrorSuccess;
444  }
445  }
446 
447  return kEipStatusOkSend;
448 }
449 
450 int EncodeData(const EipUint8 cip_type,
451  const void *const cip_data,
452  EipUint8 **cip_message) {
453  int counter = 0;
454 
455  switch (cip_type)
456  /* check the data type of attribute */
457  {
458  case (kCipBool):
459  case (kCipSint):
460  case (kCipUsint):
461  case (kCipByte):
462  counter = AddSintToMessage(*(EipUint8 *) (cip_data), cip_message);
463  break;
464 
465  case (kCipInt):
466  case (kCipUint):
467  case (kCipWord):
468  counter = AddIntToMessage(*(EipUint16 *) (cip_data), cip_message);
469  break;
470 
471  case (kCipDint):
472  case (kCipUdint):
473  case (kCipDword):
474  case (kCipReal):
475  counter = AddDintToMessage(*(EipUint32 *) (cip_data), cip_message);
476  break;
477 
478 #ifdef OPENER_SUPPORT_64BIT_DATATYPES
479  case (kCipLint):
480  case (kCipUlint):
481  case (kCipLword):
482  case (kCipLreal):
483  counter = AddLintToMessage(*(EipUint64 *) (cip_data), cip_message);
484  break;
485 #endif
486 
487  case (kCipStime):
488  case (kCipDate):
489  case (kCipTimeOfDay):
490  case (kCipDateAndTime):
491  break;
492  case (kCipString): {
493  CipString *const string = (CipString *) cip_data;
494 
495  AddIntToMessage(*(EipUint16 *) &(string->length), cip_message);
496  memcpy(*cip_message, string->string, string->length);
497  *cip_message += string->length;
498 
499  counter = string->length + 2; /* we have a two byte length field */
500  if (counter & 0x01) {
501  /* we have an odd byte count */
502  **cip_message = 0;
503  ++(*cip_message);
504  counter++;
505  }
506  break;
507  }
508  case (kCipString2):
509  case (kCipFtime):
510  case (kCipLtime):
511  case (kCipItime):
512  case (kCipStringN):
513  break;
514 
515  case (kCipShortString): {
516  CipShortString *const short_string = (CipShortString *) cip_data;
517 
518  **cip_message = short_string->length;
519  ++(*cip_message);
520 
521  memcpy(*cip_message, short_string->string, short_string->length);
522  *cip_message += short_string->length;
523 
524  counter = short_string->length + 1;
525  break;
526  }
527 
528  case (kCipTime):
529  break;
530 
531  case (kCipEpath):
532  counter = EncodeEPath( (CipEpath *) cip_data, cip_message );
533  break;
534 
535  case (kCipEngUnit):
536  break;
537 
538  case (kCipUsintUsint): {
539  CipRevision *revision = (CipRevision *) cip_data;
540 
541  **cip_message = revision->major_revision;
542  ++(*cip_message);
543  **cip_message = revision->minor_revision;
544  ++(*cip_message);
545  counter = 2;
546  break;
547  }
548 
550  /* TCP/IP attribute 5 */
552  tcp_ip_network_interface_configuration =
554  counter += AddDintToMessage(
555  ntohl(tcp_ip_network_interface_configuration->ip_address),
556  cip_message);
557  counter += AddDintToMessage(
558  ntohl(tcp_ip_network_interface_configuration->network_mask),
559  cip_message);
560  counter += AddDintToMessage(
561  ntohl(tcp_ip_network_interface_configuration->gateway),
562  cip_message);
563  counter += AddDintToMessage(
564  ntohl(tcp_ip_network_interface_configuration->name_server),
565  cip_message);
566  counter += AddDintToMessage(
567  ntohl(tcp_ip_network_interface_configuration->name_server_2),
568  cip_message);
569  counter += EncodeData(kCipString,
570  &(tcp_ip_network_interface_configuration->
571  domain_name),
572  cip_message);
573  break;
574  }
575 
576  case (kCip6Usint): {
577  EipUint8 *p = (EipUint8 *) cip_data;
578  memcpy(*cip_message, p, 6);
579  counter = 6;
580  break;
581  }
582 
583  case (kCipMemberList):
584  break;
585 
586  case (kCipByteArray): {
587  OPENER_TRACE_INFO(" -> get attribute byte array\r\n");
588  CipByteArray *cip_byte_array = (CipByteArray *) cip_data;
589  memcpy(*cip_message, cip_byte_array->data, cip_byte_array->length);
590  *cip_message += cip_byte_array->length;
591  counter = cip_byte_array->length;
592  }
593  break;
594 
595  case (kInternalUint6): /* TODO for port class attribute 9, hopefully we can find a better way to do this*/
596  {
597  EipUint16 *internal_unit16_6 = (EipUint16 *) cip_data;
598 
599  AddIntToMessage(internal_unit16_6[0], cip_message);
600  AddIntToMessage(internal_unit16_6[1], cip_message);
601  AddIntToMessage(internal_unit16_6[2], cip_message);
602  AddIntToMessage(internal_unit16_6[3], cip_message);
603  AddIntToMessage(internal_unit16_6[4], cip_message);
604  AddIntToMessage(internal_unit16_6[5], cip_message);
605  counter = 12;
606  break;
607  }
608  default:
609  break;
610 
611  }
612 
613  return counter;
614 }
615 
616 int DecodeData(const EipUint8 cip_data_type,
617  void *const cip_data,
618  const EipUint8 **const cip_message) {
619  int number_of_decoded_bytes = -1;
620 
621  switch (cip_data_type)
622  /* check the data type of attribute */
623  {
624  case (kCipBool):
625  case (kCipSint):
626  case (kCipUsint):
627  case (kCipByte):
628  *(EipUint8 *) (cip_data) = **cip_message;
629  ++(*cip_message);
630  number_of_decoded_bytes = 1;
631  break;
632 
633  case (kCipInt):
634  case (kCipUint):
635  case (kCipWord):
636  (*(EipUint16 *) (cip_data) ) = GetIntFromMessage(cip_message);
637  number_of_decoded_bytes = 2;
638  break;
639 
640  case (kCipDint):
641  case (kCipUdint):
642  case (kCipDword):
643  case (kCipReal):
644  (*(EipUint32 *) (cip_data) ) = GetDintFromMessage(cip_message);
645  number_of_decoded_bytes = 4;
646  break;
647 
648 #ifdef OPENER_SUPPORT_64BIT_DATATYPES
649  case (kCipLint):
650  case (kCipUlint):
651  case (kCipLword): {
652  (*(EipUint64 *) (cip_data) ) = GetLintFromMessage(cip_message);
653  number_of_decoded_bytes = 8;
654  }
655  break;
656 #endif
657 
658  case (kCipString): {
659  CipString *string = (CipString *) cip_data;
660  string->length = GetIntFromMessage(cip_message);
661  memcpy(string->string, *cip_message, string->length);
662  *cip_message += string->length;
663 
664  number_of_decoded_bytes = string->length + 2; /* we have a two byte length field */
665  if (number_of_decoded_bytes & 0x01) {
666  /* we have an odd byte count */
667  ++(*cip_message);
668  number_of_decoded_bytes++;
669  }
670  }
671  break;
672  case (kCipShortString): {
673  CipShortString *short_string = (CipShortString *) cip_data;
674 
675  short_string->length = **cip_message;
676  ++(*cip_message);
677 
678  memcpy(short_string->string, *cip_message, short_string->length);
679  *cip_message += short_string->length;
680 
681  number_of_decoded_bytes = short_string->length + 1;
682  break;
683  }
684 
685  default:
686  break;
687  }
688 
689  return number_of_decoded_bytes;
690 }
691 
692 CipServiceStruct *GetCipService(const CipInstance *const instance, CipUsint service_number) {
693  CipServiceStruct *service = instance->cip_class->services;
694  for (size_t i = 0; i < instance->cip_class->number_of_services; i++) /* hunt for the GET_ATTRIBUTE_SINGLE service*/
695  {
696  if (service->service_number == service_number) {
697  return service; /* found the service */
698  }
699  service++;
700  }
701  return NULL; /* didn't find the service */
702 }
703 
705  CipMessageRouterRequest *message_router_request,
706  CipMessageRouterResponse *message_router_response,
707  struct sockaddr *originator_address,
708  const int encapsulation_session) {
709 
710  EipUint8 *reply = message_router_response->data; /* pointer into the reply */
711  CipAttributeStruct *attribute = instance->attributes; /* pointer to list of attributes*/
712  CipServiceStruct *service = GetCipService(instance, kGetAttributeSingle); /* pointer to list of services*/
713 
714  if(NULL == service) {
715  /* GetAttributeAll service not found */
716  /* Return kEipStatusOk if cannot find GET_ATTRIBUTE_SINGLE service*/
717  return kEipStatusOk;
718  }
719 
720  if (0 == instance->cip_class->number_of_attributes) {
721  message_router_response->data_length = 0; /*there are no attributes to be sent back*/
722  message_router_response->reply_service = (0x80 | message_router_request->service);
723  message_router_response->general_status = kCipErrorServiceNotSupported;
724  message_router_response->size_of_additional_status = 0;
725  } else {
726  for (size_t j = 0; j < instance->cip_class->number_of_attributes; j++) {
727  /* for each instance attribute of this class */
728  int attribute_number = attribute->attribute_number;
729  if (attribute_number < 32 && ( (instance->cip_class->get_all_bit_mask[CalculateIndex(attribute_number)]) &
730  (1 << (attribute_number % 8) ) )) {
731  /* only return attributes that are flagged as being part of GetAttributeALl */
732  message_router_request->request_path.attribute_number = attribute_number;
733  if (kEipStatusOkSend != service->service_function(instance, message_router_request, message_router_response, originator_address, encapsulation_session) ) {
734  message_router_response->data = reply;
735  return kEipStatusError;
736  }
737  message_router_response->data += message_router_response->data_length;
738  }
739  attribute++;
740  }
741  message_router_response->data_length = message_router_response->data - reply;
742  message_router_response->data = reply;
743  }
744  return kEipStatusOkSend;
745 }
746 
748  EipUint8 **message) {
749  unsigned int length = epath->path_size;
750  AddIntToMessage(epath->path_size, message);
751 
752  if (epath->class_id < 256) {
753  **message = 0x20; /*8Bit Class Id */
754  ++(*message);
755  **message = (EipUint8) epath->class_id;
756  ++(*message);
757  length -= 1;
758  } else {
759  **message = 0x21; /*16Bit Class Id */
760  ++(*message);
761  **message = 0; /*pad byte */
762  ++(*message);
763  AddIntToMessage(epath->class_id, message);
764  length -= 2;
765  }
766 
767  if (0 < length) {
768  if (epath->instance_number < 256) {
769  **message = 0x24; /*8Bit Instance Id */
770  ++(*message);
771  **message = (EipUint8) epath->instance_number;
772  ++(*message);
773  length -= 1;
774  } else {
775  **message = 0x25; /*16Bit Instance Id */
776  ++(*message);
777  **message = 0; /*padd byte */
778  ++(*message);
779  AddIntToMessage(epath->instance_number, message);
780  length -= 2;
781  }
782 
783  if (0 < length) {
784  if (epath->attribute_number < 256) {
785  **message = 0x30; /*8Bit Attribute Id */
786  ++(*message);
787  **message = (EipUint8) epath->attribute_number;
788  ++(*message);
789  length -= 1;
790  } else {
791  **message = 0x31; /*16Bit Attribute Id */
792  ++(*message);
793  **message = 0; /*pad byte */
794  ++(*message);
795  AddIntToMessage(epath->attribute_number, message);
796  length -= 2;
797  }
798  }
799  }
800 
801  return 2 + epath->path_size * 2; /* path size is in 16 bit chunks according to the specification */
802 }
803 
805  const EipUint8 **message) {
806  unsigned int number_of_decoded_elements = 0;
807  const EipUint8 *message_runner = *message;
808 
809  epath->path_size = *message_runner;
810  message_runner++;
811  /* copy path to structure, in version 0.1 only 8 bit for Class,Instance and Attribute, need to be replaced with function */
812  epath->class_id = 0;
813  epath->instance_number = 0;
814  epath->attribute_number = 0;
815 
816  for (number_of_decoded_elements = 0;
817  number_of_decoded_elements < epath->path_size;
818  number_of_decoded_elements++) {
820  == ( (*message_runner) & kSegmentTypeReserved ) ) {
821  /* If invalid/reserved segment type, segment type greater than 0xE0 */
822  return kEipStatusError;
823  }
824 
825  switch (*message_runner) {
828  epath->class_id = *(EipUint8 *) (message_runner + 1);
829  message_runner += 2;
830  break;
831 
834  message_runner += 2;
835  epath->class_id = GetIntFromMessage(&(message_runner) );
836  number_of_decoded_elements++;
837  break;
838 
841  epath->instance_number = *(EipUint8 *) (message_runner + 1);
842  message_runner += 2;
843  break;
844 
847  message_runner += 2;
848  epath->instance_number = GetIntFromMessage(&(message_runner) );
849  number_of_decoded_elements++;
850  break;
851 
854  epath->attribute_number = *(EipUint8 *) (message_runner + 1);
855  message_runner += 2;
856  break;
857 
860  message_runner += 2;
861  epath->attribute_number = GetIntFromMessage(&(message_runner) );
862  number_of_decoded_elements++;
863  break;
864 
867  message_runner += 2;
868  break;
871  message_runner += 2;
872  number_of_decoded_elements++;
873  break;
874 
875  default:
876  OPENER_TRACE_ERR("wrong path requested\n");
877  return kEipStatusError;
878  }
879  }
880 
881  *message = message_runner;
882  return number_of_decoded_elements * 2 + 1; /* number_of_decoded_elements times 2 as every encoding uses 2 bytes */
883 }
884 
885 void AllocateAttributeMasks(CipClass *target_class) {
886  size_t size = 1 + CalculateIndex(target_class->highest_attribute_number);
888  ">>> Allocate memory for %s %lu bytes times 3 for masks\n",
889  target_class->class_name, size);
890  target_class->get_single_bit_mask = CipCalloc(size, sizeof(uint8_t) );
891  target_class->set_bit_mask = CipCalloc(size, sizeof(uint8_t) );
892  target_class->get_all_bit_mask = CipCalloc(size, sizeof(uint8_t) );
893 }
894 
895 size_t CalculateIndex(EipUint16 attribute_number) {
896  size_t index = attribute_number / 8;
897  return index;
898 }
899 
900 size_t GetSizeOfAttribute(const CipAttributeStruct *const attribute_struct) {
901  size_t data_type_size = 0;
902  switch (attribute_struct->type) {
903  case (kCipBool):
904  data_type_size = sizeof(CipBool);
905  break;
906  case (kCipSint):
907  data_type_size = sizeof(CipSint);
908  break;
909  case (kCipInt):
910  data_type_size = sizeof(CipInt);
911  break;
912  case (kCipDint):
913  data_type_size = sizeof(CipDint);
914  break;
915  case (kCipUsint):
916  data_type_size =sizeof(CipUsint);
917  break;
918  case (kCipUint):
919  data_type_size =sizeof(CipUint);
920  break;
921  case (kCipUdint):
922  data_type_size =sizeof(CipUdint);
923  break;
924  case (kCipReal):
925  data_type_size =sizeof(CipReal);
926  break;
927 #ifdef OPENER_SUPPORT_64BIT_DATATYPES
928  case (kCipLreal):
929  data_type_size = sizeof(CipLreal);
930  break;
931  case (kCipUlint):
932  data_type_size = sizeof(CipUlint);
933  break;
934  case (kCipLint):
935  data_type_size = sizeof(CipLint);
936  break;
937  case (kCipLword):
938  data_type_size = sizeof(CipLword);
939  break;
940  case (kCipLtime):
941  data_type_size = sizeof(CipLint);
942  break;
943 #endif /* OPENER_SUPPORT_64BIT_DATATYPES */
944 
945  case (kCipStime):
946  data_type_size = sizeof(CipDint);
947  break;
948  case (kCipDate):
949  data_type_size = sizeof(CipUint);
950  break;
951  case (kCipTimeOfDay):
952  data_type_size = sizeof(CipUdint);
953  break;
954  case (kCipDateAndTime):
955  data_type_size = sizeof(CipUdint) + sizeof(CipUint);
956  break;
957  case (kCipString): {
958  CipString *data = (CipString *) attribute_struct->data;
959  data_type_size = sizeof(CipUint) + (data->length) * sizeof(CipOctet);
960  }
961  break;
962  case (kCipByte):
963  data_type_size = sizeof(CipByte);
964  break;
965  case (kCipWord):
966  data_type_size = sizeof(CipWord);
967  break;
968  case (kCipDword):
969  data_type_size = sizeof(CipDword);
970  break;
971  case (kCipString2): {
972  CipString *data = (CipString *) attribute_struct->data;
973  data_type_size = sizeof(CipUint) + 2 * (data->length) * sizeof(CipOctet);
974  }
975  break;
976  case (kCipFtime):
977  data_type_size = sizeof(CipDint);
978  break;
979  case (kCipItime):
980  data_type_size = sizeof(CipInt);
981  break;
982  case (kCipStringN): {
983  CipStringN *data = (CipStringN *) attribute_struct->data;
984  data_type_size = sizeof(CipUint) + sizeof(CipUint)
985  + (size_t) (data->length) * (size_t) (data->size);
986  }
987  break;
988  case (kCipShortString): {
989  CipShortString *data = (CipShortString *) attribute_struct->data;
990  data_type_size = sizeof(CipUsint) + (data->length) * sizeof(CipOctet);
991  }
992  break;
993  case (kCipTime):
994  data_type_size = sizeof(CipDint);
995  break;
996  case (kCipEpath): {
997  CipEpath *data = (CipEpath *) attribute_struct->data;
998  data_type_size = 2 * (data->path_size);
999  }
1000  break;
1001  case (kCipEngUnit):
1002  data_type_size = sizeof(CipUint);
1003  break;
1004  case (kCipUsintUsint):
1005  data_type_size = 2 * sizeof(CipUsint);
1006  break;
1009  (CipTcpIpNetworkInterfaceConfiguration *) attribute_struct->data;
1010  data_type_size = 5 * sizeof(CipUdint) + sizeof(CipUint)
1011  + (data->domain_name.length) * sizeof(EipByte);
1012  }
1013  break;
1014  case (kCip6Usint):
1015  data_type_size = 6 * sizeof(CipUsint);
1016  break;
1017  case (kCipMemberList):
1018  data_type_size = 0;
1019  break;
1020  case (kCipByteArray): {
1021  CipByteArray *data = (CipByteArray *) attribute_struct->data;
1022  data_type_size = sizeof(CipUint) + (data->length) * sizeof(CipOctet);
1023  }
1024  break;
1025  case (kInternalUint6):
1026  data_type_size = 6 * sizeof(CipUint);
1027  break;
1028  default:
1029  data_type_size = 0;
1030  break;
1031  }
1032  return data_type_size;
1033 }
EipStatus ApplicationInitialization(void)
Callback for the application initialization.
CIP Short String.
Definition: ciptypes.h:130
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
Struct for padded EPATHs.
Definition: ciptypes.h:152
EipStatus ConnectionManagerInit(EipUint16 unique_connection_id)
Initialize the data of the connection manager object.
struct cip_service_struct * services
Definition: ciptypes.h:256
EipUint16 attribute_number
Definition: ciptypes.h:216
Tracing infrastructure for OpENer.
float CipReal
Definition: typedefs.h:52
EipUint16 number_of_attributes
Definition: ciptypes.h:244
#define LOGICAL_SEGMENT_TYPE_INSTANCE_ID
Definition: cipepath.c:30
int DecodePaddedEPath(CipEpath *epath, const EipUint8 **message)
Decodes padded EPath.
Definition: cipcommon.c:804
void(* InitializeCipClass)(CipClass *)
Definition: opener_api.h:122
CipAttributeStruct * attributes
Definition: ciptypes.h:229
EipStatus(* CipServiceFunction)(CipInstance *const instance, CipMessageRouterRequest *const message_router_request, CipMessageRouterResponse *const message_router_response, struct sockaddr *originator_address, const int encapsulation_session)
Signature definition for the implementation of CIP services.
Definition: ciptypes.h:277
CIP Message Router Request.
Definition: ciptypes.h:187
#define OPENER_MESSAGE_DATA_REPLY_BUFFER
The number of bytes used for the buffer that will be used for generating any reply data of messages...
EipUint32 class_id
Definition: ciptypes.h:240
char * class_name
Definition: ciptypes.h:257
Class is a subclass of Instance.
Definition: ciptypes.h:237
#define OPENER_ASSERT(assertion)
int32_t CipDint
Definition: typedefs.h:51
CIP Byte Array.
Definition: ciptypes.h:122
EipUint16 length
Definition: ciptypes.h:123
EipStatus NotifyClass(const CipClass *RESTRICT const cip_class, CipMessageRouterRequest *const message_router_request, CipMessageRouterResponse *const message_router_response, struct sockaddr *originator_address, const int encapsulation_session)
Check if requested service present in class/instance and call appropriate service.
Definition: cipcommon.c:75
EipUint32 GetDintFromMessage(const EipUint8 **const buffer)
Reads EIP_UINT32 from *buffer and converts little endian to host.
Definition: endianconv.c:83
CipServiceFunction service_function
Definition: ciptypes.h:287
Responsible for Endianess conversion.
size_t CalculateIndex(EipUint16 attribute_number)
Calculates Byte-Index of Attribute.
Definition: cipcommon.c:895
#define OPENER_TRACE_ERR(...)
Definition: trace.h:86
CipInstance * AddCIPInstance(CipClass *RESTRICT const class, const EipUint32 instance_id)
Create one instance of a given class with a certain instance number.
Definition: cipcommon.c:178
Public interface of the QoS Object.
int16_t CipInt
Definition: typedefs.h:50
int8_t CipSint
Definition: typedefs.h:49
EipUint8 service_number
Definition: ciptypes.h:286
#define SEGMENT_TYPE_LOGICAL_SEGMENT
Definition: cipepath.c:21
CIP String.
Definition: ciptypes.h:138
EipStatus CipAssemblyInitialize(void)
create the CIP Assembly object with zero instances
Definition: cipassembly.c:61
EipUint8 g_message_data_reply_buffer[OPENER_MESSAGE_DATA_REPLY_BUFFER]
Definition: cipcommon.c:30
uint8_t * get_single_bit_mask
Definition: ciptypes.h:248
CIPAttributeFlag attribute_flags
Definition: ciptypes.h:218
void * CipCalloc(size_t number_of_elements, size_t size_of_element)
Allocate memory for the CIP stack.
EipUint8 path_size
Definition: ciptypes.h:153
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
uint8_t CipOctet
Data types as defined in the CIP Specification Vol 1 Appendix C.
Definition: typedefs.h:41
void DeleteAllClasses(void)
Free all data allocated by the classes created in the CIP stack.
#define LOGICAL_SEGMENT_TYPE_CLASS_ID
Definition: cipepath.c:29
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
EipUint16 length
Definition: ciptypes.h:139
EipStatus
EIP stack status enum.
Definition: typedefs.h:93
#define LOGICAL_SEGMENT_FORMAT_SIXTEEN_BIT
Definition: cipepath.c:39
uint8_t EipUint8
Definition: typedefs.h:32
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
EipStatus RegisterCipClass(CipClass *cip_class)
Register a CIP Class to the message router.
CipInstance class_instance
Definition: ciptypes.h:238
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
struct cip_instance * next
Definition: ciptypes.h:232
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
uint8_t CipBool
Definition: typedefs.h:42
uint8_t CipByte
Definition: typedefs.h:43
EipStatus CipMessageRouterInit()
Initialize the data structures of the message router.
CipServiceStruct * GetCipService(const CipInstance *const instance, CipUsint service_number)
Definition: cipcommon.c:692
void ShutdownAssemblies(void)
clean up the data allocated in the assembly object instances
Definition: cipassembly.c:65
#define OPENER_TRACE_INFO(...)
Definition: trace.h:89
int AddSintToMessage(const EipUint8 data, EipUint8 **const buffer)
converts UINT8 data from host to little endian an writes it to buffer.
Definition: endianconv.c:103
int DecodeData(const EipUint8 cip_data_type, void *const cip_data, const EipUint8 **const cip_message)
Retrieve the given data according to CIP encoding from the message buffer.
Definition: cipcommon.c:616
void EncapsulationShutDown(void)
Shutdown the encapsulation layer.
Definition: encap.c:847
EipUint16 revision
Definition: ciptypes.h:241
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
int EncodeData(const EipUint8 cip_type, const void *const cip_data, EipUint8 **cip_message)
Produce the data according to CIP encoding onto the message buffer.
Definition: cipcommon.c:450
double CipLreal
Definition: typedefs.h:53
EipByte * string
Definition: ciptypes.h:140
void CipStackInit(const EipUint16 unique_connection_id)
Initialize and setup the CIP-stack.
Definition: cipcommon.c:36
#define LOGICAL_SEGMENT_TYPE_ATTRIBUTE_ID
Definition: cipepath.c:33
uint8_t CipUsint
Definition: typedefs.h:46
CipInstance * GetCipInstance(const CipClass *RESTRICT const cip_class, EipUint32 instance_number)
Get a pointer to an instance.
CipClass * GetCipClass(const EipUint32 class_id)
Get a pointer to a CIP object with given class code.
EipStatus CipIdentityInit()
CIP Identity object constructor.
Definition: cipidentity.c:148
CipAttributeStruct * GetCipAttribute(const CipInstance *const instance, const EipUint16 attribute_number)
Get a pointer to an instance's attribute.
Definition: cipcommon.c:373
Public interface of the TCP/IP Interface Object.
Service descriptor. These are stored in an array.
Definition: ciptypes.h:285
Struct for saving TCP/IP interface information.
Definition: ciptypes.h:294
EipUint16 class_id
Definition: ciptypes.h:154
EipUint16 length
Definition: ciptypes.h:145
void CloseAllConnections(void)
Definition: appcontype.c:407
EipUint16 instance_number
Definition: ciptypes.h:155
EipUint16 number_of_services
Definition: ciptypes.h:254
EipUint16 attribute_number
Definition: ciptypes.h:156
EipUint8 minor_revision
Definition: ciptypes.h:181
uint8_t EipByte
EIP Data type definitions.
Definition: typedefs.h:28
EipUint8 major_revision
Definition: ciptypes.h:180
int EncodeEPath(CipEpath *epath, EipUint8 **message)
Definition: cipcommon.c:747
void EncapsulationInit(void)
Initialize the encapsulation layer.
Definition: encap.c:123
#define OPENER_TRACE_WARN(...)
Definition: trace.h:87
void ShutdownCipStack(void)
Shutdown of the CIP stack.
Definition: cipcommon.c:61
This file contains the public interface of the encapsulation layer.
EipStatus CipQoSInit()
Definition: cipqos.c:118
uint32_t CipUdint
Definition: typedefs.h:48
uint16_t CipUint
Definition: typedefs.h:47
size_t GetSizeOfAttribute(const CipAttributeStruct *const attribute_struct)
Definition: cipcommon.c:900
EipUint16 highest_attribute_number
Definition: ciptypes.h:245
uint8_t * set_bit_mask
Definition: ciptypes.h:249
EipUint16 GetIntFromMessage(const EipUint8 **const buffer)
Reads EIP_UINT16 from *buffer and converts little endian to host.
Definition: endianconv.c:57
Struct storing the CIP revision.
Definition: ciptypes.h:179
CIP Message Router Response.
Definition: ciptypes.h:199
struct cip_class * cip_class
Definition: ciptypes.h:231
void ShutdownTcpIpInterface(void)
Clean up the allocated data of the TCP/IP interface object.
void AllocateAttributeMasks(CipClass *target_class)
Allocates Attribute bitmasks.
Definition: cipcommon.c:885
EipUint8 length
Definition: ciptypes.h:131
EipByte * string
Definition: ciptypes.h:132
CipInstance * AddCipInstances(CipClass *RESTRICT const cip_class, const int number_of_instances)
Add a number of CIP instances to a given CIP class.
Definition: cipcommon.c:132
EipBool8 BeforeAssemblyDataSend(CipInstance *instance)
Inform the application that the data of an assembly object will be sent.
uint32_t CipDword
Definition: typedefs.h:45
EipUint32 instance_number
Definition: ciptypes.h:228
uint16_t CipWord
Definition: typedefs.h:44
uint16_t EipUint16
Definition: typedefs.h:33
EipStatus CipTcpIpInterfaceInit()
Initializing the data structures of the TCP/IP interface object.
EipByte * data
Definition: ciptypes.h:124
#define LOGICAL_SEGMENT_TYPE_MEMBER_ID
Definition: cipepath.c:31
#define LOGICAL_SEGMENT_FORMAT_EIGHT_BIT
Definition: cipepath.c:38
uint8_t * get_all_bit_mask
Definition: ciptypes.h:250
CipUsint size_of_additional_status
Definition: ciptypes.h:205
EipUint16 size
Definition: ciptypes.h:144